lark-remote 0.5.18 → 0.5.20
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 +32 -0
- package/dist/bridge/approval-actions.d.ts +1 -1
- package/dist/bridge/approval-actions.js +1 -1
- package/dist/bridge/bash-run.d.ts +71 -0
- package/dist/bridge/bash-run.js +217 -0
- package/dist/bridge/compact.d.ts +155 -0
- package/dist/bridge/compact.js +450 -0
- package/dist/bridge/final-usage.js +4 -4
- package/dist/bridge/inbound-media.js +1 -1
- package/dist/bridge/index.d.ts +120 -119
- package/dist/bridge/index.js +257 -695
- package/dist/bridge/job-watch.d.ts +68 -0
- package/dist/bridge/job-watch.js +146 -0
- package/dist/bridge/queue-manager.d.ts +3 -3
- package/dist/bridge/queue-manager.js +10 -29
- package/dist/card/approval-render.d.ts +2 -2
- package/dist/card/approval-render.js +109 -97
- package/dist/card/bash-card-session.js +2 -0
- package/dist/card/card-budget.js +1 -1
- package/dist/card/card-helpers.d.ts +3 -3
- package/dist/card/card-helpers.js +6 -6
- package/dist/card/card-session.d.ts +17 -0
- package/dist/card/card-session.js +35 -0
- package/dist/card/final-answer-file.js +1 -1
- package/dist/card/run-card-session.js +2 -0
- package/dist/card/run-renderer.d.ts +3 -3
- package/dist/card/run-renderer.js +77 -102
- package/dist/card/run-state.d.ts +35 -8
- package/dist/card/run-state.js +117 -90
- package/dist/card/tool-render.d.ts +1 -1
- package/dist/card/tool-render.js +1 -1
- package/dist/card/usage-format.d.ts +12 -0
- package/dist/card/usage-format.js +8 -3
- package/dist/cli.js +15 -3
- package/dist/clone.js +2 -2
- package/dist/config/codex-config.js +130 -106
- package/dist/config/index.d.ts +16 -2
- package/dist/config/index.js +23 -8
- package/dist/connector/index.js +6 -6
- package/dist/error-classification.js +3 -2
- package/dist/inbound/placeholder.d.ts +1 -1
- package/dist/inbound/placeholder.js +1 -1
- package/dist/index.js +203 -133
- package/dist/logger/index.js +6 -6
- package/dist/message-handlers.d.ts +0 -5
- package/dist/message-handlers.js +4 -2
- package/dist/model-catalog.d.ts +2 -2
- package/dist/model-catalog.js +3 -8
- package/dist/platform/identity.js +1 -1
- package/dist/platform/path.d.ts +1 -1
- package/dist/platform/path.js +1 -1
- package/dist/platform/sleep-blocker.js +1 -1
- package/dist/platform/terminator-win32.js +2 -1
- package/dist/router/commands/resume.js +2 -20
- package/dist/router/config/dsh.d.ts +4 -8
- package/dist/router/config/dsh.js +3 -10
- package/dist/router/config/kimi.js +1 -1
- package/dist/router/config/types.d.ts +1 -1
- package/dist/router/config-diff.js +1 -1
- package/dist/router/index.d.ts +56 -11
- package/dist/router/index.js +222 -202
- package/dist/runner/claude/session.d.ts +1 -1
- package/dist/runner/claude/session.js +6 -4
- package/dist/runner/codex/app-server/runner.d.ts +9 -2
- package/dist/runner/codex/app-server/runner.js +30 -25
- package/dist/runner/codex/app-server/translator.d.ts +0 -5
- package/dist/runner/codex/app-server/translator.js +4 -17
- package/dist/runner/common/acp/acp-approval.d.ts +1 -1
- package/dist/runner/common/acp/acp-approval.js +1 -1
- package/dist/runner/common/acp/base-acp-runner.d.ts +5 -2
- package/dist/runner/common/acp/base-acp-runner.js +26 -65
- package/dist/runner/common/acp/base-translator.d.ts +12 -2
- package/dist/runner/common/acp/base-translator.js +31 -9
- package/dist/runner/common/acp/protocol-types.d.ts +1 -1
- package/dist/runner/common/acp/protocol-types.js +2 -2
- package/dist/runner/common/connection-based-runner.d.ts +32 -1
- package/dist/runner/common/connection-based-runner.js +32 -2
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +2 -2
- package/dist/runner/common/jsonrpc/connection-manager.js +4 -4
- package/dist/runner/common/spawning-runner.d.ts +1 -1
- package/dist/runner/common/spawning-runner.js +1 -1
- package/dist/runner/dsh/catalog-probe.d.ts +17 -0
- package/dist/runner/dsh/catalog-probe.js +10 -0
- package/dist/runner/dsh/client.d.ts +13 -8
- package/dist/runner/dsh/client.js +23 -15
- package/dist/runner/dsh/exit-cancel.d.ts +2 -2
- package/dist/runner/dsh/exit-cancel.js +2 -2
- package/dist/runner/dsh/inflight.d.ts +1 -1
- package/dist/runner/dsh/inflight.js +1 -1
- package/dist/runner/dsh/runner.d.ts +48 -2
- package/dist/runner/dsh/runner.js +288 -199
- package/dist/runner/dsh/translator.d.ts +1 -1
- package/dist/runner/dsh/translator.js +1 -1
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/kimi/acp/runner.d.ts +1 -2
- package/dist/runner/kimi/acp/runner.js +1 -2
- package/dist/runner/kimi/acp/translator.d.ts +1 -1
- package/dist/runner/kimi/acp/translator.js +3 -4
- package/dist/runner/opencode/acp/runner.d.ts +2 -2
- package/dist/runner/opencode/acp/runner.js +4 -4
- package/dist/runner/pi/rpc/protocol-types.d.ts +1 -1
- package/dist/runner/pi/rpc/protocol-types.js +1 -1
- package/dist/runner/pi/rpc/runner.d.ts +3 -0
- package/dist/runner/pi/rpc/runner.js +27 -42
- package/dist/runner/types.d.ts +25 -8
- package/dist/runner/types.js +1 -1
- package/dist/session/claude/sessions.d.ts +45 -0
- package/dist/session/claude/sessions.js +97 -71
- package/dist/session/codex/rollout-reader.js +4 -4
- package/dist/session/common/throw-session-list-error.d.ts +10 -0
- package/dist/session/common/throw-session-list-error.js +16 -0
- package/dist/session/dsh/sessions.js +11 -5
- package/dist/session/kimi/sessions.d.ts +40 -1
- package/dist/session/kimi/sessions.js +244 -192
- package/dist/session/opencode/sessions.d.ts +153 -1
- package/dist/session/opencode/sessions.js +354 -321
- package/dist/session/pi/sessions.js +4 -5
- package/dist/session/session-store.d.ts +1 -1
- package/dist/session/session-store.js +1 -1
- package/dist/update/version-check.js +2 -1
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/index.js +1 -1
- package/package.json +1 -1
|
@@ -150,7 +150,7 @@ export class ConnectionBasedRunner {
|
|
|
150
150
|
// 已被缓存层除名(evictRunnerSlot → markOrphaned):本次 run 创建的
|
|
151
151
|
// 连接挂在无人托管的实例上。主动收掉而不是挂 idle timer——否则 agent
|
|
152
152
|
// server 进程残留至 idle TTL,期间持有 agent 侧会话写锁(codex
|
|
153
|
-
// "thread already has an active writer"
|
|
153
|
+
// "thread already has an active writer")。
|
|
154
154
|
// dispose() 内部自带 try/catch,这里 fire-and-forget 不阻塞事件流收尾。
|
|
155
155
|
void this.disposeConnections().catch((err) => {
|
|
156
156
|
getLogger().warn(`[${this.logTag}] orphan dispose error: ${err.message}`);
|
|
@@ -209,7 +209,7 @@ export class ConnectionBasedRunner {
|
|
|
209
209
|
/**
|
|
210
210
|
* Mark this runner as evicted from the bridge's runner cache while a run may
|
|
211
211
|
* still be holding/creating connections on it (queue-advance race during
|
|
212
|
-
* interruptCurrentRun's await window
|
|
212
|
+
* interruptCurrentRun's await window). The active run's finally
|
|
213
213
|
* disposes connections eagerly instead of arming the idle TTL timer —
|
|
214
214
|
* otherwise the agent server process lingers for up to 30 minutes holding
|
|
215
215
|
* its session write lock (codex: "thread already has an active writer").
|
|
@@ -331,6 +331,36 @@ export class ConnectionBasedRunner {
|
|
|
331
331
|
isCurrentTurn(generation, client) {
|
|
332
332
|
return this._isRunning && generation === this.turnGeneration && client === this.currentClient;
|
|
333
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Acquire the per-turn connection and capture the callback anchor
|
|
336
|
+
* ({@link TurnAnchor}): acquire → activity ping → currentClient → anchor.
|
|
337
|
+
* Shared preamble of every setupTurn / runCompact; the acquired anchor is
|
|
338
|
+
* what the turn's hooks (and prompt-settle callbacks) validate against.
|
|
339
|
+
*
|
|
340
|
+
* `acquire` is a closure so subclasses keep their own acquire signatures
|
|
341
|
+
* (pi passes the spawn-bound `{ sessionId }`).
|
|
342
|
+
*/
|
|
343
|
+
async acquireForTurn(cwd, acquire) {
|
|
344
|
+
const client = await acquire();
|
|
345
|
+
this.notifyConnectionActivity(cwd);
|
|
346
|
+
this.currentClient = client;
|
|
347
|
+
return { client, generation: this.turnGeneration };
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Wrap a per-turn callback with the isCurrentTurn guard: events from a
|
|
351
|
+
* finished turn are dropped with a debug log and never reach the turn
|
|
352
|
+
* dispatcher. 6 处守卫原有的日志粒度不一(ACP setupTurn 记 debug,其余静默),
|
|
353
|
+
* 统一为最详细版本:dropped 一律 debug,便于事后追溯。
|
|
354
|
+
*/
|
|
355
|
+
forCurrentTurn(anchor, label, handler) {
|
|
356
|
+
return (...args) => {
|
|
357
|
+
if (!this.isCurrentTurn(anchor.generation, anchor.client)) {
|
|
358
|
+
getLogger().debug(`[${this.logTag}] dropped ${label} from a finished turn`);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
handler(...args);
|
|
362
|
+
};
|
|
363
|
+
}
|
|
334
364
|
failTurn(message) {
|
|
335
365
|
this.pushEvents([
|
|
336
366
|
{
|
|
@@ -151,8 +151,8 @@ export declare class ConnectionManager<TClient extends ConnectionClient = JsonRp
|
|
|
151
151
|
* 定时器回调带 **slot 身份校验**:武装之后 slot 可能已被替换——进程自退走
|
|
152
152
|
* baseOnClose(删 slot 但不经过 disposeSlot)、或同 cwd 已 acquire 了新连接。
|
|
153
153
|
* 这两种情况下本定时器都已过期,不得回收「当时恰好挂在该 cwd 上」的连接:
|
|
154
|
-
*
|
|
155
|
-
*
|
|
154
|
+
* 一条泄漏的过期 TTL 会杀掉继任连接的在途 turn,卡片误报
|
|
155
|
+
* "Codex app-server connection closed"。
|
|
156
156
|
*/
|
|
157
157
|
notifyIdle(cwd: string): void;
|
|
158
158
|
private createClient;
|
|
@@ -197,8 +197,8 @@ export class ConnectionManager {
|
|
|
197
197
|
* 定时器回调带 **slot 身份校验**:武装之后 slot 可能已被替换——进程自退走
|
|
198
198
|
* baseOnClose(删 slot 但不经过 disposeSlot)、或同 cwd 已 acquire 了新连接。
|
|
199
199
|
* 这两种情况下本定时器都已过期,不得回收「当时恰好挂在该 cwd 上」的连接:
|
|
200
|
-
*
|
|
201
|
-
*
|
|
200
|
+
* 一条泄漏的过期 TTL 会杀掉继任连接的在途 turn,卡片误报
|
|
201
|
+
* "Codex app-server connection closed"。
|
|
202
202
|
*/
|
|
203
203
|
notifyIdle(cwd) {
|
|
204
204
|
if (this.idleTtlMs <= 0)
|
|
@@ -245,8 +245,8 @@ export class ConnectionManager {
|
|
|
245
245
|
if (current?.client === client) {
|
|
246
246
|
// 进程自退(codex app-server 偶发 exit 0,非本程序发起,不经
|
|
247
247
|
// disposeSlot)也要撤掉挂在旧 slot 上的 idle TTL:定时器不随 slot
|
|
248
|
-
// 删除而取消,到期时会按 cwd 误杀继任连接的在途 turn
|
|
249
|
-
//
|
|
248
|
+
// 删除而取消,到期时会按 cwd 误杀继任连接的在途 turn(见 notifyIdle
|
|
249
|
+
// 的身份校验与对应回归测试)。
|
|
250
250
|
this.clearIdleTimer(current);
|
|
251
251
|
this.slots.delete(cwd);
|
|
252
252
|
this.onConnectionLost?.(cwd);
|
|
@@ -4,7 +4,7 @@ import { type Terminator } from '../../platform/terminator.js';
|
|
|
4
4
|
import { SpawnHeartbeat } from './spawn-heartbeat.js';
|
|
5
5
|
import type { SpawnOptions } from '../types.js';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* 进程级退出监听单例分发。
|
|
8
8
|
*
|
|
9
9
|
* 背景:各 agent runner 的 registerExitHandlers 曾是同构复制,每个实例
|
|
10
10
|
* process.on('exit'|'SIGINT'|'SIGTERM') 注册 3 个永不移除的闭包(捕获整个
|
|
@@ -357,7 +357,7 @@ export class SpawningRunner {
|
|
|
357
357
|
// matchMode 'agent-invocation'(不是默认的 'executable'):agent CLI 普遍是
|
|
358
358
|
// `#!/usr/bin/env node` 脚本,ps 看到的是 `node <安装路径>/…/cli.js`,名字只在
|
|
359
359
|
// 路径段里(pi → @earendil-works/pi-coding-agent/…)。用默认档会恒判 mismatch
|
|
360
|
-
// → 这些 agent
|
|
360
|
+
// → 这些 agent 的孤儿永远回收不掉。
|
|
361
361
|
const verdict = verifyPidIdentityVerdictSync(pid, {
|
|
362
362
|
expectedBinary,
|
|
363
363
|
matchMode: 'agent-invocation',
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSH 服务端目录探测(/config 卡片动态清单用)。
|
|
3
|
+
*
|
|
4
|
+
* 接口只声明卡片预取需要的三个 RPC 方法;具体传输客户端的构造(含 token
|
|
5
|
+
* 解析路径)收在本模块——router 只依赖接口,不持有 DshClient。
|
|
6
|
+
*/
|
|
7
|
+
import type { DshModelCatalogValue, DshPermissionCatalogValue, DshPresetListValue } from '../../dsh/types.js';
|
|
8
|
+
/** 卡片预取只依赖的 client 方法子集。 */
|
|
9
|
+
export interface DshCatalogClient {
|
|
10
|
+
listModels(): Promise<DshModelCatalogValue>;
|
|
11
|
+
listPresets(): Promise<DshPresetListValue>;
|
|
12
|
+
listPermissionPresets(): Promise<DshPermissionCatalogValue>;
|
|
13
|
+
}
|
|
14
|
+
/** 目录预取客户端工厂类型(测试注入 fake 用)。 */
|
|
15
|
+
export type DshCatalogClientFactory = (baseUrl: string, token?: string, credentialsFile?: string) => DshCatalogClient;
|
|
16
|
+
/** 生产实现:卡片预取是交互路径,DSH 卡死时最多等 5 秒后回退固定清单。 */
|
|
17
|
+
export declare function createDshCatalogClient(baseUrl: string, token?: string, credentialsFile?: string): DshCatalogClient;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DshClient } from './client.js';
|
|
2
|
+
/** 生产实现:卡片预取是交互路径,DSH 卡死时最多等 5 秒后回退固定清单。 */
|
|
3
|
+
export function createDshCatalogClient(baseUrl, token, credentialsFile) {
|
|
4
|
+
return new DshClient(baseUrl, {
|
|
5
|
+
token,
|
|
6
|
+
credentialsFile,
|
|
7
|
+
requestTimeoutMs: 5_000,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=catalog-probe.js.map
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* `sessionEvents()` adds per-session filtering, reconnect + follow-snapshot
|
|
20
20
|
* replay, and seq-based dedup.
|
|
21
21
|
*/
|
|
22
|
-
import type { DshApprovalStreamItem, DshCommandResult, DshModelCatalogValue, DshModelSelection, DshOpenTurnState, DshPermissionCatalogValue, DshJobView, DshPresetListValue, DshProjectionItem, DshProjectionSnapshot, DshQuestion, DshRemoteEventOutcome, DshSessionPageValue, DshStreamItem
|
|
22
|
+
import type { DshApprovalStreamItem, DshCommandResult, DshModelCatalogValue, DshModelSelection, DshOpenTurnState, DshPermissionCatalogValue, DshJobView, DshPresetListValue, DshProjectionItem, DshProjectionSnapshot, DshQuestion, DshRemoteEventOutcome, DshSessionPageValue, DshStreamItem } from '../../dsh/types.js';
|
|
23
23
|
import type { GoalView } from '../types.js';
|
|
24
24
|
export { DshError } from './errors.js';
|
|
25
25
|
interface WebSocketMessageEvent {
|
|
@@ -325,13 +325,20 @@ export declare class DshClient {
|
|
|
325
325
|
*/
|
|
326
326
|
controlFrames(signal: AbortSignal): AsyncGenerator<DshProjectionItem>;
|
|
327
327
|
/**
|
|
328
|
-
*
|
|
328
|
+
* Subscribe to one session's background-job roster as a live stream.
|
|
329
329
|
*
|
|
330
|
-
* `job/list`
|
|
331
|
-
*
|
|
332
|
-
*
|
|
330
|
+
* `job/list` 是整份替换流(whole-set replacement):首帧就是当前真相,之后
|
|
331
|
+
* 任务生命周期一变就再推一整份。**run 结束之后**必须用这个长订阅——后台任务
|
|
332
|
+
* 跨 turn 存活,任务结束这件事只会在这条流上出现;收尾时取首帧即断开
|
|
333
|
+
* ({@link jobRows})只够画那一瞬间的卡片。
|
|
334
|
+
*/
|
|
335
|
+
watchJobs(sessionId: string, signal: AbortSignal): AsyncGenerator<DshJobView[]>;
|
|
336
|
+
/**
|
|
337
|
+
* One session's current background-job roster (snapshot).
|
|
333
338
|
*
|
|
334
|
-
*
|
|
339
|
+
* "此刻有哪些任务在跑"只需要第一帧:文档明确首帧就是当前真相,取到即断开,
|
|
340
|
+
* 不长期持有连接。失败返回 undefined(与"没有任务"区分):拿不到就别在卡片
|
|
341
|
+
* 上写"0 个后台任务"。
|
|
335
342
|
*/
|
|
336
343
|
jobRows(sessionId: string, opts?: {
|
|
337
344
|
signal?: AbortSignal;
|
|
@@ -341,8 +348,6 @@ export declare class DshClient {
|
|
|
341
348
|
jobKill(sessionId: string, jobId: string, opts?: {
|
|
342
349
|
signal?: AbortSignal;
|
|
343
350
|
}): Promise<boolean>;
|
|
344
|
-
/** Extract TokenUsage from an assistant/message data payload (absent → undefined). */
|
|
345
|
-
static usageOf(data: Record<string, unknown>): DshTokenUsage | undefined;
|
|
346
351
|
}
|
|
347
352
|
/** Stable client-side prompt identity persisted on the accepted user message. */
|
|
348
353
|
export declare function newPromptRequestId(): string;
|
|
@@ -239,6 +239,7 @@ export class DshClient {
|
|
|
239
239
|
err instanceof DshError &&
|
|
240
240
|
err.code === 'http' &&
|
|
241
241
|
err.details.status === 401) {
|
|
242
|
+
getLogger().warn(`[dsh] 401 while authenticating ${method}, re-minting cookie once`);
|
|
242
243
|
continue;
|
|
243
244
|
}
|
|
244
245
|
throw err;
|
|
@@ -271,6 +272,7 @@ export class DshClient {
|
|
|
271
272
|
}
|
|
272
273
|
if (res.status === 401 && attempt === 0) {
|
|
273
274
|
this.cookiePromise = undefined;
|
|
275
|
+
getLogger().warn(`[dsh] 401 for ${method}, re-minting cookie once`);
|
|
274
276
|
continue;
|
|
275
277
|
}
|
|
276
278
|
if (res.status === 401) {
|
|
@@ -927,25 +929,35 @@ export class DshClient {
|
|
|
927
929
|
}
|
|
928
930
|
}
|
|
929
931
|
/**
|
|
930
|
-
*
|
|
932
|
+
* Subscribe to one session's background-job roster as a live stream.
|
|
931
933
|
*
|
|
932
|
-
* `job/list`
|
|
933
|
-
*
|
|
934
|
-
*
|
|
934
|
+
* `job/list` 是整份替换流(whole-set replacement):首帧就是当前真相,之后
|
|
935
|
+
* 任务生命周期一变就再推一整份。**run 结束之后**必须用这个长订阅——后台任务
|
|
936
|
+
* 跨 turn 存活,任务结束这件事只会在这条流上出现;收尾时取首帧即断开
|
|
937
|
+
* ({@link jobRows})只够画那一瞬间的卡片。
|
|
938
|
+
*/
|
|
939
|
+
async *watchJobs(sessionId, signal) {
|
|
940
|
+
for await (const frame of this.muxStream('job/list', { args: dshArgs('job/list', { sessionId }) }, signal)) {
|
|
941
|
+
const rows = frame;
|
|
942
|
+
if (rows?.type !== 'rows')
|
|
943
|
+
continue;
|
|
944
|
+
yield Array.isArray(rows.jobs) ? rows.jobs : [];
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* One session's current background-job roster (snapshot).
|
|
935
949
|
*
|
|
936
|
-
*
|
|
950
|
+
* "此刻有哪些任务在跑"只需要第一帧:文档明确首帧就是当前真相,取到即断开,
|
|
951
|
+
* 不长期持有连接。失败返回 undefined(与"没有任务"区分):拿不到就别在卡片
|
|
952
|
+
* 上写"0 个后台任务"。
|
|
937
953
|
*/
|
|
938
954
|
async jobRows(sessionId, opts = {}) {
|
|
939
955
|
const timer = new AbortController();
|
|
940
956
|
const timeout = setTimeout(() => timer.abort(), opts.timeoutMs ?? 2_000);
|
|
941
957
|
const signal = opts.signal ? AbortSignal.any([opts.signal, timer.signal]) : timer.signal;
|
|
942
958
|
try {
|
|
943
|
-
for await (const
|
|
944
|
-
|
|
945
|
-
if (rows?.type === 'rows') {
|
|
946
|
-
return Array.isArray(rows.jobs) ? rows.jobs : [];
|
|
947
|
-
}
|
|
948
|
-
}
|
|
959
|
+
for await (const rows of this.watchJobs(sessionId, signal))
|
|
960
|
+
return rows;
|
|
949
961
|
return undefined;
|
|
950
962
|
}
|
|
951
963
|
catch (err) {
|
|
@@ -968,10 +980,6 @@ export class DshClient {
|
|
|
968
980
|
return false;
|
|
969
981
|
}
|
|
970
982
|
}
|
|
971
|
-
/** Extract TokenUsage from an assistant/message data payload (absent → undefined). */
|
|
972
|
-
static usageOf(data) {
|
|
973
|
-
return data.usage ?? undefined;
|
|
974
|
-
}
|
|
975
983
|
}
|
|
976
984
|
/** Stable client-side prompt identity persisted on the accepted user message. */
|
|
977
985
|
export function newPromptRequestId() {
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* `dsh web` host (`DshDaemon`). So the usual "kill my spawned child" exit
|
|
6
6
|
* cleanup does nothing for it, and a bridge that exits mid-turn leaves the
|
|
7
7
|
* turn running with no subscriber — an orphan turn that keeps consuming tokens
|
|
8
|
-
* and mutating the workspace invisibly
|
|
9
|
-
*
|
|
8
|
+
* and mutating the workspace invisibly, potentially for hours after the bridge
|
|
9
|
+
* died.
|
|
10
10
|
*
|
|
11
11
|
* `process.on('exit')` cannot await, so this path uses the same synchronous
|
|
12
12
|
* curl transport the session reader already uses: bounded by `timeoutMs` and
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* `dsh web` host (`DshDaemon`). So the usual "kill my spawned child" exit
|
|
6
6
|
* cleanup does nothing for it, and a bridge that exits mid-turn leaves the
|
|
7
7
|
* turn running with no subscriber — an orphan turn that keeps consuming tokens
|
|
8
|
-
* and mutating the workspace invisibly
|
|
9
|
-
*
|
|
8
|
+
* and mutating the workspace invisibly, potentially for hours after the bridge
|
|
9
|
+
* died.
|
|
10
10
|
*
|
|
11
11
|
* `process.on('exit')` cannot await, so this path uses the same synchronous
|
|
12
12
|
* curl transport the session reader already uses: bounded by `timeoutMs` and
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A DSH turn runs inside the shared `dsh web` host, not in a child process. If
|
|
5
5
|
* the bridge dies (SIGKILL, crash) the turn keeps running with no subscriber —
|
|
6
|
-
*
|
|
6
|
+
* one orphaned turn kept going for hours after its bridge exited. The
|
|
7
7
|
* runner writes one entry when it submits a prompt and removes it once the run
|
|
8
8
|
* (or a verified stop) accounts for that prompt; the next startup reconciles
|
|
9
9
|
* anything left behind:
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A DSH turn runs inside the shared `dsh web` host, not in a child process. If
|
|
5
5
|
* the bridge dies (SIGKILL, crash) the turn keeps running with no subscriber —
|
|
6
|
-
*
|
|
6
|
+
* one orphaned turn kept going for hours after its bridge exited. The
|
|
7
7
|
* runner writes one entry when it submits a prompt and removes it once the run
|
|
8
8
|
* (or a verified stop) accounts for that prompt; the next startup reconciles
|
|
9
9
|
* anything left behind:
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* back to the Web UI prompt.
|
|
19
19
|
*/
|
|
20
20
|
import type { AgentSessionReader } from '../../session-contract.js';
|
|
21
|
-
import type { AgentEvent, AgentStatusInfo, SpawnOptions, StopOutcome } from '../types.js';
|
|
21
|
+
import type { AgentEvent, AgentStatusInfo, BackgroundJobRoster, SpawnOptions, StopOutcome } from '../types.js';
|
|
22
22
|
import type { AgentRunner } from '../types.js';
|
|
23
23
|
import { DshClient, type WebSocketFactory } from './client.js';
|
|
24
24
|
import type { DshDaemon } from './daemon.js';
|
|
@@ -155,12 +155,51 @@ export declare class DshRunner implements AgentRunner {
|
|
|
155
155
|
*/
|
|
156
156
|
private submitPrompt;
|
|
157
157
|
run(message: string, opts: SpawnOptions): AsyncGenerator<AgentEvent>;
|
|
158
|
+
/**
|
|
159
|
+
* 准备一个 turn(run() 的准备阶段):模型对齐 + 权限预设对齐 + goal seed 探测。
|
|
160
|
+
*
|
|
161
|
+
* 红线(逐条保留):
|
|
162
|
+
* - 对齐失败 fail closed:显式配置 provider 时 selectModel 失败必须 throw
|
|
163
|
+
* (静默回退到其他 provider 会让用户以为切换成功,实际模型与账单都错);
|
|
164
|
+
* 权限预设失败由 alignPermissionPreset throw(用户明确选了安全策略,不能在
|
|
165
|
+
* 错误的权限下继续跑 prompt)。
|
|
166
|
+
* - 准备期间被 stop(abort)→ 返回 { ok:false },由调用方 yield interrupted
|
|
167
|
+
* result 收尾。
|
|
168
|
+
* - goal seed 只探测不推断:读不到按 unknown 上报,不冒充「没有 goal」。
|
|
169
|
+
*/
|
|
170
|
+
private prepareTurn;
|
|
158
171
|
/**
|
|
159
172
|
* Consume one turn from both transports. `session/follow` owns transcript
|
|
160
173
|
* events; `$events` owns the answerable approval waterfall. The merged
|
|
161
174
|
* stream keeps either transport from starving the other.
|
|
175
|
+
*
|
|
176
|
+
* 事件源分派:projection(goal + 状态条)→ handleProjectionItem;
|
|
177
|
+
* $events waterfall(审批/提问)→ handleApprovalWaterfallItem;
|
|
178
|
+
* assistant-stream 直转发(translator 持有本 turn 的 usage 累计状态);
|
|
179
|
+
* session/follow 事件 → handleSessionEvent(含 result 收尾的 jobs + goal 复核)。
|
|
162
180
|
*/
|
|
163
181
|
private runTurn;
|
|
182
|
+
/**
|
|
183
|
+
* 事件源 handler:Host-wide 投影(goal + 状态条)。
|
|
184
|
+
* 返回要回放的事件(可能为空——未变化/非本 session 的帧不产事件)。
|
|
185
|
+
*/
|
|
186
|
+
private handleProjectionItem;
|
|
187
|
+
/**
|
|
188
|
+
* 事件源 handler:$events 审批/提问 waterfall(channel 状态、审批 waterfall
|
|
189
|
+
* 登记、提问卡、cancel 回流、审批卡)。
|
|
190
|
+
* 返回要回放的事件;channel 状态类帧(ready/unavailable/request)只改内部
|
|
191
|
+
* 状态、不产事件。
|
|
192
|
+
*/
|
|
193
|
+
private handleApprovalWaterfallItem;
|
|
194
|
+
/**
|
|
195
|
+
* 事件源 handler:`session/follow` 会话事件。
|
|
196
|
+
* - goal/change:权威变更,不等投影直接更新;
|
|
197
|
+
* - tool/call:先记账(审批卡命令展示用)再落入 translator(卡片工具行来源);
|
|
198
|
+
* - approval/decided:审批回流,清审批卡;
|
|
199
|
+
* - 其余事件经 translator 翻译;result 事件先做收尾(后台任务名单 + goal
|
|
200
|
+
* 复核)再随 result 一起返回。
|
|
201
|
+
*/
|
|
202
|
+
private handleSessionEvent;
|
|
164
203
|
/**
|
|
165
204
|
* 收尾时仍在跑的后台任务。
|
|
166
205
|
*
|
|
@@ -169,6 +208,13 @@ export declare class DshRunner implements AgentRunner {
|
|
|
169
208
|
* 任务列表不等于有任务在跑。
|
|
170
209
|
*/
|
|
171
210
|
private collectBackgroundJobs;
|
|
211
|
+
/**
|
|
212
|
+
* 订阅本 session 的后台任务名单(跨 turn 生命周期)。
|
|
213
|
+
*
|
|
214
|
+
* 卡片收尾后仍要靠它把「任务结束了」推给用户:run 的事件流在 result 就关了,
|
|
215
|
+
* 而后台任务可能再跑半小时。名单是整份替换,消费方自己做 diff。
|
|
216
|
+
*/
|
|
217
|
+
watchJobs(sessionId: string, signal: AbortSignal): AsyncGenerator<ReadonlyArray<BackgroundJobRoster>>;
|
|
172
218
|
/** Kill one background job of this runner's session (card button path). */
|
|
173
219
|
killJob(sessionId: string, jobId: string): Promise<boolean>;
|
|
174
220
|
/** Apply the configured permission preset once per session, before prompt. */
|
|
@@ -272,7 +318,7 @@ export declare class DshRunner implements AgentRunner {
|
|
|
272
318
|
*
|
|
273
319
|
* turn 跑在常驻共享的 `dsh web` host 里,不在本进程的子进程树上;所以
|
|
274
320
|
* "杀自己的子进程"这套退出清理对它无效,桥接一退出,turn 继续无人接收地跑
|
|
275
|
-
*
|
|
321
|
+
* (孤儿 turn 在桥接死后可能再跑数小时)。
|
|
276
322
|
* 这里复用进程级退出分发器,用同步 curl 发一次 `session/cancel`。
|
|
277
323
|
*/
|
|
278
324
|
registerExitHandlers(): void;
|