fix(agents): backfill missing sessionKey in embedded PI runner — prevents undefined key in model selection and live-switch#60555
Conversation
Greptile SummaryThis PR adds a Confidence Score: 5/5Safe to merge — the fix is a well-scoped read-only lookup with a no-op fallback; no behavioral regression for existing callers. All remaining findings are P2 style suggestions (silent catch, redundant fallback operand). No correctness or data-integrity issues were found. No files require special attention. Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run.ts
Line: 121-123
Comment:
**Silent error swallowing without any log**
If `resolveSessionKeyForRequest` throws unexpectedly (corrupt session store, permission error, etc.) the failure is invisible — the function returns `undefined` and the caller never knows the backfill was skipped. At minimum a `debug`/`warn` log would make future incidents diagnosable.
```suggestion
} catch (err) {
log.warn(
`[backfillSessionKey] Failed to resolve sessionKey for sessionId=${params.sessionId}: ${describeUnknownError(err)}`,
);
return params.sessionKey;
}
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run.ts
Line: 120
Comment:
**Redundant fallback operand**
`params.sessionKey` is guaranteed to be `undefined` or an empty string at this point (the early-return guard on line 112 already handles any truthy value). The `?? params.sessionKey` tail is therefore a no-op and adds a small amount of confusion — `resolved.sessionKey` alone is clearer.
```suggestion
return resolved.sessionKey;
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(agents): backfill sessionKey in runE..." | Re-trigger Greptile |
There was a problem hiding this comment.
Pull request overview
This PR addresses missing sessionKey propagation at the embedded runner boundary by backfilling sessionKey from sessionId via the existing store-backed resolver, avoiding null/undefined session keys reaching hooks/LCM/compaction.
Changes:
- Import and use
resolveSessionKeyForRequest()to backfillsessionKeywhen callers omit it. - Add a
backfillSessionKey()helper and apply it at the start ofrunEmbeddedPiAgent().
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 312b18bfc2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Pushed fixes for all review feedback: P1 (agentId binding): Removed P2 (silent catch): Replaced bare P2 (redundant fallback): Removed the P2 (whitespace normalization): Now normalizes with Docstring: Updated to reflect best-effort semantics. On the test coverage request: happy to add a regression test if you can point me at the right mock setup for |
|
CI note: the This PR only modifies |
|
@jalehman can you merge in. This quick fix enable LCM's to get the correct session key again - upstream fix of LCM patch already- need upstream to give LCM the data now to filter out subs and junk: |
|
Review feedback addressed in commit Greptile P2: silent error swallowing → Fixed. Added Greptile P2: redundant fallback operand → Fixed. Simplified to use resolved/trimmed key flow. Copilot: whitespace-only sessionKey propagation → Fixed. Now returns trimmed/resolved value, not original. Copilot: misleading docstring → Fixed. Updated to accurately describe resolver behavior. Codex P1: avoid forcing agent main key during backfill → Fixed. Resolver now uses Copilot: no regression test → Fixed. Added tests for:
All 8 review items addressed. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8374c2ef8f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 75ee14e23e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
75ee14e to
77f56fd
Compare
77f56fd to
e5ceffa
Compare
1354cda to
25fb6a4
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 25fb6a4d34
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const resolved = params.agentId?.trim() | ||
| ? resolveStoredSessionKeyForSessionId({ | ||
| cfg: params.config, | ||
| sessionId: params.sessionId, | ||
| agentId: params.agentId, |
There was a problem hiding this comment.
Fall back to explicit key when agent-store lookup misses
When agentId is present, backfillSessionKey only calls resolveStoredSessionKeyForSessionId, which returns undefined if the sessionId is not already in that store. For fresh agent-scoped runs (for example probe runs that create a new probe-<uuid> session ID), this leaves sessionKey unset and the downstream hooks/live-switch/error-context paths still see the same missing-key state this patch is trying to eliminate. Add a fallback (for example an explicit session key derived from sessionId) when the scoped lookup misses.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
The backfill is intentionally best-effort — when the session store lookup misses (new probe session, fresh sessionId not yet persisted), returning undefined is the correct behavior. Synthesizing a fake session key from the sessionId would create a key that doesn't map to any real session in the store, which is worse than undefined — downstream consumers would attempt operations against a non-existent session. The undefined case is already handled gracefully: hooks skip the sessionKey field, model selection falls back to defaults, and error formatting omits the field. The fix ensures that sessions which DO exist in the store get their key resolved, which is the primary gap this PR addresses.
25fb6a4 to
078247b
Compare
078247b to
1720b53
Compare
…mit it When callers of runEmbeddedPiAgent() don't provide params.sessionKey, the null value propagates to all downstream consumers: hooks, LCM afterTurn(), and compaction flows. This causes session_key = NULL in the LCM database, which breaks: - ignoreSessionPatterns glob matching (Martian-Engineering/lossless-claw#176) - Session-scoped compaction routing - Any extension using sessionKey for session identification Fix: resolve sessionKey from sessionId via resolveSessionKeyForRequest() at the top of runEmbeddedPiAgent(), before any downstream consumer sees it. Explicit sessionKey takes precedence (no behavior change for callers that already provide it). Resolution failure is silently swallowed. Fixes openclaw#60552
…whitespace
Review feedback from Greptile + Codex:
P1: Remove agentId from resolveSessionKeyForRequest() call to avoid
resolveExplicitAgentSessionKey() binding one-off callers (model probes,
etc.) to the agent main session. Now resolves purely by sessionId lookup.
P2: Replace silent catch with log.warn() using sanitizeForLog() so failed
backfill attempts are diagnosable in production.
P2: Remove redundant ?? params.sessionKey fallback (unreachable after the
early-return guard). Return undefined directly on failure.
P2: Normalize whitespace-only sessionKey values to undefined so downstream
consumers never see ' ' as a valid key.
… path - Revert shouldSwitchToLiveModel/clearLiveModelSwitchPending back to the original consumeLiveSessionModelSwitch API (cherry-pick artifact) - Remove duplicate inner backfill block — outer backfillSessionKey() already sets params.sessionKey before this point, so the inner path was dead code
…w#60552 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Apply redactRunIdentifier to the sessionId in the backfillSessionKey catch block to match the redaction pattern used elsewhere in the file. Update the CHANGELOG entry for openclaw#60552 to describe both the sessionKey backfill from sessionId and the whitespace normalization. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1720b53 to
8081345
Compare
|
Merged via squash.
Thanks @100yenadmin! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8081345f1c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const selection = resolveSessionIdMatchSelection( | ||
| Object.entries(sessionStore).filter(([, entry]) => entry?.sessionId === sessionId), |
There was a problem hiding this comment.
Filter agent-scoped backfill matches by agent id
The new resolveStoredSessionKeyForSessionId() path only filters by sessionId, so when runEmbeddedPiAgent backfills with an agentId and session.store is configured as a shared file (no {agentId} segment), a duplicate sessionId from another agent can be selected as the winner. That binds the current run to the wrong session key, which can leak/pollute hook, live-switch, and compaction state across agents. Fresh evidence in this commit is that the new helper introduced for scoped backfill does not constrain candidate keys to the requested agent prefix before resolveSessionIdMatchSelection.
Useful? React with 👍 / 👎.
…ents undefined key in model selection and live-switch (openclaw#60555) Merged via squash. Prepared head SHA: 8081345 Co-authored-by: 100yenadmin <239388517+100yenadmin@users.noreply.github.com> Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com> Reviewed-by: @jalehman
…ents undefined key in model selection and live-switch (openclaw#60555) Merged via squash. Prepared head SHA: 8081345 Co-authored-by: 100yenadmin <239388517+100yenadmin@users.noreply.github.com> Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com> Reviewed-by: @jalehman
…ents undefined key in model selection and live-switch (openclaw#60555) Merged via squash. Prepared head SHA: 8081345 Co-authored-by: 100yenadmin <239388517+100yenadmin@users.noreply.github.com> Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com> Reviewed-by: @jalehman
What this fixes (plain English)
When a chat session was started with only a session ID (no session key), downstream features like hooks, live-model switching, and error formatting would break because they expected a session key. This fix resolves the session key from the store at startup, so all downstream paths work correctly.
Technical details
Root cause: The embedded runner could receive a
sessionIdwithout a correspondingsessionKey. Downstream paths (hooks, live-model switch, error formatting, pending-clear) all requiresessionKeybut receivedundefined.Fix: Added
resolveSessionKeyForRequest()backfill at the start of the embedded runner when onlysessionIdis provided. The resolved key is used consistently throughout the run lifecycle. Logs a warning if backfill resolution fails (instead of silently swallowing).Files changed:
src/agents/pi-embedded-runner/run.ts— backfill sessionKey from sessionId via resolversrc/agents/command/session.ts— updated docstringsrc/agents/pi-embedded-runner.e2e.test.ts— e2e regression test for sessionKey backfillsrc/gateway/sessions-history-http.test.ts— SSE seq validation: verifies NO_REPLY messages are excluded from streamed history and seq numbering is correctCHANGELOG.md— release note for the sessionKey backfill fixRelated
Test plan