Skip to content

feat(v2): land agent-core-v2 engine and kap-server behind experimental flag#1441

Open
sailist wants to merge 408 commits into
mainfrom
kimi-code-v2
Open

feat(v2): land agent-core-v2 engine and kap-server behind experimental flag#1441
sailist wants to merge 408 commits into
mainfrom
kimi-code-v2

Conversation

@sailist

@sailist sailist commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

N/A — integration PR that lands the long-lived kimi-code-v2 branch; see Problem below.

Problem

The v2 line — the DI × Scope based agent-core-v2 engine, the kap-server that hosts it, and the minidb read model — has been built up on the long-lived kimi-code-v2 integration branch. This PR merges that branch into main.

The v2 engine and server are not the default runtime yet. Both the kimi -p prompt path and kimi server run route to v2 only when KIMI_CODE_EXPERIMENTAL_FLAG is set, and the v2 module graph is lazy-imported so it stays off the default path. With the flag unset, the CLI keeps the v1 engine and @moonshot-ai/server.

What changed

Scope: 1,207 files, +192,653 / −285. The bulk is three new packages; everything else is CLI wiring, e2e coverage, skills, and small v1 touch-ups.

1. agent-core-v2: the new DI × Scope engine (packages/agent-core-v2, +146k, 872 files)

  • New agent-core-v2 package: a DI scope engine with an explicit agent / session lifecycle.
  • Wire/op state engine with derived wire models and ReplayTimelineModel; IEventBus and Op.toEvent alongside wire.signal; context writes routed through ops and declared tool delivery.
  • Per-agent wire records (wire.jsonl); flattened agent hierarchy with swarm lifted to session.
  • Execution environment reorganized into separate filesystem / process / tool domains.
  • Goal mode: core goal workflow, budget enforcement, and per-turn goal injection.
  • Model layer: Model god-object and protocol domains; kosong vendored as the internal llmProtocol/kosong implementation (drops the @moonshot-ai/kosong and @moonshot-ai/kaos dependencies).
  • Built-in tools registered via DI / contributions, plugin management, session subagent host + Agent tool, shared rg locator/runner, AGENTS.md hierarchy loading.

2. kap-server: the v2 server (packages/kap-server, +26k, 139 files)

  • New @moonshot-ai/kap-server package — the Kimi Code server backed by agent-core-v2 (codenamed "server-v2").
  • Hosts agent-core-v2 sessions over REST (/api/v1, ~25 route modules) and WebSocket (/api/v1/ws with seq/epoch watermark and resync), and serves the web assets.
  • Auth and request-security hardening, /openapi.json via @fastify/swagger, and v2 session export (diagnostic zip archives).
  • v1 parity fixes carried along: broadcast interaction question / approval events, honor the before_id pagination cursor, treat loopback origins as same-origin for WS upgrade, and align MCP media output with v1.

3. minidb: embedded read model (packages/minidb, +13k, 77 files)

  • New @moonshot-ai/minidb package — a pure-Node.js embedded KV database (Redis-style in-memory KV with SQLite-style WAL/snapshot persistence, secondary indexes, TTL), used as the session-index read model.

