chore: merge upstream 2.0.0 - #11
Merged
Merged
Conversation
… (#3271) - turn.started now derives the attachment file id from the kimi-file URL when the media part carries no id, so prompt images uploaded through the global file library stay attached in the live transcript instead of vanishing until the post-turn heal - an explicit id must still match the URL file id, and non-kimi-file URLs are still ignored - restore the turn.started prompt-attachment regression coverage dropped by the model-as-container refactor and extend it to the id-less kimi-file form
… question entities (#3272)
The drain probe treated any callTool failure as proof the transport close
had been processed, but a stdin write error (EPIPE) can win the race
against the child's exit notification, so the listener could be registered
before the close was buffered and the synchronous replay never fired.
Break the drain loop only on errors that are impossible before the SDK's
_onclose ran ('Not connected' / 'Connection closed' / the transport's
not-running guard).
Also drop the assertion that the replayed reason contains the child's
final stderr: the reason snapshots the stderr buffer at close time, which
can legitimately race delivery of the last stderr chunk (reproduced 2/40
under CPU load). Tail capture itself stays covered by the stderrSnapshot
assertion. Finally, flush the fixture's banner through the stderr write
callback before process.exit so the write cannot be truncated.
Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
…urn it describes (#3278) * fix(agent-core-v2): clear the turn outcome when an undo rewinds the turn it describes * fix(agent-core-v2): clear the turn outcome too when an undo outruns the tracked anchors * fix(agent-core-v2): reconcile the persisted turn outcome against the replayed wire on restore * fix(agent-core-v2): keep the persisted outcome when an undo rewinds only later turns --------- Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
…ath (#3283) Add a liveness watchdog on the management and HTTP tunnel WebSockets (client ping every 30s, terminate after 300s without inbound activity) so the client recovers when a relay redeploy drops connections without a close frame. Treat registration failures after a successful session as transient and keep backing off instead of stopping permanently.
…aming (#3276) Concurrent openSession/attachResumedSession calls for the same webview both missed the sessions map before either wrapped the SDK session, so one Session facade got two SessionRuntimes. The overwritten runtime leaked and kept broadcasting, doubling every streamed delta and tool call in the view. Queue opens, attaches, and detaches per webviewId so the second caller sees the first one's runtime.
…background (#3273) * feat(kap-server): add task detach action to move foreground tasks to background * test(kimi-code-sdk): normalize v2-only parentToolCallId in task parity projections * fix(agent-core-v2): distinguish user-initiated detach in tool result text * feat(agent-core-v2): mention user-initiated backgrounding in the bash tool description * feat(agent-core-v2): use a client-agnostic background-task panel hint in the bash tool description * ci: retrigger checks * feat(agent-core-v2): client-agnostic human_shell_hint and a detached_by_user marker in tool results * fix(protocol,docs): declare parent_tool_call_id in the shared task schema and document the detach action * style: remove added comments
…3289) * fix(transcript): carry the orchestrator's prompt on subagent turns * chore: add changeset for subagent turn prompts
…e web page (#3291) * fix(oauth): show a cancelled state when authorization is denied on the web page * chore: drop the changeset and the dist-web sync from this PR
…sh or are removed (#3284) * fix(secondary-model): stop rewriting the section when providers refresh or are removed Provider refresh, provider deletion/rename, catalog/registry import, OAuth logout, and SDK removeProvider used to cascade into the user's [secondary_model] block: pool entries were silently pruned, and the whole section was deleted when its effective default dangled. The cascade ran from a cache-refresh path (including an unattended 6h scheduler), so upstream model-list changes could irreversibly destroy hand-written configuration without any notice. Config is user intent; the catalog is an availability snapshot. Stop rewriting the section on every provider/models writer. An entry whose model no longer resolves fails pool validation on the next session create with a message naming the offending alias, which is the same fail-fast contract hand-written typos already had. * chore(sdk): add changeset for the removed secondary-model cascade export * Delete .changeset/sdk-remove-secondary-model-cascade.md Signed-off-by: 7Sageer <sag77r@hotmail.com> * Delete .changeset/secondary-model-no-silent-rewrite.md Signed-off-by: 7Sageer <sag77r@hotmail.com> --------- Signed-off-by: 7Sageer <sag77r@hotmail.com>
…(#3234) * fix(mcp): forward structuredContent only as fallback when content has no usable text Servers that follow the MCP spec's backwards-compatibility SHOULD return the same JSON both as a TextContent block and as structuredContent. Forwarding both to the model sent the same data twice. structuredContent now rides the mcp-structured-result block only when the content blocks carry no usable text; _meta still always passes through. * test(mcp): verify structured-content fallback over a real stdio MCP server Round-trip four server result shapes (dual-emit, structuredContent-only, prose+structured, vendor _meta) through StdioMcpClient and the output pipeline, so the fallback behaviour is checked against real protocol bytes instead of hand-built result objects. * fix(mcp): dedupe structuredContent only against its verbatim serialization The earlier has-usable-text gate also suppressed the structured payload when content was a lossy human summary — the primary case from #2554 (list_projects returning 'N item(s)' while the items live in structuredContent). Skip the structured block only when a content text block parses to the same JSON value (semantic compare, key order and formatting insensitive); summaries and structured-only results still pass through. * fix(mcp): forward structuredContent only when content does not already cover it Replace the verbatim-serialization comparison with a size heuristic: well-behaved servers render the same data into content (the spec's dual-emit, or a faithful human reorganisation), and either way the text measures at roughly the same size as the payload, so forwarding it would double the information. Append the structured payload only when content carries no usable text, or when the payload is more than twice the text size — the signature of a lossy summary. Verified against a live video- editor MCP whose tools all measure a json/text ratio of 1.2-1.9. * fix(mcp): send content or structuredContent to the model, never both Final policy: content and structuredContent are alternatives. content wins whenever it carries anything usable (a media block or non-whitespace text); structuredContent fills in only for an empty content array. There is no reliable signal that the structured payload is richer than what the server already rendered into content, so no size or structure heuristic is attempted. _meta still always passes through. * refactor(mcp): rename the structured-extras wrapper to mcp-result-extras The block carries structuredContent and/or _meta; the old mcp-structured-result name was inaccurate whenever it is a pure _meta carrier. * ci: retrigger after flaky mcpCore client-stdio close-buffering test * ci: retrigger after flaky minidb concurrent writer/reader test
…e provider (#3294) * fix(auth): keep OAuth login alive when its own provisioning writes the provider * fix(auth): settle the OAuth flow as authenticated before provisioning * fix(auth): publish the login as authenticated only after provisioning completes
* chore: sync web dist from code-app code-app: 758f4587d10e28de8ac04678df8e379ca0f10387 * chore: consolidate web dist changesets by theme * chore: trim web dist changesets to headline items * chore: drop web prefix from fix-known-issues changeset * chore: drop web-mobile-interaction changeset as duplicative of existing mobile entries
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…minated by app exit (#3292) * fix(agent-core-v2): unify previous-session lost-task notice into a single reminder on resume * fix(agent-core-v2): harden resumed task reminders * docs: clarify task resume reminder
* feat(kap-server): support server-local path attachments Web and desktop clients can now attach files, images, and videos to a prompt by server-local absolute path instead of uploading a copy. The daemon validates the path (absolute, realpath-resolved, non-sensitive, local runtime only) and references the original file in place, so the agent reads the original path; the upload flow is unchanged. Submitted file attachments are also recorded on the prompt origin and projected as typed transcript attachments, so web clients render attachment chips for plain files without parsing the model-facing notice text. * fix(kap-server): forward file attachment metadata from skill activations * Delete .changeset/web-attach-by-path.md Signed-off-by: 7Sageer <sag77r@hotmail.com> --------- Signed-off-by: 7Sageer <sag77r@hotmail.com>
* fix(cli): give the interactive update check a longer CDN timeout `kimi update` shared the 3-second CDN fetch budget sized for passive background checks. Every CLI invocation is a fresh process paying full DNS+TCP+TLS setup, so a slow connection to the CDN intermittently aborted the interactive check with a raw "This operation was aborted". Thread a per-request timeout through the CDN fetch helpers and refreshUpdateCache; the interactive upgrade command now passes a 10 second budget (INTERACTIVE_UPDATE_CHECK_TIMEOUT_MS) while all background refresh paths keep the 3-second default. * refactor(cli): drop motivational comments and simplify the update-check changeset * docs(cli): reword the update-check changeset * docs(cli): English changeset for the update-check timeout --------- Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
…(#3293)
* feat(auth): split model readiness from sign-in state in /api/v1/auth
GET /api/v1/auth now reports models_ready (the default model resolves
against the configured catalog, providerless and env-injected models
included) instead of the compound ready flag, and no longer carries
default_model — config values are served by /config alone. The v1
summary schema follows.
OAuth managed-model refreshes now heal a lost default model: the
refresh snapshot includes defaultModel, so an unchanged catalog with
a missing default still lands the write-back branch and re-selects
one. The refresh also rebases onto a fresh config read after the
remote fetch, so a model or thinking change made during the fetch is
no longer overwritten. The shared discovery refresh path (scheduler,
POST /providers/{id}:refresh) heals the default the same way.
Config changes are now published to WS clients on every write path:
a debounced+trailing publisher bridges IConfigService section changes
to ConfigChanged with camelCase changedFields and a full config
projection, and the broadcaster forwards event.config.changed and
event.model_catalog.changed (both previously published but never
delivered). All three event types are registered in the event unions,
so session_event parsing and AsyncAPI describe them.
BREAKING CHANGE: GET /api/v1/auth drops the ready and default_model
fields in favor of models_ready; event.config.changed's changedFields
is now camelCase domain names instead of the raw snake_case request
keys (v1 summary schema follows).
* fix(kap-server): expose the session model in session list projections
GET /api/v1/sessions hardcoded agent_config.model to '' and the v2
projection had no model field at all, so clients could only learn a
session's model via the post-select /status read — which races the WS
replay and often never lands. SessionFacts now carries the live
session's model (same source as the snapshot route), toWireSession
emits it, and the v2 activity domain gains a nullable model field.
* fix(kap-server): gate prompt submission on the effective session model
The submit gate called ensureReady() with no override, so it only ever
validated config.default_model: a session with a bound model (or a
prompt carrying one) was rejected with 40113 whenever default_model was
missing or dangling. Pass the effective model (request model, then the
agent profile's bound model, falling back to default_model inside
ensureReady) on both the prompt submit and btw routes.
* fix(agent-core-v2): honor defaultProvider in model readiness resolution
resolveModelForReady stopped at the flat baseUrl fallback, so a model
that omits provider/providerId and relies on the configured
defaultProvider resolved at runtime (ModelCatalog.resolveProviderContext
falls back to it) while /api/v1/auth reported models_ready:false and the
send gate rejected the prompt. Mirror the runtime order (providerId ->
provider -> defaultProvider -> flat baseUrl) and pass the configured
default provider from both readiness callers.
* fix(kap-server): redact inline model credentials from config responses
toConfigResponse only redacted the providers section, so a model's
inline apiKey/oauth rode GET /config verbatim and, via the new
event.config.changed publisher, every WS connection plus the persistent
event journal. Project the models section the same way: strip
credential fields and report has_api_key.
* fix(agent-core-v2): honor defaultProvider in ensureReady credential checks
The readiness phase learned the defaultProvider fallback, but the
credential phase right after still derived the provider only from the
model's explicit fields: a model omitting provider/providerId passed
readiness yet missed the default provider's apiKey/OAuth material and
prompts failed with auth.token_missing. Mirror the same provider chain
(providerId -> provider -> defaultProvider) when resolving credentials.
* fix(kap-server): validate the model a profile bind will select at the prompt gate
The gate validated the session's current model even for a prompt that
switches profile without a model — but bind falls back to defaultModel
in that case, so a stale session model drew a misleading 40113 before
bind could run. Gate on bind's selection order instead: the request's
explicit model, then the default on a profile switch, then the session's
bound model.
* fix(kap-server): redact inline service credentials from config responses
The earlier redaction covered providers and models, but toConfigResponse
still passed the services section through verbatim: inline or
env-injected apiKey, oauth references, and credential-bearing
customHeaders rode GET /config and, via the event.config.changed
publisher, every WS connection plus the persistent event journal.
Project services the same way: strip apiKey/oauth into has_api_key and
report only the header names as custom_header_keys (the MCP
envKeys/headerKeys convention).
* fix(kap-server): keep unlisted config domains through event validation
The config.changed broadcaster returned the zod-parsed config, which
strips domains absent from configResponseSchema (mcp, identity,
model_catalog, image, tools, token_counting): changedFields named them
while the advertised full snapshot no longer matched GET /api/v1/config.
Make the response projection passthrough (defineRoute validates only
requests, so REST responses are unaffected).
* fix(agent-core-v2): use the exact configured key for model readiness lookups
resolveModelForReady trimmed the model id before the models-table lookup
while ModelCatalog and ensureReady use the configured string as an exact
record key: a whitespace-padded default_model was reported ready and then
crashed the submit gate with an internal error instead of 40113, and a
legitimate key containing spaces was reported dangling. Trim only rejects
blank values now; the lookup always uses the raw key.
* fix(protocol): keep unlisted config domains in the shared event projection
The shared configResponseSchema stripped domains it does not enumerate
(mcp, identity, model_catalog, image, tools, token_counting, subagent,
secondary_model), so event.config.changed parsed through agentEventSchema
named them in changedFields while omitting their values. Make the shared
projection passthrough like the kap-server-local one.
* fix(agent-core-v2): use the exact default_provider key in readiness checks
The defaultProvider fallback trimmed the configured value before the
providers-table lookup while ProviderService and ModelCatalog use the
configured string verbatim: a whitespace-padded default_provider could
build successfully yet report not-ready (40113), or report ready for a
provider runtime resolution cannot find. Trim only rejects blank values;
the lookup uses the raw key.
* chore: sync web dist from code-app
Rebuild the bundled web UI against this branch's /auth contract (models_ready, no ready/default_model): the previous bundle still read the old fields and stayed in the not-ready flow against this server.
code-app: 000d2594ff3e95b553be326126bab3f939b62944
* Revert "chore: sync web dist from code-app"
This reverts commit 9400a24a03863b3e8b780dda251540f824f02f3a.
* fix(oauth): rebase the default selection after the refresh fetch
A provider refresh snapshots the config before the remote catalog fetch;
when the user selects a default model while the fetch is in flight, the
stale snapshot's empty default made an otherwise unchanged catalog enter
the write path and the self-heal persisted the generated default over the
user's newer selection. Each branch now re-reads and rebases the
default/thinking selection after its fetch, before cloning, comparing,
or writing.
* style(kap-server): pass optional custom_header_keys without conditional spread
…transcript (#3328) * fix(kap-server): only fold user-origin steers by content in the cold transcript * fix(transcript): check marker-only origins before the steer content match * fix(transcript): limit the steer bypass to marker-only skill triggers * fix(transcript): consume the steer count for marker-only activations * fix(transcript): pair steered contents with messages by origin kind * refactor(kap-server): read the steer origin kind without nested casts --------- Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
…325) * fix(agent-core-v2): cache workspace alias resolution across calls resolveAliasIds re-read the workspace catalog and the whole session index from disk on every call, so the by_workspace grouping loop and the per-workspace session counts paid repeated full-file reads per workspace per request (~2.4s per 50-group page at 1.1k workspaces, 23 pages serially during a client startup drain). Cache both files as precomputed snapshots (by-id map plus a root-key -> alias ids index) invalidated by the storage watch events, which cover atomic rewrites and cross-process writes; storage backends without watch fall back to reading through. The first resolution primes the workspace merge via IWorkspaceService.list() so the cached catalog matches what WorkspaceService.get() would have returned. * chore: drop the changeset; the user-facing entry ships with the app changelog * fix(agent-core-v2): coalesce cold alias snapshot loads and guard publication Concurrent cold resolveAliasIds callers (the /workspaces route fans out per-workspace counts with Promise.all) all passed the cache check before any caller finished loading, re-running the full catalog and session index reads the cache exists to avoid; memoize the in-flight load promise so a cold batch shares one read. Also capture the invalidation generation before each read and publish the snapshot only when it is unchanged, so a mid-read file replacement cannot leave a stale snapshot installed over the watch invalidation. * fix(agent-core-v2): publish catalog invalidation through the persistence owner A debounced fs watch was the only invalidation channel for the alias catalog snapshot, so an in-process catalog write stayed invisible to resolveAliasIds for up to the watch debounce window while the previous read-through code observed every completed write immediately. IWorkspacePersistence now exposes onDidChange: FileWorkspacePersistence fires it synchronously on save and re-fires the underlying document watch (covering atomic rewrites and cross-process writers), and the aliases service subscribes to it instead of watching raw storage keys. The session index snapshot keeps the filesystem watch, matching the read-side ownership of that file. * fix(agent-core-v2): invalidate session alias snapshots on append-log writes A flushed session_index.jsonl append was invisible to resolveAliasIds for up to the fs-watch debounce window, so a sessions request issued right after a session create could resolve the workspace's aliases from the pre-append snapshot. IAppendLogStore now publishes onDidWrite after each durable flush (append batches and rewrites), and the aliases service drops its session-index snapshot through that event; the raw filesystem watch stays as the channel for cross-process writers. * fix(agent-core-v2): fire append-log write events only after actual writes Once a key has a LogState, every global flush() (WireService flushes after ordinary agent persistence) completed it successfully and fired onDidWrite unconditionally, so idle agent activity kept dropping the alias session-index snapshot and forced full re-reads of an unchanged index. drain() now reports whether it appended anything and the write event fires only when a flush actually persisted a batch or a rewrite. * fix(agent-core-v2): retry shared snapshot loads that span a write Callers joining an in-flight single-flight load after a completed write still received the pre-write snapshot: the generation check only guarded cache publication, not the value returned to awaiters. Each load now carries the generation it started at, and catalog()/sessionIndex() re-read (coalesced through the same single-flight) when the settled load's generation is stale. * fix(agent-core-v2): report partial progress when an append-log drain fails A drain that persisted one batch and then failed the next threw without recording the durable write, so onDidWrite never fired for records that were in fact persisted (the alias session-index snapshot then missed its synchronous invalidation). The write box now threads through the whole owned flush: each successful batch marks it, and the event fires before the failure propagates. * fix(agent-core-v2): retry the whole alias resolution across a mid-write The per-snapshot retry guarded each read on its own, so a write landing between the catalog and session-index reads returned an alias set assembled across two generations. resolveAliasIds now captures the generation once, reads both snapshots together, and retries the whole resolution when either input was invalidated mid-flight. The spanned-write test is reworked to gate after the load (so the snapshot content genuinely predates the write), and a new case covers the cross-generation mix directly. * fix(agent-core-v2): replace the session-index fs watch with a size check A resident chokidar watcher per server on the shared home directory degraded watch delivery for unrelated files under test-suite boot volume (the prompts suite lost the config.toml reload race and the catalog missed a just-written model). In-process appends were already covered synchronously by the append-log write event; cross-process writers now surface through a per-call size comparison on the append-only file, which costs one stat per resolve and needs no resident watcher.
* chore: sync web dist from code-app code-app: 2139742c91c097a1e26cec7044970067a7e3d736 * chore: clarify web sync changeset wording Reword two synced changesets to describe the actual upstream code-app changes (#420, #439). Release contents unchanged. --------- Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* ci: add VS Code extension publish workflow Publish VSIX to VS Marketplace and Open VSX on version-change pushes to main, with online-version gates and workflow_dispatch fallback. * ci(vscode): harden publish gate with before-SHA diff and per-platform checks Address review on the auto-publish workflow: - Version-change detection now compares against the push event's `before` SHA instead of `GITHUB_SHA~1`, so a single push carrying multiple commits cannot skip a version bump. An empty or all-zero `before` (e.g. first push of a branch) is treated as a version change — better an extra marketplace lookup than a missed release. - Marketplace gates now verify all 6 targetPlatforms (darwin/linux/win32 x x64/arm64) instead of only the version number: Open VSX is checked per-platform via REST, VS Marketplace via the targetPlatform entries in `vsce show --json`. A partially published version now reruns the affected publish step, which backfills idempotently via --skip-duplicate / already-exists handling. Lookup failures stay fail-closed (treated as not published). --------- Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
… (#3803) * fix(plugins): rename WebBridge display name to Kimi Browser Extension The product has renamed WebBridge to Kimi Browser Extension in work and Chrome. Update the user-facing display name across the built-in capability entry, TUI plugins selector, managed plugin manifest, marketplace catalog, skill docs, and user docs to match. Internal ids, binary names, CDN paths, and daemon references are unchanged. * fix(plugins): bump webbridge to 1.11.4 and keep legacy docs anchor Address review: point the changeset at the scoped CLI package, bump the renamed plugin's manifest/catalog/docs version so installed users are offered the renamed package as an update, and preserve the published #kimi-webbridge documentation anchor beside the renamed heading. * docs(plugins): match only the known extension-update error messages Broadening the version-mismatch trigger to the generic prefix 'Please update the' would misclassify unrelated tool errors as an outdated browser extension; match the two known full messages instead. --------- Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
* refactor(agent-core-v2): clarify human-layer names * refactor(agent-core-v2): name provider-holding members after their role - LlmRequestConfig/LlmRecoveryContext/adapter Model: credentials -> credentialProvider - requester/provider convertError option -> classifyError (matches LlmErrorClassifier) - kimiOAuthCredentialProvider -> createKimiOAuthCredentialProvider - ModelCatalog.buildCredentials -> buildCredentialProvider * refactor(agent-core-v2): rename the format-layer error hook to classifyErrorHook threads the requester's classifyError option through under a matching name * refactor(agent-core-v2): finish the human-layer naming pass - turn.failure.classified -> turn.failure.recovery.evaluated - recovery proposal beforeRetry -> beforeNextAttempt - llmRequester currentCredentials/credentialsForTurn -> currentCredentialProvider/credentialProviderForTurn - unexport ProtocolTraitsByName (only backs ProtocolTraitFor) * refactor(agent-core-v2): shorten the turn failure event to turn.failure.evaluated
* refactor(agent-core-v2): align request and recovery stage names * refactor(agent-core-v2): align cache key, google-genai, and recovery context names
…che (#3778)
* perf(tui): batch and cache agent swarm progress rendering
* perf(agent-core-v2): evict completed subagent scopes behind an LRU cache
* fix(agent-core-v2): stop the agent actor in the session machine when its scope is removed
* fix(agent-core-v2): emit a terminal event for the final rate-limited run and defer eviction while background tasks run
* fix(agent-core-v2): include in-flight retries when abandoning suspended agents
* fix(agent-core-v2): roll back the closing flag when scope removal fails and wait per the configured eviction timeout
* fix(agent-core-v2): terminalize subagents spawned after batch cancellation and report task timeouts as failures
* chore: restore upstream/main state of files mangled by lint-staged autofix in the merge commit
oxlint --fix rewrites (prefer-set-has, catch-error-name, prefer toSorted/.at(-1)/toReversed)
touched seven files the branch never modified; one of them (oauth managed-kimi-code.ts)
no longer typechecks. Restore all seven to their exact upstream/main state. Committed
with --no-verify so the same autofix does not re-mangle them.
* fix(agent-core-v2): retry deferred scope evictions without exhausting the attempt budget, dedupe terminal events for starting retries, and patch-level the changeset
* fix(agent-core-v2): finish scope teardown instead of reactivating a partially torn-down scope
* fix(agent-core-v2): terminalize subagent-start hook cancellations and re-acquire resume targets after metadata reads
* fix(tui): record cancelled background agents in the transcript
* fix(agent-core-v2): route mirror terminal events through the batch exactly-once guard
* fix(tui): guard terminal swarm members from re-cancellation and deliver terminal status to cancelled foreground subagent cards
* fix(agent-core-v2): classify eviction as removed when teardown already closed the scope
* Merge remote-tracking branch 'upstream/main' into perf/subagent-scope-eviction
Skip lint-staged for this merge: its oxlint --fix pass rewrites unrelated files
(prefer-set-has etc. mangled seven files in the previous merge commit), while the
merge content is upstream's lint-clean code plus conflict resolutions already
verified by oxlint.
* chore: restore upstream/main changes dropped by a stash roundtrip during the merge
A git stash/pop cycle used to isolate an unrelated flaky test reverted 82 files of the
merge result to the pre-merge branch state, so commit 375ff2a4a missed them. The
working tree already held the correct merged content; this commit restores it.
* fix(agent-core-v2): propagate the cancellation reason from turn abort to tool signals
Cancelling a turn aborted the turn's llm scope and every tool scope
without a reason, so tools and subagents only ever saw the default
AbortError and could not tell a user cancellation from a system abort.
With the swarm terminal-event classification this surfaced as
`subagent.failed` ("This operation was aborted") on Ctrl+C instead of
`subagent.cancelled`.
Carry the reason end to end: `MachineEngine.abort(reason)` sends it on
`input.abort`, the agent machine remembers it for the turn and forwards
it to `turn.abort` and to every tool scope it aborts, the turn machine
passes it to the llm scope, and the loop service hands its cancellation
(a `UserCancellationError` by default) to the engine.
* fix(agent-core-v2): stop rebuilding an evicted subagent after its caller aborts
`createAgentAwaitingClose` polled for the previous scope to finish
closing without ever looking at the caller's abort signal, so cancelling
an `Agent` or `AgentSwarm` resume during that wait still recreated the
scope afterwards. In the `Agent` path the run then rejected before any
terminal event was mirrored, leaving an idle scope that the scope cache
no longer tracked.
Thread the caller's signal into the helper and check it before every
attempt; the Agent tool passes its call controller and the swarm service
passes the attempt signal. Also trim the eviction changeset to the one
sentence the changeset rules ask for.
* fix(agent-core-v2): report task-manager aborts of a subagent as cancelled
When the task manager times out or stops a background subagent it aborts
the run with a plain reason ('Timed out', the TaskStop reason), and the
run rejects with that raw reason. The task manager therefore classifies
the task as timed_out or killed, but the mirror only recognised
`UserCancellationError` as a cancellation and emitted `subagent.failed`,
so the transcript recorded a failure before the authoritative
`background.task.terminated` event could land.
Classify a terminated run by the shape of its abort reason: a real
Error that is not an AbortError (the swarm's own per-item timeout) stays
a failure, everything else that aborted the run is a cancellation. The
swarm's start-failure path uses the same rule.
* fix(agent-core-v2): flush the wire before evicting a subagent scope and re-pick LRU candidates
Two gaps in the scope-cache eviction pass:
- `AgentLifecycleService.remove()` swallows a failed wire flush and still
tears the scope down, so an eviction that hit a disk-full or transient
I/O error would drop the in-memory scope and let a later resume rebuild
from a stale wire. Flush the agent's wire explicitly before removing;
if that fails, keep the scope resident and retry on a later pass. The
idle and task checks are repeated after the flush so a resume that
started meanwhile is not cancelled by the removal.
- The pass snapshotted its candidates up front and re-validated them by
attempt count only, so a scope that was resumed and completed again
while an earlier eviction was awaited kept matching with attempts 0 and
was evicted despite now being the most recently used. Pick the oldest
eligible entry from the live map on every step instead, skipping only
the entries this pass already tried.
---------
Co-authored-by: Kaiyi <me@kaiyi.cool>
…st message (#3818) * fix(tui): stop /usage and /status from prompting login before the first message * docs(changeset): simplify the /usage fix entry * fix(tui): mute the session-usage error line and cover the session-less path in tests * docs(changeset): restore the confirmed wording
… (#3784) * feat(agent-core-v2): upload images as file references for Kimi models * fix(agent-core-v2): scope media upload cache by endpoint and recognize SDK auth error status * fix(agent-core-v2): restore the stripped /v1 for kimi files uploads on the anthropic route * feat(agent-core-v2): omit oldest media when accumulated inline media exceed the request budget * fix(agent-core-v2): key the media upload cache by the stable JWT subject * fix(agent-core-v2): harden media request recovery * fix(agent-core-v2): correct image memo accounting * feat(agent-core-v2): include saved paths in dropped media placeholders * docs: drop the saved-path re-read guarantee from the media budget note The guarantee does not hold for inline data-URL media (no persisted path exists), and the runtime warning already conveys path availability when it applies. Addresses the codex P2 review suggestion by removal.
…3827) Media name preservation already ships: the REST schemas expose a name on image and video content, and kap-server reads imageUrl.name and videoUrl.name when projecting messages and prompt content. The kosong part types never declared the field, so it survived only because object literals keep excess properties through an assignment. Consumers that read these types directly cannot see the name at all. Declare it where the other optional part fields live. No runtime change; the existing media name projection tests continue to cover the behavior.
…#3831) Widen activateSkillAttachmentSchema so the attachments array accepts text parts alongside image, video and file, letting a caller interleave text and media in the order the model should read them. Schema only; the route already resolves attachments as WireContent.
…3833) Co-authored-by: konghuanjun <konghuanjun@moonshot.ai>
…ocess crashes (#3838)
…unning turn (#3832) Accept skill_activation origins with a user-slash trigger in onTurnSteered so a slash command sent while a turn is running gets a transcript frame, and keep those frames from draining a queued prompt's id. Project origin file attachments onto steered frames on both the immediate and deferred paths, matching onTurnStarted and the history rebuild.
* fix(kap-server): rebuild chat transcript after undo * test(kap-server): provide undo registry in broadcaster fixtures * fix(kap-server): preserve non-anchor steers through undo * fix(kap-server): rebuild undo transcript after persistence completes * test: complete restored notification origin fixture
…ns (#3764) Store the optional metadata object on prompt submission and skill activation as opaque client metadata on the user or skill-activation origin, carry it through prompt events, the transcript projector, snapshots and history rebuilds, and echo it on prompt items without adding it to model content. Use display_text entries for session titles, undo labels and fork titles when every entry provides one. Project user turn payloads, live and rebuilt, through a path-free projection.
…form (#3840)
* fix(agent-core-v2): watch Windows 8.3 short paths through their long form
Watching a directory given in 8.3 short form (for example
C:\Users\RUNNER~1\...) makes libuv's Windows file watcher abort the process
with "Assertion failed: !_wcsnicmp(filename, dir, dirlen)" in fs-event.c,
because change notifications arrive under the long path.
On Windows, resolve a watch root containing a short-name segment to its long
form (the nearest existing ancestor when the root does not exist yet) and map
reported changes and ignore checks back to the requested path, so callers that
compare change paths with their own keep working.
* test(agent-core-v2): keep watch tests portable to Windows runners
* test(agent-core-v2): show received events when the Windows short path watch test fails
* test(agent-core-v2): derive the Windows short path without cmd quoting
* chore: add changeset for the Windows short path watch fix
* fix(agent-core-v2): keep watch children whose names start with two dots inside the root
relative() returns "..cache/x" for a child named "..cache", which the
startsWith('..') check treated as a path outside the watched root. Mapped
change paths then kept the resolved long form, and native signal events for
such children skipped the ignore predicate. Only a bare ".." segment, ".."
followed by a separator, or an absolute result is outside the root.
…ly (#3843) * feat(agent-core-v2): add skill scopes and mark custom-theme as tui-only Builtin skills can now declare a scopes whitelist (tui | web); skills without scopes stay visible everywhere. The value is carried through SkillSummary, the klient RPC contract, and the kap-server REST wire, and the TUI slash commands filter by it. HTTP clients (code-app) drop skills whose scopes exclude their own UI mode, so TUI-only skills like /custom-theme no longer leak into app/web. * fix: filter scoped skills from the acp and vscode palettes ACP slash commands and the VS Code GetSlashCommands handler also project SkillSummary lists; both now drop skills that carry a scopes restriction so tui-scoped skills stay out of non-tui clients.
…anscripts (#3844)
… (#3849) * feat(cli): add /desktop slash command and kimi install-app subcommand Both entry points print the Kimi Code desktop app page (https://www.kimi.com/code) and open it in the default browser: the kimi install-app subcommand from the shell, and /desktop (alias /install-desktop) from the TUI. * fix(cli): derive the desktop app page from the active region Replace the hardcoded .com URL with the existing region-aware kimiCodeOfficialInstallUrl() resolved at invocation time, so global-region users land on the .ai site and region changes are respected. * docs(cli): describe the desktop app page URL as region-dependent
code-app: 3d1122617a5f16d96f4eb8308e76271e21f82c92
* fix(kap-server): rebuild chat transcript after undo * test(kap-server): provide undo registry in broadcaster fixtures * fix(kap-server): preserve non-anchor steers through undo * fix(kap-server): rebuild undo transcript after persistence completes * test: complete restored notification origin fixture * fix(kap-server): keep original prompt when steering * chore: add changeset for steered prompt content fix * fix(kap-server): keep restored prompt content after late projector attach * fix(kap-server): prefer store prompt content after transcript backfill
…rns 401 (#3846) * fix(agent-core-v2): mark MCP servers needs-auth when a tool call returns 401 * fix(agent-core-v2): cover retried MCP calls with unauthorized handling and recheck entry after close * fix(agent-core-v2): bind MCP unauthorized reports to the originating client * fix(agent-core-v2): invalidate rejected MCP OAuth tokens when entering needs-auth * fix(agent-core-v2): preserve concurrent MCP OAuth grants and recheck entry after credential awaits * fix(agent-core-v2): flip MCP servers to needs-auth before invalidating rejected tokens * fix(agent-core-v2): compare-and-clear rejected MCP OAuth tokens and tolerate cleanup failures * refactor(agent-core-v2): move rejected-grant handling into the MCP OAuth service * fix(agent-core-v2): compare MCP OAuth grant age with the scheduler clock * fix(agent-core-v2): reject future timestamps from the concurrent MCP grant window * fix(agent-core-v2): distinguish concurrent MCP grants from freshly rejected ones * fix(agent-core-v2): ignore application-level MCP errors in the unauthorized sniff * test(agent-core-v2): trim MCP unauthorized tests to the core contract * Delete .changeset/mcp-oauth-clear-if-current.md Signed-off-by: 7Sageer <sag77r@hotmail.com> --------- Signed-off-by: 7Sageer <sag77r@hotmail.com>
code-app: 3f3f3b2e52115eb0b79bc04ed4fcc2d45b30fe5d
* ci: sign Windows CLI binaries with Azure Artifact Signing * fix: resolve signtool from Windows SDK when removing SEA binary signature
* ci: release packages * chore: bump kimi-code release version to 2.0.0 --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: liruifengv <liruifeng1024@gmail.com>
Bring the fork up to @moonshot-ai/kimi-code@2.0.0 (448 commits). All ten hardening changes are carried forward and verified present after the merge; upstream fixed none of them independently. Conflicts of note: - Permission policy chain. Upstream added DangerousCommandAsk at position 3, above session-approval history and user allow rules. That placement is kept, and this fork's move of AutoModeApprove below the content-sensitive asks is kept alongside it, so auto mode still does not waive the secrets, .git and execution-trigger checks. Upstream skips the guard for non-interactive hosts; that skip is dropped so a headless host in manual or yolo mode stays guarded. - Approval broker. Upstream replaced the broker with interactions.request, so the unattended refusal is re-expressed against the new API. A headless run that needs approval still refuses with an explanation instead of waiting for an answer that cannot arrive. - Plugin marketplace. Upstream moved resolveMarketplaceLocation from the CLI into agent-core-v2. The https requirement and host allowlist move with it, extended to cover the new .ai region hosts. - Native update preflight. Upstream's staged swap verifies a SHA-256 manifest, which supersedes this fork's patch, so upstream's version is taken. agent-core-v2, kap-server and transcript are comment-free zones upstream now (scripts/check-no-comments.mjs runs in pnpm lint), so the security rationale that lived in comments there moves to HARDENING.md. Verified: typecheck, lint and build clean. The test suite has 71 failures, all in kap-server search and transcript contract; the identical 71 fail on a clean upstream 2.0.0 checkout, so the merge adds no regressions. Runtime checked against a stub endpoint: a headless Bash call is refused rather than executed or hung, and runs when KIMI_CODE_AUTO_APPROVE_BASH is set. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The fork was pinned at upstream 0.34.0. Upstream has since released 2.0.0 (448 commits), and the fork's ten hardening changes needed to be carried across a major version rather than silently lost to auto-merge.
What changed
Merges
@moonshot-ai/kimi-code@2.0.0intomain.Every hardening change was re-verified present in the merged tree, including the ones that did not conflict and so could have been dropped without a marker. Upstream fixed none of them independently.
Conflicts of note:
DangerousCommandAskat position 3, above session-approval history and user allow rules. That placement is kept, and this fork's move ofAutoModeApprovebelow the content-sensitive asks is kept alongside it, so auto mode still does not waive the secrets,.gitand execution-trigger checks. Upstream skips the guard for non-interactive hosts; that skip is dropped, so a headless host inmanualoryolomode stays guarded.interactions.request, so the unattended refusal is re-expressed against the new API. A headless run that needs approval refuses with an explanation instead of waiting for an answer that cannot arrive.resolveMarketplaceLocationfrom the CLI intoagent-core-v2. The https requirement and host allowlist move with it, extended to cover the new.airegion hosts.agent-core-v2,kap-serverandtranscriptare comment-free zones upstream now (scripts/check-no-comments.mjsruns inpnpm lint), so the security rationale that lived in comments there moves toHARDENING.md.Verification
pnpm typecheck,pnpm lintandpnpm buildclean.Bashtool call is refused rather than executed, with no hang, and the probe file is not written. WithKIMI_CODE_AUTO_APPROVE_BASH=1the same call runs and the file appears, so the check is not passing because Bash is broken.Follow-ups, not in this PR
Upstream 2.0.0 adds network surface that needs a policy decision before the fork is rolled out:
packages/remote-controlregisters the machine with a relay atcode-rc.kimi.comand forwards public traffic into the local server. Opt-in, butPOST /api/v1/remote-controlcan enable it with no terminal interaction, and the long-lived OAuth refresh token travels in a WebSocket subprotocol header.api.kimi.{com,ai}/coding/v1/tools; the experimental flag that used to gate this no longer exists.globalregion profile adds five.aihosts that can become the update, marketplace, binary, OAuth and telemetry destinations, so an egress allowlist naming only*.kimi.comis now incomplete.🤖 Generated with Claude Code