Skip to content

fix(agents): isolated cron busts prompt prefix cache via per-run session id#96686

Merged
steipete merged 3 commits into
openclaw:mainfrom
openperf:fix/96677-cron-prompt-cache-runscope
Jul 9, 2026
Merged

fix(agents): isolated cron busts prompt prefix cache via per-run session id#96686
steipete merged 3 commits into
openclaw:mainfrom
openperf:fix/96677-cron-prompt-cache-runscope

Conversation

@openperf

@openperf openperf commented Jun 25, 2026

Copy link
Copy Markdown
Member

Summary

  • Problem: isolated cron runs use a fresh run-scoped session key (agent:<agent>:cron:<job>:run:<runId>). buildRuntimeLine rendered that key and the matching session id into the prompt-facing Runtime: line. Transports that strip the explicit cache-boundary marker and rely on automatic literal-prefix caching therefore received different prompt bytes for every run, invalidating reuse before the tool catalog.
  • Root cause: fix: isolate cron context-engine session keys #72292 threaded the run-scoped key into embedded cron execution to prevent cross-run context leakage. fix #92453: add session identity to runtime prompt #92468 later exposed the execution key and id in Runtime:. Their interaction made prompt identity volatile. fix(cron): refuse keyless implicit isolated cron delivery inherited from shared agent-main bucket #91685 changed delivery-target resolution, but did not introduce or render the run-scoped key. The issue reporter's measured 2026.6.8/2026.6.9 boundary is useful runtime evidence, but that exact version boundary is not source-verifiable because v2026.6.8 already contains both source changes.
  • Fix: normalize only the model-visible identity. parseCronRunScopeSuffix recognizes the terminal canonical cron-run shape, buildRuntimeLine renders the stable job key, and a sessionId is omitted only when it duplicates the parsed run id. Execution, transcripts, routing, delivery, registry, and cleanup remain run-scoped.

Scope and behavior

  • Two different runs of one cron job now render byte-identical runtime lines.
  • A distinct rotated or stable sessionId is preserved.
  • Non-cron keys, malformed/nonterminal :run: segments, and channel-owned :run: data remain unchanged.
  • Structural markers remain case-insensitive while the stored key's original casing is preserved.
  • The parser is intentionally terminal-only; descendant session keys are outside this fix's scope.
  • Config, plugin SDK, and gateway protocol surfaces are unchanged.

The tradeoff is deliberate: the model sees stable cron-job identity instead of the concrete run key, while every operational identity path still uses the concrete run-scoped key.

Proof

Exact reviewed head: a32fa8912f9bffd23310f851ab41141d1a6e925f

Sanitized untrusted-source AWS Crabbox proof (cbx_b3d9e9da2799, run run_a702d09110a3, Linux/Node 24) ran:

pnpm test \
  src/agents/system-prompt.test.ts \
  src/routing/session-key.test.ts \
  src/cron/isolated-agent/run.session-key-isolation.test.ts \
  src/agents/embedded-agent-runner/prompt-cache-observability.test.ts \
  packages/ai/src/providers/openai-completions.test.ts \
  packages/ai/src/providers/openai-responses-shared.test.ts \
  src/agents/openai-transport-stream.test.ts

Result: 7 files across 4 Vitest shards, 579 tests passed. Fresh maintainer autoreview found no actionable findings. Exact-head hosted CI is required before merge; an Opengrep installer network-fetch failure was rerun successfully.

Not independently tested: live metered-provider token telemetry. The cache-stability mechanism is covered deterministically at the renderer, cron execution, observability, and affected transport boundaries.

Release note

Fix isolated cron prompt-cache stability by keeping per-run UUIDs out of the prompt-facing runtime identity.

Change type

  • Bug fix

Scope

  • Gateway / orchestration

Fixes #96677

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels Jun 25, 2026
@clawsweeper

clawsweeper Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 25, 2026, 4:11 AM ET / 08:11 UTC.

Summary
The PR adds cron run-scope parsing, renders the stable cron base key in buildRuntimeLine, omits duplicated per-run sessionId, and adds focused parser/runtime-line tests.

PR surface: Source +38, Tests +74. Total +112 across 4 files.

Reproducibility: yes. at source level: current main constructs a :run: isolated-cron session key, passes it into embedded execution, and renders it directly in the Runtime prompt line. I did not independently reproduce the live provider token jump.

Review metrics: 1 noteworthy metric.

  • Runtime prompt identity surface: 1 normalized, 1 conditionally omitted. The diff changes model-visible session state in the Runtime line, so maintainers should notice the identity tradeoff before merge.

Stored data model
Persistent data-model change detected: persistent cache schema: src/agents/system-prompt.test.ts, serialized state: src/routing/session-key.test.ts, serialized state: src/sessions/session-key-utils.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #96677
Summary: This PR is the candidate fix for the open isolated-cron Runtime-line prompt-cache regression; older prompt-cache and cron-isolation items are related context, not replacements.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🌊 off-meta tidepool
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

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

