@khorsheed/dsh-local-agent-kimi 0.2.0-rc.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,8 +1,23 @@
1
1
  # 变更记录
2
+ ## 0.2.0(2026-10-26)
3
+
4
+ rc.3 之后到正式版的变化:
5
+
6
+ - **修复刷新后回答被收进过程里**:实时输出原来会在日志里留下一个提前的步骤记录,刷新或冷打开时这一步排到最前、最后一步变成工具调用,宿主把最终回答一起折叠掉;现在实时输出只在浏览器里预览,不进日志(与 Claude、Codex 同一约定)。
7
+ - **修复步骤编号错乱与重复写入**:工具通知和流各自预约步骤号,后写入的补最小空号,导致日志写成 1、3、7、8、2…,迟到的通知还会让一次调用写两遍;现在步骤号在写入时决定,已在日志里的调用不再重写。
8
+ - **修复空的思考/回复流留下步骤空洞**:没有内容的流原来不释放预约,日志从第 1 步跳到第 3 步,Context Lens 整份判为损坏;现在正确释放。
9
+ - **README 重写**:改为大白话说明,完整参考移到 `docs/`。
10
+ - **版本号去掉 rc**:社区包不再发 prerelease 版本(docs/publishing.md「版本号规则」),家族各包同版 0.2.0;本节原记为 0.2.0-rc.4。
11
+ - **cacheReadTokens 恒写**:wire 上报缓存读字段时,命中为 0 也写 0——与家族其他成员同口径(「命中 0」与「未上报」可区分)。
12
+ - **request/header 的 model 统一为别名拼写**:wire 里 `llm.request` 带裸 id(`k3-256k`),`usage.record` 带别名(`kimi-code/k3-256k`);原来 header 用裸 id、消息 source 用别名,新旧日志(有/无 header)对同一模型显示两个名字。现在 header 跟随 `usage.record` 的别名拼写,与 source 同名。
13
+ - **修复子会话的回复被整轮折叠块吞掉(live 路)**:live 驱动里同一响应段的思考流与回复流原来各占一个预约 step;折叠在某一个 step 落盘后,被释放的另一个预约在日志里只剩流式帧、永不落内容——宿主的「最终答案」锚定取 turn 的最后一个 step,这种空 step 让锚定失败,折叠时连回复一起藏掉。现在同一段(generation)的两条流共享一个预约 step(宿主实况本就是 reasoning+text 同一个 step),配对折叠与 settle 收尾都按 step 合并成一条消息。
14
+ - **子会话日志写入 `request/header`**:wire 的 `llm.request` 自带 model/thinkingEffort/maxTokens,镜像按 wire step 折叠时把该声明写成宿主原生 `request/header`(只在变化时记录)——Context Lens 的配置卡片由此读出真实值,不再整卡「未记录」。
15
+ - **镜像按 wire step 聚合折叠(一次 LLM 请求 = 子会话一个 step)**:kimi 子会话里同一 wire step 的思考、回复与工具调用原来各自折成独立记录(思考独占一条无用量、0.0s 的伪请求);现在整步折成一条 assistant 消息(reasoning/text/tool-call 块同框,工具调用/结果对跟在同一边界内),与主会话同形——Context Lens 里一轮一次请求,每条 `usage.record` 挂在该 step 自己的消息上(逐请求真实用量)。wire 未闭合(无 `step.end`)的 step 在增量镜像中整步等待、闭合后整步落盘,实时增量仍走 `local-agent/stream` 通道;无 step 标记的旧格式 wire 维持逐行折叠不变。
16
+ - **成员会话的模型对话框与「可用模型」短名单严格一致**:成员的模型目录原来会混入作用域配置发现的模型与历史记录(kimi 下会列出非本端点服务的配置表模型),与卡片短名单不一致。现在成员对话框的候选即短名单(按名单顺序;名单里端点已不再供应的值保留为裸行,与卡片一致),名单外只保留成员当前绑定的模型(避免既有绑定显示空白);卡片的添加对话框只列端点真实供应的模型,配置/历史附加项不再混入。
2
17
 
3
18
  ## 0.2.0-rc.3(2026-10-22)
4
19
 
5
- (版本号说明:家族的 dsh-headless 包 0.2.0-rc.2 曾被发布后又撤回,npm 永久烧掉该版本号;为守住家族「同一版本线」纪律(check:release-groups),本波家族整体上移 rc.3,内容即 rc.2 计划稿。)
20
+ (版本号说明:家族的 dsh-headless 包 0.2.0-rc.2 版本号已被 npm 发布流水线占用(重复利用被 409 拒绝:「Cannot stage previously published version」——曾发布后被撤回或曾被暂存,外部无法区分,结果相同:该号不可复用);为守住家族「同一版本线」纪律(check:release-groups),本波家族整体上移 rc.3,内容即 rc.2 计划稿。)
6
21
 
7
22
  - **BREAKING:OAuth 移除,端点 key 成为唯一认证方式**。注入用 kimi-cli ≥2.1 的原生 `api_key_env`:作用域 `config.toml` 的 managed provider 声明从环境变量读 key,key 只存在于 `<scopedHome>/endpoint-auth.json`(0600)与子进程环境,`config.toml` 无秘密;一把幂等迁移把既有 config 改到该形态(摘 OAuth 子表、替换内联 `api_key`、钉住 `base_url`)。**升级前必须配好 `baseUrl` + `apiKey`**,否则升级后读作未认证(README 带迁移说明);`credentials/` 与 `oauth/` 残留由 provision 清扫,credential-guard 哨兵随 OAuth 一并删除。
8
23
  - **设置卡端点凭据表单,并补上「验证端点并获取模型」按钮**:表单与家族其他卡一致(编辑默认 scope 的 endpoint-auth.json);验证探测已保存端点的 `/v1/models`(kimi 服务没有已确认的无 token 探测,故探测带凭据进行)。
package/README.en.md CHANGED
@@ -2,134 +2,46 @@
2
2
 
3
3
  English | [中文](README.md)
4
4
 
5
- Delegate a task from any dsh session to the Kimi Code CLI on your machine — it runs in its own scoped home, and your `~/.kimi-code` stays untouched.
5
+ Hand work to the Kimi Code on your machine: watch it work live, get the result back in your session, and keep the conversation going.
6
6
 
7
- Getting the model to hand a whole chunk of work to another coding agent used to mean opening a terminal yourself, copy-pasting, and carrying the result back. This plugin gives every agent preset a `subagent_kimi` delegation tool and a `/kimi` command family: delegations run as child sessions in the session's workspace, their transcripts and progress show up in the subagent surface, results come back with real usage and timing, and the same handle resumes the conversation later.
7
+ Getting Kimi Code to help used to mean opening a terminal, pasting things in, and carrying the result back yourself. With this plugin you say "give this part to Kimi" in a session, and the agent hands the task, with its requirements, to Kimi Code on your machine. Kimi's thinking, tool calls, and replies show up live in a sub-session, and the result comes back with its real usage and time. Kimi runs in its own separate folder; your existing Kimi setup and sessions are never touched.
8
8
 
9
- <img src="https://raw.githubusercontent.com/Khorsheed/dsh-basic/main/docs/screenshots/local-agent-kimi-settings.png" width="640" alt="the Kimi settings card: auth status, login/logout, default model, and the resident-mode toggle">
9
+ <img src="https://raw.githubusercontent.com/Khorsheed/dsh-basic/main/docs/screenshots/local-agent-kimi.png" width="560" alt="The expanded Kimi section: Kimi Code signed in with its version, endpoint, API key, "Verify endpoint & list models", the available-models list and the resident-mode switch">
10
10
 
11
- ## Features
11
+ ## What it does
12
12
 
