Skip to content

fix(transcript): preserve steer provenance - #3374

Merged
chengluyu merged 2 commits into
mainfrom
refactor/prompt-origin-projection
Aug 30, 2026
Merged

fix(transcript): preserve steer provenance#3374
chengluyu merged 2 commits into
mainfrom
refactor/prompt-origin-projection

Conversation

@chengluyu

@chengluyu chengluyu commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

Required by MoonshotAI/kimi-code-app#423; no standalone issue.

Problem

When a queued user prompt is steered into a running turn, kap-server projects it as a transcript user text frame. That frame kept the user text and prompt IDs but dropped the structured Skill activation provenance, so clients could not reconstruct a multi-Skill message without parsing rendered instruction text.

What changed

  • Add a wire-safe user origin to transcript user text frames, containing only ordered Skill names and optional arguments.
  • Preserve it through immediate, pending, turn-end, mid-attach, and cold-rebuild steer paths.
  • Reject origin on assistant text frames at both the TypeScript and Zod contract boundaries.
  • Leave prompt REST/events, klient, and agent-core contracts unchanged.

Verification

  • Transcript and kap-server typechecks pass.
  • 171 focused transcript tests pass.
  • 99 transcript package tests pass.
  • 1,169 non-search kap-server tests pass; one fs-watch timing test passed on isolated rerun.
  • Full lint passes with baseline warnings only.
  • Full search tests are blocked locally because this Node runtime rejects the existing --experimental-transform-types worker flag.
  • Read-only diff audit passed with no P1/P2 findings.

Checklist

  • I have read the CONTRIBUTING document.
  • This internal change is linked to the downstream PR above.
  • I have added tests that prove the fix works.
  • Ran gen-changesets; this internal wire fix needs no changeset.
  • No documentation update is needed.

@changeset-bot

changeset-bot Bot commented Aug 30, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 300c3dc

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-30T14:17:46.448984Z 300c3dc Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@pkg-pr-new

pkg-pr-new Bot commented Aug 30, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@300c3dc
npx https://pkg.pr.new/@moonshot-ai/kimi-code@300c3dc