Risk before merge

  • [P1] The PR intentionally changes model-visible Runtime session identity for isolated cron runs: session= becomes the stable cron base key and duplicated per-run sessionId= is omitted while routing, transcript, cleanup, and delivery state remain run-scoped.
  • [P1] I did not independently run a live metered-provider token trace; source inspection and the PR tests prove byte-stable Runtime rendering at the fix boundary, while the exact billing delta remains reporter-provided.

Maintainer options:

  1. Accept Prompt-Facing Stable Cron Identity (recommended)
    Merge with the explicit maintainer decision that only Runtime prompt identity is normalized while actual isolated-cron run state remains per-run.
  2. Request A Redacted Live Cache Trace
    Ask for before/after isolated-cron provider output showing the Runtime line and cache or token counts if billing proof is required before merge.
  3. Pause For Broader Prompt-Volatility Design
    Defer this PR only if maintainers prefer a larger cache-boundary redesign, with the current linked regression remaining open meanwhile.

Next step before merge

  • [P2] No repair lane is needed; maintainers should review the model-visible session identity tradeoff and either land the PR or request live cache/token proof.

Security
Cleared: The diff only changes TypeScript prompt-rendering/session-key helper logic and focused tests; no dependency, workflow, package, secret, or supply-chain surface changed.

Review details

Best possible solution:

Land this prompt-rendering fix after maintainers accept the prompt-facing cron identity tradeoff, while keeping actual isolated-cron routing, transcript, cleanup, and delivery state per-run.

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

Yes at source level: current main constructs a :run: isolated-cron session key, passes it into embedded execution, and renders it directly in the Runtime prompt line. I did not independently reproduce the live provider token jump.

Is this the best way to solve the issue?

Yes. Prompt-facing normalization in buildRuntimeLine is narrower than reusing one cron session across runs, and the existing promptCacheKey path alone does not remove volatile Runtime prompt bytes.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 770b19f496c1.

Label changes

Label justifications:

  • P2: This is a focused isolated-cron prompt-cache cost regression with bounded blast radius and no outage, data loss, or security bypass.
  • merge-risk: 🚨 session-state: The PR changes model-visible Runtime session identity for cron-scoped agent runs, even though underlying routing and transcript state remain run-scoped.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🌊 off-meta tidepool and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: The external-contributor real-behavior proof gate does not apply to this MEMBER-authored PR; the body reports deterministic render-boundary tests and states no live metered-provider trace was run.
Evidence reviewed

PR surface:

Source +38, Tests +74. Total +112 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 40 2 +38
Tests 2 74 0 +74
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 114 2 +112

What I checked:

  • Repository policy read: Root AGENTS.md was read fully; its review guidance applies because this PR touches agent prompt/session state and requires whole-path session-state review. (AGENTS.md:1, 770b19f496c1)
  • Scoped policy read: The scoped agents guide was read fully; it did not add a runtime blocker beyond keeping agent tests focused and import-light. (src/agents/AGENTS.md:1, 770b19f496c1)
  • Current main renders volatile session identity: Current main directly renders runtimeInfo.sessionKey and runtimeInfo.sessionId into the Runtime prompt line, so a run-scoped cron key is model-visible before this PR. (src/agents/system-prompt.ts:1400, 770b19f496c1)
  • Current main creates run-scoped cron keys: Current main appends :run:${runSessionId} to agent-scoped cron keys for isolated cron execution, matching the reported volatile Runtime field. (src/cron/isolated-agent/run.ts:634, 770b19f496c1)
  • Prompt cache key is separate from prompt text: The executor already passes a stable promptCacheKey and the run-scoped sessionKey separately, so the prior cache-affinity fix does not remove the volatile Runtime prompt text by itself. (src/cron/isolated-agent/run-executor.ts:361, 770b19f496c1)
  • Cache boundary checked: The cache boundary is inserted before dynamic sections, while Runtime is appended later; boundary-aware transports can split it, but transports that strip the marker still see Runtime as part of the literal prompt string. (src/agents/system-prompt.ts:1277, 770b19f496c1)