13
- - **Per-session delegation grant** — the `subagent_kimi` tool is this package's `./tool` composition entry, granted to the sessions of an agent preset that names it (e.g. dev mode); sessions on other presets never see it.
14
- - **Scoped home** — config, credentials, and sessions live under `$DSH_HOME/local-agent/kimi`, never in your `~/.kimi-code`.
15
- - **Endpoint credential (the only auth mode)** — fill `baseUrl` + `apiKey` on the card's Authentication section (saved as the default scope's `endpoint-auth.json`, mode 0600, local only) or preconfigure the profile row, and the scope is authenticated; every named scope may override the deployment pair field by field with its own `endpoint-auth.json`. The managed provider reads the key through its `api_key_env` indirection from the child process's environment — the key never lands in `config.toml` (an evaluation-condition input). Container rounds share the host's credential; nothing is authorized inside a unit. There is no web login and no device code. The "Verify endpoint & list models" button next to it runs a token-free probe against the SAVED endpoint (`GET <baseUrl>/v1/models`, Bearer header) and answers with reachability plus the served model list.
16
- - **Resumable delegations** — pass back the self-described `resume` handle to continue the same Kimi session, with real per-round usage and timing.
17
- - **Session records and transcript replay** — `/kimi sessions` lists this harness's delegations (never your personal sessions); `/kimi session <id>` renders the session's wire log as a readable transcript — thinking, tool calls, and results included.
18
- - **Settings card** — a section of the core's「Local Agent Delegation」family card on the Plugins page (on an older core, this package's own `plugins.item` card; mounted while the Host serves the `local-agent-kimi` namespace) shows auth status and the scoped sessions at a glance; login/logout, the available-models shortlist (ordered, the first entry is the default; empty = the legacy chain), and the resident-mode switch all hot-apply, no reload.
19
- - **Model readback and per-cell working directory** — every settled round reads back the model from the wire.jsonl usage/request records into the delegation record; orchestrators pass a `cwd` per cell, and a resume in a different directory is rejected.
20
- - **Resident driver (optional)** — `live: true` keeps one resident `kimi acp` process per member, one `session/prompt` per round, with runtime-level graceful cancel; off — or a channel that cannot come up — means the one-shot `kimi -p` path.
13
+ - **Hand it off in one sentence**: tell the agent which part goes to Kimi; it writes up the brief, and the result comes back to your session.
14
+ - **See the work as it happens**: the sub-session lists Kimi's thinking, tool calls, and replies step by step, and they're still there after a page refresh.
15
+ - **Keep talking, no cold start**: not happy with the result? Have the agent follow up, or open the sub-session and message Kimi yourself; it's the same Kimi session.
16
+ - **Paste a key and go**: enter the endpoint and API key on the settings card, press "Save credential", then "Verify endpoint & list models" to check it connects.
17
+ - **Pick your models**: under "Available models", tick models the endpoint offers and drag to reorder; the top one is the default. You can also switch model and reasoning effort inside a sub-session.
18
+ - **Resident mode is faster**: turn on "Resident mode (live)" and the Kimi process stays up, streaming output into the sub-session; stopping doesn't restart it.
19
+ - **Look back at past hand-offs**: `/kimi sessions` lists the tasks you gave Kimi, and `/kimi session <id>` turns one into a readable record.
21
20
 
22
21
  ## Install
23
22
 
24
- Requires a running dsh profile and the Kimi Code CLI (`kimi`) on `PATH` — the plugin installs neither and never logs in on your behalf.
23
+ First install the Kimi Code CLI yourself (`kimi` runs in your terminal); the plugin doesn't install it. Then in DSH, open Plugins → Add plugin, enter this package name, and press Install:
25
24
 
26
- ```sh
27
- # Name both: `dsh plugin add` reconciles only direct dependencies.
28
- dsh plugin --profile web add @khorsheed/dsh-local-agent
29
- dsh plugin --profile web add @khorsheed/dsh-local-agent-kimi
30
25
  ```
31
-
32
- Restart the web instance to activate, then fill the endpoint and key in the Kimi section's Authentication block of the「Local Agent Delegation」family card (the Plugins page) — or preconfigure the profile row; with neither, the status reads unauthenticated. Uninstall:
33
-
34
- ```sh
35
- dsh plugin --profile web remove @khorsheed/dsh-local-agent-kimi
36
- ```
37
-
38
- The scoped home is kept on purpose so a reinstall keeps its credential — delete `$DSH_HOME/local-agent/kimi` to remove every trace.
39
-
40
- ## Config
41
-
42
- Optional: route Kimi's LLM requests through your own endpoint via the scoped `config.toml` (`$DSH_HOME/local-agent/kimi/config.toml`):
43
-
44
- ```toml
45
- [providers."managed:kimi-code"]
46
- base_url = "https://your-router.example/v1"
26
+ @khorsheed/dsh-bundle-local-agent
47
27
  ```
48
28
 
49
- Edit **only this key** — provisioning never overwrites an existing config, and the `[services.moonshot_*]` base URLs must stay (they route the built-in search/fetch tools).
50
-
51
- ⚠️ **Credential exposure**: the endpoint key is sent to whatever endpoint serves the request — point `baseUrl` only at endpoints you control or trust.
52
-
53
- Plugin config of its own (optional, in the profile patch layer):
54
-
55
- ```yaml
56
- - id: local-agent-kimi
57
- config:
58
- model: kimi-code/k3 # optional: every delegation round starts the CLI with it; absent passes no model at all (below)
59
- thinkingEffort: high # reasoning effort; written into a FRESH scoped config.toml ([thinking] effort and the model default_effort; low/high/max, default high). Provision-time only — an existing config is never overwritten
60
- live: false # resident driver: one resident kimi acp process per member, one session/prompt per round (runtime-level graceful session/cancel, push-triggered mirroring); off — or a channel that cannot come up — means the one-shot kimi -p path
61
- liveIdleMs: 1800000 # idle lifetime of a resident runtime before reclaim (default 30 min)
62
- ```
63
-
64
- **Migration note.** Live runs always consume incremental output: the old `liveMirrorGranularity: event | token` key is accepted for existing profiles but ignored, and changing it never changes a running process. Exec remains available for evaluation. Final provider items remain authoritative, including tool history and usage.
65
-
66
- ### Default model (`model`)
67
-
68
- ⚠️ **This key's meaning changed.** It used to apply exactly once, when a FRESH scoped home was provisioned: it became the `default_model` of the written `config.toml`, and an existing config was left alone. It now applies to **every delegation round**. The provisioning mirror is kept: a fresh scoped home with no user config to mirror still gets its minimal managed config built around this value.
69
-
70
- **Absent = today's behavior.** Without this key the plugin adds no model flag to the argv at all: the scoped `config.toml`'s top-level `default_model` decides which model runs.
71
-
72
- **Set = every delegation round starts the CLI with it.** The value must name a model the scoped `config.toml` defines (a `[models."…"]` key) — `-m` resolves against kimi's own model table.
73
-
74
- | Drive | How it is passed |
75
- |---|---|
76
- | one-shot (default) | `kimi -m <model> -p <task>`; a resume round is `kimi -S <session> -m <model> -p <task>` — `-S` still leads and `-m` hugs `-p` (anything after `-p` is read as the prompt) |
77
- | resident (`live: true`) | `kimi acp` has **no** model flag, so the scoped `config.toml`'s top-level `default_model` is rewritten to the value before each runtime spawns. The write is in place and idempotent: only that one top-level line moves, while comments, model tables, providers and `[thinking]` stay byte-identical; with no config to write into, none is created (provisioning owns creation), the round still runs, and the model read-back is what surfaces a mismatch |
78
-
79
- So: the one-shot drive never touches your `config.toml`; the resident drive rewrites its `default_model` line.
80
-
81
- The settings card's「Available models」section maintains an **ordered model shortlist**: "Add model" checks entries off the endpoint's served catalog, so the list can only hold what the endpoint actually serves; drag rows to reorder. **The first entry is the default model** — every delegation round starts the CLI with it (an argv flag one-shot, or the scoped `default_model` rewrite before a resident spawn), outranked only by member session overrides and delegation-level picks. The list persists in the scoped home's `models.json` (each named scope may carry its own, the same file mechanism as the endpoint credential), every edit saves immediately and applies to the next round. **Empty = the legacy chain** (the `model` key → the scoped config's top-level `default_model` → the CLI built-in). kimi's `-m` resolves against the scoped config's `[models."…"]` tables (verified against kimi-cli 2.1.1: a bare endpoint id without a table is not runnable), so adding a served id that has no table yet provisions its managed table in the same write (the endpoint-reported display name, effort levels and context window ride along). Per-member model and effort changes use the durable controls described below.
29
+ Kimi comes with the 「多Agent协作」 (multi-agent) suite; all the local agents share one core, so on its own it won't work. If you mostly write code, the Dev Suite `@khorsheed/dsh-dev-suite` includes it too. Restart DSH, then on the Plugins page open the 「本机 Agent 委派」 (Local Agent Delegation) card, expand the Kimi section, and fill in the endpoint and API key.
82
30
 
