Problem
runEmbeddedPiAgent() and runEmbeddedAttempt() forward params.sessionKey directly to downstream consumers (hooks, compaction, LCM ingest). When callers omit sessionKey (which at least 2 confirmed call sites do), it propagates as undefined/null through:
- Hook contexts (
beforeAgentStart, afterAgentEnd, beforeCompaction)
- LCM/lossless-claw
afterTurn() → stored as session_key = NULL in the LCM database
- Compaction flows
Evidence from production
We found thousands of LCM database rows with session_key = NULL:
SELECT COUNT(*) FROM conversations WHERE session_key IS NULL;
-- Result: 847 conversations with null session_key
These null-key conversations break downstream features including:
Root cause
The correct resolver already exists in the codebase: resolveSessionKeyForRequest() from src/agents/command/session.ts. It's synchronous and store-backed — it resolves a sessionKey from sessionId when sessionKey is not provided.
The issue is that runEmbeddedPiAgent and runEmbeddedAttempt in src/agents/pi-embedded-runner/run.ts don't call it. They just pass through whatever params.sessionKey they receive.
Proposed fix
Add a backfill step at the top of the runner boundary (run.ts) that resolves sessionKey from sessionId when sessionKey is not explicitly provided:
import { resolveSessionKeyForRequest } from '../command/session.js';
function backfillSessionKey(params: { sessionId: string; sessionKey?: string }): string | undefined {
if (params.sessionKey) return params.sessionKey;
return resolveSessionKeyForRequest({ sessionId: params.sessionId });
}
Then use the resolved key for all downstream consumers. Explicit sessionKey takes precedence (no behavior change for callers that already provide it).
Related
Environment
- OpenClaw v2026.4.2
- Affects:
src/agents/pi-embedded-runner/run.ts → runEmbeddedPiAgent(), runEmbeddedAttempt()
Problem
runEmbeddedPiAgent()andrunEmbeddedAttempt()forwardparams.sessionKeydirectly to downstream consumers (hooks, compaction, LCM ingest). When callers omitsessionKey(which at least 2 confirmed call sites do), it propagates asundefined/nullthrough:beforeAgentStart,afterAgentEnd,beforeCompaction)afterTurn()→ stored assession_key = NULLin the LCM databaseEvidence from production
We found thousands of LCM database rows with
session_key = NULL:These null-key conversations break downstream features including:
ignoreSessionPatternsglob matching silently no-ops (ignoreSessionPatternshas no effect: cron conversations havesession_key = NULL, so glob matching silently no-ops Martian-Engineering/lossless-claw#176)Root cause
The correct resolver already exists in the codebase:
resolveSessionKeyForRequest()fromsrc/agents/command/session.ts. It's synchronous and store-backed — it resolves a sessionKey from sessionId when sessionKey is not provided.The issue is that
runEmbeddedPiAgentandrunEmbeddedAttemptinsrc/agents/pi-embedded-runner/run.tsdon't call it. They just pass through whateverparams.sessionKeythey receive.Proposed fix
Add a backfill step at the top of the runner boundary (
run.ts) that resolves sessionKey from sessionId when sessionKey is not explicitly provided:Then use the resolved key for all downstream consumers. Explicit sessionKey takes precedence (no behavior change for callers that already provide it).
Related
ignoreSessionPatternshas no effect: cron conversations havesession_key = NULL, so glob matching silently no-ops Martian-Engineering/lossless-claw#176 (ignoreSessionPatternsno-ops on null session_key)Environment
src/agents/pi-embedded-runner/run.ts→runEmbeddedPiAgent(),runEmbeddedAttempt()