@downcity/agent 1.1.208 → 1.1.212
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 +3 -3
- package/bin/agent/local/Agent.d.ts.map +1 -1
- package/bin/agent/local/Agent.js +0 -3
- package/bin/agent/local/Agent.js.map +1 -1
- package/bin/agent/local/AgentInstructions.d.ts +1 -1
- package/bin/agent/local/AgentInstructions.d.ts.map +1 -1
- package/bin/agent/local/services/AgentAssemblyService.d.ts +3 -8
- package/bin/agent/local/services/AgentAssemblyService.d.ts.map +1 -1
- package/bin/agent/local/services/AgentAssemblyService.js +0 -1
- package/bin/agent/local/services/AgentAssemblyService.js.map +1 -1
- package/bin/agent/local/services/AgentSessions.d.ts +5 -7
- package/bin/agent/local/services/AgentSessions.d.ts.map +1 -1
- package/bin/agent/local/services/AgentSessions.js +2 -3
- package/bin/agent/local/services/AgentSessions.js.map +1 -1
- package/bin/agent/remote/RemoteAgent.d.ts +3 -1
- package/bin/agent/remote/RemoteAgent.d.ts.map +1 -1
- package/bin/agent/remote/RemoteAgent.js.map +1 -1
- package/bin/agent/remote/RemoteSession.d.ts +10 -1
- package/bin/agent/remote/RemoteSession.d.ts.map +1 -1
- package/bin/agent/remote/RemoteSession.js +18 -0
- package/bin/agent/remote/RemoteSession.js.map +1 -1
- package/bin/agent/remote/RemoteTransport.d.ts +5 -1
- package/bin/agent/remote/RemoteTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts +4 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js +7 -0
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js.map +1 -1
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts +4 -1
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.js +1 -0
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.js.map +1 -1
- package/bin/executor/Executor.d.ts +0 -16
- package/bin/executor/Executor.d.ts.map +1 -1
- package/bin/executor/Executor.js +0 -16
- package/bin/executor/Executor.js.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts +1 -3
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js +1 -5
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js.map +1 -1
- package/bin/executor/composer/history/SessionHistoryWriter.d.ts +0 -10
- package/bin/executor/composer/history/SessionHistoryWriter.d.ts.map +1 -1
- package/bin/executor/composer/history/SessionHistoryWriter.js +31 -61
- package/bin/executor/composer/history/SessionHistoryWriter.js.map +1 -1
- package/bin/executor/messages/AssistantFileResource.d.ts.map +1 -1
- package/bin/executor/messages/AssistantFileResource.js +58 -15
- package/bin/executor/messages/AssistantFileResource.js.map +1 -1
- package/bin/executor/services/ExecutorInflightService.d.ts +0 -5
- package/bin/executor/services/ExecutorInflightService.d.ts.map +1 -1
- package/bin/executor/services/ExecutorInflightService.js +0 -6
- package/bin/executor/services/ExecutorInflightService.js.map +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts +4 -0
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts.map +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +115 -3
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
- package/bin/executor/types/SessionHistoryMeta.d.ts +6 -0
- package/bin/executor/types/SessionHistoryMeta.d.ts.map +1 -1
- package/bin/index.d.ts +38 -6
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +14 -1
- package/bin/index.js.map +1 -1
- package/bin/plugin/core/ActionScheduleExecutor.js +1 -1
- package/bin/plugin/core/ActionScheduleExecutor.js.map +1 -1
- package/bin/plugin/core/BasePlugin.d.ts +7 -9
- package/bin/plugin/core/BasePlugin.d.ts.map +1 -1
- package/bin/plugin/core/BasePlugin.js +1 -14
- package/bin/plugin/core/BasePlugin.js.map +1 -1
- package/bin/plugin/core/HookRegistry.d.ts +1 -1
- package/bin/plugin/core/HookRegistry.d.ts.map +1 -1
- package/bin/plugin/core/PluginActionFactory.d.ts +1 -5
- package/bin/plugin/core/PluginActionFactory.d.ts.map +1 -1
- package/bin/plugin/core/PluginActionFactory.js +0 -3
- package/bin/plugin/core/PluginActionFactory.js.map +1 -1
- package/bin/plugin/core/PluginActionRunner.d.ts +6 -4
- package/bin/plugin/core/PluginActionRunner.d.ts.map +1 -1
- package/bin/plugin/core/PluginActionRunner.js +2 -2
- package/bin/plugin/core/PluginActionRunner.js.map +1 -1
- package/bin/plugin/core/PluginCatalog.d.ts +2 -1
- package/bin/plugin/core/PluginCatalog.d.ts.map +1 -1
- package/bin/plugin/core/PluginCatalog.js.map +1 -1
- package/bin/plugin/core/PluginCommand.d.ts +1 -1
- package/bin/plugin/core/PluginCommand.d.ts.map +1 -1
- package/bin/plugin/core/PluginCommand.js.map +1 -1
- package/bin/plugin/core/PluginHttpRoutes.d.ts +1 -1
- package/bin/plugin/core/PluginHttpRoutes.d.ts.map +1 -1
- package/bin/plugin/core/PluginLocalExecution.d.ts +4 -1
- package/bin/plugin/core/PluginLocalExecution.d.ts.map +1 -1
- package/bin/plugin/core/PluginLocalExecution.js +0 -1
- package/bin/plugin/core/PluginLocalExecution.js.map +1 -1
- package/bin/plugin/core/PluginRegistry.d.ts +4 -2
- package/bin/plugin/core/PluginRegistry.d.ts.map +1 -1
- package/bin/plugin/core/PluginRegistry.js +7 -6
- package/bin/plugin/core/PluginRegistry.js.map +1 -1
- package/bin/plugin/core/PluginStateController.d.ts +7 -27
- package/bin/plugin/core/PluginStateController.d.ts.map +1 -1
- package/bin/plugin/core/PluginStateController.js +5 -39
- package/bin/plugin/core/PluginStateController.js.map +1 -1
- package/bin/plugin/types/PluginApi.d.ts +3 -79
- package/bin/plugin/types/PluginApi.d.ts.map +1 -1
- package/bin/rpc/Client.d.ts +11 -6
- package/bin/rpc/Client.d.ts.map +1 -1
- package/bin/rpc/Client.js +2 -0
- package/bin/rpc/Client.js.map +1 -1
- package/bin/session/Session.d.ts +2 -5
- package/bin/session/Session.d.ts.map +1 -1
- package/bin/session/Session.js +3 -16
- package/bin/session/Session.js.map +1 -1
- package/bin/session/SessionSystemBuilder.d.ts +1 -1
- package/bin/session/SessionSystemBuilder.d.ts.map +1 -1
- package/bin/session/browse/Browse.d.ts +4 -6
- package/bin/session/browse/Browse.d.ts.map +1 -1
- package/bin/session/browse/Browse.js +71 -71
- package/bin/session/browse/Browse.js.map +1 -1
- package/bin/session/preview/SessionMessagePreview.d.ts +13 -0
- package/bin/session/preview/SessionMessagePreview.d.ts.map +1 -0
- package/bin/session/preview/SessionMessagePreview.js +61 -0
- package/bin/session/preview/SessionMessagePreview.js.map +1 -0
- package/bin/session/runtime/SessionPromptRuntime.d.ts +14 -0
- package/bin/session/runtime/SessionPromptRuntime.d.ts.map +1 -1
- package/bin/session/runtime/SessionPromptRuntime.js +11 -0
- package/bin/session/runtime/SessionPromptRuntime.js.map +1 -1
- package/bin/session/services/SessionStateService.d.ts +1 -1
- package/bin/session/services/SessionStateService.d.ts.map +1 -1
- package/bin/session/services/SessionStateService.js +2 -2
- package/bin/session/services/SessionStateService.js.map +1 -1
- package/bin/session/services/SessionTurnService.d.ts.map +1 -1
- package/bin/session/services/SessionTurnService.js +9 -0
- package/bin/session/services/SessionTurnService.js.map +1 -1
- package/bin/session/services/SessionViewService.d.ts +2 -1
- package/bin/session/services/SessionViewService.d.ts.map +1 -1
- package/bin/session/services/SessionViewService.js +4 -1
- package/bin/session/services/SessionViewService.js.map +1 -1
- package/bin/session/storage/Metadata.d.ts.map +1 -1
- package/bin/session/storage/Metadata.js +23 -0
- package/bin/session/storage/Metadata.js.map +1 -1
- package/bin/session/storage/Persistence.d.ts +1 -1
- package/bin/session/storage/Persistence.d.ts.map +1 -1
- package/bin/session/storage/RuntimeSessionPort.d.ts +0 -12
- package/bin/session/storage/RuntimeSessionPort.d.ts.map +1 -1
- package/bin/session/storage/RuntimeSessionPort.js +0 -8
- package/bin/session/storage/RuntimeSessionPort.js.map +1 -1
- package/bin/types/plugin/PluginAction.d.ts +0 -10
- package/bin/types/plugin/PluginAction.d.ts.map +1 -1
- package/bin/types/plugin/PluginCommand.d.ts +2 -3
- package/bin/types/plugin/PluginCommand.d.ts.map +1 -1
- package/bin/types/plugin/PluginControl.d.ts +74 -0
- package/bin/types/plugin/PluginControl.d.ts.map +1 -0
- package/bin/types/plugin/PluginControl.js +9 -0
- package/bin/types/plugin/PluginControl.js.map +1 -0
- package/bin/types/plugin/PluginDefinition.d.ts +1 -1
- package/bin/types/plugin/PluginDefinition.d.ts.map +1 -1
- package/bin/types/plugin/PluginRuntime.d.ts +1 -3
- package/bin/types/plugin/PluginRuntime.d.ts.map +1 -1
- package/bin/types/plugin/PluginState.d.ts +3 -16
- package/bin/types/plugin/PluginState.d.ts.map +1 -1
- package/bin/types/rpc/RpcProtocol.d.ts +3 -3
- package/bin/types/rpc/RpcProtocol.d.ts.map +1 -1
- package/bin/types/runtime/agent/AgentContext.d.ts +1 -9
- 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/SessionLocalState.d.ts +1 -1
- package/bin/types/session/SessionLocalState.d.ts.map +1 -1
- package/package.json +4 -7
- package/scripts/agent-ready.test.mjs +38 -0
- package/scripts/assistant-file-resource.test.mjs +39 -0
- package/scripts/city-model-tool-loop.test.mjs +18 -30
- package/scripts/image-plugin-job.test.mjs +13 -13
- package/scripts/plugin-tool-bridge.test.mjs +2 -3
- package/scripts/remote-session-reconnect.test.mjs +67 -0
- package/scripts/session-history-writer-error.test.mjs +57 -0
- package/scripts/session-list-title.test.mjs +114 -23
- package/scripts/session-prompt-runtime.test.mjs +22 -0
- package/src/agent/local/Agent.ts +4 -10
- package/src/agent/local/AgentInstructions.ts +1 -1
- package/src/agent/local/services/AgentAssemblyService.ts +3 -9
- package/src/agent/local/services/AgentSessions.ts +8 -15
- package/src/agent/remote/RemoteAgent.ts +5 -4
- package/src/agent/remote/RemoteSession.ts +21 -2
- package/src/agent/remote/RemoteTransport.ts +6 -2
- package/src/agent/remote/transports/HttpRemoteAgentTransport.ts +13 -3
- package/src/agent/remote/transports/RpcRemoteAgentTransport.ts +6 -2
- package/src/executor/Executor.ts +0 -23
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.ts +2 -8
- package/src/executor/composer/history/SessionHistoryWriter.ts +33 -64
- package/src/executor/messages/AssistantFileResource.ts +61 -17
- package/src/executor/services/ExecutorInflightService.ts +0 -10
- package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +130 -4
- package/src/executor/types/SessionHistoryMeta.ts +6 -0
- package/src/index.ts +100 -29
- package/src/plugin/core/ActionScheduleExecutor.ts +1 -1
- package/src/plugin/core/BasePlugin.ts +8 -22
- package/src/plugin/core/HookRegistry.ts +1 -1
- package/src/plugin/core/PluginActionFactory.ts +1 -8
- package/src/plugin/core/PluginActionRunner.ts +8 -11
- package/src/plugin/core/PluginCatalog.ts +2 -5
- package/src/plugin/core/PluginCommand.ts +2 -1
- package/src/plugin/core/PluginHttpRoutes.ts +1 -1
- package/src/plugin/core/PluginLocalExecution.ts +4 -7
- package/src/plugin/core/PluginRegistry.ts +10 -10
- package/src/plugin/core/PluginStateController.ts +12 -60
- package/src/plugin/types/PluginApi.ts +6 -81
- package/src/rpc/Client.ts +22 -16
- package/src/session/Session.ts +5 -21
- package/src/session/SessionSystemBuilder.ts +1 -1
- package/src/session/browse/Browse.ts +103 -84
- package/src/session/preview/SessionMessagePreview.ts +75 -0
- package/src/session/runtime/SessionPromptRuntime.ts +29 -4
- package/src/session/services/SessionStateService.ts +3 -4
- package/src/session/services/SessionTurnService.ts +9 -0
- package/src/session/services/SessionViewService.ts +6 -6
- package/src/session/storage/Metadata.ts +26 -0
- package/src/session/storage/Persistence.ts +1 -1
- package/src/session/storage/RuntimeSessionPort.ts +0 -20
- package/src/types/plugin/PluginAction.ts +0 -10
- package/src/types/plugin/PluginCommand.ts +2 -3
- package/src/types/plugin/PluginControl.ts +80 -0
- package/src/types/plugin/PluginDefinition.ts +1 -1
- package/src/types/plugin/PluginRuntime.ts +1 -3
- package/src/types/plugin/PluginState.ts +3 -20
- package/src/types/rpc/RpcProtocol.ts +4 -4
- package/src/types/runtime/agent/AgentContext.ts +1 -9
- package/src/types/session/SessionLocalState.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/bin/config/DowncitySchema.d.ts +0 -20
- package/bin/config/DowncitySchema.d.ts.map +0 -1
- package/bin/config/DowncitySchema.js +0 -160
- package/bin/config/DowncitySchema.js.map +0 -1
- package/bin/plugin/core/Activation.d.ts +0 -18
- package/bin/plugin/core/Activation.d.ts.map +0 -1
- package/bin/plugin/core/Activation.js +0 -21
- package/bin/plugin/core/Activation.js.map +0 -1
- package/bin/plugin/core/Manager.d.ts +0 -7
- package/bin/plugin/core/Manager.d.ts.map +0 -1
- package/bin/plugin/core/Manager.js +0 -6
- package/bin/plugin/core/Manager.js.map +0 -1
- package/bin/plugin/types/Plugin.d.ts +0 -15
- package/bin/plugin/types/Plugin.d.ts.map +0 -1
- package/bin/plugin/types/Plugin.js +0 -9
- package/bin/plugin/types/Plugin.js.map +0 -1
- package/bin/plugin/types/PluginLifecycle.d.ts +0 -34
- package/bin/plugin/types/PluginLifecycle.d.ts.map +0 -1
- package/bin/plugin/types/PluginLifecycle.js +0 -9
- package/bin/plugin/types/PluginLifecycle.js.map +0 -1
- package/bin/plugin/types/PluginState.d.ts +0 -5
- package/bin/plugin/types/PluginState.d.ts.map +0 -1
- package/bin/plugin/types/PluginState.js +0 -5
- package/bin/plugin/types/PluginState.js.map +0 -1
- package/bin/plugin/types/Plugins.d.ts +0 -61
- package/bin/plugin/types/Plugins.d.ts.map +0 -1
- package/bin/plugin/types/Plugins.js +0 -5
- package/bin/plugin/types/Plugins.js.map +0 -1
- package/bin/session/index.d.ts +0 -15
- package/bin/session/index.d.ts.map +0 -1
- package/bin/session/index.js +0 -15
- package/bin/session/index.js.map +0 -1
- package/bin/types/agent/AgentTypes.d.ts +0 -18
- package/bin/types/agent/AgentTypes.d.ts.map +0 -1
- package/bin/types/agent/AgentTypes.js +0 -10
- package/bin/types/agent/AgentTypes.js.map +0 -1
- package/bin/utils/logger/Format.d.ts +0 -11
- package/bin/utils/logger/Format.d.ts.map +0 -1
- package/bin/utils/logger/Format.js +0 -10
- package/bin/utils/logger/Format.js.map +0 -1
- package/src/config/DowncitySchema.ts +0 -175
- package/src/plugin/core/Activation.ts +0 -26
- package/src/plugin/core/Manager.ts +0 -17
- package/src/plugin/types/Plugin.ts +0 -63
- package/src/plugin/types/PluginLifecycle.ts +0 -35
- package/src/plugin/types/PluginState.ts +0 -12
- package/src/plugin/types/Plugins.ts +0 -67
- package/src/session/index.ts +0 -57
- package/src/types/agent/AgentTypes.ts +0 -58
- package/src/utils/logger/Format.ts +0 -15
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 验证 RemoteSession 在事件连接断开后能够重新建立订阅。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - 断流必须结束当前 pending turn,避免 finished 永久等待。
|
|
6
|
+
* - 下一次 prompt 必须重新调用 transport.subscribe。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import test from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
|
|
12
|
+
import { RemoteSession } from "../bin/agent/remote/RemoteSession.js";
|
|
13
|
+
|
|
14
|
+
test("RemoteSession reconnects the event pump after transport close", async () => {
|
|
15
|
+
const subscriptions = [];
|
|
16
|
+
let prompt_count = 0;
|
|
17
|
+
const transport = {
|
|
18
|
+
async subscribe(input) {
|
|
19
|
+
subscriptions.push(input);
|
|
20
|
+
input.on_ready();
|
|
21
|
+
return { close: async () => {} };
|
|
22
|
+
},
|
|
23
|
+
async prompt() {
|
|
24
|
+
prompt_count += 1;
|
|
25
|
+
return { id: `turn_${prompt_count}` };
|
|
26
|
+
},
|
|
27
|
+
async get_info() {
|
|
28
|
+
throw new Error("unused");
|
|
29
|
+
},
|
|
30
|
+
async stop() {
|
|
31
|
+
return { stopped: false, cancelledQueuedPrompts: 0, reason: "idle" };
|
|
32
|
+
},
|
|
33
|
+
async records() {
|
|
34
|
+
throw new Error("unused");
|
|
35
|
+
},
|
|
36
|
+
async system() {
|
|
37
|
+
throw new Error("unused");
|
|
38
|
+
},
|
|
39
|
+
async fork() {
|
|
40
|
+
throw new Error("unused");
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
const session = new RemoteSession(transport, {
|
|
44
|
+
agentId: "agent_test",
|
|
45
|
+
sessionId: "session_test",
|
|
46
|
+
messageCount: 0,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const first_turn = await session.prompt({ query: "first" });
|
|
50
|
+
subscriptions[0].on_close(new Error("stream dropped"));
|
|
51
|
+
assert.deepEqual(await first_turn.finished, {
|
|
52
|
+
turnId: "turn_1",
|
|
53
|
+
text: "",
|
|
54
|
+
success: false,
|
|
55
|
+
error: "stream dropped",
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const second_turn = await session.prompt({ query: "second" });
|
|
59
|
+
assert.equal(subscriptions.length, 2);
|
|
60
|
+
subscriptions[1].on_event({
|
|
61
|
+
type: "turn-finish",
|
|
62
|
+
turnId: second_turn.id,
|
|
63
|
+
text: "done",
|
|
64
|
+
success: true,
|
|
65
|
+
});
|
|
66
|
+
assert.equal((await second_turn.finished).text, "done");
|
|
67
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 验证 SessionHistoryWriter 不会掩盖事实源写入失败。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - user 消息写入失败必须向调用方抛出。
|
|
6
|
+
* - assistant inflight 落盘失败也必须向调用方抛出。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import test from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
|
|
12
|
+
import { SessionHistoryWriter } from "../bin/executor/composer/history/SessionHistoryWriter.js";
|
|
13
|
+
|
|
14
|
+
function create_failing_history_store() {
|
|
15
|
+
return {
|
|
16
|
+
userText() {
|
|
17
|
+
throw new Error("unused");
|
|
18
|
+
},
|
|
19
|
+
assistantText() {
|
|
20
|
+
throw new Error("unused");
|
|
21
|
+
},
|
|
22
|
+
async write_record() {
|
|
23
|
+
throw new Error("disk full");
|
|
24
|
+
},
|
|
25
|
+
async finalize_inflight() {
|
|
26
|
+
throw new Error("disk full");
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
test("append_user_message propagates history write failures", async () => {
|
|
32
|
+
const writer = new SessionHistoryWriter({
|
|
33
|
+
sessionId: "writer_error_session",
|
|
34
|
+
getHistoryStore: create_failing_history_store,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
await assert.rejects(
|
|
38
|
+
writer.append_user_message({
|
|
39
|
+
message: { v: 1, id: "user_1", role: "user", parts: [] },
|
|
40
|
+
}),
|
|
41
|
+
/disk full/,
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("append_assistant_message propagates history write failures", async () => {
|
|
46
|
+
const writer = new SessionHistoryWriter({
|
|
47
|
+
sessionId: "writer_error_session",
|
|
48
|
+
getHistoryStore: create_failing_history_store,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
await assert.rejects(
|
|
52
|
+
writer.append_assistant_message({
|
|
53
|
+
message: { v: 1, id: "assistant_1", role: "assistant", parts: [] },
|
|
54
|
+
}),
|
|
55
|
+
/disk full/,
|
|
56
|
+
);
|
|
57
|
+
});
|
|
@@ -19,28 +19,37 @@ import { Agent } from "../bin/index.js";
|
|
|
19
19
|
function create_mock_title_model(title_text) {
|
|
20
20
|
return new MockLanguageModelV3({
|
|
21
21
|
modelId: "mock-session-list-title-model",
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
{
|
|
25
|
-
type: "
|
|
26
|
-
text:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
22
|
+
doStream: async () => ({
|
|
23
|
+
stream: new ReadableStream({
|
|
24
|
+
start(controller) {
|
|
25
|
+
controller.enqueue({ type: "stream-start", warnings: [] });
|
|
26
|
+
controller.enqueue({ type: "text-start", id: "title" });
|
|
27
|
+
controller.enqueue({
|
|
28
|
+
type: "text-delta",
|
|
29
|
+
id: "title",
|
|
30
|
+
delta: title_text,
|
|
31
|
+
});
|
|
32
|
+
controller.enqueue({ type: "text-end", id: "title" });
|
|
33
|
+
controller.enqueue({
|
|
34
|
+
type: "finish",
|
|
35
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
36
|
+
usage: {
|
|
37
|
+
inputTokens: {
|
|
38
|
+
total: 0,
|
|
39
|
+
noCache: 0,
|
|
40
|
+
cacheRead: 0,
|
|
41
|
+
cacheWrite: 0,
|
|
42
|
+
},
|
|
43
|
+
outputTokens: {
|
|
44
|
+
total: 0,
|
|
45
|
+
text: 0,
|
|
46
|
+
reasoning: 0,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
controller.close();
|
|
36
51
|
},
|
|
37
|
-
|
|
38
|
-
total: 0,
|
|
39
|
-
text: 0,
|
|
40
|
-
reasoning: 0,
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
warnings: [],
|
|
52
|
+
}),
|
|
44
53
|
}),
|
|
45
54
|
});
|
|
46
55
|
}
|
|
@@ -81,8 +90,38 @@ test("list_sessions returns persisted title from active session metadata", async
|
|
|
81
90
|
|
|
82
91
|
try {
|
|
83
92
|
const page = await collection.list();
|
|
93
|
+
const meta = JSON.parse(
|
|
94
|
+
await fs.readFile(
|
|
95
|
+
path.join(
|
|
96
|
+
agent.path,
|
|
97
|
+
".downcity",
|
|
98
|
+
"agents",
|
|
99
|
+
encodeURIComponent(agent.id),
|
|
100
|
+
"sessions",
|
|
101
|
+
encodeURIComponent(session.id),
|
|
102
|
+
"messages",
|
|
103
|
+
"meta.json",
|
|
104
|
+
),
|
|
105
|
+
"utf8",
|
|
106
|
+
),
|
|
107
|
+
);
|
|
84
108
|
|
|
85
109
|
assert.equal(page.total, 1);
|
|
110
|
+
assert.equal(meta.messageCount, 1);
|
|
111
|
+
assert.equal(meta.previewText, "Need the session list to show the generated title");
|
|
112
|
+
const history_stat = await fs.stat(
|
|
113
|
+
path.join(
|
|
114
|
+
agent.path,
|
|
115
|
+
".downcity",
|
|
116
|
+
"agents",
|
|
117
|
+
encodeURIComponent(agent.id),
|
|
118
|
+
"sessions",
|
|
119
|
+
encodeURIComponent(session.id),
|
|
120
|
+
"messages",
|
|
121
|
+
"messages.jsonl",
|
|
122
|
+
),
|
|
123
|
+
);
|
|
124
|
+
assert.equal(meta.historyBytes, history_stat.size);
|
|
86
125
|
assert.deepEqual(
|
|
87
126
|
page.items.map((item) => ({
|
|
88
127
|
sessionId: item.sessionId,
|
|
@@ -93,7 +132,7 @@ test("list_sessions returns persisted title from active session metadata", async
|
|
|
93
132
|
{
|
|
94
133
|
sessionId: session.id,
|
|
95
134
|
title: "列表标题",
|
|
96
|
-
messageCount:
|
|
135
|
+
messageCount: 1,
|
|
97
136
|
},
|
|
98
137
|
],
|
|
99
138
|
);
|
|
@@ -102,6 +141,58 @@ test("list_sessions returns persisted title from active session metadata", async
|
|
|
102
141
|
}
|
|
103
142
|
});
|
|
104
143
|
|
|
144
|
+
test("list_sessions rebuilds stale metadata after external history changes", async () => {
|
|
145
|
+
const { agent, collection, session } = await create_agent_with_titled_session({
|
|
146
|
+
tmp_prefix: "downcity-agent-session-summary-repair-",
|
|
147
|
+
agent_id: "summary_repair_agent",
|
|
148
|
+
session_id: "summary_repair_session",
|
|
149
|
+
title: "摘要修复",
|
|
150
|
+
first_user_text: "Initial history",
|
|
151
|
+
});
|
|
152
|
+
const messages_dir = path.join(
|
|
153
|
+
agent.path,
|
|
154
|
+
".downcity",
|
|
155
|
+
"agents",
|
|
156
|
+
encodeURIComponent(agent.id),
|
|
157
|
+
"sessions",
|
|
158
|
+
encodeURIComponent(session.id),
|
|
159
|
+
"messages",
|
|
160
|
+
);
|
|
161
|
+
const messages_path = path.join(messages_dir, "messages.jsonl");
|
|
162
|
+
const meta_path = path.join(messages_dir, "meta.json");
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
await fs.appendFile(
|
|
166
|
+
messages_path,
|
|
167
|
+
`${JSON.stringify({
|
|
168
|
+
id: "external_assistant",
|
|
169
|
+
role: "assistant",
|
|
170
|
+
metadata: {
|
|
171
|
+
v: 1,
|
|
172
|
+
ts: Date.now(),
|
|
173
|
+
sessionId: session.id,
|
|
174
|
+
source: "egress",
|
|
175
|
+
kind: "normal",
|
|
176
|
+
},
|
|
177
|
+
parts: [{ type: "text", text: "Externally appended history" }],
|
|
178
|
+
})}\n`,
|
|
179
|
+
"utf8",
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const page = await collection.list();
|
|
183
|
+
const repaired_meta = JSON.parse(await fs.readFile(meta_path, "utf8"));
|
|
184
|
+
const history_stat = await fs.stat(messages_path);
|
|
185
|
+
|
|
186
|
+
assert.equal(page.items[0].messageCount, 2);
|
|
187
|
+
assert.equal(page.items[0].previewText, "Externally appended history");
|
|
188
|
+
assert.equal(repaired_meta.messageCount, 2);
|
|
189
|
+
assert.equal(repaired_meta.previewText, "Externally appended history");
|
|
190
|
+
assert.equal(repaired_meta.historyBytes, history_stat.size);
|
|
191
|
+
} finally {
|
|
192
|
+
await agent.dispose();
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
105
196
|
test("archive_sessions returns title from archived session metadata", async () => {
|
|
106
197
|
const { agent, collection, session } = await create_agent_with_titled_session({
|
|
107
198
|
tmp_prefix: "downcity-agent-archive-list-title-",
|
|
@@ -131,7 +222,7 @@ test("archive_sessions returns title from archived session metadata", async () =
|
|
|
131
222
|
{
|
|
132
223
|
sessionId: session.id,
|
|
133
224
|
title: "归档标题",
|
|
134
|
-
messageCount:
|
|
225
|
+
messageCount: 1,
|
|
135
226
|
},
|
|
136
227
|
],
|
|
137
228
|
);
|
|
@@ -76,6 +76,8 @@ async function isSettled(promise) {
|
|
|
76
76
|
test("SessionPromptRuntime merges queued prompts at the next step boundary", async () => {
|
|
77
77
|
const events = [];
|
|
78
78
|
const persisted = [];
|
|
79
|
+
const steer_actions = [];
|
|
80
|
+
const merge_lifecycle = [];
|
|
79
81
|
const executionFinished = createDeferred();
|
|
80
82
|
let stepMerge = null;
|
|
81
83
|
|
|
@@ -87,8 +89,13 @@ test("SessionPromptRuntime merges queued prompts at the next step boundary", asy
|
|
|
87
89
|
createAndPersistUserMessage: async (input) => {
|
|
88
90
|
const message = createUserMessage(input.query, persisted.length + 1);
|
|
89
91
|
persisted.push(message);
|
|
92
|
+
merge_lifecycle.push(`message:${input.query}`);
|
|
90
93
|
return message;
|
|
91
94
|
},
|
|
95
|
+
emit_steer_action: async (input) => {
|
|
96
|
+
steer_actions.push(input);
|
|
97
|
+
merge_lifecycle.push(`action:${input.message.parts[0]?.text}`);
|
|
98
|
+
},
|
|
92
99
|
executeTurn: async (input) => {
|
|
93
100
|
stepMerge = input.onStepMerge;
|
|
94
101
|
await executionFinished.promise;
|
|
@@ -119,6 +126,18 @@ test("SessionPromptRuntime merges queued prompts at the next step boundary", asy
|
|
|
119
126
|
persisted.map((message) => message.parts[0]?.text),
|
|
120
127
|
["first", "second"],
|
|
121
128
|
);
|
|
129
|
+
assert.deepEqual(
|
|
130
|
+
steer_actions.map((action) => ({
|
|
131
|
+
turn_id: action.turn_id,
|
|
132
|
+
text: action.message.parts[0]?.text,
|
|
133
|
+
})),
|
|
134
|
+
[{ turn_id: firstTurn.id, text: "second" }],
|
|
135
|
+
);
|
|
136
|
+
assert.deepEqual(merge_lifecycle, [
|
|
137
|
+
"message:first",
|
|
138
|
+
"message:second",
|
|
139
|
+
"action:second",
|
|
140
|
+
]);
|
|
122
141
|
|
|
123
142
|
executionFinished.resolve();
|
|
124
143
|
const result = await firstTurn.finished;
|
|
@@ -144,6 +163,7 @@ test("SessionPromptRuntime moves unmerged prompts into the next turn", async ()
|
|
|
144
163
|
createAndPersistUserMessage: async (input) => {
|
|
145
164
|
return createUserMessage(input.query, events.length + 1);
|
|
146
165
|
},
|
|
166
|
+
emit_steer_action: async () => {},
|
|
147
167
|
executeTurn: async (input) => {
|
|
148
168
|
const deferred = createDeferred();
|
|
149
169
|
finishQueue.push({
|
|
@@ -201,6 +221,7 @@ test("SessionPromptRuntime stops current turn and cancels unmerged queued prompt
|
|
|
201
221
|
createAndPersistUserMessage: async (input) => {
|
|
202
222
|
return createUserMessage(input.query, events.length + 1);
|
|
203
223
|
},
|
|
224
|
+
emit_steer_action: async () => {},
|
|
204
225
|
executeTurn: async (input) => {
|
|
205
226
|
await new Promise((resolve) => {
|
|
206
227
|
input.abortSignal.addEventListener("abort", resolve, { once: true });
|
|
@@ -257,6 +278,7 @@ test("SessionPromptRuntime does not synthesize assistant text when stopped befor
|
|
|
257
278
|
createAndPersistUserMessage: async (input) => {
|
|
258
279
|
return createUserMessage(input.query, 1);
|
|
259
280
|
},
|
|
281
|
+
emit_steer_action: async () => {},
|
|
260
282
|
executeTurn: async (input) => {
|
|
261
283
|
await new Promise((resolve) => {
|
|
262
284
|
input.abortSignal.addEventListener("abort", resolve, { once: true });
|
package/src/agent/local/Agent.ts
CHANGED
|
@@ -10,12 +10,10 @@
|
|
|
10
10
|
import type { Tool } from "ai";
|
|
11
11
|
import type { AgentContext } from "@/types/runtime/agent/AgentContext.js";
|
|
12
12
|
import type { DowncityConfig } from "@/types/config/DowncityConfig.js";
|
|
13
|
-
import type { AgentPlugins } from "@/plugin/
|
|
14
|
-
import type {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
AgentSessions as AgentSessionsApi,
|
|
18
|
-
} from "@/types/agent/AgentTypes.js";
|
|
13
|
+
import type { AgentPlugins } from "@/types/plugin/PluginRuntime.js";
|
|
14
|
+
import type { AgentModel } from "@/model/CityModelAdapter.js";
|
|
15
|
+
import type { AgentOptions } from "@/types/agent/AgentOptions.js";
|
|
16
|
+
import type { AgentSessions as AgentSessionsApi } from "@/types/agent/SessionActor.js";
|
|
19
17
|
import type {
|
|
20
18
|
ShellApprovalMode,
|
|
21
19
|
ShellApprovalDecisionResult,
|
|
@@ -25,7 +23,6 @@ import type {
|
|
|
25
23
|
ShellApprovalView,
|
|
26
24
|
Shell,
|
|
27
25
|
} from "@downcity/shell";
|
|
28
|
-
import { PluginRegistry } from "@/plugin/core/PluginRegistry.js";
|
|
29
26
|
import { Logger } from "@/utils/logger/Logger.js";
|
|
30
27
|
import { normalizeInstructionInput } from "@/agent/local/AgentInstructions.js";
|
|
31
28
|
import {
|
|
@@ -47,7 +44,6 @@ export class Agent {
|
|
|
47
44
|
|
|
48
45
|
private readonly logger: Logger;
|
|
49
46
|
private readonly agentContext: AgentContext;
|
|
50
|
-
private readonly pluginRegistry: PluginRegistry;
|
|
51
47
|
private readonly config: DowncityConfig;
|
|
52
48
|
private readonly env: Record<string, string>;
|
|
53
49
|
private readonly defaultModel?: AgentModel;
|
|
@@ -84,7 +80,6 @@ export class Agent {
|
|
|
84
80
|
this.plugins = assembly.plugins;
|
|
85
81
|
this.logger = assembly.logger;
|
|
86
82
|
this.agentContext = assembly.agent_context;
|
|
87
|
-
this.pluginRegistry = assembly.plugin_registry;
|
|
88
83
|
this.config = assembly.config;
|
|
89
84
|
this.env = assembly.env;
|
|
90
85
|
this.instruction = assembly.instruction;
|
|
@@ -262,7 +257,6 @@ export class Agent {
|
|
|
262
257
|
logger: this.logger || assembly.logger,
|
|
263
258
|
get_agent_context: () => this.agentContext ?? assembly.agent_context,
|
|
264
259
|
get_instruction: () => this.instruction,
|
|
265
|
-
plugin_instances: assembly.plugin_instances,
|
|
266
260
|
ensure_agent_ready: async () => {
|
|
267
261
|
await this.backgroundService.ready();
|
|
268
262
|
},
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { DowncityConfig } from "@/types/config/DowncityConfig.js";
|
|
11
|
-
import type { AgentSessionSystemBlock } from "@/types/agent/
|
|
11
|
+
import type { AgentSessionSystemBlock } from "@/types/agent/SessionTypes.js";
|
|
12
12
|
import { DEFAULT_SHIP_PROMPTS } from "@executor/composer/system/default/SystemDomain.js";
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -11,8 +11,8 @@ import type { LanguageModel, Tool } from "ai";
|
|
|
11
11
|
import type { Plugin } from "@/types/plugin/PluginDefinition.js";
|
|
12
12
|
import { AgentContext } from "@/types/runtime/agent/AgentContext.js";
|
|
13
13
|
import type { DowncityConfig } from "@/types/config/DowncityConfig.js";
|
|
14
|
-
import type { AgentPlugins } from "@/plugin/
|
|
15
|
-
import type { AgentOptions } from "@/types/agent/
|
|
14
|
+
import type { AgentPlugins } from "@/types/plugin/PluginRuntime.js";
|
|
15
|
+
import type { AgentOptions } from "@/types/agent/AgentOptions.js";
|
|
16
16
|
import { Logger } from "@/utils/logger/Logger.js";
|
|
17
17
|
import { loadDowncityConfig, resolveAgentEnv } from "@/config/Config.js";
|
|
18
18
|
import { PluginRegistry } from "@/plugin/core/PluginRegistry.js";
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
import {
|
|
31
31
|
createPluginTools,
|
|
32
32
|
} from "@executor/tools/plugin/PluginToolDefinition.js";
|
|
33
|
-
import type { AgentManagedSession } from "@/types/
|
|
33
|
+
import type { AgentManagedSession } from "@/types/session/SessionOptions.js";
|
|
34
34
|
import type { SessionPort } from "@/types/runtime/agent/AgentContext.js";
|
|
35
35
|
import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
|
|
36
36
|
|
|
@@ -102,11 +102,6 @@ export interface AgentAssemblyResult {
|
|
|
102
102
|
*/
|
|
103
103
|
plugin_instances: Map<string, Plugin>;
|
|
104
104
|
|
|
105
|
-
/**
|
|
106
|
-
* 当前 plugin 注册表。
|
|
107
|
-
*/
|
|
108
|
-
plugin_registry: PluginRegistry;
|
|
109
|
-
|
|
110
105
|
/**
|
|
111
106
|
* 当前 agent plugin 调用面。
|
|
112
107
|
*/
|
|
@@ -238,7 +233,6 @@ export class AgentAssemblyService {
|
|
|
238
233
|
instruction,
|
|
239
234
|
config,
|
|
240
235
|
plugin_instances,
|
|
241
|
-
plugin_registry,
|
|
242
236
|
plugins,
|
|
243
237
|
agent_context: agent_context!,
|
|
244
238
|
...(shell ? { shell } : {}),
|
|
@@ -19,25 +19,25 @@ import type {
|
|
|
19
19
|
AgentArchiveSessionsResult,
|
|
20
20
|
AgentCleanArchiveResult,
|
|
21
21
|
AgentListSessionsInput,
|
|
22
|
-
AgentManagedSession,
|
|
23
|
-
AgentModel,
|
|
24
|
-
AgentSession,
|
|
25
|
-
AgentSessions as AgentSessionsApi,
|
|
26
|
-
AgentSessionConstructor,
|
|
27
22
|
AgentSessionSummaryPage,
|
|
28
23
|
AgentSessionSystemBlock,
|
|
29
|
-
} from "@/types/agent/
|
|
24
|
+
} from "@/types/agent/SessionTypes.js";
|
|
25
|
+
import type { AgentModel } from "@/model/CityModelAdapter.js";
|
|
26
|
+
import type { AgentSessionConstructor } from "@/types/agent/AgentOptions.js";
|
|
27
|
+
import type { AgentSession, AgentSessions as AgentSessionsApi } from "@/types/agent/SessionActor.js";
|
|
28
|
+
import type { AgentManagedSession } from "@/types/session/SessionOptions.js";
|
|
30
29
|
import { Session } from "@/session/Session.js";
|
|
31
30
|
import {
|
|
32
31
|
getSdkAgentArchivedSessionDirPath,
|
|
33
32
|
getSdkAgentArchivedSessionsDirPath,
|
|
34
33
|
getSdkAgentSessionDirPath,
|
|
34
|
+
} from "@/session/storage/Paths.js";
|
|
35
|
+
import {
|
|
35
36
|
listArchivedAgentSessionSummaryPage,
|
|
36
37
|
listAgentSessionSummaryPage,
|
|
37
|
-
} from "@/session/
|
|
38
|
+
} from "@/session/browse/Browse.js";
|
|
38
39
|
import type { AgentContext } from "@/types/runtime/agent/AgentContext.js";
|
|
39
40
|
import type { SessionPort } from "@/types/runtime/agent/AgentContext.js";
|
|
40
|
-
import type { Plugin } from "@/types/plugin/PluginDefinition.js";
|
|
41
41
|
import { createInstructionSystemBlocks } from "@/agent/local/AgentInstructions.js";
|
|
42
42
|
|
|
43
43
|
function decodeMaybe(input: string): string {
|
|
@@ -82,11 +82,6 @@ type AgentSessionsOptions = {
|
|
|
82
82
|
*/
|
|
83
83
|
get_instruction: () => string[];
|
|
84
84
|
|
|
85
|
-
/**
|
|
86
|
-
* 当前 plugin 实例集合。
|
|
87
|
-
*/
|
|
88
|
-
plugin_instances: Map<string, Plugin>;
|
|
89
|
-
|
|
90
85
|
/**
|
|
91
86
|
* 等待当前 Agent 后台能力启动完成。
|
|
92
87
|
*/
|
|
@@ -113,7 +108,6 @@ export class AgentSessions implements AgentSessionsApi<AgentSession> {
|
|
|
113
108
|
private readonly logger: Logger;
|
|
114
109
|
private readonly get_agent_context: AgentSessionsOptions["get_agent_context"];
|
|
115
110
|
private readonly get_instruction: AgentSessionsOptions["get_instruction"];
|
|
116
|
-
private readonly plugin_instances: Map<string, Plugin>;
|
|
117
111
|
private readonly ensure_agent_ready: AgentSessionsOptions["ensure_agent_ready"];
|
|
118
112
|
private readonly default_model?: AgentModel;
|
|
119
113
|
private readonly SessionClass: AgentSessionConstructor;
|
|
@@ -127,7 +121,6 @@ export class AgentSessions implements AgentSessionsApi<AgentSession> {
|
|
|
127
121
|
this.logger = options.logger;
|
|
128
122
|
this.get_agent_context = options.get_agent_context;
|
|
129
123
|
this.get_instruction = options.get_instruction;
|
|
130
|
-
this.plugin_instances = options.plugin_instances;
|
|
131
124
|
this.ensure_agent_ready = options.ensure_agent_ready;
|
|
132
125
|
this.default_model = options.default_model;
|
|
133
126
|
this.SessionClass = options.SessionClass || Session;
|
|
@@ -16,12 +16,13 @@ import type {
|
|
|
16
16
|
AgentCreateSessionInput,
|
|
17
17
|
AgentListSessionsInput,
|
|
18
18
|
AgentSessionSummaryPage,
|
|
19
|
-
|
|
19
|
+
} from "@/types/agent/SessionTypes.js";
|
|
20
|
+
import type { AgentSessions, RemoteAgentSession } from "@/types/agent/SessionActor.js";
|
|
21
|
+
import type { RemoteAgentOptions } from "@/types/agent/RemoteAgentOptions.js";
|
|
22
|
+
import type {
|
|
20
23
|
RemoteAgentPluginActionInput,
|
|
21
24
|
RemoteAgentPluginActionResult,
|
|
22
|
-
|
|
23
|
-
RemoteAgentSession,
|
|
24
|
-
} from "@/types/agent/AgentTypes.js";
|
|
25
|
+
} from "@/types/agent/RemoteAgentPluginAction.js";
|
|
25
26
|
import type {
|
|
26
27
|
ShellApprovalMode,
|
|
27
28
|
ShellApprovalDecisionResult,
|
|
@@ -14,8 +14,8 @@ import type {
|
|
|
14
14
|
AgentSessionInfo,
|
|
15
15
|
AgentSessionSetInput,
|
|
16
16
|
AgentSessionSystemSnapshot,
|
|
17
|
-
|
|
18
|
-
} from "@/types/agent/
|
|
17
|
+
} from "@/types/agent/SessionTypes.js";
|
|
18
|
+
import type { RemoteAgentSession } from "@/types/agent/SessionActor.js";
|
|
19
19
|
import { isAgentSessionPromptInputEmpty } from "@/types/sdk/AgentSessionPrompt.js";
|
|
20
20
|
import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
|
|
21
21
|
import type {
|
|
@@ -171,6 +171,9 @@ export class RemoteSession implements RemoteAgentSession {
|
|
|
171
171
|
on_event: (event) => {
|
|
172
172
|
this.handle_event(event);
|
|
173
173
|
},
|
|
174
|
+
on_close: (error) => {
|
|
175
|
+
this.handle_event_pump_closed(error);
|
|
176
|
+
},
|
|
174
177
|
});
|
|
175
178
|
this.event_pump_running = true;
|
|
176
179
|
if (!resolved_ready) {
|
|
@@ -211,6 +214,22 @@ export class RemoteSession implements RemoteAgentSession {
|
|
|
211
214
|
this.event_hub.publish(event);
|
|
212
215
|
}
|
|
213
216
|
|
|
217
|
+
/**
|
|
218
|
+
* 收口底层事件连接断开后的运行态。
|
|
219
|
+
*
|
|
220
|
+
* 关键点(中文)
|
|
221
|
+
* - 连接已经结束时必须清除 running 标记,后续 prompt 才会重新订阅。
|
|
222
|
+
* - 当前未完成 turn 立即失败,避免调用侧永久等待 finished。
|
|
223
|
+
*/
|
|
224
|
+
private handle_event_pump_closed(error?: unknown): void {
|
|
225
|
+
this.event_subscription = null;
|
|
226
|
+
this.event_pump_running = false;
|
|
227
|
+
const message = error instanceof Error
|
|
228
|
+
? error.message
|
|
229
|
+
: String(error || "Remote session events connection closed");
|
|
230
|
+
this.fail_pending_turns(message);
|
|
231
|
+
}
|
|
232
|
+
|
|
214
233
|
private ensure_turn_lifecycle(turn_id: string): RemoteTurnLifecycle {
|
|
215
234
|
const cached = this.turns_by_id.get(turn_id);
|
|
216
235
|
if (cached) return cached;
|
|
@@ -20,12 +20,14 @@ import type {
|
|
|
20
20
|
AgentSessionInfo,
|
|
21
21
|
AgentSessionSummaryPage,
|
|
22
22
|
AgentSessionSystemSnapshot,
|
|
23
|
-
|
|
23
|
+
} from "@/types/agent/SessionTypes.js";
|
|
24
|
+
import type {
|
|
24
25
|
RemoteAgentPluginActionInput,
|
|
25
26
|
RemoteAgentPluginActionResult,
|
|
26
|
-
} from "@/types/agent/
|
|
27
|
+
} from "@/types/agent/RemoteAgentPluginAction.js";
|
|
27
28
|
import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
|
|
28
29
|
import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
|
|
30
|
+
import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
|
|
29
31
|
import type {
|
|
30
32
|
ShellApprovalMode,
|
|
31
33
|
ShellApprovalDecisionResult,
|
|
@@ -61,6 +63,8 @@ export type RemoteSessionTransport = {
|
|
|
61
63
|
session_id: string;
|
|
62
64
|
on_ready: () => void;
|
|
63
65
|
on_event: (event: AgentSessionEvent) => void;
|
|
66
|
+
/** 底层事件连接结束后的通知;主动关闭不触发。 */
|
|
67
|
+
on_close: (error?: unknown) => void;
|
|
64
68
|
}): Promise<TransportSubscription>;
|
|
65
69
|
/** 读取 history。 */
|
|
66
70
|
records(
|
|
@@ -20,12 +20,14 @@ import type {
|
|
|
20
20
|
AgentSessionInfo,
|
|
21
21
|
AgentSessionSummaryPage,
|
|
22
22
|
AgentSessionSystemSnapshot,
|
|
23
|
-
|
|
23
|
+
} from "@/types/agent/SessionTypes.js";
|
|
24
|
+
import type {
|
|
24
25
|
RemoteAgentPluginActionInput,
|
|
25
26
|
RemoteAgentPluginActionResult,
|
|
26
|
-
} from "@/types/agent/
|
|
27
|
+
} from "@/types/agent/RemoteAgentPluginAction.js";
|
|
27
28
|
import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
|
|
28
29
|
import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
|
|
30
|
+
import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
|
|
29
31
|
import type {
|
|
30
32
|
RemoteAgentTransport,
|
|
31
33
|
TransportSubscription,
|
|
@@ -145,6 +147,7 @@ export class HttpRemoteAgentTransport implements RemoteAgentTransport {
|
|
|
145
147
|
session_id: string;
|
|
146
148
|
on_ready: () => void;
|
|
147
149
|
on_event: (event: AgentSessionEvent) => void;
|
|
150
|
+
on_close: (error?: unknown) => void;
|
|
148
151
|
}): Promise<TransportSubscription> {
|
|
149
152
|
const abort_controller = new AbortController();
|
|
150
153
|
let resolve_ready!: () => void;
|
|
@@ -175,6 +178,10 @@ export class HttpRemoteAgentTransport implements RemoteAgentTransport {
|
|
|
175
178
|
reject_ready(error);
|
|
176
179
|
},
|
|
177
180
|
on_event: params.on_event,
|
|
181
|
+
}).then((error) => {
|
|
182
|
+
if (!abort_controller.signal.aborted) {
|
|
183
|
+
params.on_close(error);
|
|
184
|
+
}
|
|
178
185
|
});
|
|
179
186
|
await ready_promise;
|
|
180
187
|
return {
|
|
@@ -495,11 +502,12 @@ async function consume_http_event_stream(params: {
|
|
|
495
502
|
on_ready: () => void;
|
|
496
503
|
on_ready_error: (error: unknown) => void;
|
|
497
504
|
on_event: (event: AgentSessionEvent) => void;
|
|
498
|
-
}): Promise<
|
|
505
|
+
}): Promise<unknown | undefined> {
|
|
499
506
|
const decoder = new TextDecoder();
|
|
500
507
|
const reader = params.body.getReader();
|
|
501
508
|
let buffered = "";
|
|
502
509
|
let ready_resolved = false;
|
|
510
|
+
let close_error: unknown;
|
|
503
511
|
|
|
504
512
|
try {
|
|
505
513
|
while (true) {
|
|
@@ -546,6 +554,7 @@ async function consume_http_event_stream(params: {
|
|
|
546
554
|
});
|
|
547
555
|
}
|
|
548
556
|
} catch (error) {
|
|
557
|
+
close_error = error;
|
|
549
558
|
if (!params.abort_controller.signal.aborted) {
|
|
550
559
|
if (!ready_resolved) {
|
|
551
560
|
params.on_ready_error(error);
|
|
@@ -562,6 +571,7 @@ async function consume_http_event_stream(params: {
|
|
|
562
571
|
// ignore
|
|
563
572
|
}
|
|
564
573
|
}
|
|
574
|
+
return close_error;
|
|
565
575
|
}
|
|
566
576
|
|
|
567
577
|
function extract_error_message(payload: unknown): string {
|