83
- The directory's vocabulary comes from the endpoint itself (`GET <baseUrl>/v1/models`); the scoped config's model tables only enrich it: when a served id matches a managed table's `model`, the candidate's value is the TABLE KEY (the name `-m` actually runs), and display name / reasoning efforts prefer the endpoint's answer with the table as fallback. A resident member's native ACP configOptions remain that member's authoritative directory (labels plus the current model's reasoning options). With no credential, a rejected credential, an unreachable-shape answer or no models served, the directory loads empty with the reason; a transport failure keeps the last good snapshot and retries on the cache's schedule. Reads create no disposable ACP sessions. Directory refresh and subscriptions use the shared core cache. The shared model picker and member effort controls are connected. Busy selections apply at the next complete turn boundary, including tool continuations; core owns current/pending state, cancellation and retry, while frozen evaluation members reject changes.
31
+ Handing work to Kimi happens in a mode that grants delegation, such as "开发模式" (dev mode): start a new session, pick that mode, and tell the agent "give this to Kimi". Not seeing Kimi delegation in other modes is expected.
84
32
 
85
- **A delegation's own model outranks this key.** An orchestrator may name the model for ONE delegation through the facade's `DelegationCallOptions.model`, which sits above this key (the layer order is in the family core README). The first round's request is recorded and every resume round re-requests it — `resume` takes no model of its own. In resident mode it becomes the member's **start model**: bound through the scoped-config rewrite before the runtime spawns; a resident runtime already bound to another model is retired first and respawns onto the new one, `session/load`-ing the same CLI session.
33
+ ## Known limitations
86
34
 
87
- **Member-level switching (composer).** A member session's composer can switch that member's model: a **session-level override** ranking above every layer (the delegation record included). It lives in memory only and does not survive a host restart. In resident mode a switch retires the runtime whose bound model differs — the next round respawns onto the new model and `session/load`s the same CLI session, so the conversation carries over; on the one-shot drive the next round simply passes the new value to `-m`.
88
-
89
- **This is not an evaluation gap.** A run freezes its condition at setup: change the key mid-run and the next round's model read-back sees declared ≠ observed and fails the run as misattributed (frozen decision 5).
90
-
91
- **Evaluation snapshot (`effectiveSettings`).** The harness declares a live-read snapshot of its fairness-relevant settings for the evaluation condition hash: drive (exec/live, following the live preference), reasoning effort (read from the scoped config's `[thinking] effort`, falling back to the model's `default_effort`), whether tool use is auto-approved (the scoped config carries the `Bash(*)` allow rule), whether a custom endpoint is pinned (hostname only; the managed endpoint does not count as pinned), the configured model (the scope's `models.json` first entry first, then the plugin config's `model` key — it overrules the file every round — then the scoped config's top-level `default_model`; absent when none names one — never guessed), and the CLI version (`kimi --version`, cached against the executable's path + mtime; absent when the CLI cannot be asked). `/kimi status` and the `LocalAgentStatus` Remote attach the same snapshot — this is the read side of web-eval frozen decisions 2 through 4.
35
+ - Only an endpoint plus API key is supported (a Kimi coding-platform key or a relay key); Kimi membership web sign-in is not.
36
+ - Kimi still writes a few empty process records into your `~/.kimi-code`; config, credentials, and sessions stay in the plugin's own folder.
37
+ - The `/kimi` commands only work in web sessions.
92
38
 
93
39
  ## Compatibility
94
40
 
