@khorsheed/dsh-local-agent-kimi 0.1.0-rc.6
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/README.en.md +132 -0
- package/README.i18n.yaml +6 -0
- package/README.md +132 -0
- package/cordis.patch.yml +34 -0
- package/lib/client.js +1066 -0
- package/lib/index.js +4716 -0
- package/lib/invariant.js +31 -0
- package/lib/types/client/SettingsCard.d.ts +77 -0
- package/lib/types/client/SettingsCard.js +197 -0
- package/lib/types/client/icons.d.ts +18 -0
- package/lib/types/client/icons.js +2 -0
- package/lib/types/client/index.d.ts +42 -0
- package/lib/types/client/index.js +89 -0
- package/lib/types/client/locales.d.ts +64 -0
- package/lib/types/client/locales.js +55 -0
- package/lib/types/credential-guard.d.ts +29 -0
- package/lib/types/credential-guard.js +107 -0
- package/lib/types/index.d.ts +69 -0
- package/lib/types/index.js +270 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/invariant.js +33 -0
- package/lib/types/kimi-cli-provider.d.ts +215 -0
- package/lib/types/kimi-cli-provider.js +855 -0
- package/lib/types/live-driver.d.ts +245 -0
- package/lib/types/live-driver.js +1312 -0
- package/lib/types/live-switch.d.ts +78 -0
- package/lib/types/live-switch.js +112 -0
- package/lib/types/member-bridge-config.d.ts +43 -0
- package/lib/types/member-bridge-config.js +80 -0
- package/lib/types/model-broker.d.ts +97 -0
- package/lib/types/model-broker.js +205 -0
- package/lib/types/model-catalog.d.ts +26 -0
- package/lib/types/model-catalog.js +86 -0
- package/lib/types/model-configuration.d.ts +11 -0
- package/lib/types/model-configuration.js +55 -0
- package/lib/types/preset-tools.d.ts +20 -0
- package/lib/types/preset-tools.js +36 -0
- package/lib/types/provision.d.ts +131 -0
- package/lib/types/provision.js +363 -0
- package/lib/types/records.d.ts +35 -0
- package/lib/types/records.js +85 -0
- package/lib/types/session-configuration.d.ts +5 -0
- package/lib/types/session-configuration.js +26 -0
- package/lib/types/session-mirror.d.ts +180 -0
- package/lib/types/session-mirror.js +446 -0
- package/lib/types/session-view.d.ts +121 -0
- package/lib/types/session-view.js +423 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +107 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kimi provider's live driver: one resident `kimi acp` process per member
|
|
3
|
+
* (child session), driven over the vendor's Agent Client Protocol (ACP) —
|
|
4
|
+
* JSON-RPC NDJSON over stdio (protocol-probed against kimi 0.36.1; the
|
|
5
|
+
* harness `subagent-acp` package is the reference implementation). A
|
|
6
|
+
* delegation round is a `session/prompt` on the member's resident session
|
|
7
|
+
* instead of a fresh `kimi -p` process, which buys what the process boundary
|
|
8
|
+
* could not: runtime-level graceful interrupt (`session/cancel`; the process
|
|
9
|
+
* survives and the session stays continuable) and push-driven mirroring
|
|
10
|
+
* (`session/update` notifications trigger throttled file-mirror passes — see
|
|
11
|
+
* below why the transcript itself stays file-sourced).
|
|
12
|
+
*
|
|
13
|
+
* Mirroring contract (the kimi-specific call): kimi's ACP updates are
|
|
14
|
+
* token-level chunks, NOT the wire.jsonl line fold the exec mirror owns — so
|
|
15
|
+
* completed items always fold from the file: push events merely TRIGGER
|
|
16
|
+
* throttled `mirrorKimiDelta` passes and the settle pass stays authoritative
|
|
17
|
+
* (one fold, one offset, zero divergence between the two drivers). Every
|
|
18
|
+
* transcript item folds 1:1 into the child session log.
|
|
19
|
+
* Live output also mirrors the in-flight item: chunk
|
|
20
|
+
* deltas accumulate per streaming item and append throttled snapshot
|
|
21
|
+
* assistant/messages at the item's reserved (turn, step) — the host folds
|
|
22
|
+
* repeated settles at one coordinate into one live-updating chat node — and
|
|
23
|
+
* the wire line completing the item folds at the same step, finalizing it.
|
|
24
|
+
*
|
|
25
|
+
* Lifecycle mirrors the dsh/codex live drivers' discipline: lazy spawn with an
|
|
26
|
+
* initialize handshake (loadSession capability required — crash recovery is
|
|
27
|
+
* `session/load` of the recorded session id), one in-flight spawn per member,
|
|
28
|
+
* idle-timeout reclaim (stdin EOF → grace → SIGTERM ladder), a channel breaker
|
|
29
|
+
* with cooldown, `disposeAll` on unload, and cancellation honored in every
|
|
30
|
+
* window. The wire adapter is self-contained (no `@agentclientprotocol/sdk`
|
|
31
|
+
* dependency): StringDecoder framing, request correlation, and unattended
|
|
32
|
+
* auto-answers for `session/request_permission` (allow — matching the exec
|
|
33
|
+
* mode's auto-approve behavior; the proposal's default policy).
|
|
34
|
+
* @module @khorsheed/dsh-local-agent-kimi/live-driver
|
|
35
|
+
*/
|
|
36
|
+
import type { LocalAgentResolvedConfiguration } from '@khorsheed/dsh-local-agent/types';
|
|
37
|
+
import { type KimiNativeConfiguration } from './model-catalog.ts';
|
|
38
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
39
|
+
import type { Session } from '@deepseek-ai/dsh-session';
|
|
40
|
+
import { type SubagentRun, type SubagentStartRequest, type SubagentStopReason } from '@deepseek-ai/dsh-subagent';
|
|
41
|
+
/** Default idle lifetime of an unused resident runtime before reclaim. */
|
|
42
|
+
export declare const DEFAULT_LIVE_IDLE_MS: number;
|
|
43
|
+
/** Default timeout for a wire request acknowledgement (never for session/prompt). */
|
|
44
|
+
export declare const DEFAULT_LIVE_REQUEST_TIMEOUT_MS = 30000;
|
|
45
|
+
/** Default timeout for the ACP handshake (a cold boot can be slow). */
|
|
46
|
+
export declare const DEFAULT_LIVE_INITIALIZE_TIMEOUT_MS = 60000;
|
|
47
|
+
/** Bounded wait for an interrupted turn to converge while a run disposes. */
|
|
48
|
+
export declare const DEFAULT_LIVE_DISPOSE_CONVERGE_MS = 5000;
|
|
49
|
+
/** How long a tripped channel breaker stays on the exec fallback. */
|
|
50
|
+
export declare const DEFAULT_LIVE_CHANNEL_RETRY_MS: number;
|
|
51
|
+
/** Minimum gap between push-triggered mirror passes. */
|
|
52
|
+
export declare const DEFAULT_LIVE_MIRROR_THROTTLE_MS = 500;
|
|
53
|
+
/** Default minimum interval between one streaming item's snapshot messages. */
|
|
54
|
+
export declare const DEFAULT_SNAPSHOT_MIN_INTERVAL_MS = 50;
|
|
55
|
+
/** Default minimum text growth between one streaming item's snapshot messages. */
|
|
56
|
+
export declare const DEFAULT_SNAPSHOT_MIN_CHARS = 0;
|
|
57
|
+
/**
|
|
58
|
+
* The ACP channel could not come up (spawn failure, handshake
|
|
59
|
+
* timeout/mismatch, or a missing loadSession capability). The provider
|
|
60
|
+
* catches exactly this and falls back to the exec one-shot; any other error
|
|
61
|
+
* is a real round failure.
|
|
62
|
+
*/
|
|
63
|
+
export declare class LiveChannelUnavailableError extends Error {
|
|
64
|
+
constructor(message: string);
|
|
65
|
+
}
|
|
66
|
+
/** Internal timeouts; tests inject small values. */
|
|
67
|
+
export interface KimiLiveDriverTimeouts {
|
|
68
|
+
readonly initializeMs: number;
|
|
69
|
+
readonly requestMs: number;
|
|
70
|
+
readonly convergeMs: number;
|
|
71
|
+
readonly channelRetryMs: number;
|
|
72
|
+
readonly mirrorThrottleMs: number;
|
|
73
|
+
}
|
|
74
|
+
/** How much of the live event stream crosses into the child session. */
|
|
75
|
+
export type KimiLiveMirrorGranularity = 'event' | 'token';
|
|
76
|
+
/** Fully resolved inputs for one live round. */
|
|
77
|
+
export interface KimiLiveRoundSpec {
|
|
78
|
+
readonly configuration?: LocalAgentResolvedConfiguration;
|
|
79
|
+
/** Parent Session workspace; also the runtime process cwd and ACP session cwd. */
|
|
80
|
+
readonly cwd: string;
|
|
81
|
+
/** The `kimi` harness's scoped home, injected as the runtime's `KIMI_CODE_HOME`. */
|
|
82
|
+
readonly homeDir: string;
|
|
83
|
+
/** dsh subagent session recording this delegation (always live on this path). */
|
|
84
|
+
readonly childSession: Session;
|
|
85
|
+
/** The delegating session (member-channel registration). */
|
|
86
|
+
readonly parentSessionId: string;
|
|
87
|
+
/**
|
|
88
|
+
* Resume round: continue the session recorded as `cliSessionId`, appending
|
|
89
|
+
* under this turn number. Also the reattach path after a runtime crash.
|
|
90
|
+
*/
|
|
91
|
+
readonly resume?: {
|
|
92
|
+
readonly cliSessionId: string;
|
|
93
|
+
readonly turn: number;
|
|
94
|
+
} | undefined;
|
|
95
|
+
/** Fresh round: called with the server-assigned session id (delegation record). */
|
|
96
|
+
readonly onCliSessionId?: ((cliSessionId: string) => void) | undefined;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Auth-shaped failure signatures in kimi's error output: the endpoint
|
|
100
|
+
* rejected the credential. Mirrors the exec path's detector
|
|
101
|
+
* (KIMI_AUTH_FAILURE in kimi-cli-provider.ts); the live path matches against
|
|
102
|
+
* session/prompt failure messages, which is where a mid-run 401 surfaces
|
|
103
|
+
* when the process does not exit.
|
|
104
|
+
*/
|
|
105
|
+
export declare const KIMI_LIVE_AUTH_FAILURE: RegExp;
|
|
106
|
+
/**
|
|
107
|
+
* kimi ACP session ids are directory names (`session_<uuid>`); the family
|
|
108
|
+
* delegation record convention is the bare uuid (the exec path's settle-time
|
|
109
|
+
* stderr parse). Strip the prefix so live- and exec-written records stay
|
|
110
|
+
* interchangeable.
|
|
111
|
+
*/
|
|
112
|
+
export declare function bareKimiSessionId(acpSessionId: string): string;
|
|
113
|
+
/** The ACP-native form of a recorded kimi session id (idempotent). */
|
|
114
|
+
export declare function acpKimiSessionId(recordedId: string): string;
|
|
115
|
+
/**
|
|
116
|
+
* Map an ACP prompt stop reason onto the shared stop contract (the harness
|
|
117
|
+
* subagent-acp mapping, verbatim): an unclean stop is never 'completed'.
|
|
118
|
+
*/
|
|
119
|
+
export declare function acpStopReasonToHarness(reason: string): SubagentStopReason;
|
|
120
|
+
/**
|
|
121
|
+
* The kimi live driver owns every resident ACP runtime of this provider
|
|
122
|
+
* generation. Created only when `live: true`; disposed with the plugin.
|
|
123
|
+
*/
|
|
124
|
+
export declare class KimiAcpLiveDriver {
|
|
125
|
+
private readonly ctx;
|
|
126
|
+
private readonly config;
|
|
127
|
+
private readonly timeouts;
|
|
128
|
+
private readonly runtimes;
|
|
129
|
+
private readonly ensuring;
|
|
130
|
+
/** The model each in-flight spawn is binding (a stale-model spawn never serves a switched member). */
|
|
131
|
+
private readonly ensuringModel;
|
|
132
|
+
private readonly ensuringConfiguration;
|
|
133
|
+
private readonly idleTimers;
|
|
134
|
+
/** Per-member round serialization (the resume lock covers resume-vs-resume only). */
|
|
135
|
+
private readonly roundChains;
|
|
136
|
+
private channelBrokenAt;
|
|
137
|
+
private disposed;
|
|
138
|
+
/**
|
|
139
|
+
* Set by drain() (a settings-driven generation handoff): new rounds are
|
|
140
|
+
* refused so the provider falls back to exec, while in-flight rounds finish
|
|
141
|
+
* on their runtime undisturbed. Unlike `disposed`, the driver still serves
|
|
142
|
+
* what it already accepted.
|
|
143
|
+
*/
|
|
144
|
+
private draining;
|
|
145
|
+
private readonly disposeController;
|
|
146
|
+
constructor(ctx: Context, config?: {
|
|
147
|
+
liveIdleMs?: number;
|
|
148
|
+
liveMirrorGranularity?: KimiLiveMirrorGranularity;
|
|
149
|
+
/** Maximum batching wait for incremental streaming messages. */
|
|
150
|
+
snapshotMinIntervalMs?: number;
|
|
151
|
+
/** @deprecated Character growth no longer gates live publication. */
|
|
152
|
+
snapshotMinChars?: number;
|
|
153
|
+
/**
|
|
154
|
+
* Resolver for the member's effective model, read at each RUNTIME
|
|
155
|
+
* SPAWN. `kimi acp` takes no model flag, so this path pins the scoped
|
|
156
|
+
* config's `default_model` instead of extending the argv. Absent, or
|
|
157
|
+
* resolving to nothing for the member, writes nothing at all. A runtime
|
|
158
|
+
* whose bound model no longer matches the member's resolved model is
|
|
159
|
+
* retired and respawned onto the new one.
|
|
160
|
+
*/
|
|
161
|
+
model?: (childSessionId: string) => string | undefined;
|
|
162
|
+
}, timeouts?: KimiLiveDriverTimeouts);
|
|
163
|
+
/** Whether the channel is in its post-failure cooldown (rounds fall back to exec). */
|
|
164
|
+
get disabled(): boolean;
|
|
165
|
+
/** Count of resident runtimes currently registered (zombie accounting in tests). */
|
|
166
|
+
get liveCount(): number;
|
|
167
|
+
private clearIdleTimer;
|
|
168
|
+
private armIdleTimer;
|
|
169
|
+
private reclaim;
|
|
170
|
+
/** Reclaim every runtime (plugin unload); no process survives the profile. */
|
|
171
|
+
disposeAll(): Promise<void>;
|
|
172
|
+
/**
|
|
173
|
+
* True while the member's runtime exists or is being spawned. The settings
|
|
174
|
+
* controller gates a new generation on this: a fresh driver must not serve
|
|
175
|
+
* a member whose retiring generation still hosts the (same) kimi session.
|
|
176
|
+
*/
|
|
177
|
+
hasRuntime(key: string): boolean;
|
|
178
|
+
/** @deprecated Compatibility no-op: live output is always incremental. */
|
|
179
|
+
setLiveMirrorGranularity(_granularity: KimiLiveMirrorGranularity): void;
|
|
180
|
+
/**
|
|
181
|
+
* Drain for a settings-driven generation handoff: refuse new rounds (the
|
|
182
|
+
* provider's catch falls back to exec), let every in-flight round finish on
|
|
183
|
+
* its runtime, then reclaim. Resolves when no runtime or spawn remains.
|
|
184
|
+
* Unlike disposeAll, in-flight work is never interrupted.
|
|
185
|
+
*/
|
|
186
|
+
drain(): Promise<void>;
|
|
187
|
+
/** The model a runtime spawned for this member right now would bind. */
|
|
188
|
+
private resolveBoundModel;
|
|
189
|
+
private ensureRuntime;
|
|
190
|
+
/**
|
|
191
|
+
* Retire one member's resident runtime (a composer-driven model switch):
|
|
192
|
+
* the process is reclaimed and the member's next round respawns onto the
|
|
193
|
+
* new model, resuming the same CLI session. A member with no runtime (or
|
|
194
|
+
* only a dead one) is a no-op. Lazy: nothing spawns here.
|
|
195
|
+
*/
|
|
196
|
+
retireRuntime(childSessionId: string): Promise<void>;
|
|
197
|
+
/**
|
|
198
|
+
* The model the member's live runtime is bound to, or undefined when the
|
|
199
|
+
* member has no live runtime (or it bound none). The broker compares this
|
|
200
|
+
* against the post-switch effective model to make a same-model set a no-op.
|
|
201
|
+
*/
|
|
202
|
+
runtimeModel(childSessionId: string): string | undefined;
|
|
203
|
+
runtimeConfiguration(childSessionId: string): KimiNativeConfiguration | undefined;
|
|
204
|
+
/**
|
|
205
|
+
* Spawn the member's resident `kimi acp` and prove the wire: initialize +
|
|
206
|
+
* the loadSession capability (crash recovery needs it — without it the
|
|
207
|
+
* channel is not live-capable and the breaker trips). A cancellation
|
|
208
|
+
* mid-spawn reclaims the half-started process without touching the breaker.
|
|
209
|
+
*/
|
|
210
|
+
private spawnRuntime;
|
|
211
|
+
private markChannelBroken;
|
|
212
|
+
/**
|
|
213
|
+
* Report an auth-shaped round failure to the family registry's auth-failure
|
|
214
|
+
* mark (the exec path's post-exit 401 detection ported to a process that
|
|
215
|
+
* never exits: the match runs against the settled error instead). Degrades
|
|
216
|
+
* silently on a core predating reportAuthFailure.
|
|
217
|
+
*/
|
|
218
|
+
private reportAuthIfShaped;
|
|
219
|
+
/**
|
|
220
|
+
* Register the member channel for one resident process (token + bridge
|
|
221
|
+
* coordinates), duck-typed like the exec path's memberRun but WITHOUT the
|
|
222
|
+
* mcp.json write — the ACP session declares the bridge inline.
|
|
223
|
+
*/
|
|
224
|
+
private registerMember;
|
|
225
|
+
/**
|
|
226
|
+
* Auto-answer the ACP permission surface unattended. `session/request_permission`
|
|
227
|
+
* selects the first allow option (allow_once/allow_always) — matching the
|
|
228
|
+
* exec mode's auto-approve behavior for `kimi -p` — and cancels when the
|
|
229
|
+
* child offered none. Anything else (fs/terminal, which we never
|
|
230
|
+
* advertised) is an error response.
|
|
231
|
+
*/
|
|
232
|
+
private answerServerRequest;
|
|
233
|
+
/**
|
|
234
|
+
* Drive one delegation round on the member's resident ACP session. Mirrors
|
|
235
|
+
* the exec run's settlement contract exactly (settleRunResult + turn/end
|
|
236
|
+
* bookkeeping); cancel is `session/cancel` and the process survives.
|
|
237
|
+
*/
|
|
238
|
+
/** Initialize the native session and model controls without sending a prompt. */
|
|
239
|
+
prepare(spec: KimiLiveRoundSpec, signal: AbortSignal): Promise<void>;
|
|
240
|
+
private configureSession;
|
|
241
|
+
startRound(request: SubagentStartRequest, spec: KimiLiveRoundSpec): Promise<SubagentRun>;
|
|
242
|
+
/** The serialized round body. */
|
|
243
|
+
private startRoundLocked;
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=live-driver.d.ts.map
|