4. CLI wiring (apps/kimi-code, +762, 19 files)

  • kimi -p and kimi server run select v2 vs. v1 via KIMI_CODE_EXPERIMENTAL_FLAG (lazy import); v1 stays the default.
  • Add the v2 harness adapters (cli/v2/*) and the prompt-session abstraction shared by both engines; update TUI adapters to handle v2 events.

5. Tooling, e2e and docs

  • packages/server-e2e: typed v2 ServerClient SDK with a drift test and e2e coverage.
  • .agents/skills: add the agent-core-dev and write-tests skills plus other skill updates; add the dependency-graph dev viewer.
  • GOAL.md: design doc for the goal-mode feature split.
  • Minor: packages/protocol, packages/acp-adapter, packages/agent-core, packages/server, packages/node-sdk, apps/kimi-web, the hash-imports build loaders, flake.nix, and changesets.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

sailist and others added 30 commits July 1, 2026 20:25
- remove SubAgentHost / ISessionSubagentHost; a subagent is now a plain
  agent scope created via IAgentLifecycleService and driven through the
  child agent's own turn/loop services
- add IAgentLifecycleService.fork(parentAgentId); startBtw forks main
- move the Agent collaboration tool into the new agentTool domain
  (stateless runChildAgent helpers, no runner class, no subagent service)
- move SubagentBatch + runChildAgentQueued into the swarm domain
- seed IAgentScopeContext (agentId) per agent so the Agent tool and swarm
  can name themselves as the parent
- Inline SessionCronStore, CronScheduler, and CronPersistence into
  AgentCronService: state lives as private fields, the poll loop uses a
  shared timer, and persistence calls IAtomicDocumentStore directly.
- Drop CronToolManager; the cron tools take IAgentCronService directly,
  matching the background domain.
- Add a generic IntervalTimer to _base/utils and use it for the poll loop.
- Move cron-expr/jitter/clock to the cron root, merge time-format and
  cron-fire-xml into format.ts, and fold the cron types and telemetry
  constants into the contract and service.
Replace the god-object `IKaos` interface and the `@moonshot-ai/kaos`
package dependency with atomic services:

- `IHostEnvironment` (App scope) — memoised OS / shell / path-style /
  home probe; sync fields plus a `ready` promise the composition root
  awaits before seeding Session scopes.
- `IExecContext` (Session scope) — immutable cwd + env-layers seed
  value with `withCwd` / `withEnv` derivations; replaces
  `IKaos.cwd/withCwd/withEnv` and `IKaosFactory`.
- `ISessionAgentFileSystem` / `ISessionProcessRunner` — inline
  `node:fs/promises` and `child_process.spawn` directly; the
  `IKaos.backend` leak that let `profile/context.ts`, `fileTools/glob`
  and `agentFs/runRg` reach around the facades is gone.

Vendor the pure helpers into `src/_base/execEnv/` (`BufferedReadable`,
`decodeTextWithErrors`, `globPatternToRegex`, host-environment probe).
`src/app/kaos/` and `test/kaos/` are deleted; session-lifecycle awaits
`hostEnv.ready` and then seeds `IExecContext` into the child scope.

Rewrites every `@IKaos` consumer:
- `shellTools/bash`, `fileTools/{read,write,edit,glob,grep}`,
  `media/read-media`, `_base/tools/policies/path-access`
- `permissionPolicy/git-cwd-write-approve` and
  `permissionPolicy/git-control-path-access-ask`
- `agent/rpc`, `agent/agentTool`, `agent/profile/{context,profileService}`
- `session/{sessionWarning,workspaceContext}`
- `app/bootstrap` (drops `IBootstrapService.detect()`)
- `fileTools/glob` and `agentFs/runRg` now route rg through
  `ISessionProcessRunner.exec` with per-call `{ cwd }` overrides

`test/tools/fixtures/fake-kaos.ts` is replaced by `fake-exec.ts` with
per-atom factories (`createFakeHostEnvironment`, `createFakeExecContext`,
`createFakeAgentFs`, `createFakeProcessRunner`). Domain-layer registry,
PUML diagram, tsdown externals and `package.json` deps are updated
accordingly.

`packages/kaos/` stays in the workspace — v1, node-sdk and acp-adapter
still depend on it. Only `agent-core-v2` has been detached.
…into kimi-code-v2

# Conflicts:
#	packages/agent-core-v2/src/agent/agentTool/agentTool.ts
#	packages/agent-core-v2/src/agent/background/agent-task.ts
#	packages/agent-core-v2/src/session/subagentHost/index.ts
#	packages/agent-core-v2/src/session/subagentHost/subagentHost.ts
#	packages/agent-core-v2/src/session/subagentHost/subagentHostService.ts
#	packages/agent-core-v2/test/agentTool/agentTool.test.ts
#	packages/agent-core-v2/test/agentTool/runChildAgent.test.ts
#	packages/agent-core-v2/test/agentTool/subagentHostService.default.test.ts
#	packages/agent-core-v2/test/background/ids.test.ts
#	packages/agent-core-v2/test/background/manager.test.ts
#	packages/agent-core-v2/test/background/rpc-events.test.ts
#	packages/agent-core-v2/test/harness/agent.ts
#	packages/agent-core-v2/test/subagentHost/defaultSessionSubagentHost.test.ts
#	packages/agent-core-v2/test/subagentHost/subagentHostService.test.ts
#	packages/agent-core-v2/test/swarm/swarm.test.ts
#	packages/agent-core-v2/test/tool/tool.test.ts
#	packages/agent-core-v2/test/turn/turn.test.ts
Move config-section registration out of Service constructors and into
import-time contributions, mirroring the existing registerScopedService
pattern so a section is available as soon as its domain barrel is imported.

- add configSectionContributions collector (module-level, no DI) with
  registerConfigSection / get / _clearForTests
- ConfigRegistry drains the collected contributions on construction
- each owner configSection.ts calls registerConfigSection at top level
  (providers, models, modelCatalog, experimental, thinking/defaultThinking,
  loopControl, permission, hooks, background, microCompaction, cron)
- domain barrels import their configSection to guarantee the side effect
- remove registerSection calls and the now-unused IConfigRegistry injection
  from the 11 owning Services

The KIMI_MODEL_* effective overlay is still registered by modelService and
left for a follow-up.
The domain-layer checker placed `event` at L7 (edge) and
`session-context` at L6 (coordination), producing false-positive
violations for legitimate foundational dependencies:

- `event` is the App-scope pub/sub bus over `_base/event`; it belongs
  in L1 (root), matching its file header and the design doc.
- `session-context` is a pure Session-scope seed value (like
  `execContext`), so it also sits in L1.

Moving both to L1 removes the false positives for auth, modelCatalog,
sessionLog and permissionGate, and lets us drop the now-unnecessary
`session>event`, `cron>session-context` and
`background>session-context` exceptions. lint:domain goes from 13 to 8
violations; the remaining 8 are the unrelated
permissionPolicy -> plan/swarm inversion.
- add IAgentRecordService: append(record) fans out to durable persistence,
  live broadcast, and replay capture via per-type facets
  (toLive/toReplay/resume/blobs); signal(event) emits live-only events
- remove IAgentEventSinkService; fold live emission into IAgentRecordService
- migrate all agent domains to record.append/signal/define
- server-v2 subscribes to agent events via IAgentRecordService
- delete dead createLoopEventDispatcher
- AgentRecordMap extends WireRecordMap so record types stay on WireRecordMap
- make IScopeHandle generic over LifecycleScope and add IAppScopeHandle /
  ISessionScopeHandle / IAgentScopeHandle so session and agent handles cannot
  be passed to each other's parameters at compile time
- thread the aliases through IAgentLifecycleService / ISessionLifecycleService
  and their consumers (sessionLegacy, messageLegacy, server-v2 mainAgent and
  skills), narrowing at the lifecycle boundary
- dep-graph viewer: render scope-mismatch (token registered at a scope the
  caller cannot see) distinctly from a genuinely missing implementation
- add Session-scoped ISessionBtwService/SessionBtwService that forks the
  main agent into a side-question child agent (tools disabled,
  side-channel reminder) via IAgentLifecycleService.fork('main')
- remove startBtw from AgentAPI (core-api) and ISessionLegacyService;
  the server-v2 POST /sessions/{id}/btw route now resolves
  ISessionBtwService directly
- add a unit test for SessionBtwService
- Drop parentAgentId/type from agent-lifecycle; forkedFrom is provenance only, not used by business logic
- Rename IAgentLifecycleService.fork() to clone(); add list({ prefix }) for prefix-based queries
- Lift swarm batch scheduling to Session scope (new SessionSwarmService); SubagentBatch becomes its internal scheduler, no longer exported
- AgentSwarmService keeps mode UI + tool registration, delegates batch runs to SessionSwarmService
- Move ownership/cancellation out of lifecycle: drop activeChildrenByParent/cancelAllChildren/markChildDetached/SubagentDetachHandle; callers own cancellation via abort signals
- cron/permissionGate: derive subagent behavior from agentId !== 'main' instead of type
- protocol: SubagentSpawnedEvent.parentAgentId -> callerAgentId (wire break)
- Remove stale IKaos imports left after kaos was dropped; use IExecContext
… as default

- remove App-scope registration of InMemoryStorageService for
  IStorageService, IAppendLogStorage, IAtomicDocumentStorage, and IBlobStorage
- composition root now seeds FileStorageService and the test harness seeds
  the in-memory backend, so a scope that seeds neither fails on first use
- update the class doc comment to describe storage as a deployment choice
- add examples/README.md with the run command, two example styles, the
  L0-L3 learning path, and a roadmap covering the registered services
- add di-container.example.ts (Example 01): decorator/registration, the
  App/Session/Agent scope tree, sibling isolation, and disposal order
- add file-tools.example.ts (Example 13): the smallest real 3-tier slice,
  wiring AgentFileToolsService with stubbed Session/App leaf dependencies
- add tags.ts: TagMap model with localStorage persistence, tag counts,
  equality check, and deterministic dark-theme tag colors
- add a Tags section to Filters with all/none toggles and per-tag focus
  rows that drive the new activeTags filter state
- thread tags state through App: load on init, persist on change, and an
  edit handler passed down to GraphView
- add ServerClient under src/v2: typed /api/v2 resource tree over HTTP
  plus events over WebSocket, with core/session/agent scopes and a v1
  escape hatch for the legacy REST surface
- add resource modules (core/session/agent/events), a manifest mirroring
  the server-v2 actionMap, shared types, and transport (HttpRpc,
  rpcProxy, V2Socket)
- expose @moonshot-ai/server-v2/contract (actionMap + channel helpers)
  so the SDK drift test stays in lockstep with the server surface
- add an in-process smoke test and the vitest raw-text/hash-imports
  plugins needed to import server-v2 source from the e2e tests
- add optional bearer token support to the legacy HttpClient and document
  the two-client package layout
- add SkipList.iterate and DtIndex.iterate: lazy range scans that let a
  caller stop early without materializing the whole range
- add IndexManager.hasEq for O(1) equality-index membership checks that
  avoid materializing the full posting list
- add MiniDb.tryDtOrderedLimit (with cheapEqChecks): for a query bounded
  by a single dt column whose result order is that column, walk the dt
  skiplist in order and stop at limit, pre-filtering cheap equality
  predicates before decode; wire it into query()
- fix text-index tokenization overflowing the call stack on large docs by
  loop-pushing instead of spreading the match array
- add bench/* benchmarks and tests for the fast path and skiplist iteration
- rename 6 domain dirs (sessionIndex, sessionLifecycle, agentLifecycle,
  sessionActivity, sessionContext, sessionMetadata) to match the camelCase
  convention used by siblings like sessionLegacy and modelCatalog
- update #/ import paths, registerScopedService names, barrel exports, and
  the DI layer map keys/exceptions
- sync examples, di-scope-domains docs, AGENTS.md, and agent-core-dev
  skill docs
…vice

- Move git status/diff and `gh pr` lookup out of `session/agentFs` into a new
  App-scope `IGitService` (`app/git`), which spawns git via `node:child_process`
  and owns the pull-request cache.
- `ISessionFsService.gitStatus/diff` now only confine paths and delegate to
  `IGitService`; the wire surface and the `FS_GIT_UNAVAILABLE` error code are
  unchanged.
- Move pure git-output parsers to `app/git/gitParsers`, add real-git
  `GitService` tests, and rewrite the `fsService` git tests as delegation tests.
- collapse activate/activateFromModel into a single activate on
  IAgentSkillService; the model wrapping (resolve, inline and
  disableModelInvocation gates, isError result, prompt.steer) now lives
  in SkillTool behind a shared executeModelSkill helper
- keep activation recording in the service via a recordActivation
  callback passed to the tool
- drop the redundant ModelSkillTool and the TestAgentSkillService
  harness subclass; update skill tests
AgentCronService wrote every task to one global `<homeDir>/cron/<id>.json`
scope, so tasks were shared across all sessions and agents (id collisions,
cross-session resume) and diverged from the v1 layout.

Derive a per-agent atomic-document scope from ISessionContext and
IEnvironmentService (`sessions/<ws>/<sid>/agents/<agentId>/cron`), so tasks
land at `<sessionDir>/agents/<agentId>/cron/<id>.json`, matching v1 and
letting CLI/v1 and v2 sessions read each other's cron files. When the agent
has no id (ephemeral / test seam) persistence is skipped, mirroring v1's
"no homedir, no persistence" behaviour.
AgentBlobStoreService now derives its storage scope from a per-agent
`homedir` (`<agentDir>/blobs/<sha256>`) instead of the global `blobs`
scope, matching v1 so v2 can rehydrate blobs from v1-written sessions.
AgentLifecycleService seeds the per-agent `homedir` when creating an
agent scope, alongside the existing wire-record seed.
Thread ExecutableToolContext.signal through the web tool chain so an
aborted turn actually cancels the underlying HTTP request instead of
merely racing it at the executor.

- UrlFetcher.fetch and WebSearchProvider.search accept an optional
  AbortSignal; the tools forward ctx.signal
- LocalFetchURLProvider, MoonshotFetchURLProvider, and
  MoonshotWebSearchProvider pass the signal to fetch()
- MoonshotFetchURLProvider no longer falls back to the local fetcher
  when the caller aborted
- the tools re-throw on abort so the executor classifies user
  cancellation instead of surfacing a retryable network error
- add examples/session-skill.example.ts demonstrating the Session-scoped
  skill catalog: loads skills from the current workDir and reports each
  skill's source provenance (builtin / user / project)
- list the example in the examples README roadmap
7Sageer and others added 30 commits July 8, 2026 14:33
- add an Agent-scope runtime domain that holds the whole live phase as one discriminated-union field (idle, running, streaming, tool_call, retrying, awaiting_approval, interrupted, ended)
- drive it from existing turn, step, delta, tool, retry, interrupt and approval events, edge-triggered with reference-equality dedup so delta bursts do not flood the wire log
- carry the phase on the existing agent.status.updated channel and add the AgentPhase type/schema to the protocol (backward compatible)
- write `kimi version <version>` to stderr first in text mode
- emit a `system.version` meta line first in stream-json mode
- gate behind isKimiV2Enabled() so the default v1 path is unchanged
…cap to 3000px (#1460)

* fix(agent-core): report EXIF-rotated image dimensions and raise edge cap to 3000px

Image compression now reports original dimensions in the decoded
(EXIF-rotated) space, matching the coordinate system of the sent image
and of ReadMediaFile region readback; previously portrait JPEGs
(orientation 5-8) got swapped width/height in captions. The longest-edge
downscale cap rises from 2000px to 3000px, and the default jimp resize
path is documented as the anti-aliased area-average one so it is not
accidentally switched to a point-sampled interpolation mode.

* test: shrink oversized image fixtures to fit CI timeouts

The 3600x3600 fixtures introduced for the 3000px edge cap nearly doubled
the pixel area jimp has to decode and deflate, pushing the slowest
compression tests past the 5s vitest timeout on CI runners. 3600x1800
keeps every fixture over the cap while restoring roughly the workload of
the old 2600x2600 fixtures that CI handled comfortably.

* test: pin anti-aliased downscale quality with executable guards

A 1px checkerboard probe pins the compressor to full-coverage averaging
at integer and fractional ratios, with jimp's point-sampled BILINEAR
mode kept as the executable aliasing counter-example (it collapses the
50%-gray pattern to solid black at 4:1). Also guards the other classic
downscale bugs: transparent-pixel color bleed, mean-brightness drift,
iterative recompression degradation, and zero-size collapse on extreme
aspect ratios.

* fix(agent-core): report decoded EXIF-rotated dimensions in ReadMediaFile notes

The media note derived its original-dimensions line from the header
sniff, which reports pre-rotation values for EXIF orientation 5-8
JPEGs. The sent image and region readback both live in the decoded
(rotated) space, so portrait photos got axis-swapped coordinate
guidance. Once a decode has happened — compression or crop — its
dimensions now overwrite the sniffed ones.

* fix(agent-core): improve handling of EXIF orientation in image dimensions and metadata

* fix(agent-core): sniff EXIF orientation and step budget fallback through 2000px

Two follow-ups to the EXIF and 3000px-cap changes:

sniffImageDimensions now reads the JPEG EXIF Orientation tag (pure
header parse, both byte orders) and reports display-space dimensions
for orientations 5-8. Passthrough images — never decoded — previously
kept the pre-rotation header size in compression results and media
read notes, disagreeing with the decoded space that region readback
uses.

encodeWithinBudget steps the over-budget fallback through 2000px
before the 1000px last resort. Raising the cap to 3000px had left a
regression window: an image whose 2000px encode fits the byte budget
was sent at 1000px where the old 2000px cap used to send it at
2000px.

* fix(kimi-code): record pasted image dimensions in display space

The TUI paste path recorded attachment and original dimensions from its
raw header parser, which ignores EXIF orientation. For a portrait JPEG
the submit-time caption then contradicted the sent image's aspect and
region readback coordinates were axis-swapped. Dimensions now come from
the compression result, which reports display space on both the
compressed and passthrough paths; parseImageMeta remains only the
format/mime gate.

* feat(agent-core): add image compression and crop telemetry

Every image ingestion path now reports an image_compress event —
outcome (compressed / passthrough fast, guard, unsupported, unhelpful,
error), input/output formats, byte and pixel sizes, EXIF transposition,
and duration — and region readback reports an image_crop event with a
failure classification and the region's share of the original area.

Wiring is per call site via a new CompressImageOptions.telemetry
option, so the outcome split and timing are measured inside the
compressor while each caller only names its source: ReadMediaFile
(tool construction, like GrepTool), MCP tool results (McpOutputOptions),
server prompt ingestion (ICoreProcessService now exposes the host
telemetry client), ACP prompts (session track adapter), and TUI paste
(host.track adapter). Properties are numeric/enum only — never paths
or content — and a throwing client can never affect the compression
result.

* fix(agent-core): run the full JPEG quality ladder at fallback sizes

The fallback rescales encoded only at quality 20, so a JPEG whose
ladder failed at the fitted size collapsed straight to the lowest
quality even when the smaller size left budget headroom for a higher
rung (the realistic window is the 1000px step, where the 4x pixel
drop pays for q80/q60). Each fallback edge now walks the same
q80-to-q20 ladder as the fitted size.

* test: shrink heavy JPEG fixtures and add explicit timeouts

The fallback-ladder test runs ~11 pure-JS JPEG encodes and the EXIF
paste test decodes, rotates, and re-encodes a 6.5MP frame; both sat at
the edge of the 5s vitest timeout on CI runners. Narrower fixtures cut
the pixel area (the ladder test keeps its width above 2000px so the
full fallback chain still runs) and explicit 15s timeouts absorb runner
variance.

* fix(server): scope prompt image compression telemetry to the session

The prompt-ingestion image_compress events were emitted with the bare
host telemetry client, while every agent-side source inherits a
session-scoped client — so prompt_inline/prompt_file events could not
be correlated with their session. The route now wraps the client with
withTelemetryContext({ sessionId }) like rpc/core-impl does for
session telemetry.

* chore(changeset): consolidate image compression changesets

One entry covering the cap raise and the EXIF dimension fix, listed
for both the CLI and the SDK so the SDK changelog's compression
description (previously pinned at 2000px) stays accurate.
Align progressive tool disclosure with the discard-on-compaction model:
compaction no longer rebuilds loaded dynamic tool schemas. The boundary
announcement re-lists every loadable name, the model re-selects what it
still needs, and a from-memory call to a no-longer-loaded tool is
rejected by preflight with select guidance.

This removes the keep-all rebuild and its half-trigger budget heuristics
entirely: the post-compaction floor is back to users + summary, which is
structurally outside the auto-compaction trigger band, and the guard
baseline degenerates to summary + reinjected reminders. Every downstream
mechanism already treated the empty loaded set as its consistent base
state (ledger scan, pending clear at the compaction boundary, deferred
extras, preflight wording), so this is a strict simplification.

Co-authored-by: fengchenchen <fengchenchen@moonshot.ai>
Headless (`kimi -p`) failures could exit with code 0 when the event loop
drained during the shutdown cleanup (e.g. telemetry's unref'd retry backoff
when the network is blocked), because the rejection never reached the
process.exit(1) call. Set the failure exit code before any await in both
the run-prompt catch and the main catch, and keep the cleanup timeout ref'd
so the loop stays alive long enough for the rejection to propagate.
* feat(web): redesign cron reminder as a message bubble

Restyle the cron trigger notice as a right-aligned user-style message bubble that shows the scheduled prompt in full (wrapping across lines), with a small meta row beneath it for the schedule, status, job id and run time. Extract a shared MessageTime component used by both user messages and the cron reminder so the timestamp format and click-to-expand behavior stay consistent, and give the CronCreate/CronList/CronDelete tools distinct calendar icons.

* refactor(web): render cron reminders only as standalone turns

Remove the embedded cron block path from the web transcript projector so cron reminder fires always render through the standalone right-aligned bubble path.

* chore(web): simplify cron redesign changeset
)

* fix(web): composer model switch also updates global default model

The composer model switcher still switches the active session's model via
POST /sessions/{id}/profile (awaited, so the model pill reflects the result),
and additionally fires POST /api/v1/config with { default_model } as a
fire-and-forget side effect so new sessions inherit the chosen default. The
config request is skipped when the model already matches the current default.

* fix(web): route ModelPicker overlay selection through the default-model update

The overlay opened from the composer's "More models" row (and /model) is a
continuation of the same switch flow, so its selection now also bumps the
global default model instead of only switching the active session.

* fix(web): only persist the default model after a confirmed session switch

setModel now returns whether the switch was accepted (true for the draft
path), so the composer flow no longer writes a stale or invalid model alias
into the global config when the session-level switch failed and rolled back.
- port probeLoginShellPath/mergeLoginShellPath/applyLoginShellPath into
  _base/execEnv/loginShellPath.ts as a pure helper (no DI)
- export execFileText from environmentProbe for reuse by the probe
- run applyLoginShellPathFromNode concurrently with the host probe in
  HostEnvironmentService, mirroring kaos LocalKaos.create()

Aligns agent-core-v2 with kaos 021786f so the Bash tool finds
user-installed tools (e.g. Homebrew's gh) when kimi-code is launched
from a GUI or non-login shell.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants