Conversation
|
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1506063502
ℹ️ 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".
| nextTurnId: state.turnIndex.nextTurnId, | ||
| branch: store.ref.branch, | ||
| head: deps.stores.tree.openBranch(store.ref.branch).head, | ||
| tokensBefore: estimateUsedContextTokens(state.history), |
There was a problem hiding this comment.
Use the same token basis across compaction rounds
When usage metadata is unavailable and the system prompt or tool definitions are large, onBeforeStep calculates usage including those prefixes, while this snapshot records tokensBefore from history alone. The controller later assigns this smaller value to lastCompactedTokens, so if the fixed prefix still puts the compacted context above the threshold, the continuation immediately triggers another compaction; every round repeats the mismatch and can loop through paid summary requests without reaching the normal LLM call. Record and compare token counts using the same prefix-aware calculation.
Useful? React with 👍 / 👎.
| ({ context }) => { | ||
| if (context.cause !== 'user-abort') { | ||
| deps.actor.send({ type: 'input.continue' }); | ||
| } |
There was a problem hiding this comment.
Resume the blocked prompt when auto-compaction fails
When budget compaction is triggered before a prompt's first LLM step and summarization then fails, the before-step hook has already ended that turn without producing a response. This cancellation path sends only input.continue, but the idle agent resumes on that event only when history ends mid-tool-chain; a history ending with the triggering user message therefore stays idle, while the prompt has already settled as successfully completed with no answer. Auto-compaction failure needs to requeue a continuation or otherwise restart the blocked turn.
Useful? React with 👍 / 👎.
| return { | ||
| history: state.history, | ||
| queue: state.queue, | ||
| nextTurnId: state.turnIndex.nextTurnId, |
There was a problem hiding this comment.
Preserve pending reminders when switching branches
An idle agent may legitimately have persisted input.remind entries waiting for its next turn, but the quiesce snapshot captures only history and queue. The fresh compaction branch therefore initializes reminders as empty, and replay starts after this snapshot's head, so any reminder already present before compaction is silently discarded and never delivered. Include the current reminder state in the seed, along with any other pending input state that must survive the reset.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 619717435b
ℹ️ 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".
| function defaultContinuation(reason: CompactionReason): UserMessage | undefined { | ||
| if (reason === 'manual') return undefined; | ||
| return compactionContinuationMessage(); |
There was a problem hiding this comment.
Resume work interrupted by manual compaction
When manual compaction begins while a turn is executing tools, the pause ends that turn at the next tool-result boundary, and branch switching replaces the mid-tool-chain history with user messages plus the summary. Returning no continuation for every manual run then leaves the reset agent idle, so the original prompt is reported as done without ever producing its final response. Enqueue a continuation when a manual compaction actually interrupted a running turn.
Useful? React with 👍 / 👎.
| deps.actor.send({ type: 'input.pause' }); | ||
| const waiting = waitFor(deps.actor, (s) => s.matches('idle'), { timeout: PAUSE_TIMEOUT_MS }); | ||
| void waiting.catch(() => undefined); | ||
| await Promise.race([waiting, aborted(signal)]); |
There was a problem hiding this comment.
Wait for detached tools before switching branches
When the agent has detached background tools, its state is idle.waiting, which still satisfies this broad matches('idle') predicate. Compaction therefore proceeds to store.reset; the agent reset aborts its scope and clears background, silently terminating those tools and discarding their eventual completion notifications. Quiescing should wait for an idle state with no background work, or explicitly preserve the detached tasks across the reset.
Useful? React with 👍 / 👎.
| goal_control: z.enum(['pause', 'resume', 'cancel']).optional(), | ||
| disabled_tools: z.array(z.string()).optional(), | ||
| prompt_id: z.string().min(1).optional(), | ||
| steer: z.boolean().optional(), |
There was a problem hiding this comment.
Add a changeset for the new steer behavior
This adds a documented, user-visible prompt submission capability, but the reviewed diff contains no .changeset/ entry, so the CLI release changelog and versioning will omit it. Add the required user-facing changeset before merging.
AGENTS.md reference: AGENTS.md:L86-L87
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1814aa78d5
ℹ️ 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".
| deps.actor.on('turn.aborting', () => { | ||
| active?.actor.send({ type: 'cancel', cause: 'user-abort' }); | ||
| }), |
There was a problem hiding this comment.
Route idle aborts to the active compaction
Once budget compaction has quiesced the agent, the agent is paused in idle, where input.abort has no handler and therefore emits no turn.aborting; this subscription is consequently unable to cancel the active summarization. An abort issued during that potentially long or paid phase does nothing, and a successful automatic compaction subsequently submits its continuation and restarts work the user tried to stop. Ensure aborts reach the active compaction even when no turn is running.
Useful? React with 👍 / 👎.
| const seedStore = await createEventStore({ journal, slices: agentSlices }); | ||
| try { | ||
| await seedStore.dispatch([...opts.seed]); |
There was a problem hiding this comment.
Preserve registered slice state across the branch switch
When the original agent store has a registered stateful slice such as todoSlice, this fresh branch is populated only with the fixed agentSlices and the compaction seed's history/queue events. Resetting the original store then refolds its registered todo slice over that branch without any state.updated event, so a nonempty structured TodoList becomes empty; appending rendered todo text to the LLM summary does not restore what the TodoList tool or UI reads. Seed the current registered state, including the todo snapshot, before resetting.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5f639d6e62
ℹ️ 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".
| compactionStarted(): boolean { | ||
| if (this.compacting) return false; | ||
| this.compacting = true; | ||
| if (this.status !== 'running' || this.turn === undefined) return false; |
There was a problem hiding this comment.
Publish manual compaction as an agent turn
When POST /sessions/{id}:compact starts manual compaction, AgentFullCompactionService.begin requires the loop to be idle, so this tracker normally has status === 'idle' and no turn. This guard therefore suppresses the agent.state update, and because this change also removes compacting from session.state, clients receive no indication that the asynchronous manual compaction is running. Transition idle agents to a running { status: 'compacting' } turn here as well.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be69ace220
ℹ️ 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".
| index: number, | ||
| member: SwarmMemberResult | undefined, | ||
| ): void => { | ||
| if (tasks.has(agentId)) return; |
There was a problem hiding this comment.
Refresh repeated swarm member tasks
When a later AgentSwarm call resumes an agent that appeared in an earlier call, tasks already contains that agent ID, so this return discards the later run's status, result, and timeline placement. Cold history consequently keeps showing the first run even though the live projector has updated the member; update the existing task or key synthesized tasks by both tool call and agent.
Useful? React with 👍 / 👎.
| deps.actor.on('turn.done', () => { | ||
| overflowAttempts = 0; | ||
| }), | ||
| deps.actor.on('turn.failed', (event) => { | ||
| if (!isContextOverflowError(event.error) || overflowAttempts >= maxAutoAttempts) { |
There was a problem hiding this comment.
Reset overflow retries after aborted turns
After an overflow triggers compaction, overflowAttempts is reset only by turn.done. If the resumed turn is aborted, the next unrelated prompt inherits the previous attempt count; at the configured cap its first context-overflow failure is no longer compacted and is surfaced immediately. Reset the counter on aborted turns and on terminal non-overflow failures while preserving it only across the same overflow recovery chain.
Useful? React with 👍 / 👎.
| const current = { actor, reason, startedAt: Date.now() }; | ||
| active = current; | ||
| const subscriptions = pipeEvents(actor); | ||
| await deps.stores.session(); |
There was a problem hiding this comment.
Clear active compaction when session-store setup fails
If opening the session store rejects because of an I/O or backend failure, this await runs before the try/finally, after active and the event subscriptions have already been installed. The caller receives the error, but every subsequent manual compaction reports busy and the subscriptions leak until the controller is recreated. Include setup and actor startup in the cleanup-protected region.
Useful? React with 👍 / 👎.
| function parseSwarmMembers(output: string): SwarmMemberResult[] { | ||
| if (!output.includes('<agent_swarm_result>')) return []; | ||
| const members: SwarmMemberResult[] = []; | ||
| for (const match of output.matchAll(/<subagent\b([^>]*)>([\s\S]*?)<\/subagent>/g)) { |
There was a problem hiding this comment.
Parse swarm results without treating report text as markup
When a subagent report contains the literal text </subagent>—for example while discussing this result format—the producer inserts the report body without escaping it, so this non-greedy regex closes at that text and stores a truncated result_summary or error in cold history. Recover member results from structured events or use an encoding that cannot conflict with arbitrary report content.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9329c09edb
ℹ️ 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 isV3 = url === WS_PATH_V3 || url.startsWith(`${WS_PATH_V3}?`); | ||
| const isDebug = url === WS_DEBUG_PATH || url.startsWith(`${WS_DEBUG_PATH}?`); | ||
| const wss = isV1 ? wssV1 : isV3 ? wssV3 : isDebug ? wssDebug : undefined; | ||
| const wss = isV3 ? wssV3 : isDebug ? wssDebug : undefined; |
There was a problem hiding this comment.
Sync the shipped web bundle with the v3-only server
At this commit, the committed apps/kimi-code/dist-web/assets/index-HU0LCM-X.js still constructs /api/v1/ws, contains no /api/v3/ws client, and calls the removed transcript/message REST endpoints, while this branch now accepts only v3/debug WebSocket upgrades and removes those REST registrations. Consequently, the web UI shipped by kimi web cannot establish its chat socket or load history; sync and commit the code-app bundle together with the protocol removal.
AGENTS.md reference: AGENTS.md:L18-L18
Useful? React with 👍 / 👎.
| if (getLiveSessionById(this.deps.core.accessor, sessionId) !== undefined) { | ||
| return existing.view; |
There was a problem hiding this comment.
Refresh the cached roster for live session searches
When a live session is searched once and later creates a new subagent, this returns the existing view whose roster was populated only once by loadRoster. Session-wide search derives its agent IDs from view.agents(), so it never calls ensureAgentHistory for the new subagent and silently omits that agent's messages from all subsequent searches until the cached source is dropped; refresh the roster or subscribe to agent lifecycle changes.
Useful? React with 👍 / 👎.
| const cached = this.sessions.get(sessionId); | ||
| this.sessions.delete(sessionId); | ||
| if (cached === undefined) return []; |
There was a problem hiding this comment.
Emit deletions for sessions absent from the event cache
Deleting a cold session, or any session that has not emitted a created/meta/activity event since this translator started, always hits this empty-cache return. The session has already been removed from ISessionIndex, so it cannot be fetched afterward, and v3 clients receive no deletion message; for example, kimi-inspect retains its seeded session entry until a later poll or unrelated invalidation. Seed the cache from existing sessions or construct a deletion entity from lifecycle data.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fde8ccef73
ℹ️ 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".
| function replaceEntryText(entry: UserEntry, text: string): UserEntry { | ||
| return { ...entry, message: { ...entry.message, content: [{ type: 'text', text }] } }; |
There was a problem hiding this comment.
Preserve media when truncating retained user messages
When a boundary user message exceeds the head/tail token budget and contains images, audio, or video alongside text, this replacement rebuilds its content from a single text part and silently discards every non-text part. For example, a recent prompt containing several screenshots can cross the 20k compaction budget and lose all screenshots from the compacted branch, leaving the continued turn unable to inspect the original inputs. Preserve the non-text parts on one retained fragment while accounting for their token cost.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0d48c459aa
ℹ️ 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".
| agentId: file.agentId, | ||
| role: e.role, | ||
| text: e.text.length > MAX_DOC_TEXT_CHARS ? e.text.slice(0, MAX_DOC_TEXT_CHARS) : e.text, | ||
| text: e.text, |
There was a problem hiding this comment.
Restore the per-message cap before indexing wire text
When a user or assistant message exceeds 20,000 characters and the only match occurs in its suffix, the persistent route now indexes the entire e.text, while collectLiveDocs in searchService.ts still truncates the same message to MAX_DOC_TEXT_CHARS. Consequently, an identical session-scoped search can return no hit while the session is live and then return a hit after it becomes cold; retaining the existing cap here also prevents exceptionally large prompts from unnecessarily inflating the persisted text indexes.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 84645fc45d
ℹ️ 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 (dir === undefined) return []; | ||
| let text: string; | ||
| try { | ||
| text = await readFile(join(dir, 'agents', agentId, 'wire.jsonl'), 'utf-8'); |
There was a problem hiding this comment.
Stream live wire history instead of reading it wholesale
For any session-scoped search against a live, long-running session, this loads the entire append-only wire.jsonl into one string and then split('\n') parses every record before the search deadline or text budget is established. Since wire history retains old turns and can contain very large tool-result records that produce no searchable document, a single search can consume memory proportional to the full session log, block far beyond the configured query deadline, or exhaust the server heap. Read and fold the file incrementally, or cache an incrementally updated bounded projection.
Useful? React with 👍 / 👎.
…story fold (#3754) Fork copies the source agent's context into the child wire as bare append_message records with no turn structure. The history fold synthesized a numbered turn for them, shifting every real turn off its engine turnId: answers landed in the wrong turn and the last turn never saw its turn.ended, so /history reported a running turn and missing turns for forked (btw) agents. Write a durable agent.fork record after the seed copy, fold pre-boundary seed messages into an unnumbered t-1 turn instead of consuming engine turn ids, and expose the boundary as a fork.boundary system message so clients can filter the inherited prefix.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6013b9eb52
ℹ️ 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".
| logger, | ||
| }); | ||
| const wssDebug = debugEndpoints ? registerWsDebug() : undefined; | ||
| const wssDebug = registerWsDebug(); |
There was a problem hiding this comment.
Keep the debug socket behind --debug-endpoints
When the server starts without --debug-endpoints, or uses a LAN/public bind where debugEndpoints is forced off, this still creates the debug WebSocket and the upgrade handler always routes /api/v1/debug/ws to it. Consequently, any bearer-authenticated client can subscribe to raw XState inspection traffic even though the HTTP debug surface is disabled; restore conditional registration and routing so the flag and loopback restriction cover the entire debug surface.
AGENTS.md reference: AGENTS.md:L27-L27
Useful? React with 👍 / 👎.
| const manager = core.accessor.get(ISessionManager); | ||
| const closeDisposable = manager.onDidCloseSession?.((event) => drop(event.sessionId)); |
There was a problem hiding this comment.
Attach activity watchers when sessions become live
When an existing session is resumed and work starts without first publishing an app-level IEventService event—for example, by materializing the session and submitting through the debug Service RPC—this map never attaches an ISessionActivityView listener because it watches only global events and session closure, not ISessionManager.onDidCreateSession. Subsequent activity changes therefore produce no global session update, leaving established kimi-inspect clients with a stale idle badge until reconnect; attach on session creation/resume and seed any already-live sessions.
AGENTS.md reference: apps/kimi-inspect/AGENTS.md:L26-L28
Useful? React with 👍 / 👎.
| turns.set(turnId, draft); | ||
| order.push(`turn:${turnId}`); | ||
| timelineIds.push(turnId); | ||
| rawId = seedEnded ? nextTurnId : SEED_TURN_RAW_ID; |
There was a problem hiding this comment.
Make the seed turn removable by clear
When a forked agent has inherited assistant messages, this creates a t-1 turn, but turnOrdinalOf recognizes only t followed by digits. A later context.clear consequently classifies t-1 as a system ID and removes neither the turn:t-1 order entry nor its child entities, so cold GET .../history rebuilds the inherited pre-clear context after reload even though the live projection cleared it. Use an ID recognized as a turn or handle this sentinel explicitly in removal logic.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 35ca4a144a
ℹ️ 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".
| }, | ||
| }, | ||
| }); | ||
| { steerIfActive: req.body.steer === true }, |
There was a problem hiding this comment.
Materialize media before completing a direct steer
When steer: true is submitted during an active turn with an image or video supplied by a server-local path, prompt preparation stores the media in an owned daemon file. This direct-steer path resolves handle.launched as soon as the entry is steered but, unlike the ordinary prompt gate and explicit steer endpoint, never materializes that daemon reference; the existing launch cleanup then deletes the file before the next LLM step, causing the media resolver to substitute unavailable-media text. Materialize daemon references before steering or delay cleanup until the media has been copied.
Useful? React with 👍 / 👎.
| : outcome === undefined | ||
| ? tool.status === 'done' | ||
| ? 'completed' | ||
| : 'failed' |
There was a problem hiding this comment.
Keep active resumed swarm members in the running state
When live history is requested while an AgentSwarm call with resume_agent_ids is still executing, there is no member outcome yet and tool.status is running, but this branch synthesizes every known resumed member as failed and later labels it interrupted. REST history consumers therefore show agents as failed while they are still working; use running for a live running tool and reserve interrupted/failed states for cold or terminal calls.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6cfa82828e
ℹ️ 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 class AgentFork extends AgentEvent2<z.infer<typeof agentForkSchema>> { | ||
| static override readonly type = 'agent.fork'; | ||
| static override readonly durable = true; | ||
| static override readonly schema = agentForkSchema; |
There was a problem hiding this comment.
Register the durable fork event before restoring it
When any forked agent is reopened, its persisted agent.fork record is absent from both EVENT2_REGISTRY and all state-fold contributions, so EventDispatcherService.replayRecords treats it as an unknown wire record and emits a corruption-style warning on every restore. Register AgentFork with registerEvent2Class (or contribute it explicitly) so this newly written durable record is recognized.
Useful? React with 👍 / 👎.
… let cron prompts through the display gate (#3761) * refactor(agent-core-v2): let cron origins through the prompt display gate and add text-part contentType * refactor(agent-core-v2): build envelope text parts through the structural history message builder * refactor(kap-server,kimi-code): propagate text-part contentType to the wire and filter envelopes by it in the tui
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bc67e876fd
ℹ️ 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".
| return INTERNAL_ORIGINS.has(origin.kind); | ||
| if (INTERNAL_ORIGINS.has(origin.kind)) return true; | ||
| if (origin.kind === 'user') return false; | ||
| return msg.content.some((part) => part.type === 'text' && part.contentType === 'text/xml'); |
There was a problem hiding this comment.
Keep slash-skill turns in exported transcripts
When a user invokes a standalone slash skill, AgentSkillService.activate now stores its skill_activation prompt as text/xml; because its origin is not user, this condition classifies the entire user message as internal. groupIntoTurns consequently drops the skill invocation and groups its assistant response into the preceding visible turn (or creates an assistant-only first turn), so exported Markdown loses both the command and the correct conversation boundaries. Preserve a sanitized skill-activation boundary, such as /<skill> <args>, rather than filtering the whole message.
Useful? React with 👍 / 👎.
| .filter((part): part is TextPromptPart => part.type === 'text' && part.contentType === 'text/xml') | ||
| .map((part) => part.text) | ||
| .join(''); | ||
| if (envelope.length === 0) return contentPartsToText(content); |
There was a problem hiding this comment.
Parse cron envelopes that lack content metadata
For sessions containing cron records persisted before contentType was introduced, the text part has no text/xml marker, so this fallback returns the complete legacy <cron-fire ...> envelope. The previous replay path extracted <prompt> or stripped the outer envelope, meaning reopening an existing session after this change exposes raw protocol XML instead of the scheduled prompt or missed-task text. Retain the legacy envelope parser when no typed XML part is present.
Useful? React with 👍 / 👎.
…call id (#3736) Remove the generated task-id layer from AgentTaskService: a background task is now identified by the tool call id of the Bash/Agent/AskUserQuestion call that started it, instead of a separately minted id. Field and parameter names stay taskId/task_id across the wire protocols (kap-server v3 messages/REST, klient), the TUI, vis, and kimi-inspect — only the value changes — so external consumers are unaffected. Persistence files are named by the task id value, duplicate registration of the same id is rejected as a bug, and the legacy on-disk migration along with the unused track()/ITaskService injection is removed.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2c6dc12153
ℹ️ 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".
| @@ -153,8 +164,18 @@ export class SessionActivityHub { | |||
| } | |||
| this.store.seed(entries); | |||
There was a problem hiding this comment.
Preserve WebSocket updates received during reseeding
On initial connection or reconnect, a session frame can update the store while this REST request is in flight, after which seed(entries) replaces the entire map with the older HTTP snapshot. Because HTTP and WebSocket delivery are unordered, a session that became busy during reseeding can remain falsely idle until another activity event occurs; merge the baseline without overwriting newer frame data, or buffer/version frames received after the request starts.
AGENTS.md reference: apps/kimi-inspect/AGENTS.md:L26-L28
Useful? React with 👍 / 👎.
| function isPathSafeTaskId(taskId: string): boolean { | ||
| if (taskId.length === 0) return false; | ||
| if (taskId === '.' || taskId === '..') return false; | ||
| return !/[/\\\0]/.test(taskId); |
There was a problem hiding this comment.
Encode tool-call IDs before using them as filesystem paths
When a provider supplies an otherwise valid tool-call ID containing / or \, detached-task persistence rejects it here; on Windows, IDs containing characters such as : pass this check but fail in the filesystem instead. The task service swallows those persistence errors, so background task metadata and output appear to work in memory but disappear after restart. Tool-call IDs are arbitrary protocol strings, so derive an encoded filesystem key rather than requiring the external ID itself to be path-safe.
Useful? React with 👍 / 👎.
… message (#3723) * fix(agent-core-v2): deliver cron-fired prompts as single opening turn 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. * test(agent-core-v2): drop stale compaction controller test for removed 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: 4b1a364a3f
ℹ️ 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 (dir === undefined) return []; | ||
| let text: string; | ||
| try { | ||
| text = await readFile(join(dir, 'agents', agentId, 'wire.jsonl'), 'utf-8'); |
There was a problem hiding this comment.
Reject path traversal in agent IDs before reading history
When searching a live session with a caller-supplied container.agent_id, searchMessagesBodySchema accepts any nonempty string and this path joins it directly beneath the agent directory. An ID such as ../../another-session/agents/main therefore reads a wire.jsonl outside the selected session and returns those messages as if they belonged to the requested container. Validate the ID against the live session roster or verify that the resolved path remains inside the session's agents directory before reading it.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: caf839a88c
ℹ️ 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".
| signal: detached ? undefined : options.signal, | ||
| }; | ||
| this.assertCanRegister(detached); | ||
| if (this.tasks.has(task.taskId)) { |
There was a problem hiding this comment.
Reserve restored task IDs before registering new tasks
When an agent is recreated after a clear or full compaction, tool-call ID normalization sees only the surviving context, while completed persisted tasks are restored into ghosts; a provider that reuses an old call ID therefore passes this this.tasks.has check. Registration then deletes the ghost, rewrites its metadata, and appends new output to the same output.log, mixing two tasks and potentially suppressing the new completion notification. Include ghost/persisted IDs in the uniqueness check or the ID normalizer.
Useful? React with 👍 / 👎.
| const entry: ManagedTask = { | ||
| taskId: generateTaskId(task.idPrefix), | ||
| taskId: task.taskId, | ||
| task, |
There was a problem hiding this comment.
Include agent identity in visualizer task lookups
When two agents receive the same provider-assigned tool-call ID, this change gives both tasks the same taskId because ID normalization is scoped per agent. The visualizer aggregates tasks from every agent but keys cards by taskId and requests output by taskId alone, while its server scans agents for the first matching log; duplicate cards can therefore collide in React and opening either card can display the other agent's output. Use (agentId, taskId) for aggregated card identity and output lookup.
Useful? React with 👍 / 👎.
Changes