@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,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionEventHub:Session 级事件分发器。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - 收口 `Session.subscribe()` 的订阅/取消订阅能力。
|
|
6
|
+
* - 只做未来事件广播,不做缓存、重放或背压管理。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
AgentSessionEvent,
|
|
11
|
+
AgentSessionSubscriber,
|
|
12
|
+
AgentSessionUnsubscribe,
|
|
13
|
+
} from "@/types/sdk/AgentSessionEvent.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* SessionEventHub:最小事件总线实现。
|
|
17
|
+
*/
|
|
18
|
+
export class SessionEventHub {
|
|
19
|
+
private readonly subscribers = new Map<number, AgentSessionSubscriber>();
|
|
20
|
+
private nextSubscriberId = 1;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 注册一个新的 Session 事件订阅者。
|
|
24
|
+
*/
|
|
25
|
+
subscribe(subscriber: AgentSessionSubscriber): AgentSessionUnsubscribe {
|
|
26
|
+
const id = this.nextSubscriberId;
|
|
27
|
+
this.nextSubscriberId += 1;
|
|
28
|
+
this.subscribers.set(id, subscriber);
|
|
29
|
+
|
|
30
|
+
return () => {
|
|
31
|
+
this.subscribers.delete(id);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 广播一条 Session 事件。
|
|
37
|
+
*/
|
|
38
|
+
publish(event: AgentSessionEvent): void {
|
|
39
|
+
for (const subscriber of this.subscribers.values()) {
|
|
40
|
+
try {
|
|
41
|
+
subscriber(event);
|
|
42
|
+
} catch {
|
|
43
|
+
// ignore single subscriber failures
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionPromptRuntime:Session actor 模式下的最小 prompt 调度器。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - `prompt()` 是唯一输入入口,内部决定并入当前 turn 还是排到下一 turn。
|
|
6
|
+
* - 不把调度逻辑塞进 Executor;Executor 继续只负责单次执行。
|
|
7
|
+
* - 这里不暴露历史或消息模型,只编排 prompt 队列与 turn 生命周期。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { nanoid } from "nanoid";
|
|
11
|
+
import type { SessionUserMessageV1 } from "@/session/types/SessionMessages.js";
|
|
12
|
+
import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
|
|
13
|
+
import type {
|
|
14
|
+
AgentSessionTurnHandle,
|
|
15
|
+
AgentSessionTurnResult,
|
|
16
|
+
} from "@/types/sdk/AgentSessionTurn.js";
|
|
17
|
+
|
|
18
|
+
type QueuedPrompt = {
|
|
19
|
+
/**
|
|
20
|
+
* 当前排队中的用户文本。
|
|
21
|
+
*/
|
|
22
|
+
query: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 当前 prompt 对应的 turn handle Promise 控制器。
|
|
26
|
+
*/
|
|
27
|
+
deferredHandle: Deferred<AgentSessionTurnHandle>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Promise 延迟控制器。
|
|
32
|
+
*/
|
|
33
|
+
interface Deferred<T> {
|
|
34
|
+
/**
|
|
35
|
+
* 延迟 Promise。
|
|
36
|
+
*/
|
|
37
|
+
promise: Promise<T>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 兑现 Promise。
|
|
41
|
+
*/
|
|
42
|
+
resolve: (value: T) => void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 当前活跃 turn 的运行态。
|
|
47
|
+
*/
|
|
48
|
+
interface ActiveTurnState {
|
|
49
|
+
/**
|
|
50
|
+
* 当前 turnId。
|
|
51
|
+
*/
|
|
52
|
+
turnId: string;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 当前 turn 的最终结果快照。
|
|
56
|
+
*/
|
|
57
|
+
result: AgentSessionTurnResult | null;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 当前 turn 完成 Promise 控制器。
|
|
61
|
+
*/
|
|
62
|
+
deferredFinished: Deferred<AgentSessionTurnResult>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* SessionPromptRuntime 构造参数。
|
|
67
|
+
*/
|
|
68
|
+
export interface SessionPromptRuntimeOptions {
|
|
69
|
+
/**
|
|
70
|
+
* 当前 session 标识。
|
|
71
|
+
*/
|
|
72
|
+
sessionId: string;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 广播 session 事件。
|
|
76
|
+
*/
|
|
77
|
+
publish: (event: AgentSessionEvent) => void;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 构造并持久化一条 user 消息。
|
|
81
|
+
*/
|
|
82
|
+
createAndPersistUserMessage: (query: string) => Promise<SessionUserMessageV1>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 执行单轮 turn。
|
|
86
|
+
*/
|
|
87
|
+
executeTurn: (input: {
|
|
88
|
+
turnId: string;
|
|
89
|
+
query: string;
|
|
90
|
+
onStepMerge: () => Promise<SessionUserMessageV1[]>;
|
|
91
|
+
}) => Promise<{
|
|
92
|
+
text: string;
|
|
93
|
+
success: boolean;
|
|
94
|
+
error?: string;
|
|
95
|
+
}>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* SessionPromptRuntime:最小 prompt 队列调度器。
|
|
100
|
+
*/
|
|
101
|
+
export class SessionPromptRuntime {
|
|
102
|
+
private readonly sessionId: string;
|
|
103
|
+
private readonly publish: SessionPromptRuntimeOptions["publish"];
|
|
104
|
+
private readonly createAndPersistUserMessage: SessionPromptRuntimeOptions["createAndPersistUserMessage"];
|
|
105
|
+
private readonly executeTurn: SessionPromptRuntimeOptions["executeTurn"];
|
|
106
|
+
private readonly queue: QueuedPrompt[] = [];
|
|
107
|
+
private processingPromise: Promise<void> | null = null;
|
|
108
|
+
|
|
109
|
+
constructor(options: SessionPromptRuntimeOptions) {
|
|
110
|
+
this.sessionId = String(options.sessionId || "").trim();
|
|
111
|
+
this.publish = options.publish;
|
|
112
|
+
this.createAndPersistUserMessage = options.createAndPersistUserMessage;
|
|
113
|
+
this.executeTurn = options.executeTurn;
|
|
114
|
+
if (!this.sessionId) {
|
|
115
|
+
throw new Error("SessionPromptRuntime requires a non-empty sessionId");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 追加一条新的 prompt。
|
|
121
|
+
*/
|
|
122
|
+
prompt(query: string): Promise<AgentSessionTurnHandle> {
|
|
123
|
+
const deferredHandle = createDeferred<AgentSessionTurnHandle>();
|
|
124
|
+
this.queue.push({
|
|
125
|
+
query: String(query || "").trim(),
|
|
126
|
+
deferredHandle,
|
|
127
|
+
});
|
|
128
|
+
this.ensureProcessing();
|
|
129
|
+
return deferredHandle.promise;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 返回当前 actor prompt 调度器是否仍处于活跃态。
|
|
134
|
+
*
|
|
135
|
+
* 说明(中文)
|
|
136
|
+
* - 只要还有排队 prompt,或处理循环尚未结束,就视为活跃。
|
|
137
|
+
* - Session 会用它阻止内部 direct execution 与 actor 模式并发混用。
|
|
138
|
+
*/
|
|
139
|
+
isActive(): boolean {
|
|
140
|
+
return this.processingPromise !== null || this.queue.length > 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private ensureProcessing(): void {
|
|
144
|
+
if (this.processingPromise) return;
|
|
145
|
+
this.processingPromise = this.processLoop().finally(() => {
|
|
146
|
+
this.processingPromise = null;
|
|
147
|
+
if (this.queue.length > 0) {
|
|
148
|
+
this.ensureProcessing();
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private async processLoop(): Promise<void> {
|
|
154
|
+
while (this.queue.length > 0) {
|
|
155
|
+
const current = this.queue.shift();
|
|
156
|
+
if (!current) break;
|
|
157
|
+
|
|
158
|
+
const turnId = `turn:${this.sessionId}:${Date.now()}:${nanoid(6)}`;
|
|
159
|
+
const activeTurn = createActiveTurnState(turnId);
|
|
160
|
+
this.publish({
|
|
161
|
+
type: "turn-start",
|
|
162
|
+
turnId,
|
|
163
|
+
});
|
|
164
|
+
current.deferredHandle.resolve(createTurnHandle(activeTurn));
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
await this.createAndPersistUserMessage(current.query);
|
|
168
|
+
const result = await this.executeTurn({
|
|
169
|
+
turnId,
|
|
170
|
+
query: current.query,
|
|
171
|
+
onStepMerge: async () => {
|
|
172
|
+
return await this.drainQueuedPromptsAsMessages(activeTurn);
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
const finalResult: AgentSessionTurnResult = {
|
|
176
|
+
turnId,
|
|
177
|
+
text: result.text,
|
|
178
|
+
success: result.success,
|
|
179
|
+
...(result.error ? { error: result.error } : {}),
|
|
180
|
+
};
|
|
181
|
+
activeTurn.result = finalResult;
|
|
182
|
+
this.publish({
|
|
183
|
+
type: "turn-finish",
|
|
184
|
+
turnId,
|
|
185
|
+
text: finalResult.text,
|
|
186
|
+
success: finalResult.success,
|
|
187
|
+
...(finalResult.error ? { error: finalResult.error } : {}),
|
|
188
|
+
});
|
|
189
|
+
activeTurn.deferredFinished.resolve(finalResult);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
192
|
+
const finalResult: AgentSessionTurnResult = {
|
|
193
|
+
turnId,
|
|
194
|
+
text: "",
|
|
195
|
+
success: false,
|
|
196
|
+
error: message,
|
|
197
|
+
};
|
|
198
|
+
activeTurn.result = finalResult;
|
|
199
|
+
this.publish({
|
|
200
|
+
type: "error",
|
|
201
|
+
message,
|
|
202
|
+
});
|
|
203
|
+
this.publish({
|
|
204
|
+
type: "turn-finish",
|
|
205
|
+
turnId,
|
|
206
|
+
text: "",
|
|
207
|
+
success: false,
|
|
208
|
+
error: message,
|
|
209
|
+
});
|
|
210
|
+
activeTurn.deferredFinished.resolve(finalResult);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private async drainQueuedPromptsAsMessages(
|
|
216
|
+
activeTurn: ActiveTurnState,
|
|
217
|
+
): Promise<SessionUserMessageV1[]> {
|
|
218
|
+
if (this.queue.length <= 0) return [];
|
|
219
|
+
const drained = this.queue.splice(0, this.queue.length);
|
|
220
|
+
const merged: SessionUserMessageV1[] = [];
|
|
221
|
+
|
|
222
|
+
for (let index = 0; index < drained.length; index += 1) {
|
|
223
|
+
const item = drained[index];
|
|
224
|
+
try {
|
|
225
|
+
const message = await this.createAndPersistUserMessage(item.query);
|
|
226
|
+
item.deferredHandle.resolve(createTurnHandle(activeTurn));
|
|
227
|
+
merged.push(message);
|
|
228
|
+
} catch {
|
|
229
|
+
// 关键点(中文):若某条消息持久化失败,把未处理部分重新放回队列头部,避免静默丢失。
|
|
230
|
+
const remaining = drained.slice(index);
|
|
231
|
+
this.queue.unshift(...remaining);
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return merged;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function createDeferred<T>(): Deferred<T> {
|
|
241
|
+
let resolve!: (value: T) => void;
|
|
242
|
+
const promise = new Promise<T>((innerResolve) => {
|
|
243
|
+
resolve = innerResolve;
|
|
244
|
+
});
|
|
245
|
+
return {
|
|
246
|
+
promise,
|
|
247
|
+
resolve,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function createActiveTurnState(turnId: string): ActiveTurnState {
|
|
252
|
+
return {
|
|
253
|
+
turnId,
|
|
254
|
+
result: null,
|
|
255
|
+
deferredFinished: createDeferred<AgentSessionTurnResult>(),
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function createTurnHandle(
|
|
260
|
+
activeTurn: ActiveTurnState,
|
|
261
|
+
): AgentSessionTurnHandle {
|
|
262
|
+
return {
|
|
263
|
+
id: activeTurn.turnId,
|
|
264
|
+
get result() {
|
|
265
|
+
return activeTurn.result;
|
|
266
|
+
},
|
|
267
|
+
finished: activeTurn.deferredFinished.promise,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
@@ -371,7 +371,7 @@ export class ChatQueueWorker {
|
|
|
371
371
|
const typing = this.startTypingHeartbeat(runItem);
|
|
372
372
|
let result: SessionRunResult;
|
|
373
373
|
try {
|
|
374
|
-
result = await serviceContext.
|
|
374
|
+
result = await serviceContext.execute({
|
|
375
375
|
query: runItem.text,
|
|
376
376
|
onStepCallback,
|
|
377
377
|
onAssistantStepCallback,
|
|
@@ -127,7 +127,7 @@ export class ChatSession extends Executor {
|
|
|
127
127
|
* 运行当前 chat session 的一次请求。
|
|
128
128
|
*
|
|
129
129
|
* 关键点(中文)
|
|
130
|
-
* -
|
|
130
|
+
* - 外层继续走统一的内部执行入口。
|
|
131
131
|
* - ChatSession 只是在 run 生命周期里临时绑定 turn 状态给自己的 composer。
|
|
132
132
|
*/
|
|
133
133
|
override async run(params: {
|
|
@@ -64,7 +64,7 @@ export async function receiveContactChatMessage(params: {
|
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
const sessionId = `contact_${contact.id}`;
|
|
67
|
-
const result = await params.context.session.get(sessionId).
|
|
67
|
+
const result = await params.context.session.get(sessionId).execute({
|
|
68
68
|
query: params.message,
|
|
69
69
|
});
|
|
70
70
|
const reply = extractMessageText(result.assistantMessage);
|
package/src/session/README.md
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
# Session Module
|
|
2
2
|
|
|
3
|
-
`session/` 是单 Agent 会话执行内核。它不直接面向普通 SDK 用户;普通用户通过 `sdk/Session.ts` 使用 `session.
|
|
3
|
+
`session/` 是单 Agent 会话执行内核。它不直接面向普通 SDK 用户;普通用户通过 `sdk/Session.ts` 使用 `session.prompt()`、`session.subscribe()`、`session.history()` 等 API。
|
|
4
4
|
|
|
5
5
|
## 核心概念
|
|
6
6
|
|
|
7
|
-
- `Session`:用户/SDK
|
|
8
|
-
- `Executor`:单个 session
|
|
7
|
+
- `Session`:用户/SDK 面向的完整会话对象,负责模型配置、历史入口、prompt 入口和分叉能力。
|
|
8
|
+
- `Executor`:单个 session 的内部单轮执行引擎,负责并发锁、执行 scope、Composer 编排、压缩重试、assistant step 持久化和 tool-loop 调用。
|
|
9
9
|
- `Composer`:执行前的材料组装协议,只负责把原材料组装成某一阶段输入,不直接执行模型,也没有公共运行时基类。
|
|
10
10
|
- `HistoryStore`:历史事实源,负责 JSONL 读写、meta、archive、lock、compact 与消息工厂。
|
|
11
11
|
- `HistoryComposer`:历史组装策略,只负责把 `HistoryStore` 中的历史组装成本轮模型输入。
|
|
12
12
|
- `CoreEngine`:Executor 内部的模型/tool-loop 核心机制,负责模型流、tool calls、续写和最终 assistant message 合并。
|
|
13
13
|
|
|
14
|
-
## 一轮
|
|
14
|
+
## 一轮 prompt 的调用链
|
|
15
15
|
|
|
16
16
|
```text
|
|
17
|
-
sdk/Session.
|
|
17
|
+
sdk/Session.prompt({ query })
|
|
18
|
+
-> SessionPromptRuntime 绑定 turn
|
|
18
19
|
-> append user message
|
|
19
|
-
-> session/Executor
|
|
20
|
+
-> session/Executor 执行当前 turn
|
|
20
21
|
-> ContextComposer.compose()
|
|
21
22
|
-> SystemComposer.resolve()
|
|
22
23
|
-> CompactionComposer.run()
|
|
@@ -25,7 +26,7 @@ sdk/Session.run({ query })
|
|
|
25
26
|
-> ai.streamText({ model, system, messages, tools })
|
|
26
27
|
-> return assistantMessage
|
|
27
28
|
-> append final assistant message
|
|
28
|
-
->
|
|
29
|
+
-> resolve turn.finished
|
|
29
30
|
```
|
|
30
31
|
|
|
31
32
|
## Composer 分工
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Session 事件类型定义。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - `subscribe()` 暴露的是 session 级长期事件序列,而不是单次执行的局部结果。
|
|
6
|
+
* - 事件只表达“当前 turn 正在发生什么”,不负责历史回放。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { JsonValue } from "@/types/common/Json.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 单个 turn 开始事件。
|
|
13
|
+
*/
|
|
14
|
+
export interface AgentSessionTurnStartEvent {
|
|
15
|
+
/**
|
|
16
|
+
* 当前事件类型。
|
|
17
|
+
*/
|
|
18
|
+
type: "turn-start";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 当前 turn 的稳定标识。
|
|
22
|
+
*
|
|
23
|
+
* 说明(中文)
|
|
24
|
+
* - 同一个 turn 内的全部增量事件都会复用这个 turnId。
|
|
25
|
+
* - 当 Session 排队进入下一轮时,会生成新的 turnId。
|
|
26
|
+
*/
|
|
27
|
+
turnId: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 普通文本增量事件。
|
|
32
|
+
*/
|
|
33
|
+
export interface AgentSessionTextDeltaEvent {
|
|
34
|
+
/**
|
|
35
|
+
* 当前事件类型。
|
|
36
|
+
*/
|
|
37
|
+
type: "text-delta";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 当前文本所属 turn。
|
|
41
|
+
*/
|
|
42
|
+
turnId: string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 当前这次新增的可见文本片段。
|
|
46
|
+
*/
|
|
47
|
+
text: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* reasoning 文本增量事件。
|
|
52
|
+
*/
|
|
53
|
+
export interface AgentSessionReasoningDeltaEvent {
|
|
54
|
+
/**
|
|
55
|
+
* 当前事件类型。
|
|
56
|
+
*/
|
|
57
|
+
type: "reasoning-delta";
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 当前 reasoning 所属 turn。
|
|
61
|
+
*/
|
|
62
|
+
turnId: string;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 当前这次新增的 reasoning 文本片段。
|
|
66
|
+
*/
|
|
67
|
+
text: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 工具调用事件。
|
|
72
|
+
*/
|
|
73
|
+
export interface AgentSessionToolCallEvent {
|
|
74
|
+
/**
|
|
75
|
+
* 当前事件类型。
|
|
76
|
+
*/
|
|
77
|
+
type: "tool-call";
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 当前工具调用所属 turn。
|
|
81
|
+
*/
|
|
82
|
+
turnId: string;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 当前工具调用唯一标识。
|
|
86
|
+
*/
|
|
87
|
+
toolCallId: string;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 当前工具名称。
|
|
91
|
+
*/
|
|
92
|
+
toolName: string;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 当前工具输入参数。
|
|
96
|
+
*/
|
|
97
|
+
args: JsonValue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 工具结果事件。
|
|
102
|
+
*/
|
|
103
|
+
export interface AgentSessionToolResultEvent {
|
|
104
|
+
/**
|
|
105
|
+
* 当前事件类型。
|
|
106
|
+
*/
|
|
107
|
+
type: "tool-result";
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 当前工具结果所属 turn。
|
|
111
|
+
*/
|
|
112
|
+
turnId: string;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 当前工具调用唯一标识。
|
|
116
|
+
*/
|
|
117
|
+
toolCallId: string;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 当前工具名称。
|
|
121
|
+
*/
|
|
122
|
+
toolName: string;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 当前工具输出结果。
|
|
126
|
+
*/
|
|
127
|
+
result: JsonValue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 单个 turn 完成事件。
|
|
132
|
+
*/
|
|
133
|
+
export interface AgentSessionTurnFinishEvent {
|
|
134
|
+
/**
|
|
135
|
+
* 当前事件类型。
|
|
136
|
+
*/
|
|
137
|
+
type: "turn-finish";
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 当前已完成 turn 的稳定标识。
|
|
141
|
+
*/
|
|
142
|
+
turnId: string;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 当前 turn 最终可见文本。
|
|
146
|
+
*/
|
|
147
|
+
text: string;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 当前 turn 是否成功结束。
|
|
151
|
+
*/
|
|
152
|
+
success: boolean;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 当前 turn 失败时的错误文本。
|
|
156
|
+
*/
|
|
157
|
+
error?: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Session 级错误事件。
|
|
162
|
+
*/
|
|
163
|
+
export interface AgentSessionErrorEvent {
|
|
164
|
+
/**
|
|
165
|
+
* 当前事件类型。
|
|
166
|
+
*/
|
|
167
|
+
type: "error";
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* 当前错误文本。
|
|
171
|
+
*/
|
|
172
|
+
message: string;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Session 订阅可见事件联合类型。
|
|
177
|
+
*/
|
|
178
|
+
export type AgentSessionEvent =
|
|
179
|
+
| AgentSessionTurnStartEvent
|
|
180
|
+
| AgentSessionTextDeltaEvent
|
|
181
|
+
| AgentSessionReasoningDeltaEvent
|
|
182
|
+
| AgentSessionToolCallEvent
|
|
183
|
+
| AgentSessionToolResultEvent
|
|
184
|
+
| AgentSessionTurnFinishEvent
|
|
185
|
+
| AgentSessionErrorEvent;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Session 事件订阅回调。
|
|
189
|
+
*/
|
|
190
|
+
export type AgentSessionSubscriber = (event: AgentSessionEvent) => void;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 取消 Session 订阅的返回函数。
|
|
194
|
+
*/
|
|
195
|
+
export type AgentSessionUnsubscribe = () => void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Session prompt 输入类型定义。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - `prompt()` 是 Session actor 模型下唯一的输入入口。
|
|
6
|
+
* - 首条输入、运行中补充输入、排队到下一轮的输入,调用侧都使用同一结构。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Session prompt 输入。
|
|
11
|
+
*/
|
|
12
|
+
export interface AgentSessionPromptInput {
|
|
13
|
+
/**
|
|
14
|
+
* 当前这次要追加到 Session 的用户文本。
|
|
15
|
+
*
|
|
16
|
+
* 说明(中文)
|
|
17
|
+
* - 调用侧永远只传“新的用户输入”。
|
|
18
|
+
* - 它是否并入当前 turn,还是排到下一 turn,由 Session 内部决定。
|
|
19
|
+
*/
|
|
20
|
+
query: string;
|
|
21
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
/**
|
|
11
|
+
* 单个 Session turn 的最终结果。
|
|
12
|
+
*/
|
|
13
|
+
export interface AgentSessionTurnResult {
|
|
14
|
+
/**
|
|
15
|
+
* 当前已完成 turn 的稳定标识。
|
|
16
|
+
*/
|
|
17
|
+
turnId: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 当前 turn 最终可见文本。
|
|
21
|
+
*/
|
|
22
|
+
text: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 当前 turn 是否成功结束。
|
|
26
|
+
*/
|
|
27
|
+
success: boolean;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 当前 turn 失败时的错误文本。
|
|
31
|
+
*/
|
|
32
|
+
error?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 单个 Session turn 的等待句柄。
|
|
37
|
+
*/
|
|
38
|
+
export interface AgentSessionTurnHandle {
|
|
39
|
+
/**
|
|
40
|
+
* 当前句柄绑定到的 turnId。
|
|
41
|
+
*
|
|
42
|
+
* 说明(中文)
|
|
43
|
+
* - `prompt()` 只有在确定当前输入被并入哪个 turn 后才会返回。
|
|
44
|
+
* - 因此这里总是最终可用的 turnId,而不是临时 receipt id。
|
|
45
|
+
*/
|
|
46
|
+
id: string;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 当前 turn 已完成后的最终结果快照。
|
|
50
|
+
*
|
|
51
|
+
* 说明(中文)
|
|
52
|
+
* - 在 `finished` 兑现之前这里为 `null`。
|
|
53
|
+
* - 兑现之后会变成与 `finished` 相同的最终结果对象。
|
|
54
|
+
*/
|
|
55
|
+
result: AgentSessionTurnResult | null;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 等待当前 turn 完成的 Promise。
|
|
59
|
+
*
|
|
60
|
+
* 关键点(中文)
|
|
61
|
+
* - 这里无论 turn 成功还是失败都会 resolve。
|
|
62
|
+
* - 调用方应读取返回结果中的 `success` / `error` 判断最终状态。
|
|
63
|
+
*/
|
|
64
|
+
finished: Promise<AgentSessionTurnResult>;
|
|
65
|
+
}
|