@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.
Files changed (173) hide show
  1. package/README.md +1 -1
  2. package/bin/agent/local/Agent.d.ts +8 -121
  3. package/bin/agent/local/Agent.d.ts.map +1 -1
  4. package/bin/agent/local/Agent.js +63 -381
  5. package/bin/agent/local/Agent.js.map +1 -1
  6. package/bin/agent/local/AgentRuntimeFactory.d.ts +2 -2
  7. package/bin/agent/local/AgentRuntimeFactory.d.ts.map +1 -1
  8. package/bin/agent/local/AgentRuntimeFactory.js +2 -23
  9. package/bin/agent/local/AgentRuntimeFactory.js.map +1 -1
  10. package/bin/agent/local/services/AgentAssemblyService.d.ts +112 -0
  11. package/bin/agent/local/services/AgentAssemblyService.d.ts.map +1 -0
  12. package/bin/agent/local/services/AgentAssemblyService.js +135 -0
  13. package/bin/agent/local/services/AgentAssemblyService.js.map +1 -0
  14. package/bin/agent/local/services/AgentLifecycleService.d.ts +59 -0
  15. package/bin/agent/local/services/AgentLifecycleService.d.ts.map +1 -0
  16. package/bin/agent/local/services/AgentLifecycleService.js +136 -0
  17. package/bin/agent/local/services/AgentLifecycleService.js.map +1 -0
  18. package/bin/agent/local/services/AgentSessionManager.d.ts +106 -0
  19. package/bin/agent/local/services/AgentSessionManager.d.ts.map +1 -0
  20. package/bin/agent/local/services/AgentSessionManager.js +182 -0
  21. package/bin/agent/local/services/AgentSessionManager.js.map +1 -0
  22. package/bin/executor/Executor.d.ts +7 -24
  23. package/bin/executor/Executor.d.ts.map +1 -1
  24. package/bin/executor/Executor.js +73 -361
  25. package/bin/executor/Executor.js.map +1 -1
  26. package/bin/executor/SessionRunScope.d.ts +18 -34
  27. package/bin/executor/SessionRunScope.d.ts.map +1 -1
  28. package/bin/executor/SessionRunScope.js +42 -28
  29. package/bin/executor/SessionRunScope.js.map +1 -1
  30. package/bin/executor/composer/context/LocalSessionContextComposer.d.ts +5 -3
  31. package/bin/executor/composer/context/LocalSessionContextComposer.d.ts.map +1 -1
  32. package/bin/executor/composer/context/LocalSessionContextComposer.js +11 -18
  33. package/bin/executor/composer/context/LocalSessionContextComposer.js.map +1 -1
  34. package/bin/executor/composer/context/SessionContextComposer.d.ts +8 -3
  35. package/bin/executor/composer/context/SessionContextComposer.d.ts.map +1 -1
  36. package/bin/executor/composer/system/SessionSystemComposer.d.ts +2 -1
  37. package/bin/executor/composer/system/SessionSystemComposer.d.ts.map +1 -1
  38. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.d.ts +2 -1
  39. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.d.ts.map +1 -1
  40. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.js +2 -4
  41. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.js.map +1 -1
  42. package/bin/executor/core-engine/CoreEngineRunner.d.ts +62 -0
  43. package/bin/executor/core-engine/CoreEngineRunner.d.ts.map +1 -0
  44. package/bin/executor/core-engine/CoreEngineRunner.js +309 -0
  45. package/bin/executor/core-engine/CoreEngineRunner.js.map +1 -0
  46. package/bin/executor/core-engine/CoreEngineUiStreamCollector.d.ts +5 -0
  47. package/bin/executor/core-engine/CoreEngineUiStreamCollector.d.ts.map +1 -1
  48. package/bin/executor/core-engine/CoreEngineUiStreamCollector.js +2 -4
  49. package/bin/executor/core-engine/CoreEngineUiStreamCollector.js.map +1 -1
  50. package/bin/executor/services/ExecutorInflightService.d.ts +39 -0
  51. package/bin/executor/services/ExecutorInflightService.d.ts.map +1 -0
  52. package/bin/executor/services/ExecutorInflightService.js +75 -0
  53. package/bin/executor/services/ExecutorInflightService.js.map +1 -0
  54. package/bin/executor/services/ExecutorRecoveryPolicy.d.ts +103 -0
  55. package/bin/executor/services/ExecutorRecoveryPolicy.d.ts.map +1 -0
  56. package/bin/executor/services/ExecutorRecoveryPolicy.js +87 -0
  57. package/bin/executor/services/ExecutorRecoveryPolicy.js.map +1 -0
  58. package/bin/executor/tools/plugin/PluginToolBridge.d.ts +19 -0
  59. package/bin/executor/tools/plugin/PluginToolBridge.d.ts.map +1 -0
  60. package/bin/executor/tools/plugin/PluginToolBridge.js +143 -0
  61. package/bin/executor/tools/plugin/PluginToolBridge.js.map +1 -0
  62. package/bin/executor/tools/plugin/PluginToolDefinition.d.ts +32 -0
  63. package/bin/executor/tools/plugin/PluginToolDefinition.d.ts.map +1 -0
  64. package/bin/executor/tools/plugin/PluginToolDefinition.js +27 -0
  65. package/bin/executor/tools/plugin/PluginToolDefinition.js.map +1 -0
  66. package/bin/executor/tools/plugin/PluginToolSchemas.d.ts +14 -0
  67. package/bin/executor/tools/plugin/PluginToolSchemas.d.ts.map +1 -0
  68. package/bin/executor/tools/plugin/PluginToolSchemas.js +19 -0
  69. package/bin/executor/tools/plugin/PluginToolSchemas.js.map +1 -0
  70. package/bin/executor/tools/plugin/types/PluginTool.d.ts +39 -0
  71. package/bin/executor/tools/plugin/types/PluginTool.d.ts.map +1 -0
  72. package/bin/executor/tools/plugin/types/PluginTool.js +9 -0
  73. package/bin/executor/tools/plugin/types/PluginTool.js.map +1 -0
  74. package/bin/executor/tools/shell/ShellToolBridge.js +3 -3
  75. package/bin/executor/tools/shell/ShellToolBridge.js.map +1 -1
  76. package/bin/executor/types/SessionRun.d.ts +18 -0
  77. package/bin/executor/types/SessionRun.d.ts.map +1 -1
  78. package/bin/index.d.ts +10 -1
  79. package/bin/index.d.ts.map +1 -1
  80. package/bin/index.js +3 -0
  81. package/bin/index.js.map +1 -1
  82. package/bin/plugin/core/BasePlugin.d.ts +2 -2
  83. package/bin/plugin/core/BasePlugin.d.ts.map +1 -1
  84. package/bin/plugin/core/BasePlugin.js.map +1 -1
  85. package/bin/plugin/core/ImagePlugin.d.ts +56 -0
  86. package/bin/plugin/core/ImagePlugin.d.ts.map +1 -0
  87. package/bin/plugin/core/ImagePlugin.js +109 -0
  88. package/bin/plugin/core/ImagePlugin.js.map +1 -0
  89. package/bin/session/Session.d.ts +14 -83
  90. package/bin/session/Session.d.ts.map +1 -1
  91. package/bin/session/Session.js +139 -362
  92. package/bin/session/Session.js.map +1 -1
  93. package/bin/session/SessionSystemBuilder.d.ts +2 -1
  94. package/bin/session/SessionSystemBuilder.d.ts.map +1 -1
  95. package/bin/session/SessionSystemBuilder.js +2 -3
  96. package/bin/session/SessionSystemBuilder.js.map +1 -1
  97. package/bin/session/services/SessionStateService.d.ts +132 -0
  98. package/bin/session/services/SessionStateService.d.ts.map +1 -0
  99. package/bin/session/services/SessionStateService.js +242 -0
  100. package/bin/session/services/SessionStateService.js.map +1 -0
  101. package/bin/session/services/SessionTurnService.d.ts +66 -0
  102. package/bin/session/services/SessionTurnService.d.ts.map +1 -0
  103. package/bin/session/services/SessionTurnService.js +137 -0
  104. package/bin/session/services/SessionTurnService.js.map +1 -0
  105. package/bin/session/services/SessionViewService.d.ts +105 -0
  106. package/bin/session/services/SessionViewService.d.ts.map +1 -0
  107. package/bin/session/services/SessionViewService.js +184 -0
  108. package/bin/session/services/SessionViewService.js.map +1 -0
  109. package/bin/types/agent/AgentOptions.d.ts +18 -0
  110. package/bin/types/agent/AgentOptions.d.ts.map +1 -1
  111. package/bin/types/agent/AgentTypes.d.ts +3 -1
  112. package/bin/types/agent/AgentTypes.d.ts.map +1 -1
  113. package/bin/types/agent/SessionTypes.d.ts.map +1 -1
  114. package/bin/types/executor/SessionRunContext.d.ts +66 -0
  115. package/bin/types/executor/SessionRunContext.d.ts.map +1 -0
  116. package/bin/types/executor/SessionRunContext.js +10 -0
  117. package/bin/types/executor/SessionRunContext.js.map +1 -0
  118. package/bin/types/plugin/ImagePlugin.d.ts +94 -0
  119. package/bin/types/plugin/ImagePlugin.d.ts.map +1 -0
  120. package/bin/types/plugin/ImagePlugin.js +10 -0
  121. package/bin/types/plugin/ImagePlugin.js.map +1 -0
  122. package/bin/types/session/SessionComposerOptions.d.ts +90 -0
  123. package/bin/types/session/SessionComposerOptions.d.ts.map +1 -0
  124. package/bin/types/session/SessionComposerOptions.js +10 -0
  125. package/bin/types/session/SessionComposerOptions.js.map +1 -0
  126. package/bin/types/session/SessionLocalState.d.ts +35 -0
  127. package/bin/types/session/SessionLocalState.d.ts.map +1 -0
  128. package/bin/types/session/SessionLocalState.js +10 -0
  129. package/bin/types/session/SessionLocalState.js.map +1 -0
  130. package/bin/types/session/SessionOptions.d.ts +85 -0
  131. package/bin/types/session/SessionOptions.d.ts.map +1 -0
  132. package/bin/types/session/SessionOptions.js +10 -0
  133. package/bin/types/session/SessionOptions.js.map +1 -0
  134. package/package.json +1 -1
  135. package/src/agent/local/Agent.ts +74 -433
  136. package/src/agent/local/AgentRuntimeFactory.ts +4 -25
  137. package/src/agent/local/services/AgentAssemblyService.ts +268 -0
  138. package/src/agent/local/services/AgentLifecycleService.ts +187 -0
  139. package/src/agent/local/services/AgentSessionManager.ts +291 -0
  140. package/src/executor/Executor.ts +103 -441
  141. package/src/executor/README.md +4 -4
  142. package/src/executor/SessionRunScope.ts +47 -71
  143. package/src/executor/composer/context/LocalSessionContextComposer.ts +24 -20
  144. package/src/executor/composer/context/SessionContextComposer.ts +13 -3
  145. package/src/executor/composer/system/SessionSystemComposer.ts +2 -1
  146. package/src/executor/composer/system/default/DefaultSessionSystemComposer.ts +3 -4
  147. package/src/executor/core-engine/CoreEngineRunner.ts +433 -0
  148. package/src/executor/core-engine/CoreEngineUiStreamCollector.ts +7 -5
  149. package/src/executor/services/ExecutorInflightService.ts +101 -0
  150. package/src/executor/services/ExecutorRecoveryPolicy.ts +213 -0
  151. package/src/executor/tools/plugin/PluginToolBridge.ts +161 -0
  152. package/src/executor/tools/plugin/PluginToolDefinition.ts +32 -0
  153. package/src/executor/tools/plugin/PluginToolSchemas.ts +20 -0
  154. package/src/executor/tools/plugin/types/PluginTool.ts +41 -0
  155. package/src/executor/tools/shell/ShellToolBridge.ts +3 -3
  156. package/src/executor/types/SessionRun.ts +20 -0
  157. package/src/index.ts +33 -0
  158. package/src/plugin/core/BasePlugin.ts +2 -2
  159. package/src/plugin/core/ImagePlugin.ts +128 -0
  160. package/src/session/Session.ts +178 -485
  161. package/src/session/SessionSystemBuilder.ts +3 -3
  162. package/src/session/services/SessionStateService.ts +341 -0
  163. package/src/session/services/SessionTurnService.ts +202 -0
  164. package/src/session/services/SessionViewService.ts +301 -0
  165. package/src/types/agent/AgentOptions.ts +25 -0
  166. package/src/types/agent/AgentTypes.ts +10 -0
  167. package/src/types/agent/SessionTypes.ts +1 -0
  168. package/src/types/executor/SessionRunContext.ts +76 -0
  169. package/src/types/plugin/ImagePlugin.ts +103 -0
  170. package/src/types/session/SessionComposerOptions.ts +107 -0
  171. package/src/types/session/SessionLocalState.ts +40 -0
  172. package/src/types/session/SessionOptions.ts +99 -0
  173. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,268 @@
1
+ /**
2
+ * AgentAssemblyService:本地 Agent 装配服务。
3
+ *
4
+ * 关键点(中文)
5
+ * - 统一装配 logger、config、env、runtime、context、plugin registry 与 plugin port。
6
+ * - 该服务只负责一次性长期对象装配,不负责 session 缓存和生命周期启动。
7
+ * - session/lifecycle service 通过它暴露的长期对象协作,避免在 facade 中重复拼装。
8
+ */
9
+
10
+ import type { LanguageModel, Tool } from "ai";
11
+ import type { BasePlugin } from "@/plugin/core/BasePlugin.js";
12
+ import type { AgentContext } from "@/types/runtime/agent/AgentContext.js";
13
+ import type { AgentRuntime } from "@/types/runtime/agent/AgentRuntime.js";
14
+ import type { DowncityConfig } from "@/types/config/DowncityConfig.js";
15
+ import type { PluginPort } from "@/plugin/types/Plugin.js";
16
+ import type { AgentOptions } from "@/types/agent/AgentTypes.js";
17
+ import { Logger } from "@/utils/logger/Logger.js";
18
+ import { loadDowncityConfig, resolveAgentEnv } from "@/config/Config.js";
19
+ import { PluginRegistry } from "@/plugin/core/PluginRegistry.js";
20
+ import {
21
+ createFallbackSdkConfig,
22
+ normalizeInstructionInput,
23
+ } from "@/agent/local/AgentInstructions.js";
24
+ import {
25
+ createAgentPluginPort,
26
+ createAgentPluginRegistry,
27
+ } from "@/agent/local/AgentPluginFactory.js";
28
+ import {
29
+ createAgentContext,
30
+ createAgentRuntime,
31
+ } from "@/agent/local/AgentRuntimeFactory.js";
32
+ import { setShellToolRuntime } from "@executor/tools/shell/ShellToolDefinition.js";
33
+ import {
34
+ plugin_tools,
35
+ setPluginToolRuntime,
36
+ } from "@executor/tools/plugin/PluginToolDefinition.js";
37
+ import type { AgentManagedSession } from "@/types/agent/AgentTypes.js";
38
+ import type { SessionPort } from "@/types/runtime/agent/AgentContext.js";
39
+
40
+ type AgentAssemblyServiceOptions = {
41
+ /**
42
+ * 当前 agent 构造参数。
43
+ */
44
+ options: AgentOptions;
45
+
46
+ /**
47
+ * 读取当前已缓存的 session 实例。
48
+ */
49
+ list_cached_sessions: () => AgentManagedSession[];
50
+
51
+ /**
52
+ * 获取或创建 session runtime port。
53
+ */
54
+ get_session_port: (session_id: string) => SessionPort;
55
+
56
+ /**
57
+ * 解析指定 session 当前绑定的模型实例。
58
+ */
59
+ resolve_session_model: (
60
+ session_id: string,
61
+ ) => Promise<LanguageModel | undefined>;
62
+ };
63
+
64
+ /**
65
+ * 本地 Agent 装配结果。
66
+ */
67
+ export interface AgentAssemblyResult {
68
+ /**
69
+ * 当前 agent 稳定标识。
70
+ */
71
+ id: string;
72
+
73
+ /**
74
+ * 当前项目根目录。
75
+ */
76
+ path: string;
77
+
78
+ /**
79
+ * 当前 agent 默认工具集合。
80
+ */
81
+ tools: Record<string, Tool>;
82
+
83
+ /**
84
+ * 当前 agent 统一日志器。
85
+ */
86
+ logger: Logger;
87
+
88
+ /**
89
+ * 当前 agent 环境变量快照。
90
+ */
91
+ env: Record<string, string>;
92
+
93
+ /**
94
+ * 当前 agent 静态 instruction。
95
+ */
96
+ instruction: string[];
97
+
98
+ /**
99
+ * 当前解析后的项目配置。
100
+ */
101
+ config: DowncityConfig;
102
+
103
+ /**
104
+ * 当前 plugin 实例集合。
105
+ */
106
+ plugin_instances: Map<string, BasePlugin>;
107
+
108
+ /**
109
+ * 当前 plugin 注册表。
110
+ */
111
+ plugin_registry: PluginRegistry;
112
+
113
+ /**
114
+ * 当前对外 plugin 调用端口。
115
+ */
116
+ plugins: PluginPort;
117
+
118
+ /**
119
+ * 当前 agent runtime。
120
+ */
121
+ runtime: AgentRuntime;
122
+
123
+ /**
124
+ * 当前 agent context。
125
+ */
126
+ agent_context: AgentContext;
127
+ }
128
+
129
+ /**
130
+ * 本地 Agent 装配服务。
131
+ */
132
+ export class AgentAssemblyService {
133
+ private readonly options: AgentOptions;
134
+ private readonly list_cached_sessions: AgentAssemblyServiceOptions["list_cached_sessions"];
135
+ private readonly get_session_port: AgentAssemblyServiceOptions["get_session_port"];
136
+ private readonly resolve_session_model: AgentAssemblyServiceOptions["resolve_session_model"];
137
+
138
+ constructor(options: AgentAssemblyServiceOptions) {
139
+ this.options = options.options;
140
+ this.list_cached_sessions = options.list_cached_sessions;
141
+ this.get_session_port = options.get_session_port;
142
+ this.resolve_session_model = options.resolve_session_model;
143
+ }
144
+
145
+ /**
146
+ * 执行一次性长期对象装配。
147
+ */
148
+ assemble(): AgentAssemblyResult {
149
+ const id = String(this.options.id || "").trim();
150
+ const path = String(this.options.path || "").trim();
151
+ const tools =
152
+ this.options.tools && typeof this.options.tools === "object"
153
+ ? { ...this.options.tools }
154
+ : {};
155
+ if (!id) {
156
+ throw new Error("Agent requires a non-empty id");
157
+ }
158
+ if (!path) {
159
+ throw new Error("Agent requires a non-empty path");
160
+ }
161
+
162
+ const logger = new Logger();
163
+ logger.bindProjectRoot(path);
164
+ const env = resolveAgentEnv(path, this.options.env);
165
+ const instruction = normalizeInstructionInput(this.options.instruction);
166
+ const config = this.load_config(id, path);
167
+ const plugin_instances = new Map<string, BasePlugin>();
168
+
169
+ const runtime = createAgentRuntime({
170
+ agent_id: id,
171
+ project_root: path,
172
+ logger,
173
+ config,
174
+ env,
175
+ systems: instruction,
176
+ plugin_instances,
177
+ get_session_port: this.get_session_port,
178
+ list_cached_sessions: this.list_cached_sessions,
179
+ });
180
+
181
+ this.register_plugins(plugin_instances, runtime, this.options.plugins || []);
182
+
183
+ let agent_context!: AgentContext;
184
+ const plugin_registry = createAgentPluginRegistry({
185
+ plugins: [...plugin_instances.values()],
186
+ get_context: () => agent_context,
187
+ });
188
+ const plugins = createAgentPluginPort(plugin_registry);
189
+ if (this.should_register_plugin_call_tool(plugin_instances)) {
190
+ tools.plugin_call = tools.plugin_call || plugin_tools.plugin_call;
191
+ }
192
+ agent_context = createAgentContext({
193
+ runtime,
194
+ project_root: path,
195
+ logger,
196
+ config,
197
+ env,
198
+ systems: instruction,
199
+ plugin_instances,
200
+ plugins,
201
+ get_session_port: this.get_session_port,
202
+ resolve_session_model: async (session_id) =>
203
+ await this.resolve_session_model(session_id),
204
+ });
205
+ setShellToolRuntime(agent_context.invoke);
206
+ setPluginToolRuntime(plugins);
207
+
208
+ return {
209
+ id,
210
+ path,
211
+ tools,
212
+ logger,
213
+ env,
214
+ instruction,
215
+ config,
216
+ plugin_instances,
217
+ plugin_registry,
218
+ plugins,
219
+ runtime,
220
+ agent_context,
221
+ };
222
+ }
223
+
224
+ private load_config(agent_id: string, project_root: string): DowncityConfig {
225
+ try {
226
+ return loadDowncityConfig(project_root);
227
+ } catch {
228
+ return createFallbackSdkConfig(agent_id);
229
+ }
230
+ }
231
+
232
+ private register_plugins(
233
+ plugin_instances: Map<string, BasePlugin>,
234
+ runtime: AgentRuntime,
235
+ plugins: BasePlugin[],
236
+ ): void {
237
+ for (const plugin of plugins) {
238
+ const name = String(plugin?.name || "").trim();
239
+ if (!name) {
240
+ throw new Error("Agent received a plugin without a valid name");
241
+ }
242
+ if (plugin_instances.has(name)) {
243
+ throw new Error(`Duplicate plugin registration: ${name}`);
244
+ }
245
+ plugin.bindAgent(runtime);
246
+ plugin_instances.set(name, plugin);
247
+ }
248
+ }
249
+
250
+ /**
251
+ * 判断是否需要自动注册 plugin_call tool。
252
+ */
253
+ private should_register_plugin_call_tool(
254
+ plugin_instances: Map<string, BasePlugin>,
255
+ ): boolean {
256
+ for (const plugin of plugin_instances.values()) {
257
+ if (
258
+ plugin.actions &&
259
+ Object.keys(plugin.actions).some((action_name) =>
260
+ Boolean(String(action_name || "").trim()),
261
+ )
262
+ ) {
263
+ return true;
264
+ }
265
+ }
266
+ return false;
267
+ }
268
+ }
@@ -0,0 +1,187 @@
1
+ /**
2
+ * AgentLifecycleService:本地 Agent 生命周期服务。
3
+ *
4
+ * 关键点(中文)
5
+ * - 统一管理 plugins、ActionSchedule 与本机 RPC 的启动/停止。
6
+ * - 该服务只负责长期后台能力生命周期,不负责 session 构造与运行时装配。
7
+ * - facade 通过它暴露 `start()` / `stop()` 语义,避免生命周期状态散落在 Agent 主类中。
8
+ */
9
+
10
+ import type { AgentContext } from "@/types/runtime/agent/AgentContext.js";
11
+ import type {
12
+ AgentRpcBinding,
13
+ AgentRpcStartOptions,
14
+ AgentSessionCollection,
15
+ AgentStartOptions,
16
+ AgentStartResult,
17
+ AgentStopResult,
18
+ } from "@/types/agent/AgentTypes.js";
19
+ import type { Logger } from "@/utils/logger/Logger.js";
20
+ import type { ActionScheduleRuntimeHandle } from "@/plugin/core/ActionScheduleRuntime.js";
21
+ import { startActionScheduleRuntime } from "@/plugin/core/ActionScheduleRuntime.js";
22
+ import { startAllPlugins, stopAllPlugins } from "@/plugin/core/Manager.js";
23
+ import { startRpcServer } from "@/rpc/Server.js";
24
+ import type { AgentRuntime } from "@/types/runtime/agent/AgentRuntime.js";
25
+
26
+ type AgentLifecycleServiceOptions = {
27
+ /**
28
+ * 当前统一日志器。
29
+ */
30
+ logger: Logger;
31
+
32
+ /**
33
+ * 当前 agent context。
34
+ */
35
+ agent_context: AgentContext;
36
+
37
+ /**
38
+ * 当前 session collection。
39
+ */
40
+ session_collection: AgentSessionCollection;
41
+
42
+ /**
43
+ * 读取当前 agent runtime。
44
+ */
45
+ get_runtime: () => AgentRuntime;
46
+ };
47
+
48
+ /**
49
+ * 本地 Agent 生命周期服务。
50
+ */
51
+ export class AgentLifecycleService {
52
+ private readonly logger: Logger;
53
+ private readonly agent_context: AgentContext;
54
+ private readonly session_collection: AgentSessionCollection;
55
+ private readonly get_runtime: AgentLifecycleServiceOptions["get_runtime"];
56
+
57
+ private plugins_started = false;
58
+ private action_schedule_runtime: ActionScheduleRuntimeHandle | null = null;
59
+ private start_promise: Promise<AgentStartResult> | null = null;
60
+ private rpc_binding: AgentRpcBinding | null = null;
61
+
62
+ constructor(options: AgentLifecycleServiceOptions) {
63
+ this.logger = options.logger;
64
+ this.agent_context = options.agent_context;
65
+ this.session_collection = options.session_collection;
66
+ this.get_runtime = options.get_runtime;
67
+ }
68
+
69
+ /**
70
+ * 启动当前 agent 实例的长期运行能力。
71
+ */
72
+ async start(options?: AgentStartOptions): Promise<AgentStartResult> {
73
+ if (this.start_promise) {
74
+ return await this.start_promise;
75
+ }
76
+ this.start_promise = (async () => {
77
+ const should_start_plugins = options?.plugins !== false;
78
+ if (should_start_plugins) {
79
+ await this.ensure_plugins_started();
80
+ }
81
+ const rpc_binding =
82
+ options?.rpc === false || options?.rpc === undefined
83
+ ? undefined
84
+ : await this.start_rpc(options.rpc);
85
+ return {
86
+ ...(rpc_binding ? { rpc: rpc_binding } : {}),
87
+ pluginsStarted: this.plugins_started,
88
+ };
89
+ })();
90
+ try {
91
+ return await this.start_promise;
92
+ } catch (error) {
93
+ this.start_promise = null;
94
+ throw error;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * 停止当前 agent 实例的长期运行能力。
100
+ */
101
+ async stop(): Promise<AgentStopResult> {
102
+ const plugins_started = this.plugins_started;
103
+ const rpc_started = this.rpc_binding !== null;
104
+
105
+ if (plugins_started) {
106
+ await this.stop_action_schedule_runtime();
107
+ await stopAllPlugins(this.agent_context);
108
+ this.plugins_started = false;
109
+ }
110
+
111
+ if (rpc_started) {
112
+ await this.stop_rpc();
113
+ }
114
+
115
+ this.start_promise = null;
116
+
117
+ return {
118
+ rpcStopped: rpc_started,
119
+ pluginsStopped: plugins_started,
120
+ };
121
+ }
122
+
123
+ private async ensure_plugins_started(): Promise<void> {
124
+ if (this.plugins_started) return;
125
+ const lifecycle = await startAllPlugins(this.agent_context);
126
+ this.plugins_started = true;
127
+ for (const item of lifecycle.results) {
128
+ if (!item.success) {
129
+ this.logger.error(
130
+ `Plugin start failed: ${item.plugin?.name || "unknown"} - ${item.error || "unknown error"}`,
131
+ );
132
+ }
133
+ }
134
+ await this.ensure_action_schedule_runtime_started();
135
+ }
136
+
137
+ private async ensure_action_schedule_runtime_started(): Promise<void> {
138
+ if (this.action_schedule_runtime) return;
139
+ try {
140
+ this.action_schedule_runtime = await startActionScheduleRuntime(
141
+ this.agent_context,
142
+ );
143
+ } catch (error) {
144
+ this.logger.error(`ActionSchedule start failed: ${String(error)}`);
145
+ }
146
+ }
147
+
148
+ private async stop_action_schedule_runtime(): Promise<void> {
149
+ const runtime = this.action_schedule_runtime;
150
+ this.action_schedule_runtime = null;
151
+ runtime?.stop();
152
+ }
153
+
154
+ private async start_rpc(
155
+ options?: AgentRpcStartOptions,
156
+ ): Promise<AgentRpcBinding> {
157
+ if (this.rpc_binding) {
158
+ return this.rpc_binding;
159
+ }
160
+ const host = String(options?.host || "127.0.0.1").trim() || "127.0.0.1";
161
+ const port =
162
+ typeof options?.port === "number" && Number.isInteger(options.port)
163
+ ? options.port
164
+ : 15314;
165
+ const server = await startRpcServer({
166
+ host,
167
+ port,
168
+ sessionCollection: this.session_collection,
169
+ getAgentContext: () => this.agent_context,
170
+ getAgentRuntime: () => this.get_runtime(),
171
+ });
172
+ this.rpc_binding = {
173
+ url: `rpc://${host}:${port}`,
174
+ host,
175
+ port,
176
+ server,
177
+ };
178
+ return this.rpc_binding;
179
+ }
180
+
181
+ private async stop_rpc(): Promise<void> {
182
+ if (!this.rpc_binding) return;
183
+ const current = this.rpc_binding;
184
+ this.rpc_binding = null;
185
+ await current.server.stop();
186
+ }
187
+ }