@downcity/agent 1.1.79 → 1.1.81
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 +1 -1
- package/bin/agent/local/Agent.d.ts +8 -121
- package/bin/agent/local/Agent.d.ts.map +1 -1
- package/bin/agent/local/Agent.js +63 -381
- package/bin/agent/local/Agent.js.map +1 -1
- package/bin/agent/local/AgentRuntimeFactory.d.ts +2 -2
- package/bin/agent/local/AgentRuntimeFactory.d.ts.map +1 -1
- package/bin/agent/local/AgentRuntimeFactory.js +2 -23
- package/bin/agent/local/AgentRuntimeFactory.js.map +1 -1
- package/bin/agent/local/services/AgentAssemblyService.d.ts +112 -0
- package/bin/agent/local/services/AgentAssemblyService.d.ts.map +1 -0
- package/bin/agent/local/services/AgentAssemblyService.js +135 -0
- package/bin/agent/local/services/AgentAssemblyService.js.map +1 -0
- package/bin/agent/local/services/AgentLifecycleService.d.ts +59 -0
- package/bin/agent/local/services/AgentLifecycleService.d.ts.map +1 -0
- package/bin/agent/local/services/AgentLifecycleService.js +136 -0
- package/bin/agent/local/services/AgentLifecycleService.js.map +1 -0
- package/bin/agent/local/services/AgentSessionManager.d.ts +106 -0
- package/bin/agent/local/services/AgentSessionManager.d.ts.map +1 -0
- package/bin/agent/local/services/AgentSessionManager.js +182 -0
- package/bin/agent/local/services/AgentSessionManager.js.map +1 -0
- package/bin/executor/Executor.d.ts +7 -24
- package/bin/executor/Executor.d.ts.map +1 -1
- package/bin/executor/Executor.js +73 -361
- package/bin/executor/Executor.js.map +1 -1
- package/bin/executor/SessionRunScope.d.ts +18 -34
- package/bin/executor/SessionRunScope.d.ts.map +1 -1
- package/bin/executor/SessionRunScope.js +42 -28
- package/bin/executor/SessionRunScope.js.map +1 -1
- package/bin/executor/composer/context/LocalSessionContextComposer.d.ts +5 -3
- package/bin/executor/composer/context/LocalSessionContextComposer.d.ts.map +1 -1
- package/bin/executor/composer/context/LocalSessionContextComposer.js +11 -18
- package/bin/executor/composer/context/LocalSessionContextComposer.js.map +1 -1
- package/bin/executor/composer/context/SessionContextComposer.d.ts +8 -3
- package/bin/executor/composer/context/SessionContextComposer.d.ts.map +1 -1
- package/bin/executor/composer/system/SessionSystemComposer.d.ts +2 -1
- package/bin/executor/composer/system/SessionSystemComposer.d.ts.map +1 -1
- package/bin/executor/composer/system/default/DefaultSessionSystemComposer.d.ts +2 -1
- package/bin/executor/composer/system/default/DefaultSessionSystemComposer.d.ts.map +1 -1
- package/bin/executor/composer/system/default/DefaultSessionSystemComposer.js +2 -4
- package/bin/executor/composer/system/default/DefaultSessionSystemComposer.js.map +1 -1
- package/bin/executor/core-engine/CoreEngineRunner.d.ts +62 -0
- package/bin/executor/core-engine/CoreEngineRunner.d.ts.map +1 -0
- package/bin/executor/core-engine/CoreEngineRunner.js +309 -0
- package/bin/executor/core-engine/CoreEngineRunner.js.map +1 -0
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.d.ts +5 -0
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.d.ts.map +1 -1
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.js +2 -4
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.js.map +1 -1
- package/bin/executor/services/ExecutorInflightService.d.ts +39 -0
- package/bin/executor/services/ExecutorInflightService.d.ts.map +1 -0
- package/bin/executor/services/ExecutorInflightService.js +75 -0
- package/bin/executor/services/ExecutorInflightService.js.map +1 -0
- package/bin/executor/services/ExecutorRecoveryPolicy.d.ts +103 -0
- package/bin/executor/services/ExecutorRecoveryPolicy.d.ts.map +1 -0
- package/bin/executor/services/ExecutorRecoveryPolicy.js +87 -0
- package/bin/executor/services/ExecutorRecoveryPolicy.js.map +1 -0
- package/bin/executor/tools/plugin/PluginToolBridge.d.ts +19 -0
- package/bin/executor/tools/plugin/PluginToolBridge.d.ts.map +1 -0
- package/bin/executor/tools/plugin/PluginToolBridge.js +143 -0
- package/bin/executor/tools/plugin/PluginToolBridge.js.map +1 -0
- package/bin/executor/tools/plugin/PluginToolDefinition.d.ts +32 -0
- package/bin/executor/tools/plugin/PluginToolDefinition.d.ts.map +1 -0
- package/bin/executor/tools/plugin/PluginToolDefinition.js +27 -0
- package/bin/executor/tools/plugin/PluginToolDefinition.js.map +1 -0
- package/bin/executor/tools/plugin/PluginToolSchemas.d.ts +14 -0
- package/bin/executor/tools/plugin/PluginToolSchemas.d.ts.map +1 -0
- package/bin/executor/tools/plugin/PluginToolSchemas.js +19 -0
- package/bin/executor/tools/plugin/PluginToolSchemas.js.map +1 -0
- package/bin/executor/tools/plugin/types/PluginTool.d.ts +39 -0
- package/bin/executor/tools/plugin/types/PluginTool.d.ts.map +1 -0
- package/bin/executor/tools/plugin/types/PluginTool.js +9 -0
- package/bin/executor/tools/plugin/types/PluginTool.js.map +1 -0
- package/bin/executor/tools/shell/ShellToolBridge.js +3 -3
- package/bin/executor/tools/shell/ShellToolBridge.js.map +1 -1
- package/bin/executor/types/SessionRun.d.ts +18 -0
- package/bin/executor/types/SessionRun.d.ts.map +1 -1
- package/bin/index.d.ts +10 -1
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +3 -0
- package/bin/index.js.map +1 -1
- package/bin/plugin/core/BasePlugin.d.ts +2 -2
- package/bin/plugin/core/BasePlugin.d.ts.map +1 -1
- package/bin/plugin/core/BasePlugin.js.map +1 -1
- package/bin/plugin/core/ImagePlugin.d.ts +56 -0
- package/bin/plugin/core/ImagePlugin.d.ts.map +1 -0
- package/bin/plugin/core/ImagePlugin.js +109 -0
- package/bin/plugin/core/ImagePlugin.js.map +1 -0
- package/bin/session/Session.d.ts +14 -83
- package/bin/session/Session.d.ts.map +1 -1
- package/bin/session/Session.js +139 -362
- package/bin/session/Session.js.map +1 -1
- package/bin/session/SessionSystemBuilder.d.ts +2 -1
- package/bin/session/SessionSystemBuilder.d.ts.map +1 -1
- package/bin/session/SessionSystemBuilder.js +2 -3
- package/bin/session/SessionSystemBuilder.js.map +1 -1
- package/bin/session/services/SessionStateService.d.ts +132 -0
- package/bin/session/services/SessionStateService.d.ts.map +1 -0
- package/bin/session/services/SessionStateService.js +242 -0
- package/bin/session/services/SessionStateService.js.map +1 -0
- package/bin/session/services/SessionTurnService.d.ts +66 -0
- package/bin/session/services/SessionTurnService.d.ts.map +1 -0
- package/bin/session/services/SessionTurnService.js +137 -0
- package/bin/session/services/SessionTurnService.js.map +1 -0
- package/bin/session/services/SessionViewService.d.ts +105 -0
- package/bin/session/services/SessionViewService.d.ts.map +1 -0
- package/bin/session/services/SessionViewService.js +184 -0
- package/bin/session/services/SessionViewService.js.map +1 -0
- package/bin/types/agent/AgentOptions.d.ts +18 -0
- package/bin/types/agent/AgentOptions.d.ts.map +1 -1
- package/bin/types/agent/AgentTypes.d.ts +3 -1
- package/bin/types/agent/AgentTypes.d.ts.map +1 -1
- package/bin/types/agent/SessionTypes.d.ts.map +1 -1
- package/bin/types/executor/SessionRunContext.d.ts +66 -0
- package/bin/types/executor/SessionRunContext.d.ts.map +1 -0
- package/bin/types/executor/SessionRunContext.js +10 -0
- package/bin/types/executor/SessionRunContext.js.map +1 -0
- package/bin/types/plugin/ImagePlugin.d.ts +94 -0
- package/bin/types/plugin/ImagePlugin.d.ts.map +1 -0
- package/bin/types/plugin/ImagePlugin.js +10 -0
- package/bin/types/plugin/ImagePlugin.js.map +1 -0
- package/bin/types/session/SessionComposerOptions.d.ts +90 -0
- package/bin/types/session/SessionComposerOptions.d.ts.map +1 -0
- package/bin/types/session/SessionComposerOptions.js +10 -0
- package/bin/types/session/SessionComposerOptions.js.map +1 -0
- package/bin/types/session/SessionLocalState.d.ts +35 -0
- package/bin/types/session/SessionLocalState.d.ts.map +1 -0
- package/bin/types/session/SessionLocalState.js +10 -0
- package/bin/types/session/SessionLocalState.js.map +1 -0
- package/bin/types/session/SessionOptions.d.ts +85 -0
- package/bin/types/session/SessionOptions.d.ts.map +1 -0
- package/bin/types/session/SessionOptions.js +10 -0
- package/bin/types/session/SessionOptions.js.map +1 -0
- package/package.json +1 -1
- package/src/agent/local/Agent.ts +74 -433
- package/src/agent/local/AgentRuntimeFactory.ts +4 -25
- package/src/agent/local/services/AgentAssemblyService.ts +268 -0
- package/src/agent/local/services/AgentLifecycleService.ts +187 -0
- package/src/agent/local/services/AgentSessionManager.ts +291 -0
- package/src/executor/Executor.ts +103 -441
- package/src/executor/README.md +4 -4
- package/src/executor/SessionRunScope.ts +47 -71
- package/src/executor/composer/context/LocalSessionContextComposer.ts +24 -20
- package/src/executor/composer/context/SessionContextComposer.ts +13 -3
- package/src/executor/composer/system/SessionSystemComposer.ts +2 -1
- package/src/executor/composer/system/default/DefaultSessionSystemComposer.ts +3 -4
- package/src/executor/core-engine/CoreEngineRunner.ts +433 -0
- package/src/executor/core-engine/CoreEngineUiStreamCollector.ts +7 -5
- package/src/executor/services/ExecutorInflightService.ts +101 -0
- package/src/executor/services/ExecutorRecoveryPolicy.ts +213 -0
- package/src/executor/tools/plugin/PluginToolBridge.ts +161 -0
- package/src/executor/tools/plugin/PluginToolDefinition.ts +32 -0
- package/src/executor/tools/plugin/PluginToolSchemas.ts +20 -0
- package/src/executor/tools/plugin/types/PluginTool.ts +41 -0
- package/src/executor/tools/shell/ShellToolBridge.ts +3 -3
- package/src/executor/types/SessionRun.ts +20 -0
- package/src/index.ts +33 -0
- package/src/plugin/core/BasePlugin.ts +2 -2
- package/src/plugin/core/ImagePlugin.ts +128 -0
- package/src/session/Session.ts +178 -485
- package/src/session/SessionSystemBuilder.ts +3 -3
- package/src/session/services/SessionStateService.ts +341 -0
- package/src/session/services/SessionTurnService.ts +202 -0
- package/src/session/services/SessionViewService.ts +301 -0
- package/src/types/agent/AgentOptions.ts +25 -0
- package/src/types/agent/AgentTypes.ts +10 -0
- package/src/types/agent/SessionTypes.ts +1 -0
- package/src/types/executor/SessionRunContext.ts +76 -0
- package/src/types/plugin/ImagePlugin.ts +103 -0
- package/src/types/session/SessionComposerOptions.ts +107 -0
- package/src/types/session/SessionLocalState.ts +40 -0
- package/src/types/session/SessionOptions.ts +99 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { SessionSystemComposer } from "@executor/composer/system/SessionSystemComposer.js";
|
|
11
|
-
import { getSessionRunScope } from "@executor/SessionRunScope.js";
|
|
12
11
|
import type { SessionSystemMessage } from "@/executor/types/SessionPrompts.js";
|
|
13
12
|
import type {
|
|
14
13
|
AgentSessionSystemBlock,
|
|
15
14
|
AgentSessionSystemSessionInfo,
|
|
16
15
|
} from "@/types/agent/AgentTypes.js";
|
|
16
|
+
import type { SessionRunContext } from "@/types/executor/SessionRunContext.js";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* 解析 SDK session system blocks 的输入。
|
|
@@ -240,8 +240,8 @@ export class SessionSystemBuilder implements SessionSystemComposer {
|
|
|
240
240
|
/**
|
|
241
241
|
* 解析本轮 SDK session system messages。
|
|
242
242
|
*/
|
|
243
|
-
async resolve() {
|
|
244
|
-
const sessionId = String(
|
|
243
|
+
async resolve(run_context: SessionRunContext) {
|
|
244
|
+
const sessionId = String(run_context.sessionId || "").trim();
|
|
245
245
|
if (!sessionId) {
|
|
246
246
|
throw new Error("SessionSystemBuilder.resolve requires a non-empty sessionId");
|
|
247
247
|
}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionStateService:本地 Session 状态与持久化服务。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - 统一管理本地 Session 的初始化、配置、标题、metadata 与消息持久化。
|
|
6
|
+
* - 该服务只关心状态事实源与持久化副作用,不负责 turn 编排。
|
|
7
|
+
* - `Session` facade 与 turn/view service 都通过它访问可变 session 运行态。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
inferAgentModelLabel,
|
|
12
|
+
normalizeAgentModel,
|
|
13
|
+
} from "@/model/CityModelAdapter.js";
|
|
14
|
+
import {
|
|
15
|
+
patchSessionModelLabel,
|
|
16
|
+
readSessionMetadata,
|
|
17
|
+
resolveSystemTimezone,
|
|
18
|
+
touchSessionMetadata,
|
|
19
|
+
writeSessionMetadata,
|
|
20
|
+
} from "@/session/index.js";
|
|
21
|
+
import { ensureSessionTitle } from "@/session/SessionTitle.js";
|
|
22
|
+
import { persistSdkAssistantResult } from "@/session/storage/Persistence.js";
|
|
23
|
+
import type { Executor } from "@executor/Executor.js";
|
|
24
|
+
import type { JsonlSessionHistoryStore } from "@/executor/store/history/jsonl/JsonlSessionHistoryStore.js";
|
|
25
|
+
import type {
|
|
26
|
+
AgentSessionConfigSnapshot,
|
|
27
|
+
AgentSessionSetInput,
|
|
28
|
+
} from "@/types/agent/AgentTypes.js";
|
|
29
|
+
import type {
|
|
30
|
+
AgentSessionEvent,
|
|
31
|
+
} from "@/types/sdk/AgentSessionEvent.js";
|
|
32
|
+
import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
|
|
33
|
+
import type {
|
|
34
|
+
SessionMessageV1,
|
|
35
|
+
SessionUserMessageV1,
|
|
36
|
+
} from "@/executor/types/SessionMessages.js";
|
|
37
|
+
import type { SessionLocalState } from "@/types/session/SessionLocalState.js";
|
|
38
|
+
|
|
39
|
+
type SessionStateServiceOptions = {
|
|
40
|
+
/**
|
|
41
|
+
* 当前 agent 稳定标识。
|
|
42
|
+
*/
|
|
43
|
+
agent_id: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 当前项目根目录。
|
|
47
|
+
*/
|
|
48
|
+
project_root: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 当前 session 标识。
|
|
52
|
+
*/
|
|
53
|
+
session_id: string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 当前 session 历史事实源。
|
|
57
|
+
*/
|
|
58
|
+
history_store: JsonlSessionHistoryStore;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 当前 session 执行器。
|
|
62
|
+
*/
|
|
63
|
+
executor: Executor;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 当前 session 可变运行态。
|
|
67
|
+
*/
|
|
68
|
+
state: SessionLocalState;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 在执行前补齐宿主级配置。
|
|
72
|
+
*/
|
|
73
|
+
ensure_configured_hook?: () => Promise<void>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 发布 session 事件。
|
|
77
|
+
*/
|
|
78
|
+
publish_event: (event: AgentSessionEvent) => void;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 本地 Session 状态与持久化服务。
|
|
83
|
+
*/
|
|
84
|
+
export class SessionStateService {
|
|
85
|
+
private readonly agent_id: string;
|
|
86
|
+
private readonly project_root: string;
|
|
87
|
+
private readonly session_id: string;
|
|
88
|
+
private readonly history_store: JsonlSessionHistoryStore;
|
|
89
|
+
private readonly executor: Executor;
|
|
90
|
+
private readonly state: SessionLocalState;
|
|
91
|
+
private readonly ensure_configured_hook?: SessionStateServiceOptions["ensure_configured_hook"];
|
|
92
|
+
private readonly publish_event: SessionStateServiceOptions["publish_event"];
|
|
93
|
+
|
|
94
|
+
constructor(options: SessionStateServiceOptions) {
|
|
95
|
+
this.agent_id = options.agent_id;
|
|
96
|
+
this.project_root = options.project_root;
|
|
97
|
+
this.session_id = options.session_id;
|
|
98
|
+
this.history_store = options.history_store;
|
|
99
|
+
this.executor = options.executor;
|
|
100
|
+
this.state = options.state;
|
|
101
|
+
this.ensure_configured_hook = options.ensure_configured_hook;
|
|
102
|
+
this.publish_event = options.publish_event;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 读取当前 session 配置快照。
|
|
107
|
+
*/
|
|
108
|
+
get_config(): AgentSessionConfigSnapshot {
|
|
109
|
+
return {
|
|
110
|
+
...this.state.sessionConfig,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 读取当前 session 创建时间。
|
|
116
|
+
*/
|
|
117
|
+
get_created_at(): number {
|
|
118
|
+
return this.state.createdAt;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 读取当前 session 参考时区。
|
|
123
|
+
*/
|
|
124
|
+
get_timezone(): string {
|
|
125
|
+
return this.state.timezone;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 初始化当前 session metadata 与内存快照。
|
|
130
|
+
*/
|
|
131
|
+
async initialize(): Promise<void> {
|
|
132
|
+
if (this.state.initializePromise) {
|
|
133
|
+
await this.state.initializePromise;
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
this.state.initializePromise = (async () => {
|
|
137
|
+
const metadata = await readSessionMetadata({
|
|
138
|
+
projectRoot: this.project_root,
|
|
139
|
+
agentId: this.agent_id,
|
|
140
|
+
sessionId: this.session_id,
|
|
141
|
+
});
|
|
142
|
+
const created_at =
|
|
143
|
+
typeof metadata.createdAt === "number" ? metadata.createdAt : Date.now();
|
|
144
|
+
const timezone =
|
|
145
|
+
typeof metadata.timezone === "string" && metadata.timezone.trim()
|
|
146
|
+
? metadata.timezone.trim()
|
|
147
|
+
: resolveSystemTimezone();
|
|
148
|
+
await writeSessionMetadata({
|
|
149
|
+
projectRoot: this.project_root,
|
|
150
|
+
agentId: this.agent_id,
|
|
151
|
+
sessionId: this.session_id,
|
|
152
|
+
meta: {
|
|
153
|
+
...metadata,
|
|
154
|
+
agentId: this.agent_id,
|
|
155
|
+
createdAt: created_at,
|
|
156
|
+
timezone,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
this.state.createdAt = created_at;
|
|
160
|
+
this.state.timezone = timezone;
|
|
161
|
+
this.state.sessionConfig = {
|
|
162
|
+
...(metadata.modelLabel
|
|
163
|
+
? { modelLabel: metadata.modelLabel }
|
|
164
|
+
: {}),
|
|
165
|
+
};
|
|
166
|
+
})();
|
|
167
|
+
await this.state.initializePromise;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 在执行前确保当前 session 已完成初始化与宿主装配。
|
|
172
|
+
*/
|
|
173
|
+
async ensure_ready_for_execution(): Promise<void> {
|
|
174
|
+
await this.initialize();
|
|
175
|
+
if (this.state.ensureConfiguredPromise) {
|
|
176
|
+
await this.state.ensureConfiguredPromise;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
this.state.ensureConfiguredPromise = (async () => {
|
|
180
|
+
if (!this.ensure_configured_hook) return;
|
|
181
|
+
await this.ensure_configured_hook();
|
|
182
|
+
})();
|
|
183
|
+
try {
|
|
184
|
+
await this.state.ensureConfiguredPromise;
|
|
185
|
+
} catch (error) {
|
|
186
|
+
this.state.ensureConfiguredPromise = null;
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 在 prompt 执行前确保当前 session 已可运行。
|
|
193
|
+
*/
|
|
194
|
+
async ensure_runnable(): Promise<void> {
|
|
195
|
+
await this.ensure_ready_for_execution();
|
|
196
|
+
if (!this.state.sessionConfig.model) {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`Session "${this.session_id}" requires a configured model. Pass model to new Agent({ model }) or call session.set({ model }) first.`,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* 写入当前 session 配置。
|
|
205
|
+
*/
|
|
206
|
+
async set(input: AgentSessionSetInput): Promise<void> {
|
|
207
|
+
if (input.model) {
|
|
208
|
+
this.state.sessionConfig.model = normalizeAgentModel(input.model);
|
|
209
|
+
this.state.sessionConfig.modelLabel = inferAgentModelLabel(input.model);
|
|
210
|
+
this.executor.clearExecutor();
|
|
211
|
+
}
|
|
212
|
+
await patchSessionModelLabel({
|
|
213
|
+
projectRoot: this.project_root,
|
|
214
|
+
agentId: this.agent_id,
|
|
215
|
+
sessionId: this.session_id,
|
|
216
|
+
model: this.state.sessionConfig.model,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 追加一条 user 消息并刷新标题与 metadata。
|
|
222
|
+
*/
|
|
223
|
+
async append_user_message(params: {
|
|
224
|
+
message?: SessionMessageV1 | null;
|
|
225
|
+
text?: string;
|
|
226
|
+
}): Promise<void> {
|
|
227
|
+
await this.executor.appendUserMessage(params);
|
|
228
|
+
await this.ensure_title_from_history({ generate: true });
|
|
229
|
+
await this.touch_metadata();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* 追加一条 assistant 消息并刷新 metadata。
|
|
234
|
+
*/
|
|
235
|
+
async append_assistant_message(params: {
|
|
236
|
+
message?: SessionMessageV1 | null;
|
|
237
|
+
fallbackText?: string;
|
|
238
|
+
}): Promise<void> {
|
|
239
|
+
await this.executor.appendAssistantMessage(params);
|
|
240
|
+
await this.touch_metadata();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* 仅刷新当前 session metadata。
|
|
245
|
+
*/
|
|
246
|
+
async touch_metadata(): Promise<void> {
|
|
247
|
+
await touchSessionMetadata({
|
|
248
|
+
projectRoot: this.project_root,
|
|
249
|
+
agentId: this.agent_id,
|
|
250
|
+
sessionId: this.session_id,
|
|
251
|
+
sessionConfig: this.state.sessionConfig,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* 确保当前 session 已持久化 title。
|
|
257
|
+
*/
|
|
258
|
+
async ensure_title_from_history(input?: {
|
|
259
|
+
/**
|
|
260
|
+
* 是否允许调用模型生成标题。
|
|
261
|
+
*/
|
|
262
|
+
generate?: boolean;
|
|
263
|
+
}): Promise<void> {
|
|
264
|
+
const messages = await this.history_store.list();
|
|
265
|
+
const before_metadata = await readSessionMetadata({
|
|
266
|
+
projectRoot: this.project_root,
|
|
267
|
+
agentId: this.agent_id,
|
|
268
|
+
sessionId: this.session_id,
|
|
269
|
+
});
|
|
270
|
+
const before_title = String(before_metadata.title || "").trim();
|
|
271
|
+
const next_metadata = await ensureSessionTitle({
|
|
272
|
+
projectRoot: this.project_root,
|
|
273
|
+
agentId: this.agent_id,
|
|
274
|
+
sessionId: this.session_id,
|
|
275
|
+
messages,
|
|
276
|
+
...(input?.generate ? { model: this.state.sessionConfig.model } : {}),
|
|
277
|
+
generate: input?.generate === true,
|
|
278
|
+
});
|
|
279
|
+
const next_title = String(next_metadata.title || "").trim();
|
|
280
|
+
if (!next_title || next_title === before_title) return;
|
|
281
|
+
this.publish_event({
|
|
282
|
+
type: "session-title",
|
|
283
|
+
sessionId: this.session_id,
|
|
284
|
+
title: next_title,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* 持久化最终 assistant 结果。
|
|
290
|
+
*/
|
|
291
|
+
async persist_assistant_result(
|
|
292
|
+
assistant_message: SessionMessageV1,
|
|
293
|
+
): Promise<void> {
|
|
294
|
+
await persistSdkAssistantResult({
|
|
295
|
+
projectRoot: this.project_root,
|
|
296
|
+
agentId: this.agent_id,
|
|
297
|
+
sessionId: this.session_id,
|
|
298
|
+
sessionConfig: this.state.sessionConfig,
|
|
299
|
+
executor: this.executor,
|
|
300
|
+
assistantMessage: assistant_message,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* 构造并持久化一条 prompt user 消息。
|
|
306
|
+
*/
|
|
307
|
+
async create_and_persist_user_prompt_message(
|
|
308
|
+
input: AgentSessionPromptInput,
|
|
309
|
+
): Promise<SessionUserMessageV1> {
|
|
310
|
+
const message = this.history_store.userText({
|
|
311
|
+
text: String(input.query || "").trim(),
|
|
312
|
+
metadata: {
|
|
313
|
+
sessionId: this.session_id,
|
|
314
|
+
},
|
|
315
|
+
}) as SessionUserMessageV1;
|
|
316
|
+
await this.executor.appendUserMessage({
|
|
317
|
+
message,
|
|
318
|
+
});
|
|
319
|
+
await this.ensure_title_from_history({ generate: true });
|
|
320
|
+
await this.touch_metadata();
|
|
321
|
+
return message;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* 持久化本轮执行期间延迟写入的 user 消息。
|
|
326
|
+
*/
|
|
327
|
+
async persist_deferred_user_messages(
|
|
328
|
+
deferred_messages?: SessionUserMessageV1[],
|
|
329
|
+
): Promise<void> {
|
|
330
|
+
const normalized_messages = Array.isArray(deferred_messages)
|
|
331
|
+
? deferred_messages
|
|
332
|
+
: [];
|
|
333
|
+
if (normalized_messages.length <= 0) return;
|
|
334
|
+
for (const message of normalized_messages) {
|
|
335
|
+
await this.executor.appendUserMessage({
|
|
336
|
+
message,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
await this.touch_metadata();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionTurnService:本地 Session turn 编排服务。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - 统一管理 prompt actor 调度、turn 执行与 Session 事件流派发。
|
|
6
|
+
* - 该服务负责把 SessionPromptRuntime 与 Executor 连接起来。
|
|
7
|
+
* - metadata、title、assistant 结果持久化等状态副作用交由 SessionStateService 处理。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { extractTextFromUiMessage } from "@/executor/messages/UIMessageTransformer.js";
|
|
11
|
+
import type { Executor } from "@executor/Executor.js";
|
|
12
|
+
import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
|
|
13
|
+
import type {
|
|
14
|
+
AgentSessionSubscriber,
|
|
15
|
+
AgentSessionUnsubscribe,
|
|
16
|
+
} from "@/types/sdk/AgentSessionEvent.js";
|
|
17
|
+
import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
|
|
18
|
+
import type { AgentSessionTurnHandle } from "@/types/sdk/AgentSessionTurn.js";
|
|
19
|
+
import type {
|
|
20
|
+
SessionMessageV1,
|
|
21
|
+
SessionUserMessageV1,
|
|
22
|
+
} from "@/executor/types/SessionMessages.js";
|
|
23
|
+
import { mapAgentEventToSessionEvent, mapUiMessageChunkToAgentEvent } from "@/session/SessionEventMapper.js";
|
|
24
|
+
import { SessionEventHub } from "@/session/runtime/SessionEventHub.js";
|
|
25
|
+
import { SessionPromptRuntime } from "@/session/runtime/SessionPromptRuntime.js";
|
|
26
|
+
import type { SessionRunContext } from "@/types/executor/SessionRunContext.js";
|
|
27
|
+
import { SessionStateService } from "@/session/services/SessionStateService.js";
|
|
28
|
+
|
|
29
|
+
type SessionTurnServiceOptions = {
|
|
30
|
+
/**
|
|
31
|
+
* 当前 session 标识。
|
|
32
|
+
*/
|
|
33
|
+
session_id: string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 当前 session 执行器。
|
|
37
|
+
*/
|
|
38
|
+
executor: Executor;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 当前 session 状态服务。
|
|
42
|
+
*/
|
|
43
|
+
state_service: SessionStateService;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 当前 session 共享事件总线。
|
|
47
|
+
*/
|
|
48
|
+
event_hub: SessionEventHub;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 本地 Session turn 编排服务。
|
|
53
|
+
*/
|
|
54
|
+
export class SessionTurnService {
|
|
55
|
+
private readonly session_id: string;
|
|
56
|
+
private readonly executor: Executor;
|
|
57
|
+
private readonly state_service: SessionStateService;
|
|
58
|
+
private readonly event_hub: SessionEventHub;
|
|
59
|
+
private readonly prompt_runtime: SessionPromptRuntime;
|
|
60
|
+
|
|
61
|
+
constructor(options: SessionTurnServiceOptions) {
|
|
62
|
+
this.session_id = options.session_id;
|
|
63
|
+
this.executor = options.executor;
|
|
64
|
+
this.state_service = options.state_service;
|
|
65
|
+
this.event_hub = options.event_hub;
|
|
66
|
+
this.prompt_runtime = new SessionPromptRuntime({
|
|
67
|
+
sessionId: this.session_id,
|
|
68
|
+
publish: (event) => {
|
|
69
|
+
this.publish_event(event);
|
|
70
|
+
},
|
|
71
|
+
createAndPersistUserMessage: async (input) => {
|
|
72
|
+
return await this.state_service.create_and_persist_user_prompt_message(
|
|
73
|
+
input,
|
|
74
|
+
);
|
|
75
|
+
},
|
|
76
|
+
executeTurn: async ({ turnId, promptInput, onStepMerge }) => {
|
|
77
|
+
return await this.execute_prompt_turn({
|
|
78
|
+
turnId,
|
|
79
|
+
promptInput,
|
|
80
|
+
onStepMerge,
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 发布一条 session 事件。
|
|
88
|
+
*/
|
|
89
|
+
publish_event(event: AgentSessionEvent): void {
|
|
90
|
+
this.event_hub.publish(event);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 订阅当前 session 的未来事件。
|
|
95
|
+
*/
|
|
96
|
+
subscribe(subscriber: AgentSessionSubscriber): AgentSessionUnsubscribe {
|
|
97
|
+
return this.event_hub.subscribe(subscriber);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 判断当前 turn 调度器是否活跃。
|
|
102
|
+
*/
|
|
103
|
+
is_prompt_runtime_active(): boolean {
|
|
104
|
+
return this.prompt_runtime.isActive();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 追加一条新的 Session prompt。
|
|
109
|
+
*/
|
|
110
|
+
async prompt(input: AgentSessionPromptInput): Promise<AgentSessionTurnHandle> {
|
|
111
|
+
const query = String(input.query || "").trim();
|
|
112
|
+
if (!query) {
|
|
113
|
+
throw new Error("session.prompt requires a non-empty query");
|
|
114
|
+
}
|
|
115
|
+
await this.state_service.ensure_runnable();
|
|
116
|
+
return await this.prompt_runtime.prompt({
|
|
117
|
+
query,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 执行单轮 prompt turn。
|
|
123
|
+
*/
|
|
124
|
+
private async execute_prompt_turn(input: {
|
|
125
|
+
turnId: string;
|
|
126
|
+
promptInput: AgentSessionPromptInput;
|
|
127
|
+
onStepMerge: () => Promise<SessionUserMessageV1[]>;
|
|
128
|
+
}): Promise<{
|
|
129
|
+
text: string;
|
|
130
|
+
success: boolean;
|
|
131
|
+
assistantMessage: SessionMessageV1;
|
|
132
|
+
error?: string;
|
|
133
|
+
}> {
|
|
134
|
+
const tool_name_by_call_id = new Map<string, string>();
|
|
135
|
+
const run_context: SessionRunContext = {
|
|
136
|
+
sessionId: this.session_id,
|
|
137
|
+
onStepCallback: input.onStepMerge,
|
|
138
|
+
onAssistantStepCallback: async (step) => {
|
|
139
|
+
this.publish_event({
|
|
140
|
+
type: "assistant-step",
|
|
141
|
+
turnId: input.turnId,
|
|
142
|
+
text: step.text,
|
|
143
|
+
stepIndex: step.stepIndex,
|
|
144
|
+
...(step.visibility ? { visibility: step.visibility } : {}),
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
onUiMessageChunkCallback: async (chunk) => {
|
|
148
|
+
if (chunk.type === "tool-input-start") {
|
|
149
|
+
tool_name_by_call_id.set(chunk.toolCallId, chunk.toolName);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const event = mapUiMessageChunkToAgentEvent(chunk);
|
|
153
|
+
if (!event) return;
|
|
154
|
+
const resolved_event =
|
|
155
|
+
(
|
|
156
|
+
event.type === "tool-result" ||
|
|
157
|
+
event.type === "tool-error"
|
|
158
|
+
) &&
|
|
159
|
+
event.toolName === "unknown"
|
|
160
|
+
? {
|
|
161
|
+
...event,
|
|
162
|
+
toolName:
|
|
163
|
+
tool_name_by_call_id.get(event.toolCallId) || event.toolName,
|
|
164
|
+
}
|
|
165
|
+
: event;
|
|
166
|
+
if (
|
|
167
|
+
resolved_event.type === "tool-call" ||
|
|
168
|
+
resolved_event.type === "tool-error"
|
|
169
|
+
) {
|
|
170
|
+
tool_name_by_call_id.set(
|
|
171
|
+
resolved_event.toolCallId,
|
|
172
|
+
resolved_event.toolName,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
const session_event = mapAgentEventToSessionEvent({
|
|
176
|
+
event: resolved_event,
|
|
177
|
+
turnId: input.turnId,
|
|
178
|
+
});
|
|
179
|
+
if (session_event) {
|
|
180
|
+
this.publish_event(session_event);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
injectedUserMessages: [],
|
|
184
|
+
deferredPersistedUserMessages: [],
|
|
185
|
+
pendingAssistantFileParts: [],
|
|
186
|
+
};
|
|
187
|
+
const result = await this.executor.run({
|
|
188
|
+
query: input.promptInput.query,
|
|
189
|
+
runContext: run_context,
|
|
190
|
+
});
|
|
191
|
+
await this.state_service.persist_assistant_result(result.assistantMessage);
|
|
192
|
+
await this.state_service.persist_deferred_user_messages(
|
|
193
|
+
result.deferredPersistedUserMessages,
|
|
194
|
+
);
|
|
195
|
+
return {
|
|
196
|
+
text: extractTextFromUiMessage(result.assistantMessage),
|
|
197
|
+
success: result.success,
|
|
198
|
+
assistantMessage: result.assistantMessage,
|
|
199
|
+
...(result.error ? { error: result.error } : {}),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|