@downcity/agent 1.1.217 → 1.1.224
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/bin/agent/local/Agent.d.ts +1 -34
- package/bin/agent/local/Agent.d.ts.map +1 -1
- package/bin/agent/local/Agent.js +1 -44
- package/bin/agent/local/Agent.js.map +1 -1
- package/bin/agent/local/services/AgentAssemblyService.d.ts.map +1 -1
- package/bin/agent/local/services/AgentAssemblyService.js +35 -2
- package/bin/agent/local/services/AgentAssemblyService.js.map +1 -1
- package/bin/agent/local/services/AgentSessions.d.ts +6 -0
- package/bin/agent/local/services/AgentSessions.d.ts.map +1 -1
- package/bin/agent/local/services/AgentSessions.js +43 -4
- package/bin/agent/local/services/AgentSessions.js.map +1 -1
- package/bin/agent/remote/RemoteAgent.d.ts +1 -35
- package/bin/agent/remote/RemoteAgent.d.ts.map +1 -1
- package/bin/agent/remote/RemoteAgent.js +1 -37
- package/bin/agent/remote/RemoteAgent.js.map +1 -1
- package/bin/agent/remote/RemoteSession.d.ts +26 -41
- package/bin/agent/remote/RemoteSession.d.ts.map +1 -1
- package/bin/agent/remote/RemoteSession.js +75 -107
- package/bin/agent/remote/RemoteSession.js.map +1 -1
- package/bin/agent/remote/RemoteTransport.d.ts +15 -27
- package/bin/agent/remote/RemoteTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts +10 -21
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js +24 -46
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js.map +1 -1
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts +10 -20
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.js +10 -16
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.js.map +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +2 -2
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
- package/bin/executor/types/SessionHistoryPaths.d.ts +1 -1
- package/bin/executor/types/SessionRecords.d.ts +2 -0
- package/bin/executor/types/SessionRecords.d.ts.map +1 -1
- package/bin/executor/types/SessionRecords.js.map +1 -1
- package/bin/index.d.ts +6 -3
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +1 -0
- package/bin/index.js.map +1 -1
- package/bin/rpc/Client.d.ts +12 -34
- package/bin/rpc/Client.d.ts.map +1 -1
- package/bin/rpc/Client.js +31 -70
- package/bin/rpc/Client.js.map +1 -1
- package/bin/session/Session.d.ts +22 -4
- package/bin/session/Session.d.ts.map +1 -1
- package/bin/session/Session.js +95 -21
- package/bin/session/Session.js.map +1 -1
- package/bin/session/browse/Browse.d.ts.map +1 -1
- package/bin/session/browse/Browse.js +49 -18
- package/bin/session/browse/Browse.js.map +1 -1
- package/bin/session/recorder/JsonlSessionMessageStore.d.ts +51 -0
- package/bin/session/recorder/JsonlSessionMessageStore.d.ts.map +1 -0
- package/bin/session/recorder/JsonlSessionMessageStore.js +231 -0
- package/bin/session/recorder/JsonlSessionMessageStore.js.map +1 -0
- package/bin/session/recorder/SessionMessageCodec.d.ts +20 -0
- package/bin/session/recorder/SessionMessageCodec.d.ts.map +1 -0
- package/bin/session/recorder/SessionMessageCodec.js +257 -0
- package/bin/session/recorder/SessionMessageCodec.js.map +1 -0
- package/bin/session/recorder/SessionRecorder.d.ts +186 -0
- package/bin/session/recorder/SessionRecorder.d.ts.map +1 -0
- package/bin/session/recorder/SessionRecorder.js +655 -0
- package/bin/session/recorder/SessionRecorder.js.map +1 -0
- package/bin/session/recorder/SessionRecorderCompaction.d.ts +18 -0
- package/bin/session/recorder/SessionRecorderCompaction.d.ts.map +1 -0
- package/bin/session/recorder/SessionRecorderCompaction.js +142 -0
- package/bin/session/recorder/SessionRecorderCompaction.js.map +1 -0
- package/bin/session/recorder/SessionRecorderHistoryStore.d.ts +66 -0
- package/bin/session/recorder/SessionRecorderHistoryStore.d.ts.map +1 -0
- package/bin/session/recorder/SessionRecorderHistoryStore.js +195 -0
- package/bin/session/recorder/SessionRecorderHistoryStore.js.map +1 -0
- package/bin/session/runtime/SessionEventHub.d.ts +12 -5
- package/bin/session/runtime/SessionEventHub.d.ts.map +1 -1
- package/bin/session/runtime/SessionEventHub.js +11 -6
- package/bin/session/runtime/SessionEventHub.js.map +1 -1
- package/bin/session/runtime/SessionPromptRuntime.d.ts +9 -15
- package/bin/session/runtime/SessionPromptRuntime.d.ts.map +1 -1
- package/bin/session/runtime/SessionPromptRuntime.js +48 -30
- package/bin/session/runtime/SessionPromptRuntime.js.map +1 -1
- package/bin/session/services/SessionStateService.d.ts +9 -5
- package/bin/session/services/SessionStateService.d.ts.map +1 -1
- package/bin/session/services/SessionStateService.js +138 -74
- package/bin/session/services/SessionStateService.js.map +1 -1
- package/bin/session/services/SessionTurnService.d.ts +6 -7
- package/bin/session/services/SessionTurnService.d.ts.map +1 -1
- package/bin/session/services/SessionTurnService.js +84 -60
- package/bin/session/services/SessionTurnService.js.map +1 -1
- package/bin/session/services/SessionViewService.d.ts +8 -3
- package/bin/session/services/SessionViewService.d.ts.map +1 -1
- package/bin/session/services/SessionViewService.js +10 -5
- package/bin/session/services/SessionViewService.js.map +1 -1
- package/bin/session/storage/Paths.d.ts +1 -1
- package/bin/session/storage/Paths.d.ts.map +1 -1
- package/bin/session/storage/Paths.js +2 -2
- package/bin/session/storage/Paths.js.map +1 -1
- package/bin/session/storage/Persistence.d.ts +6 -0
- package/bin/session/storage/Persistence.d.ts.map +1 -1
- package/bin/session/storage/Persistence.js +7 -0
- package/bin/session/storage/Persistence.js.map +1 -1
- package/bin/session/storage/RuntimeSessionPort.d.ts +3 -3
- package/bin/session/storage/RuntimeSessionPort.d.ts.map +1 -1
- package/bin/session/storage/RuntimeSessionPort.js +2 -2
- package/bin/session/storage/RuntimeSessionPort.js.map +1 -1
- package/bin/types/agent/SessionActor.d.ts +15 -5
- package/bin/types/agent/SessionActor.d.ts.map +1 -1
- package/bin/types/rpc/RpcProtocol.d.ts +48 -61
- package/bin/types/rpc/RpcProtocol.d.ts.map +1 -1
- package/bin/types/runtime/agent/AgentContext.d.ts +5 -4
- package/bin/types/runtime/agent/AgentContext.d.ts.map +1 -1
- package/bin/types/runtime/agent/AgentContext.js.map +1 -1
- package/bin/types/session/SessionApproval.d.ts +97 -0
- package/bin/types/session/SessionApproval.d.ts.map +1 -0
- package/bin/types/session/SessionApproval.js +7 -0
- package/bin/types/session/SessionApproval.js.map +1 -0
- package/bin/types/session/SessionMessage.d.ts +223 -0
- package/bin/types/session/SessionMessage.d.ts.map +1 -0
- package/bin/types/session/SessionMessage.js +8 -0
- package/bin/types/session/SessionMessage.js.map +1 -0
- package/bin/types/session/SessionMutation.d.ts +116 -0
- package/bin/types/session/SessionMutation.d.ts.map +1 -0
- package/bin/types/session/SessionMutation.js +19 -0
- package/bin/types/session/SessionMutation.js.map +1 -0
- package/bin/types/session/SessionOptions.d.ts +9 -0
- package/bin/types/session/SessionOptions.d.ts.map +1 -1
- package/package.json +3 -3
- package/scripts/agent-env.test.mjs +4 -4
- package/scripts/remote-session-reconnect.test.mjs +7 -3
- package/scripts/session-action-message.test.mjs +98 -27
- package/scripts/session-history-inflight.test.mjs +2 -2
- package/scripts/session-list-title.test.mjs +6 -19
- package/scripts/session-prompt-runtime.test.mjs +7 -19
- package/scripts/session-recorder.test.mjs +199 -0
- package/scripts/session-title-event.test.mjs +10 -18
- package/src/agent/local/Agent.ts +1 -55
- package/src/agent/local/services/AgentAssemblyService.ts +39 -3
- package/src/agent/local/services/AgentSessions.ts +48 -3
- package/src/agent/remote/RemoteAgent.ts +1 -54
- package/src/agent/remote/RemoteSession.ts +106 -136
- package/src/agent/remote/RemoteTransport.ts +30 -30
- package/src/agent/remote/transports/HttpRemoteAgentTransport.ts +52 -77
- package/src/agent/remote/transports/RpcRemoteAgentTransport.ts +30 -34
- package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +2 -2
- package/src/executor/types/SessionHistoryPaths.ts +1 -1
- package/src/executor/types/SessionRecords.ts +2 -0
- package/src/index.ts +36 -10
- package/src/rpc/Client.ts +58 -95
- package/src/session/Session.ts +128 -37
- package/src/session/browse/Browse.ts +51 -22
- package/src/session/recorder/JsonlSessionMessageStore.ts +246 -0
- package/src/session/recorder/SessionMessageCodec.ts +284 -0
- package/src/session/recorder/SessionRecorder.ts +871 -0
- package/src/session/recorder/SessionRecorderCompaction.ts +188 -0
- package/src/session/recorder/SessionRecorderHistoryStore.ts +276 -0
- package/src/session/runtime/SessionEventHub.ts +25 -12
- package/src/session/runtime/SessionPromptRuntime.ts +60 -43
- package/src/session/services/SessionStateService.ts +159 -86
- package/src/session/services/SessionTurnService.ts +91 -73
- package/src/session/services/SessionViewService.ts +25 -13
- package/src/session/storage/Paths.ts +2 -2
- package/src/session/storage/Persistence.ts +13 -0
- package/src/session/storage/RuntimeSessionPort.ts +8 -9
- package/src/types/agent/SessionActor.ts +31 -8
- package/src/types/rpc/RpcProtocol.ts +44 -67
- package/src/types/runtime/agent/AgentContext.ts +9 -7
- package/src/types/session/SessionApproval.ts +108 -0
- package/src/types/session/SessionMessage.ts +253 -0
- package/src/types/session/SessionMutation.ts +141 -0
- package/src/types/session/SessionOptions.ts +25 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/bin/session/SessionEventMapper.d.ts +0 -32
- package/bin/session/SessionEventMapper.d.ts.map +0 -1
- package/bin/session/SessionEventMapper.js +0 -131
- package/bin/session/SessionEventMapper.js.map +0 -1
- package/bin/types/sdk/AgentSessionEvent.d.ts +0 -302
- package/bin/types/sdk/AgentSessionEvent.d.ts.map +0 -1
- package/bin/types/sdk/AgentSessionEvent.js +0 -9
- package/bin/types/sdk/AgentSessionEvent.js.map +0 -1
- package/bin/types/sdk/InternalUiChunkEvent.d.ts +0 -100
- package/bin/types/sdk/InternalUiChunkEvent.d.ts.map +0 -1
- package/bin/types/sdk/InternalUiChunkEvent.js +0 -9
- package/bin/types/sdk/InternalUiChunkEvent.js.map +0 -1
- package/scripts/session-history-archive.test.mjs +0 -188
- package/src/session/SessionEventMapper.ts +0 -148
- package/src/types/sdk/AgentSessionEvent.ts +0 -370
- package/src/types/sdk/InternalUiChunkEvent.ts +0 -108
|
@@ -1,29 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* RemoteSession
|
|
2
|
+
* RemoteSession:统一 SessionMutation 协议的远程 Session 客户端。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* - 这里只负责 session 级 API、turn lifecycle 与事件泵。
|
|
6
|
-
* - 具体 HTTP / RPC 细节由 RemoteSessionTransport 提供。
|
|
4
|
+
* 事件泵只传输一种 Mutation;审批查询、模式和决策全部绑定当前 Session。
|
|
7
5
|
*/
|
|
8
6
|
|
|
9
7
|
import type {
|
|
10
8
|
AgentSessionConfigSnapshot,
|
|
11
9
|
AgentSessionForkInput,
|
|
12
|
-
AgentSessionRecordsInput,
|
|
13
|
-
AgentSessionRecordsPage,
|
|
14
10
|
AgentSessionInfo,
|
|
15
11
|
AgentSessionSetInput,
|
|
16
12
|
AgentSessionSystemSnapshot,
|
|
17
13
|
} from "@/types/agent/SessionTypes.js";
|
|
18
14
|
import type { RemoteAgentSession } from "@/types/agent/SessionActor.js";
|
|
19
|
-
import { isAgentSessionPromptInputEmpty } from "@/types/sdk/AgentSessionPrompt.js";
|
|
20
|
-
import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
|
|
21
15
|
import type {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
ResolveSessionApprovalInput,
|
|
17
|
+
SessionApproval,
|
|
18
|
+
SessionApprovalModeSnapshot,
|
|
19
|
+
SessionApprovalResult,
|
|
20
|
+
SetSessionApprovalModeInput,
|
|
21
|
+
} from "@/types/session/SessionApproval.js";
|
|
22
|
+
import type {
|
|
23
|
+
SessionMutation,
|
|
24
|
+
SessionMutationSubscriber,
|
|
25
|
+
SessionMutationUnsubscribe,
|
|
26
|
+
} from "@/types/session/SessionMutation.js";
|
|
27
|
+
import type {
|
|
28
|
+
ListSessionMessagesInput,
|
|
29
|
+
SessionMessagePage,
|
|
30
|
+
} from "@/types/session/SessionMessage.js";
|
|
31
|
+
import { isAgentSessionPromptInputEmpty } from "@/types/sdk/AgentSessionPrompt.js";
|
|
26
32
|
import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
|
|
33
|
+
import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
|
|
27
34
|
import type {
|
|
28
35
|
AgentSessionTurnHandle,
|
|
29
36
|
AgentSessionTurnResult,
|
|
@@ -37,29 +44,27 @@ import type {
|
|
|
37
44
|
type Deferred<T> = {
|
|
38
45
|
/** 当前延迟 Promise。 */
|
|
39
46
|
promise: Promise<T>;
|
|
40
|
-
/**
|
|
47
|
+
/** 兑现当前 Promise。 */
|
|
41
48
|
resolve: (value: T) => void;
|
|
42
49
|
};
|
|
43
50
|
|
|
44
51
|
type RemoteTurnLifecycle = {
|
|
45
|
-
/** 当前
|
|
46
|
-
|
|
47
|
-
/** 当前
|
|
52
|
+
/** 当前 Turn 标识。 */
|
|
53
|
+
turn_id: string;
|
|
54
|
+
/** 当前 Turn 的最终结果;运行中为 null。 */
|
|
48
55
|
result: AgentSessionTurnResult | null;
|
|
49
|
-
/** 当前
|
|
56
|
+
/** 当前 Turn 完成 Promise 控制器。 */
|
|
50
57
|
deferred_finished: Deferred<AgentSessionTurnResult>;
|
|
51
58
|
};
|
|
52
59
|
|
|
53
|
-
/**
|
|
54
|
-
* 远程 Session 客户端。
|
|
55
|
-
*/
|
|
60
|
+
/** 远程 Session 客户端。 */
|
|
56
61
|
export class RemoteSession implements RemoteAgentSession {
|
|
57
62
|
readonly id: string;
|
|
58
63
|
readonly agentId: string;
|
|
59
64
|
readonly config: AgentSessionConfigSnapshot;
|
|
60
65
|
|
|
61
66
|
private readonly transport: RemoteSessionTransport;
|
|
62
|
-
private readonly event_hub
|
|
67
|
+
private readonly event_hub: SessionEventHub;
|
|
63
68
|
private readonly turns_by_id = new Map<string, RemoteTurnLifecycle>();
|
|
64
69
|
private readonly completed_turn_ids: string[] = [];
|
|
65
70
|
private event_pump_connect_promise: Promise<void> | null = null;
|
|
@@ -71,66 +76,58 @@ export class RemoteSession implements RemoteAgentSession {
|
|
|
71
76
|
this.transport = transport;
|
|
72
77
|
this.id = info.sessionId;
|
|
73
78
|
this.agentId = info.agentId;
|
|
74
|
-
// 远程 session 不暴露服务端模型实例,只保留可序列化配置。
|
|
75
79
|
this.config = {
|
|
76
80
|
...(info.modelId ? { modelId: info.modelId } : {}),
|
|
77
81
|
...(info.modelLabel ? { modelLabel: info.modelLabel } : {}),
|
|
78
82
|
};
|
|
83
|
+
this.event_hub = new SessionEventHub({
|
|
84
|
+
create_reply: (mutation) => ({
|
|
85
|
+
approval: async ({ decision }) => {
|
|
86
|
+
return await this.resolve_approval({
|
|
87
|
+
approval_id: require_approval_id(mutation),
|
|
88
|
+
decision,
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
79
93
|
}
|
|
80
94
|
|
|
81
95
|
/** 按稳定模型 ID 更新远程 Session 模型。 */
|
|
82
96
|
async set(input: AgentSessionSetInput): Promise<void> {
|
|
83
|
-
if (input.model)
|
|
84
|
-
throw new Error("Remote session.set does not accept a local model instance.");
|
|
85
|
-
}
|
|
97
|
+
if (input.model) throw new Error("Remote session.set does not accept a local model instance.");
|
|
86
98
|
const model_id = String(input.modelId || "").trim();
|
|
87
|
-
if (!model_id)
|
|
88
|
-
throw new Error("Remote session.set requires modelId.");
|
|
89
|
-
}
|
|
99
|
+
if (!model_id) throw new Error("Remote session.set requires modelId.");
|
|
90
100
|
const info = await this.transport.set(this.id, { modelId: model_id });
|
|
91
101
|
this.config.modelId = info.modelId;
|
|
92
102
|
this.config.modelLabel = info.modelLabel;
|
|
93
103
|
}
|
|
94
104
|
|
|
95
|
-
/**
|
|
96
|
-
* 读取当前远程 session 详情。
|
|
97
|
-
*/
|
|
105
|
+
/** 读取当前远程 Session 详情。 */
|
|
98
106
|
async get_info(): Promise<AgentSessionInfo> {
|
|
99
107
|
return await this.transport.get_info(this.id);
|
|
100
108
|
}
|
|
101
109
|
|
|
102
|
-
/**
|
|
103
|
-
* 向当前远程 session 追加一条新的 prompt。
|
|
104
|
-
*/
|
|
110
|
+
/** 向当前远程 Session 追加 Prompt。 */
|
|
105
111
|
async prompt(input: AgentSessionPromptInput): Promise<AgentSessionTurnHandle> {
|
|
106
112
|
if (isAgentSessionPromptInputEmpty(input)) {
|
|
107
113
|
throw new Error("remote session.prompt requires a non-empty query");
|
|
108
114
|
}
|
|
109
|
-
|
|
110
115
|
await this.ensure_event_pump();
|
|
111
116
|
const turn = await this.transport.prompt(this.id, input);
|
|
112
|
-
|
|
113
|
-
return create_turn_handle(lifecycle);
|
|
117
|
+
return create_turn_handle(this.ensure_turn_lifecycle(turn.id));
|
|
114
118
|
}
|
|
115
119
|
|
|
116
|
-
/**
|
|
117
|
-
* 停止当前远程 session turn,并取消未吸收队列。
|
|
118
|
-
*/
|
|
120
|
+
/** 停止当前远程 Session Turn。 */
|
|
119
121
|
async stop(): Promise<AgentSessionStopResult> {
|
|
120
122
|
await this.ensure_event_pump();
|
|
121
123
|
return await this.transport.stop(this.id);
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
/**
|
|
125
|
-
|
|
126
|
-
*/
|
|
127
|
-
subscribe(subscriber: AgentSessionSubscriber): AgentSessionUnsubscribe {
|
|
126
|
+
/** 订阅当前 Session 的全部未来 Mutation。 */
|
|
127
|
+
subscribe(subscriber: SessionMutationSubscriber): SessionMutationUnsubscribe {
|
|
128
128
|
this.event_subscriber_count += 1;
|
|
129
129
|
void this.ensure_event_pump().catch((error) => {
|
|
130
|
-
this.
|
|
131
|
-
type: "error",
|
|
132
|
-
message: error instanceof Error ? error.message : String(error),
|
|
133
|
-
});
|
|
130
|
+
this.fail_pending_turns(error instanceof Error ? error.message : String(error));
|
|
134
131
|
});
|
|
135
132
|
const unsubscribe = this.event_hub.subscribe(subscriber);
|
|
136
133
|
return () => {
|
|
@@ -140,35 +137,44 @@ export class RemoteSession implements RemoteAgentSession {
|
|
|
140
137
|
};
|
|
141
138
|
}
|
|
142
139
|
|
|
143
|
-
/**
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
async records(input?: AgentSessionRecordsInput): Promise<AgentSessionRecordsPage> {
|
|
147
|
-
return await this.transport.records(this.id, input);
|
|
140
|
+
/** 读取远程 Message 快照。 */
|
|
141
|
+
async messages(input?: ListSessionMessagesInput): Promise<SessionMessagePage> {
|
|
142
|
+
return await this.transport.messages(this.id, input);
|
|
148
143
|
}
|
|
149
144
|
|
|
150
|
-
/**
|
|
151
|
-
* 读取远程 session 当前生效的 system prompt 快照。
|
|
152
|
-
*/
|
|
145
|
+
/** 读取远程 Session 的 System 快照。 */
|
|
153
146
|
async system(): Promise<AgentSessionSystemSnapshot> {
|
|
154
147
|
return await this.transport.system(this.id);
|
|
155
148
|
}
|
|
156
149
|
|
|
157
|
-
/**
|
|
158
|
-
|
|
159
|
-
|
|
150
|
+
/** 列出当前远程 Session 的 pending 工具审批。 */
|
|
151
|
+
async approvals(): Promise<SessionApproval[]> {
|
|
152
|
+
return await this.transport.approvals(this.id);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** 读取当前远程 Session 的工具审批模式。 */
|
|
156
|
+
async approval_mode(): Promise<SessionApprovalModeSnapshot> {
|
|
157
|
+
return await this.transport.approval_mode(this.id);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** 更新当前远程 Session 的工具审批模式。 */
|
|
161
|
+
async set_approval_mode(input: SetSessionApprovalModeInput): Promise<SessionApprovalModeSnapshot> {
|
|
162
|
+
return await this.transport.set_approval_mode(this.id, input);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** 处理当前远程 Session 的 pending 工具审批。 */
|
|
166
|
+
async resolve_approval(input: ResolveSessionApprovalInput): Promise<SessionApprovalResult> {
|
|
167
|
+
return await this.transport.resolve_approval(this.id, input);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** 从当前远程 Session 创建分支。 */
|
|
160
171
|
async fork(input?: AgentSessionForkInput | string): Promise<RemoteAgentSession> {
|
|
161
|
-
|
|
162
|
-
return new RemoteSession(this.transport, info);
|
|
172
|
+
return new RemoteSession(this.transport, await this.transport.fork(this.id, input));
|
|
163
173
|
}
|
|
164
174
|
|
|
165
175
|
private async ensure_event_pump(): Promise<void> {
|
|
166
|
-
if (this.event_pump_connect_promise)
|
|
167
|
-
await this.event_pump_connect_promise;
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
176
|
+
if (this.event_pump_connect_promise) return await this.event_pump_connect_promise;
|
|
170
177
|
if (this.event_pump_running) return;
|
|
171
|
-
|
|
172
178
|
this.event_pump_connect_promise = (async () => {
|
|
173
179
|
let resolved_ready = false;
|
|
174
180
|
this.event_subscription = await this.transport.subscribe({
|
|
@@ -176,19 +182,12 @@ export class RemoteSession implements RemoteAgentSession {
|
|
|
176
182
|
on_ready: () => {
|
|
177
183
|
resolved_ready = true;
|
|
178
184
|
},
|
|
179
|
-
on_event: (
|
|
180
|
-
|
|
181
|
-
},
|
|
182
|
-
on_close: (error) => {
|
|
183
|
-
this.handle_event_pump_closed(error);
|
|
184
|
-
},
|
|
185
|
+
on_event: (mutation) => this.handle_mutation(mutation),
|
|
186
|
+
on_close: (error) => this.handle_event_pump_closed(error),
|
|
185
187
|
});
|
|
186
188
|
this.event_pump_running = true;
|
|
187
|
-
if (!resolved_ready)
|
|
188
|
-
throw new Error("Remote session events connection closed before ready");
|
|
189
|
-
}
|
|
189
|
+
if (!resolved_ready) throw new Error("Remote session events connection closed before ready");
|
|
190
190
|
})();
|
|
191
|
-
|
|
192
191
|
try {
|
|
193
192
|
await this.event_pump_connect_promise;
|
|
194
193
|
} finally {
|
|
@@ -196,53 +195,38 @@ export class RemoteSession implements RemoteAgentSession {
|
|
|
196
195
|
}
|
|
197
196
|
}
|
|
198
197
|
|
|
199
|
-
private
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (turn_id) {
|
|
205
|
-
this.ensure_turn_lifecycle(turn_id);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (event.type === "turn-finish") {
|
|
209
|
-
const lifecycle = this.ensure_turn_lifecycle(event.turnId);
|
|
198
|
+
private handle_mutation(mutation: SessionMutation): void {
|
|
199
|
+
const turn_id = "turn_id" in mutation ? mutation.turn_id : undefined;
|
|
200
|
+
if (turn_id) this.ensure_turn_lifecycle(turn_id);
|
|
201
|
+
if (mutation.variant === "turn" && mutation.type === "finish") {
|
|
202
|
+
const lifecycle = this.ensure_turn_lifecycle(mutation.turn_id);
|
|
210
203
|
const result: AgentSessionTurnResult = {
|
|
211
|
-
turnId:
|
|
212
|
-
text:
|
|
213
|
-
success:
|
|
214
|
-
...(
|
|
204
|
+
turnId: mutation.turn_id,
|
|
205
|
+
text: mutation.text || "",
|
|
206
|
+
success: mutation.status === "completed",
|
|
207
|
+
...(mutation.error ? { error: mutation.error } : {}),
|
|
215
208
|
};
|
|
216
209
|
lifecycle.result = result;
|
|
217
210
|
lifecycle.deferred_finished.resolve(result);
|
|
218
|
-
this.remember_completed_turn(
|
|
211
|
+
this.remember_completed_turn(mutation.turn_id);
|
|
219
212
|
void this.maybe_stop_event_pump();
|
|
220
213
|
}
|
|
221
|
-
|
|
222
|
-
this.event_hub.publish(event);
|
|
214
|
+
this.event_hub.publish(mutation);
|
|
223
215
|
}
|
|
224
216
|
|
|
225
|
-
/**
|
|
226
|
-
* 收口底层事件连接断开后的运行态。
|
|
227
|
-
*
|
|
228
|
-
* 关键点(中文)
|
|
229
|
-
* - 连接已经结束时必须清除 running 标记,后续 prompt 才会重新订阅。
|
|
230
|
-
* - 当前未完成 turn 立即失败,避免调用侧永久等待 finished。
|
|
231
|
-
*/
|
|
232
217
|
private handle_event_pump_closed(error?: unknown): void {
|
|
233
218
|
this.event_subscription = null;
|
|
234
219
|
this.event_pump_running = false;
|
|
235
|
-
|
|
236
|
-
? error.message
|
|
237
|
-
|
|
238
|
-
this.fail_pending_turns(message);
|
|
220
|
+
this.fail_pending_turns(
|
|
221
|
+
error instanceof Error ? error.message : String(error || "Remote session events connection closed"),
|
|
222
|
+
);
|
|
239
223
|
}
|
|
240
224
|
|
|
241
225
|
private ensure_turn_lifecycle(turn_id: string): RemoteTurnLifecycle {
|
|
242
226
|
const cached = this.turns_by_id.get(turn_id);
|
|
243
227
|
if (cached) return cached;
|
|
244
228
|
const created: RemoteTurnLifecycle = {
|
|
245
|
-
|
|
229
|
+
turn_id,
|
|
246
230
|
result: null,
|
|
247
231
|
deferred_finished: create_deferred<AgentSessionTurnResult>(),
|
|
248
232
|
};
|
|
@@ -254,14 +238,14 @@ export class RemoteSession implements RemoteAgentSession {
|
|
|
254
238
|
for (const lifecycle of this.turns_by_id.values()) {
|
|
255
239
|
if (lifecycle.result) continue;
|
|
256
240
|
const result: AgentSessionTurnResult = {
|
|
257
|
-
turnId: lifecycle.
|
|
241
|
+
turnId: lifecycle.turn_id,
|
|
258
242
|
text: "",
|
|
259
243
|
success: false,
|
|
260
244
|
error: message,
|
|
261
245
|
};
|
|
262
246
|
lifecycle.result = result;
|
|
263
247
|
lifecycle.deferred_finished.resolve(result);
|
|
264
|
-
this.remember_completed_turn(lifecycle.
|
|
248
|
+
this.remember_completed_turn(lifecycle.turn_id);
|
|
265
249
|
}
|
|
266
250
|
}
|
|
267
251
|
|
|
@@ -269,9 +253,7 @@ export class RemoteSession implements RemoteAgentSession {
|
|
|
269
253
|
this.completed_turn_ids.push(turn_id);
|
|
270
254
|
while (this.completed_turn_ids.length > 200) {
|
|
271
255
|
const oldest_turn_id = this.completed_turn_ids.shift();
|
|
272
|
-
if (oldest_turn_id)
|
|
273
|
-
this.turns_by_id.delete(oldest_turn_id);
|
|
274
|
-
}
|
|
256
|
+
if (oldest_turn_id) this.turns_by_id.delete(oldest_turn_id);
|
|
275
257
|
}
|
|
276
258
|
}
|
|
277
259
|
|
|
@@ -283,9 +265,7 @@ export class RemoteSession implements RemoteAgentSession {
|
|
|
283
265
|
this.event_pump_running = false;
|
|
284
266
|
if (!current) return;
|
|
285
267
|
await current.close().catch((error) => {
|
|
286
|
-
this.fail_pending_turns(
|
|
287
|
-
error instanceof Error ? error.message : String(error),
|
|
288
|
-
);
|
|
268
|
+
this.fail_pending_turns(error instanceof Error ? error.message : String(error));
|
|
289
269
|
});
|
|
290
270
|
}
|
|
291
271
|
}
|
|
@@ -295,17 +275,12 @@ function create_deferred<T>(): Deferred<T> {
|
|
|
295
275
|
const promise = new Promise<T>((inner_resolve) => {
|
|
296
276
|
resolve = inner_resolve;
|
|
297
277
|
});
|
|
298
|
-
return {
|
|
299
|
-
promise,
|
|
300
|
-
resolve,
|
|
301
|
-
};
|
|
278
|
+
return { promise, resolve };
|
|
302
279
|
}
|
|
303
280
|
|
|
304
|
-
function create_turn_handle(
|
|
305
|
-
lifecycle: RemoteTurnLifecycle,
|
|
306
|
-
): AgentSessionTurnHandle {
|
|
281
|
+
function create_turn_handle(lifecycle: RemoteTurnLifecycle): AgentSessionTurnHandle {
|
|
307
282
|
return {
|
|
308
|
-
id: lifecycle.
|
|
283
|
+
id: lifecycle.turn_id,
|
|
309
284
|
get result() {
|
|
310
285
|
return lifecycle.result;
|
|
311
286
|
},
|
|
@@ -313,19 +288,14 @@ function create_turn_handle(
|
|
|
313
288
|
};
|
|
314
289
|
}
|
|
315
290
|
|
|
316
|
-
function
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
case "turn-finish":
|
|
325
|
-
return event.turnId;
|
|
326
|
-
case "action":
|
|
327
|
-
return event.metadata.turnId || null;
|
|
328
|
-
default:
|
|
329
|
-
return null;
|
|
291
|
+
function require_approval_id(mutation: SessionMutation): string {
|
|
292
|
+
if (
|
|
293
|
+
mutation.variant === "part" &&
|
|
294
|
+
mutation.type === "tool" &&
|
|
295
|
+
mutation.part.state === "approval-required" &&
|
|
296
|
+
mutation.part.approval_id
|
|
297
|
+
) {
|
|
298
|
+
return mutation.part.approval_id;
|
|
330
299
|
}
|
|
300
|
+
throw new Error("Current Session Mutation is not an approval-required Tool Part");
|
|
331
301
|
}
|
|
@@ -15,8 +15,6 @@ import type {
|
|
|
15
15
|
AgentArchiveSessionsResult,
|
|
16
16
|
AgentCleanArchiveResult,
|
|
17
17
|
AgentSessionForkInput,
|
|
18
|
-
AgentSessionRecordsInput,
|
|
19
|
-
AgentSessionRecordsPage,
|
|
20
18
|
AgentSessionInfo,
|
|
21
19
|
AgentSessionSummaryPage,
|
|
22
20
|
AgentSessionSystemSnapshot,
|
|
@@ -26,17 +24,20 @@ import type {
|
|
|
26
24
|
RemoteAgentPluginActionInput,
|
|
27
25
|
RemoteAgentPluginActionResult,
|
|
28
26
|
} from "@/types/agent/RemoteAgentPluginAction.js";
|
|
29
|
-
import type {
|
|
27
|
+
import type { SessionMutation } from "@/types/session/SessionMutation.js";
|
|
28
|
+
import type {
|
|
29
|
+
ResolveSessionApprovalInput,
|
|
30
|
+
SessionApproval,
|
|
31
|
+
SessionApprovalModeSnapshot,
|
|
32
|
+
SessionApprovalResult,
|
|
33
|
+
SetSessionApprovalModeInput,
|
|
34
|
+
} from "@/types/session/SessionApproval.js";
|
|
30
35
|
import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
|
|
31
36
|
import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
|
|
32
37
|
import type {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
ShellApprovalModeOption,
|
|
37
|
-
ShellSessionApprovalModeView,
|
|
38
|
-
ShellApprovalView,
|
|
39
|
-
} from "@downcity/shell";
|
|
38
|
+
ListSessionMessagesInput,
|
|
39
|
+
SessionMessagePage,
|
|
40
|
+
} from "@/types/session/SessionMessage.js";
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* Transport 持有的事件订阅句柄。
|
|
@@ -65,15 +66,15 @@ export type RemoteSessionTransport = {
|
|
|
65
66
|
subscribe(params: {
|
|
66
67
|
session_id: string;
|
|
67
68
|
on_ready: () => void;
|
|
68
|
-
on_event: (
|
|
69
|
+
on_event: (mutation: SessionMutation) => void;
|
|
69
70
|
/** 底层事件连接结束后的通知;主动关闭不触发。 */
|
|
70
71
|
on_close: (error?: unknown) => void;
|
|
71
72
|
}): Promise<TransportSubscription>;
|
|
72
|
-
/** 读取
|
|
73
|
-
|
|
73
|
+
/** 读取 Session Message。 */
|
|
74
|
+
messages(
|
|
74
75
|
session_id: string,
|
|
75
|
-
input?:
|
|
76
|
-
): Promise<
|
|
76
|
+
input?: ListSessionMessagesInput,
|
|
77
|
+
): Promise<SessionMessagePage>;
|
|
77
78
|
/** 读取 system snapshot。 */
|
|
78
79
|
system(session_id: string): Promise<AgentSessionSystemSnapshot>;
|
|
79
80
|
/** 分叉 session。 */
|
|
@@ -81,6 +82,20 @@ export type RemoteSessionTransport = {
|
|
|
81
82
|
session_id: string,
|
|
82
83
|
input?: AgentSessionForkInput | string,
|
|
83
84
|
): Promise<AgentSessionInfo>;
|
|
85
|
+
/** 列出指定 Session 的 pending 工具审批。 */
|
|
86
|
+
approvals(session_id: string): Promise<SessionApproval[]>;
|
|
87
|
+
/** 读取指定 Session 的工具审批模式。 */
|
|
88
|
+
approval_mode(session_id: string): Promise<SessionApprovalModeSnapshot>;
|
|
89
|
+
/** 更新指定 Session 的工具审批模式。 */
|
|
90
|
+
set_approval_mode(
|
|
91
|
+
session_id: string,
|
|
92
|
+
input: SetSessionApprovalModeInput,
|
|
93
|
+
): Promise<SessionApprovalModeSnapshot>;
|
|
94
|
+
/** 处理指定 Session 的 pending 工具审批。 */
|
|
95
|
+
resolve_approval(
|
|
96
|
+
session_id: string,
|
|
97
|
+
input: ResolveSessionApprovalInput,
|
|
98
|
+
): Promise<SessionApprovalResult>;
|
|
84
99
|
};
|
|
85
100
|
|
|
86
101
|
/**
|
|
@@ -101,21 +116,6 @@ export type RemoteAgentTransport = RemoteSessionTransport & {
|
|
|
101
116
|
run_plugin_action(
|
|
102
117
|
input: RemoteAgentPluginActionInput,
|
|
103
118
|
): Promise<RemoteAgentPluginActionResult>;
|
|
104
|
-
/** 列出 shell approvals。 */
|
|
105
|
-
approvals(): Promise<ShellApprovalView[]>;
|
|
106
|
-
/** 列出 shell approval modes。 */
|
|
107
|
-
approval_modes(): Promise<ShellApprovalModeOption[]>;
|
|
108
|
-
/** 读取 shell approval mode。 */
|
|
109
|
-
approval_mode(input: { session_id: string }): Promise<ShellSessionApprovalModeView>;
|
|
110
|
-
/** 设置 shell approval mode。 */
|
|
111
|
-
set_approval_mode(input: {
|
|
112
|
-
session_id: string;
|
|
113
|
-
mode: ShellApprovalMode;
|
|
114
|
-
}): Promise<ShellApprovalModeUpdateResult>;
|
|
115
|
-
/** 批准 shell approval。 */
|
|
116
|
-
approve(input: { approval_id: string }): Promise<ShellApprovalDecisionResult>;
|
|
117
|
-
/** 拒绝 shell approval。 */
|
|
118
|
-
deny(input: { approval_id: string }): Promise<ShellApprovalDecisionResult>;
|
|
119
119
|
/** 关闭 transport 持有的长期连接。 */
|
|
120
120
|
close?(): Promise<void>;
|
|
121
121
|
};
|