@downcity/agent 1.1.22 → 1.1.25
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 +6 -5
- package/bin/core/AgentContextTypes.d.ts +21 -2
- package/bin/core/AgentContextTypes.d.ts.map +1 -1
- package/bin/index.d.ts +6 -3
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js.map +1 -1
- package/bin/runtime/server/http/Server.d.ts +1 -1
- package/bin/runtime/server/http/Server.d.ts.map +1 -1
- package/bin/runtime/server/http/Server.js +4 -0
- package/bin/runtime/server/http/Server.js.map +1 -1
- package/bin/runtime/server/http/control/ExecuteBySession.js +1 -1
- package/bin/runtime/server/http/control/ExecuteBySession.js.map +1 -1
- package/bin/runtime/server/http/control/SessionRoutes.d.ts.map +1 -1
- package/bin/runtime/server/http/control/SessionRoutes.js +0 -27
- package/bin/runtime/server/http/control/SessionRoutes.js.map +1 -1
- package/bin/runtime/server/http/execute/execute.js +1 -1
- package/bin/runtime/server/http/execute/execute.js.map +1 -1
- package/bin/runtime/server/http/sdk/Router.d.ts +14 -0
- package/bin/runtime/server/http/sdk/Router.d.ts.map +1 -0
- package/bin/runtime/server/http/sdk/Router.js +18 -0
- package/bin/runtime/server/http/sdk/Router.js.map +1 -0
- package/bin/runtime/server/http/sdk/SessionRoutes.d.ts +15 -0
- package/bin/runtime/server/http/sdk/SessionRoutes.d.ts.map +1 -0
- package/bin/runtime/server/http/sdk/SessionRoutes.js +190 -0
- package/bin/runtime/server/http/sdk/SessionRoutes.js.map +1 -0
- package/bin/sdk/AgentSdkTypes.d.ts +1 -124
- package/bin/sdk/AgentSdkTypes.d.ts.map +1 -1
- package/bin/sdk/RemoteAgent.d.ts +27 -8
- package/bin/sdk/RemoteAgent.d.ts.map +1 -1
- package/bin/sdk/RemoteAgent.js +266 -38
- package/bin/sdk/RemoteAgent.js.map +1 -1
- package/bin/sdk/Session.d.ts +31 -10
- package/bin/sdk/Session.d.ts.map +1 -1
- package/bin/sdk/Session.js +181 -73
- package/bin/sdk/Session.js.map +1 -1
- package/bin/sdk/SessionEventMapper.d.ts +32 -0
- package/bin/sdk/SessionEventMapper.d.ts.map +1 -0
- package/bin/sdk/{StreamEvents.js → SessionEventMapper.js} +43 -28
- package/bin/sdk/SessionEventMapper.js.map +1 -0
- package/bin/sdk/session/ServicePort.d.ts +51 -4
- package/bin/sdk/session/ServicePort.d.ts.map +1 -1
- package/bin/sdk/session/ServicePort.js +17 -10
- package/bin/sdk/session/ServicePort.js.map +1 -1
- package/bin/sdk/session/runtime/SessionEventHub.d.ts +24 -0
- package/bin/sdk/session/runtime/SessionEventHub.d.ts.map +1 -0
- package/bin/sdk/session/runtime/SessionEventHub.js +39 -0
- package/bin/sdk/session/runtime/SessionEventHub.js.map +1 -0
- package/bin/sdk/session/runtime/SessionPromptRuntime.d.ts +68 -0
- package/bin/sdk/session/runtime/SessionPromptRuntime.d.ts.map +1 -0
- package/bin/sdk/session/runtime/SessionPromptRuntime.js +170 -0
- package/bin/sdk/session/runtime/SessionPromptRuntime.js.map +1 -0
- package/bin/service/builtins/chat/runtime/ChatQueueWorker.js +1 -1
- package/bin/service/builtins/chat/runtime/ChatQueueWorker.js.map +1 -1
- package/bin/service/builtins/chat/runtime/ChatSession.d.ts +1 -1
- package/bin/service/builtins/chat/runtime/ChatSession.js +1 -1
- package/bin/service/builtins/contact/runtime/ChatRuntime.js +1 -1
- package/bin/service/builtins/contact/runtime/ChatRuntime.js.map +1 -1
- package/bin/types/sdk/AgentSessionEvent.d.ts +160 -0
- package/bin/types/sdk/AgentSessionEvent.d.ts.map +1 -0
- package/bin/types/sdk/AgentSessionEvent.js +9 -0
- package/bin/types/sdk/AgentSessionEvent.js.map +1 -0
- package/bin/types/sdk/AgentSessionPrompt.d.ts +21 -0
- package/bin/types/sdk/AgentSessionPrompt.d.ts.map +1 -0
- package/bin/types/sdk/AgentSessionPrompt.js +9 -0
- package/bin/types/sdk/AgentSessionPrompt.js.map +1 -0
- package/bin/types/sdk/AgentSessionTurn.d.ts +59 -0
- package/bin/types/sdk/AgentSessionTurn.d.ts.map +1 -0
- package/bin/types/sdk/AgentSessionTurn.js +10 -0
- package/bin/types/sdk/AgentSessionTurn.js.map +1 -0
- package/bin/types/sdk/InternalUiChunkEvent.d.ts +100 -0
- package/bin/types/sdk/InternalUiChunkEvent.d.ts.map +1 -0
- package/bin/types/sdk/InternalUiChunkEvent.js +9 -0
- package/bin/types/sdk/InternalUiChunkEvent.js.map +1 -0
- package/package.json +2 -1
- package/scripts/session-prompt-runtime.test.mjs +167 -0
- package/src/core/AgentContextTypes.ts +24 -2
- package/src/index.ts +11 -8
- package/src/runtime/server/http/Server.ts +5 -1
- package/src/runtime/server/http/control/ExecuteBySession.ts +1 -1
- package/src/runtime/server/http/control/SessionRoutes.ts +0 -27
- package/src/runtime/server/http/execute/execute.ts +1 -1
- package/src/runtime/server/http/sdk/Router.ts +22 -0
- package/src/runtime/server/http/sdk/SessionRoutes.ts +232 -0
- package/src/sdk/AgentSdkTypes.ts +1 -137
- package/src/sdk/RemoteAgent.ts +368 -49
- package/src/sdk/Session.ts +235 -86
- package/src/sdk/{StreamEvents.ts → SessionEventMapper.ts} +50 -40
- package/src/sdk/session/ServicePort.ts +74 -12
- package/src/sdk/session/runtime/SessionEventHub.ts +47 -0
- package/src/sdk/session/runtime/SessionPromptRuntime.ts +269 -0
- package/src/service/builtins/chat/runtime/ChatQueueWorker.ts +1 -1
- package/src/service/builtins/chat/runtime/ChatSession.ts +1 -1
- package/src/service/builtins/contact/runtime/ChatRuntime.ts +1 -1
- package/src/session/README.md +8 -7
- package/src/types/sdk/AgentSessionEvent.ts +195 -0
- package/src/types/sdk/AgentSessionPrompt.ts +21 -0
- package/src/types/sdk/AgentSessionTurn.ts +65 -0
- package/src/types/sdk/InternalUiChunkEvent.ts +108 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/bin/runtime/server/http/control/StreamBySession.d.ts +0 -22
- package/bin/runtime/server/http/control/StreamBySession.d.ts.map +0 -1
- package/bin/runtime/server/http/control/StreamBySession.js +0 -135
- package/bin/runtime/server/http/control/StreamBySession.js.map +0 -1
- package/bin/sdk/AsyncQueue.d.ts +0 -26
- package/bin/sdk/AsyncQueue.d.ts.map +0 -1
- package/bin/sdk/AsyncQueue.js +0 -75
- package/bin/sdk/AsyncQueue.js.map +0 -1
- package/bin/sdk/StreamEvents.d.ts +0 -36
- package/bin/sdk/StreamEvents.d.ts.map +0 -1
- package/bin/sdk/StreamEvents.js.map +0 -1
- package/src/runtime/server/http/control/StreamBySession.ts +0 -198
- package/src/sdk/AsyncQueue.ts +0 -92
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentSessionEvent.js","sourceRoot":"","sources":["../../../src/types/sdk/AgentSessionEvent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Session prompt 输入类型定义。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - `prompt()` 是 Session actor 模型下唯一的输入入口。
|
|
6
|
+
* - 首条输入、运行中补充输入、排队到下一轮的输入,调用侧都使用同一结构。
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Session prompt 输入。
|
|
10
|
+
*/
|
|
11
|
+
export interface AgentSessionPromptInput {
|
|
12
|
+
/**
|
|
13
|
+
* 当前这次要追加到 Session 的用户文本。
|
|
14
|
+
*
|
|
15
|
+
* 说明(中文)
|
|
16
|
+
* - 调用侧永远只传“新的用户输入”。
|
|
17
|
+
* - 它是否并入当前 turn,还是排到下一 turn,由 Session 内部决定。
|
|
18
|
+
*/
|
|
19
|
+
query: string;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=AgentSessionPrompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentSessionPrompt.d.ts","sourceRoot":"","sources":["../../../src/types/sdk/AgentSessionPrompt.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,CAAC;CACf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentSessionPrompt.js","sourceRoot":"","sources":["../../../src/types/sdk/AgentSessionPrompt.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Session turn 句柄与结果类型定义。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - `session.prompt()` 返回的是“已绑定到某个 turn”的句柄,而不是一次性文本结果。
|
|
6
|
+
* - 同一个 turn 可以吸收多条 prompt,因此多个 prompt 可能返回相同 `id` 的 turn handle。
|
|
7
|
+
* - 增量过程继续通过 `session.subscribe()` 观察;turn handle 只负责等待最终完成结果。
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* 单个 Session turn 的最终结果。
|
|
11
|
+
*/
|
|
12
|
+
export interface AgentSessionTurnResult {
|
|
13
|
+
/**
|
|
14
|
+
* 当前已完成 turn 的稳定标识。
|
|
15
|
+
*/
|
|
16
|
+
turnId: string;
|
|
17
|
+
/**
|
|
18
|
+
* 当前 turn 最终可见文本。
|
|
19
|
+
*/
|
|
20
|
+
text: string;
|
|
21
|
+
/**
|
|
22
|
+
* 当前 turn 是否成功结束。
|
|
23
|
+
*/
|
|
24
|
+
success: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* 当前 turn 失败时的错误文本。
|
|
27
|
+
*/
|
|
28
|
+
error?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 单个 Session turn 的等待句柄。
|
|
32
|
+
*/
|
|
33
|
+
export interface AgentSessionTurnHandle {
|
|
34
|
+
/**
|
|
35
|
+
* 当前句柄绑定到的 turnId。
|
|
36
|
+
*
|
|
37
|
+
* 说明(中文)
|
|
38
|
+
* - `prompt()` 只有在确定当前输入被并入哪个 turn 后才会返回。
|
|
39
|
+
* - 因此这里总是最终可用的 turnId,而不是临时 receipt id。
|
|
40
|
+
*/
|
|
41
|
+
id: string;
|
|
42
|
+
/**
|
|
43
|
+
* 当前 turn 已完成后的最终结果快照。
|
|
44
|
+
*
|
|
45
|
+
* 说明(中文)
|
|
46
|
+
* - 在 `finished` 兑现之前这里为 `null`。
|
|
47
|
+
* - 兑现之后会变成与 `finished` 相同的最终结果对象。
|
|
48
|
+
*/
|
|
49
|
+
result: AgentSessionTurnResult | null;
|
|
50
|
+
/**
|
|
51
|
+
* 等待当前 turn 完成的 Promise。
|
|
52
|
+
*
|
|
53
|
+
* 关键点(中文)
|
|
54
|
+
* - 这里无论 turn 成功还是失败都会 resolve。
|
|
55
|
+
* - 调用方应读取返回结果中的 `success` / `error` 判断最终状态。
|
|
56
|
+
*/
|
|
57
|
+
finished: Promise<AgentSessionTurnResult>;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=AgentSessionTurn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentSessionTurn.d.ts","sourceRoot":"","sources":["../../../src/types/sdk/AgentSessionTurn.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;OAMG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;;;OAMG;IACH,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAEtC;;;;;;OAMG;IACH,QAAQ,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC3C"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Session turn 句柄与结果类型定义。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - `session.prompt()` 返回的是“已绑定到某个 turn”的句柄,而不是一次性文本结果。
|
|
6
|
+
* - 同一个 turn 可以吸收多条 prompt,因此多个 prompt 可能返回相同 `id` 的 turn handle。
|
|
7
|
+
* - 增量过程继续通过 `session.subscribe()` 观察;turn handle 只负责等待最终完成结果。
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=AgentSessionTurn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentSessionTurn.js","sourceRoot":"","sources":["../../../src/types/sdk/AgentSessionTurn.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK 内部 UI chunk 事件类型定义。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - 这是 Session 事件映射器的内部中间态,不从包根入口导出。
|
|
6
|
+
* - 它只负责承接底层 AI SDK `UIMessageChunk`,再转成 `AgentSessionEvent`。
|
|
7
|
+
*/
|
|
8
|
+
import type { JsonValue } from "../../types/common/Json.js";
|
|
9
|
+
/**
|
|
10
|
+
* SDK 内部 UI chunk 事件。
|
|
11
|
+
*/
|
|
12
|
+
export type InternalUiChunkEvent = {
|
|
13
|
+
/**
|
|
14
|
+
* 文本增量事件。
|
|
15
|
+
*/
|
|
16
|
+
type: "text-delta";
|
|
17
|
+
/**
|
|
18
|
+
* 当前追加的文本片段。
|
|
19
|
+
*/
|
|
20
|
+
text: string;
|
|
21
|
+
} | {
|
|
22
|
+
/**
|
|
23
|
+
* reasoning 增量事件。
|
|
24
|
+
*/
|
|
25
|
+
type: "reasoning-delta";
|
|
26
|
+
/**
|
|
27
|
+
* 当前追加的 reasoning 文本片段。
|
|
28
|
+
*/
|
|
29
|
+
text: string;
|
|
30
|
+
} | {
|
|
31
|
+
/**
|
|
32
|
+
* 工具调用可用事件。
|
|
33
|
+
*/
|
|
34
|
+
type: "tool-call";
|
|
35
|
+
/**
|
|
36
|
+
* 当前工具调用唯一标识。
|
|
37
|
+
*/
|
|
38
|
+
toolCallId: string;
|
|
39
|
+
/**
|
|
40
|
+
* 工具名称。
|
|
41
|
+
*/
|
|
42
|
+
toolName: string;
|
|
43
|
+
/**
|
|
44
|
+
* 工具输入参数。
|
|
45
|
+
*/
|
|
46
|
+
args: JsonValue;
|
|
47
|
+
} | {
|
|
48
|
+
/**
|
|
49
|
+
* 工具调用结果事件。
|
|
50
|
+
*/
|
|
51
|
+
type: "tool-result";
|
|
52
|
+
/**
|
|
53
|
+
* 当前工具调用唯一标识。
|
|
54
|
+
*/
|
|
55
|
+
toolCallId: string;
|
|
56
|
+
/**
|
|
57
|
+
* 工具名称。
|
|
58
|
+
*/
|
|
59
|
+
toolName: string;
|
|
60
|
+
/**
|
|
61
|
+
* 工具输出结果。
|
|
62
|
+
*/
|
|
63
|
+
result: JsonValue;
|
|
64
|
+
} | {
|
|
65
|
+
/**
|
|
66
|
+
* 工具调用失败事件。
|
|
67
|
+
*/
|
|
68
|
+
type: "tool-error";
|
|
69
|
+
/**
|
|
70
|
+
* 当前工具调用唯一标识。
|
|
71
|
+
*/
|
|
72
|
+
toolCallId: string;
|
|
73
|
+
/**
|
|
74
|
+
* 工具名称。
|
|
75
|
+
*/
|
|
76
|
+
toolName: string;
|
|
77
|
+
/**
|
|
78
|
+
* 错误文本。
|
|
79
|
+
*/
|
|
80
|
+
error: string;
|
|
81
|
+
} | {
|
|
82
|
+
/**
|
|
83
|
+
* 运行结束事件。
|
|
84
|
+
*/
|
|
85
|
+
type: "finish";
|
|
86
|
+
/**
|
|
87
|
+
* 最终完成原因(若底层可提供)。
|
|
88
|
+
*/
|
|
89
|
+
finishReason?: string;
|
|
90
|
+
} | {
|
|
91
|
+
/**
|
|
92
|
+
* 运行错误事件。
|
|
93
|
+
*/
|
|
94
|
+
type: "error";
|
|
95
|
+
/**
|
|
96
|
+
* 错误文本。
|
|
97
|
+
*/
|
|
98
|
+
error: string;
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=InternalUiChunkEvent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InternalUiChunkEvent.d.ts","sourceRoot":"","sources":["../../../src/types/sdk/InternalUiChunkEvent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IACE;;OAEG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE;;OAEG;IACH,IAAI,EAAE,iBAAiB,CAAC;IACxB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE;;OAEG;IACH,IAAI,EAAE,WAAW,CAAC;IAClB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,IAAI,EAAE,SAAS,CAAC;CACjB,GACD;IACE;;OAEG;IACH,IAAI,EAAE,aAAa,CAAC;IACpB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,EAAE,SAAS,CAAC;CACnB,GACD;IACE;;OAEG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACf,GACD;IACE;;OAEG;IACH,IAAI,EAAE,QAAQ,CAAC;IACf;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GACD;IACE;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IACd;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InternalUiChunkEvent.js","sourceRoot":"","sources":["../../../src/types/sdk/InternalUiChunkEvent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@downcity/agent",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Downcity Agent 运行时 — 执行壳,通过 RPC/HTTP 调用 City 的能力",
|
|
6
6
|
"main": "./bin/index.js",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "node scripts/agent-compiler.mjs build",
|
|
47
47
|
"dev": "node scripts/agent-compiler.mjs dev",
|
|
48
|
+
"test:session-runtime": "pnpm build && node --test scripts/session-prompt-runtime.test.mjs",
|
|
48
49
|
"typecheck": "node scripts/agent-compiler.mjs typecheck"
|
|
49
50
|
}
|
|
50
51
|
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 验证 SessionPromptRuntime 的 actor 队列语义。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - 测试编译后的 bin 输出,避免把测试文件混入 package 源码导出面。
|
|
6
|
+
* - 重点锁住 prompt merge 与排队到下一 turn 的行为,防止后续重构破坏交互模型。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import test from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
|
|
12
|
+
import { SessionPromptRuntime } from "../bin/sdk/session/runtime/SessionPromptRuntime.js";
|
|
13
|
+
|
|
14
|
+
function createDeferred() {
|
|
15
|
+
let resolve;
|
|
16
|
+
const promise = new Promise((innerResolve) => {
|
|
17
|
+
resolve = innerResolve;
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
promise,
|
|
21
|
+
resolve,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createUserMessage(query, index) {
|
|
26
|
+
return {
|
|
27
|
+
id: `u:test:${String(index)}`,
|
|
28
|
+
role: "user",
|
|
29
|
+
metadata: {
|
|
30
|
+
v: 1,
|
|
31
|
+
ts: Date.now(),
|
|
32
|
+
sessionId: "test",
|
|
33
|
+
source: "sdk",
|
|
34
|
+
kind: "normal",
|
|
35
|
+
},
|
|
36
|
+
parts: [{ type: "text", text: query }],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function waitUntil(readValue) {
|
|
41
|
+
for (let index = 0; index < 20; index += 1) {
|
|
42
|
+
const value = readValue();
|
|
43
|
+
if (value) return value;
|
|
44
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
45
|
+
}
|
|
46
|
+
throw new Error("Timed out while waiting for test condition");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function isSettled(promise) {
|
|
50
|
+
const marker = {};
|
|
51
|
+
const result = await Promise.race([
|
|
52
|
+
promise.then(
|
|
53
|
+
() => true,
|
|
54
|
+
() => true,
|
|
55
|
+
),
|
|
56
|
+
new Promise((resolve) => setTimeout(() => resolve(marker), 0)),
|
|
57
|
+
]);
|
|
58
|
+
return result !== marker;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
test("SessionPromptRuntime merges queued prompts at the next step boundary", async () => {
|
|
62
|
+
const events = [];
|
|
63
|
+
const persisted = [];
|
|
64
|
+
const executionFinished = createDeferred();
|
|
65
|
+
let stepMerge = null;
|
|
66
|
+
|
|
67
|
+
const runtime = new SessionPromptRuntime({
|
|
68
|
+
sessionId: "test",
|
|
69
|
+
publish: (event) => {
|
|
70
|
+
events.push(event);
|
|
71
|
+
},
|
|
72
|
+
createAndPersistUserMessage: async (query) => {
|
|
73
|
+
const message = createUserMessage(query, persisted.length + 1);
|
|
74
|
+
persisted.push(message);
|
|
75
|
+
return message;
|
|
76
|
+
},
|
|
77
|
+
executeTurn: async (input) => {
|
|
78
|
+
stepMerge = input.onStepMerge;
|
|
79
|
+
await executionFinished.promise;
|
|
80
|
+
return {
|
|
81
|
+
text: "done",
|
|
82
|
+
success: true,
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const firstTurn = await runtime.prompt("first");
|
|
88
|
+
const secondTurnPromise = runtime.prompt("second");
|
|
89
|
+
const merge = await waitUntil(() => stepMerge);
|
|
90
|
+
|
|
91
|
+
assert.equal(await isSettled(secondTurnPromise), false);
|
|
92
|
+
|
|
93
|
+
const mergedMessages = await merge();
|
|
94
|
+
const secondTurn = await secondTurnPromise;
|
|
95
|
+
|
|
96
|
+
assert.equal(secondTurn.id, firstTurn.id);
|
|
97
|
+
assert.deepEqual(
|
|
98
|
+
mergedMessages.map((message) => message.parts[0]?.text),
|
|
99
|
+
["second"],
|
|
100
|
+
);
|
|
101
|
+
assert.deepEqual(
|
|
102
|
+
persisted.map((message) => message.parts[0]?.text),
|
|
103
|
+
["first", "second"],
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
executionFinished.resolve();
|
|
107
|
+
const result = await firstTurn.finished;
|
|
108
|
+
|
|
109
|
+
assert.equal(result.success, true);
|
|
110
|
+
assert.equal(result.text, "done");
|
|
111
|
+
assert.equal(secondTurn.result, result);
|
|
112
|
+
assert.deepEqual(
|
|
113
|
+
events.map((event) => event.type),
|
|
114
|
+
["turn-start", "turn-finish"],
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("SessionPromptRuntime moves unmerged prompts into the next turn", async () => {
|
|
119
|
+
const events = [];
|
|
120
|
+
const finishQueue = [];
|
|
121
|
+
|
|
122
|
+
const runtime = new SessionPromptRuntime({
|
|
123
|
+
sessionId: "test",
|
|
124
|
+
publish: (event) => {
|
|
125
|
+
events.push(event);
|
|
126
|
+
},
|
|
127
|
+
createAndPersistUserMessage: async (query) => {
|
|
128
|
+
return createUserMessage(query, events.length + 1);
|
|
129
|
+
},
|
|
130
|
+
executeTurn: async (input) => {
|
|
131
|
+
const deferred = createDeferred();
|
|
132
|
+
finishQueue.push({
|
|
133
|
+
query: input.query,
|
|
134
|
+
deferred,
|
|
135
|
+
});
|
|
136
|
+
await deferred.promise;
|
|
137
|
+
return {
|
|
138
|
+
text: `done:${input.query}`,
|
|
139
|
+
success: true,
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const firstTurn = await runtime.prompt("first");
|
|
145
|
+
const secondTurnPromise = runtime.prompt("second");
|
|
146
|
+
const firstExecution = await waitUntil(() => finishQueue[0]);
|
|
147
|
+
|
|
148
|
+
assert.equal(await isSettled(secondTurnPromise), false);
|
|
149
|
+
|
|
150
|
+
firstExecution.deferred.resolve();
|
|
151
|
+
const firstResult = await firstTurn.finished;
|
|
152
|
+
const secondTurn = await secondTurnPromise;
|
|
153
|
+
const secondExecution = await waitUntil(() => finishQueue[1]);
|
|
154
|
+
|
|
155
|
+
assert.notEqual(secondTurn.id, firstTurn.id);
|
|
156
|
+
assert.equal(firstResult.text, "done:first");
|
|
157
|
+
assert.equal(secondExecution.query, "second");
|
|
158
|
+
|
|
159
|
+
secondExecution.deferred.resolve();
|
|
160
|
+
const secondResult = await secondTurn.finished;
|
|
161
|
+
|
|
162
|
+
assert.equal(secondResult.text, "done:second");
|
|
163
|
+
assert.deepEqual(
|
|
164
|
+
events.map((event) => event.type),
|
|
165
|
+
["turn-start", "turn-finish", "turn-start", "turn-finish"],
|
|
166
|
+
);
|
|
167
|
+
});
|
|
@@ -34,6 +34,12 @@ import type {
|
|
|
34
34
|
SessionRunResult,
|
|
35
35
|
} from "@/session/types/SessionRun.js";
|
|
36
36
|
import type { SessionHistoryStore } from "@/session/store/history/SessionHistoryStore.js";
|
|
37
|
+
import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
|
|
38
|
+
import type {
|
|
39
|
+
AgentSessionSubscriber,
|
|
40
|
+
AgentSessionUnsubscribe,
|
|
41
|
+
} from "@/types/sdk/AgentSessionEvent.js";
|
|
42
|
+
import type { AgentSessionTurnHandle } from "@/types/sdk/AgentSessionTurn.js";
|
|
37
43
|
|
|
38
44
|
/**
|
|
39
45
|
* 跨 service 调用参数。
|
|
@@ -116,9 +122,9 @@ export interface SessionPort {
|
|
|
116
122
|
*/
|
|
117
123
|
getHistoryStore(): SessionHistoryStore;
|
|
118
124
|
/**
|
|
119
|
-
* 执行当前 session
|
|
125
|
+
* 执行当前 session 的一次内部请求。
|
|
120
126
|
*/
|
|
121
|
-
|
|
127
|
+
execute(params: {
|
|
122
128
|
/**
|
|
123
129
|
* 本轮输入文本。
|
|
124
130
|
*/
|
|
@@ -132,6 +138,22 @@ export interface SessionPort {
|
|
|
132
138
|
*/
|
|
133
139
|
onAssistantStepCallback?: SessionAssistantStepCallback;
|
|
134
140
|
}): Promise<SessionRunResult>;
|
|
141
|
+
/**
|
|
142
|
+
* 向当前 session actor 追加一条新的 prompt。
|
|
143
|
+
*
|
|
144
|
+
* 关键点(中文)
|
|
145
|
+
* - 这是面向 SDK / transport 的统一交互输入入口。
|
|
146
|
+
* - 返回值只有在当前输入被绑定到某个 turn 后才会兑现。
|
|
147
|
+
*/
|
|
148
|
+
prompt(input: AgentSessionPromptInput): Promise<AgentSessionTurnHandle>;
|
|
149
|
+
/**
|
|
150
|
+
* 订阅当前 session 后续产生的 future 事件。
|
|
151
|
+
*
|
|
152
|
+
* 关键点(中文)
|
|
153
|
+
* - 只广播订阅之后产生的事件。
|
|
154
|
+
* - 历史消息仍通过 `getHistoryStore()` / SDK `history()` 读取。
|
|
155
|
+
*/
|
|
156
|
+
subscribe(subscriber: AgentSessionSubscriber): AgentSessionUnsubscribe;
|
|
135
157
|
/**
|
|
136
158
|
* 清理当前 session 的 executor 缓存。
|
|
137
159
|
*/
|
package/src/index.ts
CHANGED
|
@@ -24,22 +24,25 @@ export type {
|
|
|
24
24
|
AgentSessionConfigSnapshot,
|
|
25
25
|
AgentSessionForkInput,
|
|
26
26
|
AgentSessionMetadata,
|
|
27
|
-
AgentSessionRunInput,
|
|
28
|
-
AgentSessionRunResult,
|
|
29
27
|
AgentSessionSetInput,
|
|
30
|
-
AgentSessionStreamEvent,
|
|
31
28
|
AgentSessionSystemBlock,
|
|
32
29
|
AgentSessionSystemBlockSource,
|
|
33
30
|
AgentSessionSystemSessionInfo,
|
|
34
31
|
AgentSessionSystemSnapshot,
|
|
35
32
|
} from "./sdk/AgentSdkTypes.js";
|
|
36
33
|
export type {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
AgentSessionEvent,
|
|
35
|
+
AgentSessionSubscriber,
|
|
36
|
+
AgentSessionUnsubscribe,
|
|
37
|
+
} from "./types/sdk/AgentSessionEvent.js";
|
|
38
|
+
export type { AgentSessionPromptInput } from "./types/sdk/AgentSessionPrompt.js";
|
|
40
39
|
export type {
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
AgentSessionTurnHandle,
|
|
41
|
+
AgentSessionTurnResult,
|
|
42
|
+
} from "./types/sdk/AgentSessionTurn.js";
|
|
43
|
+
export type { AgentRuntime, AgentRuntimeBase } from "./core/AgentCoreTypes.js";
|
|
44
|
+
export type {
|
|
45
|
+
AgentContext,
|
|
43
46
|
ChatRuntimePort,
|
|
44
47
|
InvokeServicePort,
|
|
45
48
|
SessionCollectionPort,
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import { createPluginsRouter } from "@/runtime/server/http/plugins/plugins.js";
|
|
23
23
|
import { createStaticRouter } from "@/runtime/server/http/static/static.js";
|
|
24
24
|
import { createControlRouter } from "@/runtime/server/http/control/ControlRouter.js";
|
|
25
|
+
import { createSdkRouter } from "@/runtime/server/http/sdk/Router.js";
|
|
25
26
|
import {
|
|
26
27
|
registerBuiltinPluginHttpRoutes,
|
|
27
28
|
} from "@/plugin/core/HttpRoutes.js";
|
|
@@ -38,7 +39,7 @@ export interface ServerStartOptions {
|
|
|
38
39
|
/** HTTP 服务监听主机。 */
|
|
39
40
|
host: string;
|
|
40
41
|
/** 可选实例级 agent core。 */
|
|
41
|
-
core?: Pick<AgentCore, "getContext" | "getRuntime">;
|
|
42
|
+
core?: Pick<AgentCore, "getContext" | "getRuntime" | "session" | "sessions">;
|
|
42
43
|
/** 可选实例级 runtime 读取函数。 */
|
|
43
44
|
getAgentRuntime?: () => AgentRuntime;
|
|
44
45
|
/** 可选实例级 context 读取函数。 */
|
|
@@ -122,6 +123,9 @@ export function createServerApp(
|
|
|
122
123
|
getAgentRuntime: bindings.getAgentRuntime,
|
|
123
124
|
getAgentContext: bindings.getAgentContext,
|
|
124
125
|
}));
|
|
126
|
+
if (options.core) {
|
|
127
|
+
app.route("/", createSdkRouter(options.core));
|
|
128
|
+
}
|
|
125
129
|
registerBuiltinPluginHttpRoutes({
|
|
126
130
|
app,
|
|
127
131
|
getContext: bindings.getAgentContext,
|
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
toUiMessageTimeline,
|
|
31
31
|
} from "./Helpers.js";
|
|
32
32
|
import { executeBySessionId } from "./ExecuteBySession.js";
|
|
33
|
-
import { createControlSessionStreamResponse } from "./StreamBySession.js";
|
|
34
33
|
const CONSOLEUI_SESSION_ID = "consoleui-chat-main";
|
|
35
34
|
|
|
36
35
|
function normalizeSystemText(input: string | null | undefined): string {
|
|
@@ -413,30 +412,4 @@ export function registerControlSessionRoutes(
|
|
|
413
412
|
});
|
|
414
413
|
}
|
|
415
414
|
|
|
416
|
-
for (const routePath of buildControlRouteAliases("/sessions/:sessionId/stream")) {
|
|
417
|
-
app.post(routePath, async (c) => {
|
|
418
|
-
try {
|
|
419
|
-
const runtime = params.getAgentRuntime();
|
|
420
|
-
const sessionId = decodeMaybe(String(c.req.param("sessionId") || "").trim());
|
|
421
|
-
const body = (await c.req.json().catch(() => ({}))) as Partial<ControlSessionExecuteRequestBody>;
|
|
422
|
-
const instructions = String(body.instructions || "").trim();
|
|
423
|
-
if (!sessionId) {
|
|
424
|
-
return c.json({ success: false, error: "Missing sessionId" }, 400);
|
|
425
|
-
}
|
|
426
|
-
if (!instructions) {
|
|
427
|
-
return c.json({ success: false, error: "Missing instructions" }, 400);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
return await createControlSessionStreamResponse({
|
|
431
|
-
agentState: runtime,
|
|
432
|
-
executionContext: params.getAgentContext(),
|
|
433
|
-
sessionId,
|
|
434
|
-
instructions,
|
|
435
|
-
attachments: Array.isArray(body.attachments) ? body.attachments : undefined,
|
|
436
|
-
});
|
|
437
|
-
} catch (error) {
|
|
438
|
-
return c.json({ success: false, error: String(error) }, 500);
|
|
439
|
-
}
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
415
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK HTTP 路由入口模块。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - 这里专门承载 `RemoteAgent` 对应的最小 SDK transport。
|
|
6
|
+
* - 路由面围绕 Session actor 公开能力展开,不混入 control UI 语义。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Hono } from "hono";
|
|
10
|
+
import type { AgentCore } from "@/core/AgentCore.js";
|
|
11
|
+
import { registerSdkSessionRoutes } from "@/runtime/server/http/sdk/SessionRoutes.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 创建 SDK HTTP router。
|
|
15
|
+
*/
|
|
16
|
+
export function createSdkRouter(
|
|
17
|
+
core: Pick<AgentCore, "session" | "sessions">,
|
|
18
|
+
): Hono {
|
|
19
|
+
const router = new Hono();
|
|
20
|
+
registerSdkSessionRoutes(router, core);
|
|
21
|
+
return router;
|
|
22
|
+
}
|