kimi-code/packages
7Sageer 51bd52a589
fix(kimi-code): flush wire journals before print-mode exit (#3531)
* fix(kimi-code): flush wire journals before print-mode exit

A print-mode turn's tail records (step.end / turn.ended / prompt.completed)
are dispatched fire-and-forget and reach the journal only through the wire
service's async persist queue. The print cleanup path never awaited that
queue: with telemetry disabled (KIMI_DISABLE_TELEMETRY=1) cleanup returns
in microseconds, and process.exit on the error path cut off the pending
append-log flush, dropping the failed turn's closing records. Flush every
session agent's dispatcher (which awaits the wire persist queue and the
append-log store) before disposing the app, bounded by the shutdown
timeout and best-effort so a persist failure never masks the turn outcome.

* fix(kimi-code): settle each agent's wire flush independently

Promise.all rejects as soon as one agent's flush fails; the best-effort
caller then proceeds to app.dispose() and process.exit while the remaining
agents' flushes are still in flight, re-exposing their journals to the
truncation this cleanup is meant to prevent. Await every flush with
Promise.allSettled instead (matches the drain helper's convention), and
cover it with a two-agent regression test.

* fix(kimi-code): run print-mode shutdown phases concurrently

The wire flush, v2 telemetry shutdown, and v1 telemetry shutdown each hold
a 3s allowance; run sequentially they can take 9s, past the 8s outer
cleanup bound — the caller's process.exit would then cut off the tail
(app.dispose included). The phases are independent, so await them
concurrently (worst case one allowance) while keeping the v2 shutdown
failure propagation and the best-effort semantics of the other two.

* fix(kimi-code): quiesce active turns before the print-mode wire flush

A termination signal (SIGINT/SIGTERM/SIGHUP) can arrive mid-turn: the
cleanup ran the wire flush immediately, while the still-running turn only
produced its cancellation and closing records from dispose()'s
fire-and-forget teardown — after the flush, and after the signal handler's
process.exit. Cancel every session agent's queued and active turns and
await loop idleness before flushing (best-effort, bounded by the shutdown
timeout); idle loops make this a no-op on the normal exit paths. Torn-down
agent scopes are skipped defensively, mirroring the flush's per-agent
settlement.

* fix(kimi-code): drain prompts and await prompt completion in print quiesce

Two follow-ups from review:

- The loop settles (releaseActiveTurn) before the prompt-settle chain
  dispatches prompt.completed, so awaiting loop idleness alone let the
  wire flush race the final record. Quiesce now also drains each agent's
  prompt queue and awaits the tracked prompt completions (registered at
  enqueue time) before the flush runs.

- Restore drainBackgroundTasks to Promise.all: a previous edit
  unintentionally switched it to allSettled alongside the per-agent wire
  flush, silently discarding persistence failures from
  suppressTerminalNotification()/wait(). Only the independent wire
  flushes are meant to be best-effort.

* fix(kimi-code): cover every agent's prompt queue in print quiesce

Tracking only the main run's prompt completion left subagent and
background prompts racing the wire flush the same way: the loop reports
idle before that agent's prompt-settle chain dispatches prompt.completed.
Replace the per-handle completion tracking with a uniform wait — after
draining and cancelling, poll every agent's prompt queue snapshot until
none reports an active or pending prompt. settle() clears the active
prompt and dispatches the record in one synchronous block, so an empty
snapshot proves the record is already queued for the flush.

* fix(agent-core-v2,kimi-code): cover the prompt launch window in print quiesce

A termination signal can also arrive while startNext() is mid-launch: the
prompt has left pending and is not active yet, so drain() cannot cancel it
and an active/pending snapshot reads empty. Quiesce would then flush and
exit while the launch still dispatches records afterward.

Expose the service's launching phase on PromptQueueSnapshot and make the
print cleanup's quiesce a repeat-until-idle loop: every pass drains,
cancels, and awaits the loops, then re-checks launching/active/pending, so
a prompt surfacing from the launch window is cancelled on the next pass
instead of escaping the flush.

* fix(kimi-code): freeze loop producers across the print-mode flush

An empty prompt queue is only a point-in-time observation: background
task completions and cron fires enqueue straight into the loop, bypassing
the prompt queue, so a late producer could still start a turn — and new
records — after the journals were flushed. Quiesce now leaves a
quiescence guard held on every loop once queues read empty; the caller
holds the release across the wire flush and app disposal, so late
submissions queue behind the guard and are rejected by disposal instead
of racing process.exit. Loops that refuse the guard (still busy) send the
quiesce into another drain/cancel/settle pass.

* fix(agent-core-v2): flush the wire journal when removing an agent

AgentLifecycleService.remove() quiesced the agent but never flushed its
wire journal: the records reached the append log only through the
fire-and-forget retirement flush, so a process exiting right after a
subagent's removal (e.g. print mode on a termination signal) could
truncate the closing records. Flush the agent's event dispatcher after
the quiesce and before disposal; a persist failure is reported without
blocking the removal.

* fix(agent-core-v2): wait for the prompt queue to go idle before flushing a removed agent

The remove() flush could still snapshot the persistence queue before the
cancelled prompt's final record was appended: loop.settled() resolves in
releaseActiveTurn() before the prompt-settle chain dispatches
prompt.aborted/prompt.completed, and prompt.drain() does not await that
settlement. Wait (bounded) for the prompt queue to report no launching,
active, or pending prompts before flushing; an unreadable snapshot counts
as idle so a wedged service cannot stall the removal.

* chore: widen the print wire-flush changeset to termination signals

* fix(agent-core-v2): re-cancel prompts that finish launching during removal

A prompt mid-launch (startNext awaiting daemon materialization or a
pre-submit hook) is invisible to drain() and has no turn to cancel yet;
the passive idle wait would then let it run to the deadline and flush
before its closing records existed. Repeat drain/cancel/settle on every
pass until the queue reads idle, and once idle hold a quiescence guard
across the flush and disposal so a late producer cannot start new work
in between.

* fix(kimi-code): stop task producers before the print-mode wire flush

Task termination bypasses both the prompt queue and the loop quiescence
guard: AgentTaskService dispatches TaskTerminated straight to the wire,
and disposal would force-stop still-running tasks after the journals were
already flushed. Stop every session agent's tasks up front in the quiesce
phase (mirroring AgentLifecycleService.remove()), so each task's
termination record is dispatched before the flush instead of racing
process.exit. keepAliveOnExit tasks stay exempt, matching remove().

* fix(agent-core-v2): do not let suppression failure short-circuit stopAllOnExit

A detached task's terminal-notification suppression failing (e.g. the
persist write rejects) used to reject the whole stopAllOnExit before
stopAll() ran, so every task stayed active — and callers settling the
rejection (print-mode cleanup, agent removal) proceeded as if the tasks
were stopped, losing their termination records at exit. Settle each
suppression independently, log the failure, and always stop the tasks.
keepAliveOnExit tasks remain exempt by design.

