@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.
Files changed (184) hide show
  1. package/bin/agent/local/Agent.d.ts +1 -34
  2. package/bin/agent/local/Agent.d.ts.map +1 -1
  3. package/bin/agent/local/Agent.js +1 -44
  4. package/bin/agent/local/Agent.js.map +1 -1
  5. package/bin/agent/local/services/AgentAssemblyService.d.ts.map +1 -1
  6. package/bin/agent/local/services/AgentAssemblyService.js +35 -2
  7. package/bin/agent/local/services/AgentAssemblyService.js.map +1 -1
  8. package/bin/agent/local/services/AgentSessions.d.ts +6 -0
  9. package/bin/agent/local/services/AgentSessions.d.ts.map +1 -1
  10. package/bin/agent/local/services/AgentSessions.js +43 -4
  11. package/bin/agent/local/services/AgentSessions.js.map +1 -1
  12. package/bin/agent/remote/RemoteAgent.d.ts +1 -35
  13. package/bin/agent/remote/RemoteAgent.d.ts.map +1 -1
  14. package/bin/agent/remote/RemoteAgent.js +1 -37
  15. package/bin/agent/remote/RemoteAgent.js.map +1 -1
  16. package/bin/agent/remote/RemoteSession.d.ts +26 -41
  17. package/bin/agent/remote/RemoteSession.d.ts.map +1 -1
  18. package/bin/agent/remote/RemoteSession.js +75 -107
  19. package/bin/agent/remote/RemoteSession.js.map +1 -1
  20. package/bin/agent/remote/RemoteTransport.d.ts +15 -27
  21. package/bin/agent/remote/RemoteTransport.d.ts.map +1 -1
  22. package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts +10 -21
  23. package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts.map +1 -1
  24. package/bin/agent/remote/transports/HttpRemoteAgentTransport.js +24 -46
  25. package/bin/agent/remote/transports/HttpRemoteAgentTransport.js.map +1 -1
  26. package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts +10 -20
  27. package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts.map +1 -1
  28. package/bin/agent/remote/transports/RpcRemoteAgentTransport.js +10 -16
  29. package/bin/agent/remote/transports/RpcRemoteAgentTransport.js.map +1 -1
  30. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +2 -2
  31. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
  32. package/bin/executor/types/SessionHistoryPaths.d.ts +1 -1
  33. package/bin/executor/types/SessionRecords.d.ts +2 -0
  34. package/bin/executor/types/SessionRecords.d.ts.map +1 -1
  35. package/bin/executor/types/SessionRecords.js.map +1 -1
  36. package/bin/index.d.ts +6 -3
  37. package/bin/index.d.ts.map +1 -1
  38. package/bin/index.js +1 -0
  39. package/bin/index.js.map +1 -1
  40. package/bin/rpc/Client.d.ts +12 -34
  41. package/bin/rpc/Client.d.ts.map +1 -1
  42. package/bin/rpc/Client.js +31 -70
  43. package/bin/rpc/Client.js.map +1 -1
  44. package/bin/session/Session.d.ts +22 -4
  45. package/bin/session/Session.d.ts.map +1 -1
  46. package/bin/session/Session.js +95 -21
  47. package/bin/session/Session.js.map +1 -1
  48. package/bin/session/browse/Browse.d.ts.map +1 -1
  49. package/bin/session/browse/Browse.js +49 -18
  50. package/bin/session/browse/Browse.js.map +1 -1
  51. package/bin/session/recorder/JsonlSessionMessageStore.d.ts +51 -0
  52. package/bin/session/recorder/JsonlSessionMessageStore.d.ts.map +1 -0
  53. package/bin/session/recorder/JsonlSessionMessageStore.js +231 -0
  54. package/bin/session/recorder/JsonlSessionMessageStore.js.map +1 -0
  55. package/bin/session/recorder/SessionMessageCodec.d.ts +20 -0
  56. package/bin/session/recorder/SessionMessageCodec.d.ts.map +1 -0
  57. package/bin/session/recorder/SessionMessageCodec.js +257 -0
  58. package/bin/session/recorder/SessionMessageCodec.js.map +1 -0
  59. package/bin/session/recorder/SessionRecorder.d.ts +186 -0
  60. package/bin/session/recorder/SessionRecorder.d.ts.map +1 -0
  61. package/bin/session/recorder/SessionRecorder.js +655 -0
  62. package/bin/session/recorder/SessionRecorder.js.map +1 -0
  63. package/bin/session/recorder/SessionRecorderCompaction.d.ts +18 -0
  64. package/bin/session/recorder/SessionRecorderCompaction.d.ts.map +1 -0
  65. package/bin/session/recorder/SessionRecorderCompaction.js +142 -0
  66. package/bin/session/recorder/SessionRecorderCompaction.js.map +1 -0
  67. package/bin/session/recorder/SessionRecorderHistoryStore.d.ts +66 -0
  68. package/bin/session/recorder/SessionRecorderHistoryStore.d.ts.map +1 -0
  69. package/bin/session/recorder/SessionRecorderHistoryStore.js +195 -0
  70. package/bin/session/recorder/SessionRecorderHistoryStore.js.map +1 -0
  71. package/bin/session/runtime/SessionEventHub.d.ts +12 -5
  72. package/bin/session/runtime/SessionEventHub.d.ts.map +1 -1
  73. package/bin/session/runtime/SessionEventHub.js +11 -6
  74. package/bin/session/runtime/SessionEventHub.js.map +1 -1
  75. package/bin/session/runtime/SessionPromptRuntime.d.ts +9 -15
  76. package/bin/session/runtime/SessionPromptRuntime.d.ts.map +1 -1
  77. package/bin/session/runtime/SessionPromptRuntime.js +48 -30
  78. package/bin/session/runtime/SessionPromptRuntime.js.map +1 -1
  79. package/bin/session/services/SessionStateService.d.ts +9 -5
  80. package/bin/session/services/SessionStateService.d.ts.map +1 -1
  81. package/bin/session/services/SessionStateService.js +138 -74
  82. package/bin/session/services/SessionStateService.js.map +1 -1
  83. package/bin/session/services/SessionTurnService.d.ts +6 -7
  84. package/bin/session/services/SessionTurnService.d.ts.map +1 -1
  85. package/bin/session/services/SessionTurnService.js +84 -60
  86. package/bin/session/services/SessionTurnService.js.map +1 -1
  87. package/bin/session/services/SessionViewService.d.ts +8 -3
  88. package/bin/session/services/SessionViewService.d.ts.map +1 -1
  89. package/bin/session/services/SessionViewService.js +10 -5
  90. package/bin/session/services/SessionViewService.js.map +1 -1
  91. package/bin/session/storage/Paths.d.ts +1 -1
  92. package/bin/session/storage/Paths.d.ts.map +1 -1
  93. package/bin/session/storage/Paths.js +2 -2
  94. package/bin/session/storage/Paths.js.map +1 -1
  95. package/bin/session/storage/Persistence.d.ts +6 -0
  96. package/bin/session/storage/Persistence.d.ts.map +1 -1
  97. package/bin/session/storage/Persistence.js +7 -0
  98. package/bin/session/storage/Persistence.js.map +1 -1
  99. package/bin/session/storage/RuntimeSessionPort.d.ts +3 -3
  100. package/bin/session/storage/RuntimeSessionPort.d.ts.map +1 -1
  101. package/bin/session/storage/RuntimeSessionPort.js +2 -2
  102. package/bin/session/storage/RuntimeSessionPort.js.map +1 -1
  103. package/bin/types/agent/SessionActor.d.ts +15 -5
  104. package/bin/types/agent/SessionActor.d.ts.map +1 -1
  105. package/bin/types/rpc/RpcProtocol.d.ts +48 -61
  106. package/bin/types/rpc/RpcProtocol.d.ts.map +1 -1
  107. package/bin/types/runtime/agent/AgentContext.d.ts +5 -4
  108. package/bin/types/runtime/agent/AgentContext.d.ts.map +1 -1
  109. package/bin/types/runtime/agent/AgentContext.js.map +1 -1
  110. package/bin/types/session/SessionApproval.d.ts +97 -0
  111. package/bin/types/session/SessionApproval.d.ts.map +1 -0
  112. package/bin/types/session/SessionApproval.js +7 -0
  113. package/bin/types/session/SessionApproval.js.map +1 -0
  114. package/bin/types/session/SessionMessage.d.ts +223 -0
  115. package/bin/types/session/SessionMessage.d.ts.map +1 -0
  116. package/bin/types/session/SessionMessage.js +8 -0
  117. package/bin/types/session/SessionMessage.js.map +1 -0
  118. package/bin/types/session/SessionMutation.d.ts +116 -0
  119. package/bin/types/session/SessionMutation.d.ts.map +1 -0
  120. package/bin/types/session/SessionMutation.js +19 -0
  121. package/bin/types/session/SessionMutation.js.map +1 -0
  122. package/bin/types/session/SessionOptions.d.ts +9 -0
  123. package/bin/types/session/SessionOptions.d.ts.map +1 -1
  124. package/package.json +3 -3
  125. package/scripts/agent-env.test.mjs +4 -4
  126. package/scripts/remote-session-reconnect.test.mjs +7 -3
  127. package/scripts/session-action-message.test.mjs +98 -27
  128. package/scripts/session-history-inflight.test.mjs +2 -2
  129. package/scripts/session-list-title.test.mjs +6 -19
  130. package/scripts/session-prompt-runtime.test.mjs +7 -19
  131. package/scripts/session-recorder.test.mjs +199 -0
  132. package/scripts/session-title-event.test.mjs +10 -18
  133. package/src/agent/local/Agent.ts +1 -55
  134. package/src/agent/local/services/AgentAssemblyService.ts +39 -3
  135. package/src/agent/local/services/AgentSessions.ts +48 -3
  136. package/src/agent/remote/RemoteAgent.ts +1 -54
  137. package/src/agent/remote/RemoteSession.ts +106 -136
  138. package/src/agent/remote/RemoteTransport.ts +30 -30
  139. package/src/agent/remote/transports/HttpRemoteAgentTransport.ts +52 -77
  140. package/src/agent/remote/transports/RpcRemoteAgentTransport.ts +30 -34
  141. package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +2 -2
  142. package/src/executor/types/SessionHistoryPaths.ts +1 -1
  143. package/src/executor/types/SessionRecords.ts +2 -0
  144. package/src/index.ts +36 -10
  145. package/src/rpc/Client.ts +58 -95
  146. package/src/session/Session.ts +128 -37
  147. package/src/session/browse/Browse.ts +51 -22
  148. package/src/session/recorder/JsonlSessionMessageStore.ts +246 -0
  149. package/src/session/recorder/SessionMessageCodec.ts +284 -0
  150. package/src/session/recorder/SessionRecorder.ts +871 -0
  151. package/src/session/recorder/SessionRecorderCompaction.ts +188 -0
  152. package/src/session/recorder/SessionRecorderHistoryStore.ts +276 -0
  153. package/src/session/runtime/SessionEventHub.ts +25 -12
  154. package/src/session/runtime/SessionPromptRuntime.ts +60 -43
  155. package/src/session/services/SessionStateService.ts +159 -86
  156. package/src/session/services/SessionTurnService.ts +91 -73
  157. package/src/session/services/SessionViewService.ts +25 -13
  158. package/src/session/storage/Paths.ts +2 -2
  159. package/src/session/storage/Persistence.ts +13 -0
  160. package/src/session/storage/RuntimeSessionPort.ts +8 -9
  161. package/src/types/agent/SessionActor.ts +31 -8
  162. package/src/types/rpc/RpcProtocol.ts +44 -67
  163. package/src/types/runtime/agent/AgentContext.ts +9 -7
  164. package/src/types/session/SessionApproval.ts +108 -0
  165. package/src/types/session/SessionMessage.ts +253 -0
  166. package/src/types/session/SessionMutation.ts +141 -0
  167. package/src/types/session/SessionOptions.ts +25 -0
  168. package/tsconfig.tsbuildinfo +1 -1
  169. package/bin/session/SessionEventMapper.d.ts +0 -32
  170. package/bin/session/SessionEventMapper.d.ts.map +0 -1
  171. package/bin/session/SessionEventMapper.js +0 -131
  172. package/bin/session/SessionEventMapper.js.map +0 -1
  173. package/bin/types/sdk/AgentSessionEvent.d.ts +0 -302
  174. package/bin/types/sdk/AgentSessionEvent.d.ts.map +0 -1
  175. package/bin/types/sdk/AgentSessionEvent.js +0 -9
  176. package/bin/types/sdk/AgentSessionEvent.js.map +0 -1
  177. package/bin/types/sdk/InternalUiChunkEvent.d.ts +0 -100
  178. package/bin/types/sdk/InternalUiChunkEvent.d.ts.map +0 -1
  179. package/bin/types/sdk/InternalUiChunkEvent.js +0 -9
  180. package/bin/types/sdk/InternalUiChunkEvent.js.map +0 -1
  181. package/scripts/session-history-archive.test.mjs +0 -188
  182. package/src/session/SessionEventMapper.ts +0 -148
  183. package/src/types/sdk/AgentSessionEvent.ts +0 -370
  184. package/src/types/sdk/InternalUiChunkEvent.ts +0 -108
