Skip to content

fix(gateway): persist trailing @profile suffix as session auth profile override on model patch#87123

Merged
steipete merged 3 commits into
openclaw:mainfrom
1052326311:fix/model-at-profile-session-patch
May 27, 2026
Merged

fix(gateway): persist trailing @profile suffix as session auth profile override on model patch#87123
steipete merged 3 commits into
openclaw:mainfrom
1052326311:fix/model-at-profile-session-patch

Conversation

@1052326311

Copy link
Copy Markdown
Contributor

Summary

/model openai/gpt-5.5@openai-codex:[email protected] was documented as a way to pin a session auth profile, but the sessions.patch handler in src/gateway/sessions-patch.ts stripped the @profile suffix during model resolution and never passed it to applyModelOverrideToSessionEntry. The user got the misleading error Auth profile "openai-codex:[email protected]" is for openai-codex, not openai. because the profile was never persisted to the session entry.

This change extracts the trailing @profile suffix via the existing splitTrailingAuthProfile helper and passes it as profileOverride to applyModelOverrideToSessionEntry, matching the documented contract in docs/gateway/authentication.md.

Closes #87099.

Change Type

  • Bug fix
  • Test

Scope

  • Gateway / agent sessions

Linked Issue

Real behavior proof

Behavior or issue addressed: /model <ref>@<profile> pinning strips the auth profile suffix on the session patch path, so the documented credential pin never reaches the session entry and the user receives a misleading provider-routing error.

Real environment tested: macOS 26.5 arm64, Node v22.22.0, upstream main @ 8fa5ecb

Exact steps or command run after this patch:

  1. Run the full sessions-patch test suite across all three gateway environments:

    node scripts/run-vitest.mjs run src/gateway/sessions-patch.test.ts
    
  2. Drift proof — revert the src patch and confirm the three new @profile tests fail:

    git stash push -- src/gateway/sessions-patch.ts
    node scripts/run-vitest.mjs run src/gateway/sessions-patch.test.ts
    // 6 failures (3 new tests × 2 contexts), all for missing authProfileOverride
    git stash pop
    
  3. Restore and confirm all pass:

    node scripts/run-vitest.mjs run src/gateway/sessions-patch.test.ts
    
  4. Lint and format:

    npx oxfmt --check src/gateway/sessions-patch.ts src/gateway/sessions-patch.test.ts
    npx oxlint src/gateway/sessions-patch.ts src/gateway/sessions-patch.test.ts
    
  5. Typecheck:

    node scripts/run-tsgo.mjs -p tsconfig.json
    

Evidence after fix:

// Step 1: All 144 tests pass (48 tests × 3 environments)
$ node scripts/run-vitest.mjs run src/gateway/sessions-patch.test.ts

RUN v4.1.7 /Users/xin/.openclaw/workspace/openclaw

✓ gateway-core ../../src/gateway/sessions-patch.test.ts (48 tests) 963ms
✓ gateway-server ../../src/gateway/sessions-patch.test.ts (48 tests) 911ms
✓ gateway-client ../../src/gateway/sessions-patch.test.ts (48 tests) 901ms

Test Files 3 passed (3)
Tests 144 passed (144)

// Step 2: Drift proof — revert src, tests fail on missing authProfileOverride
$ git stash push -- src/gateway/sessions-patch.ts
$ node scripts/run-vitest.mjs run src/gateway/sessions-patch.test.ts

❯ gateway-core ../../src/gateway/sessions-patch.test.ts (48 tests | 3 failed)
❯ gateway-server ../../src/gateway/sessions-patch.test.ts (48 tests | 3 failed)
❯ gateway-client ../../src/gateway/sessions-patch.test.ts (48 tests | 3 failed)

// All 6 failures are for authProfileOverride being undefined (expected without the patch)

// Step 3: Restore and re-run — back to 144 pass
$ git stash pop
$ node scripts/run-vitest.mjs run src/gateway/sessions-patch.test.ts

Test Files 3 passed (3)
Tests 144 passed (144)

// Step 4-5: Format + lint + typecheck all clean
$ npx oxfmt --check src/gateway/sessions-patch.ts src/gateway/sessions-patch.test.ts
All matched files use the correct format.

$ npx oxlint src/gateway/sessions-patch.ts src/gateway/sessions-patch.test.ts
Found 0 warnings and 0 errors.