* chore(kimi-code,agent-core-v2): halve print wire-flush tests and trim comments
2026-09-04 18:31:42 +08:00
..
acp-server refactor(acp): remove the legacy acp-adapter package (#3434) 2026-09-01 23:59:20 +08:00
agent-core feat(secondary-model): graduate the subagent model pool out of experimental (#3334) 2026-08-31 15:33:26 +08:00
agent-core-v2 fix(kimi-code): flush wire journals before print-mode exit (#3531) 2026-09-04 18:31:42 +08:00
kaos fix(kaos): resolve Git Bash POSIX paths for file tools on Windows (#2200) 2026-08-20 22:42:16 +08:00
kap-server feat(agent-core-v2): drop the experimental gate from turn-level file history (#3525) 2026-09-04 15:57:59 +08:00
klient refactor(acp): remove the legacy acp-adapter package (#3434) 2026-09-01 23:59:20 +08:00
kosong fix: fail fast on provider-filtered empty responses (#3101) 2026-08-20 11:55:26 +08:00
migration-legacy fix(migration-legacy): stop re-prompting for kimi-cli migration once completed or dismissed (#3467) 2026-09-02 17:04:12 +08:00
minidb fix: drain in-flight persistence and log writes on session close and shutdown (#3122) 2026-08-20 17:19:20 +08:00
node-sdk fix(telemetry): deduplicate session_started and model switch events (#3499) 2026-09-03 16:49:27 +08:00
oauth feat(agent-core-v2): support openai_responses protocol for kimi provider (#3375) 2026-08-31 14:51:21 +08:00
pi-tui ci: release packages (#2932) 2026-08-18 19:19:18 +08:00
protocol feat(agent-core-v2): rework tower mode entry and surface worker deaths (#3399) 2026-09-01 18:03:13 +08:00
telemetry feat(kimi-code): add session rating survey (#3516) 2026-09-04 12:32:24 +08:00
transcript fix(agent-core-v2): keep background questions open past turn end and inline their answers (#3522) 2026-09-03 20:53:09 +08:00
tree-sitter-bash fix(tree-sitter-bash): recognize heredocs in character-level balanced scanning (#3503) 2026-09-03 15:28:11 +08:00