mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-10 17:29:18 +00:00
* feat(agent-core-v2): persist the last turn outcome into session metadata for cold listings A cold session (no live handle) reported no lastTurnReason, so after a server restart the session list could not mark a session whose last turn failed until it was opened and resumed. A new Session-scope SessionOutcomeRecorder subscribes to the activity aggregate's turn_ended changes and persists the outcome (completed/failed) into the session metadata document; the summary pipeline (mirror + cold reader) carries it as SessionSummary .lastTurnReason, and toWireSession falls back to it when no live fact exists. 'cancelled' is deliberately not persisted: it is also what an in-flight turn ends with during scope disposal, and writing there races the host's home-dir teardown. Verified end to end with an isolated home and a dead provider: a turn fails, the server restarts, and GET /sessions reports last_turn_reason=failed without opening the session. * fix(klient): carry lastTurnReason/lastTurnOutcome in the validated contracts Review follow-up: zod strips unknown keys on parse, so the new outcome fields never reached klient callers; add them to the session summary and metadata/patch/key schemas (contract parity test covers the engine mirror). * fix(agent-core-v2): persist user-cancelled outcomes, never teardown aborts Review follow-up: skipping every 'cancelled' left a stale earlier outcome in the metadata (e.g. a prior failed reported for a session whose latest turn was stopped by the user). The recorder now subscribes to the main agent's turn.ended facts directly and keys on interruptReason: user_cancelled is persisted like any other terminal state, while programmatic aborts — including the cancel every in-flight turn suffers during scope disposal — are never written, so no metadata write races the host's home-dir teardown. * fix(kap-server): only fall back to the persisted outcome for cold sessions Review follow-up: a warm session that just started a new turn clears its live lastTurn, and the unconditional ?? fallback would then report the previous turn's persisted outcome for a turn that is still running. SessionFacts now reports whether a live handle exists, and the wire projection only reads the persisted value when the session is cold. * docs(agent-core-v2): keep the outcome-recorder header at role level * fix(agent-core-v2): settle turn outcomes on turn start and drain metadata writes on close Review follow-ups: - a new main turn now clears the persisted outcome (turn.started), so a process that dies mid-retry no longer reports the previous turn's terminal state for a turn that never ended - the dedupe marker only advances after a successful write, so a failed persist no longer suppresses the next identical outcome - session metadata writes are tracked in a module-level pending set with drainSessionMetadataWrites(), awaited by kap-server close alongside the mirror/query-store drains — an event-driven write (e.g. the outcome recorder) can no longer land in a session dir while the host removes it * fix(agent-core-v2): track the metadata dispose flag locally Disposable exposes no public isDisposed accessor; keep a class-local flag set in the dispose override. * fix(kap-server): drain session metadata writes before the mirror and disposal A write still in flight when close() begins must settle before the mirror flushes its summary into the read model and before scope disposal marks the service disposed — not after. * fix(agent-core-v2): reattach the recorder when the main agent is recreated Review follow-up: a failed bootstrap still fires onDidCreate before the handle is dropped; the subscription then pointed at a dead bus and the guard blocked any later reattach. Track onDidDispose and reset so the next main creation attaches cleanly. * test(agent-core-v2): resolve the recorder through the scoped DI harness Review follow-up: construct SessionOutcomeRecorder via registerScopedService + a Session-scope test host (stubbed lifecycle/metadata), so the test covers the production registration path; add the durable-value adoption case. * fix(agent-core-v2): unbreak CI — iterable Promise.all and the debug channel surface - Promise.all takes the pending-writes set directly (oxlint error) - the disposed flag moves into a _register'd marker instead of a public dispose() override, which the debug channels listing (and its test) correctly rejects as framework plumbing * fix(kap-server): surface persisted failures on the v2 session status The v2 list folds the outcome into activity.status, which previously read only live facts — a cold session always looked idle. Cold sessions now map a persisted failed outcome to status 'failed' (completed and cancelled stay idle, matching the live fold); warm sessions are unchanged, and the statuses filter inherits the mapping. * refactor(agent-core-v2): name the persisted field lastTurnReason Aligns with the established name for the same concept end to end (activity view's lastTurnReason, the v1 wire's last_turn_reason, and the SessionSummary mirror), instead of introducing a third variant. * fix(agent-core-v2): drain pending metadata writes before session teardown Review follow-up: closing/archiving a session right after a turn ended could dispose the scope while the outcome write was still queued, and delete() removes the session dir immediately after close. Await the pending metadata writes before the handle goes away. * fix(node-sdk): carry lastTurnReason through the SDK session summary Review follow-up: the in-process SDK path maps the engine summary through v2SummaryToSessionSummary, which dropped the new outcome field. Add it to the public SessionSummary type and the mapper; the parity gate projects it away (the v1 engine never records an outcome). * fix(node-sdk): populate lastTurnReason on live SDK summaries Review follow-up: resumeSession/reloadSession build their summary from the live session's metadata document, which now carries the outcome — surface it there too so the SDK reports it consistently for live and listed sessions. * fix(agent-core-v2): carry the last turn outcome across session forks Review follow-up: fork skips state.json when copying the session dir, so the fork's fresh metadata never had the outcome and a restart dropped a marker the warm fork was still reporting. The fork's metadata patch now inherits the source's lastTurnReason. * fix(agent-core-v2): settle pending outcome writes before reading a fork source Review follow-up: a fork requested right after the source's turn ended could read the metadata before the recorder's queued write landed, inheriting a stale or absent outcome. Drain pending metadata writes first. * fix(agent-core-v2): backfill restored outcomes into the session metadata Review follow-up: for sessions whose last turn ended before this field existed, the cold-resume seed restores the outcome into the activity view without a turn.ended fact, so the recorder never persisted it and cold listings stayed blank. The recorder now also watches the main agent's activity updates and backfills the restored outcome when nothing is persisted yet. * fix(agent-core-v2): never backfill restored cancellations Review follow-up: a restored 'cancelled' cannot be told apart from a programmatic abort (the activity event carries no interruptReason), and those are never persisted. Backfill now covers only completed/failed; user stops are still persisted from the live turn.ended fact. * refactor(agent-core-v2): rename the outcome recorder to outcome mirror Mirror is the codebase's established term for a write side that reflects live state into a store (SessionIndexMirror); Recorder has no precedent. * fix(agent-core-v2): backfill without bumping recency; header-only comments Review follow-ups: - a mere resume must not float an old session to the top of the list: metadata updates accept touchUpdatedAt:false and the outcome mirror's backfill uses it (live outcome writes keep bumping — turn end is a recency moment) - the mirror service's inline notes move into the file header per the package comment convention - drop the redundant |undefined from the SDK's optional outcome field * fix(node-sdk): read the live outcome for resumed session summaries Review follow-up: on a fresh resume the restored outcome can still be queued as a metadata backfill, so the document may lag a tick; the live activity aggregate already holds it. Resume/reload summaries now prefer the live value and fall back to the metadata field. * fix(agent-core-v2): confine the outcome backfill to pure resumes Review follow-up: the view publishes its turn.ended fold before this mirror's own turn.ended handler runs, so a live ending reached the backfill branch first and got persisted without the recency bump. The backfill now only applies when no turn ever started in this process — live endings always take the bumped write. * fix(agent-core-v2): drain the session-index mirror before session teardown Review follow-up: settling the metadata write alone left the fresh summary in the mirror's pending queue, so a list right after close could read a stale outcome from the read model. close/archive now also drain ISessionIndexMirror. Test harnesses register a mirror stub for the new dependency. * docs(agent-core-v2): fold the metadata drain contract into the file header * chore: include the SDK package in the changeset; fold the drain note into the header * fix(agent-core-v2): backfill restored cancellations too, quietly Review follow-ups: dropping every restored cancel loses legitimate user stops whose live write never landed (or was rejected) before a restart — cold surfaces never mark cancelled anyway, so healing them is harmless and strictly more accurate. The metadata disposal note moves into the file header per the comment convention. * fix(node-sdk): prefer the live outcome over the index in SDK listings Review follow-up: a live session that just started a new turn after a failure can briefly keep the stale outcome in the index while the mirror's clear is queued. listSessions now reads the live activity aggregate for warm sessions, matching the kap-server cold-only fallback. * fix(node-sdk): never read the metadata outcome for a live session Review follow-up: with a retry in flight the live aggregate has no outcome while the document may still hold the previous failure — the fallback showed the stale one. Live summaries now take the live aggregate's answer alone; the restored outcome is already seeded there on resume. |
||
|---|---|---|
| .. | ||
| examples | ||
| scripts | ||
| src | ||
| test | ||
| api-extractor.json | ||
| CHANGELOG.md | ||
| package.json | ||
| README.md | ||
| tsconfig.api-extractor.json | ||
| tsconfig.dts.json | ||
| tsconfig.json | ||
| tsdown.config.ts | ||
| vitest.config.ts | ||