mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-25 00:27:32 +00:00
381 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ea0626ad48
|
fix(agent-core): gate background questions on task controls (#3159)
* fix(agent-core): gate background questions on task controls * fix(agent-core): recheck background question policy |
||
|
|
d723cc47ee
|
feat(agent-core-v2): add the unified MCP management plane (#3002)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* feat(agent-core-v2): add the unified MCP management plane Port the v1 MCP management plane (#2858) onto the v2 DI x Scope engine: - App-scope IMcpOAuthService shared by every workspace handler and session overlay: credential events, single-flight refresh, proactive refresh timers, OAuthTokenTransaction-serialized writes, offline tokenState, shutdown. Providers read tokens through the store so grants written or revoked by another process are honored immediately; http/sse transports ride the transaction fetch. - IMcpConfigStore: the single write point for the user-level mcp.json over the filesystem byte store, byte-identical to v1's format, with per-entry validation, name normalization, __proto__-safe parsing, a mutation tail, and an onDidWrite event. - IMcpRegistryService: the unified read view over the layered config files (with per-entry origins) and plugin manifests (full descriptors incl. disabled, with provenance); collisions stay visible and runtime resolution ranks an enabled plugin above the file layers. - IMcpManagementService: guarded CRUD, connection-test probes, the locator-addressed inspection/auth-status surface, and locator-addressed OAuth begin/complete/cancel/reset with ambiguity rejection. Engine services stay ungated; the mcp_management flag gates the edge exposure. - Workspace runtime aligns with v1 precedence (an enabled plugin entry wins over the file layers, shadows revive), and management writes reload immediately via onDidWrite instead of the watch debounce. - node-sdk v2 facade delegates to the engine service (deleting its in-process duplication); kap-server exposes /api/v2/mcp/* and klient gains global.mcp.*, both flag-gated. * fix(agent-core-v2): settle early and cancelled MCP OAuth callbacks * refactor(node-sdk): write session MCP persists through the engine config store * refactor(agent-core-v2): strip comments from the MCP management plane files * fix(agent-core-v2): harden MCP management readiness * test(node-sdk): cover offline MCP auth statuses * fix(agent-core-v2): isolate stdio MCP probes * fix(klient): normalize MCP OAuth errors * fix(mcp): honor workspace CRUD context and refresh timing * fix(mcp): drain OAuth refreshes during shutdown * fix(mcp): guard CRUD across registry collisions * fix(mcp): canonicalize trust and refresh scheduling * fix(mcp): close callback listener on setup failure * fix(mcp): preserve trust and oauth behavior * fix(oauth): retain refresh tokens after SDK saves * fix(oauth): stop proactive sweep during shutdown * fix: await MCP workspace reconciliation * fix: serialize MCP OAuth and trust cleanup * fix: reject persisted MCP plugin collisions * fix: reconcile MCP workspaces concurrently * fix(mcp): check project-layer trust at the queried cwd * fix(mcp): expire abandoned OAuth flows after an idle timeout * fix(mcp): keep mutable user entries writable past read-only collisions * fix(mcp): abort the auth::complete long poll on client disconnect * fix(mcp): map OAuth flow failures to wire code 40929 * docs(mcp): note probe credential effects and plane semantics * chore: add the SDK changeset for MCP management cwd params * feat(mcp): expose the management plane without the experimental flag * fix(mcp): preserve auth management semantics * fix(agent-core-v2): bound MCP OAuth auth-server requests and the shutdown drain * fix(node-sdk): restate engine MCP management errors as KimiError * fix(agent-core-v2): preserve shared OAuth flow lifetime * fix(agent-core-v2): close MCP OAuth cancellation and shutdown gaps - bound the authorization-code exchange with the request timeout and the flow/caller abort signals, and make shutdown abort hung begins and close their callback listeners immediately - keep token-transaction effect coalescing intact when durable tokens carry local stamps, and serialize the meta sidecar and tokens-saved event with the token write inside the lock - drain transport-driven grants, their trailing SDK save continuations, and interactive completions during shutdown, with a cancellable deadline * fix(agent-core-v2): harden MCP probe runtime resolution and path handling - resolve stdio probes against the containing workspace's runtimes and reject out-of-workspace probes for non-local runtime_id instead of silently falling back to a local-only transient registry - share one Windows-aware path canonicalization across the config loader, registry trust lookup, trust records, and workspace matching - keep a UTF-8 BOM fatal for the user-level mcp.json store, matching the workspace loader and v1 - validate completeServerAuth timeoutMs bounds at the engine boundary * fix(agent-core-v2): await workspace MCP reconciliation on plugin mutations Plugin install/enable/disable/remove now resolve only after reload listeners settle their waitUntil work, so a disabled plugin's MCP server cannot linger connected and an enabled one is visible to the next session, matching v1. The workspace MCP consumer joins the barrier while keeping its log-only failure tolerance; delivery is awaited outside the mutation queue to avoid self-deadlock through consumption reads. * fix(mcp): close the SDK, klient, and server edge gaps - register mcp.oauth_failed in the v1 error registry and restate unknown engine codes as internal instead of minting undeclared KimiError codes - route persisted session MCP adds through the same KimiError restating as the global management methods - give the klient IPC transport a per-call timeout so completeAuth's long poll outlives the 30s default, clamped to the Node timer ceiling, and align the contract timeoutMs upper bound with REST - await the MCP OAuth service shutdown directly in SDK and server close before scope disposal * fix(agent-core-v2): keep file-over-plugin MCP precedence and harden the plane - Revert the v1-style precedence flip: the workspace merge and resolveRuntimeTarget keep the file entry above plugins (v2's historical order; the divergence from v1 is deliberate and documented in AGENTS.md). - Guards follow each engine's winner: project-layer entries stay read-only, while plugin entries never block user-level writes, so a file entry may shadow a plugin and removing it revives the plugin. The parity suite pins the engine split for a persisted session add over a plugin-owned name. - inspectServers tolerates a wire-encoded null targets array: klient's ipc transport sends null for an omitted leading optional argument. - Fire the config store's onDidWrite after the mutation tail settles, so a write listener can re-enter the store without deadlocking the queue; concurrent-mutation and re-entrant-listener tests pin both contracts. * chore: condense the sdk MCP changeset to one sentence * test(node-sdk): pin verify:false auth-status parity and fix the sdk changeset |
||
|
|
30e7f62d2c
|
fix(kaos): resolve Git Bash POSIX paths for file tools on Windows (#2200)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
Add a shell path bridge that translates between win32 paths and the MSYS2/Git Bash path dialect. File tools resolve model-supplied paths through it before canonicalization and workspace checks: drive-letter forms translate lexically, root-relative paths resolve via cygpath -w with per-segment caching, and every failure mode falls back to the previous behavior. Fixes #2199 |
||
|
|
3fdce983f8
|
fix: drain in-flight persistence and log writes on session close and shutdown (#3122) | ||
|
|
d96b4a0149
|
fix: fail fast on provider-filtered empty responses (#3101)
* fix: fail fast on provider-filtered empty responses An APIEmptyResponseError carrying finishReason 'filtered' (OpenAI content_filter, Anthropic refusal) is deterministic: replaying the same request re-triggers the provider safety filter. Both isRetryableGenerateError implementations (kosong, agent-core-v2) treated every empty response as retryable, so step retry replayed the doomed request the full 10 attempts before the filter notice surfaced. Return non-retryable for filtered empty responses in both engines; the error already carries the provider.filtered code, so the turn fails immediately with the existing filter notice. * fix: skip the compaction shrink-retry for filtered empty responses Both full-compaction loops routed every APIEmptyResponseError into the shrink-and-continue branch before isRetryableGenerateError was consulted, so a filtered response was retried with shrinking input instead of failing fast. Exclude finishReason 'filtered' from the shrink branch in both engines; it now falls through to the retryability check and throws immediately. Add end-to-end tests (real kosong generate over a filtered think-only stream) asserting a single attempt with the history untouched. --------- Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com> |
||
|
|
3d7762003a
|
feat(kimi-code): support two OAuth login endpoints (#2862)
* feat(kimi-code): add China/International region selection for OAuth login
- Add region profiles (cn/overseas) and resolver in @moonshot-ai/kimi-code-oauth:
env override → persisted login host → install-channel marker → default cn
- /login now offers Kimi Code (China) / Kimi Code (International); the CLI
login entries (kimi login, kimi acp --login) accept --region cn|overseas
- Update/plugin/site/telemetry endpoints derive from the selected region;
plugin trust list covers both .com and .ai hosts
- kap-server: POST /oauth/login accepts an optional region; new GET /oauth/region
* fix(oauth): keep an explicit default-slot login ahead of the install marker
A China login persists no oauthHost (the default credential slot carries
no host trace), so after switching back from International the resolver
fell through to a stale overseas install marker. Treat a persisted
default-slot oauth ref (key === oauth/kimi-code) as an explicit-cn signal
that outranks the marker; getRegion() on the v2 side mirrors it.
* fix(agent-core-v2): thread the default-slot key through capability region resolution
Capability installs resolved the region from the persisted oauthHost only,
so an explicit China login (which persists no host) lost to a stale
overseas install marker. Pass the oauth ref key through as well, matching
getRegion(). Also move the region contract notes into the auth.ts file
header per the package comment convention.
* fix(agent-core-v2): honor the region-marker opt-out for the telemetry endpoint
Hosts that set KIMI_CODE_REGION_MARKER=off (the desktop embedded server)
skip the install marker in getRegion(), but the default telemetry endpoint
still consulted it, so a stale overseas marker could split the reported
region from the telemetry destination.
* feat(cli): show region site domains in login platform selector
* chore: reword oauth login changesets
* fix: honor the region marker opt-out in the CLI and capability resolvers
* refactor: rename login region values to mainland-cn and global
* fix: keep the --region help text in English
* fix: simplify the --region help text to site domains
* feat: drop the suggested login platform order
* feat: split a browser-safe region profile table out of the region resolver
* Revert "feat: split a browser-safe region profile table out of the region resolver"
This reverts commit
|
||
|
|
86674ac895
|
test: remove wording-pinning tests of model-facing prose across both suites (#3031)
* test: replace prose-pinning system-prompt tests with a structural sharing check
The two removed tests pinned exact sentences of the default system prompt
('reversibility and blast radius', 'premature abstraction', optional-tool
phrasings that must not appear, ...). They broke on any intentional
wording change while only catching regressions that reused the same words.
The one real contract underneath — shared, ungated sections must render
byte-identically in the root agent and every subagent profile — is now
checked structurally by slicing the section out of the root prompt and
asserting the other profiles contain it, regardless of its wording.
* test: remove wording-pinning tests of model-facing prose across both suites
Sweep of the class identified in #3030: assertions pinning the exact
English wording of product model-facing text (system prompt, reminder
and injection .md files, tool descriptions, shipped profile/skill
bodies). They break on any intentional rewording yet only catch
regressions that reuse the same words.
Across 35 files (~60 test cases, net -1131 lines):
- deleted dedicated wording tests: 'exposes current metadata and
schema' description pins, goal/plan/todo reminder content tests,
tower skill-body prose pins, goal-outcome.test.ts;
- trimmed wording assertions from behavioral tests that otherwise
stand alone; kept identifiers (tool names, XML tags, section
markers), structural properties (wrapping/escaping/gating/cadence),
fixture data, tool outputs and error messages;
- re-anchored a few gating tests on exported constants
(WINDOWS_PATH_HINT, DEFAULT_REPLY_STYLE_GUIDE) instead of prose
literals.
Deferred for a follow-up decision: ~15 tests whose prose pin is the
only discriminator of which reminder/budget-band fired (constants not
exported). Wire baselines and snapshot machinery untouched.
|
||
|
|
5c8df5973e
|
test: drop the assertion for the removed ambiguous-means-task example (#3030)
#3028 removed the 'treat ambiguous requests as tasks' rule and its 'locate the method in the code' example from the default system prompt. The profile test pinned that example verbatim, so it now fails on main. The removal was intentional; update the test to the new contract. |
||
|
|
40e1784089
|
fix: tone down over-proactiveness in the default system prompt (#3028)
* fix: tone down over-proactiveness in the default system prompt The default system prompt pushed the agent to act before discussing: ambiguous requests were explicitly resolved to tasks, the opening framed the primary goal as taking action, and 'default to making progress, not to asking' discouraged clarifying questions. Trim both copies (agent-core and agent-core-v2) by deletion only: the ambiguous-means-task rule and its example, the action-framed opening clause, the 'default to taking action with tools' paragraph, the duplicated must-use-tools sentence (kept once in Ultimate Reminders), and the 'default to making progress, not to asking' bullet. Operational guidance and the execution guards stay untouched. * Delete .changeset/tame-system-prompt-proactiveness.md Signed-off-by: 7Sageer <sag77r@hotmail.com> * fix: drop the tool-use and no-placeholder bullets from the default system prompt --------- Signed-off-by: 7Sageer <sag77r@hotmail.com> |
||
|
|
d3150fe947
|
chore: remove internal-network references from comments and test fixtures (#3029)
* chore: remove internal-network references from comments and test fixtures - Reword two comments that named the internal free-tokens model registration flow; the generic OAuth / managed wording carries the same meaning - Replace the qianxun.example placeholder base URL in google-genai and runtime-provider tests with genai-gateway.example - Swap realistic-looking LAN fixture IPs in the kimi web banner tests (192.168.98.66, 10.8.12.216) for RFC 5737 documentation addresses (192.0.2.66, 198.51.100.216) * chore: retrigger CI (flaky kap-server searchRoute title-indexing test) --------- Co-authored-by: bj456736 <bj456736@users.noreply.github.com> |
||
|
|
59dde734f3
|
feat(agent-core): unify the v1 MCP management plane (#2858)
* feat(agent-core): unify the v1 MCP management plane - McpServerRegistry: one config view over global (layered mcp.json), plugin (manifests, read-only, final effective config), and caller (SDK-injected) servers; name collisions keep both entries. - Write plane: add/update/removeGlobalMcpServer mutate the user-level file and push into live sessions; getGlobalMcpServer returns the effective config; mutations of read-only entries are rejected. - testGlobalMcpServer accepts an inline config; addSessionMcpServer connects a server in one live session with an optional persist flag; reconnect accepts a replacement config and re-resolves via the registry. - One process-wide McpOAuthService shared with every session: obtained_at stamps, offline token state, single-flight and proactive refresh, and credential events. Sessions self-subscribe in the constructor, so even initializing sessions see every event; token writes serialize through the process-local OAuthTokenTransaction per credential identity. - inspectAppMcpServers + locator-addressed begin/complete/cancel/reset cover plugin servers; inspection output redacts env/headers to sorted key lists; locator OAuth ops reject ambiguous shared runtime names. - The legacy auth-status surface reads the registry (offline by default, verify=true probes) and never mutates credentials. - VS Code panel receives source/origin/mutable and hides mutating actions on read-only entries. - v2 client facade in node-sdk mirrors the surface over agent-core-v2 (plugin inventory stays v1-only for now). * fix(agent-core): close the v1 MCP live-session reconciliation gaps Recompute each live session's MCP target from the registry's runtime resolution (enabled plugin > project layer > user file; caller injection shadows everything) behind every config mutation, instead of per-path patching: shadowed file layers recover when a plugin winner is disabled or removed, removing a user-level entry resurrects its project-layer shadow, disabled plugin descriptors no longer block removals, persisted session adds validate against the session's project layer and broadcast to other live sessions, and per-session sync failures are logged with context. Session status entries and read-only management entries now report redacted config views (envKeys/headerKeys instead of literal env/headers values); core-internal reconciliation compares full configs via the connection manager's raw-entry accessor. OAuth: interactive flows are serialized per credential (concurrent begins join the in-flight flow instead of clobbering its PKCE/state), a malformed credential meta sidecar no longer aborts core start, grants inside the refresh-ahead window refresh immediately while far-future grants re-arm through a max-length timer, and the service shuts its timers and flows down with KimiCore/SDKRpcClient close. * fix(agent-core): route the proactive MCP OAuth refresh through the token transaction refreshNow ran its /token request with the SDK default fetch, outside the credential-serializing OAuthTokenTransaction that every other token write uses; a slower response carrying an older rotating refresh token could overwrite a newer grant written by a concurrent transport-side refresh. * fix(agent-core): keep disabled MCP servers out of auth-state classification The unified mcpServerAuthState dropped the previous enabled short-circuit, so a disabled oauth-flagged server reported oauth-required — or was even probed over the network — instead of not-applicable. * fix(kimi-code-sdk): short-circuit disabled MCP servers in the v2 auth-status classifier The v2 parity copy of v1's mcpServerAuthState missed the same enabled guard v1 just regained; a disabled oauth-flagged entry would report oauth-required (or be probed). The parity suite now pins the disabled case on both engines. * fix(kimi-code): refresh the VS Code MCP list with the workspace cwd after mutations The add/update/remove RPCs return a cwd-less management list, so the webview broadcast dropped project-layer entries until the next full load; re-list with the workspace cwd after every mutation instead. * fix(agent-core): keep SDK token saves matched to the OAuth token transaction saveTokens stamped obtained_at onto a fresh object before calling tokenTransaction.save, so it never matched the exact payload the transaction recorded for a grant fetch; the consume path was dead and every save re-wrote. Between the fetch and the SDK callback an intervening clear could then be overwritten — the resurrected grant came back after a reset. The write callback stamps the durable record instead. * fix(agent-core): reject ambiguous legacy name-based MCP auth lookups The legacy begin/reset auth RPCs took the registry's first name match, silently starting OAuth for one entry of a runtime-name collision while the locator path refused the same ambiguity; align them on the shared uniqueness rule and point callers at the locator-addressed variants. * fix(agent-core): propagate registry errors during live-session MCP sync resolveMcpRuntimeTarget collapsed every registry failure into "no target": a project config file that turned malformed mid-session made sync treat a still-configured server as gone (tearing down the live connection) and made config-aware reconnects report "no longer configured" instead of the actionable config error. Absence still resolves to undefined; malformed config now propagates — per-session sync logs and keeps the entry, and reconnect surfaces config.invalid. * fix(agent-core): close the remaining registry-error and ambiguity gaps The management guard lookup mapped every registry failure to "absent", so a malformed project config let a persisted session add write a user-level entry over an unknown state; only not-found is a miss now. And the name-only connection test now shares the auth paths' uniqueness rule instead of probing the first match of a runtime-name collision. * fix(agent-core): probe the enabled MCP entry under a disabled-name collision The name-only connection test counted enabled matches for its ambiguity guard but still probed the first registry match, and the file layers list before plugins. With a disabled file entry shadowing an enabled plugin of the same runtime name, Test probed the disabled entry instead of the one a live session would run. Select the sole enabled match, falling back to the first entry only when every match is disabled so it reports as disabled. * fix(agent-core): let session-local MCP adds shadow plugin entries Caller injection shadows every registry source at session start, plugins included, and reconciliation leaves caller entries untouched; the live non-persist add path rejected plugin-owned names anyway, so SDK clients could not apply the same per-session override without a restart. Gate the plugin-source rejection on persist: session-local adds connect as caller, while persisted adds stay rejected as user-level writes behind a read-only owner. * fix(agent-core): normalize session MCP names before connecting The persisted store trims server names, but addSessionMcpServer used the raw name for the live connect and cross-session reconciliation: a padded name persisted under the trimmed key while the requesting session ran and reconciled the raw one, and a blank name connected with no identity at all. Normalize once up front (rejecting blank) so the store write, the session entry, and reconciliation agree on the same server. * fix(agent-core,node-sdk): close the collision-selection and probe-freshness gaps The legacy name-only auth resolver started from the first registry match, so a disabled file-layer shadow plus an enabled plugin of the same runtime name was misread as an ambiguity conflict; select the sole enabled match before judging ambiguity, exactly like the test probe path. On the v2 client, addSessionMcpServer connected the raw name while the store wrote the trimmed key — normalize once for both, and route the verify-triggered auth probes through the per-call OAuth service instead of the cached one whose providers snapshot tokens at construction, so a grant saved after the first probe is honored. * fix(agent-core): normalize global MCP mutation names and guard disabled reconnect swaps The global add/update/remove mutations guarded and reconciled with the raw server name while the store persisted the trimmed key, so a padded name left live sessions unreconciled and could slip past the plugin read-only guard; normalize once before lookup, persistence, and reconciliation. And a config-carrying reconnect assigned the replacement before the disabled check fired, leaving a connected entry that reported the disabled config; reject disabled replacements before mutating, keeping the same error. * fix(agent-core): skip proactive refresh while an interactive flow owns the credential refreshNow reset the shared provider's flow state before and after the token request; when a proactive timer (or a manual refresh) fired while beginAuthorization was waiting on the browser callback for the same store key, that wiped the redirect URL, PKCE verifier, and state the in-flight flow needed — complete() then failed the exchange even though the user authorized. Refresh now skips when an interactive flow is active for the credential: the flow delivers fresh tokens on completion, and the 401 transport path is the backstop if it fails. * fix(agent-core): allow global MCP adds over disabled plugin descriptors A disabled plugin entry is absent from the runtime target, but the read-only guard still treated it as the owner, so a user-level fallback could only exist if it predated the plugin disable. Relax the shared guard: disabled plugin descriptors never block mutations (disabled project entries still shadow the user file and keep their rejection). * fix(node-sdk): close the v2 session-MCP parity gaps A v2 reconnect with an explicit enabled:false replacement config used connect()'s upsert semantics — closing the live client and reporting success where v1's manager reconnect rejects before applying anything; reject disabled replacements up front with the same error. And a persisted v2 session add never consulted the workspace config, so a same-named project-layer entry was silently shadowed: the user-level write never takes effect while the direct workspace-manager upsert displaces the project config for every live session. Resolve the workspace layers and reject like v1's read-only rule. * fix(agent-core): keep __proto__-named MCP servers through config parsing A z.record() parse rebuilds its output via property assignment, so a server literally named __proto__ hit the prototype setter and vanished before validation; the layer merge then repeated the same trap with plain object accumulators. Parse the server map entry-by-entry over the JSON own keys and accumulate into null-prototype maps, so session startup and the unified registry keep the declared server and its origin. * fix(node-sdk): begin v2 MCP auth against a fresh OAuth service The v2 begin path ran through the cached globalMcpOAuth, whose providers snapshot tokens at construction: a grant another process saved (or reset) after that cache materialized was invisible, so begin could open a browser flow over a valid grant, or report already-authorized off a removed one. Build the service per call — the read path and the verify probes already do — and route the status list through the same helper. The test fixture grows a real token endpoint honoring one rotating refresh token; the regression fails against the cached-service implementation on v2. * fix(agent-core): broadcast SDK-driven MCP token invalidations to live sessions * test(agent-core-v2): give the no-op reconnect test runtime plumbing The branch added the case against a bare McpConnectionManager, but #2961 made stdio connects resolve the runtime through runtimeResolver, matching every other case in the file. |
||
|
|
d96cd03770
|
fix(cli): pre-send warning and clearer error for over-long /goal objectives (#2928)
Some checks are pending
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix(cli): warn on over-long /goal objectives before sending and keep the input - Show a live footer warning in the TUI while a typed /goal objective exceeds the 4000-character limit, measuring paste-expanded text only when the input can be a /goal command. - Restore the rejected /goal input into the editor instead of losing it. - Include the file-reference workaround in the GOAL_OBJECTIVE_TOO_LONG error messages (TUI, goal queue, agent-core, agent-core-v2). * fix(cli): keep the /goal length warning in its own footer slot A transient hint (exit confirm, detach, image paste) that displaced the warning previously left the footer blank after clearing, because no editor change re-applied it. The footer now renders the warning from a dedicated slot whenever no transient hint is active, so the warning returns on its own. * fix(cli): gate the /goal length warning on trimmed text Submitted text is trimmed before slash-command dispatch, so leading whitespace still runs /goal — normalize with trimStart in the gate and in the length check to match. * fix(cli): restore input rejected by the slash-command busy gate An idle-only command submitted while streaming/compacting was rejected after the editor buffer had already been cleared, losing hand-typed input (e.g. an over-long /goal objective that never reached the local validation). * fix(cli): restore input at the post-creation busy re-check The lazy-session race rejects an idle-only command after a first prompt has already started a turn; the editor buffer is long cleared by then, so give the submitted input back like the dispatch blocked branch does. * fix(cli): close the remaining input-loss and gate gaps around /goal - Restore the submitted input when lazy session creation fails before a session-requiring command runs. - Restore only into a still-empty editor after async gates, so a draft typed while creation was pending is never overwritten. - Expand pastes that can complete a partially typed /goal command (e.g. /go[paste #1 …]) in the length-warning gate. * fix(cli): never displace newer UI state with a delayed input restore A session-less /goal submission restores its input only after an async gap (lazy session creation). If the user opened an editor-replacement panel meanwhile, restoring would tear it down (and leave activeDialog inconsistent). Track editorReplacementMounted in TUIState and gate all delayed restores through canRestoreSubmittedInput. * refactor(cli): move canRestoreSubmittedInput into commands/resolve Avoids the goal.ts <-> dispatch.ts runtime import cycle flagged by import/no-cycle; the helper takes a structural host shape instead. * fix(cli): match the slash parser's delimiter in the /goal length warning parseSlashInput splits the command name at a literal space only, so a newline or tab after /goal dispatches as a plain message — the warning must not fire for inputs the dispatcher will not treat as a goal. |
||
|
|
13d86f8b7b
|
ci: release packages (#2881)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
102984aa66
|
fix: settle cancelled MCP OAuth callbacks (#2899)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Co-authored-by: yuchengzhen <yuchengzhen@moonshot.cn> |
||
|
|
c9bfe8b2c8
|
feat: replace the secondary-model experiment with a declarative subagent model pool (#2700)
* feat: replace secondary-model experiment with [subagent.models] pool
Add a declarative subagent model pool to agent-core-v2: [subagent.models]
maps [models] entry ids to selection hints rendered in the Agent/AgentSwarm
tool descriptions, and [subagent].default_model picks the spawn model when
the caller passes none. The tools' model parameter becomes a free-form
alias string (stripped when no pool is configured), description rendering
is caller-aware (primary (alias) [main model]), and a session-start
validation service fails fast with CONFIG_INVALID on a missing/invalid
default_model or an unresolvable pool alias.
Remove the secondary-model experiment from the v2 engine, node-sdk,
kap-server, and the TUI (the /secondary_model command), and drop the
agent-profile modelPreference / model_preference frontmatter field on v2.
The legacy v1 engine keeps the experiment unchanged; v2 ignores leftover
[secondary_model] config silently.
* fix(agent-core-v2): harden subagent model-pool validation and error/picker mapping
Deep-review follow-ups to the [subagent.models] pool:
- validate the pool before session materialization (after config.ready)
and before the fork file copy, so a broken pool no longer leaves
orphaned session dirs or leaked MCP overlay connections; the
Session-scope validation service stays as a backstop
- reject the reserved "primary" pool alias at startup, and again
defensively in resolveSubagentBinding so a pool broken by a runtime
config edit fails loudly at spawn instead of binding the wrong model
- keep the [default] marker when the caller's own model is the pool
default (primary (alias) [main model] [default])
- recompile the cached tool-args validator when a tool advertises a new
schema object (mid-session pool edits no longer hit a stale validator)
- map config.invalid to VALIDATION_FAILED in kap-server's session routes,
the debug transport mapper, and the catch-all error handler
- hide the v1-synthesized __secondary__ entry from the /model and
/provider pickers again
- fold per-export doc blocks into file headers per package comment
conventions; add pre-flight/reserved-key/validator/mapping tests and
document that create/resume/fork all fail on a broken pool
* feat: re-add /secondary_model and accept a lone subagent default_model
- v2 engine: a pool-less [subagent] default_model forms an implicit
single-entry pool — validated at session create/resume/fork like an
explicit pool, and advertised through the Agent/AgentSwarm model
parameter.
- Tool descriptions: the caller's own alias is a normal pool entry
marked [main model]; the primary line stays distinct because only it
inherits the caller's thinking level.
- TUI: /secondary_model returns, persisting [subagent] default_model
(merging into an existing pool with an empty description); the picker
hides the no-op Thinking footer and rejects the reserved primary
alias.
- kap-server: /api/v1/config accepts and echoes subagent; the
snake-to-camel patch conversion preserves user-defined map keys under
providers/models/experimental/raw without leaking preserve mode into
a colliding alias's own fields.
- v1 config schema learns subagent.defaultModel/models so the shared
config.toml round-trips; the v1 engine still ignores them at runtime.
- Docs (en/zh) and changesets updated.
* docs: use public model identifiers in the subagent model pool examples
* refactor: rename /secondary_model to /secondary-model
* test: cover the /secondary-model command name resolution
* Revert "test: cover the /secondary-model command name resolution"
This reverts commit
|
||
|
|
504e6292ed
|
feat(mcp): inspect effective authorization state in v1 (#2856)
* feat(mcp): inspect effective authorization state * test(agent-core-v2): register MCP auth coordinator fixture * fix(mcp): validate runtime names against full catalog * fix(mcp): reconnect after pending auth updates * docs(mcp): describe auth coordinator collaborator * fix(mcp): ignore disabled runtime name collisions * fix(mcp): serialize OAuth token refresh * test(mcp): await OAuth credential writes * fix(mcp): queue trailing credential reconnect * fix(oauth): preserve access-only refresh winners * fix(mcp): preserve legacy offline auth state * fix(mcp): redact inspection credentials * refactor(mcp): keep app inspection on v1 * fix(mcp): guard legacy auth status mutations * fix(mcp): avoid deterministic legacy auth probes * fix(mcp): cover initialization credential updates --------- Co-authored-by: 刘仲诺 <liuzhongnuo@dev.msh.team> |
||
|
|
3b0936d8e0
|
fix(agent-core): only discover the root SKILL.md for plugin skills fallback (#2847)
When a plugin manifest omits `skills` and the plugin root contains a SKILL.md, the fallback treated the whole plugin root as a generic skill scan directory, so sibling Markdown files such as CHANGELOG.md were misidentified as skills and inflated the plugin skill count. Mark the fallback root as root-skill-only so discovery parses only the root SKILL.md; explicit `skills` entries (including "./") keep the directory scan semantics. Applied to both agent-core and agent-core-v2. |
||
|
|
101c4d1997
|
feat(agent-core-v2): remove Agent and AgentSwarm from builtin profile tool lists (#2837)
* feat(agent-core-v2): remove Agent and AgentSwarm from builtin profile tool lists The builtin agent and coder profiles no longer expose the Agent and AgentSwarm tools, so sessions on the v2 engine do not offer subagent delegation by default. The tools themselves remain registered; profiles that list them explicitly can still opt in. * feat(agent-core): remove Agent and AgentSwarm from builtin profile tool lists Align the v1 builtin agent/coder profiles with the v2 change: the default profiles no longer offer subagent delegation, while the tools stay registered for profiles that list them explicitly. The parity projection drops v1's inactive Agent/AgentSwarm roster entries: v1 reports registered-but-inactive builtin tools where v2 only registers the tools a profile lists, so an inactive entry has no v2 counterpart. Active entries still compare in full. * fix: keep Agent and AgentSwarm in the builtin agent profile Scope the removal to the coder subagent profile on both engines: the main agent keeps Agent/AgentSwarm so default sessions can still delegate, while coder subagents no longer spawn nested subagents by default. Snapshots and token counts shift only for the embedded coder tool list; the v1 parity projection needs no change since the main agent rosters match again. |
||
|
|
01c74e9372
|
fix(agent-core): isolate builtin profile catalogs per session (#2740)
Some checks failed
CI / build (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test (5) (push) Has been cancelled
CI / test-pi-tui (push) Has been cancelled
CI / test-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / typecheck (push) Has been cancelled
Nix Build / Check flake.nix workspace sync (push) Has been cancelled
Release / Release (push) Has been cancelled
Release / Native release artifact (push) Has been cancelled
Nix Build / nix build .#kimi-code (push) Has been cancelled
Release / Deploy docs (push) Has been cancelled
Release / Publish native release assets (push) Has been cancelled
|
||
|
|
437a1b8ba1
|
fix(sdk): probe MCP auth status through connection (#2731)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
|
||
|
|
0b2e803d5e
|
feat(sdk): expose global MCP auth status (#2706)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
|
||
|
|
02c026d487
|
feat(agent-core-v2): tombstone removed MCP servers and freeze plugin prompt inputs (#2694)
* feat(mcp): tombstone removed MCP servers and apply plugin changes immediately (20 files) - add 'removed' MCP server status: workspace config removals call markRemoved instead of remove, keeping tool registrations alive while short-circuiting calls with a removal notice - fire onDidReload after every plugin mutation (install/enable/disable/remove) so workspace consumers refresh contributions immediately - TUI renders the removed status in the MCP panel/startup summary and shows an apply-immediately hint on the v2 engine * feat(agent-core-v2): freeze plugin prompt inputs for live agents (2 files) - snapshot the model skill listing and plugin system-prompt sections on the first successful prompt build and reuse the frozen values for the agent's lifetime, so plugin install / enable / disable / remove / reload never rewrites a live agent's prompt (same keep-live-sessions-stable philosophy as the MCP tombstone) - freeze only on success: a not-yet-ready skill catalog or a failed enabledSystemPrompts() read must not pin empty values for the agent's lifetime - refreshSystemPrompt still rebuilds on catalog change events but reuses the frozen values, so the prompt only moves when non-plugin inputs change (AGENTS.md, [tools] section, session tool policy, compaction); new agents snapshot the then-current state * chore(changeset): add changesets for MCP tombstone and frozen plugin prompt inputs * docs: describe immediate plugin changes and the removed MCP status on the v2 engine * fix(klient): mirror the removed MCP server status in the wire contract * docs: drop the legacy-engine behavior notes from the plugin and MCP pages * fix(agent-core-v2): freeze plugin sections only on a loaded snapshot - enabledSystemPrompts() resolves to its consumption fallback (never rejects) while the initial plugin load has failed; freezing that empty read locked plugin sections out of the live agent even after a later successful reload - expose hasLoadedSnapshot() on IPluginService so resolvePluginSections can tell a real empty snapshot from the fallback before freezing |
||
|
|
7b2784b9b7
|
feat: surface the bound model and thinking effort on subagent UIs (#2679)
* feat: surface the bound model on subagent UIs The subagent.spawned event now carries the display-normalized model alias (the derived __secondary__ entry resolves to its base alias), so clients can show which model a subagent is bound to. The TUI subagent card, swarm panel header, and background-agent entry show it at spawn; the WS snapshot roster and REST /tasks (background/detached subagents) carry it too, keeping the model visible across client reconnects. * feat: carry the subagent thinking effort alongside the model The spawned event, snapshot roster, and REST /tasks now also carry the child's effective thinking effort (read from the child profile at spawn, the same vocabulary as agent.status.updated). UIs show it only when it diverges from the main session's current effort — an inherited level adds no information, and 'off' is never shown. * feat(tui): show the bound model and effort in the /tasks browser The task browser's Detail pane renders Model and Effort rows for agent tasks (raw alias and level — it is the inspector surface, so no diff filtering), and its minimum height grows to fit the new rows. The values were already persisted on SubagentTaskInfo; the TaskInfo union, its zod schemas (protocol, kap-server, klient contract), and the v1 type declaration now carry them so nothing strips them in transit. * feat(tui): show concrete subagent effort levels unconditionally Display rule simplified: any concrete effort tier (low/high/max/…) is shown next to the model — including when it matches the main session's level. Only the boolean states stay hidden: 'off' (no thinking) and 'on' (generic thinking) carry no level information. * docs: trim the changeset entry * fix(tui): keep the model and effort on background-agent entries across resume replayBackgroundProjection only copied agentId/parentToolCallId/ description, so a background subagent that outlived a resume lost its model/effort on the later terminal transcript entry. The projection now threads the persisted values (catalog-mapped model; boolean effort states dropped), and session replay passes the loaded model catalog through. * fix(agent-core-v2): normalize the derived secondary alias regardless of the flag A child bound while the secondary-model experiment was on keeps __secondary__ in its persisted binding; if the flag is later switched off with the recipe still configured, resolveSecondaryModel() gated the normalization and the sentinel leaked back onto resumed subagents. subagentDisplayModel now reads the recipe straight from config (the flag gates new bindings, not the interpretation of existing ones), which also drops SessionSwarmService's now-unused IFlagService dependency. Also adds the SDK package to the release: the new SubagentSpawnedEvent/AgentTaskInfo fields are SDK-visible types. * fix(agent-core-v2): normalize the status-frame model at the source A derived-bound child republishes agent.status.updated right after spawn with its raw modelAlias, which overwrote the spawned event's normalized display model on single-subagent cards (swarm headers were first-wins and escaped). emitStatusUpdated now maps through subagentDisplayModel, a no-op for the never-derived main agent. Also moves the inline comments added by this branch into top-of-file headers per the v2 comment convention. * fix(tui): clamp the /tasks detail frame to the available body At terminals near the minimum height the forced 10-row detail frame overflowed the body and truncated the preview frame's border. The detail height now caps out at whatever leaves the preview its borders plus one content row, with a regression test at exactly MIN_HEIGHT. * fix: normalize inherited derived aliases and keep model/effort on replayed terminal entries - resolveSubagentBinding's caller-fallback branch also maps through subagentDisplayModel: a caller itself bound to the derived entry (a resumed subagent making a nested Agent call) no longer publishes __secondary__. - The replayed background-task terminal notification builds its metadata with the persisted model (catalog-mapped) and concrete effort, matching the live completion path. - Drops the inline comments this branch added inside v2 test bodies; the scenario context lives in the source file headers. |
||
|
|
f881cdd970
|
feat(cli): default CLI surfaces to the agent-core-v2 engine (#2627)
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
* feat(cli): default to agent-core-v2 engine with KIMI_CODE_LEGACY_FLAG opt-out - invert the engine gate: isKimiV2Enabled() now returns true unless KIMI_CODE_LEGACY_FLAG is truthy; KIMI_CODE_EXPERIMENTAL_FLAG no longer selects the engine - replace the experimental `kimi acp-v2` command with the native v2 implementation as the default `kimi acp`; the legacy acp-adapter path remains under the legacy flag - drop the acp-v2 experimental flag from the registry - rename the dev:cli:v2 script to dev:cli:legacy - update en/zh docs for the new default engine and the legacy flag * feat(cli): route export and provider through the engine gate - select the harness via isKimiV2Enabled(): agent-core-v2 by default, the legacy harness when KIMI_CODE_LEGACY_FLAG is truthy - close the harness after each one-shot command so the v2 engine's watchers do not keep the process alive - document both commands in the KIMI_CODE_LEGACY_FLAG env-var entry |
||
|
|
2a4990182d
|
docs: slim root AGENTS.md, move deep package docs to package guides (#2626)
- move the kimi-inspect, kap-server, transcript, and minidb project-map entries into new package-level AGENTS.md files - move the standalone Agent class rule to packages/agent-core/AGENTS.md - merge root-only agent-core-v2 facts (MCP persistence, trust routes, seed contract examples) into packages/agent-core-v2/AGENTS.md - compress the remaining long project-map entries to summaries with pointers, and add an anti-bloat rule for map entries - drop the stale server-e2e entry; the package no longer exists |
||
|
|
2ee6e43124
|
fix(mcp): re-register the OAuth client when its redirect URI no longer matches (#2620)
The callback listener binds a random port per flow, while DCR registration records the redirect URI of the flow that created it — so every interactive authorization after the first was rejected with "Invalid redirect URI", an error rendered only in the user's browser while the client waited for a callback that never came. Detect the mismatch before invoking auth() and drop the stale registration so the flow re-registers with the current callback URI (v1 + v2). Resolve #2606 Co-authored-by: zouying <zouying@moonshot.cn> |
||
|
|
74c321e4c6
|
fix(mcp): drop protocol-reserved _meta keys from model-visible output (#2600)
* fix(mcp): drop protocol-reserved _meta keys from model-visible output Follow-up to #2596. The MCP spec reserves _meta key prefixes whose labels include "modelcontextprotocol" or "mcp" for protocol use; those entries carry host/protocol plumbing rather than model-facing data, so filter them out before serializing the <mcp-structured-result> block. Unprefixed and vendor-prefixed keys still pass through — their semantics belong to the server. Also moves the v2 implementation commentary into the module header per the agent-core-v2 comment convention. * fix(mcp): reserve _meta prefixes only when a label follows mcp/modelcontextprotocol Per the spec's key-name rules a prefix is reserved when a modelcontextprotocol or mcp label is followed by at least one more label; a trailing reserved word (com.example.mcp/) is a legitimate vendor namespace and now passes through. --------- Co-authored-by: zouying <zouying@moonshot.cn> |
||
|
|
3126422757
|
feat(mcp): carry an absolute expiresAt on the OAuth authorization-url update (#2609)
* feat(mcp): carry an absolute expiresAt on the OAuth authorization-url update The authenticate flow waits for the OAuth callback with a fixed budget, but the authorization-url tool update surfaced to embedding hosts did not say when that window ends — hosts had to hardcode a mirror of the 15-minute constant to render countdowns. Include the absolute deadline (now + effective wait timeout) in the update payload for v1 and v2. Resolve #2607 * fix(protocol,kap-server): accept expiresAt in the OAuth authorization-url update schemas The zod validators mirrored the pre-expiresAt payload shape and would strip the new field at the kap-server boundary. --------- Co-authored-by: zouying <zouying@moonshot.cn> |
||
|
|
c32e661faa
|
fix(mcp): pass structuredContent and _meta through to model-visible tool output (#2596)
MCP tool results were narrowed to {content, isError}, dropping the
spec-defined structuredContent field and _meta metadata. Servers that
return structured contracts in these fields (validated against
outputSchema, or namespaced metadata such as browser-handoff payloads)
were invisible to the agent. Surface them as a serialized
<mcp-structured-result> block appended to the tool output, still subject
to the existing text budget.
Co-authored-by: zouying <zouying@moonshot.cn>
|
||
|
|
1328b32037
|
feat(acp): add experimental agent-core-v2 ACP server (kimi acp-v2) (#2571)
* feat(acp): add agent-core-v2 ACP server - add ACP session lifecycle, configuration, permissions, and event bridging - expose the experimental kimi acp-v2 command with terminal authentication - add integration coverage and workspace build configuration * test: use neutral example domains in test fixtures and docs - replace placeholder hostnames (evil.com, foo.com, internal.corp, real.corp) with example.test / example.com in agent-core-v2 and kap-server tests - replace fixture emails (x@y.com, a@x.com) with example addresses in minidb tests and README * fix(acp): align acp-server with agent-core-v2 interfaces and address review - add missing appendText to AcpHostFileSystem (IHostFileSystem drift) - replace IAgentPromptService.prompt with inject - use Turn.cancel() instead of abortController - gate FS reverse-RPCs on client capabilities, fallback to local FS - return PROTOCOL_VERSION constant instead of echoing client version - remove misleading mcpCapabilities from initialize response - dispose old session wrapper before replacing on load/resume - fix object stringification lint error in convert.ts - add acp-v2 to expected CLI sub-command list in test * fix(acp): use enqueue for prompt submission, stop advertising unimplemented builtins - replace IAgentPromptService.inject with enqueue so onBeforeSubmitPrompt hooks (prompt-blocking policy) are not bypassed - stop advertising builtin slash commands (/help, /status, etc.) until builtin command execution is implemented - add comment explaining appendText stays local (ACP has no append RPC) - update skills test to match new availableCommands behavior * fix(acp): filter turn events by turnId, surface auth failures as auth_required - track turnId in driveTurn and ignore events from unrelated turns, preventing queued prompts from settling on the running turn - reject prompt requests with auth_required when turn fails with an auth-related error code, enabling ACP client re-auth flow * fix(acp): gate acp-v2 behind experimental flag, filter sessions by cwd - add acp-v2 experimental flag (KIMI_CODE_EXPERIMENTAL_ACP_V2) and gate CLI command registration behind it - filter session/list results by requested cwd instead of returning sessions from all workspaces - detect hook-blocked prompts via PromptHandle.state and add TODO for streaming block messages once the hook context exposes them * refactor(acp-server): rewire ACP server onto the klient facade - replace direct agent-core-v2 scope/service access (ISessionLifecycleService, ISessionIndex, IEventBus, ISessionInteractionService, etc.) with the Klient facade: klient.global.sessions / klient.session(id) / agent('main') handles - drive turns via agent.prompt() + session-level agent event subscriptions instead of per-prompt IEventBus wiring; settle on turn.ended - route approval/question bridging through session.interactions events - hide the thinking config option and skill catalog behind KLIENT-GAP markers until klient exposes those surfaces - acp-fs: pass realpath through to the local inner backend - klient: session.restore() rejects both null and undefined handles * feat(agent-core-v2): add session delete and ephemeral per-session MCP servers - add ISessionLifecycleService.delete: close a live session first, then remove its persisted data, evict the index read-model entry, and append a deleted tombstone to session_index.jsonl; unknown ids raise session.not_found - add CreateSessionOptions/ResumeSessionOptions.mcpServers: session-owned MCP overlay merged over the workspace manager via MergedMcpConnectionView (an ephemeral name shadows a workspace server), never persisted, released when the session scope tears down - return PromptLaunchResult from activateSkill so callers get the launched turn id and activation failures (unknown skill, busy) surface - add ISessionSkillCatalog.list() as a wire-friendly catalog snapshot - add ISessionIndex.remove for read-model eviction on delete * feat(klient): expose session delete, per-session MCP, skills, and stream events - session lifecycle contract: delete, resume/restore options, and CreateSessionOptions.mcpServers (ephemeral per-session MCP servers) - add the session skills contract and facade accessors for the wire-friendly skill catalog snapshot - register tool.call.delta, tool.progress, and compaction.* agent stream events so consumers can subscribe with typed payloads * feat(acp-server): align ACP v2 server with acp-adapter capabilities - complete the klient-facade rewire: ACP client connection holder and the terminal/* reverse-RPC runner routed through the Agent scope - negotiate the protocol version on initialize instead of pinning v1 - compress oversized prompt images at the ACP ingestion point with a format gate, caption, and persisted originals; a cancel arriving mid-compression settles the prompt as cancelled without a turn - stream tool call args via tool.call.delta (lazy pending create, cumulative replace, started upgrade) and refresh titles via tool.progress status updates - report compaction progress and results after /compact via the compaction.* events - answer unknown slash commands locally instead of sending them to the model - accept legacy "<id>,thinking" model ids and legacy approve / approve_for_session approval option ids - keep sessions without cwd metadata in cwd-filtered session/list - sanitize wire errors: auth codes map to auth_required, turn.agent_busy to invalid_request, everything else to a fixed internal-error message - bump @agentclientprotocol/sdk to ^1.3.0 * fix(cli): drop stale registerServerCommand call and sherif ACP SDK split - commands.ts called registerServerCommand, which no longer exists on current main (the deprecated `kimi server` shim is registered via registerWebCommand), breaking typecheck, build, and every CLI test that builds the program - sherif rejects the @agentclientprotocol/sdk major split between acp-adapter (^0.23.0, production kimi acp) and acp-server (^1.3.0, experimental); the two hosts legitimately target different SDK majors, so ignore the dependency in the sherif invocation * test: update fixtures for acp-v2 flag and domain rename, refresh nix deps hash - kap-server origin.test: two CORS cases still used foo.com after the whitelist moved to foo.example.com, so the origin was no longer whitelisted and the expected CORS headers were withheld - node-sdk config.test: expect the new acp-v2 experimental flag in the harness feature metadata - flake.nix: update the fetchPnpmDeps hash for the @agentclientprotocol/sdk 1.3.0 lockfile change * fix(acp): widen the ACP v2 auth gate beyond OAuth-only providers The gate consulted only auth.summarize(), which iterates providers declaring an oauth section — configurations that authenticate with a plain apiKey or provider env-bag credentials (no OAuth at all) were rejected with auth_required even though the default model is fully usable. - klient: expose authSummaryService.ensureReady on the global auth facade (the contract already declared it) - acp-server: gate on the engine's own readiness probe for the default model — config apiKey / env-bag / OAuth token all count, matching how the model is actually used — and fall back to "any logged-in OAuth provider" (the legacy adapter's first branch) - test: an apiKey-only config passes the gate with auth enforcement on; the OAuth logout regression is unchanged * fix(acp): reject concurrent prompts instead of displacing the in-flight turn A second session/prompt while a turn is running overwrote the session's only TurnDriver: the engine quietly queues plain prompts submitted during an active turn (the launch resolves undefined, indistinguishable from a hook-blocked launch), so the first prompt never settled and both turns' events went unattributed. Guard both model-bound launch paths (plain prompt and skill activation) with a synchronous in-flight check and reject with invalid_request (turn.agent_busy), matching the legacy adapter's busy semantics. Local slash handling (builtins, unknown-command answers) is unaffected. |
||
|
|
98ef0f0b2f
|
fix(agent-core): replay v2 profile.bind records so resumed sessions keep their tools (#2567)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix(agent-core): replay v2 profile.bind records so resumed sessions keep their tools Sessions created by the v2 engine (CLI 0.31+, wire protocol 1.5) persist the profile binding, including the tool allowlist, as a profile.bind record. The v1 replay path had no branch for it and silently dropped the record, so a session resumed by a v1 host (e.g. the VS Code extension via kimi-code-sdk) never called setActiveTools and sent requests with no tools at all (observed server-side as tools_count=0; the model emits reasoning only and stops with empty content). v1 replay now maps profile.bind onto config.update + setActiveTools when activeToolNames is an array, skips the record otherwise so the resume-time default-profile fallback still applies, and treats tools.reset_active_tools as a no-op. * fix(vis): handle v2 profile records in context projection * fix(agent-core): avoid synthetic replay for v2 profile binds * fix(vis): render v2 profile wire records |
||
|
|
6ba75a173b
|
feat(config): add deprecation mechanism and rename loop retry limit (#2572)
* feat(config): add deprecation mechanism and rename loop retry limit - agent-core-v2 config: declarative section `deprecations` (deprecated TOML keys are ignored and report a warning diagnostic; the file is never rewritten) and env binding `deprecatedEnv` (old var still resolves as a fallback with a warning), surfaced via the new `IConfigService.onDidChangeDiagnostics` event - loop_control: rename `max_retries_per_step` to `max_attempts_per_step` and `KIMI_LOOP_MAX_RETRIES_PER_STEP` to `KIMI_LOOP_MAX_ATTEMPTS_PER_STEP`; `max_steps_per_run` moves onto the same mechanism (no longer silently mapped) - kap-server: push the global `event.config.warning` WS event to every connection whenever the config warning set changes - TUI: show config diagnostics in warning yellow at startup instead of the dim startup notice - docs: config-files/env-vars (en+zh), regenerated config manifest, and the agent-core-dev config guide * feat(cli): validate config.toml against v2 section registry in doctor - add v2/validate-config.ts: validate config.toml with the agent-core-v2 ConfigRegistry, reporting registered-section schema failures as errors and unknown top-level keys / deprecated keys and env vars as non-fatal warnings - route `kimi doctor` config validation through the v2 validator when the KIMI_CODE_EXPERIMENTAL_FLAG master switch is on (lazy dynamic import, keeping the v2 module graph off the default path) - let doctor checks surface non-fatal warning messages on OK results * chore: downgrade loop-control changeset to patch |
||
|
|
95a656ca61
|
fix(agent-core): strip the no-op subagent model parameter while the secondary-model experiment is off (#2449)
The Agent/AgentSwarm tool schemas always advertised a \`model\` choice parameter, so the secondary-model concept entered the prompt even with the experiment disabled. Gate the advertised JSON schema on the flag in both engines: off (the default) drops the parameter, on keeps it, and spawn-time resolution already falls back to the caller's model either way. Also scrub ambient KIMI_CODE_EXPERIMENTAL_* env vars in both packages' vitest setup so flag-dependent tool schemas in llm.tools_snapshot stay deterministic regardless of the developer shell. |
||
|
|
bc28e9d802
|
ci: release packages (#2342)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
40172c7ca9
|
feat: unify the host identity across OAuth, telemetry, and kap-server (#2382)
* refactor(oauth): make X-Msh-Platform an explicit host identity field X-Msh-Platform was hardcoded to kimi_code_cli in createKimiDeviceHeaders, so non-CLI hosts could not state their own platform and the desktop had to patch the header after the fact. KimiHostIdentity now carries a required platform (every host declares its own value; the CLI constant stays the fallback only for direct createKimiDeviceHeaders callers), and userAgentProduct is renamed to productName so the transport identity uses one name everywhere. All in-repo identity constructions pass platform explicitly; the wire value for CLI and VS Code hosts is unchanged (kimi_code_cli). * feat(agent-core-v2): carry the host identity in the bootstrap snapshot Replace the flat clientVersion field with a required clientIdentity (KimiHostIdentity) so every consumer reads the same host identity object: OAuthToolkitService now passes it to the OAuth toolkit, which means the OAuth device-flow endpoints (device authorization, token polling, refresh) on the kap-server path finally send the full X-Msh-* device headers instead of none, and the telemetry cloud appender reads client_version from the same source. A built-in CLI fallback keeps bare bootstrap() calls in tests working; composition roots must pass their own identity. The session export manifest grows an optional desktopVersion field (payload plumbed through; filled by kap-server in a follow-up). * feat(agent-core): thread the host identity into the managed auth facades The v1 managed auth facade constructed its OAuth toolkit without an identity, so token refreshes from inside the core went out without any X-Msh-* device headers. createManagedAuthFacade now takes an optional KimiHostIdentity and every call site supplies one: CoreProcessService._defaultOAuthTokenResolver forwards the core process's options.identity (the same source _defaultKimiRequestHeaders uses), and the DI-held services (oauth / auth summary / model catalog) read it from a new optional identity field on IEnvironmentService. The library-level "no identity, no device headers" contract is unchanged. * feat(kap-server)!: require the host identity and derive request headers from it ServerStartOptions.hostIdentity is now a required ServerHostIdentity (KimiHostIdentity + optional prompt display fields), replacing both the old optional HostIdentityOverrides (renamed to PromptIdentityOverrides, its productName field now displayName) and the version option (renamed to serverVersion — it is the engine version reported as server_version, while the host product version travels in hostIdentity.version). The server now feeds bootstrap's clientIdentity from hostIdentity and derives the default outbound headers (User-Agent + X-Msh-*) from it via createKimiDefaultHeaders, so kap-server-hosted OAuth flows and model / WebSearch requests carry the real host identity instead of a hardcoded kimi-code-cli fallback UA. Explicit header seeds still win as an escape hatch. Session export manifests record the host product version: kimiCodeVersion now carries hostIdentity.version (the engine version no longer appears), and desktop exports (desktop: true) are additionally stamped with a desktopVersion field. The instance registry keeps its host_version wire field for compatibility (kimi-inspect reads it); only the in-memory name changed to serverVersion. * feat(cli): wire the CLI host identity into the kimi web server kimi web now passes createKimiCodeHostIdentity(version) as the server's hostIdentity, so web-UI OAuth flows and the engine's outbound requests carry the explicit CLI identity (productName + version + platform). The explicit hostRequestHeadersSeed is dropped — kap-server derives the same headers from hostIdentity — and buildKimiDefaultHeaders goes away with its only consumer. * test(klient): drop clientVersion from the bootstrap contract parity list * chore: add changesets for the host identity unification * feat(cli): tag kimi web requests with a (web) User-Agent suffix kimi web shares the CLI product token and platform, so its outbound requests were indistinguishable from direct CLI runs upstream. Its host identity now carries userAgentSuffix 'web', putting web-UI traffic at kimi-code-cli/<version> (web) while X-Msh-Platform stays kimi_code_cli. * fix(klient): keep the env() clientVersion wire field after the bootstrap identity switch The bootstrap snapshot replaced the flat clientVersion scalar with clientIdentity, which broke klient's env() fan-out (RPCError: method not found). The wire surface keeps clientVersion — now sourced from clientIdentity.version — and bootstrapService gains a clientIdentity read (registered in envContract with an object schema) for consumers that want the full identity. * feat(oauth): send the product User-Agent on OAuth requests The OAuth endpoints used to receive only the X-Msh-* device headers (undici's default UA otherwise), which left the OAuth host unable to distinguish runtime surfaces — notably kimi web, whose platform matches the CLI and whose only distinguishing mark is the (web) UA suffix. The toolkit now feeds the full identity headers (User-Agent + X-Msh-*) into every device authorization, token polling, and refresh request; the request-header type widens from DeviceHeaders to OAuthRequestHeaders. * feat(vscode): report kimi_code_vscode as the extension's platform The VS Code extension inherited the CLI's hardcoded X-Msh-Platform value; with platform now an explicit identity field it declares its own, so the managed endpoints and OAuth host can tell extension traffic apart from CLI runs. * refactor(agent-core-v2)!: require the client identity at the composition root The bootstrap fallback identity fabricated a kimi-code-cli/unknown host for any caller that forgot to pass one — the same silent-misreport pattern this series set out to remove, and it made "required" a lie. BootstrapInput.clientIdentity is now required, so a missing identity fails at compile time instead of being papered over. Test and example callers pass a shared fixture (klient examples and test engines get one each); the node-sdk v2 client asserts its host identity with the oauth helper. Also folds DeviceHeaders from an interface into a type alias so it stays assignable to the widened OAuthRequestHeaders record. * feat(oauth)!: require and validate the platform in device headers Drops the quiet CLI fallback in createKimiDeviceHeaders (the same silent-misreport pattern removed from the bootstrap identity): platform is now a required option, validated with the same required-ASCII rule as the version — empty or all-non-ASCII values throw instead of emitting a blank X-Msh-Platform, and header-unsafe characters are stripped rather than sent raw. * fix(node-sdk): seed the host request headers on the v2 client path The interactive v2 engine path (experimental flag) bootstrapped without a hostRequestHeaders seed, so managed vendor calls went out with the SDK's default User-Agent (OpenAI/JS) and no X-Msh-* at all — v1 passes the full identity headers on the same requests. The v2 client now seeds the headers from its asserted host identity, and a test pins the seed. * chore: simplify the CLI changeset wording |
||
|
|
691ec4679e
|
fix: remove the blocking wait from the TaskOutput tool (#2379)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix: remove the blocking wait from the TaskOutput tool The block/timeout parameters let a model stall the whole turn waiting for a background task (up to 3600s), even though completion already arrives via automatic notification. Remove both parameters from the v1 and v2 engines (kept in model-facing parity), simplify retrieval_status to success/not_ready, and update the tool, Bash, and Agent prompt wording plus user docs accordingly. Stale callers passing block are silently treated as a non-blocking snapshot. * fix: align background-task prompts with the non-blocking TaskOutput The compaction reminder promised TaskOutput could fetch a task's result for tasks that are still running, where it now returns not_ready — reword it to snapshot semantics and point at the completion notification. Also list AskUserQuestion(background=true) as a task source in the TaskOutput description. * test: exercise stale TaskOutput args through the runtime validator A stale block/timeout argument never reaches the tool: the executor's preflight validates args against the closed tool schema and rejects them immediately, so the old test documented silent-tolerance semantics the runtime never exhibits. Assert the real behavior through compileToolArgsValidator/validateToolArgs instead, and drop statement-adjacent comments to match the package's header-only comment convention. |
||
|
|
fa2c5ce18b
|
feat: support plugin-contributed custom agents (#2365)
* feat: support plugin-contributed custom agents * fix: await plugin loading before agent catalog * fix: refresh plugin agents on v1 reload * test(agent-core-v2): add enabledSystemPrompts to the plugin service stub |
||
|
|
02d77b20d9
|
feat(agent-core-v2): let plugins contribute system prompt instructions via the manifest systemPrompt field (#2314)
* feat(agent-core-v2): let plugins contribute system prompt instructions via the manifest systemPrompt field
* feat(agent-core-v2): add systemPromptPath to load plugin system prompt from a file
* docs: explain plugin system prompt templates
* fix(agent-core-v2): refresh plugin system prompts after changes
* fix(agent-core-v2): freeze restored profile bindings and converge plugin contributions at session scope
- restore no longer re-renders or re-persists prompts: a resumed agent
keeps its replayed profile binding (prompt and tool set) as persisted
- a new Session-level convergence point reloads plugin skills into the
session skill catalog before fanning out to every live agent prompt,
and every catalog-kind plugin mutation awaits the whole pipeline;
MCP-only toggles carry a distinct change kind and skip it
- live refreshes after a restart re-resolve the bound profile by name
and rebind the full slice (prompt, disallowed tools, active tools)
atomically, warning and keeping the persisted state when the profile
is gone; renders reuse the first-render timestamp and unchanged
prompts are not re-persisted, so convergence never churns the wire
- cap plugin system-prompt contributions (32 KB per field/file, 64 KB
aggregate per prompt build) with manifest diagnostics and warnings
- bump the changeset to minor: this is a new user-facing capability
* fix(agent-core-v2): register the new session domain and dedupe the missing-profile warning
- add sessionPluginContribution to the domain-layer registry so
lint:domain stays green
- emit system-prompt-refresh-profile-missing once per profile name,
matching the service's other deduped warnings
- document the convergence timeout escape hatch and the klient
exclusion of enabledSystemPrompts
* fix(agent-core-v2): dedupe the plugin budget warning and surface section read failures
- emit plugin-sections-oversized once per skipped-plugin signature
- let enabledSystemPrompts failures propagate to the refresh catch
(keeps the current prompt and warns) instead of silently rendering
and persisting a prompt without plugin instructions
- cover the convergence timeout cut-off with a fake-timers test
- clarify that the first-render timestamp anchors per process
* fix(agent-core-v2): serialize session convergence and restore onDidReload timing
- run at most one convergence per session and bound each change's wait
by the timeout, so a fan-out emitter never interleaves deliveries
after a timed-out convergence
- fire onDidReload as soon as the reload commits again, keeping hook
reloads independent of prompt convergence
- sign the plugin budget warning with an unambiguous key
* docs(agent-core-v2): align convergence wording with the serialized semantics
- the timeout retry promise only holds once stalled work clears
- note the per-session serial delivery cost model on the plugin change
contract and the dual-queue invariant on the service
* fix(agent-core-v2): keep empty plugin sections byte-neutral in the prompt template
- place ${plugin_sections} on the same template line as
${skills_section} so prompts without either block render exactly as
before this feature
- note on the change contract that waitUntil work must not call back
into plugin mutations, and spell out the per-session convergence
order in the user docs
* fix(agent-core-v2): pin a fork's profile so refresh triggers never rebind it
- applyBindingSnapshot left the fork with no pinned profile, which
routed in-process forks into the post-restart catalog rebind and
could reset an inherited tool set; forks now inherit the source
agent's pinned profile object
- pin the first-render timestamp reuse with a ${now}-embedding test
and document the anchored ${now} semantics
- tighten the plugin docs budget and resume-refresh wording
* fix(agent-core-v2): join in-flight convergence during agent bootstrap
- an agent created while a plugin convergence is in flight now waits
for it, and a restored agent refreshes once after it, so a plugin
mutation never straddles an agent's bootstrap
- warn on a non-string systemPrompt field and strip a UTF-8 BOM from
systemPromptPath files before trimming
- correct the consumption-surface wording (every CLI surface on the
experimental flag, not just kimi -p), the per-session queueing note,
and the single-plugin combined budget clause
* fix(agent-core-v2): bound the bootstrap convergence join by the timeout
A permanently wedged convergence kept convergeTail pending forever,
and the unconditional settled() wait in bindBootstrap would have
blocked every later agent creation in that session; the join now
races the shared convergence timeout and continues (a restored agent
still refreshes once, which never touches the tail), and the timeout
constant moves to the contract for reuse
* fix(agent-core-v2): close the convergence race against in-progress restores
- a convergence fan-out could land while an agent's wire log is still
replaying, dispatching a replay-visible config record whose effect
the rest of the replay then overwrites; refreshSystemPrompt now
skips while the wire restore is in progress
- convergence completion is tracked by a generation counter; bootstrap
compares it (after a bounded join) and refreshes a restored agent
exactly once when a round completed after its creation began,
replacing the wasConverging flag that could miss both windows
* fix(agent-core-v2): bound each convergence so a wedged participant cannot stop the pipeline
- the fan-out now races the convergence timeout, so convergeTail always
settles: a permanently hung refresh delays its round (blocked entries
drain oldest-first on later changes) instead of killing the session's
convergence for good
- warn when agent bootstrap stops waiting on a stalled convergence
- diagnose a blank systemPromptPath and pin the plugin-root escape
guard with traversal, absolute-path, and symlink tests
* fix(agent-core-v2): bound the skill reload, preserve user-tool overlays, roll the prompt clock daily
- the convergence's skill-reload segment now races the same timeout as
the fan-out, so no segment of the pipeline can wedge a session for
good; it continues with the previous catalog and retries next change
- a cold rebind that resets the tool set replays session-added user
tools onto the new base instead of dropping them for the rest of the
process
- the rendered timestamp re-anchors when the UTC date rolls over, so
long-lived processes keep a fresh clock while steady-state renders
stay byte-stable within a day
- the plugin budget warning dedupes per plugin id, and the docs note
that systemPromptPath content is frozen until the next reload
* feat(agent-core-v2): converge cold plugin changes on resume through a drift-free gate
- restore replays the persisted binding untouched, then bootstrap
refreshes only when drift-free inputs changed while the session was
cold: the catalog profile's tool set/denylist, or the plugin-sections
baseline persisted alongside the prompt on the existing bind/update
payloads; directory-listing and date drift wait for live triggers,
so quiet resumes append no replay-visible records
- the rendered timestamp is day-precision (UTC date at 00:00,
re-anchored on rollover), keeping steady-state renders byte-stable
across resumes and sessions on the same day
- consolidate both timeout helpers onto a shared raceOutcome, and drop
the generation counter the gate supersedes
- align the plugin-sections precedence prose with the AGENTS.md
disclaimer (no self-granted authority, system instructions win on
conflict)
* fix(agent-core-v2): bound the restored-prompt gate and land the sections baseline
- the gate's plugin-sections read now races the convergence timeout, so
agent creation never blocks behind an unrelated plugin mutation
- refreshes serialize per agent through a tail, so overlapping triggers
cannot write prompts out of order
- when plugin sections change but a plugin-free custom prompt does not,
the new baseline lands as a sections-only update instead of making
every later resume re-render in vain
- align the system prompt's Date and Time paragraph with the
day-precision anchored timestamp
* Update plugin system-prompt instructions in changeset
Live sessions pick up plugin changes, while the default TUI and `kimi -p` paths ignore these fields.
Signed-off-by: 7Sageer <sag77r@hotmail.com>
* refactor(agent-core-v2): keep plugin skill reload user-driven
Plugin mutations still converge live agent prompts, but the session
skill catalog goes back to refreshing only on explicit plugin reload,
as before: the prompt feature does not need skill convergence, and the
pre-existing manual-reload semantics stay uniform across all plugin
contributions. Removes the convergence-driven skill reload, the
reloadSource de-privatization, and their tests; restores the
PluginSkillSource onDidReload forwarding and its catalog tests.
* refactor(agent-core-v2): apply plugin system-prompt changes only on explicit reload
Drop the live convergence machinery (the plugin onDidChange barrier,
the sessionPluginContribution fan-out, the restored-prompt drift gate,
and the day-precision render clock) so plugin system-prompt sections
take effect at the same point as every other plugin contribution:
/plugins reload or a new session. The profile now refreshes when the
session skill catalog re-pulls its plugin source on reload, reading
both the skill list and the prompt sections fresh.
* feat(agent-core): let plugins contribute system prompt instructions via the manifest systemPrompt field
* chore(agent-core-v2): remove inline implementation comment
* docs: clarify plugin prompt refresh semantics
---------
Signed-off-by: 7Sageer <sag77r@hotmail.com>
|
||
|
|
efac96c8a9
|
feat(agent-core): custom agent files and secondary model on the v1 engine (#2232)
* feat(agent-core): custom agent files and secondary model on the v1 engine
Migrate the custom agentfile and secondary-model capabilities from
agent-core-v2 to the v1 engine so they work in the TUI and plain
kimi -p sessions:
- discover Markdown agent files from user/project/extra/explicit
directories with the v2 precedence rules, a merged session profile
catalog replacing the hardcoded builtin profile lookups, SYSTEM.md
main prompt override, and ${base_prompt} backed by the effective
default
- --agent/--agent-file now work in print mode on the default engine;
CreateSessionOptions gains agentProfile/agentFiles
- [secondary_model] config + KIMI_SECONDARY_MODEL/EFFORT bind newly
spawned subagents to a cheaper model behind the secondary-model
experiment flag, with primary/secondary model params on Agent and
AgentSwarm and upfront session warnings
- full disallowedTools deny semantics (exact names + mcp__ globs)
evaluated by the tool manager and persisted in the agent wire
* fix(cli): guard optional agentFiles in the prompt runner
runPrompt is also driven programmatically (headless goal flow) with
options that never pass through the CLI parser defaults, so agentFiles
can be undefined; mirror the addDirs optional-chaining pattern. Also
extend the SDK experimental-feature assertion with the secondary-model
flag.
* fix(agent-core): preserve custom agent bindings on v1
* fix(agent-core): narrow secondary model error hints
* fix(agent-core): persist custom agent profile bindings
* Delete .changeset/sdk-agent-profile-options.md
Signed-off-by: 7Sageer <sag77r@hotmail.com>
* Update v1-custom-agent-files.md
Signed-off-by: 7Sageer <sag77r@hotmail.com>
* Update v1-secondary-model.md
Signed-off-by: 7Sageer <sag77r@hotmail.com>
* Update v1-custom-agent-files.md
Signed-off-by: 7Sageer <sag77r@hotmail.com>
* fix(agent-core): keep SYSTEM.md a prompt-only overlay for delegation
* docs: update agent file and secondary model availability wording
* fix(cli): reject --agent-file combined with session resume
The resume path only forwards the agent file's name for the bound-profile
assertion; the file's content is never re-applied (the session keeps its
creation-time catalog snapshot). Previously the combination was silently
accepted, so an edited file (or a same-named one) appeared to apply but did
not. Reject it at option validation and document the constraint.
* refactor(agent-core): share prompt-section prose and note v2 twins in agentfile headers
The Windows notes, additional-dirs and skills prose blocks existed twice:
inline in the builtin default template (system.md) and as constants in the
agent-file renderer (from-file.ts). Extract them to profile/prompt-sections.ts
as the single source: system.md renders them through injected KIMI_* template
variables and from-file.ts imports the same constants. Rendered prompts are
byte-identical for all four builtin profiles across macOS/Windows and
skills/dirs on/off; a new test pins system.md to the shared constants.
Also mark each profile/agentfile file with the path of its agent-core-v2
counterpart so format/semantics changes land in both engines.
* feat(cli): add /secondary_model command for the subagent model
Mirror /model: a picker with a thinking-effort step that persists [secondary_model] and live-applies to the current session via a new Session.setSecondaryModel RPC (node-sdk wrapper included), so newly spawned subagents bind the new model right away. The /model picker now hides the synthesized __secondary__ derived entry; docs and the update-config builtin skill mention the section.
* feat(tui): show the bound model in subagent run stats
Subagents report their model alias via agent.status.updated after spawn; resolve it to a display name and surface it in tool-call subagent stats and agent-group rows.
* fix(agent-core): validate agent profile before session persistence
* fix(agent-core): refresh subagent tools after model switch
* fix(agent-core): show subagent model preferences
* fix(agent-core): preserve secondary model recipe on live apply
* fix(agent-core): make secondary model apply explicit
* fix(tui): refresh secondary model display state
* chore: merge secondary model changesets into one
* Add /secondary_model command for subagent configuration
Show each subagent's model in the subagent card header and agent-group rows. Requires the secondary-model experiment (KIMI_CODE_EXPERIMENTAL_SECONDARY_MODEL=1); run /secondary_model to pick a model and thinking effort, applied to the current session immediately.
Signed-off-by: 7Sageer <sag77r@hotmail.com>
* fix(agent-core): align explicit agent file precedence
* fix(agent-core): let disallowedTools deny select_tools
* chore(cli): drop engine mention from --agent/--agent-file help text
* feat(cli): support --agent/--agent-file in the interactive TUI
Bind the selected agent profile to the startup session when launching
the TUI with --agent/--agent-file, including the session created after
an OAuth login at startup. Sessions created later in the process (/new)
keep the default profile.
Make both flags creation-only in every mode: combining them with
--session/--continue is now rejected in print mode too, since resume
restores the bound agent from the session automatically.
* fix(agent-core): persist new secondary-model selections under env overrides
stripSecondaryModelConfig restored secondary_model.model/default_effort
from raw whenever KIMI_SECONDARY_MODEL/KIMI_SECONDARY_EFFORT was set, so
a /secondary_model pick made under the env vars was silently discarded
on write. Restore from raw only when the value being written still
equals the env value (an overlay round-trip), mirroring the pointer
check in stripEnvModelConfig; a genuinely different selection now
reaches config.toml.
* fix(cli): report the effective secondary model when env overrides the pick
/secondary_model toasted the picked alias even when
KIMI_SECONDARY_MODEL/KIMI_SECONDARY_EFFORT made the session bind a
different model. Read the effective binding back from the reloaded
config (as /model does from session status) and warn with the
env-overridden values instead.
* feat(tui): show the bound model name in the AgentSwarm panel header
---------
Signed-off-by: 7Sageer <sag77r@hotmail.com>
|
||
|
|
de0ba9d065
|
fix(agent-core): count validation-rejected tool calls toward the repeat breaker (#2313)
* fix(agent-core): count validation-rejected tool calls toward the repeat breaker
Args-rejected calls returned before prepareToolExecution, so the breaker
never counted them and the model could re-issue the same invalid call
until maxSteps. Register them in finalizeToolResult so reminders fire at
3/5/8 and the turn force-stops at 12.
* fix(agent-core): key parse-failed repeats on raw argument text
Malformed JSON arguments normalize to {} on parse failure, which keyed
every malformed-but-different attempt identically and could force-stop a
turn whose calls were evolving rather than identical. Register skipped
calls on the raw arguments text when parsing failed.
---------
Co-authored-by: fengchenchen <fengchenchen@moonshot.ai>
|
||
|
|
cdbd33c13c
|
fix(kosong): fail fast on quota-exhausted 429 instead of retrying (#1857)
* fix(kosong): fail fast on quota-exhausted 429 instead of retrying A 429 caused by an exhausted account quota or insufficient balance (Moonshot error.type "exceeded_current_quota_error", OpenAI "insufficient_quota") can never succeed on retry, yet it was classified as APIProviderRateLimitError and silently retried for the whole budget (10 attempts, ~3 minutes of backoff) with no UI feedback — the session appeared frozen on every request. Introduce APIProviderQuotaExhaustedError, minted in normalizeAPIStatusError from the structured body error.type/error.code forwarded by convertOpenAIError, with billing-anchored message patterns as a fallback for gateways that flatten the body to text. The new class is excluded from isRetryableGenerateError (fail fast, even when a retry-after header is present) and from isProviderRateLimitError (no swarm requeue/suspend). toKimiErrorPayload and translateProviderError map it to provider.api_error (retryable: false) instead of provider.rate_limit, and classifyApiError reports it as quota_exhausted in telemetry. agent-core-v2 mirrors the same fix. Transient rate-limit 429s keep the existing retry, backoff, and Retry-After behavior (verified end-to-end against a mock provider: quota body fails after attempt 1/10; rate-limit body still walks the full 10-attempt ladder). Behavior changes to note: quota-failed swarm subagents now fail instead of suspending indefinitely as "Rate limited...", and quota errors cross the wire as provider.api_error rather than provider.rate_limit. * fix(kosong): classify quota exhaustion in OpenAI Responses stream errors Responses response.failed / error SSE events carry no HTTP status and were minted by errorFromOpenAIResponsesEvent as either a rate-limit error (rate_limit_exceeded / embedded status_code=429) or a base ChatProviderError — and the base class falls into the retryable unclassified-failure fallback, so an insufficient_quota event still burned the whole retry budget on the openai_responses path. Route the event code and message through the same quota-exhausted check before the rate-limit branch, in kosong and the agent-core-v2 mirror. Covers all three entry paths (error events, response.failed, nested gateway frames) since they share the single converter. * style(agent-core-v2): drop inline comments per AGENTS.md header-only rule agent-core-v2 comments live solely in the top-of-file block, never beside functions or statements; the kosong twins keep the full rationale. * refactor(kosong,agent-core-v2): move quota-429 checks to vendor hook Per review on #1857: the knowledge of how a backend signals quota exhaustion is vendor-specific and must not run for every OpenAI-compatible provider from the shared conversion layer. - Add a convertError hook: ProtocolTrait.convertError in agent-core-v2 (single-value, last-declarer-wins, bound by composeOpenAIChatHooks / composeAnthropicHooks / traitConvertError) and an equivalent optional hook parameter on convertOpenAIError / convertAnthropicError. Bases consult it with the raw failure (SDK error on HTTP paths, raw event on the Responses in-stream path) after the abort guard, before their own rules. - Declare Moonshot's quota signals (exceeded_current_quota_error, billing wordings) on the Kimi side: kimiOpenAITrait and kimiAnthropicTrait in v2, the KimiChatProvider and KimiFiles catch sites in kosong, all through the new classifyKimiQuotaError. - Drop the options parameter from normalizeAPIStatusError and the shared quota code/pattern tables: the contract layer keeps only the vendor-neutral APIProviderQuotaExhaustedError type and its retry / rate-limit / wire-mapping semantics. - The OpenAI bases keep recognizing only OpenAI's own documented insufficient_quota code (HTTP and Responses stream events) as protocol knowledge of that wire. Behavior: kimi and openai provider types classify exactly as before; an unregistered vendor speaking Moonshot billing wordings through a plain openai transport now stays a retryable rate limit by design. * fix(kosong,agent-core,agent-core-v2): wire kimi quota hook fully Follow-up to the second review round on #1857, all four findings: - Kimi-over-Anthropic (legacy engine): AnthropicOptions gains the same optional convertError hook as the OpenAI bases, threaded through AnthropicStreamedMessage and every catch site, and the provider manager's anthropic route now passes classifyKimiQuotaError for provider type kimi — a quota-exhausted 429 over this transport previously still burned the retry budget. classifyKimiQuotaError now also walks error -> .error -> .error.error for the code/type, since the Anthropic SDK keeps the full body on .error instead of hoisting. - v2 telemetry: ApiErrorKind gains 'quota_exhausted' and classifyApiError checks APIProviderQuotaExhaustedError before the generic 429 branch, matching the legacy engine's reporting. - Hook contract: converted ChatProviderErrors now pass through before the vendor hook is consulted in convertOpenAIError / convertAnthropicError (both engines), so the hook sees each raw failure exactly once even when a stream-minted error crosses an outer catch; tests assert the single consult. - protocolTrait: the convertError member doc shrinks to the concise style and the consult contract moves into the file header's composition rules. * test(kosong,agent-core,agent-core-v2): lock quota hook assembly paths Third review round on #1857: - Fix the v2 anthropic base header and AnthropicHooks doc still claiming withThinking is the only hook. - Drop the two remaining non-header JSDoc blocks in protocolTrait.ts per the AGENTS.md header-only rule; the consult contract already lives in the file header. - Update the ProtocolTrait contract test to the seventeen-hook shape (convertError included) and cover the traitConvertError binding. - Add real-assembly regression probes: the v2 registry composes a (kimi, anthropic) provider whose mocked SDK client throws a Moonshot quota 429 and generate rejects with the non-retryable APIProviderQuotaExhaustedError (a plain anthropic composition keeps the same 429 retryable); the legacy ProviderManager routing test asserts convertError is classifyKimiQuotaError on the kimi-anthropic route and absent for plain anthropic; the legacy provider threads options.convertError to its generate catch. * test(kosong,agent-core-v2): cover KimiFiles quota 429 and drop stale docs Fourth review round on #1857: - Drop the AnthropicHooks member JSDoc (its content already lives in the anthropic.ts and anthropicHooks.ts file headers) and fix the anthropic contrib header still calling the hook set single-hook. - Add the missing KimiFiles regression in both engines: a mocked files client rejecting with a Moonshot quota 429 makes uploadVideo reject with the non-retryable APIProviderQuotaExhaustedError, locking the classifyKimiQuotaError argument at the upload catch sites. |
||
|
|
0cef160c4b
|
fix(agent-core): continue goal pursuit when a goal turn hits the per-turn step limit (#2210)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
Release / Native release artifact (push) Blocked by required conditions
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix(agent-core): continue goal pursuit when a goal turn hits the per-turn step limit * chore(agent-core-v2): regenerate state manifest * fix(agent-core): start goal pursuit when the goal-creating turn hits the step limit * refactor(agent-core-v2): drop step-cap narration from goal module and test |
||
|
|
c497af60e6
|
fix(tui): steer user messages into the running turn while a goal is active (#2153)
Some checks failed
CI / build (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test (5) (push) Has been cancelled
CI / test-pi-tui (push) Has been cancelled
CI / test-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / typecheck (push) Has been cancelled
Nix Build / Check flake.nix workspace sync (push) Has been cancelled
Release / Release (push) Has been cancelled
Nix Build / nix build .#kimi-code (push) Has been cancelled
Release / Deploy docs (push) Has been cancelled
Release / Native release artifact (push) Has been cancelled
Release / Publish native release assets (push) Has been cancelled
* fix(tui): steer user messages into the running turn while a goal is active * fix(tui): reset request state when steering mid-goal input fails * fix(agent-core): update session prompt metadata on steer |
||
|
|
f06eb5c60e
|
feat(agent-core): defer registered user tools (#2119)
Some checks are pending
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / build (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* feat(agent-core): defer registered user tools Allow hosts to mark registered user tools as deferred so select_tools can discover and load their schemas on demand in both agent-core implementations. * fix(agent-core): hide unregistered deferred tools Filter loaded deferred user-tool schemas from provider history and loaded-state checks after unregister while preserving canonical history and disconnected MCP behavior. * fix(agent-core-v2): drop stale inline schemas Stop treating previously loaded user-tool schemas as active after the same tool is re-registered for inline disclosure. |
||
|
|
66f611aae9
|
fix: echo thinking under the reasoning field the endpoint actually uses (#2104)
Some checks are pending
CI / lint (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
OpenAI-compatible endpoints disagree on the wire field for reasoning content: `reasoning_content` (DeepSeek/Moonshot convention, older vLLM) vs `reasoning` (OpenAI GPT-OSS guidance, current vLLM — which also only accepts `reasoning` on the request side, vllm-project/vllm#38488). Reading only `reasoning_content` silently dropped thinking, and the lost thinking then never made it back into later requests. Add per-endpoint dialect detection: inbound responses are scanned in priority order (reasoning_content, reasoning_details, reasoning; first string value wins), the carrying key is remembered, and outbound messages echo thinking under the same key (default reasoning_content). An explicit `reasoningKey` / `reasoning_key` config still pins the dialect. - kosong: shared reasoning-key module; wire the kimi and openai-legacy providers; the dialect cell is shared across per-step provider clones. - agent-core-v2: same mechanism in the vendored openai-legacy base; the kimi trait no longer pins reasoning_content (the default already is), keeping Moonshot wire behavior byte-identical while adapting to vLLM. - agent-core: memoize the base provider behind ConfigState.provider so the detected dialect survives across turns instead of being rebuilt per access. |
||
|
|
5fdbdb4a22
|
feat: configure web search/fetch services via KIMI_WEB_* env vars (#2096)
* feat: configure web search/fetch services via KIMI_WEB_* env vars KIMI_WEB_SEARCH_BASE_URL / KIMI_WEB_SEARCH_API_KEY and KIMI_WEB_FETCH_BASE_URL / KIMI_WEB_FETCH_API_KEY overlay the [services] config section field by field in both engines (env wins over config.toml), so the WebSearch and FetchURL backends can be pointed at a Moonshot service without OAuth login. The v2 engine now also honors the explicit [services.moonshot_fetch] section (config > managed OAuth > local), which it previously parsed but never consumed. * fix(agent-core-v2): guard stripServicesEnv against clearing the services section config.replace(SERVICES_SECTION, undefined) — the logout deprovisioning path in authService — passes undefined straight into the section strip, and the composed stripServicesEnv dereferenced it (value[key]), throwing TypeError and aborting logout mid-cleanup. Add the same isPlainObject guard the other strip implementations (stripProvidersEnv, stripEnvBoundFields) already have, plus a regression test that also locks in the env overlay staying effective after the file value is cleared. * style(agent-core-v2): follow header-only comment convention * fix: isolate env web service credentials * Add env vars for web search and fetch services The new environment variables `KIMI_WEB_SEARCH_BASE_URL`, `KIMI_WEB_SEARCH_API_KEY`, `KIMI_WEB_FETCH_BASE_URL`, and `KIMI_WEB_FETCH_API_KEY` take priority over the corresponding fields in `config.toml`. The `kimi web` backend now honors the `[services.moonshot_fetch]` config section. Signed-off-by: 7Sageer <sag77r@hotmail.com> --------- Signed-off-by: 7Sageer <sag77r@hotmail.com> |
||
|
|
527d485d92
|
feat: add global default MCP server timeout configs (#2065)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* feat: add global default MCP server startup timeout config Add a `[mcp] startup_timeout_ms` config.toml section with a `KIMI_MCP_STARTUP_TIMEOUT_MS` env override as the global default MCP server connection (startup + tool discovery) timeout. Precedence: per-server `startupTimeoutMs` in mcp.json > env var > config.toml > built-in 30s default. * feat: add global default MCP tool call timeout config Extend the `[mcp]` section with `tool_timeout_ms` and the `KIMI_MCP_TOOL_TIMEOUT_MS` env override as the global default for single MCP tool calls, mirroring the startup timeout: a per-server `toolTimeoutMs` in mcp.json still wins, and unset entries fall back to the SDK built-in 60s default. * chore: shorten the mcp timeouts changeset * feat(agent-core): add global default MCP server timeout configs Port the `[mcp]` section (`startup_timeout_ms` / `tool_timeout_ms`) and the `KIMI_MCP_STARTUP_TIMEOUT_MS` / `KIMI_MCP_TOOL_TIMEOUT_MS` env overrides to agent-core (v1), mirroring the v2 semantics: per-server fields in mcp.json > env vars > config.toml > built-in defaults. The v1 TOML loader gains explicit `mcp` read/write mappings, and both connection-manager construction sites (Session, testGlobalMcpServer RPC) pass the resolved defaults through. * fix(agent-core): validate and apply MCP timeout defaults * fix: propagate MCP startup timeout to SDK requests * refactor(agent-core-v2): resolve MCP default timeouts at connect time Keep the session connection manager synchronously lazy instead of gating its existence on config readiness: resolveDefaultTimeouts is read from the mcp config section at each (re)connect, so AgentMcpService's eager construction stays unconditionally safe and reconnects pick up changed preferences. The initial connect still awaits config.ready for a deterministic snapshot. Also restore the ISessionMcpService method docs, bump the changeset to minor, and fix the v1 env-parse comment. * chore(agent-core-v2): regenerate config manifest for the mcp section * Add global default MCP server timeouts configuration Specify the new global default MCP server timeouts in both the config file and environment variables. Signed-off-by: 7Sageer <sag77r@hotmail.com> --------- Signed-off-by: 7Sageer <sag77r@hotmail.com> |
||
|
|
8bf5bacba9
|
ci: release packages (#1989)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
8250e590f3
|
docs(cron): drop references to the non-existent kimi resume command (#2050)
* docs(cron): drop references to the non-existent `kimi resume` command - point user docs at the real resume command `kimi --session` - reword cron tool descriptions and code comments in agent-core and agent-core-v2 to describe session resume without naming a subcommand * chore: add changeset for cron docs wording fix |
||
|
|
4c763f6763
|
feat: send prompt-attached videos directly with the prompt (#1999)
Some checks are pending
CI / lint (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Release / Native release artifact (push) Blocked by required conditions
Release / Release (push) Waiting to run
CI / test-windows (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Deploy docs (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* feat: send prompt-attached videos directly with the prompt
Videos attached to a prompt (pasted in the TUI, uploaded in the web UI)
previously reached the model only after it opened the file with
ReadMediaFile — an extra tool round trip that could leave the video
unseen when the model never made that call. They are now uploaded
through the model provider's file channel and embedded directly in the
user message as the provider-issued reference; ReadMediaFile stays as
the fallback and as the model's own way to open video files.
- agent-core: new uploadVideo agent RPC and Session.uploadVideo in the
SDK; the TUI uploads pasted videos at submit time, falling back to
the file-tag form on failure
- kap-server: inline file-source video prompt parts at the REST edge
and map provider file ids back to local uploads behind
GET /files/llm/{llm_id}
- kimi-web: play provider-referenced prompt videos after reload/resume
* fix: fall back to inline video when the upload channel fails
ReadMediaFile only used the provider's video upload channel when one
was bound, and surfaced a hard tool error when the upload itself
failed — on providers without a files endpoint (or a transient upload
failure) the model was told the video could not be read at all. Now a
missing or failing upload falls back to delivering the video inline
(base64), the same shape providers without an upload channel already
get. Both engines (agent-core and agent-core-v2) are fixed.
* test: cover prompt video edge cases and failure paths
Stress coverage for the prompt video pipeline:
- agent-core uploadVideo RPC: extension/magic classification
(.txt with video bytes accepted, extension trusted when magic is
absent), exact 100MB boundary, directory and nonexistent paths
- TUI: mixed per-video outcomes (one inlined, one tag fallback),
submission order behind an in-flight upload, queued video messages
carrying final uploaded parts
- kap-server: per-video provider-id mappings, Range requests through
the llm redirect, mapping persistence across a server restart
* fix: surface auth rejections from the video upload channel
The base64 fallback for a failing video upload must not mask auth
rejections: a 401/403 (surfaced as provider.auth_error) drives the
credential force-refresh and a clear auth error, while an inline
payload would just be rejected again by the next request. Only a
missing or broken upload channel (no files endpoint, network/server
errors) falls back to inline delivery.
* fix: keep the by-design no-hook video error from degrading to inline
Main's contract for a provider with no video upload hook is an honest
"does not support video upload" tool error — an inline payload would
be dropped on that protocol's wire anyway. The base64 fallback now only
applies to an upload channel that exists but failed at runtime. The
no-hook throw gets a stable type (VideoUploadUnsupportedError) so the
two cases are told apart without matching message text.
* fix: constrain the llm video route param to a safe alphabet
The provider file id is used as a blob-store key, and the node-fs
backend joins scope and key into a storage path. An id containing an
encoded path separator (%2F) could address a different storage path
than the intended llm-video mapping; the route now only accepts the
provider-id alphabet.
* style(agent-core-v2): move added explanations into top-of-file comment blocks
The package's comment convention keeps comments solely in the top-of-file
block; relocate the new notes (url-source id pairing, video delivery
fallback, VideoUploadUnsupportedError) from functions and schema fields
into their module headers.
* fix: reject prompt video uploads when the model lacks video input
The uploadVideo RPC only checked the provider's upload channel, so an
SDK caller on a text-only or unknown-capability model could obtain a
valid-looking video_url part the current model is not supposed to
accept. The TUI capability guard does not cover this public path, so
the agent now gates on video_in itself.
* fix: sniff uploaded video bytes before inlining them
The inline branch trusted the upload-time content type; now the bytes
are sniffed first, and anything magic-confirmed as a non-video kind
(e.g. an image mislabeled as video/mp4) falls back to the file-tag
form instead of being uploaded. Like the image gate, bytes are
authoritative where the container format allows it — an MPEG-PS
lookalike still rides the extension, matching ReadMediaFile.
* test: keep the generation stub pending until the abort lands
An immediately-answered 404 ends the turn (non-retryable) before the
test's abort call, racing the cleanup into a 409; the stub now hangs
generation until the abort cancels it.
* fix: validate prompt file references before mutating session controls
A stale file_id failed inside media resolution — after the model,
thinking and permission overrides had already been applied — so a
rejected prompt still changed the session's controls. File references
are now checked up front, keeping failed submits side-effect free.
* fix: serialize prompt submissions per session
A slow provider video upload let a later text-only request reach the
queue ahead of an earlier video one, silently reordering the
conversation for REST clients and multiple tabs. Submissions to the
same session now chain, matching the ordering the TUI already
guarantees locally.
* fix: play reloaded provider videos through the authenticated fetch path
A video recovered from an ms:// reference carried only the bare redirect
URL, which 401s under daemon auth when loaded natively. The attachment
now keeps the provider file id (llmFileId) end to end, and AuthMedia
fetches the bytes with the Bearer credential through the daemon's llm
redirect — the same blob-URL path uploaded files already use.
* fix: fence pending video submits against session and model switches
A slow paste-upload left the TUI idle, so /new, the session picker or
/model could fire mid-upload; the continuation then dispatched the old
session's provider reference into the newly selected session or a
model that cannot resolve it. The dispatch now re-checks that the
session and model are unchanged and asks for a resend instead.
* fix: preserve the caller's video path verbatim in uploadVideo
Trimming the path changed the filesystem target before validation and
upload, so a name that legitimately starts or ends with whitespace
resolved to the wrong file; the trim is now only the emptiness check.
* fix: forward provider-issued ids on image URL prompt parts too
The shared url-source schema accepts id for image and video parts, but
only the video path forwarded it, dropping provider-keyed image ids
between prompt acceptance and the model request.
* fix(web): reconcile inlined video echoes into the optimistic user message
The loose user-message matcher counted media parts and <video path>
tags but not the [video:ms://…] text shape, so a racing server echo of
an inlined upload slipped through as a duplicate user bubble.
* fix: queue bash submits behind a pending video upload
A bash-mode submit could start while a pasted video was still
uploading, recording shell context before the earlier prompt was
dispatched and reordering user actions; it now chains behind the
upload like normal submits.
* test: cast the driver through unknown for the session-switch fence test
* fix: validate prompt file references before resolving the prompt agent
A stale file_id posted to a fresh or cold session materialized the main
agent (registering it in session metadata and igniting agent-scoped
services) before the request was rejected. The file check now runs
first, so failed submits create nothing and mutate nothing.
* fix: key the playback mapping by the id embedded in the reference URL
Projections and clients read the provider id from the ms:// URL, not
the id field, so an upload that returns an id-less or mismatched
reference would inline fine but 404 on playback. The mapping now
derives its key from the URL, falling back to the explicit id.
* fix: sanitize provider video ids on the write side of the playback map
The read route got the safe-alphabet guard, but recordLlmVideoRef still
used the provider-returned id verbatim as a blob-store key; a crafted
provider response could write the mapping outside the llm-video
namespace. Out-of-alphabet ids are now dropped on both put and get.
* fix(web): keep recovered provider videos resendable through the edit path
The composer reload path only honored fileId and fell back to a
bare fetch(url) without the Bearer token, so editing a reloaded
provider-video turn dropped the chip after a 401. llmFileId is now
threaded through and the bytes are re-uploaded via the authenticated
llm redirect.
* fix: fall back to inline video for no-hook providers whose wire carries it
The by-design no-hook error is only the honest answer when the wire
would drop an inline payload anyway (the OpenAI family). Protocols
that convert video_url (kimi, anthropic, google-genai, vertex) now
take the base64 fallback instead of failing every video read; the
registrar computes the flag from the model's protocol.
* test: satisfy the full IBlobStore shape in the playback-map stub
The tsgo typecheck job rejects a structural stub missing _serviceBrand
and list even though plain tsc accepted it.
* fix: queue prompt-producing slash commands behind pending uploads
Skill activations and plugin commands started their turn immediately
while a pasted video was still uploading, so the earlier video prompt
queued behind them and user actions ran out of order. Both paths now
chain behind inputSubmitChain (and re-check session/model at dispatch)
like normal and bash submits.
* fix: validate media kinds in the prompt file-reference preflight
The preflight only proved a referenced file exists; a real upload used
with the wrong kind (e.g. a PDF submitted as video) still passed it and
mutated session controls before assertMediaFile rejected the request.
The kind assertion now runs up front with the existence check.
* fix(web): play sent and recovered videos in the file preview
The media preview returned early for every kind except image, so a
user-turn video chip's play action was a no-op even with llmFileId
threaded through. The preview now handles video: bytes come from the
authenticated file/llm fetch into a blob URL and render in a native
player.
* fix(web): preview recovered videos with the authenticated blob URL
The llm re-upload branch fetched bytes with auth but kept the protected
redirect URL as the chip preview, which 401s as a native video src; the
fetched blob now becomes the preview URL, mirroring the fileId branch.
* style(agent-core-v2): move the inline-fallback note into the module header
Same package comment convention as before: rationale lives in the
top-of-file block, not beside the registration call.
* fix: fence delayed bash submits to the originating session
The chained bash callback ran runShellCommandFromInput against whatever
session was active at dispatch time, so a command submitted in session
A could execute in session B's workspace and be recorded there after a
mid-upload switch. The originating session is now captured at submit
and re-verified at dispatch, like the prompt and skill paths.
* fix: emit prompt video telemetry from the agent scope
video_upload is an agent-level event requiring ambient agent identity,
but the uploader was built with the Core-scoped session view, leaving
prompt-upload events unattributable. The route now resolves telemetry
from the target agent for the uploader while image compression keeps
the session-scoped view.
* fix: preserve provider image ids through legacy projections and web mappers
The url-source id accepted by the prompt schema was dropped again by
the legacy message projection and the web wire mapper, so provider-
keyed image references lost their id across messages, snapshots, and
undo responses. It now flows through both directions.
* fix(web): revoke recovered video blob URLs before dropping attachments
A failed llm re-upload removed the attachment without revoking the
freshly created preview blob URL, pinning the whole video in the
browser blob store until page unload on every failed edit attempt.
* fix: serialize foreground slash commands behind pending uploads
/compact and /init started their turn while a pasted video was still
uploading, so the earlier message landed after them — and compaction
summarized the context without it. Prompt-producing builtin commands
now share the same queueBehindPendingUploads chain (with the
session/model dispatch fence) as skill, plugin, and bash submits.
* fix: defer session controls until media preparation succeeds
Media resolution now runs before any profile/model/thinking/permission/
denylist mutation, with the uploader resolved transiently from the
requested (or currently bound) model — a failed submission leaves the
session's controls untouched. A concurrent model switch during
preparation is rejected with session.busy instead of enqueueing a
reference uploaded for the previous model.
* chore: bump the new SDK video upload API as a minor release
Session.uploadVideo is new public API surface, not a patch-level tweak.
* fix: re-check busy state before draining upload-queued commands
A slash command deferred behind a video upload ran the moment the video
prompt dispatched, landing on an already-running turn: beginSessionRequest
wiped the active turn's live pane, and /init or /compact started on top
of it. The deferred callbacks for skills, plugin commands, /compact and
/init now re-run the resolver's busy check at dispatch and show the same
blocked message the user would get when typing while streaming.
* fix: resolve profile-bound models before choosing the uploader
A first prompt carrying "profile" without "model" resolved the upload
model from the still-unbound alias, so no uploader was installed and
every attached video fell back to a tool-read tag even when the
configured default model supports provider upload. The transient
resolution now mirrors AgentProfileService.bind: an explicit body model
wins, a profile bind falls back to the configured default model, and
only otherwise does the currently bound alias apply.
* refactor: resolve prompt videos at request time inside the engine
Move prompt-video delivery out of the submission edge: the TUI submits
synchronously with a local file:// part the v1 turn resolves before the
message enters history, and kap-server carries an internal kimi-file://
reference the v2 requester resolves against the effective model with an
app-scoped upload cache. History keeps the durable local file id, the
/messages projection emits structured video parts, and the web plays
videos back through the authenticated /files channel - deleting the
submit fences, per-session serialization, provider-id reverse mapping,
redirect endpoint, and the unreleased SDK upload API.
* fix: propagate abort through video upload delivery instead of degrading
A turn cancelled mid-upload used to be treated as an ordinary upload
failure: v1 fell back to an inline base64 part and appended the degraded
message to history, and the v2 resolver memoized the tag fallback for the
rest of the agent's lifetime. Both catch sites now check the delivery
signal itself - abort rejections vary in shape by provider - and re-throw
so cancellation ends the turn (v1, classified as cancelled via the abort
reason) or the request (v2, not memoized, so the next turn uploads).
* fix: keep the tag form for no-upload providers whose wire drops inline video
An OpenAI-family model configured with video_in but no provider upload
channel used to receive prompt videos as an inline base64 part - which
chat completions rejects and the Responses adapter degrades to an
omitted-video placeholder, persisting ~4/3x the file size in history for
bytes the model never sees. The prompt path now mirrors the v2 resolver's
protocol gate and degrades to the <video path> tag instead; ReadMediaFile's
own delivery is unchanged. Also merges the prompt-video changesets into a
single user-facing entry.
* fix: escape the NUL separator in the video upload cache key
The cache-key template literal contained a literal NUL byte instead of
the \0 escape, which made Git classify the whole source file as binary
- no inline diffs, unreliable text tooling. The escape produces the
byte-identical runtime string, so hashed cache keys are unchanged.
* fix: check the abort signal before the inline video fallback
The no-uploader inline path (and the post-upload-failure fall-through)
never consulted the delivery signal, so cancelling a turn while the video
bytes were being read still base64-encoded the file and appended the
degraded message to history. The inline branch now re-throws the abort
reason first, matching the upload catch.
* fix: retry transient prompt video upload failures on later steps
A generic upload failure used to memoize its tag fallback for the rest of
the agent's lifetime, freezing a transient files-endpoint error into a
permanently degraded video. The resolver now marks failure-born fallbacks
as non-memoizable: the current request keeps the lightweight tag form and
the next step retries the upload. Structural outcomes (successful uploads,
capability and sniff fallbacks, no-hook inline) stay memoized for
step-retry stability.
|