fix(agent-core-v2): deliver cron-fired prompts as single opening turn message - #3723
fix(agent-core-v2): deliver cron-fired prompts as single opening turn message#3723sailist wants to merge 2 commits into
Conversation
… message isDisplayablePromptOrigin now admits cron_job/cron_missed, so the observable turn.started carries the cron-fire prompt text instead of leaving the opening wire user empty. prompt.inject only dispatches turn.steer when the message actually steers into a running turn; a fresh-turn submission is fully expressed by turn.prompt/turn.started, so the duplicate materialization and both opening-steer dedup hacks (live projector and coldFold) go away.
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6ad9786705
ℹ️ 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".
| if (rawId === undefined || hiddenTurnIds.has(rawId)) return; | ||
| const input = Array.isArray(record['input']) ? (record['input'] as ContentPart[]) : []; | ||
| const skipBlocks = kind === 'user' ? (origin?.skillActivations?.length ?? 0) : 0; | ||
| const entry = scratch(rawId); | ||
| if ( | ||
| entry.currentStep === undefined && | ||
| !entry.openingSteerDeduped && | ||
| entry.openingInputKey !== undefined && | ||
| entry.openingInputKey === JSON.stringify(input) | ||
| ) { | ||
| entry.openingSteerDeduped = true; | ||
| return; | ||
| } | ||
| if (kind === 'user') { |
There was a problem hiding this comment.
Preserve opening-steer dedup for stored histories
When reading sessions written by the previous version, foldWireHistory still receives the turn.prompt followed by the identical opening turn.steer that the old prompt.inject emitted. Without this check, onTurnPrompt creates tN.u0 and this path unconditionally creates tN.u1, so reopening any pre-upgrade session containing an idle cron/user/skill injection reintroduces the duplicate message this change is intended to fix. Keep the cold-fold compatibility dedup even if new writes no longer need it.
Useful? React with 👍 / 👎.
…d modules The file imports #/llm/requester/machine, #/llm/message and other modules that no longer exist after the requester-pipeline refactor; it resurfaced in the dev rewrite and fails the suite at import time.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4a568713fd
ℹ️ 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".
|
|
||
| export function isDisplayablePromptOrigin(origin: PromptOrigin): boolean { | ||
| if (origin.kind === 'user') return true; | ||
| if (origin.kind === 'cron_job' || origin.kind === 'cron_missed') return true; |
There was a problem hiding this comment.
Add a CLI changeset for the transcript fix
This change fixes a user-visible duplicate message in the CLI session transcript, but the commit adds no changeset. Without an @moonshot-ai/kimi-code patch changeset, the fix will ship without the required user-facing changelog entry; add the short changeset mandated for perceptible behavior changes.
AGENTS.md reference: AGENTS.md:L85-L86
Useful? React with 👍 / 👎.
Related Issue
N/A — internal bug fix, no tracking issue.
Problem
When a cron job fires, the session transcript shows two user messages instead of one: first an empty user message carrying the cron origin, then a second one with the actual
<cron-fire>envelope (observed as an emptyt1.u0immediately followed byt1.u1with the envelope, samecron_id).Root cause: the turn's opening message was expressed by two overlapping events.
turn.startedwithheld itspromptfor cron origins (theisDisplayablePromptOrigingate, a leftover from the removed v1 transcript layer), so the v3 projector created the opening user entity with empty text.prompt.injectthen dispatched a duplicateturn.steerfor the same message, and the projector's opening-steer dedup — keyed on the withheld, empty prompt — could never match, so the same message materialized twice.cron_missedinjections share the same path and defect.What changed
isDisplayablePromptOriginnow admitscron_job/cron_missed, soturn.startedcarries the cron-fire prompt and the opening user message materializes once, whole, with its origin.prompt.injectonly dispatchesturn.steerwhen the message actually steers into a running turn; a fresh-turn submission is fully expressed byturn.prompt/turn.started.steerKeyOfhelper), plus the two test scenarios that pinned it.The cold-history fold already sourced opening messages solely from
turn.promptand never double-projected; this aligns the live path with that single-source model.Checklist
gen-changesetsskill, or this PR needs no changeset — evaluated; no changeset per review decision.gen-docsskill, or this PR needs no doc update — internal wire mechanics, no doc impact.