Likely related people:

  • zhangguiping-xydt: Authored the merged Runtime identity PR that added session= and sessionId= to prompt rendering. (role: introduced Runtime session identity; confidence: high; commits: 78c66742ab97; files: src/agents/system-prompt.ts, src/agents/system-prompt-params.ts, src/agents/embedded-agent-runner/run/attempt.ts)
  • vincentkoc: History search shows multiple prompt-cache boundary and transport commits that this fix must preserve. (role: prompt-cache area contributor; confidence: high; commits: 64f28906de09, 4798e125f40c; files: src/agents/system-prompt.ts, src/agents/system-prompt-cache-boundary.ts, src/agents/openai-transport-stream.ts)
  • steipete: Prior review and history point to the isolated-cron fresh-session change that made the cron identity run-scoped. (role: introduced isolated-cron freshness behavior; confidence: high; commits: 91f75a2b33b6; files: src/cron/isolated-agent/run.ts)
  • ferminquant: Merged prior isolated-cron prompt-cache affinity work that this PR complements rather than replaces. (role: previous prompt-cache affinity contributor; confidence: high; commits: 3f9d2415acc8; files: src/cron/isolated-agent/run-executor.ts, src/cron/isolated-agent/run.session-key-isolation.test.ts, src/agents/openai-transport-stream.ts)
  • nxmxbbd: Authored the merged adjacent isolated-cron delivery/session PR cited as root-cause context for the run-scoped key. (role: recent adjacent cron delivery contributor; confidence: medium; commits: d4833e27c775; files: src/cron/isolated-agent/run.ts, src/cron/isolated-agent/delivery-target.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: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels Jun 25, 2026
@openperf
openperf force-pushed the fix/96677-cron-prompt-cache-runscope branch from cea99f9 to c8d516b Compare June 25, 2026 07:36
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jun 25, 2026
@steipete steipete self-assigned this Jul 9, 2026
openperf and others added 3 commits July 9, 2026 08:38
…ion id

Isolated cron runs carry a per-run :run:<id> session scope (openclaw#91685) rendered
verbatim into the cached system-prompt Runtime line, re-busting byte-exact
prefix caching for the tool catalog after it every run (openclaw#96677, openclaw#43148 class).
buildRuntimeLine now renders the stable base session key and drops the per-run
id the run scope duplicates; parseCronRunScopeSuffix is gated to the
isolated-cron key shape so a :run: segment in any other session key is never
truncated.
@steipete
steipete force-pushed the fix/96677-cron-prompt-cache-runscope branch from c8d516b to a32fa89 Compare July 9, 2026 15:40
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Maintainer landing proof for a32fa8912f9bffd23310f851ab41141d1a6e925f:

  • Rebased onto 2e160718d4b77716ec7675e659619dff893b3fb7; the final merge guard compared current main and found only unrelated drift.
  • Deep review confirmed prompt-only normalization: operational execution, transcript, routing, delivery, registry, and cleanup identity remain run-scoped.
  • Review caught and fixed mixed-case canonical marker parsing, added a regression for it, and added explicit coverage that a distinct cron sessionId remains visible.
  • Fresh autoreview: no actionable findings (0.94 confidence).
  • Sanitized AWS Crabbox proof: provider aws, lease cbx_b3d9e9da2799, run run_a702d09110a3; 7 focused files across 4 Vitest shards, 579 tests passed.
  • Exact-head hosted CI is green. The only initial failure was Opengrep's installer failing to fetch its release list; the exact failed job was rerun and passed.
  • Repository prepare and merge-verification gates passed. Root changelog is release-owned for this file set; release-note context is in the PR body.

Residual evidence limit: no independent live metered-provider token trace; cache stability is proven deterministically at the renderer, cron execution, observability, and affected transport boundaries.

@steipete
steipete merged commit f6c16d2 into openclaw:main Jul 9, 2026
103 of 104 checks passed
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

Simon-XYDT pushed a commit to Simon-XYDT/openclaw that referenced this pull request Jul 9, 2026
…ion id (openclaw#96686)

* fix(agents): isolated cron busts prompt prefix cache via per-run session id

Isolated cron runs carry a per-run :run:<id> session scope (openclaw#91685) rendered
verbatim into the cached system-prompt Runtime line, re-busting byte-exact
prefix caching for the tool catalog after it every run (openclaw#96677, openclaw#43148 class).
buildRuntimeLine now renders the stable base session key and drops the per-run
id the run scope duplicates; parseCronRunScopeSuffix is gated to the
isolated-cron key shape so a :run: segment in any other session key is never
truncated.

* fix(agents): preserve mixed-case cron run markers

* test(agents): cover rotated cron session identity

---------

Co-authored-by: Peter Steinberger <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
…ion id (openclaw#96686)

* fix(agents): isolated cron busts prompt prefix cache via per-run session id

Isolated cron runs carry a per-run :run:<id> session scope (openclaw#91685) rendered
verbatim into the cached system-prompt Runtime line, re-busting byte-exact
prefix caching for the tool catalog after it every run (openclaw#96677, openclaw#43148 class).
buildRuntimeLine now renders the stable base session key and drops the per-run
id the run scope duplicates; parseCronRunScopeSuffix is gated to the
isolated-cron key shape so a :run: segment in any other session key is never
truncated.

* fix(agents): preserve mixed-case cron run markers

* test(agents): cover rotated cron session identity

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: 2026.6.9 re-busts prompt prefix caching — per-run :run:<UUID> injected into the system-prompt "Runtime:" line (regression of #43148)

2 participants