commit: 300c3dc

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c1f538bd5

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/kap-server/src/services/transcript/coreEventMap.ts Outdated
Comment thread packages/agent-core-v2/src/agent/prompt/promptService.ts Outdated
Comment thread packages/protocol/src/events.ts Outdated
@chengluyu

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c1f538bd5

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/kap-server/src/routes/prompts.ts Outdated
@chengluyu chengluyu changed the title fix(transcript): preserve bundled prompt origin fix(transcript): preserve steer provenance Aug 30, 2026
@chengluyu

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 300c3dc614

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chengluyu
chengluyu merged commit cbe0a77 into main Aug 30, 2026
17 checks passed
@chengluyu
chengluyu deleted the refactor/prompt-origin-projection branch August 30, 2026 14:41
YeKc1M added a commit to YeKc1M/kimi-code that referenced this pull request Sep 4, 2026
* fix(cli): use the unicode ellipsis in user-facing interface text (#3366)

Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>

* fix(cli): validate config.toml against the v2 schema in kimi doctor (#3372)

* fix(transcript): preserve steer provenance (#3374)

* fix(transcript): preserve bundled prompt origin

* refactor(transcript): narrow steer origin projection

* fix(transcript): preserve turn prompt identity (#3377)

* fix(transcript): preserve turn prompt identity

* fix(transcript): backfill active prompt identity

* fix(transcript): seed late-bound turn identity

* fix(transcript): persist turn prompt identity

* fix(transcript): skip undone prompt identities

* fix(transcript): hide undone continuation turns

* docs(agent-core): update wire manifest

* fix(transcript): match cold turns by prompt identity

* fix(transcript): match internal prompt turns by origin

* fix(transcript): align undo anchors with context

* fix(transcript): prioritize cold turn matches

* fix(transcript): retire unmatched turn boundaries

* style(transcript): align cold matcher

* fix(agent-core-v2): spawn tower workers on dirty base (#3346)

* feat(agent-core-v2): spawn tower workers on a snapshot of base checkout WIP

Tower worktrees were created from the base branch tip, so a worker never
saw uncommitted changes sitting in the base checkout — it would start
building on a foundation that did not exist in its worktree.

When a mission branch is first created, the store now captures the base
checkout's dirty paths (staged, unstaged, and untracked per git status;
.tower/ and git's own ignore rules excluded; unmerged paths refuse the
spawn) into a synthetic snapshot commit built through a temporary index
(read-tree + add + write-tree + commit-tree), so the user's checkout,
index, and base branch are never touched. The mission branch starts at
that commit and the mission records it as spawnBase.

The merge gate diffs the branch from spawnBase instead of the base tip,
so snapshotted WIP is never mistaken for a worker scope violation, and
the reviewer briefing diffs from the same point. Alternatives
considered: applying the WIP as uncommitted changes inside the new
worktree (fragile — it mixes into the worker's first commit and can be
lost before that), and excluding the WIP file set inside the gate
(permanent holes in scope enforcement, hidden provenance). A snapshot
commit keeps the gate strict and makes the WIP an explicit, mergeable
part of the branch history.

TowerMerge now also refuses to merge while the main checkout holds
uncommitted changes in files the merge would overwrite (blocked reason
base-dirty) and tells the user to commit or stash them first; dirt that
does not intersect the merge no longer blocks it.

* fix(agent-core-v2): harden tower base-WIP snapshot edge cases

- fall back to the base branch as diff base once a rebase drops the
  snapshot commit (it is only used while still an ancestor), so scope
  checks, reviewer prompts, and conflict attribution stop blaming base
  changes on the worker
- run snapshot index commands from the worktree top-level and filter
  .tower by path segment, fixing dirty-base spawning from a repo
  subdirectory (porcelain paths are worktree-root relative)
- refuse to snapshot WIP collected from a checkout that is not the
  recorded base (or a detached HEAD) instead of mixing another
  branch's content into base history

* fix(agent-core-v2): let tower mode take over from a live but idle owner session

The tower-mode ownership check refused entry whenever the recorded
owner session was still materialized in the process. kap-server keeps
sessions materialized until explicit close, so a session that stopped
abnormally (closed tab, failed turn) owned the workspace tower forever
and no second session could enter tower mode.

Now the owner is only protected while actually occupied: entry is
refused when the owner session has an active turn or a pending
interaction; a live but idle owner is exited remotely (durable
TowerModeExit in its own event log) and the entering session takes
over.

* feat(agent-core-v2): keep tower mode active after tower teardown

* chore: add changeset for tower teardown staying active

* docs(tower): merge changeset

* docs(tower): merge changeset

* fix(agent-core-v2): make tower mode mutually exclusive with plan and swarm modes

* chore: add changeset for tower mode mutual exclusion

---------

Co-authored-by: konghuanjun <konghuanjun@moonshot.ai>

* fix(agent-core-v2): persist prompt resolution events (#3371)

* fix(agent-core-v2): persist prompt resolution events so replays can reconcile queued prompts

* docs(changset): update prompt desc

---------

Co-authored-by: konghuanjun <konghuanjun@moonshot.ai>

* feat(agent-core-v2): support openai_responses protocol for kimi provider (#3375)

* feat(secondary-model): graduate the subagent model pool out of experimental (#3334)

* feat(secondary-model): enable the subagent model pool by default

* feat(secondary-model): graduate the subagent model pool out of experimental

* fix(secondary-model): honor the v2 default_model key on the legacy engine

* fix(secondary-model): enforce forced subagent pools on the legacy engine

* fix(tower): keep reviewers on primary model

* fix(secondary-model): live-apply picker saves and replace the legacy model key

* fix(secondary-model): accept default_model in the live-apply setter and clear on removal

* fix(secondary-model): revert the legacy v1 engine, keep the v2 pool opt-out

* feat(secondary-model): graduate pool with model source telemetry

* fix(secondary-model): keep legacy engine opt-in

* test(sdk): pin secondary-model engine divergence

* fix(tower): honor forced model for reviewers

* fix(cli): default the workspace trust prompt to "Trust this folder" (#3391)

* feat(agent-core-v2): preserve config.toml formatting on writeback (#3392)

* feat(agent-core-v2): preserve config.toml formatting on writeback

Config persistence previously re-serialized the whole document on every
write, destroying user comments, key order, and blank lines. Writes now go
through a raw-text channel on the TOML document store: the file is scanned
into top-level domain regions, changed domains are diffed at key level so
only edited statements are rewritten, and untouched regions keep their
original bytes (including CRLF). The effort max-to-high migration performs
a single-line text replacement instead of a full rewrite.

Ambiguous constructs (dotted keys, arrays of tables, unmapped files) fall
back to re-serializing the affected domain, and any scanner failure falls
back to the previous whole-document write. Byte-identical results skip the
write entirely.

* feat(agent-core-v2): support quoted table headers in config writeback

The region scanner parsed only bare-key table headers, so files using
quoted segments such as [models."acme/m1"] or ["x.y"] fell back to a
whole-document rewrite, dropping user comments for exactly the configs
with the most hand-written content. Header parsing now walks TOML key
paths segment by segment (bare, basic-quoted with escape decoding,
literal-quoted), so quoted regions participate in key-level preservation
and are edited or removed in place. Emission of new sub-table headers
already quotes non-bare segments through smol-toml. Unparseable headers
still decline to the whole-document fallback.

* feat(agent-core-v2): require approval for dangerous bash commands in all permission modes (#3290)

* feat(agent-core-v2): require approval for dangerous bash commands in all permission modes

* feat(agent-core-v2): deny dangerous commands in auto mode, unwrap command launchers, and skip the guard for non-interactive hosts

* feat(agent-core-v2): support disabling the dangerous-command guard via config

* test(node-sdk): project v2's env-materialized empty permission section in config parity

* docs: add Remote Control guide (zh/en) (#3398)

* feat(agent-core-v2): add P0 telemetry events for auth, execution, and degradation paths (#3394)

* feat(agent-core-v2): add P0 telemetry events for auth, execution, and degradation paths

* test(agent-core-v2): drop telemetry emission assertions from existing test suites

* feat(cli): rename permission modes to Always Ask, Ask When Needed, and Never Ask (#3403)

TUI copy for the three permission modes (manual/yolo/auto) now uses the
new display names and descriptions across the /permission selector,
footer badge, toggle notices, goal/swarm start prompts, session replay,
and /status. The /yolo and /auto commands are renamed to
/ask-when-needed and /never-ask, with the old names kept as aliases.

* refactor(agent-core-v2): replace agent runtime with agent-scoped DI services (#3402)

* refactor(agent-core-v2): migrate todo domain to agent-scoped DI service

* refactor(agent-core-v2): migrate skill domain to agent-scoped DI service

* refactor(agent-core-v2): migrate reminder domain to agent-scoped DI service

* refactor(agent-core-v2): migrate interaction domain to agent-scoped DI service

* refactor(agent-core-v2): migrate cron domain to agent-scoped DI service

* refactor(agent-core-v2): migrate dateChange domain to agent-scoped DI service

* refactor(agent-core-v2): migrate goal domain to agent-scoped DI service

* refactor(agent-core-v2): remove agent runtime infrastructure

* docs(agent-core-v2): rewrite agent domain standard as agent-scoped DI service

* fix(agent-core-v2): restore actor services on late feature re-provide and order agent-created events after metadata registration

* docs: rename permission modes to Always Ask, Ask When Needed, and Never Ask (#3406)

Follow-up to #3403 for the user docs: living pages (en + zh mirrors)
now use the new mode names and descriptions — slash-commands and
interaction references for /ask-when-needed (aliases /yolo, /yes) and
/never-ask (alias /auto), CLI flag and config glosses, guides,
customization pages, and the docs AGENTS.md terminology table. Wire
and config ids (manual/yolo/auto) are unchanged; release notes are
historical and untouched.

* feat(cli): compress native update artifacts and decompress them while staging (#3405)

* feat(cli): compress native update artifacts and decompress them while staging

Co-authored-by: qer <wbxl2000@outlook.com>

* fix(cli): generate compressed native artifacts in the publish job

The zip's checksum never pairs with the bare executable the updater
verifies after inflating, and artifacts produced in the matrix job never
leave the runner (the workflow's upload-artifact path lists only the
zip). Extract each zip in the publish job, hash the bare executable, and
emit the .zst/.tar.gz artifacts there so the manifest entry pairs
checksum with what compressed inflates to, and everything new reaches
the release via the existing upload glob — no workflow changes needed.

Co-authored-by: qer <wbxl2000@outlook.com>

* fix(cli): keep the .exe suffix in windows manifest filenames

The updater's bare-binary fallback downloads entry.filename, and the CDN
layout carries .exe on Windows — without it the fallback 404s. The .zst
and .tar.gz artifact names stay unchanged. Also fold the manifest
coverage into the pre-existing release-artifacts test (its fake-zip
fixture predates extraction) and pin the end-to-end chain there.

Co-authored-by: qer <wbxl2000@outlook.com>

---------

Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
Co-authored-by: qer <wbxl2000@outlook.com>

* fix(agent-core-v2): allow sessions without valid models (#3411)

* fix(agent-core-v2): allow sessions without valid models

* fix(agent-core-v2): wait for model initialization

* fix(agent-core-v2): align session lifecycle dependencies

* refactor(agent-core-v2): deliver the subagent fork notice via reminder injection (#3412)

* fix(agent-core-v2): parse git status porcelain with -z for non-ASCII paths (#3415)

git status --porcelain=v1 without -z C-quotes non-ASCII paths under
git's default core.quotePath, and parsePorcelain consumed the quoted
form verbatim while the posix() helper turned each \3xx octal escape
into a fake path segment — the changes tree then split those segments
on '/' and rendered Chinese filenames as bogus directory chains, and
diff requests for such entries failed the same way.

Run porcelain with -z (NUL-separated, never quoted; rename records are
XY new\0old with the new path first) and drop the posix() helper —
porcelain already emits '/' separators on every platform. The v1 engine
shares the bug and is intentionally left unchanged for now.

Refs #3414

Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
Co-authored-by: liruifengv <liruifeng1024@gmail.com>

* Delete GOAL.md (#3416)

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* test: catch fixtures up with the model-validation removal (#3418)

#3411 dropped two positional constructor params from
WorkspaceInstanceManager, shifting the agent-profile stub the
Reflect.construct fixture pins by index, and turned the broken
subagent-pool session create from VALIDATION_FAILED into a success;
both suites fail on main since then.

Co-authored-by: user <user@userdeMacBook-Pro.local>

* fix(agent-core-v2): re-remind subdirectory AGENTS.md after context compaction (#3409)

* fix(agent-core-v2): re-remind subdirectory AGENTS.md after context compaction

Deliver the discovery reminder through the reminder runtime's register()
channel so it re-injects whenever the previous reminder leaves the context
(compaction, /clear, or undo), instead of firing a one-shot notify() that
compaction silently drops while the known-set survives.

Discovery bookkeeping splits into agentsMdReminder.pending (discovered, not
yet read) and agentsMdReminder.known (injected or read); the provider injects
only pending paths not covered by the last injection's disclosure. A newly
created AGENTS.md lands in pending until read; a modified one counts as
injected.

* fix(agent-core-v2): drop deleted AGENTS.md from reminder bookkeeping

A discovered-but-unread AGENTS.md that gets deleted stayed in
agentsMdReminder.pending, so the next re-injection after context loss
pointed the model at a file that no longer exists. Remove deleted paths
from both the pending and known sets on the watcher event.

* Delete .changeset/agents-md-reminder-compaction-reset.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

---------

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* feat(agent-core-v2): report enabled experimental flags in session_started telemetry (#3419)

* feat(agent-core-v2): report enabled experimental flags in session_started telemetry

Add a sorted, comma-separated experimental_flags property to the v2
session_started event so feature-gated metrics gain a session-granular
exposure denominator, and carry the post-apply enabled set on the TUI
experimental_features_apply event to bound mid-session flag flips.

* feat(node-sdk): carry experimental flags on the harness session_started row

The v2 in-process path emits session_started twice (engine-side from
SessionLifecycleService, harness-side from KimiHarness), and only the
engine row carried experimental_flags, so consumers could double-count
or miss the flag dimension. Merge a per-emission dynamic getter into the
harness row, wired to the in-process engine's flag service, so both
rows report the same enabled flag set.

* fix(node-sdk): keep experimental_flags canonical on session_started

A caller-supplied experimental_flags in per-call sessionStartedProperties
could overwrite the engine-owned dynamic value, breaking row-to-row flag
consistency. Merge the dynamic properties after the session-scoped ones
so engine-owned keys always win.

* fix(agent-core-v2): count tower as exposure only once assembled

The tower flag reacts live to mid-process flips, but TowerFeature's
tools and profiles are assembled at App scope construction, so a session
started after an in-process flip cannot actually use tower. Filter it
out of experimental_flags on both session_started producers unless
isTowerFeatureAssembled says the feature is assembled in this process,
keeping the exposure denominator honest.

* test: recalibrate fixtures for the added constructor param and drop timing-sensitive tower assertion

The WorkspaceInstanceManager test builds the service with positional
args; the new flags param shifted unitHostFactory one slot. The tower
inclusion assertion in the SDK integration test depended on feature
assembly winning the race against async config load, which slow CI
runners lose; tower assembled-state coverage stays with the tower
service tests.

* refactor(agent-core-v2): move flag exposure gating into the flag definition

Telemetry consumers hardcoded tower's assemble-at-startup semantics to
keep it out of experimental_flags until assembled. Push the gate into
FlagDefinitionInput as an optional isExposed predicate owned by the
flag's own domain, expose it as IFlagService.exposedIds(), and let both
session_started producers call it — no feature-specific knowledge leaks
into the SDK or the session lifecycle.

* fix(agent-core-v2): drop compaction mechanics from the AGENTS.md discovery reminder (#3420)

* fix(agent-core-v2): drop compaction mechanics from the AGENTS.md discovery reminder

The re-injection trigger is harness mechanics the model cannot act on, and the unread-path condition never fires from the model's perspective. End the reminder at the actionable instruction.

* fix(agent-core-v2): reword the AGENTS.md discovery reminder lead

Lead with the files instead of the paths, and replace harness vocabulary (touched / covered by / injected instructions) with terms the model can place: apply to, your system prompt.

* feat(agent-core-v2): rework tower mode entry and surface worker deaths (#3399)

Tower mode is now entered only manually — /tower on, or /tower
<base-branch> to also pin the local branch missions merge back into. The
agent can no longer enter it on its own: TowerInit refuses while the mode
is off and points at the slash command.

/tower <base-branch> is deterministic end to end: a missing base branch is
created from the current checkout (uncommitted changes committed onto it
as a labeled WIP snapshot), the checkout switches to it, and the tower
workspace is initialized immediately instead of relying on the model to
apply the base. With an existing workspace the tower rebases onto the
requested base when no missions are open and refuses naming the blocking
missions otherwise. The base rides the tower_mode.enter event into the new
tower.base state key and TowerInit falls back to it.

Tower agent deaths (failed/timed_out/killed/lost) are recorded in the
tower protocol: TowerStatus marks dead roster entries and warns about
missions whose owner died, with a resume hint. The tower console prompt
now requires a per-worker deliverables summary before TowerTeardown.

The session profile REST surface accepts tower_base so web clients can
turn tower mode on with /tower <base-branch> instead of sending the
argument as a prompt.

Co-authored-by: konghuanjun <konghuanjun@moonshot.ai>

* refactor(agent-core-v2): simplify the default system prompt (#3390)

* perf(agent-core-v2): fork sessions without materializing the target (#3421)

* fix(agent-core-v2): persist plan.revision as agent-relative key

- replace the session-scoped `path` field in durable plan.revision records
  with an agent-relative `key`, resolved to a display path at read and
  projection time against the current agent/session scope
- migrate legacy `path` records during wire restore and rewrite the journal
  once migration succeeds, emitting low-cardinality
  `wire_plan_revision_migrated` telemetry
- tolerate journal truncation during the migration rebuild and keep the
  legacy `path` display in cold transcript folds for unmigrated records
- keep external transcript marker `path` and meta `reviewPath` projections
  unchanged

* perf(agent-core-v2): fork sessions without materializing the target

- copy session files byte-for-byte (wire.jsonl included, parallel file
  writes) and append the forked marker per agent instead of parsing and
  rewriting every wire journal
- write the forked session's state.json, agent registry, and session
  index entry directly without creating a live session or agent scopes;
  fork returns SessionMeta and SessionForkedEvent drops the scope handle
- keep turnIndex truncation on the per-record path
- kap-server fork/createChild routes, the klient facade and wire
  contract, and the node-sdk forkSession resume the forked session
  through the normal resume path when a live handle is needed
- stop healing truncated source wires during fork; the forked session
  repairs its own copy lazily on resume
- add the `kimi fork [--cwd] [-y]` CLI command

* feat(kimi-code): allow overriding the remote control relay origin via env (#3424)

* fix(agent-core-v2): reproject a stale session index at startup (#3422)

- add mtime to the file system storage service (node-fs stat, memory write clock)
- record the source max mtime in the session index checkpoint at projection
- compare the cheap mtime signal before adopting a persisted manifest on prepare
- refresh the checkpoint mtime after reconcile so warm starts stay scan-free

* fix(agent-core-v2): let experimental config override the master flag env (#3427)

* feat(cli): add the kimi session list subcommand (#3425)

* feat(cli): add the kimi session list subcommand

- add the session command group with list: cwd scope by default, --all/--cwd/--archived/--limit/--json
- pass includeArchived through the SDK listSessions options (v2 klient query, v1 includeArchive mapping)

* docs: condense the session list changeset to one sentence

* fix(cli): sanitize session list rows and tidy option types

- strip control characters and line breaks from user-controlled row fields
- declare cwd/limit as plain optional properties without undefined unions

* feat(agent-core-v2): persist step retry and interrupt events to the wire (#3428)

* feat(agent-core-v2): persist step retry and interrupt events to the wire

* feat(transcript): create the missing interrupted step in the cold fold

* docs(transcript): add SDK contract document (#3432)

* docs(transcript): rewrite SDK document against the current contract (#3437)

* docs(transcript): add SDK contract document

* docs(transcript): rewrite SDK document against the current contract

* refactor(acp): remove the legacy acp-adapter package (#3434)

* refactor(vis): migrate vis from agent-core v1 to agent-core-v2 (#3438)

* refactor(vis): migrate vis from agent-core v1 to agent-core-v2

- swap vis-server engine deps to @moonshot-ai/agent-core-v2, drop kosong
- rebuild the wire record union from v2 durable payload types
- fold token_counting records into the context-window fill
- read cron state from wire records alongside legacy cron files
- read agent parent/swarm metadata from state.json labels
- align context projection and web rendering with the v2 wire vocabulary
- bundle agent-core-v2 into the vis-server build

* fix(vis): replay legacy compactions per engine rules, tolerate bad cron payloads

- treat every record without keptUserMessageCount (or with an explicit
  legacyTail flag) as a verbatim-tail compaction, matching the engine's
  readContextCompactionShapeInput instead of gating on compactedCount
- derive tokensAfter from the reconstructed shape when the record omits
  it, instead of keeping the stale pre-compaction fill
- skip malformed cron.delete / cron.cursor payloads instead of throwing

* refactor(vscode): migrate the webview data layer from ahooks to TanStack Query (#3440)

* fix(vscode): keep current and root work dirs visible in directory picker

* refactor(vscode): migrate the webview data layer from ahooks to TanStack Query

* fix(agent-core-v2): allow Bash cwd outside the workspace roots (#3444)

- drop the built-in escape assertion from RuntimeWorkspaceView.resolve so it is a pure path mapping
- return the validated path from assertAllowed and compose it explicitly in terminalService
- add a bash test covering cwd outside the workspace roots

* fix(migration-legacy): faithfully migrate kimi-cli user data into kimi-code (#3446)

* fix(migration-legacy): faithfully migrate kimi-cli user data into kimi-code

* fix(migration-legacy): faithfully migrate kimi-cli user data into kimi-code

* fix(kap-server): report the real event watermark as last_seq in getSession (#3436)

* fix(kap-server): report the real event watermark as last_seq in getSession

GET /api/v1/sessions/{id} hardcoded last_seq to 0, so event subscribers
catching up from the fetched watermark always replayed the whole session
journal from seq 0. Historical work_changed frames then surfaced as
spurious busy state in clients. Return the broadcaster's journal cursor
(live seq, or the persisted watermark for cold sessions) so subscribers
land on the journal tail with an empty replay.

* fix(kap-server): capture the event cursor before session state in getSession

A profile update landing between the summary read and the cursor read
could produce a response pairing stale fields with a cursor that already
covers the update event; subscribers from that last_seq would then skip
the event entirely. Capture the cursor first so every state read is at
least as new as the watermark; later events still replay past it.

The watermark test now relies on the dispatch queue ordering behind
getCursor instead of wall-clock polling.

* feat(kap-server): add POST /workspaces/{id}/add-dir endpoint (#3451)

* chore: sync web dist from code-app (#3454)

code-app: d2636232d883f10ce17af968b51c592fbf0ce725

* ci: release packages (#3347)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* feat: add experimental turn-level file history snapshots (#3339)

* feat(agent-core-v2): add experimental turn-level file history snapshots

Back up the original content of every file the Edit/Write tools touch
(whole-file blob on first touch, captured through the tool executor's
will-execute hook so the read races nothing) and version all tracked
files at each main-agent turn boundary — a checkpoint at turn start and
one at turn end, so edits the user makes between turns attribute to no
turn. Unchanged files deduplicate by content hash; files past the 4 MiB
cap record an oversize sentinel fingerprinted by size and mtime; durable
checkpoint events are delta-encoded and fold back into replayable agent
state; reads (per-turn changes, checkpoint content) are computed from the
blobs on demand and serialize with writes. Gated behind
KIMI_CODE_EXPERIMENTAL_FILE_HISTORY (default off).

* feat(kap-server): serve turn-level file history over REST

GET /sessions/{session_id}/file-history/changes returns one turn's exact
per-file additions/deletions from the daemon's whole-file checkpoints;
/file-history/content returns a file's full content at either checkpoint
boundary. Persisted sessions resume on demand, matching the transcript
routes' cold-session behavior.

* fix(agent-core-v2): drain queued snapshots on agent teardown, single-sentence changeset

Register the snapshot queue with the unit ledger so agent-scope disposal
waits for an in-flight end checkpoint instead of racing runtime and log
teardown, and fold the changeset's enablement note into one sentence per
the changeset format rule.

* fix(agent-core-v2): bound aggregate LCS work per changes() call

Each file's line-count diff had its own 4M-cell LCS budget, so one
changes() request over a turn that rewrote hundreds of files could sum
to hundreds of millions of synchronous DP cells on the server event
loop (and on the snapshot queue). A per-call aggregate budget (16M
cells) is now threaded through diffChange/countLineDiff; files past the
budget fall back to the existing oversize no-counts marker. Files over
the per-file cap short-circuit without consuming aggregate budget.

* refactor(agent-core-v2): store per-turn checkpoint deltas instead of cumulative maps

Each checkpoint previously materialized the full session-wide entry
table, so changes() walked every file the session ever touched --
blob-reading and diffing files the turn never modified. Checkpoints now
keep only their own delta (entryAt already resolves by walking back);
when the cap evicts old checkpoints their entries fold into the new
head so resolution, maxVersion, and blob retention stay correct.
changes() derives its path set from the end checkpoint's delta, which
is exactly the files the turn touched.

* fix(agent-core-v2): gate live reads on the actually active turn

A start checkpoint without a matching end previously counted as live
whenever it was the latest checkpoint, so a session reloaded after a
crash or a lost end write compared that checkpoint against the current
workspace and attributed unrelated edits to the interrupted turn. The
service now tracks the active turn from TurnStarted/TurnEnded and takes
the live-disk path only while that turn is genuinely running; a cold
session reports no changes for an unpaired start instead.

* fix(agent-core-v2): reset file history in turn-sliced forks

A turn-indexed fork slices the journal at the next turn's first user
record, and the asynchronously written end checkpoint of the forked-at
turn can land after that boundary, leaving the fork with partial file
history. Instead of teaching the slicer to chase late records, the
slice now drops all file_history records: a turn-sliced fork starts
with an empty snapshot store and re-captures baselines on first touch,
while full forks copy the journal unchanged and keep complete history.

* fix(agent-core-v2): settle snapshots before fork copy, prune sliced-fork blobs

A fork accepted right after a turn completes could copy the blob
directory before the queued end checkpoint wrote its blobs, then copy a
journal that references them; fork() now awaits each live agent's file
history settling before copying. Turn-sliced forks drop file_history
records but previously kept every copied snapshot blob unreachable on
disk; pruneTruncatedForkFiles removes the file-history directory
alongside tasks and cron.

* fix(agent-core-v2): capture subagent edits into the main agent's file history

Non-main agents previously registered no tool hook, so a file first
touched by a delegated subagent had no baseline backup and never
appeared in the turn's changes. Subagent services now route their
file_io captures to the main agent's service, which records the
pre-image against its currently active turn; the existing end-of-turn
checkpoint then picks up the file's final state from disk.

* fix(agent-core-v2): hold loop quiescence on source agents while forking

The active-turn precheck and snapshot drain did not stop a prompt that
arrives mid-fork from starting a turn between the file copy and the
journal copy, letting the fork pick up journal records whose blobs were
written after the directory copy. fork() now acquires loop quiescence
on every live source agent (the undo/compaction idiom) and holds it
through both copy phases; prompts submitted meanwhile are held by the
loop and re-admitted on release.

* feat(agent-core-v2): retain file history for a five-turn sliding window

The 400-checkpoint cap with fold-on-eviction kept every touched file's
resolution (and its blobs, v1 forever) for the session's lifetime, so
disk and the per-boundary tracked-file scan both grew without bound.
Retention becomes a queue over the last five turns: checkpoints older
than the window are dropped outright, the tracked set shrinks to files
appearing in the remaining deltas, and their blobs -- v1 included --
are evicted. A file edited again after leaving the window re-captures
a fresh v1 baseline. Reads outside the window return empty and the
client already degrades to its local stats for those turns; the fold
machinery and the v1-forever rule are deleted.

* feat(agent-core-v2): capture a per-turn baseline so turns are self-contained

capture() previously fired only on a file's first touch in the session,
so a later turn's before-image resolved by walking back into older
turns' entries -- the cross-turn dependency that made window pruning
able to misreport an edge turn's modification as an addition. Every
turn now records its own baseline at first touch: when the pre-image
hash matches the latest known entry the entry is copied with its
existing blob key (no new content written), otherwise a new version is
backed up. changes()/contentAt() resolve within the turn's own start
checkpoint, and the prune-time fold remains only as the backstop for
files changed out-of-band mid-turn.

* refactor(agent-core-v2): turns record only their own tool snapshots, reads never walk back

Simplify the model to exactly what the feature displays: a turn records
the before-image of each file its tools touch (at first touch) and the
after-image of those same files at turn end, compared against the
turn's own baseline. changes() and contentAt() are direct lookups in
the turn's two checkpoints -- no cross-turn resolution, so the
prune-time fold and the walk-back helpers are deleted, the start
boundary scan is gone, and the live path iterates the turn's touched
files instead of every tracked file. An empty end record still lands on
turns without edits so the retention window keeps advancing.

Semantics change: files modified only by external means during a turn
(no tool touch) no longer appear in that turn's changes, and deletions
are recorded only for tool-touched files -- the turn diff now covers
exactly the tool activity, matching the client's row set.

* feat(kap-server): report file-history availability on the changes response

An empty changes list is ambiguous for clients: the flag may be off, or
the turn's checkpoint may have left the retention window. Carry the
service's enabled state so clients can tell the two apart.

* fix(agent-core-v2): retain the last five recorded turns, not five turn ids

Cancelled queued turns leave gaps in the ordinal sequence, so id
arithmetic evicted more history than the advertised window; retention
and blob eviction now keep the newest five distinct recorded turns. The
changeset sentence also catches up with the per-turn snapshot scope.

* fix(agent-core-v2): count only completed turns in the file-history window

A crash between a turn's first capture and its end checkpoint leaves a
start-only turn that used to occupy a retention slot and shrink the
usable window; retention and blob eviction now count turns with an end
record, dropping stale start-only leftovers while preserving anything
newer than the latest completed turn. The flag catalog description also
catches up with the per-turn snapshot scope.

* fix(agent-core-v2): flush the end checkpoint before evicting displaced blobs

dispatch queues the durable append without waiting for it, so a crash
between the window advancing and the journal flush could leave the old
checkpoints on disk with their blobs already deleted; the journal is now
flushed before any displaced blob is removed.

* fix(agent-core-v2): size snapshot reads to the statted file

Every snapshot read requested the 4 MiB limit, and the local fs backend
allocates the requested length up front — a turn touching many small
files paid hundreds of megabytes of zero-fill. Request the statted size
plus one byte instead; growth past the stat still surfaces as a length
mismatch, and a file already at the limit keeps the oversize path.

* fix(agent-core-v2): keep file-history blobs out of session exports, sweep crash orphans

Session export packed the whole session directory, shipping up to five
turns of whole-file snapshots inside the zip; the blob directory is now
excluded. A crash between the checkpoint flush and blob eviction could
also strand blobs no surviving checkpoint references — the first end
checkpoint of a session now sweeps unreferenced file-history blobs
once.

* feat(agent-core-v2): retain file history for the thirty most recently active sessions

Snapshots previously accumulated across every session a workspace ever
ran. A per-workspace LRU (persisted beside the sessions) is touched on
each end checkpoint; when it exceeds thirty sessions the least recently
active one's snapshot blobs are removed. An evicted session simply has
no snapshots — resuming it re-enters the window and rebuilds baselines
on the next edit, and a session evicted while idle self-heals because
blob writes recreate their directories.

* fix(agent-core-v2): keep the retention ledger out of the session listing

The per-workspace LRU document lived inside sessions/<workspace>, where
listSessionIds enumerates directory entries as session-id candidates;
it now lives in its own top-level file-history scope keyed by workspace
id.

* fix(agent-core-v2): review round — editing-turn window, full blob hashes, tests in-tree

Editless turns no longer emit end checkpoints, so pure chat neither
grows the wire journal nor evicts real edit history — the window now
keeps the last five editing turns. Blob keys use the full path hash
(truncation could collide and interleave histories), a lost blob
degrades its row to a countless marker instead of misreporting status,
and the window rule lives in one shared helper used by both the reducer
and blob eviction. The fork guard gets an honest message about
concurrent holds plus its own changeset, and the service/route/window
suites move into the tree with new unit coverage for the window helper
and diff budget.

* feat(agent-core-v2): report whether a turn's history is recorded

The changes response gains a recorded flag — true when the turn has a
start checkpoint and either its end checkpoint or a live turn — so
clients can tell an authoritative empty result from a turn whose
records were never made, lost to a crash, or displaced by retention.

* fix(agent-core-v2): recorded probes blob availability, content falls back for unchanged files

turnRecorded now verifies a keyed blob still exists, so a session whose
snapshots were displaced by the session window stops claiming authority
and clients keep their local rows. contentAt(end) resolves a file the
turn left unchanged from its start entry instead of returning nothing,
and session eviction deletes blobs before updating the ledger so a
crash retries the deletion instead of stranding it.

* fix(agent-core-v2): satisfy lint on the recorded probe

* fix(agent-core-v2): keep the retention ledger honest across eviction failure, fork and delete

A victim whose blob removal hits an IO error stays in the ledger for a
later retry instead of being delisted with its blobs stranded. A full
fork that copied snapshot blobs now enters the target session into the
ledger, so repeated forks cannot hold history outside the session
window, and deleting a session drops its ledger entry so ghost rows no
longer displace live sessions.

* chore(agent-core-v2): regenerate the wire manifest after the merge

* fix(agent-core-v2): count a trailing-newline-only change in authoritative stats

The daemon's line splitter adopts the client's last-line sentinel so a
file differing only in its trailing newline reports 1/1 instead of 0/0,
keeping authoritative counts in agreement with the client. Closes the
follow-up tracked in #3449.

---------

Co-authored-by: user <user@userdeMacBook-Pro.local>

* feat(vscode): engine-backed @ file suggestions (#3453)

* docs(changelog): sync 0.40.0 from apps/kimi-code/CHANGELOG.md (#3457)

Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>

* fix(agent-core-v2): re-remind uninjected AGENTS.md on directory access after context loss (#3462)

* fix(agent-core-v2): re-remind uninjected AGENTS.md on directory access after context loss

* fix(agent-core-v2): deduplicate AGENTS.md reminders across staggered same-step tool completions

* fix(agent-core-v2): inject AGENTS.md discovery reminders at step head from an access-fed queue

* Delete .changeset/agents-md-access-reminder.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* fix(agent-core-v2): stop tracking read state for AGENTS.md reminders

* fix(agent-core-v2): suppress queued AGENTS.md reminders for same-step reads and deletions

---------

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* fix(migration-legacy): stop re-prompting for kimi-cli migration once completed or dismissed (#3467)

* chore: add changeset for the kimi-cli migration re-prompt fix (#3469)

* chore(changesets): drop unpublished @moonshot-ai/kimi-code entries (#3470)

Remove the pending changesets for the experimental turn-level file
history snapshots and the fork quiescence guard so they do not land
in the 0.41.0 release. The features themselves stay in the codebase;
only the release-note entries are dropped.

* ci: release packages (#3456)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* feat(agent-core-v2): add a handoff step after forced stops and report subagent stop reasons (#3459)

* feat(agent-core-v2): add a handoff step after forced stops and report subagent stop reasons

- When the tool-call repeat breaker stops a turn, the loop now runs one
  text-only handoff step; tool calls issued in that step are refused and
  the turn ends with the same stop reason.
- Tool results can carry stopTurnReason; LoopRunResult and turn.ended
  expose the forced stop reason.
- Subagent results report stop_reason, a resume hint, and a next-step
  line; a turn that ends without a final message fails with
  agent.no_final_message, and the step-cap failure is rephrased for the
  parent model.
- Remove the subagent summary length policy and its continuation prompt.

* chore(agent-core-v2): regenerate the state manifest after merging main

* fix(agent-core-v2): run the handoff step at the step cap and surface swarm stop reasons

- The per-turn step cap no longer skips a queued handoff step, so a
  forced stop that lands on the last permitted step still produces the
  text handoff instead of a max_steps failure.
- AgentSwarm results carry the worker's stop reason and render it as a
  stop_reason attribute; a stuck worker now also triggers the resume hint.

* fix(agent-core-v2): keep the repeat-breaker classification and persist turn.ended stop reasons

- A handoff that ends without text keeps stop_reason repeat_breaker on
  the parent-facing failure instead of collapsing to no_final_message.
- Only a user cancellation maps to stop_reason cancelled; other kills
  report stopped and keep the resume hint.
- turn.ended persists stopReason in its durable record and the wire
  manifest lists it.

* docs(changelog): sync 0.40.1 from apps/kimi-code/CHANGELOG.md (#3475)

* feat(kimi-code): show file-change warning when switching to ask-when-needed or never-ask mode (#3473)

* feat(kimi-code): show file-change warning when switching to ask-when-needed or never-ask mode

* Update permission-mode-file-warning.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* feat(kimi-code): show file-change warning on goal and swarm permission switches

* fix(kimi-code): indent every line of multi-line notice details

* feat(kimi-code): render the permission-mode file-change warning in warning color

* refactor(kimi-code): render the file-change warning via showStatus

* fix(kimi-code): defer the goal permission-switch notice until the goal starts

* refactor(kimi-code): move the file-change warning copy into the TUI constant directory

---------

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* docs: annotate renamed permission modes with bilingual names and former aliases (#3476)

* refactor(agent-core-v2): rebuild telemetry context as a scope-bound layered registry (#3430)

* refactor(agent-core-v2): rebuild telemetry context as a scope-bound layered registry

* fix(agent-core-v2): prefer ambient model in telemetry envelope and repair print-runner stub

* fix(agent-core-v2): delete only the fragment registered by this telemetry binding

* fix(agent-core-v2): bind telemetry context writes to the binding's own fragment

* fix(agent-core-v2): keep stale telemetry emissions on the binding-owned fragment

* refactor(agent-core-v2): mirror turn-request trace_id into ambient telemetry context

* refactor(agent-core-v2): telemetry key-resolution cleanups

Drop the dead defineAgentTelemetryEvent branch in declaredKeysFor: agent_id is already copied unconditionally as identity plumbing before the declared-key loop, and the loop itself skips agent_id, so the branch had no runtime effect. Name the wire session id property key (WIRE_SESSION_ID_PROPERTY) so the session_id-to-sessionId mapping is explicit.

* refactor(agent-core-v2): flow ambient telemetry context to every event unconditionally

Remove the registry-key filtering and the FILTERED_CONTEXT_KEYS hard
filter from composeTelemetryProperties: the merged ambient now reaches
every event's properties, with session_id still remapped to the
camelCase sessionId key and explicit defined values winning on
collision. Explicit undefined values no longer clobber ambient fields.

With filtering gone, correctness for time-varying fields rests on
lifecycle discipline, so the loop now clears the ambient trace_id when
a step starts (mirroring the activeRequestTrace reset) instead of
relying on an explicit undefined payload value to mask the stale
mirror.

* refactor(agent-core-v2): move thinking_effort into the turn telemetry context

* refactor(agent-core-v2): replace the telemetry fragment registry with parent references

* fix(agent-core-v2): assemble flag-gated features after config ready (#3471)

FeatureAssemblyService ran during the eager bootstrap batch, while
ConfigService was still loading config.toml asynchronously, so
flags.enabled() always read false for config-sourced flags and gated
features (e.g. tower via [experimental] tower = true) never assembled.

registerFeature now accepts a { flag } option; gated registrations are
assembled in a deferred pass once IConfigService.ready resolves, and
IFeatureAssemblyService.ready exposes that pass. WorkspaceInstanceManager
.materialize also awaits config.ready so session creation cannot race
the deferred assembly.

* fix(tower): support config.toml configuration (#3461)

* fix(agent-core-v2): rework tower mode enter failures and config-flag assembly

- IAgentTowerService.enter() returns a typed TowerEnterResult: the 4
  former silent failure points now carry their reason (not-main-agent /
  experiment-off / feature-not-assembled / owned-by-live-session with
  the owner session id + title); kap-server and node-sdk map each reason
  to a distinct SESSION_TOWER_MODE_INVALID message via
  towerEnterFailureMessage() instead of one misleading catch-all.
- Fix config-sourced [experimental] tower flag never assembling the
  tower feature: ConfigService seeds its state synchronously at
  construction with a best-effort readFileSync of the config document it
  owns, so the flag is already visible when TowerFeature's constructor
  runs during App-scope creation. No event machinery: a runtime config
  flip updates flag reads but does not re-run feature constructors — a
  restart is required, pinned by test. docs/flag.md + docs/features.md
  document the contract.
- Consolidated changeset for @moonshot-ai/kimi-code.

* fix(tower): release handler when teardown

---------

Co-authored-by: konghuanjun <konghuanjun@moonshot.ai>

* fix(kap-server): stop exiting the process on uncaughtException (#3477)

The process-level uncaughtException handler installed by startServer
called process.exit(1), so a single stray exception killed every
session the process served — and, embedded in the desktop main
process, killed the whole app past the shell's own crash guard. Log
the error at error level and keep serving instead.

createServerLogger gains an optional stream so hosts can route server
logs into their own log channel.

* docs: remove agent-core-v2, kap-server, and transcript package docs (#3481)

* Revert "fix(agent-core-v2): assemble flag-gated features after config ready (…" (#3486)

This reverts commit eb4cd4b38efcd122a88cc59656d1274f54aa4ffd.

* fix(agent-core-v2): write the bound model into the ambient telemetry context (#3484)

* fix(agent-core-v2): write the bound model into the ambient telemetry context

* fix(agent-core-v2): restore the ambient telemetry model after profile replay

* fix(agent-core-v2): rebuild persisted subagents when resuming after a restart (#3478)

* fix(agent-core-v2): rebuild persisted subagents when resuming after a restart

Agent(resume=<id>) only consulted the in-memory agent roster, so once a
session was reopened in a new process every persisted subagent id failed
with "does not exist" even though its wire log and metadata were intact.
The resume path now reads the session metadata once, verifies the target
is a subagent owned by the caller, and re-creates its agent scope from
the persisted records when it is not live before running the turn.

* fix(agent-core-v2): sync rebuilt subagents to the caller mode and match rules by their persisted profile

A subagent rebuilt for resume replayed the permission mode it was
spawned with, so a child persisted in yolo kept running in yolo after
the parent had switched back to manual; the rebuild now copies the
caller's current mode the way a fresh spawn does.

Permission rules with a profile subject such as Agent(coder) were
matched against the fallback label while the target was offline,
because only live agents exposed their profile during execution
resolution. Every spawn site now records the profile name in the
subagent labels and the resume path reads it back for display and rule
matching when the agent is not live.

Adds a kap-server e2e case that spawns a subagent, restarts the server
on the same home directory, resumes it through the Agent tool, and
checks that its prior context reaches the next model request.

* fix(agent-core-v2): keep pinned permission modes when rebuilding a subagent for resume

Tower workers are pinned to auto mode at spawn and skipped by the
permission-mode broadcast, but the rebuild path synced every restored
subagent to the caller's mode, so a dead worker recovered through
Agent(resume=...) after a restart lost its pinned mode. The exception is
now a single predicate next to the worker profile, shared by the
broadcast and the rebuild.

* fix(agent-core-v2): record subagent profiles in the lifecycle instead of at each spawn site

The persisted profile name that offline resumes use for display and
permission-rule matching was written by three spawn sites, and the
session-init child was still missing it. The lifecycle now records it
centrally: create() takes the profile from the binding it is given and
fork() takes the override or the source agent's profile, so every
subagent spawn is covered and the spawn sites no longer pass it.

* chore: merge the subagent-resume changesets into one

* fix(agent-core-v2): track session index mirror give-up event once per failure episode (#3493)

* fix(agent-core-v2): track session index mirror give-up event once per failure episode

The give-up telemetry fired on every failed flush once the consecutive
failure count crossed the threshold, so a session with a persistently
failing mirror reported hundreds of thousands of events per day. Emit
it only when crossing the threshold; the counter resets on the next
successful flush, so a later episode reports again.

* fix(agent-core-v2): latch the mirror give-up event per failure episode

The equality guard missed episodes where unpublished-manifest flushes
(manifest === undefined also increments the counter) pushed the count
past the threshold before the first throwing flush. Latch the report
per episode instead; the latch resets on the next successful flush.

* test: speed up kap-server suite and exclude minidb from default projects (#3504)

* test: speed up kap-server suite and exclude minidb from default projects

* test(kap-server): restore baseline server after sessions tests replace it

* fix(kimi-code): honor KIMI_DISABLE_TELEMETRY and restore crash telemetry in v2 print mode (#3498)

* fix(kimi-code): honor KIMI_DISABLE_TELEMETRY and restore crash telemetry in v2 print mode

* fix(kimi-code): attribute v2 print crash telemetry to the resolved session model

* fix(tree-sitter-bash): recognize heredocs in character-level balanced scanning (#3503)

* fix(tree-sitter-bash): recognize heredocs in character-level balanced scanning

scanBalancedStatements treated heredoc bodies as ordinary characters, so a stray quote, paren, or backtick inside a heredoc body (for example an apostrophe in a PR body passed through a command substitution) broke the scan and produced ERROR nodes; the resulting hasError made dangerous-command-ask judge the whole command unanalyzable and prompt for approval even in yolo mode.

Parse << and <<- delimiters (excluding <<< herestrings) with the same unquoting rules as the token-level heredoc reader, queue pending bodies, and skip them line-wise at newlines. Skip arithmetic $(( ... )) regions via scanBalanced so a left-shift << is never mistaken for a heredoc operator.

* fix(agent-core-v2): raise the bash parse wall-clock budget to 500ms

A 20ms wall-clock budget could abort an otherwise fine parse under CPU contention, GC pauses, or cold-start JIT, flipping the permission verdict to unanalyzable (spurious approval prompts) or silently dropping AGENTS.md re-reminders. Normal commands parse in well under 1ms; maxNodes stays the deterministic cap, and 500ms remains a backstop against pathological parser loops.

* fix(tree-sitter-bash): skip comments and legacy arithmetic during heredoc-aware scanning

The heredoc-aware scan queued a heredoc for any << it encountered, including inside comments (echo $(printf x # <<EOF\n)) and legacy arithmetic expansions (echo $(echo $[x << 2]\n)); both are valid bash that parsed cleanly before, and the regression flipped them to hasError and an unanalyzable permission verdict.

Skip # comments to end of line when the preceding character starts a new word, and skip ${ ... } / $[ ... ] expansions as balanced units (mirroring skipDollar), so << is only recognized where a redirection operator can actually appear.

* fix(tree-sitter-bash): skip word-glued subscripts during heredoc-aware scanning

Indexed assignments such as echo $(a[x<<2]=3\n) put arithmetic inside a word-glued [ ... ] subscript; the heredoc-aware scan read the << shift operator there as a heredoc start, regressing valid bash that parsed cleanly before to hasError and an unanalyzable permission verdict.

Skip a [ ... ] region as a balanced unit when the bracket immediately follows a word character (subscripts and glued glob classes); a bracket at word start keeps the existing character scan, so real heredocs after words (cat foo[ab]<<EOF) and bare [ command arguments are unaffected. The subscript regression is covered by a unit case only: the reference parser splits subscript arithmetic into binary_expression while this parser keeps it an opaque word, a structural difference that predates this change and has no differential fixture yet.

* fix(tree-sitter-bash): skip conditional regions and look through continuations in heredoc-aware scanning

Two more character-scan contexts queued bogus heredocs after the heredoc-aware scan: a [[ ... ]] conditional region (echo $( [[ x == @(<<EOF) ]]\n) and regex right-hand sides such as [[ x =~ <<a ]]), and a # preceded by a backslash-newline continuation (echo $(printf foo\<newline>#bar)), where removing the continuation keeps the hash inside the preceding word instead of starting a comment. Both are valid bash that parsed cleanly before.

Skip word-start [[ ... ]] as a balanced region (a << inside a conditional is never a heredoc operator; a bracket in argument position keeps the character scan), and walk back over \+newline pairs before classifying a # as a comment. The extglob conditional case joins the differential fixtures; the continuation case is unit-only because the reference parser errors on it.

* fix(tree-sitter-bash): scan substitutions as part of heredoc delimiters

A heredoc delimiter containing a substitution (echo $(cat <<$(foo)\nbody\n$(foo)\n)) was truncated at the first paren, so the queued delimiter never matched the body closing line and the scan swallowed the rest of the range, regressing valid bash to hasError and an unanalyzable permission verdict.

scanHeredocDelimiter now scans $( ), ${ }, $[ ], and backtick regions wholesale as part of the delimiter word (recursing with the heredoc-aware statement scanner for $( )), mirroring how bash treats the whole word as the delimiter. The case stays unit-only because unquoted delimiters hit the already-registered heredoc-content-chunks structural difference with the reference parser.

* docs(zh,en): restyle configuration and customization sections (#3485)

* docs(zh): restyle configuration and customization sections

Editorial pass across 11 pages: clear explanatory dashes, replace arrow
cross-references with inline links, compress oversized table cells while
keeping operational facts (value ranges, override precedence, activation
conditions), split >5-sentence paragraphs by theme, fold interface
contracts and low-frequency internals into details blocks, add map
sentences to multi-paragraph sections, add subcommand overview table to
kimi-command reference. Add /provider manager screenshot to media.

* docs(zh): restore dangerous_command_guard, fix trust prompt default and secondary-model default

- config-files: restore the dangerous_command_guard paragraph dropped
  during the style pass (regression, content from upstream #3290)
- mcp: the trust prompt defaults to Trust this folder per
  trust-prompt.test.ts; docs had the direction reversed (pre-existing)
- config-files: subagent model pool defaults on since #3334;
  KIMI_CODE_EXPERIMENTAL_SECONDARY_MODEL=0 disables (pre-existing staleness)

* docs(zh,en): sync en mirrors and fix anchor slugs

Add restyled en mirrors for all 11 configuration/customization pages,
mirroring the zh structure (section parity, map sentences, compressed
cells, details folds) while keeping en phrasing.

Fix anchor slugs in both locales (underscore kept, dots dropped per
@mdit-vue slugify): loop_control, openai_responses, kimi_model_,
systemmd variants; retarget renamed permission-mode section
(yolo/auto -> The three permission modes / 三种权限模式).

* fix(telemetry): deduplicate session_started and model switch events (#3499)

* fix(telemetry): deduplicate session_started and model switch events

* fix(telemetry): keep engine session_started for direct v2 SDK clients and avoid model_switch race

* fix(telemetry): preserve model_switch when activation rebinds the same alias

* fix(telemetry): route TUI reload through harness

* test: update /reload message-flow test for harness reload route

* refactor(agent-core-v2): remove the staleGuard feature (#3517)

* refactor(agent-core-v2): remove the staleGuard feature

Drop the read-before-edit runtime guard: Edit/Write executions are no
longer vetoed when the target file was never read or its mtime changed
since the last read, and successful Read/Edit/Write no longer refresh a
recorded mtime. Removes the staleGuard replayable state key and the
staleGuard.recorded / staleGuard.cleared durable wire events; old wires
keep replaying through the unknown-type skip path. apps/vis keeps
projecting and rendering those historical records via locally declared
legacy record types.

* fix(agent-core-v2): skip retired wire record types silently during restore

Restore reports every journal record whose type has no registered event
class through onUnexpectedError. Sessions written before the staleGuard
removal can hold a staleGuard.recorded entry per successful
Read/Edit/Write, so loading one floods the log with WireError stacks.
Keep a retired-type list of record types that were once durable
vocabulary; restore skips them without reporting, while genuinely
unknown records stay on the error path.

* fix(telemetry): drop null values from flattened event payloads (#3518)

* feat(agent-core-v2): remind the model of its context budget and point compaction notes at the wire journal (#3423)

* feat(agent-core-v2): remind the model of its context budget and point compaction notes at the wire journal

Add the contextBudget feature: a context_budget reminder that restates used/max/trigger tokens as usage crosses half, three quarters and ninety percent of the compaction trigger, and a compaction_ahead reminder delivered once per window when the trigger is within ten percent of the context window, so the model can persist and verify state while it can still call tools. Both read IAgentFullCompactionService.budget(), which derives from the same CompactionTriggerBudget that drives auto compaction, and both are stripped from the summarizer input.

Behind compaction_recovery_pointer, compaction records the wire journal line range it covered (wireLines on context.apply_compaction, folded into the replayable fullCompaction.wireRanges key) and appends a Context Recovery footer to the model-facing contextSummary with the on-disk wire.jsonl path, every earlier window's line range, and a primer on reading the journal; the UI-facing summary stays the note plus TODO. Read returns wire.jsonl lines under the sessions directory untruncated and spill-exempt so a single record can be read back after Grep locates it, and the compaction instruction tells the summarizer a recovery pointer follows the note.

Both flags default on; KIMI_CODE_EXPERIMENTAL_CONTEXT_BUDGET_REMINDERS=0 and KIMI_CODE_EXPERIMENTAL_COMPACTION_RECOVERY_POINTER=0 disable them. Telemetry gains context_budget_reminder, compaction_ahead_reminder, and ahead_* fields on compaction_finished.

* feat(agent-core-v2): ship context budget reminders and the recovery pointer without flags

- Remove the two experimental flags; both behaviors now ship unconditionally and the compaction instruction carries the recovery note in its template.
- Lower-bound recovery windows at the latest context.clear journal record so a window never points into history the user discarded.
- Add the appended recovery footer's estimated tokens to summaryOutputTokens so tokens_after and the post-compaction token floor stay honest.

* fix(agent-core-v2): cap event log reads and refuse empty-history compaction

- Cap a single wire.jsonl record read at 150k chars, below the window-minus-trigger margin, so one read can never push the context past the model window; the note points at sed | jq for longer records.
- Keep at least the last record when tail-reading the event log instead of returning silently empty output with a contradictory note.
- Fail the compaction when an overflow shrink would drop every message, instead of compacting an empty history and replacing the context with a groundless note.

* fix(agent-core-v2): drop the redundant ninety bucket and soften ahead-reminder wording

- Remove the 90% context-budget bucket: the compaction-ahead threshold is always at or below it, so it only echoed the stronger last-chance reminder moments later.
- Stop suggesting a commit as a way to persist state before compaction; files and the todo list cover it without prompting unwanted commits.
- Make the event-log note's primer reference conditional on a compaction having run.

* chore: merge the compaction changesets into one

* fix(tui): drop the /dance Easter egg hint from the tips rotation (#3521)

Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
Co-authored-by: qer <wbxl2000@outlook.com>

* fix(agent-core-v2): keep background questions open past turn end and inline their answers (#3522)

* fix(agent-core-v2): keep background questions open past turn end and inline their answers

Background AskUserQuestion reused the generic task pipeline end to end, which
broke it in two ways: the pending interaction was still bound to the asking
turn, so it was cancelled the moment the agent finished its turn, and the
turn-end cancel response was then misread as an answer. On top of that the
completion notification only carried a pointer to the task output file,
forcing an extra Read round trip for a few bytes of JSON.

- Detach background question interactions from the asking turn so they stay
  pending until answered, stopped, or the agent closes.
- Treat cancelled interaction responses as dismissals.
- Inline the answer JSON in the question task notification and word the
  notification as answered or dismissed; fall back to the output file only
  when the answer exceeds the inline budget.
- Trim the background launch result to task id, status, and one next step.
- Fold transcript notification summaries before inline answer blocks.

* fix(agent-core-v2): fail background questions on tool errors and translate interaction cancellations in the question service

Follow-up hardening from review:

- The interaction kernel's cancellation response now has a named shape,
  InteractionCancellation, and SessionQuestionService.request translates it
  into a dismissal (null) before handing the result to callers. The
  AskUserQuestion tool no longer inspects answer maps for a cancelled key,
  so a bare answer map can never be mistaken for a cancellation.
- QuestionBackgroundTask settles as failed with the tool's message as the
  stop reas…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant