@downcity/agent 1.1.43 → 1.1.62
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/README.md +11 -12
- package/bin/agent/Agent.d.ts +31 -16
- package/bin/agent/Agent.d.ts.map +1 -1
- package/bin/agent/Agent.js +47 -63
- package/bin/agent/Agent.js.map +1 -1
- package/bin/agent/RemoteAgent.d.ts +6 -6
- package/bin/agent/RemoteAgent.d.ts.map +1 -1
- package/bin/agent/RemoteAgent.js +377 -267
- package/bin/agent/RemoteAgent.js.map +1 -1
- package/bin/config/AgentInitializer.d.ts +5 -5
- package/bin/config/AgentInitializer.d.ts.map +1 -1
- package/bin/config/AgentInitializer.js +15 -13
- package/bin/config/AgentInitializer.js.map +1 -1
- package/bin/config/Config.d.ts +9 -30
- package/bin/config/Config.d.ts.map +1 -1
- package/bin/config/Config.js +23 -70
- package/bin/config/Config.js.map +1 -1
- package/bin/config/Defaults.d.ts.map +1 -1
- package/bin/config/Defaults.js +1 -9
- package/bin/config/Defaults.js.map +1 -1
- package/bin/config/DowncitySchema.d.ts.map +1 -1
- package/bin/config/DowncitySchema.js +4 -112
- package/bin/config/DowncitySchema.js.map +1 -1
- package/bin/config/ExecutionBinding.d.ts +1 -16
- package/bin/config/ExecutionBinding.d.ts.map +1 -1
- package/bin/config/ExecutionBinding.js +2 -22
- package/bin/config/ExecutionBinding.js.map +1 -1
- package/bin/config/Paths.d.ts +4 -43
- package/bin/config/Paths.d.ts.map +1 -1
- package/bin/config/Paths.js +10 -30
- package/bin/config/Paths.js.map +1 -1
- package/bin/config/PlatformPaths.d.ts +0 -4
- package/bin/config/PlatformPaths.d.ts.map +1 -1
- package/bin/config/PlatformPaths.js +5 -1
- package/bin/config/PlatformPaths.js.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js +0 -4
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js.map +1 -1
- package/bin/executor/composer/system/default/InitPrompts.d.ts +1 -1
- package/bin/executor/composer/system/default/InitPrompts.js +1 -1
- package/bin/executor/composer/system/default/SystemDomain.js +1 -1
- package/bin/executor/composer/system/default/assets/core.prompt.d.ts +1 -1
- package/bin/executor/composer/system/default/assets/core.prompt.js +1 -1
- package/bin/executor/composer/system/default/assets/init/PROFILE.md.d.ts +1 -1
- package/bin/executor/composer/system/default/assets/init/PROFILE.md.d.ts.map +1 -1
- package/bin/executor/composer/system/default/assets/init/PROFILE.md.js +1 -1
- package/bin/executor/composer/system/default/assets/init/PROFILE.md.js.map +1 -1
- package/bin/executor/composer/system/default/assets/plugin.prompt.d.ts +1 -1
- package/bin/executor/composer/system/default/assets/plugin.prompt.js +1 -1
- package/bin/executor/composer/system/default/assets/task.prompt.d.ts +1 -1
- package/bin/executor/composer/system/default/assets/task.prompt.js +1 -1
- package/bin/executor/messages/ChatMessageMarkupTypes.d.ts +1 -1
- package/bin/executor/messages/ChatMessageMarkupTypes.js +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts +1 -2
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts.map +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +17 -56
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
- package/bin/executor/tools/shell/ShellToolBridge.js +1 -1
- package/bin/executor/tools/shell/ShellToolBridge.js.map +1 -1
- package/bin/executor/tools/shell/ShellToolDefinition.d.ts +2 -2
- package/bin/executor/tools/shell/ShellToolFormatting.d.ts +1 -1
- package/bin/executor/tools/shell/ShellToolFormatting.js +9 -9
- package/bin/executor/tools/shell/ShellToolFormatting.js.map +1 -1
- package/bin/executor/tools/shell/ShellToolSchemas.d.ts +7 -75
- package/bin/executor/tools/shell/ShellToolSchemas.d.ts.map +1 -1
- package/bin/executor/types/SessionHistoryMeta.d.ts +5 -24
- package/bin/executor/types/SessionHistoryMeta.d.ts.map +1 -1
- package/bin/executor/types/SessionHistoryMeta.js +1 -1
- package/bin/executor/types/SessionRun.d.ts +1 -1
- package/bin/index.d.ts +5 -6
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +6 -5
- package/bin/index.js.map +1 -1
- package/bin/model/CityModelAdapter.d.ts +23 -0
- package/bin/model/CityModelAdapter.d.ts.map +1 -0
- package/bin/model/CityModelAdapter.js +338 -0
- package/bin/model/CityModelAdapter.js.map +1 -0
- package/bin/plugin/core/PluginCommandRequest.d.ts +1 -1
- package/bin/plugin/core/PluginCommandRequest.js +1 -1
- package/bin/plugin/core/PluginLocalExecution.d.ts.map +1 -1
- package/bin/plugin/core/PluginLocalExecution.js +4 -8
- package/bin/plugin/core/PluginLocalExecution.js.map +1 -1
- package/bin/plugin/types/PluginApi.d.ts +1 -1
- package/bin/rpc/Client.d.ts +104 -0
- package/bin/rpc/Client.d.ts.map +1 -0
- package/bin/rpc/Client.js +300 -0
- package/bin/rpc/Client.js.map +1 -0
- package/bin/rpc/Server.d.ts +41 -0
- package/bin/rpc/Server.d.ts.map +1 -0
- package/bin/rpc/Server.js +164 -0
- package/bin/rpc/Server.js.map +1 -0
- package/bin/runtime/host/daemon/Api.d.ts +1 -1
- package/bin/runtime/host/daemon/Client.d.ts +1 -1
- package/bin/runtime/host/daemon/Client.d.ts.map +1 -1
- package/bin/runtime/host/daemon/Client.js +30 -20
- package/bin/runtime/host/daemon/Client.js.map +1 -1
- package/bin/runtime/host/daemon/Paths.d.ts +1 -1
- package/bin/runtime/host/daemon/Paths.js +1 -1
- package/bin/runtime/host/daemon/ProjectSetup.js +2 -2
- package/bin/runtime/server/http/control/OverviewRoutes.js +1 -1
- package/bin/runtime/server/http/control/OverviewRoutes.js.map +1 -1
- package/bin/session/Session.d.ts +1 -0
- package/bin/session/Session.d.ts.map +1 -1
- package/bin/session/Session.js +32 -6
- package/bin/session/Session.js.map +1 -1
- package/bin/session/SessionTitle.d.ts +49 -0
- package/bin/session/SessionTitle.d.ts.map +1 -0
- package/bin/session/SessionTitle.js +130 -0
- package/bin/session/SessionTitle.js.map +1 -0
- package/bin/session/browse/Browse.d.ts +2 -1
- package/bin/session/browse/Browse.d.ts.map +1 -1
- package/bin/session/browse/Browse.js +18 -15
- package/bin/session/browse/Browse.js.map +1 -1
- package/bin/session/index.d.ts +3 -2
- package/bin/session/index.d.ts.map +1 -1
- package/bin/session/index.js +3 -2
- package/bin/session/index.js.map +1 -1
- package/bin/session/storage/Metadata.d.ts +4 -0
- package/bin/session/storage/Metadata.d.ts.map +1 -1
- package/bin/session/storage/Metadata.js +12 -25
- package/bin/session/storage/Metadata.js.map +1 -1
- package/bin/session/storage/Paths.d.ts +0 -4
- package/bin/session/storage/Paths.d.ts.map +1 -1
- package/bin/session/storage/Paths.js +0 -6
- package/bin/session/storage/Paths.js.map +1 -1
- package/bin/session/storage/Persistence.d.ts.map +1 -1
- package/bin/session/storage/Persistence.js +1 -4
- package/bin/session/storage/Persistence.js.map +1 -1
- package/bin/types/agent/AgentTypes.d.ts +32 -57
- package/bin/types/agent/AgentTypes.d.ts.map +1 -1
- package/bin/types/config/AgentProject.d.ts +7 -6
- package/bin/types/config/AgentProject.d.ts.map +1 -1
- package/bin/types/config/DowncityConfig.d.ts +11 -69
- package/bin/types/config/DowncityConfig.d.ts.map +1 -1
- package/bin/types/config/ExecutionBinding.d.ts +4 -4
- package/bin/types/config/ExecutionBinding.js +1 -1
- package/bin/types/config/LlmConfig.d.ts +1 -1
- package/bin/types/config/Start.d.ts +3 -0
- package/bin/types/config/Start.d.ts.map +1 -1
- package/bin/types/config/Start.js +2 -0
- package/bin/types/config/Start.js.map +1 -1
- package/bin/types/runtime/auth/AuthPermission.js +2 -2
- package/bin/types/runtime/auth/AuthPermission.js.map +1 -1
- package/bin/types/runtime/host/Store.d.ts +10 -227
- package/bin/types/runtime/host/Store.d.ts.map +1 -1
- package/bin/types/runtime/host/Store.js +7 -0
- package/bin/types/runtime/host/Store.js.map +1 -1
- package/bin/types/runtime/http/InlineInstant.d.ts +1 -1
- package/bin/types/runtime/platform/Platform.d.ts +7 -7
- package/bin/types/runtime/platform/Platform.d.ts.map +1 -1
- package/bin/types/runtime/platform/PlatformGateway.d.ts +2 -2
- package/bin/types/runtime/platform/PlatformGateway.d.ts.map +1 -1
- package/bin/utils/Time.d.ts +0 -1
- package/bin/utils/Time.d.ts.map +1 -1
- package/bin/utils/Time.js +0 -7
- package/bin/utils/Time.js.map +1 -1
- package/bin/utils/storage/index.d.ts +0 -1
- package/bin/utils/storage/index.d.ts.map +1 -1
- package/bin/utils/storage/index.js +0 -6
- package/bin/utils/storage/index.js.map +1 -1
- package/package.json +22 -23
- package/src/agent/Agent.ts +57 -73
- package/src/agent/RemoteAgent.ts +515 -345
- package/src/config/AgentInitializer.ts +15 -13
- package/src/config/Config.ts +28 -85
- package/src/config/Defaults.ts +1 -9
- package/src/config/DowncitySchema.ts +4 -114
- package/src/config/ExecutionBinding.ts +2 -24
- package/src/config/Paths.ts +10 -43
- package/src/config/PlatformPaths.ts +5 -1
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.ts +0 -4
- package/src/executor/composer/system/default/InitPrompts.ts +1 -1
- package/src/executor/composer/system/default/SystemDomain.ts +1 -1
- package/src/executor/composer/system/default/assets/core.prompt.ts +1 -1
- package/src/executor/composer/system/default/assets/core.prompt.ts.txt +1 -1
- package/src/executor/composer/system/default/assets/init/PROFILE.md.ts +1 -1
- package/src/executor/composer/system/default/assets/init/PROFILE.md.ts.txt +1 -2
- package/src/executor/composer/system/default/assets/plugin.prompt.ts +1 -1
- package/src/executor/composer/system/default/assets/plugin.prompt.ts.txt +18 -18
- package/src/executor/composer/system/default/assets/task.prompt.ts +1 -1
- package/src/executor/composer/system/default/assets/task.prompt.ts.txt +1 -1
- package/src/executor/messages/ChatMessageMarkupTypes.ts +1 -1
- package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +17 -57
- package/src/executor/tools/shell/ShellToolBridge.ts +1 -1
- package/src/executor/tools/shell/ShellToolFormatting.ts +9 -9
- package/src/executor/types/SessionHistoryMeta.ts +5 -25
- package/src/executor/types/SessionRun.ts +1 -1
- package/src/index.ts +12 -19
- package/src/model/CityModelAdapter.ts +384 -0
- package/src/plugin/core/PluginCommandRequest.ts +1 -1
- package/src/plugin/core/PluginLocalExecution.ts +4 -8
- package/src/plugin/types/PluginApi.ts +1 -1
- package/src/rpc/Client.ts +467 -0
- package/src/rpc/Server.ts +302 -0
- package/src/runtime/host/daemon/Api.ts +1 -1
- package/src/runtime/host/daemon/Client.ts +44 -22
- package/src/runtime/host/daemon/Paths.ts +1 -1
- package/src/runtime/host/daemon/ProjectSetup.ts +2 -2
- package/src/runtime/server/http/control/OverviewRoutes.ts +1 -1
- package/src/session/Session.ts +40 -6
- package/src/session/SessionTitle.ts +192 -0
- package/src/session/browse/Browse.ts +22 -13
- package/src/session/index.ts +5 -1
- package/src/session/storage/Metadata.ts +14 -29
- package/src/session/storage/Paths.ts +0 -10
- package/src/session/storage/Persistence.ts +1 -4
- package/src/types/agent/AgentTypes.ts +33 -62
- package/src/types/config/AgentProject.ts +7 -6
- package/src/types/config/DowncityConfig.ts +11 -70
- package/src/types/config/ExecutionBinding.ts +4 -4
- package/src/types/config/LlmConfig.ts +1 -1
- package/src/types/config/Start.ts +3 -0
- package/src/types/runtime/auth/AuthPermission.ts +2 -2
- package/src/types/runtime/host/Store.ts +10 -235
- package/src/types/runtime/http/InlineInstant.ts +1 -1
- package/src/types/runtime/platform/Platform.ts +7 -7
- package/src/types/runtime/platform/PlatformGateway.ts +2 -2
- package/src/utils/Time.ts +0 -6
- package/src/utils/storage/index.ts +0 -7
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/bin/config/ConfigEnvResolver.d.ts +0 -22
- package/bin/config/ConfigEnvResolver.d.ts.map +0 -1
- package/bin/config/ConfigEnvResolver.js +0 -41
- package/bin/config/ConfigEnvResolver.js.map +0 -1
- package/bin/runtime/server/rpc/Server.d.ts +0 -18
- package/bin/runtime/server/rpc/Server.d.ts.map +0 -1
- package/bin/runtime/server/rpc/Server.js +0 -315
- package/bin/runtime/server/rpc/Server.js.map +0 -1
- package/bin/runtime/transport/rpc/Client.d.ts +0 -13
- package/bin/runtime/transport/rpc/Client.d.ts.map +0 -1
- package/bin/runtime/transport/rpc/Client.js +0 -98
- package/bin/runtime/transport/rpc/Client.js.map +0 -1
- package/bin/runtime/transport/rpc/Paths.d.ts +0 -14
- package/bin/runtime/transport/rpc/Paths.d.ts.map +0 -1
- package/bin/runtime/transport/rpc/Paths.js +0 -42
- package/bin/runtime/transport/rpc/Paths.js.map +0 -1
- package/bin/runtime/transport/rpc/Transport.d.ts +0 -21
- package/bin/runtime/transport/rpc/Transport.d.ts.map +0 -1
- package/bin/runtime/transport/rpc/Transport.js +0 -30
- package/bin/runtime/transport/rpc/Transport.js.map +0 -1
- package/bin/types/common/ResolvedConfigValue.d.ts +0 -12
- package/bin/types/common/ResolvedConfigValue.d.ts.map +0 -1
- package/bin/types/common/ResolvedConfigValue.js +0 -2
- package/bin/types/common/ResolvedConfigValue.js.map +0 -1
- package/bin/types/runtime/rpc/LocalRpc.d.ts +0 -69
- package/bin/types/runtime/rpc/LocalRpc.d.ts.map +0 -1
- package/bin/types/runtime/rpc/LocalRpc.js +0 -9
- package/bin/types/runtime/rpc/LocalRpc.js.map +0 -1
- package/src/config/ConfigEnvResolver.ts +0 -52
- package/src/runtime/server/rpc/Server.ts +0 -408
- package/src/runtime/transport/rpc/Client.ts +0 -113
- package/src/runtime/transport/rpc/Paths.ts +0 -50
- package/src/runtime/transport/rpc/Transport.ts +0 -43
- package/src/types/common/ResolvedConfigValue.ts +0 -16
- package/src/types/runtime/rpc/LocalRpc.ts +0 -72
package/bin/agent/RemoteAgent.js
CHANGED
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* RemoteAgent
|
|
2
|
+
* RemoteAgent:统一远程 SDK 客户端。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* - `RemoteAgent`
|
|
5
|
+
* - 对外只暴露一个 `url` 入口,不向用户暴露 transport 细节。
|
|
6
|
+
* - 当前内部支持 `http/https` 与 `rpc` 两种访问方式。
|
|
7
|
+
* - `RemoteAgent` 只负责远程访问与 turn handle 合成,不重复实现第二套会话编排器。
|
|
8
8
|
*/
|
|
9
9
|
import { SessionEventHub } from "../session/runtime/SessionEventHub.js";
|
|
10
|
+
import { RpcClient, parse_rpc_url } from "../rpc/Client.js";
|
|
10
11
|
/**
|
|
11
12
|
* 远程 Session 客户端。
|
|
12
13
|
*/
|
|
13
14
|
class RemoteSession {
|
|
14
15
|
id;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
constructor(
|
|
24
|
-
this.
|
|
25
|
-
this.id =
|
|
16
|
+
transport;
|
|
17
|
+
event_hub = new SessionEventHub();
|
|
18
|
+
turns_by_id = new Map();
|
|
19
|
+
completed_turn_ids = [];
|
|
20
|
+
event_pump_connect_promise = null;
|
|
21
|
+
event_pump_running = false;
|
|
22
|
+
event_subscriber_count = 0;
|
|
23
|
+
event_subscription = null;
|
|
24
|
+
constructor(transport, session_id) {
|
|
25
|
+
this.transport = transport;
|
|
26
|
+
this.id = session_id;
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
28
29
|
* 远程 session 当前不支持直接注入本地模型实例。
|
|
@@ -34,12 +35,7 @@ class RemoteSession {
|
|
|
34
35
|
* 读取当前远程 session 详情。
|
|
35
36
|
*/
|
|
36
37
|
async getInfo() {
|
|
37
|
-
|
|
38
|
-
const payload = (await response.json());
|
|
39
|
-
if (!response.ok || !payload.success || !payload.session?.sessionId) {
|
|
40
|
-
throw new Error(String(payload.error || "Remote session info failed"));
|
|
41
|
-
}
|
|
42
|
-
return payload.session;
|
|
38
|
+
return await this.transport.get_info(this.id);
|
|
43
39
|
}
|
|
44
40
|
/**
|
|
45
41
|
* 向当前远程 session 追加一条新的 prompt。
|
|
@@ -49,207 +45,88 @@ class RemoteSession {
|
|
|
49
45
|
if (!query) {
|
|
50
46
|
throw new Error("remote session.prompt requires a non-empty query");
|
|
51
47
|
}
|
|
52
|
-
await this.
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"Content-Type": "application/json",
|
|
57
|
-
},
|
|
58
|
-
body: JSON.stringify({
|
|
59
|
-
query,
|
|
60
|
-
}),
|
|
61
|
-
});
|
|
62
|
-
const payload = (await response.json());
|
|
63
|
-
if (!response.ok || !payload.success || !payload.turn?.id) {
|
|
64
|
-
throw new Error(String(payload.error || "Remote session prompt failed"));
|
|
65
|
-
}
|
|
66
|
-
const lifecycle = this.ensureTurnLifecycle(payload.turn.id);
|
|
67
|
-
return createTurnHandle(lifecycle);
|
|
48
|
+
await this.ensure_event_pump();
|
|
49
|
+
const turn = await this.transport.prompt(this.id, input);
|
|
50
|
+
const lifecycle = this.ensure_turn_lifecycle(turn.id);
|
|
51
|
+
return create_turn_handle(lifecycle);
|
|
68
52
|
}
|
|
69
53
|
/**
|
|
70
54
|
* 订阅当前远程 session 的 future 事件。
|
|
71
55
|
*/
|
|
72
56
|
subscribe(subscriber) {
|
|
73
|
-
this.
|
|
74
|
-
void this.
|
|
75
|
-
this.
|
|
57
|
+
this.event_subscriber_count += 1;
|
|
58
|
+
void this.ensure_event_pump().catch((error) => {
|
|
59
|
+
this.event_hub.publish({
|
|
76
60
|
type: "error",
|
|
77
61
|
message: error instanceof Error ? error.message : String(error),
|
|
78
62
|
});
|
|
79
63
|
});
|
|
80
|
-
const unsubscribe = this.
|
|
64
|
+
const unsubscribe = this.event_hub.subscribe(subscriber);
|
|
81
65
|
return () => {
|
|
82
66
|
unsubscribe();
|
|
83
|
-
this.
|
|
84
|
-
this.
|
|
67
|
+
this.event_subscriber_count = Math.max(0, this.event_subscriber_count - 1);
|
|
68
|
+
void this.maybe_stop_event_pump();
|
|
85
69
|
};
|
|
86
70
|
}
|
|
87
71
|
/**
|
|
88
72
|
* 读取远程消息历史。
|
|
89
73
|
*/
|
|
90
74
|
async history(input) {
|
|
91
|
-
|
|
92
|
-
if (input?.limit !== undefined)
|
|
93
|
-
query.set("limit", String(input.limit));
|
|
94
|
-
if (input?.cursor)
|
|
95
|
-
query.set("cursor", input.cursor);
|
|
96
|
-
if (input?.order)
|
|
97
|
-
query.set("order", input.order);
|
|
98
|
-
if (input?.view)
|
|
99
|
-
query.set("view", input.view);
|
|
100
|
-
const response = await fetch(`${this.baseUrl}/api/sdk/sessions/${encodeURIComponent(this.id)}/history${query.size > 0 ? `?${query.toString()}` : ""}`);
|
|
101
|
-
const payload = (await response.json());
|
|
102
|
-
if (!response.ok ||
|
|
103
|
-
!payload.success ||
|
|
104
|
-
!payload.history ||
|
|
105
|
-
!Array.isArray(payload.history.items)) {
|
|
106
|
-
throw new Error(String(payload.error || "Remote session history failed"));
|
|
107
|
-
}
|
|
108
|
-
return payload.history;
|
|
75
|
+
return await this.transport.history(this.id, input);
|
|
109
76
|
}
|
|
110
77
|
/**
|
|
111
78
|
* 读取远程 session 当前生效的 system prompt 快照。
|
|
112
79
|
*/
|
|
113
80
|
async system() {
|
|
114
|
-
|
|
115
|
-
const payload = (await response.json());
|
|
116
|
-
if (!response.ok ||
|
|
117
|
-
!payload.success ||
|
|
118
|
-
!payload.system ||
|
|
119
|
-
!Array.isArray(payload.system.blocks)) {
|
|
120
|
-
throw new Error(String(payload.error || "Remote session system failed"));
|
|
121
|
-
}
|
|
122
|
-
return payload.system;
|
|
81
|
+
return await this.transport.system(this.id);
|
|
123
82
|
}
|
|
124
83
|
/**
|
|
125
84
|
* 分叉远程 session。
|
|
126
85
|
*/
|
|
127
86
|
async fork(input) {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
: String(input?.messageId || "").trim() || undefined;
|
|
131
|
-
const response = await fetch(`${this.baseUrl}/api/sdk/sessions/${encodeURIComponent(this.id)}/fork`, {
|
|
132
|
-
method: "POST",
|
|
133
|
-
headers: {
|
|
134
|
-
"Content-Type": "application/json",
|
|
135
|
-
},
|
|
136
|
-
body: JSON.stringify({
|
|
137
|
-
...(messageId ? { messageId } : {}),
|
|
138
|
-
}),
|
|
139
|
-
});
|
|
140
|
-
const payload = (await response.json());
|
|
141
|
-
if (!response.ok || !payload.success || !payload.session?.sessionId) {
|
|
142
|
-
throw new Error(String(payload.error || "Remote session fork failed"));
|
|
143
|
-
}
|
|
144
|
-
return new RemoteSession(this.baseUrl, payload.session.sessionId);
|
|
87
|
+
const info = await this.transport.fork(this.id, input);
|
|
88
|
+
return new RemoteSession(this.transport, info.sessionId);
|
|
145
89
|
}
|
|
146
|
-
async
|
|
147
|
-
if (this.
|
|
148
|
-
await this.
|
|
90
|
+
async ensure_event_pump() {
|
|
91
|
+
if (this.event_pump_connect_promise) {
|
|
92
|
+
await this.event_pump_connect_promise;
|
|
149
93
|
return;
|
|
150
94
|
}
|
|
151
|
-
if (this.
|
|
95
|
+
if (this.event_pump_running)
|
|
152
96
|
return;
|
|
153
|
-
this.
|
|
154
|
-
|
|
155
|
-
this.
|
|
156
|
-
|
|
157
|
-
|
|
97
|
+
this.event_pump_connect_promise = (async () => {
|
|
98
|
+
let resolved_ready = false;
|
|
99
|
+
this.event_subscription = await this.transport.subscribe({
|
|
100
|
+
session_id: this.id,
|
|
101
|
+
on_ready: () => {
|
|
102
|
+
resolved_ready = true;
|
|
103
|
+
},
|
|
104
|
+
on_event: (event) => {
|
|
105
|
+
this.handle_event(event);
|
|
106
|
+
},
|
|
158
107
|
});
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
throw new Error(
|
|
108
|
+
this.event_pump_running = true;
|
|
109
|
+
if (!resolved_ready) {
|
|
110
|
+
throw new Error("Remote session events connection closed before ready");
|
|
162
111
|
}
|
|
163
|
-
this.eventPumpRunning = true;
|
|
164
|
-
const ready = createEventConnectionReady();
|
|
165
|
-
void this.consumeEventConnection(response.body, abortController, ready)
|
|
166
|
-
.finally(() => {
|
|
167
|
-
const wasAborted = abortController.signal.aborted;
|
|
168
|
-
this.eventPumpRunning = false;
|
|
169
|
-
if (this.eventPumpAbortController === abortController) {
|
|
170
|
-
this.eventPumpAbortController = null;
|
|
171
|
-
}
|
|
172
|
-
if (!wasAborted) {
|
|
173
|
-
this.failPendingTurns("Remote session events connection closed");
|
|
174
|
-
this.eventHub.publish({
|
|
175
|
-
type: "error",
|
|
176
|
-
message: "Remote session events connection closed",
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
await ready.promise;
|
|
181
112
|
})();
|
|
182
113
|
try {
|
|
183
|
-
await this.
|
|
184
|
-
}
|
|
185
|
-
catch (error) {
|
|
186
|
-
this.eventPumpAbortController = null;
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
finally {
|
|
190
|
-
this.eventPumpConnectPromise = null;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
async consumeEventConnection(body, abortController, ready) {
|
|
194
|
-
const decoder = new TextDecoder();
|
|
195
|
-
const reader = body.getReader();
|
|
196
|
-
let buffered = "";
|
|
197
|
-
try {
|
|
198
|
-
while (true) {
|
|
199
|
-
const { done, value } = await reader.read();
|
|
200
|
-
if (done)
|
|
201
|
-
break;
|
|
202
|
-
buffered += decoder.decode(value, { stream: true });
|
|
203
|
-
let newlineIndex = buffered.indexOf("\n");
|
|
204
|
-
while (newlineIndex >= 0) {
|
|
205
|
-
const line = buffered.slice(0, newlineIndex).trim();
|
|
206
|
-
buffered = buffered.slice(newlineIndex + 1);
|
|
207
|
-
if (line) {
|
|
208
|
-
this.handleEventLine(JSON.parse(line), ready);
|
|
209
|
-
}
|
|
210
|
-
newlineIndex = buffered.indexOf("\n");
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
const tail = buffered.trim();
|
|
214
|
-
if (tail) {
|
|
215
|
-
this.handleEventLine(JSON.parse(tail), ready);
|
|
216
|
-
}
|
|
217
|
-
rejectEventConnectionReady(ready, "Remote session events connection closed before ready");
|
|
218
|
-
}
|
|
219
|
-
catch (error) {
|
|
220
|
-
if (!abortController.signal.aborted) {
|
|
221
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
222
|
-
rejectEventConnectionReady(ready, message);
|
|
223
|
-
this.failPendingTurns(message);
|
|
224
|
-
this.eventHub.publish({
|
|
225
|
-
type: "error",
|
|
226
|
-
message,
|
|
227
|
-
});
|
|
228
|
-
}
|
|
114
|
+
await this.event_pump_connect_promise;
|
|
229
115
|
}
|
|
230
116
|
finally {
|
|
231
|
-
|
|
232
|
-
reader.releaseLock();
|
|
233
|
-
}
|
|
234
|
-
catch {
|
|
235
|
-
// ignore
|
|
236
|
-
}
|
|
117
|
+
this.event_pump_connect_promise = null;
|
|
237
118
|
}
|
|
238
119
|
}
|
|
239
|
-
|
|
240
|
-
if (
|
|
241
|
-
|
|
242
|
-
return;
|
|
120
|
+
handle_event(event) {
|
|
121
|
+
if (event.type === "error") {
|
|
122
|
+
this.fail_pending_turns(event.message);
|
|
243
123
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const turnId = extractTurnId(event);
|
|
248
|
-
if (turnId) {
|
|
249
|
-
this.ensureTurnLifecycle(turnId);
|
|
124
|
+
const turn_id = extract_turn_id(event);
|
|
125
|
+
if (turn_id) {
|
|
126
|
+
this.ensure_turn_lifecycle(turn_id);
|
|
250
127
|
}
|
|
251
128
|
if (event.type === "turn-finish") {
|
|
252
|
-
const lifecycle = this.
|
|
129
|
+
const lifecycle = this.ensure_turn_lifecycle(event.turnId);
|
|
253
130
|
const result = {
|
|
254
131
|
turnId: event.turnId,
|
|
255
132
|
text: event.text,
|
|
@@ -257,26 +134,26 @@ class RemoteSession {
|
|
|
257
134
|
...(event.error ? { error: event.error } : {}),
|
|
258
135
|
};
|
|
259
136
|
lifecycle.result = result;
|
|
260
|
-
lifecycle.
|
|
261
|
-
this.
|
|
262
|
-
this.
|
|
137
|
+
lifecycle.deferred_finished.resolve(result);
|
|
138
|
+
this.remember_completed_turn(event.turnId);
|
|
139
|
+
void this.maybe_stop_event_pump();
|
|
263
140
|
}
|
|
264
|
-
this.
|
|
141
|
+
this.event_hub.publish(event);
|
|
265
142
|
}
|
|
266
|
-
|
|
267
|
-
const cached = this.
|
|
143
|
+
ensure_turn_lifecycle(turn_id) {
|
|
144
|
+
const cached = this.turns_by_id.get(turn_id);
|
|
268
145
|
if (cached)
|
|
269
146
|
return cached;
|
|
270
147
|
const created = {
|
|
271
|
-
turnId,
|
|
148
|
+
turnId: turn_id,
|
|
272
149
|
result: null,
|
|
273
|
-
|
|
150
|
+
deferred_finished: create_deferred(),
|
|
274
151
|
};
|
|
275
|
-
this.
|
|
152
|
+
this.turns_by_id.set(turn_id, created);
|
|
276
153
|
return created;
|
|
277
154
|
}
|
|
278
|
-
|
|
279
|
-
for (const lifecycle of this.
|
|
155
|
+
fail_pending_turns(message) {
|
|
156
|
+
for (const lifecycle of this.turns_by_id.values()) {
|
|
280
157
|
if (lifecycle.result)
|
|
281
158
|
continue;
|
|
282
159
|
const result = {
|
|
@@ -286,48 +163,78 @@ class RemoteSession {
|
|
|
286
163
|
error: message,
|
|
287
164
|
};
|
|
288
165
|
lifecycle.result = result;
|
|
289
|
-
lifecycle.
|
|
290
|
-
this.
|
|
166
|
+
lifecycle.deferred_finished.resolve(result);
|
|
167
|
+
this.remember_completed_turn(lifecycle.turnId);
|
|
291
168
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
this.
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
this.turnsById.delete(oldestTurnId);
|
|
169
|
+
}
|
|
170
|
+
remember_completed_turn(turn_id) {
|
|
171
|
+
this.completed_turn_ids.push(turn_id);
|
|
172
|
+
while (this.completed_turn_ids.length > 200) {
|
|
173
|
+
const oldest_turn_id = this.completed_turn_ids.shift();
|
|
174
|
+
if (oldest_turn_id) {
|
|
175
|
+
this.turns_by_id.delete(oldest_turn_id);
|
|
300
176
|
}
|
|
301
177
|
}
|
|
302
178
|
}
|
|
303
|
-
|
|
304
|
-
if (this.
|
|
179
|
+
async maybe_stop_event_pump() {
|
|
180
|
+
if (this.event_subscriber_count > 0)
|
|
305
181
|
return;
|
|
306
|
-
if ([...this.
|
|
182
|
+
if ([...this.turns_by_id.values()].some((item) => item.result === null))
|
|
307
183
|
return;
|
|
308
|
-
|
|
184
|
+
const current = this.event_subscription;
|
|
185
|
+
this.event_subscription = null;
|
|
186
|
+
this.event_pump_running = false;
|
|
187
|
+
if (!current)
|
|
309
188
|
return;
|
|
310
|
-
|
|
311
|
-
|
|
189
|
+
await current.close().catch((error) => {
|
|
190
|
+
this.fail_pending_turns(error instanceof Error ? error.message : String(error));
|
|
191
|
+
});
|
|
312
192
|
}
|
|
313
193
|
}
|
|
314
194
|
/**
|
|
315
195
|
* RemoteAgent:远程 Agent 客户端。
|
|
316
196
|
*/
|
|
317
197
|
export class RemoteAgent {
|
|
318
|
-
|
|
198
|
+
transport;
|
|
319
199
|
constructor(options) {
|
|
320
|
-
const
|
|
321
|
-
if (!
|
|
322
|
-
throw new Error("RemoteAgent requires a non-empty
|
|
200
|
+
const url = String(options.url || "").trim();
|
|
201
|
+
if (!url) {
|
|
202
|
+
throw new Error("RemoteAgent requires a non-empty url");
|
|
323
203
|
}
|
|
324
|
-
this.
|
|
204
|
+
this.transport = create_remote_agent_transport(url);
|
|
325
205
|
}
|
|
326
206
|
/**
|
|
327
207
|
* 新建一个远程 session。
|
|
328
208
|
*/
|
|
329
209
|
async createSession(input) {
|
|
330
|
-
const
|
|
210
|
+
const info = await this.transport.create_session(input);
|
|
211
|
+
return new RemoteSession(this.transport, info.sessionId);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* 获取一个已存在的远程 session。
|
|
215
|
+
*/
|
|
216
|
+
async getSession(sessionId) {
|
|
217
|
+
const resolved_session_id = String(sessionId || "").trim();
|
|
218
|
+
if (!resolved_session_id) {
|
|
219
|
+
throw new Error("getSession requires a non-empty sessionId");
|
|
220
|
+
}
|
|
221
|
+
const info = await this.transport.get_info(resolved_session_id);
|
|
222
|
+
return new RemoteSession(this.transport, info.sessionId);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* 列出远程 agent 的 session 摘要页。
|
|
226
|
+
*/
|
|
227
|
+
async listSessions(input) {
|
|
228
|
+
return await this.transport.list_sessions(input);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
class HttpRemoteAgentTransport {
|
|
232
|
+
base_url;
|
|
233
|
+
constructor(url) {
|
|
234
|
+
this.base_url = url.replace(/\/+$/, "");
|
|
235
|
+
}
|
|
236
|
+
async create_session(input) {
|
|
237
|
+
const payload = await read_http_json(`${this.base_url}/api/sdk/sessions`, {
|
|
331
238
|
method: "POST",
|
|
332
239
|
headers: {
|
|
333
240
|
"Content-Type": "application/json",
|
|
@@ -336,31 +243,110 @@ export class RemoteAgent {
|
|
|
336
243
|
...(input?.sessionId ? { sessionId: input.sessionId } : {}),
|
|
337
244
|
}),
|
|
338
245
|
});
|
|
339
|
-
|
|
340
|
-
if (!response.ok || !payload.success || !payload.session?.sessionId) {
|
|
246
|
+
if (!payload.success || !payload.session?.sessionId) {
|
|
341
247
|
throw new Error(String(payload.error || "Remote session create failed"));
|
|
342
248
|
}
|
|
343
|
-
return
|
|
249
|
+
return payload.session;
|
|
344
250
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
const resolvedSessionId = String(sessionId || "").trim();
|
|
350
|
-
if (!resolvedSessionId) {
|
|
351
|
-
throw new Error("getSession requires a non-empty sessionId");
|
|
251
|
+
async get_info(session_id) {
|
|
252
|
+
const payload = await read_http_json(`${this.base_url}/api/sdk/sessions/${encodeURIComponent(session_id)}`);
|
|
253
|
+
if (!payload.success || !payload.session?.sessionId) {
|
|
254
|
+
throw new Error(String(payload.error || "Remote session info failed"));
|
|
352
255
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
256
|
+
return payload.session;
|
|
257
|
+
}
|
|
258
|
+
async prompt(session_id, input) {
|
|
259
|
+
const payload = await read_http_json(`${this.base_url}/api/sdk/sessions/${encodeURIComponent(session_id)}/prompt`, {
|
|
260
|
+
method: "POST",
|
|
261
|
+
headers: {
|
|
262
|
+
"Content-Type": "application/json",
|
|
263
|
+
},
|
|
264
|
+
body: JSON.stringify({
|
|
265
|
+
query: input.query,
|
|
266
|
+
}),
|
|
267
|
+
});
|
|
268
|
+
const id = String(payload.turn?.id || "").trim();
|
|
269
|
+
if (!payload.success || !id) {
|
|
270
|
+
throw new Error(String(payload.error || "Remote session prompt failed"));
|
|
357
271
|
}
|
|
358
|
-
return
|
|
272
|
+
return { id };
|
|
359
273
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
274
|
+
async subscribe(params) {
|
|
275
|
+
const abort_controller = new AbortController();
|
|
276
|
+
let resolve_ready;
|
|
277
|
+
let reject_ready;
|
|
278
|
+
const ready_promise = new Promise((resolve, reject) => {
|
|
279
|
+
resolve_ready = resolve;
|
|
280
|
+
reject_ready = reject;
|
|
281
|
+
});
|
|
282
|
+
const response = await fetch(`${this.base_url}/api/sdk/sessions/${encodeURIComponent(params.session_id)}/events`, {
|
|
283
|
+
signal: abort_controller.signal,
|
|
284
|
+
});
|
|
285
|
+
if (!response.ok || !response.body) {
|
|
286
|
+
const text = await response.text().catch(() => "");
|
|
287
|
+
throw new Error(text || `Remote session events failed (${response.status})`);
|
|
288
|
+
}
|
|
289
|
+
void consume_http_event_stream({
|
|
290
|
+
body: response.body,
|
|
291
|
+
abort_controller,
|
|
292
|
+
on_ready: () => {
|
|
293
|
+
params.on_ready();
|
|
294
|
+
resolve_ready();
|
|
295
|
+
},
|
|
296
|
+
on_ready_error: (error) => {
|
|
297
|
+
reject_ready(error);
|
|
298
|
+
},
|
|
299
|
+
on_event: params.on_event,
|
|
300
|
+
});
|
|
301
|
+
await ready_promise;
|
|
302
|
+
return {
|
|
303
|
+
close: async () => {
|
|
304
|
+
abort_controller.abort();
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
async history(session_id, input) {
|
|
309
|
+
const query = new URLSearchParams();
|
|
310
|
+
if (input?.limit !== undefined)
|
|
311
|
+
query.set("limit", String(input.limit));
|
|
312
|
+
if (input?.cursor)
|
|
313
|
+
query.set("cursor", input.cursor);
|
|
314
|
+
if (input?.order)
|
|
315
|
+
query.set("order", input.order);
|
|
316
|
+
if (input?.view)
|
|
317
|
+
query.set("view", input.view);
|
|
318
|
+
const payload = await read_http_json(`${this.base_url}/api/sdk/sessions/${encodeURIComponent(session_id)}/history${query.size > 0 ? `?${query.toString()}` : ""}`);
|
|
319
|
+
if (!payload.success || !payload.history || !Array.isArray(payload.history.items)) {
|
|
320
|
+
throw new Error(String(payload.error || "Remote session history failed"));
|
|
321
|
+
}
|
|
322
|
+
return payload.history;
|
|
323
|
+
}
|
|
324
|
+
async system(session_id) {
|
|
325
|
+
const payload = await read_http_json(`${this.base_url}/api/sdk/sessions/${encodeURIComponent(session_id)}/system`);
|
|
326
|
+
if (!payload.success || !payload.system || !Array.isArray(payload.system.blocks)) {
|
|
327
|
+
throw new Error(String(payload.error || "Remote session system failed"));
|
|
328
|
+
}
|
|
329
|
+
return payload.system;
|
|
330
|
+
}
|
|
331
|
+
async fork(session_id, input) {
|
|
332
|
+
const message_id = typeof input === "string"
|
|
333
|
+
? String(input || "").trim() || undefined
|
|
334
|
+
: String(input?.messageId || "").trim() || undefined;
|
|
335
|
+
const payload = await read_http_json(`${this.base_url}/api/sdk/sessions/${encodeURIComponent(session_id)}/fork`, {
|
|
336
|
+
method: "POST",
|
|
337
|
+
headers: {
|
|
338
|
+
"Content-Type": "application/json",
|
|
339
|
+
},
|
|
340
|
+
body: JSON.stringify({
|
|
341
|
+
...(message_id ? { messageId: message_id } : {}),
|
|
342
|
+
}),
|
|
343
|
+
});
|
|
344
|
+
if (!payload.success || !payload.session?.sessionId) {
|
|
345
|
+
throw new Error(String(payload.error || "Remote session fork failed"));
|
|
346
|
+
}
|
|
347
|
+
return payload.session;
|
|
348
|
+
}
|
|
349
|
+
async list_sessions(input) {
|
|
364
350
|
const query = new URLSearchParams();
|
|
365
351
|
if (input?.limit !== undefined)
|
|
366
352
|
query.set("limit", String(input.limit));
|
|
@@ -368,66 +354,190 @@ export class RemoteAgent {
|
|
|
368
354
|
query.set("cursor", input.cursor);
|
|
369
355
|
if (input?.query)
|
|
370
356
|
query.set("query", input.query);
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
if (!response.ok || !payload.success || !payload.page) {
|
|
357
|
+
const payload = await read_http_json(`${this.base_url}/api/sdk/sessions${query.size > 0 ? `?${query.toString()}` : ""}`);
|
|
358
|
+
if (!payload.success || !payload.page) {
|
|
374
359
|
throw new Error(String(payload.error || "Remote sessions list failed"));
|
|
375
360
|
}
|
|
376
361
|
return payload.page;
|
|
377
362
|
}
|
|
378
363
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
364
|
+
class RpcRemoteAgentTransport {
|
|
365
|
+
client;
|
|
366
|
+
constructor(url) {
|
|
367
|
+
this.client = new RpcClient(parse_rpc_url(url));
|
|
368
|
+
}
|
|
369
|
+
async create_session(input) {
|
|
370
|
+
return await this.client.create_session(input);
|
|
371
|
+
}
|
|
372
|
+
async get_info(session_id) {
|
|
373
|
+
return await this.client.get_session(session_id);
|
|
374
|
+
}
|
|
375
|
+
async prompt(session_id, input) {
|
|
376
|
+
return await this.client.prompt_session({
|
|
377
|
+
session_id,
|
|
378
|
+
input,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
async subscribe(params) {
|
|
382
|
+
const subscription = await this.client.subscribe_session({
|
|
383
|
+
session_id: params.session_id,
|
|
384
|
+
on_ready: params.on_ready,
|
|
385
|
+
on_event: params.on_event,
|
|
386
|
+
});
|
|
387
|
+
return {
|
|
388
|
+
close: async () => {
|
|
389
|
+
await subscription.unsubscribe();
|
|
390
|
+
},
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
async history(session_id, input) {
|
|
394
|
+
return await this.client.get_session_history({
|
|
395
|
+
session_id,
|
|
396
|
+
input,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
async system(session_id) {
|
|
400
|
+
return await this.client.get_session_system(session_id);
|
|
401
|
+
}
|
|
402
|
+
async fork(session_id, input) {
|
|
403
|
+
const message_id = typeof input === "string"
|
|
404
|
+
? String(input || "").trim() || undefined
|
|
405
|
+
: String(input?.messageId || "").trim() || undefined;
|
|
406
|
+
return await this.client.fork_session({
|
|
407
|
+
session_id,
|
|
408
|
+
...(message_id ? { message_id } : {}),
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
async list_sessions(input) {
|
|
412
|
+
return await this.client.list_sessions(input);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function create_remote_agent_transport(url) {
|
|
416
|
+
if (/^https?:\/\//i.test(url)) {
|
|
417
|
+
return new HttpRemoteAgentTransport(url);
|
|
418
|
+
}
|
|
419
|
+
if (/^rpc:\/\//i.test(url)) {
|
|
420
|
+
return new RpcRemoteAgentTransport(url);
|
|
421
|
+
}
|
|
422
|
+
throw new Error(`Unsupported RemoteAgent url protocol: ${url}. Expected http://, https://, or rpc://`);
|
|
423
|
+
}
|
|
424
|
+
async function read_http_json(input, init) {
|
|
425
|
+
const response = await fetch(input, init);
|
|
426
|
+
const payload = (await response.json().catch(() => ({})));
|
|
427
|
+
if (!response.ok) {
|
|
428
|
+
const message = extract_error_message(payload);
|
|
429
|
+
throw new Error(message || `HTTP ${response.status}`);
|
|
430
|
+
}
|
|
431
|
+
return payload;
|
|
388
432
|
}
|
|
389
|
-
function
|
|
433
|
+
async function consume_http_event_stream(params) {
|
|
434
|
+
const decoder = new TextDecoder();
|
|
435
|
+
const reader = params.body.getReader();
|
|
436
|
+
let buffered = "";
|
|
437
|
+
let ready_resolved = false;
|
|
438
|
+
try {
|
|
439
|
+
while (true) {
|
|
440
|
+
const { done, value } = await reader.read();
|
|
441
|
+
if (done)
|
|
442
|
+
break;
|
|
443
|
+
buffered += decoder.decode(value, { stream: true });
|
|
444
|
+
let newline_index = buffered.indexOf("\n");
|
|
445
|
+
while (newline_index >= 0) {
|
|
446
|
+
const line = buffered.slice(0, newline_index).trim();
|
|
447
|
+
buffered = buffered.slice(newline_index + 1);
|
|
448
|
+
if (line) {
|
|
449
|
+
const value = JSON.parse(line);
|
|
450
|
+
if (is_sdk_events_ready_frame(value)) {
|
|
451
|
+
ready_resolved = true;
|
|
452
|
+
params.on_ready();
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
params.on_event(value);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
newline_index = buffered.indexOf("\n");
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
const tail = buffered.trim();
|
|
462
|
+
if (tail) {
|
|
463
|
+
const value = JSON.parse(tail);
|
|
464
|
+
if (is_sdk_events_ready_frame(value)) {
|
|
465
|
+
ready_resolved = true;
|
|
466
|
+
params.on_ready();
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
params.on_event(value);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (!params.abort_controller.signal.aborted) {
|
|
473
|
+
if (!ready_resolved) {
|
|
474
|
+
const error = new Error("Remote session events connection closed before ready");
|
|
475
|
+
params.on_ready_error(error);
|
|
476
|
+
throw error;
|
|
477
|
+
}
|
|
478
|
+
params.on_event({
|
|
479
|
+
type: "error",
|
|
480
|
+
message: "Remote session events connection closed",
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
catch (error) {
|
|
485
|
+
if (!params.abort_controller.signal.aborted) {
|
|
486
|
+
if (!ready_resolved) {
|
|
487
|
+
params.on_ready_error(error);
|
|
488
|
+
}
|
|
489
|
+
params.on_event({
|
|
490
|
+
type: "error",
|
|
491
|
+
message: error instanceof Error ? error.message : String(error),
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
finally {
|
|
496
|
+
try {
|
|
497
|
+
reader.releaseLock();
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
// ignore
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
function extract_error_message(payload) {
|
|
505
|
+
if (!payload || typeof payload !== "object")
|
|
506
|
+
return "";
|
|
507
|
+
if ("error" in payload && typeof payload.error === "string") {
|
|
508
|
+
return payload.error;
|
|
509
|
+
}
|
|
510
|
+
if ("message" in payload && typeof payload.message === "string") {
|
|
511
|
+
return payload.message;
|
|
512
|
+
}
|
|
513
|
+
return "";
|
|
514
|
+
}
|
|
515
|
+
function create_deferred() {
|
|
390
516
|
let resolve;
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
resolve = innerResolve;
|
|
394
|
-
reject = innerReject;
|
|
517
|
+
const promise = new Promise((inner_resolve) => {
|
|
518
|
+
resolve = inner_resolve;
|
|
395
519
|
});
|
|
396
520
|
return {
|
|
397
521
|
promise,
|
|
398
|
-
settled: false,
|
|
399
522
|
resolve,
|
|
400
|
-
reject,
|
|
401
523
|
};
|
|
402
524
|
}
|
|
403
|
-
function
|
|
404
|
-
if (ready.settled)
|
|
405
|
-
return;
|
|
406
|
-
ready.settled = true;
|
|
407
|
-
ready.resolve();
|
|
408
|
-
}
|
|
409
|
-
function rejectEventConnectionReady(ready, error) {
|
|
410
|
-
if (ready.settled)
|
|
411
|
-
return;
|
|
412
|
-
ready.settled = true;
|
|
413
|
-
ready.reject(error);
|
|
414
|
-
}
|
|
415
|
-
function isSdkEventsReadyFrame(value) {
|
|
525
|
+
function is_sdk_events_ready_frame(value) {
|
|
416
526
|
return (typeof value === "object" &&
|
|
417
527
|
value !== null &&
|
|
418
528
|
"type" in value &&
|
|
419
529
|
value.type === "sdk-events-ready");
|
|
420
530
|
}
|
|
421
|
-
function
|
|
531
|
+
function create_turn_handle(lifecycle) {
|
|
422
532
|
return {
|
|
423
533
|
id: lifecycle.turnId,
|
|
424
534
|
get result() {
|
|
425
535
|
return lifecycle.result;
|
|
426
536
|
},
|
|
427
|
-
finished: lifecycle.
|
|
537
|
+
finished: lifecycle.deferred_finished.promise,
|
|
428
538
|
};
|
|
429
539
|
}
|
|
430
|
-
function
|
|
540
|
+
function extract_turn_id(event) {
|
|
431
541
|
switch (event.type) {
|
|
432
542
|
case "turn-start":
|
|
433
543
|
case "text-delta":
|