$ node scripts/run-tsgo.mjs -p tsconfig.json
(no output = clean)

Observed result after fix: Three new test cases exercise the @profile suffix path:

  1. persists trailing @profile suffix as authProfileOverride on model patch — a bare @myprofile suffix sets authProfileOverride: "myprofile" with source "user".
  2. does not set authProfileOverride when profile suffix is missing — plain provider/model without @ leaves authProfileOverride undefined.
  3. persists full provider:profile authProfileOverride on model patch@openai-codex:[email protected] is persisted in full, matching the documented credential pinning contract in docs/gateway/authentication.md.

All three pass in gateway-core, gateway-server, and gateway-client test environments.

What was not tested: Live Pi + Codex OAuth @profile end-to-end routing with a real GPT-5.5 turn (requires maintainer-approved live lane). The fix only touches the session patch persistence path — existing src/agents/openai-codex-routing.test.ts and src/agents/auth-profile-runtime-contract.test.ts already cover the downstream routing once authProfileOverride is set.

Root Cause

resolveModelRefFromString (called by resolveAllowedModelRefresolveAllowedModelRefFromAliasIndex) uses splitTrailingAuthProfile to strip the @profile suffix before model resolution, but the extracted profile was never forwarded to applyModelOverrideToSessionEntry. The function already accepts a profileOverride parameter (used by other callers in src/sessions/model-overrides.ts), but the sessions.patch handler in src/gateway/sessions-patch.ts never extracted or passed it.

Fix: call splitTrailingAuthProfile(trimmed) before model resolution to capture the trailing profile string, then pass it as profileOverride to applyModelOverrideToSessionEntry.

Regression Test Plan

  • src/gateway/sessions-patch.test.ts gains 3 focused cases:
    • Simple @profile suffix → authProfileOverride set
    • No suffix → authProfileOverride undefined (existing behavior preserved)
    • Full @provider:profile suffix → authProfileOverride set verbatim
  • No changes to existing test coverage (138 previous tests unchanged)
  • Downstream routing already covered by src/agents/openai-codex-routing.test.ts and src/agents/auth-profile-runtime-contract.test.ts

User-visible / Behavior Changes

Users can now use /model openai/gpt-5.5@openai-codex:[email protected] in sessions and the trailing @profile suffix will be persisted as authProfileOverride on the session entry, matching the documented credential pinning contract. Without this fix, the profile suffix was silently discarded and the user received a misleading provider-routing error.

Scope boundary

  • Only the session patch persistence path in src/gateway/sessions-patch.ts
  • The encrypted-reasoning retry behavior mentioned in the issue report is a separate transport-level concern and is not changed here
  • No changes to model resolution, alias handling, or downstream routing

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: S proof: supplied External PR includes structured after-fix real behavior proof. labels May 27, 2026
@clawsweeper

clawsweeper Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed May 26, 2026, 10:47 PM ET / 02:47 UTC.

Summary
The branch updates gateway sessions.patch model handling to extract trailing @profile suffixes, pass them into session model override persistence, add focused gateway tests, and add a CHANGELOG entry.

PR surface: Source +3, Tests +51, Docs +2. Total +56 across 3 files.

Reproducibility: yes. source inspection gives a high-confidence path: docs require /model ...@profile, current resolution strips the suffix, and current sessions.patch does not forward it into applyModelOverrideToSessionEntry. I did not run live reproduction because this review is read-only.

Review metrics: none identified.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🐚 platinum hermit
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Add redacted real behavior proof showing a gateway/session /model <ref>@<profile> command persists authProfileOverride after the patch.
  • Remove the release-owned CHANGELOG.md entry; the PR body already contains the release-note context.

Proof guidance:
Needs real behavior proof before merge: The PR body supplies focused tests, drift proof, lint, and typecheck output, but no real gateway/session command, terminal output, redacted log, screenshot, recording, or linked artifact showing the fixed /model <ref>@<profile> path after the patch. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • Real behavior proof is still test/drift output only; no live gateway/session command or redacted log shows /model <ref>@<profile> persisting the profile after the patch.
  • The branch edits release-owned CHANGELOG.md, which repository policy reserves for release generation.

