chore: merge upstream main (f8ec3d16) and adopt upstream secondary-model/agentfile (#2232) - #12
Merged
Merged
Conversation
* feat(kap-server): add global fs:mkdir endpoint Add POST /api/v1/fs:mkdir to create a directory on the host filesystem by absolute path, backing the folder picker's "new folder" action. Implemented directly on node:fs/promises.mkdir in the transport layer for now, non-recursive by design, with wire errors mapped to the existing fs.* codes (40001/40409/40411/40919). * test(kap-server): update api surface snapshot for fs:mkdir * test(kap-server): stop export tests from holding server.close() open The export download tests reused pooled undici keep-alive connections, so afterEach's server.close() could wait out fastify's 72s default keepAliveTimeout and die on the 10s hook timeout (flaky on CI). Send connection: close on the streamed export requests, matching the fs:content tests.
* chore(web): upgrade markstream-vue to 1.0.7 Fix garbled code-block line numbers reported on 0.29.2: the async code-block loading fallback rendered unstyled (proportional font, code overlapping the line-number gutter) and with an over-estimated reserved height that clipped leading lines. markstream-vue 1.0.6 adds self-contained fallback styles and 1.0.7 fixes the height estimate. * chore(nix): update pnpmDeps hash for markstream-vue 1.0.7 * chore(web): scope lockfile update to the markstream-vue graph Regenerate pnpm-lock.yaml with a plain install so only markstream-vue and its transitive deps move (markdown-it-ts, stream-markdown-parser, etc.); unrelated toolchains (e.g. lightningcss in kimi-inspect) stay pinned as before. Addresses review feedback. * chore(nix): update pnpmDeps hash after lockfile scoping * chore(changeset): shorten release note to one user-facing sentence
…t-core-v2 bashParser service (MoonshotAI#2016) * feat(tree-sitter-bash): scaffold pure-TypeScript bash parser package Add packages/tree-sitter-bash with the SyntaxNode tree model (UTF-16 code-unit offsets, tree-sitter-bash named-node type names), a parse budget (deadline + node cap) with an aborted ParseResult variant, and a placeholder parse() to be replaced by the real lexer/parser. * feat(tree-sitter-bash): add lexer and core recursive-descent parser Cover the permission-analysis grammar subset: lists, pipelines, commands, words, quotes, expansions, command/process substitution, subshells, the full redirect operator set, heredocs and comments, with tree-sitter-bash named-node type names. Long scan loops check the parse deadline via budget.progress() so large literals cannot exhaust the node cap; parse depth is bounded on all recursion chains. * feat(tree-sitter-bash): support the full bash grammar Add compound commands (if/while/until/for/c-style-for/select/case/ function/compound/do_group), test commands with reference-exact extglob/regex right-hand-side rules, a Pratt expression engine for arithmetic expansion shared across arith/c-for/test modes, arrays and subscripts, declaration/unset commands, ansi-c/translated strings and brace expressions. Reserved words are recognized only in statement position. Case-aware balanced scanning keeps command substitutions intact around case items, expression leftovers are kept as ERROR nodes instead of dropped, and recursion depth is bounded per chain (substitution 150, parse 500, lexer scan 1024). * test(tree-sitter-bash): add differential fixtures, corpus, fuzz and perf suites Turn the ad-hoc wasm comparison work into permanent infrastructure: a differential helper pinning reference-equivalent and known-difference samples against the real tree-sitter-bash wasm (478 match / 79 known-diff fixtures plus the official v0.25.0 corpus), a three-way consistency check between fixtures, the known-difference registry and the README, deterministic seeded fuzz with tree-integrity assertions, and performance smoke tests. Converges 15 further divergence groups found by systematic probing and documents the rest; the full suite is 853 tests in ~4s. * feat(agent-core-v2): add App-scope bashParser service Wrap the pure @moonshot-ai/tree-sitter-bash package as IBashParserService (L1, no dependencies): parse(source, options) returns a wire-safe BashParseResult whose nodes drop the cyclic parent link so trees can cross the RPC boundary. Budget exhaustion surfaces as { ok: false, reason: 'aborted' }, malformed input as hasError — never a throw. * chore: add changeset for the bash parser service * chore: update pnpmDeps hash after adding tree-sitter-bash package * fix(agent-core-v2): register bashParser service with ScopeActivation The registration was written against the removed InstantiationType API (#/_base/di/extensions); switch to ScopeActivation.OnDemand from #/_base/di/scope so the package typechecks and the service registers. * feat(kimi-inspect): add Bash Parser view Add a fourth icon-rail tab that exercises the App-scope bash parser service over the debug RPC surface: a source textarea with a parse budget (timeoutMs / maxNodes), a dropdown of curated examples adapted from the tree-sitter-bash differential fixtures, and an expandable syntax tree with per-node type, UTF-16 range and leaf text, plus hasError / aborted / node-count badges. * fix(agent-core-v2): snapshot bash syntax trees iteratively A long left-associative chain (e.g. an arithmetic expression with a few thousand operands) parses into a tree thousands of levels deep while still within budget; the recursive DTO conversion then overflowed the JS call stack and made parse throw RangeError, breaking the never-throws contract. Convert the tree with an explicit stack, the same approach as the parser's own materialize. * feat(kimi-inspect): add a deep-arithmetic example to the Bash Parser view A thousand-operand left-associative chain fills the textarea with a thousand-level binary_expression tree — the shape that once overflowed the DTO conversion. Deeper chains still parse in-process but cannot cross the JSON RPC transport (V8 call-stack limit in serialization), so the example stays within the wire limit. * chore: update pnpmDeps hash for the rebased lockfile The rebase onto main merged pnpm-lock.yaml, invalidating the recorded fetchPnpmDeps hash; use the hash CI computed for the merged lockfile.
…onshotAI#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 MoonshotAI#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 MoonshotAI#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 MoonshotAI#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 MoonshotAI#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.
* feat(oauth): return structured managed usage rows
Stop formatting plan-usage labels and reset hints into English strings
at the oauth layer. The parser still absorbs backend field drift, but
now emits a stable structured row (name / window{duration,unit} / used
/ limit / resetAt) that kap-server passes through and clients localize
themselves:
- window: normalized from duration/timeUnit (minute/hour/day/week),
whole-hour minute windows fold to hours, unnamed summaries are the
weekly limit
- resetAt: absolute ISO timestamp; relative reset_in/ttl seconds are
converted at parse time
- TUI /usage panel formats labels and reset hints locally
* refactor(oauth): parse managed usage strictly to the current payload shape
Drop the defensive drift tolerance (alternate reset-time spellings,
reset_in/ttl seconds, remaining-derived used, title/scope names,
top-level duration/timeUnit, fuzzy time-unit matching) and parse only
what the platform actually sends: numeric strings, resetTime, nested
detail/window records, TIME_UNIT_* enums.
* fix(node-sdk): update managed usage smoke example and facade tests for structured rows
… disk (MoonshotAI#2312) - add writeStream/putStream to the storage and blob store interfaces so large values are written incrementally (tmp + fsync + rename) instead of being buffered in memory - FileService.save now streams the request body straight to the blob store and only counts bytes for FileMeta.size - drop the multipart fileSize limit and the file.too_large error from the /files upload path (41301 stays in the wire protocol for session export)
…at breaker (MoonshotAI#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>
…epeat breaker (MoonshotAI#2317) * fix(agent-core-v2): count validation-rejected tool calls toward the repeat breaker * style(agent-core-v2): remove inline implementation comments
…shotAI#2262) * feat(node-sdk): add agent-core-v2 backed SDKRpcClientV2 harness - add SDKRpcClientV2 wiring the v2 engine (DI x Scope) in-process via the klient memory transport, with getExperimentalFeatures migrated to klient.global.flags.list() and unmigrated methods failing fast - export createKimiHarnessV2 / SDKRpcClientV2 from the SDK index - wire the experimental v2 gate into the CLI interactive shell (run-shell) - extend build-dts to bundle agent-core-v2 and klient declarations * feat(node-sdk): migrate listWorkspaceSkills to agent-core-v2 - add engineAccessor escape hatch exposing the in-process engine's app-scope service accessor for SDK methods the klient facade does not cover yet - implement listWorkspaceSkills via ISkillDiscovery plus the v2 user/project root helpers and BUILTIN_SKILLS (plugin skills and skillDirs still gaps) - add a v1-v2 parity test pinning identical return values per migrated method, with understood gaps listed explicitly in KNOWN_DIFFS * feat(node-sdk): migrate the SDK method surface to agent-core-v2 - implement the remaining SDKRpcClientBase methods on SDKRpcClientV2, routed through the klient facade where covered, the engineAccessor escape hatch where the engine has a service, or SDK-side rebuilds on v2 primitives where only primitives exist (config shape mapping, global mcp.json store, MCP OAuth flows, importContext, session warnings, print background policy) - translate the v2 event stream into the v1 Event union and bridge approval/question/user_tool interactions per live session - rebuild resume replay by folding the v2 wire.jsonl through the v1 agent restore pipeline, so resumed sessions render history again - keep deleteSession as not_implemented; the v2 engine has no delete capability - extend the v1-v2 parity suite to every migrated method, pinning understood engine differences in KNOWN_DIFFS - add the dev:cli:v2 root script to launch the TUI on the v2 engine * fix(node-sdk): await the v2 undo and compaction-cancel agent calls * test(cli): spread the real oauth module in the telemetry test mock * feat(node-sdk): forward v2 engine telemetry to the host telemetry client * feat(cli): gate the v2 TUI route behind a dedicated KIMI_CODE_TUI_V2 switch * fix(node-sdk): honor skillDirs on the agent-core-v2 SDK route The v2 SDK client accepted KimiHarnessOptions.skillDirs (the CLI's --skills-dir) but never seeded it into the engine, so explicit skill dirs were silently dropped on the v2 TUI route and the Skill tool could not find skills from them. Seed skillCatalogRuntimeOptions at bootstrap and let listWorkspaceSkills resolve the explicit dirs as the user source, matching the engine's session skill catalog. * refactor(cli): gate the v2 TUI route behind the master experimental flag again Drop the dedicated KIMI_CODE_TUI_V2 switch: the TUI v2 harness route is gated by KIMI_CODE_EXPERIMENTAL_FLAG, the same master switch as the kimi -p v2 route. The gate tests are kept with updated assertions, and dev:cli:v2 sets the master flag again.
…sion modes (MoonshotAI#2321) * feat(kap-server): add the /api/v1/search global message search endpoint Cross-session full-text search over user messages, assistant text and session titles, backed by a minidb index under <home>/search-index with a single-writer lock election and read-only WAL catch-up for other processes. Hits carry transcript anchors (turn ordinal and step id) so clients can jump straight to the matching turn or step. * feat(kimi-inspect): add a search view with chat-timeline navigation The left rail gains a Search view over the global search endpoint, with role and sort filters and cursor pagination. Clicking a hit switches to the chat view and navigates to its session, agent, turn and step — the channel pages the turn into the loaded window, scrolls it into view and flashes the target briefly. * chore(kimi-code): start the dev server without built web assets The repo's dev server scripts (dev:server, dev:kap-server, dev:kap-server:multi, dev:server:restart) now set KIMI_CODE_DEV_SERVER=1. When it is set and dist-web/index.html is missing, kimi web starts the API server without the bundled web UI instead of failing at startup, so backend dev no longer requires a kimi-web build. * feat(kap-server): add literal substring search and a live session route - minidb: text indexes accept an injectable tokenizer/queryTokenizer, and a hashed 2/3-gram tokenizer (NFKC + lowercase, code-point windows) backs substring search; tokenizer names persist in db.textindexes.json with backward-compatible defaults - /api/v1/search gains mode: 'literal' — n-gram candidates confirmed against the original text (zero false positives), with an 'candidate_cap' incomplete flag when the candidate set truncates - container.session_id queries against a session live in this process scan the in-memory transcript store instead of the index (both modes); the response's source: live|index field names the serving route and rides in the page-token fingerprint - kimi-inspect: exact-match toggle and source badge in the search view, plus an in-chat session search bar with jump-to-hit navigation * test(kimi-inspect): avoid stringifying BodyInit in search api tests
…onshotAI#2255) * feat(tui): customizable footer status line via status_line config The bottom status bar was a fixed layout. Add a [status_line] section to tui.toml covering the two established models: - items: codex-style composition. Pick and order the built-in slots (mode, goal, model, tasks, cwd, git, tips); unset keeps today's layout, unknown ids are skipped with a warning, and an empty list blanks line 1. - command: claude-code-style custom line. The footer runs the command with a JSON snapshot on stdin (model, cwd, git branch, permission and plan mode, context usage, session id, version) and renders the first stdout line. Runs are throttled to one per second and capped at 300ms; nonzero exit, empty output, or a timeout falls back to the built-in layout. Line 2 (context readout) stays built-in in every mode. Resolve MoonshotAI#2116. * feat(tui): apply status_line on /reload-tui and document it The reload command pushes reloaded tui.toml fields into AppState; the new statusLine field joins that list so edits go live without a restart. The config files reference (EN/ZH) documents the new section. * fix(tui): round-trip active status_line on save and harden the runner Codex review on MoonshotAI#2255 caught a real one: saveTuiConfig rewrites the whole tui.toml, so changing any other preference dropped an active [status_line] section. Render it live when set (items and command), commented-out guide when unset. Also: spawn the command through ComSpec/cmd.exe on Windows instead of assuming sh.exe, and take the whole process tree down on timeout (process-group kill on POSIX, taskkill /T on Windows) so a script that spawned children cannot leak them. * fix(tui): address status_line review: runner lifecycle, capture cap, tips slot - recreate the command runner when a reload swaps status_line.command; the old runner kept executing the previous script until restart - schedule a trailing refresh instead of dropping updates that arrive inside the throttle window, so the last state change always lands - stop accumulating stdout once the first line is complete (and cap a missing-newline stream at 64KB); only the first line is ever rendered - honor the configured position of the tips slot in items instead of always pinning tips to the far right - route unknown status_line.items warnings through the TUI status area on reload instead of raw stderr, which could corrupt the display Changeset text tightened per maintainer note. --------- Co-authored-by: Kai <me@kaiyi.cool>
* chore: prune non-user-facing changesets before release - Drop changesets for changes users cannot perceive: internal bash parser groundwork, host-identity server start option, and the structured managed-usage refactor - Drop the duplicate agent-core-v2 repeat-breaker entry and remap the v1 fix to @moonshot-ai/kimi-code with user-facing wording - Remove the untouched @moonshot-ai/kimi-code-sdk entry from the quota-exhausted fail-fast changeset - Downgrade the upload size-cap removal to patch and drop the implementation detail from its wording * chore: simplify verbose changeset entries * chore: shorten changeset entries to single statements
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…gine (MoonshotAI#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>
…onshotAI#2345) * test(node-sdk): drop v1-only subagentNames from the resume parity projection Custom agent files made v1's resumed agent config carry the bound profile's delegatable subagent roster; v2's resumed agent state has no equivalent field, so the resume parity cases fail on main. Project the engine-owned field away instead of pinning it as a resume-data gap. * fix(node-sdk): wire applyPersistedSecondaryModel to agent-core-v2 On the v2 engine route the /secondary_model command persisted the recipe but failed to apply it to the current session: the SDK method fell through to the base class's not_implemented getRpc(). v1 pushes a reloaded config snapshot into the session because its spawn binding, tool descriptions, and cached startup warning all read that snapshot. agent-core-v2 resolves the secondary model live against IConfigService at spawn time and rebuilds the tool description per read, so the setConfig write already takes effect session-wide. The override keeps the rest of v1's contract: config reload, the same loud validations (session lookup, persist-first recipe check, pointed-model resolution wrapped at [secondary_model].model), and a warning-cache refresh via a new recheckSecondaryModelWarning on the session warning service. getSessionWarnings also surfaces the v2 secondary-model warning next to the AGENTS.md one, matching v1's aggregate. * fix(agent-core-v2): surface the subagent's bound model on status events The v2 model slice rides only the bind-time agent.status.updated, which precedes subagent.spawned and is dropped by clients that key child events off the spawn, so subagent cards never learned the model — and a single-step run emits no usage/context slice until it ends, so the model only appeared at completion. Re-affirm the binding right after the spawn announcement via a new IAgentProfileService.republishStatus, and fold a consistent usage/context/model snapshot into every status event at both v1 edges (kap-server's broadcaster and the in-process SDK session wiring, resolving the secondary-model derived id to a readable display name. EOF ) * Delete .changeset/subagent-card-model.md Signed-off-by: 7Sageer <sag77r@hotmail.com> * style(agent-core-v2): remove inline implementation comments --------- Signed-off-by: 7Sageer <sag77r@hotmail.com>
* docs: fix dead anchor links in en/zh docs - #loop_control -> #loop-control (heading slug uses hyphens) - #secondary_model -> #secondary-model - env-vars model section anchors: kimi_model -> kimi-model - provider credential section anchors: configtoml -> config-toml - /provider management anchors: point at the renamed heading in each locale - hooks: point the stale config-files#hooks reference at the local Configuration section - en files: replace two leftover Chinese anchors with their English targets * docs: add missing .md extension to themes page links --------- Co-authored-by: qer <wbxl2000@outlook.com>
…odel/agentfile (MoonshotAI#2232) Syncs 30 upstream commits. Upstream MoonshotAI#2232 ported custom agent files + secondary-model binding to the v1 engine, covering the fork's exact-alias subagent model selection (fb6d57c) and subagent model surfacing (353a1c5) — so the fork's v1-side implementation is retired in favor of upstream's: - v1 collision files restored to upstream (agent/agent-swarm tools, subagent-host, tool registry, flags, docs); fork's v1 subagent-model-directory.ts dropped as dead code - TUI subagent model display deduplicated onto upstream's stats placement (agent-group, tool-call); fork's per-row model chip removed - config schema/toml unions keep the fork's disabledSkills alongside upstream's extraAgentDirs - footer quota readout ported onto upstream's slot-based footer (status_line); managed-usage rows adapted to upstream's structured ManagedUsageRow shape (window/name, no label) - node-sdk getSessionWarnings passes pathClass for the fork's AGENTS.md include expansion - state manifest regenerated Fork-unique deltas kept: disabled_skills denylist (PR MoonshotAI#1983 upstream), session-only default model, managed plan quota display, AGENTS.md include expansion, v2-side subagent model selection, misc fixes. Review follow-ups (PR #12): - v1 subagent-host + node-sdk getSessionWarnings: thread agentsMdExpandIncludes through spawned-subagent and warning prompt contexts (with a subagent-host test covering include expansion) - TUI: keep the status-derived subagent model when later events carry no model (subagent-event-handler, tool-call); AgentSwarm header shows a shared model only when all reported members agree (setMemberModel) - kap-server subagentRosterTracker learns the model from agent.status.updated; kimi-web agentEventProjector projects it onto the task - lint: drop useless spread in skillCatalogService; FORK.md + config docs note the v1 exact-alias retirement (v2-only)
zicochaos
force-pushed
the
merge/upstream-2026-07-29
branch
from
July 29, 2026 11:43
b702d5c to
6f7d5de
Compare
Owner
Author
Review follow-ups addressed (6f7d5de)Fixes from the gpt-5.6-sol review, scope: blockers + merge fallout. Blockers
Merge fallout (subagent model propagation)
Housekeeping
Verification
Pre-existing findings not addressed here will be filed as follow-up issues. |
This was referenced Jul 29, 2026
This was referenced Jul 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Upstream shipped the fork's headline feature (subagent/secondary model selection + custom agent files) in MoonshotAI#2232, creating a head-on collision with the fork's own implementation (
fb6d57cd2,353a1c573). 16 of 19 merge conflicts traced to that single upstream commit.Decision
Adopt upstream's implementation (superset: secondary-model binding + custom agent files on v1, with TUI
/secondary_modelcommand and bound-model display in subagent cards). The fork's v1-side exact-alias model selection is retired.What changed
Adopted upstream (collision files restored to upstream versions):
agent/agent-swarmtools,subagent-host, tool registry, flags registry, en/zh docstools/support/subagent-model-directory.tsdropped (dead code); fork tests asserting exact-alias resume semantics removedagent-group.ts,tool-call.ts) — the auto-merge had rendered the model twice per rowFork deltas kept and re-applied onto upstream's new layout:
disabled_skillsdenylist (separately pending as feat(config): add disabled_skills denylist for shared skill directories MoonshotAI/kimi-code#1983) — union with upstream'sextraAgentDirsin config schema/tomlstatus_line, feat(tui): customizable footer status line via status_line config MoonshotAI/kimi-code#2255); adapted to upstream's structuredManagedUsageRowshape (window/name, nolabel, feat(oauth): return structured managed usage rows MoonshotAI/kimi-code#2300)pathClasswiring in node-sdkgetSessionWarnings)state-manifest.d.tsregeneratedLanded for free from upstream: global message search (MoonshotAI#2321), streaming uploads (MoonshotAI#2312), tree-sitter-bash parser (MoonshotAI#2016), customizable footer (MoonshotAI#2255), quota fail-fast (MoonshotAI#1857), repeat-breaker fixes (MoonshotAI#2313/MoonshotAI#2317), oauth structured usage (MoonshotAI#2300), markstream-vue fix (MoonshotAI#2294).
Verification
tsc --noEmitclean: agent-core, agent-core-v2, kap-server, kimi-code-sdk, kimi-code (TUI), kimi-webcoder-subagent-tools.test.ts— fixtures hardcode/bin/bash, absent on NixOS; untouched by this merge)