95
- - npm release line (`@deepseek-ai/dsh@0.1.5-rc.1`): ✅ public API compatible — live generation rides the local-agent transient Remote and public Conversation nodes; suffix checkpoints provide recovery, and native final messages retain transcript and usage semantics. minHost is 0.1.5-rc.1; older hosts stay on the previous release line. 0.1.5 retired the per-chunk session event: token-granularity deltas no longer land in the child session log — they ride the run-progress channel and the round settles as one combined assistant/message (identical final text); a late-arriving usage whose carrier message already mirrored is dropped with a warn (the host has no usage-backfill event). The settings card renders as a section of the core's「Local Agent Delegation」family card (the core's `plugins.item` entry on the Plugins page, 0.1.7-alpha.1+; on an older core this package falls back to its own `plugins.item` card), mounted through `configForms.whileServed` while the Host serves the `local-agent-kimi` namespace; 0.1.5 renders no card (the host removed the `settings.plugin.item` seat) — every other surface is unchanged.
96
- - source line (deepseek-harness master): ✅ (verifiedHost: 0.2.1-rc.1) — host-021 wave: full build+test green against the 0.2.1-rc.1 tree; delegation migrated to `ctx.subagents.startActivation` (managed activation), and run.id is now unique per execution. The `thinkingEffort` config item (default high, provision-time only) and the `effectiveSettings` evaluation snapshot are plugin-level: they read and write scoped files only, with no host-API dependency on either host line.
97
-
98
- ## Known Limitations
99
-
100
- - **No web login** — the endpoint credential is the only auth path (the card or the profile row; a kimi-for-coding platform key or a relay key alike). The kimi-subscription OAuth path is not part of this package.
101
- - **Process bookkeeping touches the real home** — kimi writes content-free `~/.kimi-code/server/instances/*.json` regardless of `KIMI_CODE_HOME`; config, credentials, and sessions stay scoped.
102
- - **`/kimi` commands need a Web session** — headless profiles can still delegate through a composition that mounts the tool row.
103
-
104
- ## How it works
105
-
106
- <details>
107
- <summary>Internals (click to expand)</summary>
108
-
109
- **Scoped home and credentials.** Every Kimi process the bundle starts runs with `KIMI_CODE_HOME=$DSH_HOME/local-agent/kimi`. Authentication is endpoint-key only: the scope's `endpoint-auth.json` (mode 0600) merges field by field over the profile row's `baseUrl`/`apiKey`; the managed provider (`managed:kimi-code`) declares `api_key_env = "DSH_KIMI_ENDPOINT_KEY"` in config.toml (the kimi CLI natively reads the key from a named environment variable — mutually exclusive with an inline `api_key`), so the key lives only in endpoint-auth.json and in the child process's environment, and `config.toml` never carries a secret and stays a legitimate evaluation-condition input. The card's Authentication section edits exactly this file for the default scope (through the family gateway's `endpointAuth`/`configureEndpoint` Remotes); saving a baseUrl re-points the managed provider's `base_url` in the same write (clearing it falls back to kimi's own service), and an idempotent pre-spawn pass applies hand-edits just as immediately. The one-shot `kimi -p`, the resident `kimi acp`, and container rounds (`containerExecSpawn`'s name-only env forwarding) share the same injection. On first boot the scoped home is provisioned with a `config.toml` — the user's own config with every `api_key` blanked and migrated onto the env-key shape, or a minimal managed config when the user has none. The OAuth era's `credentials/` and `oauth/` directories are swept on every provision — this package no longer reads them, and keeping them would let a dead grant authenticate while the status reads unauthenticated. `/kimi logout` deletes the scope's `endpoint-auth.json`; when the credential comes entirely from the profile row, logout refuses and names the profile as the place to edit.
110
-
111
- **Mounting.** The bundle patch registers the `kimi` harness (exactly one provider row); the `subagent_kimi` tool is this package's `./tool` composition entry (sharing the family core's `./tool-factory` implementation), granted per session by an agent preset that names it — the dev preset's `tool-subagent-kimi` row is the grant point. The `kimi-cli` one-shot provider spawns `kimi -p` under the scoped home. The family core (`local-agent` row, shared scoped-homes root) ships in `@khorsheed/dsh-local-agent`'s own patch, declared here as a dependency. The browser settings card ships with this package's own `./client` half, composing the family core's shared building blocks (the auth block, the model picker): it renders as a section of the core's「Local Agent Delegation」family card, mounted through `configForms.whileServed` while the Host serves the `local-agent-kimi` namespace — one section for a standalone install, a family bundle, or a mode pack alike (on an older core, this package's own `plugins.item` card instead). The identity triangle stays consistent: the `cordis.patch.yml` row id, the package.json name, and tsdown's `clientBundle('@khorsheed/dsh-local-agent-kimi')`.
112
-
113
- **Session records and transcripts.** `/kimi sessions` lists the scoped home's `session_index.jsonl` — this harness's delegations, never the user's personal sessions. `/kimi session <id>` reads that session's `wire.jsonl` and renders a readable transcript: user prompts, thinking, and assistant replies are tagged with their wire turn number (1-based, matching the child session's `turn/start` numbering), tool calls render with arguments and results paired to their calls (file-editing calls render patch-style, unknown content types keep a visible marker), and kimi's auto-permission `<system-reminder>` messages are filtered out. The settings card shows auth status and the scoped sessions narrowed to the current workspace; while a login is pending the status keeps re-probing until credentials land.
114
-
115
- **Model readback and the cwd override.** After every settled round the provider reports the actual model from the wire.jsonl `usage.record` (falling back to `llm.request`) events' `model` field — last one seen, since a resumed session's later rounds append later records — through the `settled` run-progress event, and merges it into the delegation record's `observedModel` field; absence is recorded, never guessed. An orchestrator may also pass a per-round working directory through the facade's `DelegationCallOptions.cwd` (recorded as the record's `cwd`); when a resume round resolves to a different directory than the recorded first round, it fails loud before any process spawns — a CLI session continues in the directory its first round ran in.
116
-
117
- **Model broker.** The harness registers a `modelBroker` with the registry: the settings card reads the memberless `modelInfo` (effective layer + choices) and the member composer reads and writes the per-member override through the gateway. The resolution order is fixed: override → the delegation's recorded model → the scope's `models.json` first entry → the plugin `model` key → the scoped `default_model` → the CLI's built-in default (which names nothing). Choices: a non-empty `models.json` is the COMPLETE vocabulary (nothing outside the endpoint's served catalog sneaks in); empty falls back to the legacy chain — the deduped union of the key, the scoped default, the config's `[models."…"]` tables, and the recent saves. The override and the start-model ledger are in-memory (cleared on restart); `setMemberModel` throws while the member has a round in flight, and otherwise retires the resident runtime when its bound model differs from the new effective one (a same-model switch is a no-op) — the next round respawns lazily.
118
-
119
- **Tool-call accounting.** Every settled round also reports how many tool calls it made, on the `settled` run-progress event (`toolCalls: { count, byName }`). What is counted is the transcript's `tool.call` lines carrying THIS ROUND'S TURN — deliberately not the mirror window: in resident mode a live poll may have drained the settle pass's delta, and a resume round must not inherit the earlier rounds' calls. `byName` keys are the tool names the wire gave, verbatim. One accounting per round, never cumulative; a round that called nothing carries no field at all (absent is not zero).
120
-
121
- **Resume.** A fresh delegation's result text self-describes the handle (`追问请带 resume="<childSessionId>"`); passing it back as the tool's optional `resume` parameter continues the same kimi session (`kimi -S session_<id> -p`) inside the same dsh child session. The handle never rides the prompt: it is resolved through the `localAgent` delegation registry only for the same parent session and provider that recorded the delegation — a forged handle is rejected before any CLI process starts.
122
-
123
- **Isolation and accounting.** The child is a fresh session in the delegating session's workspace; the parent receives only the final answer or the exact error — child context, commentary, tool activity, and diffs never cross into the parent session. The provider opens `turn/start` at spawn and closes `turn/end` at settle, including on failure or abort (reason `error`/`aborted`), so durations equal real CLI runtime. Every mirrored step (assistant message, tool call/result) is wrapped in a `step/start`–`step/end` boundary pair at the same (turn, step) — the host's live conversation assembler registers a step only at its boundaries, so without them assistant messages do not render in the real-time view (only a full rebuild recovers them); the token granularity's streaming snapshots and completion folds also land before `turn/end`, boundaries included. Usage is the sum of the round's `usage.record` deltas (each one LLM request, not cumulative), carried on the round's final mirrored assistant message; the mirror filters kimi's auto-permission `<system-reminder>` messages, renders tool calls with arguments, pairs results to their calls, and advances incrementally so earlier messages never duplicate. Aborting settles the tool result immediately (SIGTERM→grace→SIGKILL) and keeps the partial work already mirrored.
124
-
125
- **Named scopes.** a named scope opens a second `KIMI_CODE_HOME` at `<homesRoot>/kimi@<name>`; the directory is provisioned with the same two steps in the same order (provider/model config first, then the permission rules — the permission write reads the config file). From then on that scope has its own endpoint-auth.json, its own wire log and its own transcript mirror. A scoped delegation is exec-only (the resident `kimi acp` is bound per member to the default scoped home) and carries **no member channel**: the bridge declaration is written into a scoped home's `mcp.json` and the socket is a single homes-root one, so a named absence beats a half-wired presence.
126
-
127
- **Container delegation.** An orchestrator may run the round inside an **already-acquired container** through the facade's `DelegationCallOptions.exec` (`{ container, workdir, env? }`): the argv becomes `docker exec -w <workdir> [-e NAME…] <container> kimi -p …` and everything else (the wire.jsonl mirror and readback, settle, recording) is byte-for-byte unchanged. `env` must name the in-container `KIMI_CODE_HOME`, and it should be the read-write bind mount of the host scoped home — the transcript mirror and the model readback read the host copy of the wire log. A container round always takes the exec one-shot (the resident `kimi acp` is a host process) and **does not write** the member-bridge entry into `mcp.json`: that declaration names a host node path the unit cannot start, and leaving a broken server in a shared config file is worse than running one round without the member channel.
128
-
129
- **Live driver (`live: true`).** Replaces the per-round spawn: the member's first delegation brings up one resident `kimi acp` process (ACP over stdio; the handshake requires the `loadSession` capability, otherwise the breaker falls back), `session/new` creates the session (the server-assigned id becomes the delegation record's `cliSessionId`), and every later round is one `session/prompt`; `cancel` lands as `session/cancel` — the process survives and the session stays continuable. The member bridge rides the ACP `mcpServers` inline declaration (no mcp.json write). `session/request_permission` is auto-answered unattended (first allow option, cancelled when none — matching `kimi -p`'s auto-approve). **Mirroring of completed items deliberately stays on the file fold**: ACP pushes token-level chunks, which are not isomorphic to the wire.jsonl line fold, so pushes only trigger throttled `mirrorKimiDelta` passes and the settle pass stays authoritative — one fold, one offset, and the two driver paths cannot drift. Live output folds each completed item 1:1; generation-time text uses the shared transient channel with a maximum batching wait of 50ms. Incremental recovery checkpoints are independent of browser publication, and native final messages replace transient presentation at the reserved (turn, step). Aborted streams retain a final message marked interrupted. Runtimes are reclaimed after an idle timeout (stdin EOF → SIGTERM ladder); after a crash the next round re-spawns and `session/load`s the on-disk session.
130
-
131
- </details>
41
+ Needs DSH 0.1.5-rc.1 or later; verified on 0.2.1-rc.1.
132
42
 
133
- ## Development
43
+ ## For developers
134
44
 
135
- Part of the [dsh-plugins](https://github.com/Khorsheed/dsh-plugins) monorepo (`packages/local-agent-kimi`). Issues and contributions welcome there.
45
+ - Config keys, the default-model order, the scoped home, where the endpoint credential is stored, the resident driver, and in-container delegation are in the [full reference](https://github.com/Khorsheed/dsh-plugins/blob/main/packages/local-agent-kimi/docs/reference.en.md).
46
+ - To install it alone, name the core too: `dsh plugin --profile web add @khorsheed/dsh-local-agent @khorsheed/dsh-local-agent-kimi`; the delegation tool is granted by a mode and won't appear unless a mode names it.
47
+ - Part of [dsh-plugins](https://github.com/Khorsheed/dsh-plugins); open issues and contributions there. Changes: [CHANGELOG.md](CHANGELOG.md).
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # last confirmed-consistent state. Both languages carry equal authority; after
3
3
  # editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/local-agent-kimi/README.en.md
5
- packages/local-agent-kimi/README.en.md: 15fa4b8608ecf1d1e535cfe69f2d4b0e116a62cb
6
- packages/local-agent-kimi/README.md: 62b45828587f0341ab8569c5d687d5dead5b0413
5
+ packages/local-agent-kimi/README.en.md: 8f0813f18bc811196a0eb15c90fa5b6660515a51
6
+ packages/local-agent-kimi/README.md: 2257a947e66a8db09eea80bd83faa57ba335c709
package/README.md CHANGED
@@ -2,134 +2,46 @@
2
2
 
3
3
  [English](README.en.md) | 中文
4
4
 
5
- 把任务从任意 dsh 会话委派给本机的 Kimi Code CLI——它跑在自己的作用域目录里,你的 `~/.kimi-code` 分文不动。
5
+ 把活交给你电脑上的 Kimi Code:过程实时看得见,跑完结果回到当前会话,还能接着聊。
6
6
 
7
- 想让模型把一整块活交给另一个编码 agent,以前只能自己开终端、复制粘贴、再把结果搬回来。这个插件给每个 agent preset 配上 `subagent_kimi` 委派工具和 `/kimi` 命令族:委派在会话工作区的子会话里执行,转写与进度直接出现在子代理界面,结果带着真实用量与耗时回来,还能用同一句柄续聊。
7
+ 想让 Kimi Code 帮一把,以前得自己开终端、复制粘贴、再把结果搬回来。装上之后,你在会话里说一句「这块交给 Kimi」,agent 就把任务连同要求交给本机的 Kimi Code;它的思考、工具调用和回复实时出现在子会话里,跑完把结果带回来,附上真实的用量和耗时。Kimi 在自己单独的目录里运行,你电脑上原来的 Kimi 配置和会话一点不碰。
8
8
 
9
- <img src="https://raw.githubusercontent.com/Khorsheed/dsh-basic/main/docs/screenshots/local-agent-kimi-settings.png" width="640" alt="Kimi 设置卡:认证状态、登录/退出、默认模型与常驻模式开关">
9
+ <img src="https://raw.githubusercontent.com/Khorsheed/dsh-basic/main/docs/screenshots/local-agent-kimi.png" width="560" alt="展开的 Kimi 一节:已登录的 Kimi Code 和版本号,端点地址、API Key、「验证端点并获取模型」,可用模型名单和常驻模式开关">
10
10
 
11
- ## 特性
11
+ ## 能做什么
12
12
 
13
- - **按会话授予的委派**——`subagent_kimi` 工具是本包的 `./tool` 组合入口,由点名它的 agent 预设(如开发模式)授予该预设的会话;其余预设的会话看不到它。
14
- - **作用域目录**——config、凭据、会话全部留在 `$DSH_HOME/local-agent/kimi`,与你自己的 `~/.kimi-code` 互不干扰。
15
- - **端点凭据(唯一的认证方式)**——设置卡「认证」区填 `baseUrl` + `apiKey`(保存进默认 scope 的 `endpoint-auth.json`,0600,只存本机)或预配在 profile 配置行即已认证;每个命名 scope 可用自己的 `endpoint-auth.json` 按字段覆盖部署级配置。managed provider 经 `api_key_env` 从子进程环境读 key——密钥不落 `config.toml`(它要进评测条件指纹)。容器轮与宿主轮用同一套凭据,容器里不需要再授权一次。没有网页登录、没有 device-code。旁边的「验证端点并获取模型」按钮对**已保存**的端点跑一次无 token 探测(`GET <baseUrl>/v1/models`,Bearer 头),回执可达性与端点当前供应的模型列表。
16
- - **可续聊的委派**——把结果自述的 `resume` 句柄传回,即继续同一个 Kimi 会话,并按轮记录真实用量与耗时。
17
- - **会话记录与转写回放**——`/kimi sessions` 列出本 harness 的委派记录(绝不含你的私人会话);`/kimi session <id>` 把该会话的 wire 日志渲染成可读转写——思考、工具调用与结果一目了然。
18
- - **设置卡片**——core 的「本机 Agent 委派」家族卡里的一节(Plugins 页;旧版 core 上回落为本包自己的 `plugins.item` 卡,宿主服务 `local-agent-kimi` 命名空间时挂载)一眼看清认证状态与作用域会话,登录/退出、可用模型(有序短名单,第一个为默认;留空 = 跟随旧链)、常驻模式开关全部热生效,无需重载。
19
- - **模型回读与独立工作目录**——每轮从 wire.jsonl 的 usage/request 记录回读实际模型,写进委派记录;编排器可用 `cwd` 选项给每格独立目录,resume 换目录即拒绝。
20
- - **常驻驱动(可选)**——`live: true` 让每个成员常驻一个 `kimi acp` 进程,按轮 `session/prompt`,支持运行时级优雅取消;关闭或通道不可用即回一次性 `kimi -p`。
13
+ - **一句话交出去**:告诉 agent 哪段活给 Kimi,它会自己写好要求交过去,结果回到当前会话。
14
+ - **过程看得见**:子会话里一步一步列出 Kimi 的思考、调用的工具和回复,刷新页面也还在,不用等到最后才知道它干了什么。
15
+ - **接着聊,不冷启动**:结果不满意就让 agent 追问,或者打开子会话直接给它发消息,继续的是同一个 Kimi 会话。
16
+ - **填好 key 就能用**:在设置卡片里填端点地址和 API Key,点「保存凭据」,再点「验证端点并获取模型」确认能连上。
17
+ - **自己挑模型**:在「可用模型」里从端点供应的模型中勾选、拖动排序,排第一的就是默认模型;子会话里也能临时换模型和推理强度。
18
+ - **常驻模式更快**:打开「常驻模式(live)」,Kimi 进程常驻,输出实时流进子会话,停下也不用重开进程。
19
+ - **翻看以前的委派**:`/kimi sessions` 列出交给 Kimi 的历史任务,`/kimi session <编号>` 把其中一次整理成可读的记录。
21
20
 
22
21
  ## 安装
23
22
 
24
- 需要一个可运行的 dsh profile,且 `PATH` 上有 Kimi Code CLI(`kimi`)——插件既不替你安装,也不替你准备凭据。
23
+ 先在电脑上装好 Kimi Code CLI(命令行里能运行 `kimi`),插件不替你装。然后在 DSH 的「插件 → 添加插件」里输入下面的包名,点安装:
25
24
 
26
- ```sh
27
- # 两个都得点名:`dsh plugin add` 只调和直接依赖。
28
- dsh plugin --profile web add @khorsheed/dsh-local-agent
29
- dsh plugin --profile web add @khorsheed/dsh-local-agent-kimi
30
25
  ```
31
-
32
- 重启 web 实例后生效,然后在「本机 Agent 委派」家族卡(Plugins 页)的 Kimi 一节「认证」区填端点与 key 即可(也可预配在 profile 的本包配置行);都不配则状态为未认证。卸载:
33
-
34
- ```sh
35
- dsh plugin --profile web remove @khorsheed/dsh-local-agent-kimi
36
- ```
37
-
38
- 作用域目录会被刻意保留,重装后凭据仍在——删除 `$DSH_HOME/local-agent/kimi` 即可清除全部痕迹。
39
-
40
- ## 配置
41
-
42
- 可选:经作用域 `config.toml`(`$DSH_HOME/local-agent/kimi/config.toml`)把 Kimi 的 LLM 请求路由到你自己的端点:
43
-
44
- ```toml
45
- [providers."managed:kimi-code"]
46
- base_url = "https://your-router.example/v1"
47
- ```
48
-
49
- **只改写这一个键**——预置逻辑从不覆盖已存在的 config,且 `[services.moonshot_*]` 的 base_url 必须保留(它们路由内置的搜索/抓取工具)。
50
-
51
- ⚠️ **凭据暴露**:端点 key 会发送给处理请求的端点——`baseUrl` 只指向你控制或信任的端点。
52
-
53
- 插件自身配置(可选,写在 profile patch 层):
54
-
55
- ```yaml
56
- - id: local-agent-kimi
57
- config:
58
- model: kimi-code/k3 # 可选:每轮委派以它起 CLI;不写就一个模型参数都不传(见下)
59
- thinkingEffort: high # 推理强度;写入「全新」作用域 config.toml 的 [thinking] effort 与模型 default_effort(low/high/max,默认 high)。仅预置期生效——已存在的 config 永不覆盖
60
- live: false # 常驻驱动:每成员常驻一个 kimi acp 进程,按轮发 session/prompt(runtime 级优雅取消 session/cancel、推送触发的镜像);关闭或通道不可用即回一次性 kimi -p
61
- liveIdleMs: 1800000 # 常驻 runtime 空闲回收时限(默认 30 分钟)
26
+ @khorsheed/dsh-bundle-local-agent
62
27
  ```
63
28
 
64
- **迁移提示。** live 轮次统一消费增量输出:旧 `liveMirrorGranularity: event | token` 键继续兼容读取,但不再影响行为,也不会改变运行中的进程。评测继续保留 exec。最终内容仍以 provider 完成项为准,包括工具记录和用量。
65
-
66
- ### 默认模型(`model`)
67
-
68
- ⚠️ **这个键的语义变了。** 旧版里 `model` 只在**首次预置**全新作用域目录时用一次——写进 `config.toml` 的 `default_model`,已存在的 config 不动。现在它**每轮委派都生效**。首次预置的镜像行为保留:全新的、没有用户 config 可镜像的作用域目录,仍然按它写出最小 managed config。
69
-
70
- **不写 = 今天的表现。** 没有这个键时,本插件在 argv 上一个模型参数都不加,跑哪个模型由作用域 `config.toml` 的顶层 `default_model` 决定。
71
-
72
- **写了 = 每轮委派以它起 CLI。** 值必须是作用域 `config.toml` 里已定义的那个模型名(`[models."…"]` 的键)——`-m` 是按 kimi 自己的模型表解析的。
73
-
74
- | 驱动 | 传法 |
75
- |---|---|
76
- | 一次性(默认) | `kimi -m <模型> -p <任务>`;resume 轮为 `kimi -S <会话> -m <模型> -p <任务>`——`-S` 仍在最前,`-m` 紧贴 `-p`(`-p` 之后的词会被当成提示词) |
77
- | 常驻(`live: true`) | `kimi acp` **没有**模型旗标,所以每次起常驻进程前,把作用域 `config.toml` 的顶层 `default_model` 改写成该值。改写是就地、幂等的:只动顶层那一行,注释、模型表、provider、`[thinking]` 全部逐字节保留;没有 config 可写时不新建(预置逻辑才负责创建),该轮照跑,模型回读负责暴露不一致 |
78
-
79
- 也就是说:一次性驱动不碰你的 `config.toml`,常驻驱动会改写其中的 `default_model` 一行。
80
-
81
- 设置卡「可用模型」区维护一份**有序模型短名单**:点「添加模型」从端点当前供应的目录里勾选加入,列表里只会有端点真实供应的模型;拖动行调整顺序。**第一个模型就是默认模型**——每轮委派以它起 CLI(一次性 argv 旗标,常驻模式起进程前改写作用域 `default_model`),优先级只低于成员会话级覆盖与委派级指定。列表保存在作用域目录的 `models.json`(每个命名 scope 可各有一份,与端点凭据同一套文件机制),编辑即保存,下一轮委派生效。**留空 = 回退旧链**(`model` 键 → 作用域 `config.toml` 的顶层 `default_model` → CLI 内置)。kimi 的 `-m` 按作用域 config 的 `[models."…"]` 表解析(kimi-cli 2.1.1 实测:裸端点 id 没有表不能跑),所以加入一个还没有表的端点 id 时,同一次写入会按 managed 形状补上它的表(端点上报的显示名/推理档位/上下文窗口随行)。成员级模型和推理强度修改使用下文的持久控制面。
82
-
83
- 目录词汇来自端点本身(`GET <baseUrl>/v1/models`),作用域 config 的模型表只做元数据补全:端点供应的 id 命中某张 managed 表的 `model` 时,候选值取**表键**(`-m` 真正可运行的名字),显示名与推理档位端点优先、表兜底。常驻成员的 ACP 原生 configOptions 仍是该成员的权威目录(保留显示名及当前模型的推理选项)。端点无凭据、拒绝凭据、不应答或答非 `/models` 形态时,目录带原因空载;传输故障保留最后一次成功快照并按缓存节奏重试。查询不创建临时 ACP 会话。目录刷新与订阅共用 core 缓存,共用模型菜单和成员 effort 控制已接入。运行中选择排到下一完整轮次(含工具续跑);core 统一持有当前/待生效配置、撤销与重试,冻结评测成员禁止变更。
29
+ Kimi 会跟着「多Agent协作」套件一起装好(各家本机 agent 共用同一个底座,单装用不起来);如果你主要写代码,直接装开发套件 `@khorsheed/dsh-dev-suite` 也包含它。装完重启 DSH,到「插件」页的「本机 Agent 委派」卡片里,展开 Kimi 一节填好端点和 API Key。
84
30
 
85
- **委派级的模型优先。** 编排器可以经门面 `DelegationCallOptions.model` 给**某一次委派**点名模型,它排在这个键之前(顺序见家族核心 README)。首轮请求的值记进委派记录,resume 轮照它重发——resume 不接受 model 参数。常驻模式下它成为该成员的**起始模型**:起进程前改写作用域 `default_model` 绑定;已有常驻 runtime 绑着别的模型时先退役,以新模型重起并 `session/load` 续上同一个 CLI 会话。
86
-
87
- **成员级切换(composer)。** 成员会话的 composer 可以为该成员切换模型:一个**会话级 override**,排在所有层(含委派记录)之前;只存内存,宿主重启即失效。常驻模式下,切换让绑定模型不同的常驻 runtime 退役——下一轮以新模型重起、`session/load` 续上同一个 CLI 会话,对话本身不断;一次性模式下下一轮 `-m` 直接带新值。
88
-
89
- **这不是评测的缺口。** 评测 run 的条件在建立时冻结:run 跑到一半改这个键,下一轮的模型回读会发现声明模型 ≠ 实测模型,run 直接判为 misattributed 而失败(冻结决策 5)。
90
-
91
- **评测快照(effectiveSettings)。** 本 harness 向注册表声明一份实时读取的公平性设置快照,供评测条件哈希使用:drive(exec/live,随 live 偏好)、推理强度(读作用域 config 的 `[thinking] effort`,缺则回模型 `default_effort`)、是否自动批准(作用域 config 是否带 `Bash(*)` 放行规则)、端点是否固定(只报主机名;managed 端点不算固定)、已配置模型(先看作用域 `models.json` 的首项,没有才看插件配置的 `model` 键——它每轮覆盖;再没有才读作用域 config 的顶层 `default_model`;都没有就不给字段)、CLI 版本(`kimi --version`,按可执行文件路径+mtime 缓存;探测不到即字段缺位)。`/kimi status` 与 `LocalAgentStatus` Remote 附带同一份快照。web-eval 冻结决策 2 到 4 的显式化即由此读取。
92
-
93
- ## Compatibility
94
-
95
- - npm 发布线(`@deepseek-ai/dsh@0.1.5-rc.1`):✅ 公开 API 兼容——生成中的内容走 local-agent 瞬时 Remote 与公开 Conversation 节点;后缀检查点负责恢复,最终原生消息保留转写与用量语义。minHost 为 0.1.5-rc.1,更旧宿主请停留在旧发布线。0.1.5 退役了 per-chunk 会话事件:token 粒度的增量不再落进子会话日志——改走 run-progress 通道,轮次 settle 为一条合并的 assistant/message(最终文本一致);晚到的 usage 若其载体消息已经镜像,则带一条 warn 丢弃(宿主没有 usage 回填事件可挂)。设置卡渲染为 core「本机 Agent 委派」家族卡的一节(Plugins 页 core 的 `plugins.item` 条目,0.1.7-alpha.1+;旧版 core 上回落为本包自己的 `plugins.item` 卡),`configForms.whileServed` 随宿主服务的 `local-agent-kimi` 命名空间挂载;0.1.5 线不再呈现卡片(宿主删除了 `settings.plugin.item` 席位),其余表面不变。
96
- - 源码线(deepseek-harness master):✅(verifiedHost: 0.2.1-rc.1)——host-021 波对 0.2.1-rc.1 树全量 build+test 绿;委派迁移到 `ctx.subagents.startActivation`(受管 activation),run.id 改为每次执行唯一。`thinkingEffort` 配置项(默认 high、仅预置期生效)与 `effectiveSettings` 评测快照均为插件级实现:只读写作用域文件,在两条宿主线上都不依赖宿主 API。
31
+ 把活交给 Kimi 要在带委派的模式里进行,比如「开发模式」:开一个新会话、选这个模式,对 agent 说「把这个交给 Kimi」。在其它模式里看不到 Kimi 委派是正常的。
97
32
 
98
33
  ## 已知限制
99
34
 
100
- - **没有网页登录**——认证只有端点凭据一条路(设置卡/profile 行,kimi-for-coding 平台 key 或中转 key 均可);kimi 会员的 OAuth 路径不在本包。
101
- - **进程簿记会写真实 home**——无论 `KIMI_CODE_HOME` 如何,kimi 都会写入无实质内容的 `~/.kimi-code/server/instances/*.json`;config、凭据、会话仍在作用域内。
102
- - **`/kimi` 命令需要 Web 会话**——headless profile 仍可通过挂载工具行的组合进行委派。
103
-
104
- ## 实现原理
105
-
106
- <details>
107
- <summary>内部结构(点击展开)</summary>
108
-
109
- **作用域目录与凭据。** 本包启动的每个 Kimi 进程都以 `KIMI_CODE_HOME=$DSH_HOME/local-agent/kimi` 运行。认证是端点凭据制:scope 的 `endpoint-auth.json`(0600)按字段覆盖 profile 配置行的 `baseUrl`/`apiKey`;managed provider(`managed:kimi-code`)在 config.toml 里声明的是 `api_key_env = "DSH_KIMI_ENDPOINT_KEY"`(kimi CLI 原生支持从指定环境变量读 key,与内联 `api_key` 互斥),key 只存在于 endpoint-auth.json 和子进程环境里,`config.toml` 永不携带秘密、可以安全进入评测条件哈希。设置卡「认证」区编辑的就是默认 scope 的 endpoint-auth.json(经家族 gateway 的 `endpointAuth`/`configureEndpoint` Remote);保存 baseUrl 时同一次写入会把 managed provider 的 `base_url` 重指过去(清空即回落到 kimi 官方服务),每轮 spawn 前还有一次幂等校准,手改文件同样即时生效。一次性 `kimi -p`、常驻 `kimi acp`、容器轮(`containerExecSpawn` 按名字转发环境变量)三条路共用同一套注入。首次启动时作用域目录会被预置一份 `config.toml`——把用户自己的 config 中所有 `api_key` 抹空后复制并迁移到 env-key 形态,用户没有 config 时则写入最小 managed config。OAuth 时代的 `credentials/` 与 `oauth/` 目录在每次 provision 时被清扫——本包不再读取它们,留着只会让一份失效授权在状态显示未认证时仍悄悄可用。`/kimi logout` 删除 scope 的 `endpoint-auth.json`;凭据完全来自 profile 配置行时 logout 拒绝并提示去改 profile。
110
-
111
- **挂载。** bundle patch 注册 `kimi` harness(恰好一行 provider 行);`subagent_kimi` 工具是本包的 `./tool` 组合入口(实现共享自家族核的 `./tool-factory` 导出),由点名它的 agent 预设按会话授予——dev 预设的 `tool-subagent-kimi` 行是授予点。`kimi-cli` 一次性 provider 在作用域目录下 spawn `kimi -p`。家族 core(`local-agent` 行,共享作用域目录根)随 `@khorsheed/dsh-local-agent` 自己的 patch 提供,本包把它声明为依赖。浏览器设置卡片由本包的 `./client` 半提供,复用家族 core 的共享构件(认证块、模型选择器):渲染为 core「本机 Agent 委派」家族卡的一节,宿主服务 `local-agent-kimi` 命名空间时经 `configForms.whileServed` 挂载——独立安装、家族 bundle、模式包都是同一节(旧版 core 上回落为本包自己的 `plugins.item` 卡)。身份三角保持一致:`cordis.patch.yml` 的行 id、package.json 的 name、tsdown 的 `clientBundle('@khorsheed/dsh-local-agent-kimi')`。
35
+ - 只支持端点和 API Key(Kimi 编程平台的 key 或中转的 key 都行),不支持 Kimi 会员的网页登录。
36
+ - Kimi 仍会在你的 `~/.kimi-code` 里写几份没有实际内容的进程记录;配置、凭据和会话都留在插件自己的目录里。
37
+ - `/kimi` 这组命令只能在网页会话里用。
112
38
 
113
- **会话记录与转写。** `/kimi sessions` 列出作用域目录下的 `session_index.jsonl`——本 harness 的委派,绝不是用户的私人会话。`/kimi session <id>` 读取该会话的 `wire.jsonl` 渲染成可读转写:用户提示、思考与助手回复逐行标注 wire 轮次号(1 起,与子会话 `turn/start` 编号一致),工具调用带参数渲染、结果按调用配对(文件编辑类调用渲染成 patch 形态,不认识的内容类型保留可见标记),kimi 自动权限模式的 `<system-reminder>` 消息被过滤。设置卡片呈现认证状态与收窄到当前工作区的作用域会话;登录进行中时状态会持续重新探测,直到凭据落地。
114
-
115
- **模型回读与 cwd 覆盖。** 每轮 settle 后,provider 把 wire.jsonl 里 `usage.record`(次选 `llm.request`)事件 `model` 字段的实际模型(最后一个为准——resume 会话后续轮次追加在文件尾部)随 `settled` 进度事件上报,并合并进 `delegations.jsonl` 的 `observedModel` 字段;取不到即缺位,绝不猜测。编排器还可以经门面 `DelegationCallOptions.cwd` 给本轮指定工作目录(记录进 `cwd` 字段);resume 轮解析出的目录若与首轮记录不一致,进程启动前即 fail loud——CLI 会话延续的是首轮所在目录的上下文。
116
-
117
- **Model broker。** 本 harness 向注册表声明 `modelBroker`:设置卡读无成员的 `modelInfo`(生效层 + 候选),成员 composer 经 gateway 读写成员级 override。解析顺序固定:override → 委派记录模型 → 作用域 `models.json` 首项 → 插件 `model` 键 → 作用域 `default_model` → CLI 内置默认(不指名任何模型)。候选:作用域 `models.json` 非空时它就是**全部**词汇(端点目录外的一个也不混入);为空时回退旧链 = 本键 + 作用域默认 + config 的 `[models."…"]` 表 + 最近存值,去重。override 与起始模型账本都在内存(重启即清);`setMemberModel` 在成员有进行中轮次时抛错,否则在常驻 runtime 绑定模型 ≠ 新生效值时将其退役(同模型是 no-op),下一轮懒重起。
118
-
119
- **工具调用计数。** 每轮 settle 时,provider 顺带数出本轮的工具调用,随 `settled` 进度事件上报(`toolCalls: { count, byName }`)。数的是 transcript 里**本轮 turn** 的 `tool.call` 行——刻意不按镜像窗口数:常驻模式下 settle 那一遍的 delta 可能已被 live 轮询清空,而 resume 轮也不该把前几轮的调用算进来。`byName` 的键是 wire 给出的工具名,原样保留。本轮一份,绝不累计;一次都没调用就整个字段缺位(缺席 ≠ 0)。
120
-
121
- **续聊(resume)。** 首次委派的结果文本自述句柄(`追问请带 resume="<childSessionId>"`);把它作为工具的可选 `resume` 参数传回,即在同一个 dsh 子会话里继续同一个 kimi 会话(`kimi -S session_<id> -p`)。句柄绝不进 prompt:它只经 `localAgent` 委派 registry 对记录该委派的同一 parent 会话与 provider 解析——伪造的句柄在任何 CLI 进程启动前就被拒绝。
122
-
123
- **隔离与记账。** 子会话是委派会话工作区内一个全新会话;父级只收到最终回答或精确错误——子会话的上下文、评论、工具活动与 diff 永不跨入父级会话。provider 在 spawn 时开 `turn/start`、settle 时关 `turn/end`,失败或被中止也会关(reason `error`/`aborted`),因此耗时等于真实 CLI 运行时长。每个镜像 step(assistant 消息、工具调用/结果)都包在同 (turn, step) 的 `step/start`–`step/end` 边界对里——宿主会话的实时装配只在边界上登记 step,缺了边界 assistant 消息在实时视图里不渲染(整页刷新重建时才补回);token 粒度的流式快照与收尾折叠也在 `turn/end` 之前落地并带边界。用量是该轮 delta 内所有 `usage.record` 之和(每条是一次 LLM 请求的口径、非累计),挂在当轮最后一条镜像的 assistant 消息上;镜像过滤 kimi 自动权限模式的 `<system-reminder>` 消息、工具调用带参数渲染、结果按调用配对,并增量推进,早期消息绝不重复。中止会让工具结果立即 settle(SIGTERM→grace→SIGKILL),并保留已镜像的部分成果。
124
-
125
- **命名 scope。** `/kimi login --scope <名>` 在 `<homesRoot>/kimi@<名>` 里另开一份 `KIMI_CODE_HOME`:目录建立时跑同一份 provision(provider/model 配置,然后是权限规则——顺序不能反,权限写入要读配置文件),之后该 scope 各自的 endpoint-auth.json、各自 wire 日志、各自转写镜像。带 scope 的委派只走 exec(常驻 `kimi acp` 按成员绑缺省目录),且**不带成员通道**:成员桥声明写在作用域目录的 `mcp.json` 里、socket 又是 homes 根级单例,与其半接上不如这一轮明确不要。
126
-
127
- **容器内委派。** 编排器可以经门面 `DelegationCallOptions.exec`(`{ container, workdir, env? }`)让本轮跑在一个**已取得的容器**里:argv 变成 `docker exec -w <workdir> [-e NAME…] <container> kimi -p …`,其余(wire.jsonl 镜像与回读、settle、记录)逐字节不变。`env` 必须给出容器内的 `KIMI_CODE_HOME`,且它应当是宿主作用域目录的 rw bind 挂载点——转写镜像与模型回读读的是宿主那份 wire 日志。容器轮固定走 exec 一次性驱动(常驻 `kimi acp` 是宿主进程),且**不写** `mcp.json` 的成员桥条目:那条声明带着宿主 node 路径,容器里起不来,与其在共享配置文件里留一个坏 server,不如这一轮不要成员通道。
128
-
129
- **常驻驱动(`live: true`)。** 替代每轮 spawn:成员首轮委派拉起一个常驻 `kimi acp` 进程(ACP over stdio;握手要求 `loadSession` 能力,否则熔断回退),`session/new` 建会话(server 分配 id,即委派记录的 `cliSessionId`),之后每轮 = `session/prompt`;`cancel` 落地为 `session/cancel`——进程不死、会话可续。成员桥经 ACP `mcpServers` 内联声明(不写 mcp.json)。`session/request_permission` 按无人值守策略自动应答(选第一个 allow,无则 cancelled,与 `kimi -p` 的自动批准一致)。**完成项的镜像刻意仍是文件折叠**:ACP 推送的是 token 级 chunk,与 wire.jsonl 行折叠不同构,所以推送只触发节流的 `mirrorKimiDelta` 过一遍,settle 对账仍是权威——单一折叠、单一 offset,两条驱动路径不可能漂移;实时输出把完成子项 1:1 全量折叠,生成中的文本经共用瞬时通道发布,默认最多合并 50ms;增量恢复检查点独立于浏览器发布,最终原生消息在预留的 (turn, step) 替换临时展示,中止的流保留带 interrupted 的最终消息。runtime 空闲超时回收(stdin EOF → SIGTERM 阶梯),崩溃后下一轮自动重连并 `session/load` 盘上的会话。
39
+ ## Compatibility
130
40
 
131
- </details>
41
+ 需要 DSH 0.1.5-rc.1 或更新版本,已在 0.2.1-rc.1 上验证。
132
42
 
133
- ## 开发
43
+ ## 给开发者
134
44
 
135
- 隶属 [dsh-plugins](https://github.com/Khorsheed/dsh-plugins) monorepo(`packages/local-agent-kimi`)。问题与贡献请移步该仓库。
45
+ - 配置项、默认模型的取值顺序、作用域目录、端点凭据的存放、常驻驱动和容器内委派等细节,都在[完整参考](https://github.com/Khorsheed/dsh-plugins/blob/main/packages/local-agent-kimi/docs/reference.md)里。
46
+ - 单独安装要连同底座一起点名:`dsh plugin --profile web add @khorsheed/dsh-local-agent @khorsheed/dsh-local-agent-kimi`;委派工具由模式授予,没有模式点名时不会出现。
47
+ - 隶属 [dsh-plugins](https://github.com/Khorsheed/dsh-plugins),问题与贡献请到该仓库;变更见 [CHANGELOG.md](CHANGELOG.md)。