lark-remote 0.4.4 → 0.5.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 +28 -0
- package/dist/binder.d.ts +11 -10
- package/dist/binder.js +17 -16
- package/dist/bridge/approval-coordinator.d.ts +1 -1
- package/dist/bridge/approval-coordinator.js +3 -3
- package/dist/bridge/inbound-media.d.ts +1 -27
- package/dist/bridge/inbound-media.js +23 -21
- package/dist/bridge/index.d.ts +57 -57
- package/dist/bridge/index.js +136 -129
- package/dist/bridge/queue-manager.d.ts +45 -38
- package/dist/bridge/queue-manager.js +136 -136
- package/dist/card/approval-render.d.ts +1 -1
- package/dist/card/approval-render.js +6 -6
- package/dist/card/bash-card-session.d.ts +3 -3
- package/dist/card/bash-card-session.js +3 -3
- package/dist/card/bash-renderer.js +5 -5
- package/dist/card/card-session.d.ts +4 -4
- package/dist/card/card-session.js +6 -6
- package/dist/card/card-shared.d.ts +1 -1
- package/dist/card/card-shared.js +2 -2
- package/dist/card/run-card-session.js +2 -2
- package/dist/card/run-renderer.d.ts +1 -1
- package/dist/card/run-renderer.js +22 -22
- package/dist/card/run-state.d.ts +2 -2
- package/dist/card/run-state.js +3 -3
- package/dist/card/tool-render.d.ts +1 -1
- package/dist/card/tool-render.js +6 -6
- package/dist/cli.js +5 -6
- package/dist/clone.d.ts +6 -9
- package/dist/clone.js +12 -8
- package/dist/common/clamp.d.ts +2 -0
- package/dist/common/clamp.js +5 -0
- package/dist/common/fs.d.ts +4 -3
- package/dist/common/fs.js +5 -4
- package/dist/common/truncate.d.ts +1 -1
- package/dist/common/truncate.js +2 -2
- package/dist/common/ttl-cache.d.ts +2 -2
- package/dist/common/ttl-cache.js +2 -2
- package/dist/config/codex-config.d.ts +9 -9
- package/dist/config/codex-config.js +18 -18
- package/dist/config/dir.d.ts +4 -5
- package/dist/config/dir.js +12 -10
- package/dist/config/index.d.ts +3 -3
- package/dist/config/index.js +6 -6
- package/dist/config/opencode-config.js +3 -3
- package/dist/config/wizard.js +2 -2
- package/dist/connector/index.d.ts +5 -7
- package/dist/connector/index.js +29 -16
- package/dist/inbound/event.d.ts +1 -1
- package/dist/inbound/event.js +1 -1
- package/dist/inbound/placeholder.d.ts +2 -2
- package/dist/inbound/placeholder.js +2 -2
- package/dist/inbound/receipt.d.ts +1 -3
- package/dist/inbound/receipt.js +2 -2
- package/dist/inbound/turn-assembler.d.ts +1 -3
- package/dist/inbound/turn-assembler.js +2 -2
- package/dist/index.js +38 -30
- package/dist/instance-lock.js +8 -7
- package/dist/logger/index.d.ts +1 -1
- package/dist/logger/index.js +4 -4
- package/dist/persistence/atomic-write.d.ts +1 -1
- package/dist/persistence/atomic-write.js +9 -5
- package/dist/platform/agent-stopper.d.ts +2 -2
- package/dist/platform/identity.d.ts +7 -1
- package/dist/platform/identity.js +2 -2
- package/dist/platform/path.d.ts +6 -0
- package/dist/platform/path.js +14 -8
- package/dist/platform/select.d.ts +1 -1
- package/dist/platform/select.js +1 -1
- package/dist/platform/shell.d.ts +2 -3
- package/dist/platform/spawn.d.ts +2 -2
- package/dist/platform/spawn.js +2 -2
- package/dist/platform/terminator-posix.js +6 -6
- package/dist/platform/terminator-win32.js +3 -3
- package/dist/platform/terminator.d.ts +3 -3
- package/dist/platform/terminator.js +2 -2
- package/dist/platform/types.d.ts +1 -1
- package/dist/restart.d.ts +1 -1
- package/dist/restart.js +5 -3
- package/dist/router/card-helpers.d.ts +1 -3
- package/dist/router/card-helpers.js +2 -2
- package/dist/router/config/codex.d.ts +1 -1
- package/dist/router/config/codex.js +3 -3
- package/dist/router/config/common/model-patch.d.ts +1 -2
- package/dist/router/config/common/model-patch.js +1 -2
- package/dist/router/config/opencode.js +2 -2
- package/dist/router/config/pi.js +1 -1
- package/dist/router/index.d.ts +30 -30
- package/dist/router/index.js +103 -84
- package/dist/router/order-exec-dispatch.d.ts +3 -10
- package/dist/router/order-exec-dispatch.js +5 -5
- package/dist/router/{utils.d.ts → usage-format.d.ts} +2 -4
- package/dist/router/{utils.js → usage-format.js} +3 -8
- package/dist/runner/bash/runner.d.ts +2 -2
- package/dist/runner/bash/runner.js +6 -6
- package/dist/runner/claude/runner.d.ts +1 -1
- package/dist/runner/claude/runner.js +2 -3
- package/dist/runner/claude/session.d.ts +4 -6
- package/dist/runner/claude/session.js +21 -23
- package/dist/runner/codex/app-server/runner.js +3 -3
- package/dist/runner/codex/app-server/translator.d.ts +2 -2
- package/dist/runner/codex/app-server/translator.js +5 -5
- package/dist/runner/common/acp/{protocol-helpers.d.ts → acp-approval.d.ts} +4 -10
- package/dist/runner/common/acp/{protocol-helpers.js → acp-approval.js} +7 -6
- package/dist/runner/common/acp/base-acp-runner.d.ts +1 -1
- package/dist/runner/common/acp/base-acp-runner.js +2 -2
- package/dist/runner/common/acp/base-translator.d.ts +3 -3
- package/dist/runner/common/acp/base-translator.js +4 -4
- package/dist/runner/common/acp/protocol-types.js +1 -1
- package/dist/runner/common/connection-based-runner.d.ts +5 -5
- package/dist/runner/common/connection-based-runner.js +5 -5
- package/dist/runner/common/jsonl-stream.d.ts +2 -2
- package/dist/runner/common/jsonl-stream.js +12 -12
- package/dist/runner/common/jsonrpc/client.d.ts +1 -1
- package/dist/runner/common/jsonrpc/client.js +1 -1
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +13 -13
- package/dist/runner/common/jsonrpc/connection-manager.js +37 -37
- package/dist/runner/common/jsonrpc/transport.d.ts +1 -1
- package/dist/runner/common/jsonrpc/transport.js +2 -2
- package/dist/runner/common/{usage.d.ts → result-usage.d.ts} +1 -1
- package/dist/runner/common/{usage.js → result-usage.js} +2 -2
- package/dist/runner/common/spawning-runner.d.ts +23 -10
- package/dist/runner/common/spawning-runner.js +48 -22
- package/dist/runner/common/{runner-utils.d.ts → synthetic-events.d.ts} +4 -4
- package/dist/runner/common/{runner-utils.js → synthetic-events.js} +5 -5
- package/dist/runner/dsh/client.d.ts +1 -1
- package/dist/runner/dsh/client.js +1 -1
- package/dist/runner/dsh/runner.js +3 -3
- package/dist/runner/kimi/acp/runner.d.ts +4 -4
- package/dist/runner/kimi/acp/runner.js +10 -10
- package/dist/runner/kimi/acp/translator.d.ts +2 -2
- package/dist/runner/kimi/acp/translator.js +5 -5
- package/dist/runner/opencode/acp/runner.d.ts +4 -4
- package/dist/runner/opencode/acp/runner.js +4 -4
- package/dist/runner/opencode/acp/translator.js +2 -2
- package/dist/runner/pi/rpc/runner.d.ts +1 -1
- package/dist/runner/pi/rpc/runner.js +2 -2
- package/dist/runner/pi/rpc/translator.d.ts +1 -2
- package/dist/runner/pi/rpc/translator.js +4 -6
- package/dist/runner/registry.d.ts +3 -3
- package/dist/runner/registry.js +3 -3
- package/dist/runner/types.d.ts +1 -1
- package/dist/session/claude/session-index.d.ts +13 -1
- package/dist/session/claude/session-index.js +21 -6
- package/dist/session/claude/session-reader.d.ts +1 -1
- package/dist/session/claude/session-reader.js +1 -1
- package/dist/session/claude/sessions.js +10 -10
- package/dist/session/codex/rollout-reader.d.ts +4 -4
- package/dist/session/codex/rollout-reader.js +14 -14
- package/dist/session/common/two-pass.js +2 -2
- package/dist/session/common/usage-accumulator.d.ts +2 -2
- package/dist/session/common/usage-accumulator.js +2 -2
- package/dist/session/dsh/sessions.d.ts +1 -1
- package/dist/session/dsh/sessions.js +3 -3
- package/dist/session/kimi/sessions.d.ts +2 -6
- package/dist/session/kimi/sessions.js +13 -19
- package/dist/session/opencode/sessions.d.ts +3 -3
- package/dist/session/opencode/sessions.js +15 -13
- package/dist/session/pi/sessions.js +13 -12
- package/dist/session/registry.d.ts +1 -1
- package/dist/session/registry.js +1 -1
- package/dist/session/session-store.d.ts +3 -4
- package/dist/session/session-store.js +3 -5
- package/dist/update/index.d.ts +1 -1
- package/dist/update/index.js +1 -1
- package/dist/update/version-check.d.ts +5 -3
- package/dist/update/version-check.js +10 -8
- package/dist/workspace/index.d.ts +4 -4
- package/dist/workspace/index.js +5 -5
- package/package.json +1 -1
|
@@ -114,7 +114,7 @@ export declare abstract class BaseAcpTranslator {
|
|
|
114
114
|
*/
|
|
115
115
|
setOperationKind(kind: 'turn' | 'compact'): void;
|
|
116
116
|
/**
|
|
117
|
-
* plan update → PlanEvent(信息保真
|
|
117
|
+
* plan update → PlanEvent(信息保真 不再显式丢弃)。
|
|
118
118
|
* ACP PlanEntry: { content, priority, status }(status: pending/in_progress/
|
|
119
119
|
* completed)。基类具体方法:kimi/opencode wire 结构相同,直接复用。
|
|
120
120
|
*/
|
|
@@ -125,7 +125,7 @@ export declare abstract class BaseAcpTranslator {
|
|
|
125
125
|
* JSON.parse (older agents send JSON strings) — keeps the card from
|
|
126
126
|
* crashing on undefined input.
|
|
127
127
|
*
|
|
128
|
-
* 信息保真
|
|
128
|
+
* 信息保真 kind 命中 KIND_TO_TOOL 时用映射名渲染结构化面板;
|
|
129
129
|
* title 与 name 不同时把 title 存到 content block 的 summary 字段
|
|
130
130
|
* (渲染层做面板副标题)。
|
|
131
131
|
*/
|
|
@@ -144,7 +144,7 @@ export declare abstract class BaseAcpTranslator {
|
|
|
144
144
|
/** tool_use name recorded at tool_call time (kind mapping wins, else title). */
|
|
145
145
|
protected getToolCallName(toolCallId: string): string | undefined;
|
|
146
146
|
/**
|
|
147
|
-
* kind → canonical tool name (信息保真
|
|
147
|
+
* kind → canonical tool name (信息保真). Shared by the initial tool_call
|
|
148
148
|
* handler and the tool_call_update patch builder so both agree on the name.
|
|
149
149
|
*/
|
|
150
150
|
protected toolNameFromKind(kind: string | undefined): string | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NotificationMethod, ServerRequestMethod, SessionEventType, } from './protocol-types.js';
|
|
2
2
|
/**
|
|
3
|
-
* ACP tool kind →
|
|
3
|
+
* ACP tool kind → 常用工具名映射(信息保真,数据驱动无 agent 分支)。
|
|
4
4
|
* kind 命中映射时用映射名渲染结构化面板;否则回落 title(维持现状)。
|
|
5
5
|
*/
|
|
6
6
|
const KIND_TO_TOOL = {
|
|
@@ -199,7 +199,7 @@ export class BaseAcpTranslator {
|
|
|
199
199
|
// Shared notification handlers
|
|
200
200
|
// =========================================================================
|
|
201
201
|
/**
|
|
202
|
-
* plan update → PlanEvent(信息保真
|
|
202
|
+
* plan update → PlanEvent(信息保真 不再显式丢弃)。
|
|
203
203
|
* ACP PlanEntry: { content, priority, status }(status: pending/in_progress/
|
|
204
204
|
* completed)。基类具体方法:kimi/opencode wire 结构相同,直接复用。
|
|
205
205
|
*/
|
|
@@ -224,7 +224,7 @@ export class BaseAcpTranslator {
|
|
|
224
224
|
* JSON.parse (older agents send JSON strings) — keeps the card from
|
|
225
225
|
* crashing on undefined input.
|
|
226
226
|
*
|
|
227
|
-
* 信息保真
|
|
227
|
+
* 信息保真 kind 命中 KIND_TO_TOOL 时用映射名渲染结构化面板;
|
|
228
228
|
* title 与 name 不同时把 title 存到 content block 的 summary 字段
|
|
229
229
|
* (渲染层做面板副标题)。
|
|
230
230
|
*/
|
|
@@ -327,7 +327,7 @@ export class BaseAcpTranslator {
|
|
|
327
327
|
return this.toolCallNameByCallId.get(toolCallId);
|
|
328
328
|
}
|
|
329
329
|
/**
|
|
330
|
-
* kind → canonical tool name (信息保真
|
|
330
|
+
* kind → canonical tool name (信息保真). Shared by the initial tool_call
|
|
331
331
|
* handler and the tool_call_update patch builder so both agree on the name.
|
|
332
332
|
*/
|
|
333
333
|
toolNameFromKind(kind) {
|
|
@@ -45,7 +45,7 @@ export const RpcErrorCode = {
|
|
|
45
45
|
//
|
|
46
46
|
// REAL envelope: {sessionId, update: {sessionUpdate: '<kind>', ...}}.
|
|
47
47
|
// The discriminator field is `update.sessionUpdate` — there is NO nested
|
|
48
|
-
// `event.type` / `event.delta` (
|
|
48
|
+
// `event.type` / `event.delta` (旧实现读 params.event,
|
|
49
49
|
// 真实通知全部静默丢弃)。
|
|
50
50
|
// =============================================================================
|
|
51
51
|
/** Notification method names for ACP protocol. */
|
|
@@ -51,7 +51,7 @@ export declare abstract class ConnectionBasedRunner<TClient, TEvent = AgentEvent
|
|
|
51
51
|
/** Set up the turn: acquire + thread|session new/resume + prompt. */
|
|
52
52
|
protected abstract setupTurn(message: string, opts: SpawnOptions): Promise<void>;
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
54
|
+
* 本连接的协议停止通道。
|
|
55
55
|
*
|
|
56
56
|
* win32 上「优雅停止」没有可拦截的跨进程 SIGTERM,只能经 agent 自有协议通道
|
|
57
57
|
* 请求对方收摊。子类把这个方法的结果交给 ConnectionManager.stopper,由后者按
|
|
@@ -60,9 +60,9 @@ export declare abstract class ConnectionBasedRunner<TClient, TEvent = AgentEvent
|
|
|
60
60
|
* 两件事,顺序不能反:
|
|
61
61
|
* 1. 若本连接就是当前在途 turn 的连接,先发协议取消(codex turn/interrupt /
|
|
62
62
|
* ACP session/cancel / pi abort)。**归属判定不能省**:runner 实例按 agent
|
|
63
|
-
* 维度共享(一个实例管多条
|
|
63
|
+
* 维度共享(一个实例管多条 cwd 连接),无条件调用
|
|
64
64
|
* `cancelCurrentTurn()` 会用它自己的 currentClient/activeSessionId 去打断
|
|
65
|
-
* **另一个
|
|
65
|
+
* **另一个 cwd** 正在跑的 turn;
|
|
66
66
|
* 2. 关 stdin。stdio 型 agent server 在 stdin EOF 后自行退出——只发协议取消
|
|
67
67
|
* 不会让进程退出,优雅段会空转到 grace 超时后照样树杀,等于通道白注册。
|
|
68
68
|
*/
|
|
@@ -118,9 +118,9 @@ export declare abstract class ConnectionBasedRunner<TClient, TEvent = AgentEvent
|
|
|
118
118
|
protected respawnAfterConnectionLost(opts: SpawnOptions): Promise<void>;
|
|
119
119
|
/** Hook: clear subclass turn state in run() finally (session ids, translator, flags). */
|
|
120
120
|
protected abstract clearTurnState(): void;
|
|
121
|
-
/** Release the connection for a
|
|
121
|
+
/** Release the connection for a cwd (subclass dispatches to its manager). */
|
|
122
122
|
protected abstract releaseConnection(cwd: string): Promise<void>;
|
|
123
|
-
/** Notify the connection manager that the
|
|
123
|
+
/** Notify the connection manager that the cwd is idle (subclass). */
|
|
124
124
|
protected abstract notifyIdle(cwd: string): void;
|
|
125
125
|
/** Dispose all connections (subclass dispatches to its manager). */
|
|
126
126
|
protected abstract disposeConnections(): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ConnectionLostError } from './jsonrpc/client.js';
|
|
2
2
|
import { getLogger } from '../../logger/index.js';
|
|
3
|
-
import { syntheticInitEvent } from './
|
|
3
|
+
import { syntheticInitEvent } from './synthetic-events.js';
|
|
4
4
|
import { DEFAULT_TURN_IDLE_TIMEOUT_MINUTES } from '../../config/index.js';
|
|
5
5
|
/** How long to wait for turn output notifications before failing.
|
|
6
6
|
* 30 分钟(单源于 config 的 DEFAULT_TURN_IDLE_TIMEOUT_MINUTES):ACP/app-server
|
|
@@ -28,7 +28,7 @@ export class ConnectionBasedRunner {
|
|
|
28
28
|
this.turnIdleTimeoutMs = opts.turnIdleTimeoutMs ?? defaultTurnIdleTimeoutMs;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* 本连接的协议停止通道。
|
|
32
32
|
*
|
|
33
33
|
* win32 上「优雅停止」没有可拦截的跨进程 SIGTERM,只能经 agent 自有协议通道
|
|
34
34
|
* 请求对方收摊。子类把这个方法的结果交给 ConnectionManager.stopper,由后者按
|
|
@@ -37,9 +37,9 @@ export class ConnectionBasedRunner {
|
|
|
37
37
|
* 两件事,顺序不能反:
|
|
38
38
|
* 1. 若本连接就是当前在途 turn 的连接,先发协议取消(codex turn/interrupt /
|
|
39
39
|
* ACP session/cancel / pi abort)。**归属判定不能省**:runner 实例按 agent
|
|
40
|
-
* 维度共享(一个实例管多条
|
|
40
|
+
* 维度共享(一个实例管多条 cwd 连接),无条件调用
|
|
41
41
|
* `cancelCurrentTurn()` 会用它自己的 currentClient/activeSessionId 去打断
|
|
42
|
-
* **另一个
|
|
42
|
+
* **另一个 cwd** 正在跑的 turn;
|
|
43
43
|
* 2. 关 stdin。stdio 型 agent server 在 stdin EOF 后自行退出——只发协议取消
|
|
44
44
|
* 不会让进程退出,优雅段会空转到 grace 超时后照样树杀,等于通道白注册。
|
|
45
45
|
*/
|
|
@@ -141,7 +141,7 @@ export class ConnectionBasedRunner {
|
|
|
141
141
|
async stop(_opts) {
|
|
142
142
|
if (!this._isRunning)
|
|
143
143
|
return;
|
|
144
|
-
//
|
|
144
|
+
// 启动阶段(client/session 未建立)也必须记录停止意图,否则 /stop 被吞、
|
|
145
145
|
// turn 照常执行。executeTurn 在 setup 完成后检查 stopRequested 补发 cancel。
|
|
146
146
|
this.stopRequested = true;
|
|
147
147
|
this.forceFinish = true;
|
|
@@ -4,7 +4,7 @@ import type { Readable } from 'node:stream';
|
|
|
4
4
|
interface JSONLStreamOptions {
|
|
5
5
|
onParseError?: (line: string) => void;
|
|
6
6
|
/**
|
|
7
|
-
* Pause stdout once `lineQueue` exceeds this depth (
|
|
7
|
+
* Pause stdout once `lineQueue` exceeds this depth (backpressure).
|
|
8
8
|
* Default 100 (matches production; tests may pass a smaller value).
|
|
9
9
|
*/
|
|
10
10
|
pauseThreshold?: number;
|
|
@@ -23,7 +23,7 @@ interface JSONLStreamOptions {
|
|
|
23
23
|
* - JSON parse errors: when `options.onParseError` is provided, bad lines are
|
|
24
24
|
* forwarded to the callback; otherwise a warning is logged via getLogger().warn
|
|
25
25
|
* and the line is skipped.
|
|
26
|
-
* - Optional backpressure
|
|
26
|
+
* - Optional backpressure: when `pauseThreshold` is set, stdout is
|
|
27
27
|
* paused once the parsed-line queue exceeds the threshold and resumed once
|
|
28
28
|
* the consumer drains it back below `resumeThreshold`, bounding memory in
|
|
29
29
|
* long runs where the producer (agent stdout) outpaces the consumer (card
|
|
@@ -8,7 +8,7 @@ import { getLogger } from '../../logger/index.js';
|
|
|
8
8
|
* - JSON parse errors: when `options.onParseError` is provided, bad lines are
|
|
9
9
|
* forwarded to the callback; otherwise a warning is logged via getLogger().warn
|
|
10
10
|
* and the line is skipped.
|
|
11
|
-
* - Optional backpressure
|
|
11
|
+
* - Optional backpressure: when `pauseThreshold` is set, stdout is
|
|
12
12
|
* paused once the parsed-line queue exceeds the threshold and resumed once
|
|
13
13
|
* the consumer drains it back below `resumeThreshold`, bounding memory in
|
|
14
14
|
* long runs where the producer (agent stdout) outpaces the consumer (card
|
|
@@ -22,7 +22,7 @@ import { getLogger } from '../../logger/index.js';
|
|
|
22
22
|
*/
|
|
23
23
|
export function createJSONLStream(stdout, options) {
|
|
24
24
|
const lineQueue = [];
|
|
25
|
-
//
|
|
25
|
+
// accumulate partial-line fragments in an array instead of repeatedly
|
|
26
26
|
// string-concatenating a growing `partialLine`. A huge single JSON line
|
|
27
27
|
// (large tool_result / text_end) spanning many chunks caused O(n²) copies:
|
|
28
28
|
// each chunk rebuilt `partialLine + text` over the whole accumulated prefix.
|
|
@@ -30,7 +30,7 @@ export function createJSONLStream(stdout, options) {
|
|
|
30
30
|
// and push complete lines; the residual tail stays as array fragments until
|
|
31
31
|
// the next newline or stream end. Net allocation: O(n) instead of O(n²).
|
|
32
32
|
const partialFragments = [];
|
|
33
|
-
//
|
|
33
|
+
// accumulated byte length of partialFragments. Backpressure (above)
|
|
34
34
|
// only counts COMPLETE lines in lineQueue; a never-newline stream (malformed
|
|
35
35
|
// output, binary garbage) accumulates fragments without ever completing a
|
|
36
36
|
// line, so pause never fires and memory grows unbounded. Cap the partial
|
|
@@ -41,13 +41,13 @@ export function createJSONLStream(stdout, options) {
|
|
|
41
41
|
const completeLines = [];
|
|
42
42
|
let done = false;
|
|
43
43
|
let resolveNext = null;
|
|
44
|
-
//
|
|
44
|
+
// backpressure thresholds. Default matches production (100).
|
|
45
45
|
const pauseThreshold = options?.pauseThreshold ?? 100;
|
|
46
46
|
// Default low-water mark is half the high-water mark for meaningful hysteresis
|
|
47
47
|
// (avoids per-line pause/resume thrashing when callers don't set it explicitly).
|
|
48
48
|
let resumeThreshold = options?.resumeThreshold ?? Math.max(0, Math.floor(pauseThreshold / 2));
|
|
49
49
|
// Clamp misconfiguration: resumeThreshold > pauseThreshold would resume at queue
|
|
50
|
-
// high water then immediately re-pause on the next line → thrash (
|
|
50
|
+
// high water then immediately re-pause on the next line → thrash (nit).
|
|
51
51
|
if (resumeThreshold > pauseThreshold)
|
|
52
52
|
resumeThreshold = pauseThreshold;
|
|
53
53
|
let paused = false;
|
|
@@ -58,7 +58,7 @@ export function createJSONLStream(stdout, options) {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
// Flush any trailing partial line and mark the stream finished. Shared by the
|
|
61
|
-
// 'end'/'close'/'error' handlers so flush logic lives in one place (
|
|
61
|
+
// 'end'/'close'/'error' handlers so flush logic lives in one place (nit).
|
|
62
62
|
function flushAndFinish() {
|
|
63
63
|
if (partialFragments.length > 0) {
|
|
64
64
|
const trimmed = partialFragments.join('').trim();
|
|
@@ -70,7 +70,7 @@ export function createJSONLStream(stdout, options) {
|
|
|
70
70
|
done = true;
|
|
71
71
|
notify();
|
|
72
72
|
}
|
|
73
|
-
//
|
|
73
|
+
// flush an oversize partial line as a bad line. When partialFragments
|
|
74
74
|
// exceeds the byte cap, the partial line is treated as malformed (a single
|
|
75
75
|
// JSON line should never reach 10MB) and reported via onParseError rather
|
|
76
76
|
// than accumulated indefinitely. Resets the buffer so a pathological stream
|
|
@@ -93,7 +93,7 @@ export function createJSONLStream(stdout, options) {
|
|
|
93
93
|
}
|
|
94
94
|
// Apply backpressure after pushing new lines: pause stdout when the queue
|
|
95
95
|
// exceeds the high-water mark so the producer stops feeding until the
|
|
96
|
-
// consumer drains it.
|
|
96
|
+
// consumer drains it.bounds memory in long runs.
|
|
97
97
|
function maybePause() {
|
|
98
98
|
if (pauseThreshold > 0 && !paused && lineQueue.length > pauseThreshold) {
|
|
99
99
|
paused = true;
|
|
@@ -110,7 +110,7 @@ export function createJSONLStream(stdout, options) {
|
|
|
110
110
|
}
|
|
111
111
|
stdout.on('data', (chunk) => {
|
|
112
112
|
const text = chunk.toString('utf-8');
|
|
113
|
-
//
|
|
113
|
+
// split on newlines. The first segment continues the pending partial
|
|
114
114
|
// line (joined with accumulated fragments — one join per chunk, not per
|
|
115
115
|
// byte); subsequent segments are complete lines. The last segment is the
|
|
116
116
|
// new partial tail (kept as a single fragment).
|
|
@@ -119,7 +119,7 @@ export function createJSONLStream(stdout, options) {
|
|
|
119
119
|
// No newline in this chunk: the whole chunk is a partial fragment.
|
|
120
120
|
partialFragments.push(segments[0]);
|
|
121
121
|
partialBytes += segments[0].length;
|
|
122
|
-
//
|
|
122
|
+
// cap the partial line. A never-newline stream would otherwise
|
|
123
123
|
// accumulate fragments without bound (backpressure only counts complete
|
|
124
124
|
// lines). Flush as a bad line once the byte cap is exceeded.
|
|
125
125
|
if (partialBytes > PARTIAL_BYTE_LIMIT) {
|
|
@@ -140,7 +140,7 @@ export function createJSONLStream(stdout, options) {
|
|
|
140
140
|
// Last segment is the new partial tail.
|
|
141
141
|
partialFragments.push(segments[segments.length - 1]);
|
|
142
142
|
partialBytes = segments[segments.length - 1].length;
|
|
143
|
-
//
|
|
143
|
+
// the trailing partial tail can itself exceed the cap if a single
|
|
144
144
|
// chunk is larger than 10MB with no internal newline.
|
|
145
145
|
if (partialBytes > PARTIAL_BYTE_LIMIT) {
|
|
146
146
|
flushOversizePartial();
|
|
@@ -162,7 +162,7 @@ export function createJSONLStream(stdout, options) {
|
|
|
162
162
|
stdout.on('close', () => {
|
|
163
163
|
flushAndFinish();
|
|
164
164
|
});
|
|
165
|
-
//
|
|
165
|
+
// handle stdout 'error' so the generator terminates instead of
|
|
166
166
|
// hanging forever on the `await new Promise` below. Without this, a stdout
|
|
167
167
|
// error (e.g. broken pipe, runner crash) leaves the consumer awaiting a
|
|
168
168
|
// notify that never comes → bridge serial queue blocks permanently. We do
|
|
@@ -44,7 +44,7 @@ export declare class JsonRpcClient<InitializeResult = unknown> {
|
|
|
44
44
|
* Replace the per-run hooks (used by the runner to bridge
|
|
45
45
|
* notifications/server requests into the active turn's translator).
|
|
46
46
|
* Connection-layer hooks (slot cleanup / onConnectionLost) are preserved:
|
|
47
|
-
*
|
|
47
|
+
* an overwrite here previously silenced onClose slot cleanup,
|
|
48
48
|
* leaving dead slots behind after the server process was killed.
|
|
49
49
|
*/
|
|
50
50
|
setHooks(hooks: ClientHooks): void;
|
|
@@ -61,7 +61,7 @@ export class JsonRpcClient {
|
|
|
61
61
|
* Replace the per-run hooks (used by the runner to bridge
|
|
62
62
|
* notifications/server requests into the active turn's translator).
|
|
63
63
|
* Connection-layer hooks (slot cleanup / onConnectionLost) are preserved:
|
|
64
|
-
*
|
|
64
|
+
* an overwrite here previously silenced onClose slot cleanup,
|
|
65
65
|
* leaving dead slots behind after the server process was killed.
|
|
66
66
|
*/
|
|
67
67
|
setHooks(hooks) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ConnectionManager: manages agent-server connections per
|
|
2
|
+
* ConnectionManager: manages agent-server connections per cwd, shared by
|
|
3
3
|
* all workspace-lifetime JSON-line runners (codex app-server, kimi acp,
|
|
4
4
|
* opencode acp, and pi rpc).
|
|
5
5
|
*
|
|
6
|
-
* Each
|
|
6
|
+
* Each cwd gets its own connection (transport + client). Connections are
|
|
7
7
|
* created on demand via `acquire()`, cached for reuse, and released after an
|
|
8
8
|
* idle timeout (30 minutes default).
|
|
9
9
|
*
|
|
@@ -92,9 +92,9 @@ export declare class ConnectionManager<TClient extends ConnectionClient = JsonRp
|
|
|
92
92
|
private readonly logTag;
|
|
93
93
|
private readonly stoppers;
|
|
94
94
|
/** Callback when a connection is lost — cleared from slot map. */
|
|
95
|
-
onConnectionLost?: (
|
|
95
|
+
onConnectionLost?: (cwd: string) => void;
|
|
96
96
|
/**
|
|
97
|
-
*
|
|
97
|
+
* 协议停止通道工厂:连接建立后按 pid 登记到 AgentStopperRegistry,
|
|
98
98
|
* 供 Terminator 在**优雅**停止时回调(win32 上没有可拦截的 SIGTERM,只能靠
|
|
99
99
|
* 协议通道让 agent 自己收摊)。返回 undefined = 该协议无通道。
|
|
100
100
|
*
|
|
@@ -108,37 +108,37 @@ export declare class ConnectionManager<TClient extends ConnectionClient = JsonRp
|
|
|
108
108
|
}) => AgentStopper | undefined;
|
|
109
109
|
constructor(opts: ConnectionManagerOptions<TClient>);
|
|
110
110
|
/**
|
|
111
|
-
* Acquire a connection for the given
|
|
111
|
+
* Acquire a connection for the given cwd.
|
|
112
112
|
* Creates a new connection if one does not exist or the previous one was lost
|
|
113
113
|
* (or, for session-bound protocols, bound to a different session).
|
|
114
114
|
* Serializes creation so concurrent calls share the same connection.
|
|
115
115
|
*/
|
|
116
|
-
acquire(
|
|
116
|
+
acquire(cwd: string, req?: AcquireRequest): Promise<TClient>;
|
|
117
117
|
/**
|
|
118
118
|
* Record the session id a fresh connection actually bound to (e.g. discovered
|
|
119
119
|
* via a protocol `get_state` after a fresh spawn). This lets a subsequent run
|
|
120
120
|
* resume the SAME session on the live connection instead of respawning it.
|
|
121
121
|
*/
|
|
122
|
-
bindSession(
|
|
122
|
+
bindSession(cwd: string, sessionId: string): void;
|
|
123
123
|
/**
|
|
124
|
-
* Release (dispose) a connection for the given
|
|
124
|
+
* Release (dispose) a connection for the given cwd.
|
|
125
125
|
*/
|
|
126
|
-
release(
|
|
126
|
+
release(cwd: string): Promise<void>;
|
|
127
127
|
/**
|
|
128
128
|
* Dispose all connections.
|
|
129
129
|
*/
|
|
130
130
|
disposeAll(): Promise<void>;
|
|
131
131
|
/**
|
|
132
|
-
* Notify that the
|
|
132
|
+
* Notify that the cwd is active — disarm the idle timer.
|
|
133
133
|
*/
|
|
134
|
-
notifyActivity(
|
|
134
|
+
notifyActivity(cwd: string): void;
|
|
135
135
|
/**
|
|
136
|
-
* Notify that the
|
|
136
|
+
* Notify that the cwd is idle — arm the idle timer.
|
|
137
137
|
*
|
|
138
138
|
* `idleTtlMs: 0` = 不回收(与 claude 会话层的 `armIdleTimer` 同口径;按 0
|
|
139
139
|
* setTimeout 会秒删刚建好的连接,等于每条消息重起一次进程)。
|
|
140
140
|
*/
|
|
141
|
-
notifyIdle(
|
|
141
|
+
notifyIdle(cwd: string): void;
|
|
142
142
|
private createClient;
|
|
143
143
|
private clearIdleTimer;
|
|
144
144
|
private disposeSlot;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ConnectionManager: manages agent-server connections per
|
|
2
|
+
* ConnectionManager: manages agent-server connections per cwd, shared by
|
|
3
3
|
* all workspace-lifetime JSON-line runners (codex app-server, kimi acp,
|
|
4
4
|
* opencode acp, and pi rpc).
|
|
5
5
|
*
|
|
6
|
-
* Each
|
|
6
|
+
* Each cwd gets its own connection (transport + client). Connections are
|
|
7
7
|
* created on demand via `acquire()`, cached for reuse, and released after an
|
|
8
8
|
* idle timeout (30 minutes default).
|
|
9
9
|
*
|
|
@@ -34,7 +34,7 @@ export class ConnectionManager {
|
|
|
34
34
|
/** Callback when a connection is lost — cleared from slot map. */
|
|
35
35
|
onConnectionLost;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
37
|
+
* 协议停止通道工厂:连接建立后按 pid 登记到 AgentStopperRegistry,
|
|
38
38
|
* 供 Terminator 在**优雅**停止时回调(win32 上没有可拦截的 SIGTERM,只能靠
|
|
39
39
|
* 协议通道让 agent 自己收摊)。返回 undefined = 该协议无通道。
|
|
40
40
|
*
|
|
@@ -62,13 +62,13 @@ export class ConnectionManager {
|
|
|
62
62
|
this.stoppers = opts.stoppers ?? agentStopperRegistry;
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
* Acquire a connection for the given
|
|
65
|
+
* Acquire a connection for the given cwd.
|
|
66
66
|
* Creates a new connection if one does not exist or the previous one was lost
|
|
67
67
|
* (or, for session-bound protocols, bound to a different session).
|
|
68
68
|
* Serializes creation so concurrent calls share the same connection.
|
|
69
69
|
*/
|
|
70
|
-
async acquire(
|
|
71
|
-
const existing = this.slots.get(
|
|
70
|
+
async acquire(cwd, req = {}) {
|
|
71
|
+
const existing = this.slots.get(cwd);
|
|
72
72
|
if (existing) {
|
|
73
73
|
// If a create is in flight, wait for it
|
|
74
74
|
if (existing.createPromise) {
|
|
@@ -85,10 +85,10 @@ export class ConnectionManager {
|
|
|
85
85
|
})) {
|
|
86
86
|
return existing.client;
|
|
87
87
|
}
|
|
88
|
-
this.disposeSlot(
|
|
88
|
+
this.disposeSlot(cwd);
|
|
89
89
|
}
|
|
90
|
-
const createPromise = this.createClient(
|
|
91
|
-
this.slots.set(
|
|
90
|
+
const createPromise = this.createClient(cwd, req);
|
|
91
|
+
this.slots.set(cwd, {
|
|
92
92
|
client: null, // placeholder
|
|
93
93
|
boundSessionId: req.sessionId,
|
|
94
94
|
idleTimer: null,
|
|
@@ -99,11 +99,11 @@ export class ConnectionManager {
|
|
|
99
99
|
// 竞态:创建期间 release()/disposeAll() 已把 slot 删掉(并可能已
|
|
100
100
|
// dispose 连接)。此时不能再把新连接塞回 slot——否则会复活一个无人管理、
|
|
101
101
|
// 无 idle timer 的连接泄漏。归还给调用者继续使用,但不再缓存。
|
|
102
|
-
const slotAfterCreate = this.slots.get(
|
|
102
|
+
const slotAfterCreate = this.slots.get(cwd);
|
|
103
103
|
if (!slotAfterCreate || slotAfterCreate.createPromise !== createPromise) {
|
|
104
104
|
return client;
|
|
105
105
|
}
|
|
106
|
-
this.slots.set(
|
|
106
|
+
this.slots.set(cwd, {
|
|
107
107
|
client,
|
|
108
108
|
boundSessionId: req.sessionId,
|
|
109
109
|
idleTimer: null,
|
|
@@ -114,9 +114,9 @@ export class ConnectionManager {
|
|
|
114
114
|
catch (err) {
|
|
115
115
|
// 只删除自己的槽位:并发 release + 重新 acquire 后 slot 可能已被新的
|
|
116
116
|
// createPromise 占据,误删会破坏新连接。
|
|
117
|
-
const current = this.slots.get(
|
|
117
|
+
const current = this.slots.get(cwd);
|
|
118
118
|
if (current && current.createPromise === createPromise) {
|
|
119
|
-
this.slots.delete(
|
|
119
|
+
this.slots.delete(cwd);
|
|
120
120
|
}
|
|
121
121
|
throw err;
|
|
122
122
|
}
|
|
@@ -126,16 +126,16 @@ export class ConnectionManager {
|
|
|
126
126
|
* via a protocol `get_state` after a fresh spawn). This lets a subsequent run
|
|
127
127
|
* resume the SAME session on the live connection instead of respawning it.
|
|
128
128
|
*/
|
|
129
|
-
bindSession(
|
|
130
|
-
const slot = this.slots.get(
|
|
129
|
+
bindSession(cwd, sessionId) {
|
|
130
|
+
const slot = this.slots.get(cwd);
|
|
131
131
|
if (slot)
|
|
132
132
|
slot.boundSessionId = sessionId;
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
|
-
* Release (dispose) a connection for the given
|
|
135
|
+
* Release (dispose) a connection for the given cwd.
|
|
136
136
|
*/
|
|
137
|
-
async release(
|
|
138
|
-
this.disposeSlot(
|
|
137
|
+
async release(cwd) {
|
|
138
|
+
this.disposeSlot(cwd);
|
|
139
139
|
}
|
|
140
140
|
/**
|
|
141
141
|
* Dispose all connections.
|
|
@@ -145,46 +145,46 @@ export class ConnectionManager {
|
|
|
145
145
|
await Promise.all(workspaces.map((w) => this.disposeSlot(w)));
|
|
146
146
|
}
|
|
147
147
|
/**
|
|
148
|
-
* Notify that the
|
|
148
|
+
* Notify that the cwd is active — disarm the idle timer.
|
|
149
149
|
*/
|
|
150
|
-
notifyActivity(
|
|
151
|
-
const slot = this.slots.get(
|
|
150
|
+
notifyActivity(cwd) {
|
|
151
|
+
const slot = this.slots.get(cwd);
|
|
152
152
|
if (slot) {
|
|
153
153
|
this.clearIdleTimer(slot);
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
/**
|
|
157
|
-
* Notify that the
|
|
157
|
+
* Notify that the cwd is idle — arm the idle timer.
|
|
158
158
|
*
|
|
159
159
|
* `idleTtlMs: 0` = 不回收(与 claude 会话层的 `armIdleTimer` 同口径;按 0
|
|
160
160
|
* setTimeout 会秒删刚建好的连接,等于每条消息重起一次进程)。
|
|
161
161
|
*/
|
|
162
|
-
notifyIdle(
|
|
162
|
+
notifyIdle(cwd) {
|
|
163
163
|
if (this.idleTtlMs <= 0)
|
|
164
164
|
return;
|
|
165
|
-
const slot = this.slots.get(
|
|
165
|
+
const slot = this.slots.get(cwd);
|
|
166
166
|
if (slot) {
|
|
167
167
|
this.clearIdleTimer(slot);
|
|
168
168
|
slot.idleTimer = setTimeout(() => {
|
|
169
|
-
getLogger().info(`[${this.logTag}] idle timeout for
|
|
170
|
-
this.disposeSlot(
|
|
169
|
+
getLogger().info(`[${this.logTag}] idle timeout for cwd=${cwd}, releasing connection`);
|
|
170
|
+
this.disposeSlot(cwd);
|
|
171
171
|
}, this.idleTtlMs);
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
// =========================================================================
|
|
175
175
|
// Internal
|
|
176
176
|
// =========================================================================
|
|
177
|
-
async createClient(
|
|
177
|
+
async createClient(cwd, req) {
|
|
178
178
|
let client = null;
|
|
179
179
|
const transport = new JsonlRpcTransport({
|
|
180
180
|
binary: this.binary,
|
|
181
181
|
args: this.buildArgs(req),
|
|
182
|
-
cwd:
|
|
182
|
+
cwd: cwd,
|
|
183
183
|
env: this.env,
|
|
184
184
|
stoppers: this.stoppers,
|
|
185
185
|
// 通道工厂要拿到**连接本身**:协议取消(codex turn/interrupt、ACP
|
|
186
186
|
// session/cancel)必须发在这条连接上,不能借 runner 的共享状态——那会
|
|
187
|
-
// 打断另一
|
|
187
|
+
// 打断另一 cwd 正在跑的 turn。工厂是在 transport.start() 内侧调用
|
|
188
188
|
// 的,那时 client 已由下面的 clientFactory 赋好。
|
|
189
189
|
stopper: this.stopper
|
|
190
190
|
? (pid) => this.stopper?.({ pid, client: client })
|
|
@@ -194,12 +194,12 @@ export class ConnectionManager {
|
|
|
194
194
|
transport,
|
|
195
195
|
requestTimeoutMs: this.requestTimeoutMs,
|
|
196
196
|
baseOnClose: () => {
|
|
197
|
-
getLogger().info(`[${this.logTag}] connection closed
|
|
197
|
+
getLogger().info(`[${this.logTag}] connection closed cwd=${cwd}`);
|
|
198
198
|
// 只清理自己创建的 slot:并发 release + 重新 acquire 后 slot 可能已被
|
|
199
199
|
// 新连接占据,误删会破坏新连接。
|
|
200
|
-
if (this.slots.get(
|
|
201
|
-
this.slots.delete(
|
|
202
|
-
this.onConnectionLost?.(
|
|
200
|
+
if (this.slots.get(cwd)?.client === client) {
|
|
201
|
+
this.slots.delete(cwd);
|
|
202
|
+
this.onConnectionLost?.(cwd);
|
|
203
203
|
}
|
|
204
204
|
},
|
|
205
205
|
});
|
|
@@ -212,18 +212,18 @@ export class ConnectionManager {
|
|
|
212
212
|
slot.idleTimer = null;
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
|
-
async disposeSlot(
|
|
216
|
-
const slot = this.slots.get(
|
|
215
|
+
async disposeSlot(cwd) {
|
|
216
|
+
const slot = this.slots.get(cwd);
|
|
217
217
|
if (!slot)
|
|
218
218
|
return;
|
|
219
|
-
this.slots.delete(
|
|
219
|
+
this.slots.delete(cwd);
|
|
220
220
|
this.clearIdleTimer(slot);
|
|
221
221
|
if (slot.client) {
|
|
222
222
|
try {
|
|
223
223
|
await slot.client.dispose();
|
|
224
224
|
}
|
|
225
225
|
catch (err) {
|
|
226
|
-
getLogger().warn(`[${this.logTag}] dispose error
|
|
226
|
+
getLogger().warn(`[${this.logTag}] dispose error cwd=${cwd}: ${err}`);
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
}
|
|
@@ -42,7 +42,7 @@ export declare class JsonlRpcTransport {
|
|
|
42
42
|
/** 终止器注入(测试用);默认按平台建实现 */
|
|
43
43
|
terminator?: Terminator;
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* 协议停止通道工厂:spawn 成功后按 pid 建通道并登记到
|
|
46
46
|
* AgentStopperRegistry,进程退出/关闭时注销。返回 undefined = 无通道。
|
|
47
47
|
*/
|
|
48
48
|
stopper?: (pid: number) => AgentStopper | undefined;
|
|
@@ -70,7 +70,7 @@ export class JsonlRpcTransport {
|
|
|
70
70
|
// agent 是用户自己的可信二进制,provider 认证依赖 API key /
|
|
71
71
|
// 自定义 provider 的 env_key,代理环境依赖 HTTP(S)_PROXY、TMPDIR 等;
|
|
72
72
|
// 任何白名单收窄都会打断认证或网络。调用方 this.env 覆盖 process.env 同名键。
|
|
73
|
-
// env 覆盖必须大小写不敏感合并(win32 PATH/Path
|
|
73
|
+
// env 覆盖必须大小写不敏感合并(win32 PATH/Path 双键防护)
|
|
74
74
|
const childEnv = mergeProcessEnv(process.env, this.env);
|
|
75
75
|
const proc = spawnProcess(this.binary, this.args, {
|
|
76
76
|
cwd: this.cwd,
|
|
@@ -195,7 +195,7 @@ export class JsonlRpcTransport {
|
|
|
195
195
|
}
|
|
196
196
|
try {
|
|
197
197
|
// 入队后顺序 flush;write() 返回 false(高水位)时暂停直到 drain,
|
|
198
|
-
// 避免大消息/突发消息在 Node
|
|
198
|
+
// 避免大消息/突发消息在 Node 内部无限缓冲。
|
|
199
199
|
this.writeQueue.push(Buffer.from(JSON.stringify(msg) + '\n', 'utf8'));
|
|
200
200
|
this.flush();
|
|
201
201
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Normalized usage extracted from a result event.
|
|
3
3
|
*
|
|
4
|
-
* @module runner/common/usage
|
|
4
|
+
* @module runner/common/result-usage
|
|
5
5
|
*/
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
7
7
|
// Implementation
|
|
@@ -30,4 +30,4 @@ export function normalizeResultUsage(usage) {
|
|
|
30
30
|
contextLength,
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
//# sourceMappingURL=usage.js.map
|
|
33
|
+
//# sourceMappingURL=result-usage.js.map
|