fix(agents): keep auto-compaction on the live session model (#95696)#95713
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 9, 2026, 5:03 AM ET / 09:03 UTC. Summary PR surface: Source +25, Tests +168. Total +193 across 2 files. Reproducibility: yes. Source inspection shows Review metrics: 2 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land this focused compaction-context repair after normal maintainer review of the provider/auth routing change, and keep #101676 as separate follow-up for mid-attempt retry behavior. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows Is this the best way to solve the issue? Yes. This is the best narrow fix for #95696 because it reuses the already-resolved live selection at the two compaction caller sites; the model-selection-only PR is incomplete and #101676 is an adjacent fallback-boundary issue. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against f984209f54d5. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +25, Tests +168. Total +193 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
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
Review history (1 earlier review cycle)
|
|
@vincentkoc ready for review when you have a moment. Closes #95696. The single failing check ( |
|
Great design — the "reuse I had a few spare minutes, so I wrote a real-environment repro at The interesting assertion is #2: with the pre-fix wiring ( If you'd like to land it, the cleanest way is to copy the script into this branch and reference it from the PR body's "Real behavior proof" section — that should be enough to flip ClawSweeper from 🧂 → 🐚 and unblock maintainer review. Happy to send a follow-up commit if it's useful. #!/usr/bin/env node
// scripts/repro/issue-95696-compaction-model-override.mjs
import assert from "node:assert/strict";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { shouldSwitchToLiveModel } from "../../src/agents/live-model-switch.ts";
import { buildEmbeddedCompactionRuntimeContext } from "../../src/agents/embedded-agent-runner/compaction-runtime-context.ts";
const RUN_START_PROVIDER = "anthropic";
const RUN_START_MODEL = "sonnet-4.6";
const SESSION_KEY = "agent:main:dm:repro-95696";
async function writeSessionStoreWithOverride(storePath, { withOverride }) {
const entry = withOverride
? { sessionId: "repro-session", liveModelSwitchPending: true, providerOverride: "openai", modelOverride: "gpt-5.5", modelOverrideSource: "user", updatedAt: Date.now() }
: { sessionId: "repro-session", updatedAt: Date.now() };
await fs.mkdir(path.dirname(storePath), { recursive: true });
await fs.writeFile(storePath, JSON.stringify({ [SESSION_KEY]: entry }, null, 2), "utf8");
}
function resolvePostFixTarget(cfg) {
const requestedSelection = shouldSwitchToLiveModel({
cfg, sessionKey: SESSION_KEY,
defaultProvider: RUN_START_PROVIDER, defaultModel: RUN_START_MODEL,
currentProvider: RUN_START_PROVIDER, currentModel: RUN_START_MODEL,
});
const compactionProvider = requestedSelection?.provider ?? RUN_START_PROVIDER;
const compactionModelId = requestedSelection?.model ?? RUN_START_MODEL;
return buildEmbeddedCompactionRuntimeContext({
sessionKey: SESSION_KEY, workspaceDir: "/tmp/repro-ws", agentDir: "/tmp/repro-agent",
provider: compactionProvider, modelId: compactionModelId,
});
}
function resolvePreFixTarget() {
return buildEmbeddedCompactionRuntimeContext({
sessionKey: SESSION_KEY, workspaceDir: "/tmp/repro-ws", agentDir: "/tmp/repro-agent",
provider: RUN_START_PROVIDER, modelId: RUN_START_MODEL,
});
}
async function main() {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-repro-95696-"));
const storePath = path.join(tmpDir, "sessions.json");
const cfg = { session: { store: storePath } };
try {
await writeSessionStoreWithOverride(storePath, { withOverride: true });
const a = resolvePostFixTarget(cfg);
assert.equal(a.provider, "openai"); assert.equal(a.model, "gpt-5.5");
const b = resolvePreFixTarget();
assert.equal(b.provider, RUN_START_PROVIDER); assert.equal(b.model, RUN_START_MODEL);
await writeSessionStoreWithOverride(storePath, { withOverride: false });
const c = resolvePostFixTarget(cfg);
assert.equal(c.provider, RUN_START_PROVIDER); assert.equal(c.model, RUN_START_MODEL);
await writeSessionStoreWithOverride(storePath, { withOverride: true });
const d = resolvePostFixTarget({});
assert.equal(d.provider, RUN_START_PROVIDER); assert.equal(d.model, RUN_START_MODEL);
console.log("=== All repro assertions passed ===");
} finally {
await fs.rm(tmpDir, { recursive: true, force: true });
}
}
main().catch((err) => { console.error(err); process.exit(1); }); |
|
Addressed the [P1] auth-pairing finding. Both compaction sites in Live multi-provider timeout/overflow compaction is unreachable locally (no multi-provider credentials), so the auth invariant is proven through the real @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
81bb38e to
e9fd14f
Compare
|
Rebased onto |
e9fd14f to
0470aa6
Compare
0470aa6 to
cac3a45
Compare
cac3a45 to
188363e
Compare
|
ClawSweeper status: review started. I am starting a fresh review of this pull request: fix(agents): keep auto-compaction on the live session model (#95696) This is item 1/1 in the current shard. Shard 0/1. This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking. Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted. |
Co-authored-by: 0xghost42 <[email protected]>
188363e to
01141d6
Compare
|
ClawSweeper status: review started. I am starting a fresh review of this pull request: fix(agents): keep auto-compaction on the live session model (#95696) This is item 1/1 in the current shard. Shard 0/1. This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking. Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted. |
|
Merged via squash.
|
* origin/main: (24 commits) fix(agents): keep compaction on live session model (#95713) fix(plugin-sdk): guard provider catalog live URL parsing against malformed responses (#109986) chore(cli): drop dead classifiers and single-use wrappers left by fallback removal (#112191) feat(ui): expand the lobster pet's random universe (#112073) chore(ci): audit dependency fingerprint exports (#112190) fix(ui): preserve graphemes in provider icons (#109509) fix(ui): align settings search with navigation rows (#112172) fix(agents): allow configless gateway rebind to activate standalone owner (#111841) fix(secrets): register secret targets for installed-origin plugins (#104347) improve(ui): show real machine identity in the place picker (#112162) fix: webChat scrollback history is too limited — older assistant replies and tool outputs disappear when scrolling… (#104250) test(ui): run DOM-free suites in Node (#112031) feat(nodes): make computer.act eligibility capability-based for desktop nodes (#112107) fix(apps): harden mobile gateway and watch state fix(ci): restore Z.AI API Platform validation (#112171) fix(ui): prevent Logs controls from overlapping (#112170) fix #95291: message tool fails to deliver files/images on Feishu (400 volc-dcdn / write ECONNRESET) while same Lark SDK upload succeeds standalone (#95514) refactor(cli)!: remove automatic gateway→embedded fallback from openclaw agent (#112074) refactor: move provider transports into packages/ai behind a typed host port (#111669) fix(anthropic): complete transcript reverse-scan windows across short reads (#109431) ...
Co-authored-by: Peter Steinberger <[email protected]>
What Problem This Solves
Fixes #95696. After a mid-session
/modelswitch, the UI shows the new model and normal turns use it, but auto-compaction (timeout or overflow recovery) reverted to the model that was active when the run started. After a cross-provider switch it also kept the run-start auth profile, which would pair the newly selected provider with the previous provider's credentials.Why This Change Was Made
The auto-compaction sites in
src/agents/embedded-agent-runner/run.tsfed the run-start-resolvedprovider/modelIdandlastProfileIdintobuildEmbeddedCompactionRuntimeContext. The run loop already resolves the current selection one block earlier asrequestedSelection = shouldSwitchToLiveModel(...)(the restart check). When a switch is pending but the attempt cannot restart in place, it falls through to compaction.This reuses that already-resolved selection for the compaction provider/model, and now for the auth profile too:
provider/modelIdfall back to the run-start values when no switch is pending.authProfileIduses the switch's pinned profile when present; otherwise the run-start profile is kept only when the provider is unchanged, and dropped on a cross-provider switch so compaction resolves the new provider's own credentials instead of sending stale ones.No new store read is added on the path; it reuses the prepared selection the loop already computed (carry-forward of a prepared fact, per the agents hot-path guidance).
User Impact
After switching models with
/model, compaction now uses the model you selected and the matching credentials. No behavior change when no switch is pending.Evidence
/modelselection persisted in the session store.shouldSwitchToLiveModel+buildEmbeddedCompactionRuntimeContextmodules (only the session-store I/O and the registry-validating model-ref resolver are mocked, at the same boundarylive-model-switch.test.tsuses). Filesrc/agents/embedded-agent-runner/compaction-live-model-override.test.ts.node scripts/run-vitest.mjs src/agents/embedded-agent-runner/compaction-live-model-override.test.ts;./node_modules/.bin/oxlint --type-aware src/agents/embedded-agent-runner/run.ts src/agents/embedded-agent-runner/compaction-live-model-override.test.ts;./node_modules/.bin/oxfmt --write.liveModelSwitchPending+providerOverride: openai/modelOverride: gpt-5.5) over a run-startanthropic/sonnet-4.6resolves the compaction context toprovider: openai,model: gpt-5.5.authProfileOverride: openai:p1resolves compactionauthProfileId: openai:p1(not the run-startanthropic:default).authProfileIdto something other than the staleanthropic:default(the new provider's default).authProfileIdretained when the provider is unchanged).