@@ -1,29 +1,36 @@
1
1
  /**
2
- * RemoteSession:远程 session actor 客户端。
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
- AgentSessionEvent,
23
- AgentSessionSubscriber,
24
- AgentSessionUnsubscribe,
25
- } from "@/types/sdk/AgentSessionEvent.js";
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
- /** 兑现 Promise。 */
47
+ /** 兑现当前 Promise。 */
41
48
  resolve: (value: T) => void;
42
49
  };
43
50
 
44
51
  type RemoteTurnLifecycle = {
45
- /** 当前 turnId。 */
46
- turnId: string;
47
- /** 当前 turn 的最终结果快照。 */
52
+ /** 当前 Turn 标识。 */
53
+ turn_id: string;
54
+ /** 当前 Turn 的最终结果;运行中为 null。 */
48
55
  result: AgentSessionTurnResult | null;
49
- /** 当前 turn 完成 Promise 控制器。 */
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 = new SessionEventHub();
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
- const lifecycle = this.ensure_turn_lifecycle(turn.id);
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
- * 订阅当前远程 session 的 future 事件。
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.event_hub.publish({
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
- * 分叉远程 session。
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
- const info = await this.transport.fork(this.id, input);
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: (event) => {
180
- this.handle_event(event);
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 handle_event(event: AgentSessionEvent): void {
200
- if (event.type === "error") {
201
- this.fail_pending_turns(event.message);
202
- }
203
- const turn_id = extract_turn_id(event);
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: event.turnId,
212
- text: event.text,
213
- success: event.success,
214
- ...(event.error ? { error: event.error } : {}),
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(event.turnId);
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
- const message = error instanceof Error
236
- ? error.message
237
- : String(error || "Remote session events connection closed");
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
- turnId: turn_id,
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.turnId,
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.turnId);
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.turnId,
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 extract_turn_id(event: AgentSessionEvent): string | null {
317
- switch (event.type) {
318
- case "turn-start":
319
- case "text-delta":
320
- case "reasoning-delta":
321
- case "tool-call":
322
- case "tool-result":
323
- case "assistant-step":
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 { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
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
- ShellApprovalMode,
34
- ShellApprovalDecisionResult,
35
- ShellApprovalModeUpdateResult,
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: (event: AgentSessionEvent) => void;
69
+ on_event: (mutation: SessionMutation) => void;
69
70
  /** 底层事件连接结束后的通知;主动关闭不触发。 */
70
71
  on_close: (error?: unknown) => void;
71
72
  }): Promise<TransportSubscription>;
72
- /** 读取 history。 */
73
- records(
73
+ /** 读取 Session Message。 */
74
+ messages(
74
75
  session_id: string,
75
- input?: AgentSessionRecordsInput,
76
- ): Promise<AgentSessionRecordsPage>;
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
  };