Align toProtocolModel with the v1 projection and the protocol wire schema by applying effectiveModelConfig and emitting support_efforts / default_effort, so clients of the v2 /models endpoint see thinking-effort levels again.
Replace the nonexistent getHandle call introduced by the blocked-goal continuation tests with the public get API and the shared MAIN_AGENT_ID constant, restoring typecheck and both continuation tests.
The init run spawns a coder subagent through agentLifecycle.run with an
AbortController that was a local of generateAgentsMd, so nothing outside
the service could cancel it: Ctrl+C in clients only cancels the main
agent's loop turn, which does not exist during /init.
ISessionInitService gains cancelInit(): the service keeps the in-flight
run's AbortController (cleared in finally), and cancelInit aborts it with
a user-cancellation reason. Cancellations propagate unwrapped from
generateAgentsMd (UserCancellationError / AbortError, never
SESSION_INIT_FAILED, no subagent.failed event) so callers can distinguish
"aborted" from "failed".
* fix(agent-core-v2): keep invalidated OAuth flows observable during login
invalidateFlows() deleted flows outright when the provider configuration
changed, including terminal ones. That voided the TERMINAL_RETENTION_MS
window and, worse, left the status guards in handleSuccess /
finalizeAuthentication blind when the invalidation landed in the
microtask gap after toolkit.login resolved: setTerminal then wrote
'authenticated' onto an orphaned state the client could never observe,
so the login hung after a successful browser authorization.
Transition affected pending flows to a visible 'cancelled' terminal
status instead, mirroring abortExisting().
Also normalize the KIMI_CODE_BASE_URL env override at the source in
kimiCodeBaseUrl(): provision persists it verbatim while the model
refresh rewrites it normalized, and the deep-equal diff between the two
shapes fired a spurious providers-changed event mid-login.
* style(agent-core-v2): drop non-header comments from the oauth login fix
* chore: cover agent-core-v2 in the oauth login fix changeset
* feat(server): allow X-Kimi-Client-* headers in CORS for cross-origin desktop renderer
* feat(server): reflect request headers in CORS preflight
For allowed origins, echo the preflight's Access-Control-Request-Headers back in Access-Control-Allow-Headers (falling back to CORS_ALLOW_HEADERS for non-preflight responses). Newly added client request headers (e.g. X-Request-Id) no longer require a matching server-side allowlist change, unblocking desktop app://renderer cross-origin requests that were failing preflight on headers absent from the fixed list.
* fix(agent-core): mark auto-approved plan exits as not user-reviewed
In auto permission mode ExitPlanMode is approved without user
involvement, but its result read "## Approved Plan:" exactly like a
genuine user approval and the transcript showed a green "Approved"
chip. The model treated that as a signal to start executing, even
when the user had asked it to stop after planning.
- Emit an "auto-approved, not user-reviewed" result with a note that
execution follows the user's original instructions (v1 + v2).
- Extend the auto-mode reminder: plan approvals are automatic and are
not a user signal to proceed (v1 + v2).
- Render an "Auto-approved" warning-toned chip in the TUI, keeping
backward compatibility with the old result marker.
- Document the Auto mode plan-exit behavior in interaction guides.
* fix(agent-core): only mark plan exits as auto-approved in auto permission mode
Address review feedback on the auto-approved plan exit change:
- Branch the direct-execution output on the permission mode in both
engines: only auto mode yields the "auto-approved, not
user-reviewed" result and telemetry outcome. In manual / yolo modes
the direct path means a configured or session allow/ask rule let the
call through — an explicit user decision that keeps the user-approved
output, the Approved transcript chip, and the approved outcome.
- Move the v2 rationale out of the method body into the file header,
per the agent-core-v2 comment convention.
- Drop the absolute "only Auto mode" wording from the interaction
guides (en/zh).
Enforce the package comment convention that comments live only in the
top-of-file block: strip mid-file doc, prose, and trailing comments
while preserving header blocks and eslint/oxlint/@ts-* suppression
comments. No code tokens are changed.
* fix(agent-core-v2): fix wire migration rewrite race and reject unversioned logs (8 files)
- await the migration rewrite in wireRecordService.restore() so restore only resolves once the migrated log is durable and rewrite failures surface
- serialize AppendLogStore.rewrite() behind the log flush so appends arriving during the whole-file replace land after the new content
- reject wire logs missing the metadata envelope (missingWireMetadataError) in restore, session fork, and agent create instead of fabricating a current-version envelope over legacy records
* fix(agent-core-v2): stop background tasks on session close (10 files)
- add IAgentTaskService.stopAllOnExit: suppress terminal notifications, then SIGTERM → grace → SIGKILL for every active task (v1 stopBackgroundTasksOnExit parity, gated by keepAliveOnExit)
- call stopAllOnExit from agentLifecycle.remove before scope disposal, and abort live tasks in AgentTaskService.dispose as a last resort for disposal paths that bypass the graceful close
- honor [task] killGracePeriodMs in the stop grace window and bind the v1 KIMI_CODE_BACKGROUND_KEEP_ALIVE_ON_EXIT env override for keepAliveOnExit
* fix(agent-core-v2): root task persistence at the owning agent's scope
- persist task records under <sessionScope>/agents/<agentId>/tasks/ (v1's
per-agent layout) so tasks written by older versions are found on resume
- stop one agent's restore from loading, marking lost, or re-notifying
another agent's tasks
- add a per-agent isolation test covering loadFromDisk + reconcile
* fix(agent-core-v2): address task lifecycle review findings
* fix(agent-core-v2): preserve queued appends across rewrites
* test(agent-core-v2): cover rewrite cutover flush
* fix(agent-core-v2): surface append durability failures
* fix(agent-core-v2): retire released append log buffers
* fix(agent-core-v2): preserve session-level task records
* fix(agent-core-v2): harden append log cutover recovery
* fix(agent-core-v2): suppress only background exit notifications
---------
Co-authored-by: qer <wbxl2000@outlook.com>
* feat(agent-core-v2): support caller-supplied MCP servers on session create
- add mcpServers to CreateSessionOptions, forwarded to the session's first
ensureMcpReady call so caller-supplied servers ride on the initial load
- ensureMcpReady accepts callerServers, honored only by the call that starts
the initial load; later calls just await the in-flight single-flight load
- merge precedence mirrors v1 (rpc/core-impl.ts): file config <
caller-supplied < plugin servers
* feat(agent-core-v2): file tools reach skill roots; add skillDirs seed
- add extendWorkspaceWithSkillRoots to path-access; Read/Write/Edit/Grep/
Glob and media tools merge skill-catalog roots into the workspace per
call (v1 merged once at construction), so skill dirs outside the cwd
stay reachable and late-loading roots are picked up
- add skillCatalogRuntimeOptionsSeed; wire --skillsDir into the v2 print
CLI and skillDirs into kap-server startServer (v1 SDK skillDirs parity)
* chore: add changesets for v2 caller MCP servers and skill dirs fixes
* feat(agent-core-v2): support caller-supplied MCP servers on session create
- add mcpServers to CreateSessionOptions, forwarded to the session's first
ensureMcpReady call so caller-supplied servers ride on the initial load
- ensureMcpReady accepts callerServers, honored only by the call that starts
the initial load; later calls just await the in-flight single-flight load
- merge precedence mirrors v1 (rpc/core-impl.ts): file config <
caller-supplied < plugin servers
* chore: add changeset for v2 caller MCP servers
- rehydrate restored `blobref:` media URLs to inline `data:` URIs from the
agent's blob store, matching the shape of live emissions
- pass tool results carrying media (e.g. ReadMediaFile) through as raw
content parts instead of flattening them to empty text
- use wire record times for `created_at`, nudged to stay strictly
increasing, instead of a synthesized session-start offset
- carry per-entry record times through `ContextTranscript` and the
live-tail merge
* fix(agent-core-v2): surface provider rejection on post-refresh 401
- map a 401 that survives forced token refresh to PROVIDER_AUTH_ERROR
carrying the provider's sanitized message, instead of a misleading
AUTH_LOGIN_REQUIRED re-login prompt
- propagate provider auth errors through full compaction instead of
wrapping them as compaction failure
- export sanitizeStatusErrorMessage for reuse
* fix(agent-core-v2): align repeat-reminder and AskUserQuestion copy with v1
- rewrite repeated tool call reminders to redirect instead of prohibit (port of v1 #1518)
- simplify makeReminderText2 to (repeatCount), no longer echoing tool name and args
- treat dismissed AskUserQuestion as no answer, not the recommended pick (port of v1 #1550)
- update toolDedupe test assertions and regenerate affected wire snapshots
* chore: add changeset for v2 reminder and question copy alignment
* fix(kap-server): drain in-flight heartbeat writes before unlinking the instance file
- count writes that passed the released check and await them in release()
so their atomic rename cannot recreate the file after unlink
- harden the heartbeat test: 1ms cadence plus a post-release re-check
catches the recreate-after-unlink race (verified failing on old code)
* docs(agent-core-v2): move toProviderAuthError rationale to the file header
Address Codex review: agent-core-v2 keeps comments in the top-of-file
header only, never beside functions
Resolve the login environment via resolveKimiCodeLoginAuth so
KIMI_CODE_BASE_URL / KIMI_CODE_OAUTH_HOST steer the credential slot
login writes to the same way they steer runtime token reads — fixes
"login succeeds but every call 401s" against non-default environments.
The provisioned provider entry now records the login environment and
credential slot explicitly, and logout deletes from the runtime
(env-aware) slot.
- drop the "missing a base URL" rejection in ModelResolverService so a
structured provider without base_url resolves to undefined and the wire
provider applies its protocol default endpoint, matching v1
- relax baseUrl to optional across Model, ModelImplInit, and
ProtocolAdapterConfig; guard the anthropic /v1 strip against undefined
* fix(protocol): make server_hello heartbeat_ms optional
kap-server dropped the server-initiated WS heartbeat and no longer emits
heartbeat_ms in server_hello, but the published v1 schema still required
it, so spec-compliant clients rejected the handshake before subscribing.
- mark heartbeat_ms optional in serverHelloPayloadSchema (advisory only)
- add a ws-control test for a server_hello without heartbeat_ms
- align kimi-web WireServerHello and the server-e2e handshake assertion
* fix(agent-core-v2): pass media parts through tool_result projection
- keep raw kosong content-part array for tool results carrying
image/video/audio parts instead of flattening to text
- restore ReadMediaFile media rendering after session reload/resume
* chore: add changeset for optional server_hello heartbeat_ms
* docs(agent-core-v2): move tool_result media rationale to module header
Per the agent-core-v2 comment conventions, comments live solely in the
top-of-file block — move the media-passthrough rationale out of the
buildProtocolContent JSDoc into the module header.
* fix(agent-core-v2): ignite toolDedupe plugin on agent creation
- ignite IAgentToolDedupeService in AgentLifecycleService before external
hooks so it sits ahead of permission on onBeforeExecuteTool
- mirror the ignition in the test harness AgentTestContext
- add lifecycle test asserting the dedupe hooks are registered
* fix(agent-core-v2): carry session files and cron tasks over on fork
- copy blobs, plans, background-task output, and media originals into the
forked session dir (excluding state.json, wire logs, and logs/)
- duplicate the source session's cron tasks with fresh ids retagged to the
target session via the shared CRON_SESSION_TAG
- roll back the half-fork on failure: drop the materialized handle from the
live registry and delete the target session dir
* feat(kap-server): drop WS heartbeat; never terminate idle connections
- remove ping interval / pong timeout / socket.terminate() from both the
v1 (WsConnectionV1) and v2 (WsConnection) WebSocket connections
- v2 protocol: drop pong from the client message schema, remove PingMessage
and ReadyMessage.heartbeatMs; the ready frame is now bare { type: 'ready' }
- v1 protocol: remove buildPing/PingFrame and ServerHelloPayload.heartbeat_ms;
server_hello no longer advertises a heartbeat
- drop pingIntervalMs/pongTimeoutMs options from registerWs/registerWsV1
* feat(agent-core-v2): gate image formats and add media-stripped resend
- add image-format-policy as the single source of truth for the
provider-accepted image MIME set (PNG/JPEG/GIF/WebP), with MIME
normalization, data-URL parsing, byte sniffing, and refusal notices
- enforce the format gate at every ingestion point: ReadMediaFile refuses
unsupported formats with per-OS conversion guidance, MCP tool results and
prompt step requests drop them for a text notice, and kap-server prompt
routes gate inline, uploaded, and remote-URL images on the sniffed bytes
- resend once with every media part replaced by a text marker when the
provider rejects an image's format, and keep later steps of the same turn
on the media-stripped projection (v1 parity)
- commit the WebP decoder wasm as a base64 module for the bundled CLI, with
a regenerate script
* feat(agent-core-v2): add media-degraded 413 resend and WebP re-encoding
- resend once with the media-degraded projection after an HTTP 413
body-size rejection: all but the two most recent media parts are replaced
by text markers, and later steps of the turn stay degraded (stripped
still wins over degraded)
- generalize stripAllMediaParts into degradeOlderMediaParts; the
media-stripped resend is now the keepRecent=0 case
- re-encode non-animated WebP through the wasm decoder and the PNG/JPEG
ladder instead of passing oversized WebP through (animated WebP still
passes through whole)
- stop lossless PNG rescaling at a 1000px floor and switch to the JPEG
ladder below it, so small byte budgets stay readable
- add the @jsquash/webp dependency
* feat(agent-core-v2): add flag-gated fault injection for recovery testing
- add the faultInjection domain: a one-shot arm/take latch that raises a
deterministic provider failure (HTTP 413 body-size or image-format 400)
before the provider is contacted, so the media-degraded / media-stripped
recovery resends can be exercised end-to-end against a real provider
- gate arming behind the new fault-injection experimental flag
(KIMI_CODE_EXPERIMENTAL_FAULT_INJECTION), off by default
- expose IAgentPromptService and IFaultInjectionService over the kap-server
/api/v2 RPC channel
- add a klient example that drives the REST ingestion gate and both
recovery resends against a live server
* feat(server): default to kap-server and remove the v1 server package
- kimi server run / kimi web now boot kap-server (agent-core-v2 engine)
unconditionally; the KIMI_CODE_EXPERIMENTAL_FLAG gate on the server
path is gone (the kimi -p print-mode gate stays)
- move the OS service manager (svc: launchd/systemd/schtasks) from
packages/server into packages/kap-server and export it there
- repoint the CLI server subcommands, tests, and dev scripts at
kap-server; relabel the web dev backend presets default/multi
- delete packages/server and update workspace bookkeeping (flake.nix,
pnpm-lock.yaml, changeset ignore docs, AGENTS.md, agent-core-dev skill)
* test(server-e2e): remove scenarios that depend on v1 debug endpoints
Scenarios 04-stateless-controls, 10-prompt-queue-steer and
12-send-and-cancel assert through the /api/v1/debug/prompts/*
introspection routes, which only the deleted v1 server mounted —
kap-server's --debug-endpoints is a documented no-op, so these
scenarios can only 404 now. The vitest e2e files using the same
surface already skip when it is absent.
* fix(web): size workspace picker from full content
* chore: add web workspace picker changeset
* refactor(web): use intrinsic workspace picker sizing
* fix(web): cap workspace picker to conversation pane
* fix(agent-core-v2): support services.moonshot_search config for WebSearch
The v2 engine only resolved the WebSearch backend from the managed Kimi OAuth provider, so an environment that configures web search purely via [services.moonshot_search] (api key, no login) got no provider and the WebSearch tool stayed hidden. Register the services config section and resolve the provider config-first, mirroring v1 precedence.
* fix(agent-core-v2): preserve custom services config
* fix(web): make mid-turn delta offsets step-relative
Reset in-flight text and client stream alignment at step boundaries so
resync seeds only the current step instead of duplicating prior steps.
* fix(web): dedupe resync-seeded messages by normalized content
The exact-JSON content signature missed duplicates when the two copies
differed by thinking signature, tool progress, part boundaries, or the
tool set (finished parallel tools leave running_tools). Reduce content
to concatenated stream text plus sorted tool-call ids and treat a
covered subset as the duplicate, merging the seed's tool progress into
the existing cards before dropping it.
* fix(agent-core-v2): append sessions to legacy index so v1 TUI can resume web-created sessions
* chore: remove changeset
* refactor: rename appendLegacySessionIndexEntry to appendSessionIndexEntry
* fix(agent-core-v2): address review feedback on session index append
- Await appendLogStore.flush() so the shared index is durable before create/fork returns
- Append fork entries only after wire copy and agent replay complete
- Move method-level rationale into the file header per package comment conventions
* fix(web): restore the goal card after a page refresh
* fix(web): assert goal endpoint URL without stringification
* fix(web): skip goal recovery write when a live goal event wins the race
* fix(web): track goal events with a per-session version so clears win the recovery race
- recognize ucrt64/clang64/clangarm64 prefixes in git --exec-path
alongside legacy mingw32/mingw64 when locating bash on Windows
- port the three MSYS2 regression tests from kaos to the v2 probe
* fix: send the product User-Agent on provider registry and catalog fetches
Registry (api.json) and models.dev catalog fetches only carried the
runtime default User-Agent while every other outbound request sends
kimi-code-cli/<version>. Thread an optional userAgent through
fetchCustomRegistry / fetchCatalog and the shared refresh host, pass
the product UA from the CLI, TUI, and both daemons, and seed a default
product UA in kap-server that hosts can override via opts.seeds.
* refactor: use options for registry fetches