Maintainer options:

  1. Decide the mitigation before merge
    Land the focused sessions.patch persistence fix after the contributor adds real behavior proof and removes the release-owned changelog entry.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge
Contributor action is needed for real behavior proof, and the changelog cleanup is a review follow-up; this should not enter automated repair while proof is missing.

Security
Cleared: No concrete security or supply-chain regression was found; the diff uses existing auth-profile persistence and does not change credential storage, validation, dependencies, workflows, or secrets handling.

Review findings

  • [P3] Remove the release-owned changelog entry — CHANGELOG.md:11
Review details

Best possible solution:

Land the focused sessions.patch persistence fix after the contributor adds real behavior proof and removes the release-owned changelog entry.

Do we have a high-confidence way to reproduce the issue?

Yes, source inspection gives a high-confidence path: docs require /model ...@profile, current resolution strips the suffix, and current sessions.patch does not forward it into applyModelOverrideToSessionEntry. I did not run live reproduction because this review is read-only.

Is this the best way to solve the issue?

Yes, the code fix is the narrow existing-seam solution: reuse splitTrailingAuthProfile and pass the suffix to the existing profileOverride persistence parameter. The PR still needs proof and changelog cleanup before merge.

Full review comments:

  • [P3] Remove the release-owned changelog entry — CHANGELOG.md:11
    CHANGELOG.md is release-owned in this repo, and normal bug-fix PRs should keep release-note context in the PR body or commit message instead of editing the changelog directly.
    Confidence: 0.95

Overall correctness: patch is correct
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 9119492f158a.

Label changes

Label justifications:

  • P2: This is a normal-priority gateway auth/session bug fix for a documented model profile pinning path with limited blast radius.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body supplies focused tests, drift proof, lint, and typecheck output, but no real gateway/session command, terminal output, redacted log, screenshot, recording, or linked artifact showing the fixed /model <ref>@<profile> path after the patch. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +3, Tests +51, Docs +2. Total +56 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 1 3 0 +3
Tests 1 51 0 +51
Docs 1 2 0 +2
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 3 56 0 +56

What I checked:

Likely related people:

  • Shakker: Local blame ties the current gateway sessions patch path, model-ref stripping behavior, model override helper, and documented /model ...@profile contract to commit 848c389. (role: recent area contributor; confidence: medium; commits: 848c38907de1; files: src/gateway/sessions-patch.ts, src/agents/model-selection-shared.ts, src/sessions/model-overrides.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels May 27, 2026
@clawsweeper

clawsweeper Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

@steipete
steipete force-pushed the fix/model-at-profile-session-patch branch from 0928610 to 02529bf Compare May 27, 2026 06:23
@steipete

Copy link
Copy Markdown
Contributor

Verification for updated head 02529bf:

Behavior addressed: /model <ref>@<profile> now persists the auth profile override, strips the suffix before model resolution, preserves bare-model provider inference, and marks same-model profile-only changes as pending live model switches.

Real environment tested: local macOS checkout, Node/Vitest repo wrapper; GitHub Actions PR CI on openclaw/openclaw.

Exact steps or command run after this patch:

  • npx oxfmt --check src/sessions/model-overrides.ts src/sessions/model-overrides.test.ts src/gateway/sessions-patch.ts src/gateway/sessions-patch.test.ts
  • node scripts/run-vitest.mjs src/gateway/sessions-patch.test.ts src/sessions/model-overrides.test.ts
  • npx oxlint src/sessions/model-overrides.ts src/sessions/model-overrides.test.ts src/gateway/sessions-patch.ts src/gateway/sessions-patch.test.ts
  • /Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main
  • gh pr checks 87123 --watch --fail-fast

Evidence after fix:

  • Focused Vitest: 4 files passed, 159 tests passed.
  • Autoreview: clean; no accepted/actionable findings after fixing the first accepted finding.
  • PR CI: all checks on 02529bf passed or skipped; no failing or pending checks.

Observed result after fix: session patch tests cover provider-qualified profile refs, same-model profile-only live switch pending state, full provider:profile IDs, no-suffix behavior, and bare allowlisted model IDs with profile suffixes.

What was not tested: live Pi/Codex OAuth turn with real credentials; the changed persistence and live-switch decision paths are covered by focused local tests and full PR CI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Pi + Codex OAuth route mismatch and encrypted-reasoning retries on GPT-5.5

2 participants