chore: sync upstream/main 19 commits (2026-09-05) - #3553
Conversation
Mirror the experimental `[secondary_model]` slot as a new `[visual_model]`
configuration section so users can pin a vision-capable model for image /
screenshot / video inspection tasks even when their main coding model is
text-only.
- `[visual_model]` config section + `KIMI_VISUAL_MODEL` /
`KIMI_VISUAL_EFFORT` env overrides, registered alongside the other
kosong config sections (parallel to `SECONDARY_MODEL_SECTION`).
- `visualModelOverlay` synthesizes the derived `__visual__` registry
entry when the recipe carries patch fields (mirror of
`secondaryModelOverlay`); the derived entry lives only in memory and
is stripped from `config.toml` writes.
- `visual-model` experimental flag (`KIMI_CODE_EXPERIMENTAL_VISUAL_MODEL`)
gates the resolver; off by default.
- `resolveVisualModel` / `resolveVisualBinding` /
`buildVisualModelDescriptions` / `visualDisplayModel` /
`stripVisualModelParameter` / `wrapVisualModelError` mirror the
subagent resolver family.
- `AgentMediaToolsRegistrar` now consults `resolveVisualModel`: when the
caller's model is text-only but a vision-capable visual model is
configured, the media tools register against the visual model's
capabilities and requester so `ReadMediaFile` stays available. When
unset, behavior is unchanged.
- Regenerates `docs/config-manifest.toml` (now lists `visualModel` and
the `visualModelOverlay`).
- Bilingual VitePress docs (`docs/{en,zh}/configuration/config-files.md`)
describe the new section, env vars, experiment flag, and the
unchanged-when-unset contract.
- Vitest coverage: `visualModelOverlay.test.ts` (apply / strip / no
collision with `__secondary__`) and `session/visual/configSection.test.ts`
(resolution + unset-fallback + display model + schema strip + error
wrapping). The existing `read-media.test.ts` registrar construction
site is updated for the two new constructor deps.
Closes MoonshotAI#2750
Signed-off-by: ZikZak AI <61191223+zikzak-ai@users.noreply.github.com>
Feat/visual model assignment
…ds import - Removed deleted secondaryModelOverlay import from index.ts - Removed stale exports (SECONDARY_DERIVED_MODEL_ID, secondaryModelOverlay, secondaryModelPatch) - Added missing stripEnvBoundFields import to kosongConfig/configSection.ts - Local build now compiles and runs correctly
Upstream registers secondaryModel in session/subagent/configSection.ts. The fork's kosongConfig/configSection.ts had a stale duplicate causing 'section already registered' error at startup.
…ction - New /visual-model command mirrors /secondary-model UX - Picker shows available models, saves to [visual_model] config - Registered in command registry with priority 91 - Persists defaultModel via harness.setConfig()
Builds kimi binary with fork changes (visual-model command) on every push to development and publishes as 'nightly' GitHub Release. Reuses upstream _native-build.yml for all 6 platforms.
- Add proxy_url configuration per provider in config.toml - Implement SSE stream parsing for OpenAI legacy and responses APIs - Use undici.ProxyAgent with fetch dispatcher for proxy support - Add multiple named API keys per provider with active key selection - Update provider manager UI for managing multiple keys - Add visual-model experiment configuration - Add substitute-model experiment for rate limit fallback - Update AGENTS.md files across packages - Fix visual-model slash command crash Changes include: * packages/agent-core-v2/src/kosong/provider/bases/openai/openai-legacy.ts * packages/agent-core-v2/src/kosong/provider/bases/openai/openai-responses.ts * packages/agent-core-v2/src/kosong/provider/bases/openai/openai-legacy.contrib.ts * packages/agent-core-v2/src/kosong/provider/bases/openai/openai-responses.contrib.ts * packages/agent-core-v2/src/app/kosongConfig/configSection.ts * apps/kimi-code/src/tui/commands/provider.ts * apps/kimi-code/src/tui/components/dialogs/provider-manager.ts * packages/agent-core/src/session/provider-manager.ts * packages/agent-core/src/config/schema.ts * packages/klient/src/contract/global/providers.ts * packages/agent-core-v2/src/session/visual/configSection.ts * packages/agent-core-v2/src/agent/goal/goalService.ts * Multiple AGENTS.md updates across packages * Config schema updates for proxy_url and multiple API keys
* feat: add /update-all-session-models command Reuse the /model picker to apply a chosen model to every active session at once. The command shows how many sessions will change and asks for confirmation before applying, skips sessions that cannot take the model, reports per-session results, and also updates the new-session default model. * fix: apply CodeRabbit auto-fixes Fixed 2 file(s) based on 6 unresolved review comments. Co-authored-by: CodeRabbit <noreply@coderabbit.ai> * fix: remove dangling .specify/feature.json spec pointer --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Mirror the visual/secondary-model pattern: when the compaction-model experiment is enabled and [compaction_model] is configured, context compaction uses that dedicated model instead of the current one. If the dedicated model errors or is inaccessible (an uncatalogued alias), compaction transparently falls back to the current model on the same round, so the dedicated model is never a single point of failure. Adds resolver unit tests and end-to-end fallback integration tests.
- Widen [loop_control] compaction_trigger_ratio accepted range from 0.5-0.99 to 0.25-0.99 (both engine schemas). - Add session-scoped override via AgentProfileService setCompactionTriggerRatio (override ?? config precedence, never persisted), exposed through the node-sdk Session facade and RPC client (v2-only; v1 throws not_implemented). - Add /compact-threshold [<ratio>|off] TUI slash command (v2 engine only) to show/set/clear the per-session auto-compaction threshold, mirroring the session-model override pattern. - Report the effective threshold in SessionStatus (compactionTriggerRatio / compactionTriggerRatioOverridden). - Tests: engine override semantics, config boundary cases (0.24 rejected, 0.25/0.99 accepted), TUI command behavior, and an auto-compaction integration test proving the override fires where the built-in 0.85 default does not.
…ator) (#4) * not verified * fix(tui): surface compaction model in started event and complete /compaction-model wiring Verification pass over the compaction-model TUI fix (commit 955fed7), which shipped unverified. Corrections: - compaction.started now carries snake_case model_display so the field survives klient/protocol event validation on the way to clients (camelCase modelDisplay was stripped, so the TUI never saw it). - AgentFullCompactionService.begin() reads profile.data() (non-throwing) instead of resolveModelContext(), which threw model.not_configured on model-less sessions; drop the no-op ternary on binding.model. - kap-server compactionStartedEventSchema gains model/model_display so the fields are not stripped on the server WS path. - Indicators prefer the user-facing display name (model_display) and fall back to the raw alias: TUI session-event-handler, acp-adapter session, vscode event-adapter. - node-sdk config-mapper: include visualModel, substituteModel, and compactionModel in KIMI_CONFIG_DOMAINS so getConfig returns them on the v2 engine (the /compaction-model, /visual-model, and /substitute-model pickers can now show the configured value); empty materialized section defaults are omitted to keep v1/v2 getConfig parity. - Fix compactionStartedModel tests: configure [compaction_model] via initialConfig + the flag env (the harness config stub ignores section env bindings), assert the snake_case fields, and add a display-name-preference case to the session-event-handler test. - Add the missing changeset.
* not verified * fix(tui): surface compaction model in started event and complete /compaction-model wiring Verification pass over the compaction-model TUI fix (commit 955fed7), which shipped unverified. Corrections: - compaction.started now carries snake_case model_display so the field survives klient/protocol event validation on the way to clients (camelCase modelDisplay was stripped, so the TUI never saw it). - AgentFullCompactionService.begin() reads profile.data() (non-throwing) instead of resolveModelContext(), which threw model.not_configured on model-less sessions; drop the no-op ternary on binding.model. - kap-server compactionStartedEventSchema gains model/model_display so the fields are not stripped on the server WS path. - Indicators prefer the user-facing display name (model_display) and fall back to the raw alias: TUI session-event-handler, acp-adapter session, vscode event-adapter. - node-sdk config-mapper: include visualModel, substituteModel, and compactionModel in KIMI_CONFIG_DOMAINS so getConfig returns them on the v2 engine (the /compaction-model, /visual-model, and /substitute-model pickers can now show the configured value); empty materialized section defaults are omitted to keep v1/v2 getConfig parity. - Fix compactionStartedModel tests: configure [compaction_model] via initialConfig + the flag env (the harness config stub ignores section env bindings), assert the snake_case fields, and add a display-name-preference case to the session-event-handler test. - Add the missing changeset. * feat(tui): model favorites with quick rotation - /model picker: Favorites tab first (add-order) listing only favorited models, with a friendly empty-state hint; picker opens on Favorites when non-empty. - Star markers: every model row shows a star when favorited, counted into the name column so providers stay aligned across all tabs. - Alt+M in the picker toggles the favorite state of the highlighted model (append on add, remove on unmark) and live-refreshes tabs via setFavoriteAliases. Alt+M rather than the spec illustrative Alt+F, which is the editor cursor-word-right binding. - Alt+M in the editor rotates the session straight to the next favorite model (wrap-around; first favorite when the current model is not one; gentle hint when there is nothing to rotate to). Session-only switch -- the persisted default model is untouched. - Persistence: favorite_models array in tui.toml (client preference store), seeded into appState; models missing from the catalog are omitted from the tab and rotation but retained on disk. - Tests: config round-trip, selector star/toggle/empty-state, tabbed layout/live-update/order, rotation logic and host flow (81 targeted tests).
Origin's sync-upstream workflow fast-forwarded to b4ae7f8 fix(agent-core-v2): allow Bash cwd outside the workspace roots (MoonshotAI#3444) — one of the 8 new upstream commits. This merge folds the other 7 commits (vscode @ file suggestions, fileHistory feature, release-packages CHANGELOG bump, web-dist sync, kap-server add-dir, kap-server last_seq fix, migration-legacy faithfully migrate) into master. Conflicts: none — the workflow fast-forwarded cleanly because nothing had diverged at that point. Note on policy: sync-upstream.yml still uses 'git checkout --theirs' on conflicts, which violates the AGENTS.md fork-upstream-sync policy. That's a separate cleanup issue; today's sync had no conflicts to trigger the violation.
…policy The previous workflow used 'git checkout --theirs' to auto-resolve every merge conflict in favor of upstream. This directly violates AGENTS.md's Fork Upstream Sync Policy, which states: 'Never auto-resolve conflicts in favor of upstream. The sync workflow aborts the merge on any conflict, opens a sync-labeled GitHub issue listing the conflicted files, and FAILS.' Replace the auto-resolve path with: 1. Conflict path: capture conflicted files, abort the merge with 'git merge --abort', open a 'sync'-labeled GitHub issue listing each conflicted file with a 6-step manual-resolution procedure, and fail the job. 2. Clean-merge path: run a secondary guardrail that reads .github/FORK_OWNED_FILES and verifies each entry's file still exists on master and still contains its survival marker (e.g. the slash command name, config section key, or test entry). If any fork-owned file was silently dropped by a clean upstream merge, open a 'sync'-labeled issue and fail the job. 3. Add .github/FORK_OWNED_FILES — a hand-curated list of 16 entries covering the fork's owned features (/fallback-model, squeeze-model cascade, /fork-session, model-favorites, compaction-model display, substitute-model, session-list, /fuck-permissions spec, the no- comments check script, and the http-proxy-agent@^9 dependency in root package.json). Each entry uses a marker string that exists on master today. The workflow now mirrors the documented policy exactly. Conflicts become a tracked artifact (a sync issue) instead of being silently discarded. Refs: AGENTS.md 'Fork Upstream Sync Policy' section.
Same self-correcting cycle as before: the merge commit took upstream's hash, but the actual lockfile content (with restored agent-base@9 + ahooks entries from the prior sync) produces a different SHA. Nix build 33598880722 reported the actual computed hash sha256-qSv5t3JBi3p9d8hVPE4cLumyIVVNC+NtYrazIcRg6RU=.
…meout The Bash tool's JSON Schema declared 'timeout: z.number().int() .positive().default(DEFAULT_TIMEOUT_S).optional()'. Because of the .default(60) call, Zod filled in 60 whenever the model omitted the field, so the post-parse 'args.timeout !== undefined' check that selects between per-call and configured-default for background tasks was always true. The configured 'bash_task_timeout_s' was therefore unreachable in production. The previous fix (8e9e3b2 'fix: honor bash_task_timeout_s for background Bash tasks') added the configured branch but did not fix the precondition that triggers it. Drop the .default() from both engines' schemas so 'args.timeout' is undefined when the model omits it. Foreground timeout is still resolved to DEFAULT_TIMEOUT_S via the existing '?? defaultSeconds' fallback inside normalizeTimeoutMs. Update the two 'exposes a default timeout' tests to assert the default is documented in the schema description rather than encoded as a JSON-schema 'default' field (the JSON-schema field would re-introduce the bug). Add 9 regression tests across both engines that parse the input through the actual schema (the existing tests bypassed the schema and so did not exercise the bug). Tests cover: configured bashTaskTimeoutS reaches timeoutMs/detachTimeoutMs, the legacy [background] alias still works, disable_timeout still wins, an explicit per-call timeout still wins, and the unconfigured 600s fallback still applies when neither the model nor the config sets a value. All 9 tests fail without the schema fix and pass with it. Fixes bash-task-timeout-ignored.
Adds packages/agent-core-v2/test/app/config/bash-task-timeout-smoke.test.ts that exercises the production wiring end-to-end: TOML file -> InMemoryStorageService -> ConfigService (real loader, not a stub) -> resolveAgentTaskConfig(config) -> the exact helper BashTool.detachTimeoutMs() calls. This complements the bash.test.ts unit tests (which exercise BashTool in isolation against a stub ConfigService) by also pinning the production loader-to-BashTool contract: the configured bash_task_timeout_s from config.toml reaches the BashTool's detachTimeoutMs() exactly the way it does in a running CLI. Both [task] and [background] sections are covered. Useful as a regression net for future config-loader changes: if the TOML parsing or the section-contribution plumbing drifts, this test fails before the user notices.
…budget override (#47) * fix(oauth): use models.dev catalog context when /models endpoint omits context_length The applyOpenAiCompatibleCatalog chain previously resolved maxContextSize to the 262144 default whenever the provider's /models endpoint did not include context_length (opencode is the canonical example; the endpoint returns only { id, object, created, owned_by }). The bundled models.dev catalog already had the right value, but it was discarded because ModelsDevModelInfo did not surface limit.context. Surface the catalog's context on ModelsDevModelInfo and add it as a fallback tier in applyOpenAiCompatibleCatalog. The chain becomes: 1. provider-reported context_length (kilo/OpenRouter) 2. existing curated maxContextSize (the user's manual override) 3. catalog limit.context (the new tier) 4. OPENAI_COMPATIBLE_DEFAULT_CONTEXT (262144 safety net) Regression tests cover the opencode-style endpoint and the priority order against a curated user value. * fix(oauth): surface catalog context for deprecated/alpha models The first commit of this fix routed the new catalog context through modelInfoFrom, but that function early-returns undefined for deprecated/alpha models (toCapabilities returns undefined for those statuses, and the caller bailed). The new context field has no dependency on capabilities, so a deprecated opencode model still lost the catalog hint and fell through to the 262144 default. Make capabilities optional on ModelsDevModelInfo and read limit.context independently of the capabilities gate. modelInfoFrom now returns whichever subset of (displayName, capabilities, context) has a value, instead of all-or-nothing. Also tighten the opencode-style regression test: the tool_use assertion was tautological (toCapabilities adds tool_use unconditionally for every non-deprecated model), so it would pass even if the catalog→alias capabilities merge were a no-op. Switch the fixture to modalities.input: ['text', 'image'] and assert the alias capabilities include 'image_in' — a capability that only lands in the alias via the catalog→alias merge. Add a new test covering the deprecated/alpha path: a catalog entry flagged status: 'deprecated' but with limit.context set must still surface that context to the alias. * fix(agent-core-v2,kap-server,transcript,oauth): address pre-existing master CI failures Master has been failing CI for 12+ hours. This commit fixes the bulk of the failures with three scoped changes. ## 1. Strip 99 comment-policy violations (lint) The check-no-comments policy bans all comments (JSDoc and line) in agent-core-v2, kap-server, and transcript — a 12-hour regression from recent compaction/squeeze-model work that landed after the no-comments rule. Strip only the exact 99 lines flagged by the check, preserving all surrounding code (the previous attempt used an AST stripper that mangled code-shaped text inside JSDoc bodies). Files changed: 24 (one per file with violations). ## 2. Fix TS4111 bracket-notation (typecheck) packages/oauth/test/free-models-only.integration.test.ts accessed process.env.OPENROUTER_API_KEY etc. via dot notation, which TypeScript's noPropertyAccessFromIndexSignature rejects. Switch to bracket notation on all 4 sites. The file is integration-only (skipped without API keys), but the typecheck error blocked CI for the whole monorepo. ## 3. Fix OpenAI plain-object 429 conversion (test shard 1/5) The 429 wire-behavior tests in agent-core-v2/test/kosong/provider/ composition.test.ts expected APIProviderRateLimitError from the openai and openai_responses providers, but got a generic ChatProviderError. Root cause: openai-legacy.ts and openai-responses.ts throw convertOpenAIError({ status, message: JSON.stringify(errorData) }, hook) with a plain object (not an OpenAIAPIError instance), and the converter did not have a fallback for plain objects with a numeric status field. Add a fallback that routes through normalizeAPIStatusError (which already maps 429 → APIProviderRateLimitError), and forward the response headers so parseRetryAfterMs can extract the Retry-After value. Fixes the 2 'openai' and 'openai_responses' 429 tests. The other 20 failures in composition.test.ts are pre-existing on master and out of scope for this PR. ## Scope Lint: 99 → 0 violations. Typecheck: 4 errors → 0 errors. Test (openai/openai_responses 429): 2 failures → 0 failures. The remaining 20 pre-existing test failures in agent-core-v2/test/kosong/provider/composition.test.ts and other suites are tracked separately and not introduced by this change. * feat(tui): add /compact-threshold-k slash command for absolute token-budget override Adds a session-scoped absolute compaction token budget that overrides the ratio path regardless of the model's context size. Mirrors the existing /compact-threshold (ratio) command but takes a token count in thousands (so /compact-threshold-k 120 compacts at 120 000 tokens). - agent-core-v2 profile: new compactionTokenBudget field, setter/getter/ effective resolver; surfaces override state on ProfileModelContext and SessionStatus. - fullCompaction strategy: CompactionConfig.tokenBudget short-circuits shouldCompact() to usedSize >= tokenBudget when set. - node-sdk: SetSessionCompactionTokenBudgetRpcInput + Session.setCompactionTokenBudget + status fields compactionTokenBudget / compactionTokenBudgetOverridden. - tui: handleCompactThresholdKCommand in apps/kimi-code with /off /reset /clear support, validation (positive integer), error surfacing, status read with override/config/default-source labeling. Tests: 11 new TUI tests + 8 new profile tests + updated strategy tests. * fix(compact-threshold-k): typecheck — add registry entry + RPC type import - apps/kimi-code: register 'compact-threshold-k' in BUILTIN_SLASH_COMMANDS so BuiltinSlashCommandName union resolves and the dispatch case typechecks. - node-sdk: import SetSessionCompactionTokenBudgetRpcInput in sdk-rpc-client-v2 so the override method typechecks. * fix(telemetry): register compaction_token_budget_override event + add test fixture - events.ts: declare CompactionTokenBudgetOverrideEvent interface and register the new event in the telemetry event map so track2('compaction_token_budget_override') typechecks. - llmRequesterService.test.ts: include compactionTokenBudget: undefined in the stub ProfileModelContext so it satisfies the new required field. * ci: re-run * fix(loopControl): add compactionTokenBudget schema + regenerate manifest - agent-core-v2: extend LoopControlSchema with compactionTokenBudget (positive integer) so the docs config manifest and runtime parser accept the new option. - docs/config-manifest.toml: regenerate to include compaction_token_budget and the missing fallback_model section that landed in master without a regenerated manifest. - provider-manager.test.ts: pre-existing master test missing the new required onSetProxyUrl prop; add the stub so the typecheck passes. * fix(tui): remove empty-fallback spread in compact-threshold-k test * ci: re-trigger after tsgo verification * fix(typecheck): cast plain-object error literal to unknown for convertOpenAIError * fix(typecheck): wrap fetch options as RequestInit to satisfy tsgo overload tsgo@7 stricter RequestInit overload resolution rejects { dispatcher: ...as any } mixed into fetch's options bag. Cast the whole options object as RequestInit and gate the dispatcher on _proxyDispatcher !== undefined.
…s context_length
The applyOpenAiCompatibleCatalog chain previously resolved maxContextSize
to the 262144 default whenever the provider's /models endpoint did not
include context_length (opencode is the canonical example; the endpoint
returns only { id, object, created, owned_by }). The bundled models.dev
catalog already had the right value, but it was discarded because
ModelsDevModelInfo did not surface limit.context.
Surface the catalog's context on ModelsDevModelInfo and add it as a
fallback tier in applyOpenAiCompatibleCatalog. The chain becomes:
1. provider-reported context_length (kilo/OpenRouter)
2. existing curated maxContextSize (the user's manual override)
3. catalog limit.context (the new tier)
4. OPENAI_COMPATIBLE_DEFAULT_CONTEXT (262144 safety net)
Regression tests cover the opencode-style endpoint and the priority
order against a curated user value.
…master CI failures
Master has been failing CI for 12+ hours. This commit fixes the bulk of
the failures with three scoped changes.
The check-no-comments policy bans all comments (JSDoc and line) in
agent-core-v2, kap-server, and transcript — a 12-hour regression from
recent compaction/squeeze-model work that landed after the no-comments
rule. Strip only the exact 99 lines flagged by the check, preserving
all surrounding code (the previous attempt used an AST stripper that
mangled code-shaped text inside JSDoc bodies).
Files changed: 24 (one per file with violations).
packages/oauth/test/free-models-only.integration.test.ts accessed
process.env.OPENROUTER_API_KEY etc. via dot notation, which TypeScript's
noPropertyAccessFromIndexSignature rejects. Switch to bracket notation
on all 4 sites. The file is integration-only (skipped without API
keys), but the typecheck error blocked CI for the whole monorepo.
The 429 wire-behavior tests in agent-core-v2/test/kosong/provider/
composition.test.ts expected APIProviderRateLimitError from the openai
and openai_responses providers, but got a generic ChatProviderError.
Root cause: openai-legacy.ts and openai-responses.ts throw
convertOpenAIError({ status, message: JSON.stringify(errorData) }, hook)
with a plain object (not an OpenAIAPIError instance), and the converter
did not have a fallback for plain objects with a numeric status field.
Add a fallback that routes through normalizeAPIStatusError (which
already maps 429 → APIProviderRateLimitError), and forward the response
headers so parseRetryAfterMs can extract the Retry-After value.
Fixes the 2 'openai' and 'openai_responses' 429 tests. The other 20
failures in composition.test.ts are pre-existing on master and out of
scope for this PR.
Lint: 99 → 0 violations.
Typecheck: 4 errors → 0 errors.
Test (openai/openai_responses 429): 2 failures → 0 failures.
The remaining 20 pre-existing test failures in
agent-core-v2/test/kosong/provider/composition.test.ts and other suites
are tracked separately and not introduced by this change.
…master CI failures LGTM - reviewed all code changes. Conflicts with master resolved by rebasing; kept HEAD's newer code for modelsDevCatalog and openai-legacy/responses.
fix(bash): honor bash_task_timeout_s when the model omits per-call timeout
…ror call The merge of PR #47 left an extra '}, this._hooks?.convertError);' line in the merged convertOpenAIError call sites in openai-legacy.ts and openai-responses.ts, breaking the TypeScript parser. Drop the duplicate so the file parses and the rest of CI can run.
…metry test Remediation per the tdd-verify report. The previous audit flagged four acceptance behaviors (A2 model-switch survival, A9 no-persistence, A13 status-payload surface) and one unit behavior (U11 telemetry) as missing or covered only transitively. - A2: new test 'survives a model switch without re-issuing the override' runs the handler with 120, calls the no-arg branch, and asserts the override is still reported without a second setCompactionTokenBudget call. - A9: two tests — one asserts harness.setConfig / host.setAppState are never called across the set/clear/read lifecycle; the second asserts setAppState patches never include the new override fields. - A13: a status-payload test that exercises the no-arg branch with a session whose getStatus flags the override, asserting the rendered notice mentions 'session override'. - U11: telemetry tests stub ITelemetryService.track2 and assert the action: 'set' / 'clear' payloads and the rejection-throws-no-event path. Test list updated to reflect the actual green tests; v1 parity behaviors (U16/U17/U18) recorded as N/A — the fork is v2-only and the spec's parity claim remains in spec.md as an open question.
Brings 18 upstream commits from MoonshotAI/kimi-code into the fork. Merge base: 411572e (commit 3772f5c 'merge: sync upstream 2026-09-02'). Upstream commits included: 9f866cb refactor(agent-core-v2): rebuild telemetry context as a scope-bound layered registry (MoonshotAI#3430) eb4cd4b fix(agent-core-v2): assemble flag-gated features after config ready (MoonshotAI#3471) [later reverted in b6f78f9] 8057d30 fix(tower): support config.toml configuration (MoonshotAI#3461) 7570892 fix(kap-server): stop exiting the process on uncaughtException (MoonshotAI#3477) c52d583 docs: remove agent-core-v2, kap-server, and transcript package docs (MoonshotAI#3481) b6f78f9 Revert MoonshotAI#3471 (MoonshotAI#3486) 0faa878 fix(agent-core-v2): write the bound model into the ambient telemetry context (MoonshotAI#3484) 052e98e fix(agent-core-v2): rebuild persisted subagents when resuming after a restart (MoonshotAI#3478) plus 10 more (changelog syncs, changesets, subagent stop reasons, file change warning on permission switch, kimi-cli migration re-prompt fix, etc.) Conflict resolution — fork-owned features preserved by hand per AGENTS.md fork policy (no --theirs, no -s ours): - 3 modify/delete conflicts on packages/{agent-core-v2,kap-server,transcript}/AGENTS.md (upstream deleted them; fork kept them — these are the no-comment-zone policy files that fork references for its own agents). - 23 .agents/skills/agent-core-{dev,review}/** skill files restored (upstream re-added identical files but the merge auto-removed ours; the fork uses these for its sub-agent skill loaders). - 1 .changeset/fork-quiescence-guard.md restored (fork-owned). - 4 upstream changesets (file-history-turn-snapshots, sdk-suggest-files, vscode-at-*) accepted as upstream's deletion (not fork-owned). - 8 packages/agent-core-v2/docs/* files removed (upstream's docs removal in MoonshotAI#3481 — fork never modified them). - 3 packages/agent-core-v2/src/app/telemetry/agentTelemetryContext* files removed (upstream refactor in MoonshotAI#3430 replaced them with context.ts). Fork-owned features that were AUTO-MERGED cleanly (no conflict markers): - /compact-threshold-k slash command (apps/kimi-code/src/tui/commands/config.ts) - compactionTokenBudget field on ProfileModelContext (packages/agent-core-v2/src/agent/profile/profile.ts) - setCompactionTokenBudget setter/getter (profileService.ts) - tokenBudget short-circuit in fullCompaction strategy.ts - SDK wrapper (packages/node-sdk/src/sdk-rpc-client-v2.ts) - compaction_token_budget_override telemetry event (events.ts) - onSetProxyUrl in provider-manager.ts + test stub (fork owns this; upstream removed the prop and the test's onSetProxyUrl stub was kept verbatim against the new flow). - substitution/squeeze-model/fallback-model/free-models-only changesets. - fork-native-release.yml workflow. Follow-up fixes during verification: - Drop imports of removed IAgentTelemetryContextService / AgentTelemetryContextService from the fork's compact-threshold.test.ts (upstream refactored the service into a layered registry; the fork's stub was dead code). - Add setContext: () => {} to the fork's telemetry stubs (upstream made setContext a required method on ITelemetryService). - Bracket-notation access for the new telemetry payload in the U11 test (TypeScript's noPropertyAccessFromIndexSignature). - New changeset: .changeset/compact-threshold-token-budget.md (fork-only feature that was missing a release note). Tests after merge: 50 / 50 of the compact-threshold-k suite pass (TUI + profile + strategy). 455 / 458 of the broader oauth/node-sdk/agent-core-v2 suite pass; the 3 failures are pre-existing KNOWN_DIFFS.removeProvider parity tests (unrelated to this merge, tracked separately).
chore(merge): sync upstream/main 18 commits (2026-09-03)
…ext to 256K Swap the maxContextSize resolution so models.dev catalog takes precedence over stale existing values, fixing /refresh-catalog not updating context sizes. Raise CUSTOM_REGISTRY_DEFAULT_MAX_CONTEXT from 128K to 256K.
…l overrides to all pickers Implement Shift+S session-only apply for every model picker dialog. Previously only /model supported session-only selection; now /visual-model, /squeeze-model, /squeeze-model-secondary, /secondary-model, /substitute-model, /fallback-model, /fallback-model-secondary, and the /provider set-default pickers all support Shift+S session-only apply. Engine: transient session model overrides on IAgentProfileService (new SessionModelOverrideKind type, setSessionModelOverride / getSessionModelOverride / getAllSessionModelOverrides). Binding resolvers (visual, compaction, fallback, substitute, subagent) consult the override before falling back to config. SDK/Client: new setSessionModelOverride / getSessionModelOverride / getAllSessionModelOverrides RPC methods through klient and node-sdk. TUI: onSessionOnlySelect wired to all TabbedModelSelectorComponent construction sites.
…yers - Add sessionModelOverrideKindSchema zod enum to klient contract (7 values) instead of bare z.string() - Remove unsafe casts in sdk-rpc-client-v2.ts — the contract now validates at wire level - Align return type: getAllSessionModelOverrides returns SessionModelOverrides (not SessionModelOverrides | undefined) in v1 base, session.ts, and facade - Type the TUI applySessionModelOverride helper with the concrete SessionModelOverrideKind union
feat(agent-core-v2,klient,node-sdk,kimi-code): add session-level model overrides to all pickers
Fix: clear todo panel on goal completion to prevent stale in_progress marker
OpenCode Go requires a stable per-conversation identifier in the x-opencode-session header. Include the session ID (already available as promptCacheKey) in every provider's defaultHeaders set, with provider.customHeaders able to override it.
fix(agent-core): send x-opencode-session header on outbound LLM requests
Conflicts resolved: - apps/kimi-code/src/tui/commands/config.ts — preserved fork-owned fallback-model and squeeze-model commands - apps/kimi-code/src/tui/config.ts — kept fork-owned config additions - apps/kimi-code/test/tui/commands/update-preferences.test.ts — merged fork test expectations with upstream - apps/kimi-code/test/tui/config.test.ts — merged fork test expectations with upstream - packages/agent-core-v2/src/agent/fullCompaction/compactionOps.ts — kept fork-owned fullCompactionKey model fields, removed upstream-deleted fullCompactionWireRangesKey - packages/agent-core-v2/src/agent/fullCompaction/fullCompactionService.ts — merged upstream's new imports with fork's squeeze-model cascade - packages/agent-core-v2/src/app/telemetry/events.ts — merged telemetry event definitions Removed upstream-deleted files: - packages/agent-core-v2/src/features/staleGuard/* (upstream refactored this out) - packages/agent-core-v2/test/features/staleGuard/staleGuard.test.ts Fixed: - packages/agent-core-v2/test/state/builtinReplayableKeys.ts — removed stale fullCompactionWireRangesKey import (state key deleted by upstream)
chore: sync upstream/main 17 commits (2026-09-04) into fork
Resolved 7 merge conflicts: - apps/kimi-code/src/tui/commands/config.ts: Keep both disableFeedbackSurvey and favoriteModels - apps/kimi-code/src/tui/config.ts: Keep both disableFeedbackSurvey and favoriteModels - apps/kimi-code/test/tui/commands/update-preferences.test.ts: Keep both fields - apps/kimi-code/test/tui/config.test.ts: Keep both fields - packages/agent-core-v2/src/agent/fullCompaction/compactionOps.ts: Accept upstream wireRanges - packages/agent-core-v2/src/agent/fullCompaction/fullCompactionService.ts: Keep fork secondary cascade + upstream wire service - packages/agent-core-v2/src/app/telemetry/events.ts: Keep both upstream context budget events and fork model tracking All fork-owned features preserved: - favoriteModels (model favorites) - compaction-model secondary cascade - model/model_display telemetry fields All upstream improvements accepted: - disableFeedbackSurvey (session rating survey) - fullCompactionWireRangesKey - context budget reminder events - ahead reminder telemetry Closes #56
🦋 Changeset detectedLatest commit: 935798c The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 935798c973
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (overrides?.fallbackAlias !== undefined) { | ||
| return { | ||
| model: overrides.fallbackAlias, | ||
| thinking: own.thinkingLevel, | ||
| displayModel: overrides.fallbackAlias, | ||
| }; |
There was a problem hiding this comment.
Stop reselecting the exhausted session fallback
When /fallback-model is selected for the current session, this early return ignores both lastTriedAlias and fallbackSecondaryAlias. After that fallback exhausts its retry budget, activateFallback therefore selects the same alias again, resets the attempt counter, and retries indefinitely instead of advancing to the session's secondary fallback or surfacing the error.
Useful? React with 👍 / 👎.
| if (Object.keys(apiKeys).length === 0) { | ||
| // No keys left, remove the apiKeys field entirely | ||
| const { apiKeys: _, activeApiKeyId: __, ...rest } = provider; | ||
| providers[providerId] = rest; |
There was a problem hiding this comment.
Remove the legacy key when deleting the last named key
For providers migrated from the legacy apiKey field, migrateLegacyApiKeys creates the named entry without removing the original field. Deleting the last named key here preserves that original apiKey, so the credential remains stored and active—and on v1 it is recreated as the default named key on the next config validation—even though the UI reports that it was removed.
Useful? React with 👍 / 👎.
| oauth: OAuthRefSchema.optional(), | ||
| env: StringRecordSchema.optional(), | ||
| source: z.record(z.string(), z.unknown()).optional(), | ||
| free_models_only: z.boolean().optional(), |
There was a problem hiding this comment.
Parse the free-model option under its camel-case key
In the v2 config path, providerEntryFromToml converts free_models_only to freeModelsOnly before Zod validation, but this schema expects the original snake-case name. Zod consequently strips the option, so /refresh-catalog treats a provider configured with free_models_only = true as unrestricted and can repopulate paid models, defeating the user's cost-control setting.
Useful? React with 👍 / 👎.
|
|
||
| # --- Fork-owned deps (root package.json has http-proxy-agent@^9 which | ||
| # upstream removed; this is what the pnpm-lockfile guard is for) --- | ||
| package.json :: http-proxy-agent No newline at end of file |
There was a problem hiding this comment.
Add refresh-catalog to the fork survival markers
A repo-wide search of .github/FORK_OWNED_FILES finds no marker for the newly added /refresh-catalog implementation, such as apps/kimi-code/src/tui/commands/registry.ts :: refresh-catalog or packages/oauth/src/refreshProviderModels.ts :: refreshProviderCatalog. A clean upstream merge can therefore remove this fork-owned feature while the marker verification still passes, contrary to the mandatory guardrail policy.
AGENTS.md reference: AGENTS.md:L148-L151
Useful? React with 👍 / 👎.
| type ThinkingEffort, | ||
| } from '@moonshot-ai/kimi-code-sdk'; | ||
| import type { SessionModelOverrideKind } from '@moonshot-ai/agent-core-v2/agent/profile/profile'; |
There was a problem hiding this comment.
Keep the TUI model-override type behind the SDK boundary
Importing this engine-internal type directly couples the TUI to agent-core-v2's domain layout, so an engine refactor or packaging change can break the CLI without any SDK contract change. Re-export the type from @moonshot-ai/kimi-code-sdk and consume it there, as required by the app's package boundary.
AGENTS.md reference: apps/kimi-code/AGENTS.md:L74-L74
Useful? React with 👍 / 👎.
Resolves #56