@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
package/src/rpc/Client.ts
CHANGED
|
@@ -16,13 +16,15 @@ import type {
|
|
|
16
16
|
AgentArchiveSessionResult,
|
|
17
17
|
AgentArchiveSessionsResult,
|
|
18
18
|
AgentCleanArchiveResult,
|
|
19
|
-
AgentSessionRecordsInput,
|
|
20
|
-
AgentSessionRecordsPage,
|
|
21
19
|
AgentSessionInfo,
|
|
22
20
|
AgentSessionSummaryPage,
|
|
23
21
|
AgentSessionSystemSnapshot,
|
|
24
22
|
AgentSessionSetInput,
|
|
25
23
|
} from "@/types/agent/SessionTypes.js";
|
|
24
|
+
import type {
|
|
25
|
+
ListSessionMessagesInput,
|
|
26
|
+
SessionMessagePage,
|
|
27
|
+
} from "@/types/session/SessionMessage.js";
|
|
26
28
|
import type { JsonValue } from "@/types/common/Json.js";
|
|
27
29
|
import type { JsonObject } from "@/types/common/Json.js";
|
|
28
30
|
import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
|
|
@@ -36,7 +38,14 @@ import type {
|
|
|
36
38
|
PluginControlResult,
|
|
37
39
|
PluginSnapshot,
|
|
38
40
|
} from "@/types/plugin/PluginState.js";
|
|
39
|
-
import type {
|
|
41
|
+
import type { SessionMutation } from "@/types/session/SessionMutation.js";
|
|
42
|
+
import type {
|
|
43
|
+
ResolveSessionApprovalInput,
|
|
44
|
+
SessionApproval,
|
|
45
|
+
SessionApprovalModeSnapshot,
|
|
46
|
+
SessionApprovalResult,
|
|
47
|
+
SetSessionApprovalModeInput,
|
|
48
|
+
} from "@/types/session/SessionApproval.js";
|
|
40
49
|
import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
|
|
41
50
|
import type {
|
|
42
51
|
RpcClientEndpoint,
|
|
@@ -45,14 +54,6 @@ import type {
|
|
|
45
54
|
RpcSessionSubscription,
|
|
46
55
|
RpcSystemPromptPayload,
|
|
47
56
|
} from "@/types/rpc/RpcProtocol.js";
|
|
48
|
-
import type {
|
|
49
|
-
ShellApprovalMode,
|
|
50
|
-
ShellApprovalDecisionResult,
|
|
51
|
-
ShellApprovalModeUpdateResult,
|
|
52
|
-
ShellApprovalModeOption,
|
|
53
|
-
ShellSessionApprovalModeView,
|
|
54
|
-
ShellApprovalView,
|
|
55
|
-
} from "@downcity/shell";
|
|
56
57
|
|
|
57
58
|
export type {
|
|
58
59
|
RpcClientEndpoint,
|
|
@@ -67,7 +68,7 @@ type PendingRequest = {
|
|
|
67
68
|
|
|
68
69
|
type RpcSubscription = {
|
|
69
70
|
on_ready: () => void;
|
|
70
|
-
on_event: (event:
|
|
71
|
+
on_event: (event: SessionMutation) => void;
|
|
71
72
|
/** 底层 RPC 连接结束后的通知。 */
|
|
72
73
|
on_close: (error?: unknown) => void;
|
|
73
74
|
};
|
|
@@ -219,18 +220,18 @@ export class RpcClient {
|
|
|
219
220
|
/**
|
|
220
221
|
* 读取 session records。
|
|
221
222
|
*/
|
|
222
|
-
async
|
|
223
|
+
async get_session_messages(params: {
|
|
223
224
|
session_id: string;
|
|
224
|
-
input?:
|
|
225
|
-
}): Promise<
|
|
226
|
-
const data = await this.request<{
|
|
227
|
-
method: "sdk.sessions.
|
|
225
|
+
input?: ListSessionMessagesInput;
|
|
226
|
+
}): Promise<SessionMessagePage> {
|
|
227
|
+
const data = await this.request<{ messages: SessionMessagePage }>({
|
|
228
|
+
method: "sdk.sessions.messages",
|
|
228
229
|
params: {
|
|
229
230
|
sessionId: params.session_id,
|
|
230
231
|
input: params.input,
|
|
231
232
|
},
|
|
232
233
|
});
|
|
233
|
-
return data.
|
|
234
|
+
return data.messages;
|
|
234
235
|
}
|
|
235
236
|
|
|
236
237
|
/**
|
|
@@ -246,6 +247,44 @@ export class RpcClient {
|
|
|
246
247
|
return data.system;
|
|
247
248
|
}
|
|
248
249
|
|
|
250
|
+
async get_session_approvals(session_id: string): Promise<SessionApproval[]> {
|
|
251
|
+
const data = await this.request<{ approvals: SessionApproval[] }>({
|
|
252
|
+
method: "sdk.sessions.approvals",
|
|
253
|
+
params: { sessionId: session_id },
|
|
254
|
+
});
|
|
255
|
+
return data.approvals;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async get_session_approval_mode(session_id: string): Promise<SessionApprovalModeSnapshot> {
|
|
259
|
+
const data = await this.request<{ approval_mode: SessionApprovalModeSnapshot }>({
|
|
260
|
+
method: "sdk.sessions.approvalMode",
|
|
261
|
+
params: { sessionId: session_id },
|
|
262
|
+
});
|
|
263
|
+
return data.approval_mode;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async set_session_approval_mode(
|
|
267
|
+
session_id: string,
|
|
268
|
+
input: SetSessionApprovalModeInput,
|
|
269
|
+
): Promise<SessionApprovalModeSnapshot> {
|
|
270
|
+
const data = await this.request<{ approval_mode: SessionApprovalModeSnapshot }>({
|
|
271
|
+
method: "sdk.sessions.setApprovalMode",
|
|
272
|
+
params: { sessionId: session_id, input },
|
|
273
|
+
});
|
|
274
|
+
return data.approval_mode;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async resolve_session_approval(
|
|
278
|
+
session_id: string,
|
|
279
|
+
input: ResolveSessionApprovalInput,
|
|
280
|
+
): Promise<SessionApprovalResult> {
|
|
281
|
+
const data = await this.request<{ result: SessionApprovalResult }>({
|
|
282
|
+
method: "sdk.sessions.resolveApproval",
|
|
283
|
+
params: { sessionId: session_id, input },
|
|
284
|
+
});
|
|
285
|
+
return data.result;
|
|
286
|
+
}
|
|
287
|
+
|
|
249
288
|
/**
|
|
250
289
|
* 分叉 session。
|
|
251
290
|
*/
|
|
@@ -269,7 +308,7 @@ export class RpcClient {
|
|
|
269
308
|
async subscribe_session(params: {
|
|
270
309
|
session_id: string;
|
|
271
310
|
on_ready: () => void;
|
|
272
|
-
on_event: (event:
|
|
311
|
+
on_event: (event: SessionMutation) => void;
|
|
273
312
|
on_close: (error?: unknown) => void;
|
|
274
313
|
}): Promise<RpcSessionSubscription> {
|
|
275
314
|
const data = await this.request<{ subscriptionId: string }>({
|
|
@@ -450,78 +489,6 @@ export class RpcClient {
|
|
|
450
489
|
});
|
|
451
490
|
}
|
|
452
491
|
|
|
453
|
-
/**
|
|
454
|
-
* 列出 shell approvals。
|
|
455
|
-
*/
|
|
456
|
-
async list_shell_approvals(): Promise<ShellApprovalView[]> {
|
|
457
|
-
const data = await this.request<{ approvals: ShellApprovalView[] }>({
|
|
458
|
-
method: "internal.shell.approvals",
|
|
459
|
-
});
|
|
460
|
-
return Array.isArray(data.approvals) ? data.approvals : [];
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* 列出 shell approval 模式。
|
|
465
|
-
*/
|
|
466
|
-
async list_shell_approval_modes(): Promise<ShellApprovalModeOption[]> {
|
|
467
|
-
const data = await this.request<{ modes: ShellApprovalModeOption[] }>({
|
|
468
|
-
method: "internal.shell.approvalModes",
|
|
469
|
-
});
|
|
470
|
-
return Array.isArray(data.modes) ? data.modes : [];
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
/**
|
|
474
|
-
* 读取 shell approval 模式。
|
|
475
|
-
*/
|
|
476
|
-
async get_shell_approval_mode(session_id: string): Promise<ShellSessionApprovalModeView> {
|
|
477
|
-
return await this.request<ShellSessionApprovalModeView>({
|
|
478
|
-
method: "internal.shell.approvalMode",
|
|
479
|
-
params: {
|
|
480
|
-
sessionId: session_id,
|
|
481
|
-
},
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/**
|
|
486
|
-
* 设置 shell approval 模式。
|
|
487
|
-
*/
|
|
488
|
-
async set_shell_approval_mode(input: {
|
|
489
|
-
session_id: string;
|
|
490
|
-
mode: ShellApprovalMode;
|
|
491
|
-
}): Promise<ShellApprovalModeUpdateResult> {
|
|
492
|
-
return await this.request<ShellApprovalModeUpdateResult>({
|
|
493
|
-
method: "internal.shell.setApprovalMode",
|
|
494
|
-
params: {
|
|
495
|
-
sessionId: input.session_id,
|
|
496
|
-
mode: input.mode,
|
|
497
|
-
},
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* 批准 shell approval。
|
|
503
|
-
*/
|
|
504
|
-
async approve_shell_approval(approval_id: string): Promise<ShellApprovalDecisionResult> {
|
|
505
|
-
return await this.request<ShellApprovalDecisionResult>({
|
|
506
|
-
method: "internal.shell.approve",
|
|
507
|
-
params: {
|
|
508
|
-
approvalId: approval_id,
|
|
509
|
-
},
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
/**
|
|
514
|
-
* 拒绝 shell approval。
|
|
515
|
-
*/
|
|
516
|
-
async deny_shell_approval(approval_id: string): Promise<ShellApprovalDecisionResult> {
|
|
517
|
-
return await this.request<ShellApprovalDecisionResult>({
|
|
518
|
-
method: "internal.shell.deny",
|
|
519
|
-
params: {
|
|
520
|
-
approvalId: approval_id,
|
|
521
|
-
},
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
|
|
525
492
|
/**
|
|
526
493
|
* 关闭底层连接。
|
|
527
494
|
*/
|
|
@@ -669,10 +636,6 @@ export class RpcClient {
|
|
|
669
636
|
|
|
670
637
|
private fail_all_subscriptions(message: string): void {
|
|
671
638
|
for (const subscription of this.subscriptions.values()) {
|
|
672
|
-
subscription.on_event({
|
|
673
|
-
type: "error",
|
|
674
|
-
message,
|
|
675
|
-
});
|
|
676
639
|
subscription.on_close(new Error(message));
|
|
677
640
|
}
|
|
678
641
|
this.subscriptions.clear();
|
package/src/session/Session.ts
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
import { Executor } from "@executor/Executor.js";
|
|
11
11
|
import type { Tool } from "ai";
|
|
12
12
|
import { JsonlSessionHistoryComposer } from "@executor/composer/history/jsonl/JsonlSessionHistoryComposer.js";
|
|
13
|
-
import {
|
|
13
|
+
import { SessionRecorderHistoryStore } from "@/session/recorder/SessionRecorderHistoryStore.js";
|
|
14
|
+
import { JsonlSessionMessageStore } from "@/session/recorder/JsonlSessionMessageStore.js";
|
|
15
|
+
import { SessionRecorder } from "@/session/recorder/SessionRecorder.js";
|
|
14
16
|
import type {
|
|
15
17
|
AgentSessionConfigSnapshot,
|
|
16
18
|
AgentSessionForkInput,
|
|
17
|
-
AgentSessionRecordsInput,
|
|
18
|
-
AgentSessionRecordsPage,
|
|
19
19
|
AgentSessionInfo,
|
|
20
20
|
AgentSessionSetInput,
|
|
21
21
|
AgentSessionSystemBlock,
|
|
@@ -23,18 +23,30 @@ import type {
|
|
|
23
23
|
} from "@/types/agent/SessionTypes.js";
|
|
24
24
|
import type { AgentSession } from "@/types/agent/SessionActor.js";
|
|
25
25
|
import {
|
|
26
|
-
|
|
26
|
+
getSdkAgentSessionAssistantMessagePath,
|
|
27
27
|
getSdkAgentSessionDirPath,
|
|
28
|
-
getSdkAgentSessionInflightPath,
|
|
29
28
|
} from "@/session/storage/Paths.js";
|
|
30
29
|
import { resolveSystemTimezone } from "@/session/storage/Metadata.js";
|
|
31
30
|
import { createRuntimeSessionPort } from "@/session/storage/RuntimeSessionPort.js";
|
|
32
31
|
import { SessionSystemBuilder } from "@/session/SessionSystemBuilder.js";
|
|
33
32
|
import type { SessionPort } from "@/types/runtime/agent/AgentContext.js";
|
|
34
33
|
import type {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
SessionMutation,
|
|
35
|
+
SessionMutationSubscriber,
|
|
36
|
+
SessionMutationUnsubscribe,
|
|
37
|
+
} from "@/types/session/SessionMutation.js";
|
|
38
|
+
import type {
|
|
39
|
+
ResolveSessionApprovalInput,
|
|
40
|
+
SessionApproval,
|
|
41
|
+
SessionApprovalModeSnapshot,
|
|
42
|
+
SessionApprovalResult,
|
|
43
|
+
SetSessionApprovalModeInput,
|
|
44
|
+
SessionApprovalRuntimeEvent,
|
|
45
|
+
} from "@/types/session/SessionApproval.js";
|
|
46
|
+
import type {
|
|
47
|
+
ListSessionMessagesInput,
|
|
48
|
+
SessionMessagePage,
|
|
49
|
+
} from "@/types/session/SessionMessage.js";
|
|
38
50
|
import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
|
|
39
51
|
import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
|
|
40
52
|
import type { AgentSessionTurnHandle } from "@/types/sdk/AgentSessionTurn.js";
|
|
@@ -69,10 +81,16 @@ export class Session implements AgentSession {
|
|
|
69
81
|
private readonly getPluginSystemBlocks: SessionOptions["getPluginSystemBlocks"];
|
|
70
82
|
private readonly ensureConfiguredHook?: SessionOptions["ensureConfigured"];
|
|
71
83
|
private readonly composers?: SessionComposerOptions;
|
|
72
|
-
private readonly historyStore:
|
|
84
|
+
private readonly historyStore: SessionRecorderHistoryStore;
|
|
85
|
+
private readonly messageStore: JsonlSessionMessageStore;
|
|
86
|
+
private readonly recorder: SessionRecorder;
|
|
73
87
|
private readonly historyComposer: SessionHistoryComposer;
|
|
74
88
|
private readonly executor: Executor;
|
|
75
|
-
private readonly eventHub
|
|
89
|
+
private readonly eventHub: SessionEventHub;
|
|
90
|
+
private readonly list_approvals: SessionOptions["list_approvals"];
|
|
91
|
+
private readonly get_approval_mode: SessionOptions["get_approval_mode"];
|
|
92
|
+
private readonly set_approval_mode_hook: SessionOptions["set_approval_mode"];
|
|
93
|
+
private readonly resolve_approval_hook: SessionOptions["resolve_approval"];
|
|
76
94
|
private readonly localState: SessionLocalState;
|
|
77
95
|
private readonly stateService: SessionStateService;
|
|
78
96
|
private readonly turnService: SessionTurnService;
|
|
@@ -90,6 +108,10 @@ export class Session implements AgentSession {
|
|
|
90
108
|
this.getPluginSystemBlocks = options.getPluginSystemBlocks;
|
|
91
109
|
this.ensureConfiguredHook = options.ensureConfigured;
|
|
92
110
|
this.composers = options.composers;
|
|
111
|
+
this.list_approvals = options.list_approvals;
|
|
112
|
+
this.get_approval_mode = options.get_approval_mode;
|
|
113
|
+
this.set_approval_mode_hook = options.set_approval_mode;
|
|
114
|
+
this.resolve_approval_hook = options.resolve_approval;
|
|
93
115
|
if (!this.id) {
|
|
94
116
|
throw new Error("Session requires a non-empty sessionId");
|
|
95
117
|
}
|
|
@@ -100,6 +122,22 @@ export class Session implements AgentSession {
|
|
|
100
122
|
throw new Error("Session requires a non-empty projectRoot");
|
|
101
123
|
}
|
|
102
124
|
|
|
125
|
+
this.eventHub = new SessionEventHub({
|
|
126
|
+
create_reply: (mutation) => ({
|
|
127
|
+
approval: async ({ decision }) => {
|
|
128
|
+
const approval_id = require_approval_id(mutation);
|
|
129
|
+
return await this.resolve_approval({ approval_id, decision });
|
|
130
|
+
},
|
|
131
|
+
}),
|
|
132
|
+
});
|
|
133
|
+
this.messageStore = this.create_message_store();
|
|
134
|
+
this.recorder = new SessionRecorder({
|
|
135
|
+
session_id: this.id,
|
|
136
|
+
store: this.messageStore,
|
|
137
|
+
publish: (mutation) => {
|
|
138
|
+
this.eventHub.publish(mutation);
|
|
139
|
+
},
|
|
140
|
+
});
|
|
103
141
|
this.historyStore = this.create_history_store();
|
|
104
142
|
this.localState = this.create_local_state();
|
|
105
143
|
const composer_context = this.create_composer_context();
|
|
@@ -118,6 +156,7 @@ export class Session implements AgentSession {
|
|
|
118
156
|
project_root: this.projectRoot,
|
|
119
157
|
session_id: this.id,
|
|
120
158
|
history_store: this.historyStore,
|
|
159
|
+
recorder: this.recorder,
|
|
121
160
|
executor: this.executor,
|
|
122
161
|
state: this.localState,
|
|
123
162
|
logger: this.logger,
|
|
@@ -137,12 +176,14 @@ export class Session implements AgentSession {
|
|
|
137
176
|
executor: this.executor,
|
|
138
177
|
state_service: this.stateService,
|
|
139
178
|
event_hub: this.eventHub,
|
|
179
|
+
recorder: this.recorder,
|
|
140
180
|
});
|
|
141
181
|
this.viewService = new SessionViewService<this>({
|
|
142
182
|
agent_id: this.agentId,
|
|
143
183
|
project_root: this.projectRoot,
|
|
144
184
|
session_id: this.id,
|
|
145
185
|
history_store: this.historyStore,
|
|
186
|
+
recorder: this.recorder,
|
|
146
187
|
state_service: this.stateService,
|
|
147
188
|
logger: this.logger,
|
|
148
189
|
is_executing: () => this.isExecuting(),
|
|
@@ -158,6 +199,7 @@ export class Session implements AgentSession {
|
|
|
158
199
|
return {
|
|
159
200
|
session,
|
|
160
201
|
history_store: session.historyStore,
|
|
202
|
+
recorder: session.recorder,
|
|
161
203
|
state_service: session.stateService,
|
|
162
204
|
};
|
|
163
205
|
},
|
|
@@ -168,6 +210,7 @@ export class Session implements AgentSession {
|
|
|
168
210
|
* 初始化当前 session。
|
|
169
211
|
*/
|
|
170
212
|
async initialize(): Promise<this> {
|
|
213
|
+
await this.recorder.initialize();
|
|
171
214
|
await this.stateService.initialize();
|
|
172
215
|
return this;
|
|
173
216
|
}
|
|
@@ -203,8 +246,45 @@ export class Session implements AgentSession {
|
|
|
203
246
|
/**
|
|
204
247
|
* 订阅当前 Session 的未来事件。
|
|
205
248
|
*/
|
|
206
|
-
subscribe(
|
|
207
|
-
|
|
249
|
+
subscribe(
|
|
250
|
+
subscriber: SessionMutationSubscriber,
|
|
251
|
+
): SessionMutationUnsubscribe {
|
|
252
|
+
return this.eventHub.subscribe(subscriber);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** 列出当前 Session 的 pending 工具审批。 */
|
|
256
|
+
async approvals(): Promise<SessionApproval[]> {
|
|
257
|
+
return await this.list_approvals(this.id);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** 读取当前 Session 的工具审批模式。 */
|
|
261
|
+
async approval_mode(): Promise<SessionApprovalModeSnapshot> {
|
|
262
|
+
return await this.get_approval_mode(this.id);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** 更新当前 Session 的工具审批模式。 */
|
|
266
|
+
async set_approval_mode(input: SetSessionApprovalModeInput): Promise<SessionApprovalModeSnapshot> {
|
|
267
|
+
return await this.set_approval_mode_hook(this.id, input);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** 处理当前 Session 的 pending 工具审批。 */
|
|
271
|
+
async resolve_approval(input: ResolveSessionApprovalInput): Promise<SessionApprovalResult> {
|
|
272
|
+
return await this.resolve_approval_hook(this.id, input);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private async apply_runtime_event(event: SessionApprovalRuntimeEvent): Promise<void> {
|
|
276
|
+
if (event.type === "tool-approval-request") {
|
|
277
|
+
await this.recorder.require_tool_approval({
|
|
278
|
+
tool_call_id: event.tool_call_id,
|
|
279
|
+
approval_id: event.approval_id,
|
|
280
|
+
});
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
await this.recorder.resolve_tool_approval({
|
|
284
|
+
tool_call_id: event.tool_call_id,
|
|
285
|
+
approval_id: event.approval_id,
|
|
286
|
+
decision: event.decision,
|
|
287
|
+
});
|
|
208
288
|
}
|
|
209
289
|
|
|
210
290
|
/**
|
|
@@ -239,8 +319,8 @@ export class Session implements AgentSession {
|
|
|
239
319
|
/**
|
|
240
320
|
* 读取当前 session records 分页。
|
|
241
321
|
*/
|
|
242
|
-
async
|
|
243
|
-
return await this.
|
|
322
|
+
async messages(input?: ListSessionMessagesInput): Promise<SessionMessagePage> {
|
|
323
|
+
return await this.recorder.list_messages(input);
|
|
244
324
|
}
|
|
245
325
|
|
|
246
326
|
/**
|
|
@@ -275,8 +355,8 @@ export class Session implements AgentSession {
|
|
|
275
355
|
prompt: async (input) => await this.prompt(input),
|
|
276
356
|
stop: async () => await this.stop(),
|
|
277
357
|
subscribe: (subscriber) => this.subscribe(subscriber),
|
|
278
|
-
publishEvent: (event) => {
|
|
279
|
-
this.
|
|
358
|
+
publishEvent: async (event) => {
|
|
359
|
+
await this.apply_runtime_event(event);
|
|
280
360
|
},
|
|
281
361
|
append_user_message: async (message_params) => {
|
|
282
362
|
await this.stateService.append_user_message(message_params);
|
|
@@ -312,6 +392,10 @@ export class Session implements AgentSession {
|
|
|
312
392
|
getPluginSystemBlocks: this.getPluginSystemBlocks,
|
|
313
393
|
ensureConfigured: this.ensureConfiguredHook,
|
|
314
394
|
composers: this.composers,
|
|
395
|
+
list_approvals: this.list_approvals,
|
|
396
|
+
get_approval_mode: this.get_approval_mode,
|
|
397
|
+
set_approval_mode: this.set_approval_mode_hook,
|
|
398
|
+
resolve_approval: this.resolve_approval_hook,
|
|
315
399
|
});
|
|
316
400
|
}
|
|
317
401
|
|
|
@@ -329,33 +413,28 @@ export class Session implements AgentSession {
|
|
|
329
413
|
return new SessionClass(options) as this;
|
|
330
414
|
}
|
|
331
415
|
|
|
332
|
-
private
|
|
416
|
+
private create_message_store(): JsonlSessionMessageStore {
|
|
333
417
|
const session_dir_path = getSdkAgentSessionDirPath(
|
|
334
418
|
this.projectRoot,
|
|
335
419
|
this.agentId,
|
|
336
420
|
this.id,
|
|
337
421
|
);
|
|
338
422
|
const messages_dir_path = `${session_dir_path}/messages`;
|
|
339
|
-
return new
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
this.projectRoot,
|
|
355
|
-
this.agentId,
|
|
356
|
-
this.id,
|
|
357
|
-
),
|
|
358
|
-
},
|
|
423
|
+
return new JsonlSessionMessageStore({
|
|
424
|
+
session_id: this.id,
|
|
425
|
+
file_path: `${messages_dir_path}/messages.jsonl`,
|
|
426
|
+
assistant_message_file_path: getSdkAgentSessionAssistantMessagePath(
|
|
427
|
+
this.projectRoot,
|
|
428
|
+
this.agentId,
|
|
429
|
+
this.id,
|
|
430
|
+
),
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private create_history_store(): SessionRecorderHistoryStore {
|
|
435
|
+
return new SessionRecorderHistoryStore({
|
|
436
|
+
session_id: this.id,
|
|
437
|
+
recorder: this.recorder,
|
|
359
438
|
});
|
|
360
439
|
}
|
|
361
440
|
|
|
@@ -471,3 +550,15 @@ export class Session implements AgentSession {
|
|
|
471
550
|
return input;
|
|
472
551
|
}
|
|
473
552
|
}
|
|
553
|
+
|
|
554
|
+
function require_approval_id(mutation: SessionMutation): string {
|
|
555
|
+
if (
|
|
556
|
+
mutation.variant === "part" &&
|
|
557
|
+
mutation.type === "tool" &&
|
|
558
|
+
mutation.part.state === "approval-required" &&
|
|
559
|
+
mutation.part.approval_id
|
|
560
|
+
) {
|
|
561
|
+
return mutation.part.approval_id;
|
|
562
|
+
}
|
|
563
|
+
throw new Error("Current Session Mutation is not an approval-required Tool Part");
|
|
564
|
+
}
|
|
@@ -45,6 +45,8 @@ import { getSdkAgentArchivedSessionsDirPath } from "@/session/storage/Paths.js";
|
|
|
45
45
|
import { getSdkAgentArchivedSessionMessagesPath } from "@/session/storage/Paths.js";
|
|
46
46
|
import { getSdkAgentArchivedSessionMetaPath } from "@/session/storage/Paths.js";
|
|
47
47
|
import { readSessionMetadataFromPath } from "@/session/storage/Metadata.js";
|
|
48
|
+
import { to_executor_ui_message } from "@/session/recorder/SessionMessageCodec.js";
|
|
49
|
+
import type { SessionMessage } from "@/types/session/SessionMessage.js";
|
|
48
50
|
|
|
49
51
|
type AnyUiPart = UIMessagePart<Record<string, never>, Record<string, never>>;
|
|
50
52
|
|
|
@@ -324,46 +326,73 @@ export function toSessionTimelineEvents(
|
|
|
324
326
|
export async function loadSessionMessagesFromPath(
|
|
325
327
|
filePath: string,
|
|
326
328
|
): Promise<SessionRecordV1[]> {
|
|
327
|
-
const
|
|
329
|
+
const messages_by_id = new Map<string, SessionMessage>();
|
|
328
330
|
if (await fs.pathExists(filePath)) {
|
|
329
331
|
const raw = await fs.readFile(filePath, "utf-8");
|
|
330
332
|
const lines = raw.split("\n").filter(Boolean);
|
|
331
333
|
for (const line of lines) {
|
|
332
334
|
try {
|
|
333
|
-
const
|
|
334
|
-
if (!
|
|
335
|
-
const
|
|
336
|
-
if (
|
|
337
|
-
|
|
338
|
-
candidate.role !== "user" &&
|
|
339
|
-
candidate.role !== "assistant"
|
|
340
|
-
) {
|
|
341
|
-
continue;
|
|
335
|
+
const message = JSON.parse(line) as SessionMessage;
|
|
336
|
+
if (!is_canonical_session_message(message)) continue;
|
|
337
|
+
const previous = messages_by_id.get(message.message_id);
|
|
338
|
+
if (!previous || message.revision > previous.revision) {
|
|
339
|
+
messages_by_id.set(message.message_id, message);
|
|
342
340
|
}
|
|
343
|
-
messages.push(parsed);
|
|
344
341
|
} catch {
|
|
345
342
|
// 关键点(中文):单行损坏不影响整个 session 的可读性。
|
|
346
343
|
}
|
|
347
344
|
}
|
|
348
345
|
}
|
|
349
346
|
|
|
350
|
-
const inflight_path = filePath.replace(/messages\.jsonl$/, "
|
|
347
|
+
const inflight_path = filePath.replace(/messages\.jsonl$/, "assistant_message.json");
|
|
351
348
|
if (await fs.pathExists(inflight_path)) {
|
|
352
349
|
try {
|
|
353
|
-
const
|
|
354
|
-
if (
|
|
355
|
-
|
|
356
|
-
parsed.role === "assistant" &&
|
|
357
|
-
Array.isArray(parsed.parts)
|
|
358
|
-
) {
|
|
359
|
-
messages.push(parsed);
|
|
350
|
+
const message = (await fs.readJson(inflight_path)) as SessionMessage;
|
|
351
|
+
if (is_canonical_session_message(message) && message.type === "assistant") {
|
|
352
|
+
messages_by_id.set(message.message_id, message);
|
|
360
353
|
}
|
|
361
354
|
} catch {
|
|
362
|
-
//
|
|
355
|
+
// 运行中快照损坏时仍返回已经完成的历史。
|
|
363
356
|
}
|
|
364
357
|
}
|
|
365
358
|
|
|
366
|
-
return
|
|
359
|
+
return [...messages_by_id.values()]
|
|
360
|
+
.sort((left, right) => left.sequence - right.sequence)
|
|
361
|
+
.flatMap(project_canonical_message_record);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function is_canonical_session_message(input: unknown): input is SessionMessage {
|
|
365
|
+
if (!input || typeof input !== "object") return false;
|
|
366
|
+
const candidate = input as Partial<SessionMessage>;
|
|
367
|
+
return (
|
|
368
|
+
typeof candidate.message_id === "string" &&
|
|
369
|
+
typeof candidate.session_id === "string" &&
|
|
370
|
+
typeof candidate.sequence === "number" &&
|
|
371
|
+
typeof candidate.revision === "number" &&
|
|
372
|
+
(candidate.type === "user" ||
|
|
373
|
+
candidate.type === "assistant" ||
|
|
374
|
+
candidate.type === "action" ||
|
|
375
|
+
candidate.type === "error")
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function project_canonical_message_record(message: SessionMessage): SessionRecordV1[] {
|
|
380
|
+
const projected = to_executor_ui_message(message);
|
|
381
|
+
if (projected) return [projected];
|
|
382
|
+
if (message.type !== "action") return [];
|
|
383
|
+
return [{
|
|
384
|
+
type: "action",
|
|
385
|
+
id: message.message_id,
|
|
386
|
+
title: message.title,
|
|
387
|
+
...(message.description ? { description: message.description } : {}),
|
|
388
|
+
state: message.status,
|
|
389
|
+
metadata: {
|
|
390
|
+
v: 1,
|
|
391
|
+
ts: message.updated_at,
|
|
392
|
+
sessionId: message.session_id,
|
|
393
|
+
...(message.turn_id ? { turnId: message.turn_id } : {}),
|
|
394
|
+
},
|
|
395
|
+
}];
|
|
367
396
|
}
|
|
368
397
|
|
|
369
398
|
/**
|
|
@@ -481,7 +510,7 @@ async function resolve_session_summary_metadata(input: {
|
|
|
481
510
|
const history_bytes = await fs.stat(input.messagesPath)
|
|
482
511
|
.then((file_stat) => file_stat.size)
|
|
483
512
|
.catch(() => 0);
|
|
484
|
-
const inflight_path = `${input.messagesPath.slice(0, -"messages.jsonl".length)}
|
|
513
|
+
const inflight_path = `${input.messagesPath.slice(0, -"messages.jsonl".length)}assistant_message.json`;
|
|
485
514
|
const has_inflight = await fs.pathExists(inflight_path);
|
|
486
515
|
if (
|
|
487
516
|
!input.refresh &&
|