lark-remote 0.5.3 → 0.5.5
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 +38 -0
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/dist/bridge/approval-coordinator.d.ts +18 -1
- package/dist/bridge/approval-coordinator.js +57 -10
- package/dist/bridge/index.js +90 -17
- package/dist/card/approval-render.js +18 -0
- package/dist/card/run-state.js +10 -5
- package/dist/config/index.d.ts +16 -0
- package/dist/config/index.js +46 -6
- package/dist/config/opencode-config.d.ts +3 -3
- package/dist/config/opencode-config.js +38 -22
- package/dist/inbound/authorize.d.ts +34 -0
- package/dist/inbound/authorize.js +31 -0
- package/dist/index.js +116 -63
- package/dist/instance-lock.d.ts +9 -0
- package/dist/instance-lock.js +113 -42
- package/dist/router/config/dsh.d.ts +51 -21
- package/dist/router/config/dsh.js +255 -66
- package/dist/router/config/opencode.js +16 -6
- package/dist/router/config/types.d.ts +6 -3
- package/dist/router/index.d.ts +1 -0
- package/dist/router/index.js +13 -5
- package/dist/runner/codex/app-server/translator.js +21 -7
- package/dist/runner/common/acp/base-acp-runner.d.ts +12 -0
- package/dist/runner/common/acp/base-acp-runner.js +83 -8
- package/dist/runner/common/acp/protocol-types.d.ts +10 -2
- package/dist/runner/common/acp/protocol-types.js +3 -1
- package/dist/runner/common/connection-based-runner.d.ts +15 -0
- package/dist/runner/common/connection-based-runner.js +40 -5
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +15 -0
- package/dist/runner/common/jsonrpc/connection-manager.js +83 -50
- package/dist/runner/dsh/approval.d.ts +53 -0
- package/dist/runner/dsh/approval.js +161 -0
- package/dist/runner/dsh/auth.d.ts +36 -0
- package/dist/runner/dsh/auth.js +118 -0
- package/dist/runner/dsh/client.d.ts +161 -42
- package/dist/runner/dsh/client.js +551 -244
- package/dist/runner/dsh/daemon.d.ts +85 -0
- package/dist/runner/dsh/daemon.js +272 -0
- package/dist/runner/dsh/merge.d.ts +9 -0
- package/dist/runner/dsh/merge.js +51 -0
- package/dist/runner/dsh/runner.d.ts +94 -11
- package/dist/runner/dsh/runner.js +553 -67
- package/dist/runner/dsh/translator.d.ts +43 -3
- package/dist/runner/dsh/translator.js +115 -38
- package/dist/runner/dsh/types.d.ts +189 -27
- package/dist/runner/dsh/types.js +11 -5
- package/dist/runner/kimi/acp/runner.js +15 -3
- package/dist/runner/opencode/acp/error-monitor.d.ts +2 -2
- package/dist/runner/opencode/acp/error-monitor.js +2 -2
- package/dist/runner/opencode/acp/runner.d.ts +9 -0
- package/dist/runner/opencode/acp/runner.js +40 -1
- package/dist/runner/opencode/acp/translator.d.ts +4 -2
- package/dist/runner/opencode/acp/translator.js +12 -3
- package/dist/runner/pi/rpc/translator.d.ts +2 -0
- package/dist/runner/pi/rpc/translator.js +27 -1
- package/dist/runner/types.d.ts +34 -0
- package/dist/runner/types.js +24 -0
- package/dist/session/codex/rollout-reader.js +44 -7
- package/dist/session/dsh/sessions.d.ts +45 -6
- package/dist/session/dsh/sessions.js +171 -27
- package/dist/session/opencode/sessions.d.ts +18 -7
- package/dist/session/opencode/sessions.js +294 -15
- package/dist/session/pi/sessions.js +6 -2
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,44 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.5.5] - 2026-10-18
|
|
9
|
+
|
|
10
|
+
### 新增
|
|
11
|
+
|
|
12
|
+
- **`/config` 卡片可以切换 DSH 的 provider**:新增 `agents.dsh.provider`。卡片里的 provider 下拉取自 DSH 的实时目录(打开卡片时强制刷新,在 DSH 侧新增 provider 后不必重启 lark-remote)。切换 provider 不清空会话,下一次运行用新 provider 重新对齐;显式配置的 provider 不可用时运行直接失败,不会静默改用别的 provider。模型留空时用该 provider 的默认模型
|
|
13
|
+
- **DSH 支持压缩(Compact)**:运行卡片的压缩按钮对 DSH 生效,走 DSH 的命令通道、只在会话空闲时执行。按钮的渲染与执行改用同一份「该 agent 是否声明支持压缩」判据,不再出现能点下去但必然失败的按钮
|
|
14
|
+
- **DSH 权限预设与飞书审批转发**:新增 `agents.dsh.permissionPreset`(沙箱模式 + 审批策略),在会话首次运行前用 `/permission` 对齐一次;DSH 不提供该命令时运行 fail closed,不会带着用户没选的权限继续跑。运行期间的审批请求渲染成卡片底部的「允许一次 / 拒绝」,允许只对当次调用生效;旧版 DSH 没有应答通道时回退为「请到 DSH Web UI 处理」,回合保持存活
|
|
15
|
+
- **DSH 未运行时由 lark-remote 后台拉起**:探测不到 DSH Web Host 时自动以后台脱离方式启动 `dsh web`(默认最多等 30 秒端口就绪),lark-remote 退出或重启都不会停止它;已在运行则直接复用。设 `agents.dsh.manageProcess: false` 可改为只连接已在跑的实例,`dshHome` / `dshCommand` / `startTimeoutMs` 分别指定启动目录、可执行文件与等待上限
|
|
16
|
+
|
|
17
|
+
### 变更
|
|
18
|
+
|
|
19
|
+
- **DSH 凭据改为自动签发**:DSH 0.2.x 起接口要求认证。lark-remote 默认读取 DSH 的持久凭据文件(`$DSH_HOME/.credentials.yaml`,未设置 `DSH_HOME` 时为 `~/.dsh/.credentials.yaml`,文件权限必须是 `0600`),用其中的浏览器会话签名密钥现签一个短时效凭据,`dsh web` 重启后不需要再手动更新 token。`agents.dsh.token` 降级为凭据文件不可读时的 YAML 兜底,并且不再出现在 `/config` 卡片上——启动 token 每个进程随机生成、重启即换,写进飞书卡片既会过期又多余
|
|
20
|
+
- **opencode 会话读取适配 2.0**:会话列表与历史改用 2.0 的导出结构(同时保留 1.x 的读法),工具执行结果按新形态解析
|
|
21
|
+
- **DSH 配置卡片文案精简**:权限预设不再在卡片上堆长段说明
|
|
22
|
+
|
|
23
|
+
### 修复
|
|
24
|
+
|
|
25
|
+
- **第一条消息是图片/文件时不再被静默丢弃**:会话归属绑定只发生在文本消息入口,媒体入口此前只做只读检查。全新安装的用户第一条消息若是图片/文件,媒体下载被丢掉、绑定也永远完不成。现在文本与媒体走同一个授权入口
|
|
26
|
+
- **点停止后执行位不再被卡住**:DSH 会接受 HTTP 连接但可能永不返回(卡住的模型请求),运行协程于是停在等待处,`/stop` 和空闲超时都腾不出该工作目录的执行位。请求加上默认 60 秒超时并可取消
|
|
27
|
+
- **opencode 后台服务不可用时不再让卡片挂一小时**:2.0 的对话走共享后台进程,该进程不可用时以前没有任何提示,卡片要等完整的重试退避(约 1 小时)才结束。现在直接报错并给出 `opencode service restart` 的处置提示
|
|
28
|
+
- **审批应答发送失败时保留重试入口**:连接断开或进程退出导致应答没送达时,卡片此前静默停在可点状态,用户以为已经批准。现在写明失败原因并保留原按钮重试(应答成功才消费该次审批的一次性标识)
|
|
29
|
+
- **DSH「本 run」token 不再少算**:跑了多趟工具往返的回合只统计了最后一条用量,现在按回合汇总该回合内所有调用
|
|
30
|
+
- **运行结束的使用量归属本轮自己的会话**:回合中途 `/new` / `/resume` / `/cd` 会移动全局会话指针,收尾按全局指针读取用量会把别的会话的 token 记到这条运行上
|
|
31
|
+
- **中断后迟到的上一轮错误不再影响新一轮**:回合加了代际标识,回调落地前复核归属;同时清理了唤醒后遗留的兜底定时器,高频事件不再持续堆积
|
|
32
|
+
- **替换连接时先等旧连接销毁完成**:不再让两个 agent 服务进程重叠,同一会话不会被两个进程同时持有;陈旧实例锁的接管改为「原子改名 + 复核」两步,中间不再可能被第三个进程插入
|
|
33
|
+
- **恢复会话时不再错认前缀相同的会话 id**:文件名匹配从「包含子串」改为按 `<id>.jsonl` / `_<id>.jsonl` 结尾匹配,完整 id 的前缀或相似 id 不再命中;读取 DSH 会话内容也加上目录守卫,会话属于另一个工作目录时 fail closed
|
|
34
|
+
- **思考过程不再被换行切碎**:同一条思考的增量按字拼接,此前每段增量都插一个换行
|
|
35
|
+
|
|
36
|
+
## [0.5.4] - 2026-10-12
|
|
37
|
+
|
|
38
|
+
### 修复
|
|
39
|
+
|
|
40
|
+
- **codex「本 run」token 少算(多步运行只统计了最后一步)**:codex 每发起一次模型调用就记一条 token 用量,一个回合里有几趟工具往返就有几条,而运行结束卡片与 `/resume` 末尾统计此前只取最后一条。于是一个跑了 7 趟工具往返的回合,实际输出 3,648 个 token 只显示 679、未命中缓存的输入 3,022 只显示 212。现在按回合汇总该回合内所有调用的用量,与 codex 自己按回合统计的结果逐字段一致;「Context」仍显示最后一次调用的上下文窗口占用,累计用量与 `Total` 的取法不变。恢复会话时服务端可能重放上回合的用量,已按回合标识丢弃。更早的、不带回合标识的记录保持原读法
|
|
41
|
+
|
|
42
|
+
### 变更
|
|
43
|
+
|
|
44
|
+
- **测试注释与用例类型对齐**:一处用例注释改为不点名具体消息;两处 app-server 用例的类型写法与协议定义对齐(这些文件不在既有类型检查覆盖范围内,改动不影响运行时行为)。无行为变化
|
|
45
|
+
|
|
8
46
|
## [0.5.3] - 2026-10-12
|
|
9
47
|
|
|
10
48
|
### 修复
|
package/README.en.md
CHANGED
|
@@ -32,7 +32,7 @@ In approval mode (Claude, Codex, Kimi), an approval card arrives before a comman
|
|
|
32
32
|
- OS: macOS / Linux / Windows 10+ (native Windows support is verified on real hardware, with behavior matching macOS/Linux)
|
|
33
33
|
- Node.js 20+ ([Bun](https://bun.sh/) for development)
|
|
34
34
|
- A Feishu custom app (either way): scan-to-create (a QR code pops up in the terminal on first launch; scan it with the Feishu app to create the app and write credentials automatically); or create one manually in the Open Platform — enable bot capability, subscribe to `im.message.receive_v1` and `card.action.trigger` via **long connection** (WebSocket, no public address needed), with at least the `im:message` scope.
|
|
35
|
-
- Claude Code CLI installed locally and logged in once in a terminal (`claude` → browser OAuth). Same idea for other agents (codex / opencode / pi / kimi): install the corresponding CLI first. DSH connects to a local DSH Web Host via HTTP+WebSocket (no local subprocess), default address `http://127.0.0.1:3080`.
|
|
35
|
+
- Claude Code CLI installed locally and logged in once in a terminal (`claude` → browser OAuth). Same idea for other agents (codex / opencode / pi / kimi): install the corresponding CLI first. DSH connects to a local DSH Web Host via HTTP+WebSocket (no local subprocess), default address `http://127.0.0.1:3080`. lark-remote reads `$DSH_HOME/.credentials.yaml` (default `~/.dsh/.credentials.yaml`) and mints short-lived cookies automatically, so a `dsh web` restart needs no manual token update; `agents.dsh.token` is only a fallback when that file is unavailable.
|
|
36
36
|
|
|
37
37
|
## Installation
|
|
38
38
|
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
- 操作系统:macOS / Linux / Windows 10+(原生 Windows 支持已完成真机验证,行为与 macOS/Linux 对齐)
|
|
33
33
|
- Node.js 20+(开发时用 [Bun](https://bun.sh/))
|
|
34
34
|
- 飞书自建应用(二选一):扫码创建(首次启动终端弹二维码,飞书 App 扫码即自动创建并写入凭据);或手动在开放平台建应用——开启机器人能力,订阅 `im.message.receive_v1` 和 `card.action.trigger`,订阅方式选「长连接」(WebSocket,无需公网地址),权限至少 `im:message`。
|
|
35
|
-
- Claude Code CLI:本地安装并在终端完成一次登录(`claude` → 浏览器 OAuth)。使用其他 agent(codex / opencode / pi / kimi)同理,先装好对应 CLI;DSH
|
|
35
|
+
- Claude Code CLI:本地安装并在终端完成一次登录(`claude` → 浏览器 OAuth)。使用其他 agent(codex / opencode / pi / kimi)同理,先装好对应 CLI;DSH 需本地安装 `dsh` CLI,lark-remote 会在 DSH Web Host 未运行时后台拉起它(默认 `http://127.0.0.1:3080`,lark-remote 退出不影响 DSH)。lark-remote 会读取 DSH 的 `$DSH_HOME/.credentials.yaml`(默认 `~/.dsh/.credentials.yaml`)自动签发短期 cookie,`dsh web` 重启后无需重新复制 token;`agents.dsh.token` 仅作为凭据文件不可用时的 YAML 兜底,不在 `/config` 卡片展示。
|
|
36
36
|
|
|
37
37
|
## 安装
|
|
38
38
|
|
|
@@ -18,6 +18,8 @@ export interface TrackedApproval {
|
|
|
18
18
|
view: ApprovalView;
|
|
19
19
|
createdAt: number;
|
|
20
20
|
timeoutTimer: ReturnType<typeof setTimeout> | null;
|
|
21
|
+
/** 本次审批的超时窗口(ms):响应失败回滚 pending 时按同一窗口重新计时。 */
|
|
22
|
+
timeoutMs: number;
|
|
21
23
|
/** AskUserQuestion 已答问题索引 → 答案 label[](kind === 'question')。 */
|
|
22
24
|
answers?: Map<number, string[]>;
|
|
23
25
|
/** AskUserQuestion 补充说明(Codex user_note):问题索引 → 文本。 */
|
|
@@ -144,8 +146,23 @@ export declare class ApprovalCoordinator {
|
|
|
144
146
|
private clearTimer;
|
|
145
147
|
/** 装超时计时器;先清掉旧的,保证一个 requestId 最多只有一条待触发的计时。 */
|
|
146
148
|
private armTimeout;
|
|
147
|
-
/**
|
|
149
|
+
/**
|
|
150
|
+
* nonce 去重(只校验不消费):同一 nonce 已生效过则拒绝。
|
|
151
|
+
* 提交类操作在 responder 成功后才 `consumeNonce`,失败可原样重试。
|
|
152
|
+
*/
|
|
148
153
|
private assertFreshNonce;
|
|
154
|
+
/** 标记 nonce 已生效(同一按钮连点/飞书重投递只允许一次)。 */
|
|
155
|
+
private consumeNonce;
|
|
156
|
+
/** 校验并立即消费 nonce(切换/回显类操作:本身幂等,重复投递只生效一次)。 */
|
|
157
|
+
private assertAndConsumeNonce;
|
|
158
|
+
/** 清掉失败提示(重试或新视图到达时)。 */
|
|
159
|
+
private clearDeliveryError;
|
|
160
|
+
/**
|
|
161
|
+
* 响应发送失败:状态回滚 pending、卡片写失败原因并重新计时,允许用户重试。
|
|
162
|
+
* 不回滚成 failed——failed 会让后续点击永远报 "no longer pending",
|
|
163
|
+
* 用户看到失败却没有任何重试入口。
|
|
164
|
+
*/
|
|
165
|
+
private failSubmission;
|
|
149
166
|
/** 记录问题答案到 tracked.answers(懒初始化 Map)。 */
|
|
150
167
|
private recordAnswer;
|
|
151
168
|
private getPendingQuestion;
|
|
@@ -39,6 +39,7 @@ export class ApprovalCoordinator {
|
|
|
39
39
|
// Already tracked — update state
|
|
40
40
|
existing.state = 'pending';
|
|
41
41
|
existing.view = event.view;
|
|
42
|
+
existing.timeoutMs = timeoutMs;
|
|
42
43
|
// 重投必须重新计时:上一路的计时器在 resolved/expired 时已清掉,不重装
|
|
43
44
|
// 这条审批就永不过期,server 只能无限等待(红线「审批超时自动 cancel」)。
|
|
44
45
|
this.armTimeout(existing, timeoutMs);
|
|
@@ -51,6 +52,7 @@ export class ApprovalCoordinator {
|
|
|
51
52
|
view: event.view,
|
|
52
53
|
createdAt: Date.now(),
|
|
53
54
|
timeoutTimer: null,
|
|
55
|
+
timeoutMs,
|
|
54
56
|
};
|
|
55
57
|
this.approvals.set(event.requestId, tracked);
|
|
56
58
|
this.armTimeout(tracked, timeoutMs);
|
|
@@ -123,17 +125,25 @@ export class ApprovalCoordinator {
|
|
|
123
125
|
// Atomic state transition: pending → submitting(同步,无 await)
|
|
124
126
|
tracked.state = 'submitting';
|
|
125
127
|
this.clearTimer(tracked);
|
|
128
|
+
// 重新提交时清掉上一次的失败提示(视图会随本次结果重渲染)。
|
|
129
|
+
this.clearDeliveryError(tracked);
|
|
126
130
|
// Send response via the responder
|
|
127
131
|
try {
|
|
128
132
|
await this.responder(ctx.requestId, effectiveAction);
|
|
129
133
|
tracked.state = 'resolved';
|
|
134
|
+
// nonce 在 responder 成功后才消费:失败可原按钮重试,
|
|
135
|
+
// 不会被自己的 nonce 去重挡掉(失败后已回滚 pending 并重新计时)。
|
|
136
|
+
this.consumeNonce(ctx.requestId, ctx.nonce);
|
|
130
137
|
// 提交成功后立即从卡片移除审批区(agent 无关):claude 控制协议没有
|
|
131
138
|
// resolved 回发,不推就会「已点允许按钮仍在」残留 UI;codex 的 server
|
|
132
139
|
// 稍后也会发 approval_resolved,reducer 按 requestId 过滤幂等。
|
|
133
140
|
this.pushResolved(ctx.requestId);
|
|
134
141
|
}
|
|
135
|
-
catch {
|
|
136
|
-
|
|
142
|
+
catch (err) {
|
|
143
|
+
// 响应失败必须向上抛(router 据此返回 error toast,而不是骗用户「已提交」),
|
|
144
|
+
// 并把失败原因写回卡片;状态回滚 pending + 重新装超时计时器,允许重试。
|
|
145
|
+
this.failSubmission(tracked, err);
|
|
146
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
137
147
|
}
|
|
138
148
|
}
|
|
139
149
|
/**
|
|
@@ -183,7 +193,7 @@ export class ApprovalCoordinator {
|
|
|
183
193
|
// 多选切换按钮同一 nonce 重复投递(双击/飞书重投递)只应
|
|
184
194
|
// toggle 一次,否则勾选会被二次 toggle 抵消。单选用例的重复防护在
|
|
185
195
|
// respondQuestionAnswers(提交即幂等,选中是 set 语义)。
|
|
186
|
-
this.
|
|
196
|
+
this.assertAndConsumeNonce(ctx.requestId, ctx.nonce);
|
|
187
197
|
if (selected.has(action.option)) {
|
|
188
198
|
selected.delete(action.option);
|
|
189
199
|
}
|
|
@@ -266,7 +276,7 @@ export class ApprovalCoordinator {
|
|
|
266
276
|
if (!text) {
|
|
267
277
|
throw new Error('请输入补充说明');
|
|
268
278
|
}
|
|
269
|
-
this.
|
|
279
|
+
this.assertAndConsumeNonce(ctx.requestId, ctx.nonce);
|
|
270
280
|
tracked.notes ??= new Map();
|
|
271
281
|
tracked.notes.set(action.questionIndex, text);
|
|
272
282
|
q.note = text;
|
|
@@ -295,7 +305,7 @@ export class ApprovalCoordinator {
|
|
|
295
305
|
if (!text) {
|
|
296
306
|
throw new Error('请输入修改意见');
|
|
297
307
|
}
|
|
298
|
-
this.
|
|
308
|
+
this.assertAndConsumeNonce(ctx.requestId, ctx.nonce);
|
|
299
309
|
tracked.feedback = text;
|
|
300
310
|
tracked.view.planFeedback = text;
|
|
301
311
|
this.pushApprovalViewUpdate(ctx.requestId, tracked);
|
|
@@ -338,17 +348,50 @@ export class ApprovalCoordinator {
|
|
|
338
348
|
this.expireApproval(tracked.requestId);
|
|
339
349
|
}, timeoutMs);
|
|
340
350
|
}
|
|
341
|
-
/**
|
|
351
|
+
/**
|
|
352
|
+
* nonce 去重(只校验不消费):同一 nonce 已生效过则拒绝。
|
|
353
|
+
* 提交类操作在 responder 成功后才 `consumeNonce`,失败可原样重试。
|
|
354
|
+
*/
|
|
342
355
|
assertFreshNonce(requestId, nonce) {
|
|
343
356
|
if (nonce === undefined)
|
|
344
357
|
return;
|
|
345
|
-
const seen = this.submittedNonces.get(requestId)
|
|
346
|
-
if (seen
|
|
358
|
+
const seen = this.submittedNonces.get(requestId);
|
|
359
|
+
if (seen?.has(nonce)) {
|
|
347
360
|
throw new Error(`Approval request ${requestId} already submitted (duplicate nonce)`);
|
|
348
361
|
}
|
|
362
|
+
}
|
|
363
|
+
/** 标记 nonce 已生效(同一按钮连点/飞书重投递只允许一次)。 */
|
|
364
|
+
consumeNonce(requestId, nonce) {
|
|
365
|
+
if (nonce === undefined)
|
|
366
|
+
return;
|
|
367
|
+
const seen = this.submittedNonces.get(requestId) ?? new Set();
|
|
349
368
|
seen.add(nonce);
|
|
350
369
|
this.submittedNonces.set(requestId, seen);
|
|
351
370
|
}
|
|
371
|
+
/** 校验并立即消费 nonce(切换/回显类操作:本身幂等,重复投递只生效一次)。 */
|
|
372
|
+
assertAndConsumeNonce(requestId, nonce) {
|
|
373
|
+
this.assertFreshNonce(requestId, nonce);
|
|
374
|
+
this.consumeNonce(requestId, nonce);
|
|
375
|
+
}
|
|
376
|
+
/** 清掉失败提示(重试或新视图到达时)。 */
|
|
377
|
+
clearDeliveryError(tracked) {
|
|
378
|
+
if (tracked.view.deliveryError === undefined)
|
|
379
|
+
return;
|
|
380
|
+
const { deliveryError: _deliveryError, ...view } = tracked.view;
|
|
381
|
+
tracked.view = view;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* 响应发送失败:状态回滚 pending、卡片写失败原因并重新计时,允许用户重试。
|
|
385
|
+
* 不回滚成 failed——failed 会让后续点击永远报 "no longer pending",
|
|
386
|
+
* 用户看到失败却没有任何重试入口。
|
|
387
|
+
*/
|
|
388
|
+
failSubmission(tracked, err) {
|
|
389
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
390
|
+
tracked.state = 'pending';
|
|
391
|
+
tracked.view = { ...tracked.view, deliveryError: message };
|
|
392
|
+
this.armTimeout(tracked, tracked.timeoutMs);
|
|
393
|
+
this.pushApprovalViewUpdate(tracked.requestId, tracked);
|
|
394
|
+
}
|
|
352
395
|
/** 记录问题答案到 tracked.answers(懒初始化 Map)。 */
|
|
353
396
|
recordAnswer(tracked, questionIndex, values) {
|
|
354
397
|
tracked.answers ??= new Map();
|
|
@@ -413,6 +456,7 @@ export class ApprovalCoordinator {
|
|
|
413
456
|
}
|
|
414
457
|
tracked.state = 'submitting';
|
|
415
458
|
this.clearTimer(tracked);
|
|
459
|
+
this.clearDeliveryError(tracked);
|
|
416
460
|
try {
|
|
417
461
|
await this.responder(ctx.requestId, {
|
|
418
462
|
action: 'answer',
|
|
@@ -420,10 +464,13 @@ export class ApprovalCoordinator {
|
|
|
420
464
|
...(Object.keys(notes).length > 0 ? { notes } : {}),
|
|
421
465
|
});
|
|
422
466
|
tracked.state = 'resolved';
|
|
467
|
+
this.consumeNonce(ctx.requestId, ctx.nonce);
|
|
423
468
|
this.pushResolved(ctx.requestId);
|
|
424
469
|
}
|
|
425
|
-
catch {
|
|
426
|
-
|
|
470
|
+
catch (err) {
|
|
471
|
+
// 与 submit 同口径:失败上抛(router error toast)+ 卡片失败视图 + 可重试。
|
|
472
|
+
this.failSubmission(tracked, err);
|
|
473
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
427
474
|
}
|
|
428
475
|
}
|
|
429
476
|
/** 推 approval_resolved 到卡片(移除审批区;幂等,失败仅记日志)。 */
|
package/dist/bridge/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { agentDisplayName, resumeUseButton } from '../card/card-shared.js';
|
|
|
11
11
|
import { enforceCardBudget } from '../card/card-budget.js';
|
|
12
12
|
import { normalizeResultUsage } from '../runner/common/result-usage.js';
|
|
13
13
|
import { BashProcessRunner } from '../runner/index.js';
|
|
14
|
-
import { AGENT_KINDS } from '../runner/types.js';
|
|
14
|
+
import { AGENT_KINDS, supportsCompact } from '../runner/types.js';
|
|
15
15
|
import { QueueManager, } from './queue-manager.js';
|
|
16
16
|
import { ApprovalCoordinator, decisionToApprovalAction } from './approval-coordinator.js';
|
|
17
17
|
import { InboundMediaHandler } from './inbound-media.js';
|
|
@@ -57,6 +57,27 @@ function terminalReactionEmoji(terminal) {
|
|
|
57
57
|
function runnerHasRunCompact(runner) {
|
|
58
58
|
return ('runCompact' in runner && typeof runner.runCompact === 'function');
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* 已告警过的能力不一致 kind。能力表(`COMPACT_CAPABILITY`)是声明,runner 方法
|
|
62
|
+
* 是实现;两者不一致是开发期缺陷,只在首次冲突时打 error,避免每次渲染刷屏。
|
|
63
|
+
*/
|
|
64
|
+
const compactMismatchWarned = new Set();
|
|
65
|
+
/**
|
|
66
|
+
* Compact 能力的双重门控:声明的能力表 && runner 实际实现。
|
|
67
|
+
*
|
|
68
|
+
* 只做鸭子探测会把「漏实现」降级成静默隐藏按钮(dsh 就这样漏了),所以声明表
|
|
69
|
+
* 是必需项;只信声明表则可能渲染出点不动的死按钮,所以实现检查也保留。两者
|
|
70
|
+
* 不一致时打 error 日志,让缺陷在运行日志里可见。
|
|
71
|
+
*/
|
|
72
|
+
function runnerSupportsCompact(runner, kind) {
|
|
73
|
+
const declared = supportsCompact(kind);
|
|
74
|
+
const implemented = runnerHasRunCompact(runner);
|
|
75
|
+
if (declared !== implemented && !compactMismatchWarned.has(kind)) {
|
|
76
|
+
compactMismatchWarned.add(kind);
|
|
77
|
+
getLogger().error(`[lark-remote] compact capability mismatch kind=${kind} declared=${declared} implemented=${implemented}`);
|
|
78
|
+
}
|
|
79
|
+
return declared && implemented;
|
|
80
|
+
}
|
|
60
81
|
/**
|
|
61
82
|
* 每个 cwd 保留的「可压缩 run」条数上限。Compact 按钮挂在终态 run 卡片上,
|
|
62
83
|
* 卡片会被后续消息不断顶上去;无上限会让长跑进程随 run 数无界增长,而用户
|
|
@@ -250,6 +271,12 @@ export class Bridge {
|
|
|
250
271
|
return undefined;
|
|
251
272
|
return { mode: opencodeConfig.mode };
|
|
252
273
|
}
|
|
274
|
+
case 'dsh': {
|
|
275
|
+
const dshConfig = agents?.dsh;
|
|
276
|
+
if (!dshConfig)
|
|
277
|
+
return undefined;
|
|
278
|
+
return { permissionPreset: dshConfig.permissionPreset };
|
|
279
|
+
}
|
|
253
280
|
default:
|
|
254
281
|
return undefined;
|
|
255
282
|
}
|
|
@@ -265,7 +292,7 @@ export class Bridge {
|
|
|
265
292
|
*/
|
|
266
293
|
hasRunCompact(cwd, kind = this.config.defaultAgent) {
|
|
267
294
|
const runner = this.getRunner(cwd, kind);
|
|
268
|
-
return
|
|
295
|
+
return runnerSupportsCompact(runner, kind);
|
|
269
296
|
}
|
|
270
297
|
/** 入队时刻快照:当前 defaultAgent + 该 agent 的 sessionId(无 session 则 undefined)。
|
|
271
298
|
* 唯一捕获点:排队消息在入队时刻把 agent+session 钉进 AgentBinding,随任务闭包带到执行时刻
|
|
@@ -816,9 +843,15 @@ export class Bridge {
|
|
|
816
843
|
// Step 1: Create run session (runId, cardSession, activeRun tracking)
|
|
817
844
|
const { runId, cardSession, activeRun } = this.createRunSession(ctx, cwd, runner, agentKind);
|
|
818
845
|
// Step 2: Consume the agent stream (runner.run loop, event processing, state updates)
|
|
819
|
-
|
|
820
|
-
//
|
|
821
|
-
|
|
846
|
+
// 兜底:run 消费阶段任何异常都必须仍走 finalizeRun 释放 activeRuns 槽位,
|
|
847
|
+
// 否则该 cwd 永久 busy(后续消息被 busy-drop,只能手动 /stop)。
|
|
848
|
+
try {
|
|
849
|
+
await this.runAgentStreamToEnd(runner, cardSession, activeRun, sessionId, sessionEpochAtStart, ctx, cwd, runId, message, agentKind);
|
|
850
|
+
}
|
|
851
|
+
finally {
|
|
852
|
+
// Step 3: Finalize the run (error handling, fallback card, completion notification, cleanup)
|
|
853
|
+
await this.finalizeRun(cardSession, activeRun, ctx, cwd);
|
|
854
|
+
}
|
|
822
855
|
}
|
|
823
856
|
/**
|
|
824
857
|
* Step 1 of forwardToClaude: Create run session components.
|
|
@@ -904,13 +937,19 @@ export class Bridge {
|
|
|
904
937
|
* Step 2 of forwardToClaude: Run the agent and consume its event stream.
|
|
905
938
|
* Handles idle watchdog, event processing, session sync, and state transitions.
|
|
906
939
|
*/
|
|
907
|
-
async runAgentStreamToEnd(runner, cardSession, sessionId, sessionEpochAtStart, ctx, cwd, runId, message, agentKind = this.config.defaultAgent) {
|
|
940
|
+
async runAgentStreamToEnd(runner, cardSession, activeRun, sessionId, sessionEpochAtStart, ctx, cwd, runId, message, agentKind = this.config.defaultAgent) {
|
|
908
941
|
// Runner 声明的 usage 权威来源:codex app-server = 'live'
|
|
909
942
|
// (turn/started 的 tokenUsage.last 是本 turn 增量)。其余 runner 未声明。
|
|
910
943
|
const usageAuthority = runner.getUsageAuthority?.();
|
|
911
944
|
// §9.12 空闲看门狗:判定口径见 startIdleWatchdog;武装点在 cardSession.start() 之后。
|
|
912
945
|
let watchdog = null;
|
|
913
946
|
let sawResult = false;
|
|
947
|
+
// A runner can fail before emitting its synthetic system/init (e.g. DSH
|
|
948
|
+
// session/create -> 401). The pre-init guard below drops that result to
|
|
949
|
+
// protect Claude resume replay, but if the stream ends without ever seeing
|
|
950
|
+
// init the result was the only terminal signal we had. Keep it so the card
|
|
951
|
+
// shows the real error instead of the generic "no result" fallback.
|
|
952
|
+
let pendingPreInitTerminal;
|
|
914
953
|
// 记录 result 是否为 error: error 时跳过 jsonl usage 读取 (见 stream end 处说明)
|
|
915
954
|
let resultNotSuccess = false;
|
|
916
955
|
// Final usage read from jsonl after the run completes. live stream-json does
|
|
@@ -1012,6 +1051,9 @@ export class Bridge {
|
|
|
1012
1051
|
}
|
|
1013
1052
|
if (event.type === 'system' && event.subtype === 'init') {
|
|
1014
1053
|
sawInit = true;
|
|
1054
|
+
// 本轮真实使用的 session(不可变身份):指针在 run 中被 /new 等移动时,
|
|
1055
|
+
// 结束后的 usage 读取仍以它为准。
|
|
1056
|
+
activeRun.sessionId = event.session_id;
|
|
1015
1057
|
// 代际守卫:run 在途时 /new(或 new-session 卡片、/cd、/resume、
|
|
1016
1058
|
// /config 切换)移动了 session 指针,此 init 的写回是 stale 的——
|
|
1017
1059
|
// 跳过,否则 /new 的清空会被在途 run 静默撤销(2026-08-09 事故:
|
|
@@ -1047,6 +1089,8 @@ export class Bridge {
|
|
|
1047
1089
|
// (§9.22 守卫前提),此处 turn_started 写回保留为双保险:两者都用
|
|
1048
1090
|
// threadId 写回 sessionId(代际守卫一致),幂等。缺失会导致每次消息
|
|
1049
1091
|
// 都新建线程(thread/start 而非 thread/resume),会话无法延续。
|
|
1092
|
+
// init 缺失时以 threadId 作为本轮身份兜底。
|
|
1093
|
+
activeRun.sessionId ??= event.threadId;
|
|
1050
1094
|
const pointerMoved = this.sessionStore.getSessionEpoch(ctx.userId, agentKind) !== sessionEpochAtStart;
|
|
1051
1095
|
if (!pointerMoved) {
|
|
1052
1096
|
this.sessionStore.setSessionIdAndCwd(ctx.userId, agentKind, event.threadId, cwd);
|
|
@@ -1078,6 +1122,12 @@ export class Bridge {
|
|
|
1078
1122
|
const preInitResult = !sawInit;
|
|
1079
1123
|
if (preInitResult && usageAuthority !== 'live') {
|
|
1080
1124
|
getLogger().info(`[lark-remote] pre-init result ignored (resume replay) runId=${runId}`);
|
|
1125
|
+
if (event.subtype === 'error' || event.subtype === 'interrupted') {
|
|
1126
|
+
pendingPreInitTerminal ??= {
|
|
1127
|
+
subtype: event.subtype,
|
|
1128
|
+
errorMessage: event.errorMessage,
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1081
1131
|
// Still reset idle timer — the CLI is alive and producing events.
|
|
1082
1132
|
watchdog?.touch();
|
|
1083
1133
|
// Do NOT push to cardSession: the run-state reducer would also
|
|
@@ -1085,6 +1135,12 @@ export class Bridge {
|
|
|
1085
1135
|
// layer avoids the push + render overhead for a no-op event.
|
|
1086
1136
|
continue;
|
|
1087
1137
|
}
|
|
1138
|
+
if (preInitResult && (event.subtype === 'error' || event.subtype === 'interrupted')) {
|
|
1139
|
+
pendingPreInitTerminal ??= {
|
|
1140
|
+
subtype: event.subtype,
|
|
1141
|
+
errorMessage: event.errorMessage,
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1088
1144
|
if (!preInitResult) {
|
|
1089
1145
|
sawResult = true;
|
|
1090
1146
|
}
|
|
@@ -1204,7 +1260,11 @@ export class Bridge {
|
|
|
1204
1260
|
// 但 result=error 时跳过: 进程可能立即退出未写新 usage (如 kimi 0.26+ 拒绝 -p+--auto
|
|
1205
1261
|
// 立即 exit=1), 此时 jsonl 里是上一次成功 turn 的历史 usage, 会被误当作本次 usage 显示,
|
|
1206
1262
|
// 误导用户以为本次出错的请求也消耗了 token。error 时只用 live 捕获的 usage (若有)。
|
|
1207
|
-
|
|
1263
|
+
// 本轮使用的 session:run 期间 /new //resume //cd 会移动全局
|
|
1264
|
+
// 指针,结束时再读 store 会把别条会话的 token/context 显示到这张卡上。
|
|
1265
|
+
// 优先级:卡片状态(本轮 init 写入)→ activeRun(本轮 init/turn_started)
|
|
1266
|
+
// → 本轮开始时捕获的 sessionId。三者都没有就跳过 usage,绝不回读全局指针。
|
|
1267
|
+
const finalSessionId = cardSession.currentState.sessionId ?? activeRun.sessionId ?? sessionId;
|
|
1208
1268
|
const finalUsage = resultNotSuccess
|
|
1209
1269
|
? undefined
|
|
1210
1270
|
: resolveFinalUsage(this.sessionReaderRegistry, this.config.defaultAgent, finalSessionId, cwd, agentKind);
|
|
@@ -1262,10 +1322,21 @@ export class Bridge {
|
|
|
1262
1322
|
});
|
|
1263
1323
|
}
|
|
1264
1324
|
else if (finalState.terminal === 'running') {
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1325
|
+
if (pendingPreInitTerminal) {
|
|
1326
|
+
const terminal = pendingPreInitTerminal.subtype === 'interrupted' ? 'interrupted' : 'error';
|
|
1327
|
+
getLogger().warn(`[lark-remote] stream ended without init; using pre-init ${terminal} result runId=${runId} error=${pendingPreInitTerminal.errorMessage ?? '(none)'}`);
|
|
1328
|
+
await cardSession.finish(terminal, {
|
|
1329
|
+
...usageMeta(),
|
|
1330
|
+
errorMsg: pendingPreInitTerminal.errorMessage ??
|
|
1331
|
+
agentDisplayName(agentKind) + (terminal === 'interrupted' ? ' 已中断' : ' 启动失败'),
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1334
|
+
else {
|
|
1335
|
+
await cardSession.finish('error', {
|
|
1336
|
+
...usageMeta(),
|
|
1337
|
+
errorMsg: agentDisplayName(agentKind) + ' 输出流已结束,但未收到 result 事件',
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1269
1340
|
}
|
|
1270
1341
|
else if (sawResult) {
|
|
1271
1342
|
// 已终态(interrupted/idle_timeout)+ result 已收到:首终态优先,
|
|
@@ -1391,7 +1462,7 @@ export class Bridge {
|
|
|
1391
1462
|
// 写入条件从「codex 终态」放宽为「runner 有 runCompact 的终态」
|
|
1392
1463
|
// (codex app-server + kimi acp 均满足)。
|
|
1393
1464
|
const runTerminal = cardSession.currentState.terminal;
|
|
1394
|
-
const runnerHasCompact =
|
|
1465
|
+
const runnerHasCompact = runnerSupportsCompact(activeRun.runner, activeRun.agentKind);
|
|
1395
1466
|
if (runnerHasCompact &&
|
|
1396
1467
|
activeRun.runner.lifetime === 'workspace' &&
|
|
1397
1468
|
(runTerminal === 'done' ||
|
|
@@ -1609,9 +1680,9 @@ export class Bridge {
|
|
|
1609
1680
|
if (await this.rejectIfCompactionInFlight(target.sessionId, cwd, target.agentKind, ctx)) {
|
|
1610
1681
|
return;
|
|
1611
1682
|
}
|
|
1612
|
-
// Check that the runner has runCompact method
|
|
1683
|
+
// Check that the runner has runCompact method(声明表 && runner 实现)
|
|
1613
1684
|
const runner = this.getRunner(cwd, target.agentKind);
|
|
1614
|
-
if (!
|
|
1685
|
+
if (!runnerSupportsCompact(runner, target.agentKind)) {
|
|
1615
1686
|
await this.sendResult({ text: '⚠️ 当前运行模式不支持 Compact' }, ctx);
|
|
1616
1687
|
return;
|
|
1617
1688
|
}
|
|
@@ -1670,7 +1741,8 @@ export class Bridge {
|
|
|
1670
1741
|
log.info(`[lark-remote] streamCompact sessionId=${sessionId} cwd=${cwd}`);
|
|
1671
1742
|
// 防御性能力检查:调用方已校验(runId / resume 两条路径),此处双保险并
|
|
1672
1743
|
// 让 TS 收窄 runner 类型('runCompact' in runner 之后的 cast 才合法)。
|
|
1673
|
-
if (!(
|
|
1744
|
+
if (!runnerSupportsCompact(runner, agentKind) ||
|
|
1745
|
+
!('runCompact' in runner) ||
|
|
1674
1746
|
typeof runner.runCompact !== 'function') {
|
|
1675
1747
|
await this.sendResult({ text: '⚠️ 当前运行模式不支持 Compact' }, ctx);
|
|
1676
1748
|
return;
|
|
@@ -1855,9 +1927,10 @@ export class Bridge {
|
|
|
1855
1927
|
// §5.3: kimi 压缩在途检测(与 handleCompactAction 同一入口)。
|
|
1856
1928
|
if (await this.rejectIfCompactionInFlight(sessionId, cwd, agentKind, ctx))
|
|
1857
1929
|
return;
|
|
1858
|
-
// Check that the runner has runCompact
|
|
1930
|
+
// Check that the runner has runCompact(声明表 && runner 实现;
|
|
1931
|
+
// codex/kimi/opencode/pi/claude/dsh 均已实现)。
|
|
1859
1932
|
const runner = this.getRunner(cwd, agentKind);
|
|
1860
|
-
if (!
|
|
1933
|
+
if (!runnerSupportsCompact(runner, agentKind)) {
|
|
1861
1934
|
await this.sendResult({ text: '⚠️ 当前运行模式不支持 Compact' }, ctx);
|
|
1862
1935
|
return;
|
|
1863
1936
|
}
|
|
@@ -44,6 +44,13 @@ export function renderApprovalArea(approval, opts) {
|
|
|
44
44
|
return [];
|
|
45
45
|
}
|
|
46
46
|
const elements = [];
|
|
47
|
+
if (approval.note) {
|
|
48
|
+
const neutralized = approval.note.replace(/`/g, '·');
|
|
49
|
+
elements.push({
|
|
50
|
+
tag: 'div',
|
|
51
|
+
text: { tag: 'lark_md', content: `ℹ️ ${neutralized}` },
|
|
52
|
+
});
|
|
53
|
+
}
|
|
47
54
|
if (approval.kind === 'command') {
|
|
48
55
|
elements.push(...renderCommandApproval(approval, opts?.expired, opts?.runId));
|
|
49
56
|
}
|
|
@@ -59,6 +66,17 @@ export function renderApprovalArea(approval, opts) {
|
|
|
59
66
|
else if (approval.kind === 'question') {
|
|
60
67
|
elements.push(...renderQuestionApproval(approval, opts?.expired, opts?.runId));
|
|
61
68
|
}
|
|
69
|
+
// 响应发送失败:明确告知原因 + 可重试,而不是静默停在可点状态。
|
|
70
|
+
if (approval.deliveryError) {
|
|
71
|
+
const neutralized = approval.deliveryError.replace(/`/g, '·');
|
|
72
|
+
elements.push({
|
|
73
|
+
tag: 'div',
|
|
74
|
+
text: {
|
|
75
|
+
tag: 'lark_md',
|
|
76
|
+
content: `⚠️ **审批提交失败**:${neutralized}\n可直接再次点击按钮重试。`,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
62
80
|
return elements;
|
|
63
81
|
}
|
|
64
82
|
/**
|
package/dist/card/run-state.js
CHANGED
|
@@ -327,21 +327,26 @@ function reduceAssistantEvent(state, event) {
|
|
|
327
327
|
let next = state;
|
|
328
328
|
for (const content of event.message.content) {
|
|
329
329
|
if (content.type === 'thinking') {
|
|
330
|
+
// 增量通道语义:chunk 边界是传输事实,不是文档结构。同一 itemId 的连续
|
|
331
|
+
// 内容是同一块的增量,逐字拼接;itemId 变化才开新块。不能用 '\n' 表示
|
|
332
|
+
// “来了新 delta”——DSH/opencode 的 reasoning delta 是 token 粒度。
|
|
330
333
|
const last = next.blocks[next.blocks.length - 1];
|
|
331
|
-
const
|
|
334
|
+
const prev = last?.kind === 'thinking' ? last : undefined;
|
|
335
|
+
const sameItem = prev !== undefined && prev.itemId === content.itemId;
|
|
336
|
+
const newBlocks = sameItem
|
|
332
337
|
? [
|
|
333
338
|
...next.blocks.slice(0, -1),
|
|
334
339
|
{
|
|
335
|
-
|
|
336
|
-
content: keepTailMarked(
|
|
340
|
+
...prev,
|
|
341
|
+
content: keepTailMarked(prev.content + content.thinking, MAX_REASONING_CHARS),
|
|
337
342
|
active: true,
|
|
338
|
-
timestamp: last.timestamp ?? event.timestamp,
|
|
339
343
|
},
|
|
340
344
|
]
|
|
341
345
|
: [
|
|
342
|
-
...next.blocks,
|
|
346
|
+
...markThinkingInactive(next.blocks),
|
|
343
347
|
{
|
|
344
348
|
kind: 'thinking',
|
|
349
|
+
...(content.itemId !== undefined ? { itemId: content.itemId } : {}),
|
|
345
350
|
content: keepTailMarked(content.thinking, MAX_REASONING_CHARS),
|
|
346
351
|
active: true,
|
|
347
352
|
timestamp: event.timestamp,
|
package/dist/config/index.d.ts
CHANGED
|
@@ -134,7 +134,15 @@ export declare const DEFAULT_DSH_HOST = "http://127.0.0.1:3080";
|
|
|
134
134
|
/** DSH (DeepSeek Harness) Web Host connection config. */
|
|
135
135
|
declare const DshConfigSchema: z.ZodObject<{
|
|
136
136
|
host: z.ZodDefault<z.ZodString>;
|
|
137
|
+
manageProcess: z.ZodDefault<z.ZodBoolean>;
|
|
138
|
+
dshHome: z.ZodOptional<z.ZodString>;
|
|
139
|
+
dshCommand: z.ZodOptional<z.ZodString>;
|
|
140
|
+
startTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
141
|
+
token: z.ZodOptional<z.ZodString>;
|
|
142
|
+
credentialsFile: z.ZodOptional<z.ZodString>;
|
|
137
143
|
agentPreset: z.ZodOptional<z.ZodString>;
|
|
144
|
+
permissionPreset: z.ZodOptional<z.ZodString>;
|
|
145
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
138
146
|
model: z.ZodOptional<z.ZodString>;
|
|
139
147
|
reasoningEffort: z.ZodOptional<z.ZodString>;
|
|
140
148
|
}, z.core.$strip>;
|
|
@@ -235,7 +243,15 @@ export declare const AppConfigSchema: z.ZodObject<{
|
|
|
235
243
|
}, z.core.$strip>>;
|
|
236
244
|
dsh: z.ZodOptional<z.ZodObject<{
|
|
237
245
|
host: z.ZodDefault<z.ZodString>;
|
|
246
|
+
manageProcess: z.ZodDefault<z.ZodBoolean>;
|
|
247
|
+
dshHome: z.ZodOptional<z.ZodString>;
|
|
248
|
+
dshCommand: z.ZodOptional<z.ZodString>;
|
|
249
|
+
startTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
250
|
+
token: z.ZodOptional<z.ZodString>;
|
|
251
|
+
credentialsFile: z.ZodOptional<z.ZodString>;
|
|
238
252
|
agentPreset: z.ZodOptional<z.ZodString>;
|
|
253
|
+
permissionPreset: z.ZodOptional<z.ZodString>;
|
|
254
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
239
255
|
model: z.ZodOptional<z.ZodString>;
|
|
240
256
|
reasoningEffort: z.ZodOptional<z.ZodString>;
|
|
241
257
|
}, z.core.$strip>>;
|