@ai-setting/roy-agent-core 1.4.13 → 1.4.15

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 (102) hide show
  1. package/dist/config/index.js +32 -0
  2. package/dist/env/agent/index.js +24 -0
  3. package/dist/env/commands/index.js +14 -0
  4. package/dist/env/debug/formatters/index.js +11 -0
  5. package/dist/env/debug/index.js +26 -0
  6. package/dist/env/hook/index.js +29 -0
  7. package/dist/env/index.js +81 -0
  8. package/dist/env/llm/index.js +40 -0
  9. package/dist/env/log-trace/index.js +83 -0
  10. package/dist/env/mcp/index.js +39 -0
  11. package/dist/env/mcp/tool/index.js +14 -0
  12. package/dist/env/memory/built-in/index.js +11 -0
  13. package/dist/env/memory/index.js +56 -0
  14. package/dist/env/memory/plugin/index.js +36 -0
  15. package/dist/env/prompt/index.js +20 -0
  16. package/dist/env/session/index.js +25 -0
  17. package/dist/env/session/storage/index.js +18 -0
  18. package/dist/env/skill/index.js +34 -0
  19. package/dist/env/skill/tool/index.js +9 -0
  20. package/dist/env/task/delegate/index.js +18 -0
  21. package/dist/env/task/hooks/index.js +7 -0
  22. package/dist/env/task/index.js +30 -0
  23. package/dist/env/task/plugins/index.js +23 -0
  24. package/dist/env/task/storage/index.js +14 -0
  25. package/dist/env/task/tools/index.js +17 -0
  26. package/dist/env/task/tools/operation/index.js +15 -0
  27. package/dist/{shared/chunk-1d4rwms4.js → env/tool/built-in/index.js} +4 -4
  28. package/dist/env/tool/index.js +39 -0
  29. package/dist/env/workflow/decorators/index.js +27 -0
  30. package/dist/env/workflow/engine/index.js +28 -0
  31. package/dist/env/workflow/index.js +132 -0
  32. package/dist/env/workflow/nodes/index.js +19 -0
  33. package/dist/env/workflow/service/index.js +13 -0
  34. package/dist/env/workflow/storage/index.js +27 -0
  35. package/dist/env/workflow/tools/index.js +159 -0
  36. package/dist/env/workflow/types/index.js +94 -0
  37. package/dist/env/workflow/utils/index.js +637 -0
  38. package/dist/index.js +233 -16386
  39. package/dist/shared/{chunk-2b5kbhx3.js → @ai-setting/roy-agent-core-0rtxwr28.js} +6 -114
  40. package/dist/shared/@ai-setting/roy-agent-core-0vbdz0x7.js +36 -0
  41. package/dist/shared/@ai-setting/roy-agent-core-12zkpda2.js +393 -0
  42. package/dist/shared/@ai-setting/roy-agent-core-1ce3fqrk.js +117 -0
  43. package/dist/shared/@ai-setting/roy-agent-core-2dhd60aw.js +11 -0
  44. package/dist/shared/@ai-setting/roy-agent-core-2kg2wma8.js +620 -0
  45. package/dist/shared/@ai-setting/roy-agent-core-2x0m2p66.js +851 -0
  46. package/dist/shared/@ai-setting/roy-agent-core-35x0wrtt.js +172 -0
  47. package/dist/shared/{chunk-1pf5mfgd.js → @ai-setting/roy-agent-core-37e4tep3.js} +2 -2
  48. package/dist/shared/@ai-setting/roy-agent-core-3agad0d9.js +603 -0
  49. package/dist/shared/@ai-setting/roy-agent-core-4arba14a.js +419 -0
  50. package/dist/shared/@ai-setting/roy-agent-core-4rqmfr7t.js +266 -0
  51. package/dist/shared/@ai-setting/roy-agent-core-4t40mkpv.js +206 -0
  52. package/dist/shared/@ai-setting/roy-agent-core-561b1c4p.js +377 -0
  53. package/dist/shared/@ai-setting/roy-agent-core-5xf65pz6.js +1305 -0
  54. package/dist/shared/@ai-setting/roy-agent-core-6a72jfdy.js +303 -0
  55. package/dist/shared/{chunk-1aakcfp1.js → @ai-setting/roy-agent-core-7f303ffd.js} +3 -3
  56. package/dist/shared/@ai-setting/roy-agent-core-7fgf85wc.js +284 -0
  57. package/dist/shared/{chunk-t1rh6jtm.js → @ai-setting/roy-agent-core-7n436rb4.js} +7 -12
  58. package/dist/shared/@ai-setting/roy-agent-core-7r85t0qn.js +492 -0
  59. package/dist/shared/@ai-setting/roy-agent-core-7rewcey6.js +862 -0
  60. package/dist/shared/@ai-setting/roy-agent-core-92z6t4he.js +14 -0
  61. package/dist/shared/@ai-setting/roy-agent-core-9qwp5qkz.js +1387 -0
  62. package/dist/shared/{chunk-mf5xqbdh.js → @ai-setting/roy-agent-core-9yxb3ty9.js} +3 -2
  63. package/dist/shared/@ai-setting/roy-agent-core-anwsxdds.js +1205 -0
  64. package/dist/shared/{chunk-1qwabsm0.js → @ai-setting/roy-agent-core-bncgx3gb.js} +1 -1
  65. package/dist/shared/@ai-setting/roy-agent-core-cd00w5mb.js +762 -0
  66. package/dist/shared/@ai-setting/roy-agent-core-cgs0j60t.js +442 -0
  67. package/dist/shared/@ai-setting/roy-agent-core-ctdhjv68.js +93 -0
  68. package/dist/shared/@ai-setting/roy-agent-core-dbsk841j.js +286 -0
  69. package/dist/shared/@ai-setting/roy-agent-core-e25xkv53.js +64 -0
  70. package/dist/shared/{chunk-yqmx37vm.js → @ai-setting/roy-agent-core-e5jcp24a.js} +2 -2
  71. package/dist/shared/@ai-setting/roy-agent-core-e62e2a5a.js +204 -0
  72. package/dist/shared/{chunk-g6j5n3gv.js → @ai-setting/roy-agent-core-ewrj1c4k.js} +2 -2
  73. package/dist/shared/{chunk-rncy3rtd.js → @ai-setting/roy-agent-core-fdb6m4e4.js} +119 -1113
  74. package/dist/shared/{chunk-q9j99fsm.js → @ai-setting/roy-agent-core-fv32jaa8.js} +3 -3
  75. package/dist/shared/@ai-setting/roy-agent-core-g1s2h0e5.js +171 -0
  76. package/dist/shared/@ai-setting/roy-agent-core-gmnkza34.js +202 -0
  77. package/dist/shared/@ai-setting/roy-agent-core-hz7rr4yx.js +513 -0
  78. package/dist/shared/@ai-setting/roy-agent-core-j3bbr2n0.js +378 -0
  79. package/dist/shared/{chunk-a9qmy3sc.js → @ai-setting/roy-agent-core-j3wc4465.js} +6 -3
  80. package/dist/shared/@ai-setting/roy-agent-core-jj79gszx.js +1130 -0
  81. package/dist/shared/@ai-setting/roy-agent-core-mwwk6req.js +913 -0
  82. package/dist/shared/{chunk-0q6s9wm6.js → @ai-setting/roy-agent-core-pc9g3962.js} +6 -50
  83. package/dist/shared/@ai-setting/roy-agent-core-psvxt4c9.js +60 -0
  84. package/dist/shared/@ai-setting/roy-agent-core-pzsg9pvf.js +393 -0
  85. package/dist/shared/{chunk-91bas8w5.js → @ai-setting/roy-agent-core-q779wnwm.js} +5 -5
  86. package/dist/shared/{chunk-25x2pdtp.js → @ai-setting/roy-agent-core-qw0ebh1d.js} +1 -1
  87. package/dist/shared/@ai-setting/roy-agent-core-qxhq8ven.js +57 -0
  88. package/dist/shared/@ai-setting/roy-agent-core-qxnbvgwe.js +66 -0
  89. package/dist/shared/@ai-setting/roy-agent-core-qya7seh6.js +408 -0
  90. package/dist/shared/@ai-setting/roy-agent-core-rbetrphj.js +97 -0
  91. package/dist/shared/@ai-setting/roy-agent-core-re1wjfw7.js +587 -0
  92. package/dist/shared/@ai-setting/roy-agent-core-rft3fmp0.js +14 -0
  93. package/dist/shared/@ai-setting/roy-agent-core-rvv6ydff.js +584 -0
  94. package/dist/shared/{chunk-ze20rksg.js → @ai-setting/roy-agent-core-rvxg1wps.js} +1 -1
  95. package/dist/shared/@ai-setting/roy-agent-core-rzp9kxne.js +341 -0
  96. package/dist/shared/@ai-setting/roy-agent-core-t94ktchq.js +213 -0
  97. package/dist/shared/@ai-setting/roy-agent-core-w78syn7w.js +788 -0
  98. package/dist/shared/{chunk-9qzt1v1p.js → @ai-setting/roy-agent-core-z2t8hse8.js} +3 -2
  99. package/package.json +8 -7
  100. package/dist/index.d.ts +0 -7825
  101. package/dist/shared/chunk-hs7tbmje.js +0 -24
  102. /package/dist/shared/{chunk-wbkh7wat.js → @ai-setting/roy-agent-core-fs0mn2jk.js} +0 -0
@@ -0,0 +1,1130 @@
1
+ import {
2
+ AskUserError,
3
+ init_workflow_hil
4
+ } from "./roy-agent-core-e25xkv53.js";
5
+ import {
6
+ ContextError
7
+ } from "./roy-agent-core-ctdhjv68.js";
8
+ import {
9
+ envKeyToConfigKey
10
+ } from "./roy-agent-core-qxhq8ven.js";
11
+ import {
12
+ BaseComponent
13
+ } from "./roy-agent-core-rbetrphj.js";
14
+ import {
15
+ SessionMessageConverter
16
+ } from "./roy-agent-core-e62e2a5a.js";
17
+ import {
18
+ TracedAs,
19
+ init_decorator
20
+ } from "./roy-agent-core-35x0wrtt.js";
21
+ import {
22
+ createLogger,
23
+ init_logger
24
+ } from "./roy-agent-core-j3wc4465.js";
25
+ import {
26
+ __legacyDecorateClassTS
27
+ } from "./roy-agent-core-fs0mn2jk.js";
28
+
29
+ // src/env/agent/agent-component.ts
30
+ init_logger();
31
+ import { z } from "zod";
32
+
33
+ // src/env/agent/agent-config-registration.ts
34
+ var AGENT_DEFAULTS = {
35
+ "agent.defaultAgent.maxIterations": 200,
36
+ "agent.defaultAgent.temperature": 0,
37
+ "agent.defaultAgent.timeout": 300000,
38
+ "agent.defaultAgent.streaming": false,
39
+ "agent.defaultAgent.filterHistory": false
40
+ };
41
+ var AGENT_CONFIG_REGISTRATION = {
42
+ name: "agent",
43
+ sources: [
44
+ { type: "env", envPrefix: "AGENT", priority: 20, watch: false }
45
+ ],
46
+ keys: [
47
+ { key: "agent.defaultAgent.model", sources: ["env", "file"] },
48
+ { key: "agent.defaultAgent.maxIterations", sources: ["env", "file"] },
49
+ { key: "agent.defaultAgent.temperature", sources: ["env", "file"] },
50
+ { key: "agent.defaultAgent.timeout", sources: ["env", "file"] },
51
+ { key: "agent.defaultAgent.systemPrompt", sources: ["env", "file"] },
52
+ { key: "agent.defaultAgent.streaming", sources: ["env", "file"] },
53
+ { key: "agent.defaultAgent.tools", sources: ["env", "file"] },
54
+ { key: "agent.defaultAgent.maxErrorRetries", sources: ["env", "file"] },
55
+ { key: "agent.defaultAgent.filterHistory", sources: ["env", "file"] }
56
+ ]
57
+ };
58
+
59
+ // src/env/agent/agent-component.ts
60
+ init_decorator();
61
+ init_workflow_hil();
62
+ var logger = createLogger("agent:component");
63
+ function toLLMMessage(msg) {
64
+ let content;
65
+ let toolCallId;
66
+ let toolName;
67
+ let toolCalls;
68
+ if (typeof msg.content === "string") {
69
+ content = msg.content;
70
+ if (msg.role === "tool") {
71
+ toolCallId = msg.toolCallId;
72
+ toolName = msg.toolName;
73
+ }
74
+ if (msg.role === "assistant" && msg.toolCalls) {
75
+ toolCalls = msg.toolCalls;
76
+ }
77
+ } else if (Array.isArray(msg.content)) {
78
+ if (msg.role === "tool") {
79
+ const toolResult = msg.content.find((part) => part.type === "tool-result");
80
+ const output = toolResult?.output;
81
+ if (typeof output === "string") {
82
+ content = output;
83
+ } else if (output && typeof output === "object" && "value" in output) {
84
+ content = output.value?.toString() || "";
85
+ } else {
86
+ content = JSON.stringify(output) || "";
87
+ }
88
+ toolCallId = toolResult?.toolCallId;
89
+ toolName = toolResult?.toolName;
90
+ } else {
91
+ const textParts = msg.content.filter((part) => part.type === "text");
92
+ const toolCallParts = msg.content.filter((part) => part.type === "tool-call");
93
+ content = textParts.map((part) => part.text || "").join("");
94
+ if (msg.role === "assistant" && toolCallParts.length > 0) {
95
+ toolCalls = toolCallParts.map((part) => {
96
+ const argsString = typeof part.input === "string" ? part.input : JSON.stringify(part.input || {});
97
+ const toolName2 = part.toolName || "unknown";
98
+ return {
99
+ id: part.toolCallId,
100
+ name: toolName2,
101
+ arguments: argsString,
102
+ function: {
103
+ name: toolName2,
104
+ arguments: argsString
105
+ }
106
+ };
107
+ });
108
+ }
109
+ }
110
+ } else {
111
+ content = "";
112
+ }
113
+ return {
114
+ role: msg.role,
115
+ content,
116
+ ...toolCallId ? { toolCallId } : {},
117
+ ...toolName ? { name: toolName } : {},
118
+ ...toolCalls && toolCalls.length > 0 ? { toolCalls } : {}
119
+ };
120
+ }
121
+ var DEFAULT_AGENT_CONFIG = {
122
+ type: "primary",
123
+ maxIterations: 200,
124
+ maxErrorRetries: 3,
125
+ doomLoopThreshold: 5,
126
+ toolTimeout: 60000,
127
+ toolRetries: 3,
128
+ filterHistory: false
129
+ };
130
+ var AgentInstanceSchema = z.object({
131
+ type: z.enum(["primary", "sub"]).default("primary"),
132
+ systemPrompt: z.string().optional(),
133
+ behaviorSpecId: z.string().optional(),
134
+ model: z.string().optional(),
135
+ maxIterations: z.number().default(200),
136
+ maxErrorRetries: z.number().default(3),
137
+ doomLoopThreshold: z.number().default(5),
138
+ allowedTools: z.array(z.string()).optional(),
139
+ deniedTools: z.array(z.string()).optional(),
140
+ toolTimeout: z.number().default(60000),
141
+ toolRetries: z.number().default(3),
142
+ filterHistory: z.boolean().default(false)
143
+ });
144
+ var AgentComponentConfigSchema = z.object({
145
+ defaultAgent: AgentInstanceSchema
146
+ });
147
+
148
+ class AgentComponent extends BaseComponent {
149
+ name = "agent";
150
+ version = "1.0.0";
151
+ agents = new Map;
152
+ config;
153
+ llmComponent = null;
154
+ toolComponent = null;
155
+ aborted = new Map;
156
+ abortControllers = new Map;
157
+ defaultTools = [];
158
+ doomLoopCaches = new Map;
159
+ configComponent;
160
+ configWatcher;
161
+ messageConverter = new SessionMessageConverter;
162
+ _constructorConfig;
163
+ runCounter = 0;
164
+ constructor(options = {}) {
165
+ super();
166
+ this._constructorConfig = options.config;
167
+ this.config = {
168
+ defaultAgent: {
169
+ ...DEFAULT_AGENT_CONFIG,
170
+ ...options.config?.defaultAgent
171
+ }
172
+ };
173
+ }
174
+ async init(config) {
175
+ await super.init(config);
176
+ const options = config.options;
177
+ if (!options?.configComponent) {
178
+ throw new Error("ConfigComponent is required for AgentComponent initialization");
179
+ }
180
+ this.configComponent = options.configComponent;
181
+ await this.registerConfig(options);
182
+ this.setStatus("running");
183
+ }
184
+ async registerConfig(options) {
185
+ const configComponent = options.configComponent;
186
+ if (!configComponent)
187
+ return;
188
+ const { configPath, envPrefix, config } = options;
189
+ const prefix = envPrefix ?? "AGENT";
190
+ configComponent.registerComponent(AGENT_CONFIG_REGISTRATION);
191
+ if (configPath) {
192
+ configComponent.registerSource({
193
+ type: "file",
194
+ relativePath: configPath,
195
+ optional: true,
196
+ watch: false
197
+ });
198
+ }
199
+ configComponent.registerSource({
200
+ type: "env",
201
+ envPrefix: prefix,
202
+ priority: 20,
203
+ watch: false
204
+ });
205
+ await configComponent.load("agent");
206
+ for (const envKey of Object.keys(process.env)) {
207
+ const configKey = envKeyToConfigKey(envKey, prefix, "agent");
208
+ if (!configKey)
209
+ continue;
210
+ const value = process.env[envKey];
211
+ if (value !== undefined) {
212
+ await configComponent.set(configKey, value);
213
+ }
214
+ }
215
+ for (const [key, value] of Object.entries(AGENT_DEFAULTS)) {
216
+ if (configComponent.get(key) === undefined) {
217
+ await configComponent.set(key, value);
218
+ }
219
+ }
220
+ if (config) {
221
+ const flatConfig = this.flattenConfig(config);
222
+ for (const [key, value] of Object.entries(flatConfig)) {
223
+ await configComponent.set(key, value);
224
+ }
225
+ }
226
+ const constructorDefaultAgent = this._constructorConfig?.defaultAgent;
227
+ this.config.defaultAgent = {
228
+ maxIterations: constructorDefaultAgent?.maxIterations ?? configComponent.get("agent.defaultAgent.maxIterations") ?? 200,
229
+ maxErrorRetries: constructorDefaultAgent?.maxErrorRetries ?? configComponent.get("agent.defaultAgent.maxErrorRetries") ?? 3,
230
+ doomLoopThreshold: constructorDefaultAgent?.doomLoopThreshold ?? configComponent.get("agent.defaultAgent.doomLoopThreshold") ?? 5,
231
+ toolTimeout: constructorDefaultAgent?.toolTimeout ?? configComponent.get("agent.defaultAgent.toolTimeout") ?? 60000,
232
+ toolRetries: constructorDefaultAgent?.toolRetries ?? configComponent.get("agent.defaultAgent.toolRetries") ?? 3,
233
+ filterHistory: constructorDefaultAgent?.filterHistory ?? configComponent.get("agent.defaultAgent.filterHistory") ?? false,
234
+ type: constructorDefaultAgent?.type ?? configComponent.get("agent.defaultAgent.type") ?? "primary",
235
+ systemPrompt: constructorDefaultAgent?.systemPrompt ?? configComponent.get("agent.defaultAgent.systemPrompt"),
236
+ model: constructorDefaultAgent?.model ?? configComponent.get("agent.defaultAgent.model"),
237
+ behaviorSpecId: constructorDefaultAgent?.behaviorSpecId ?? configComponent.get("agent.defaultAgent.behaviorSpecId")
238
+ };
239
+ logger.info(`[registerConfig] Synced config from ConfigComponent: maxIterations=${this.config.defaultAgent.maxIterations}`);
240
+ this.registerConfigWatcher(configComponent);
241
+ }
242
+ flattenConfig(obj, prefix = "agent") {
243
+ const result = {};
244
+ for (const [key, value] of Object.entries(obj)) {
245
+ const fullKey = `${prefix}.${key}`;
246
+ if (value && typeof value === "object" && !Array.isArray(value)) {
247
+ Object.assign(result, this.flattenConfig(value, fullKey));
248
+ } else {
249
+ result[fullKey] = value;
250
+ }
251
+ }
252
+ return result;
253
+ }
254
+ registerConfigWatcher(configComponent) {
255
+ if (typeof configComponent.watch !== "function") {
256
+ return;
257
+ }
258
+ this.configWatcher = configComponent.watch("agent.*", (event) => {
259
+ this.onConfigChange(event);
260
+ });
261
+ }
262
+ onConfigChange(event) {
263
+ logger.info(`Agent config changed: ${event.key}`, {
264
+ oldValue: event.oldValue,
265
+ newValue: event.newValue
266
+ });
267
+ }
268
+ async onStop() {
269
+ logger.info("[AgentComponent] Stopping and cleaning up resources...");
270
+ for (const [name, agent] of this.agents) {
271
+ if (agent.status === "running" || agent.status === "idle") {
272
+ this.abort(name);
273
+ logger.debug(`[AgentComponent] Aborted agent: ${name}`);
274
+ }
275
+ }
276
+ this.abortControllers.clear();
277
+ this.doomLoopCaches.clear();
278
+ if (this.configWatcher) {
279
+ this.configWatcher();
280
+ this.configWatcher = undefined;
281
+ }
282
+ this.agents.clear();
283
+ this.setStatus("stopped");
284
+ logger.info("[AgentComponent] Cleanup completed");
285
+ }
286
+ refreshDependencies() {
287
+ if (this.env) {
288
+ const llm = this.env.getComponent("llm");
289
+ const tool = this.env.getComponent("tool");
290
+ this.llmComponent = llm ? llm : null;
291
+ this.toolComponent = tool ? tool : null;
292
+ logger.debug("[refreshDependencies] AgentComponent refreshed", {
293
+ hasLLM: !!this.llmComponent,
294
+ hasTool: !!this.toolComponent
295
+ });
296
+ }
297
+ }
298
+ getAgent(agentName) {
299
+ return this.agents.get(agentName);
300
+ }
301
+ listAgents() {
302
+ return Array.from(this.agents.values());
303
+ }
304
+ addRemainingToolResults(ctx, allToolCalls, processedCount, reason) {
305
+ const remainingToolCalls = allToolCalls.slice(processedCount);
306
+ for (const tc of remainingToolCalls) {
307
+ const tcName = tc.function?.name || tc.name || "unknown";
308
+ this.pushMessage(ctx, {
309
+ role: "tool",
310
+ content: [{
311
+ type: "tool-result",
312
+ toolCallId: tc.id,
313
+ toolName: tcName,
314
+ output: JSON.stringify({ error: reason })
315
+ }]
316
+ });
317
+ }
318
+ }
319
+ registerAgent(name, config) {
320
+ const mergedConfig = {
321
+ type: config.type ?? this.config.defaultAgent.type,
322
+ name,
323
+ maxIterations: config.maxIterations ?? this.config.defaultAgent.maxIterations,
324
+ maxErrorRetries: config.maxErrorRetries ?? this.config.defaultAgent.maxErrorRetries,
325
+ doomLoopThreshold: config.doomLoopThreshold ?? this.config.defaultAgent.doomLoopThreshold,
326
+ toolTimeout: config.toolTimeout ?? this.config.defaultAgent.toolTimeout,
327
+ toolRetries: config.toolRetries ?? this.config.defaultAgent.toolRetries,
328
+ systemPrompt: config.systemPrompt ?? this.config.defaultAgent.systemPrompt,
329
+ model: config.model ?? this.config.defaultAgent.model,
330
+ behaviorSpecId: config.behaviorSpecId ?? this.config.defaultAgent.behaviorSpecId,
331
+ allowedTools: config.allowedTools ?? this.config.defaultAgent.allowedTools,
332
+ deniedTools: config.deniedTools ?? this.config.defaultAgent.deniedTools,
333
+ filterHistory: config.filterHistory ?? this.config.defaultAgent.filterHistory
334
+ };
335
+ const instance = {
336
+ name,
337
+ config: mergedConfig,
338
+ status: "idle",
339
+ plugins: new Map
340
+ };
341
+ this.agents.set(name, instance);
342
+ logger.info(`Agent registered: ${name}`, { type: instance.config.type });
343
+ return instance;
344
+ }
345
+ unregisterAgent(name) {
346
+ const deleted = this.agents.delete(name);
347
+ if (deleted) {
348
+ logger.info(`Agent unregistered: ${name}`);
349
+ }
350
+ return deleted;
351
+ }
352
+ registerPlugin(agentName, plugin) {
353
+ const agent = this.agents.get(agentName);
354
+ if (!agent) {
355
+ throw new Error(`Agent not found: ${agentName}`);
356
+ }
357
+ agent.plugins.set(plugin.name, plugin);
358
+ logger.info(`Plugin registered: ${plugin.name} to ${agentName}`, {
359
+ hooks: plugin.hooks.map((h) => h.point)
360
+ });
361
+ }
362
+ unregisterPlugin(agentName, pluginName) {
363
+ const agent = this.agents.get(agentName);
364
+ if (!agent) {
365
+ return false;
366
+ }
367
+ const deleted = agent.plugins.delete(pluginName);
368
+ if (deleted) {
369
+ logger.info(`Plugin unregistered: ${pluginName} from ${agentName}`);
370
+ }
371
+ return deleted;
372
+ }
373
+ setDefaultTools(tools) {
374
+ this.defaultTools = tools;
375
+ }
376
+ getAvailableTools(agent, context) {
377
+ let tools = [...this.defaultTools];
378
+ logger.debug(`[getAvailableTools] After defaultTools: ${tools.length} tools`, {
379
+ toolNames: tools.map((t) => t.name)
380
+ });
381
+ if (this.toolComponent?.listTools) {
382
+ const componentTools = this.toolComponent.listTools();
383
+ tools = [...tools, ...componentTools];
384
+ logger.debug(`[getAvailableTools] After adding componentTools: ${tools.length} tools`, {
385
+ componentToolNames: componentTools.map((t) => t.name)
386
+ });
387
+ }
388
+ const allowedTools = context?.allowedTools ?? agent.config.allowedTools;
389
+ const deniedTools = context?.deniedTools ?? agent.config.deniedTools;
390
+ logger.debug(`[getAvailableTools] Filtering: allowed=${allowedTools}, denied=${deniedTools}`);
391
+ if (allowedTools?.length) {
392
+ tools = tools.filter((t) => allowedTools.includes(t.name));
393
+ logger.debug(`[getAvailableTools] After allowedTools filter: ${tools.length} tools`, {
394
+ toolNames: tools.map((t) => t.name)
395
+ });
396
+ }
397
+ if (deniedTools?.length) {
398
+ tools = tools.filter((t) => !deniedTools.includes(t.name));
399
+ logger.debug(`[getAvailableTools] After deniedTools filter: ${tools.length} tools`, {
400
+ toolNames: tools.map((t) => t.name)
401
+ });
402
+ }
403
+ logger.debug(`[getAvailableTools] Final tools: ${tools.length}`, {
404
+ toolNames: tools.map((t) => t.name)
405
+ });
406
+ return tools;
407
+ }
408
+ async run(agentName, query, context) {
409
+ return this._run(agentName, query, context);
410
+ }
411
+ pushMessage(hookCtx, message) {
412
+ hookCtx.messages.push(message);
413
+ this.notifyMessageAdded(message);
414
+ }
415
+ async _run(agentName, query, context) {
416
+ this.refreshDependencies();
417
+ const agent = this.getAgent(agentName);
418
+ if (!agent) {
419
+ throw new Error(`Agent not found: ${agentName}`);
420
+ }
421
+ const runId = `${agentName}:${++this.runCounter}`;
422
+ logger.info(`Starting agent run: ${agentName} (runId=${runId})`, { query: query.substring(0, 100) });
423
+ agent.status = "running";
424
+ this.aborted.set(runId, false);
425
+ const abortController = new AbortController;
426
+ this.abortControllers.set(runId, abortController);
427
+ if (!this.doomLoopCaches.has(runId)) {
428
+ this.doomLoopCaches.set(runId, new Map);
429
+ }
430
+ const effectiveContext = {
431
+ ...context,
432
+ agentType: agent.config.type,
433
+ model: agent.config.model,
434
+ abort: abortController.signal
435
+ };
436
+ const result = {
437
+ iterations: 0,
438
+ toolCalls: []
439
+ };
440
+ const hookCtx = {
441
+ agent,
442
+ iteration: 0,
443
+ maxIterations: agent.config.maxIterations,
444
+ messages: [],
445
+ tools: this.getAvailableTools(agent, effectiveContext),
446
+ systemPrompt: agent.config.systemPrompt || "You are a helpful assistant.",
447
+ context: effectiveContext
448
+ };
449
+ let historyMessageCount = 0;
450
+ if (effectiveContext.sessionId) {
451
+ try {
452
+ const sessionComponent = this.env.getComponent("session");
453
+ if (sessionComponent) {
454
+ const filterHistory = effectiveContext.filterHistory ?? agent.config.filterHistory ?? false;
455
+ const messages = await this.getConversationHistory(sessionComponent, effectiveContext.sessionId, { minUserMessages: 100, filterHistory });
456
+ hookCtx.messages = messages.map((msg) => this.messageConverter.toModelMessage(msg));
457
+ historyMessageCount = hookCtx.messages.length;
458
+ }
459
+ } catch (err) {
460
+ logger.warn(`Failed to load session history: ${err}`);
461
+ }
462
+ }
463
+ this.pushEnvEvent({
464
+ type: "agent.start",
465
+ payload: {
466
+ sessionId: effectiveContext.sessionId,
467
+ model: effectiveContext.model
468
+ }
469
+ });
470
+ this.pushMessage(hookCtx, {
471
+ role: "user",
472
+ content: query
473
+ });
474
+ await this.executePluginHooks(agent, "agent:before.start", hookCtx);
475
+ if (hookCtx._stopped) {
476
+ return this.finalizeResult(result, hookCtx);
477
+ }
478
+ let iteration = 0;
479
+ let finalText;
480
+ while (iteration < agent.config.maxIterations) {
481
+ if (hookCtx._stopped) {
482
+ break;
483
+ }
484
+ if (this.aborted.get(runId)) {
485
+ hookCtx._stopped = true;
486
+ hookCtx._stopReason = "aborted";
487
+ break;
488
+ }
489
+ if (effectiveContext.abort?.aborted) {
490
+ hookCtx._stopped = true;
491
+ hookCtx._stopReason = "abort_signal";
492
+ break;
493
+ }
494
+ iteration++;
495
+ hookCtx.iteration = iteration;
496
+ result.iterations = iteration;
497
+ logger.debug(`Iteration ${iteration} started`);
498
+ this.doomLoopCaches.set(runId, new Map);
499
+ hookCtx.maxIterations = agent.config.maxIterations;
500
+ try {
501
+ logger.debug(`[ReAct] Iteration ${iteration} buildMessages result: ${hookCtx.messages.length} messages`);
502
+ await this.executePluginHooks(agent, "agent:before.llm", hookCtx);
503
+ if (hookCtx._stopped)
504
+ break;
505
+ const llmOutput = await this.invokeLLM(hookCtx);
506
+ hookCtx.llmOutput = llmOutput;
507
+ if (this.aborted.get(runId) || effectiveContext.abort?.aborted) {
508
+ hookCtx._stopped = true;
509
+ hookCtx._stopReason = "aborted";
510
+ break;
511
+ }
512
+ await this.executePluginHooks(agent, "agent:after.llm", hookCtx);
513
+ if (hookCtx._stopped)
514
+ break;
515
+ if (llmOutput.content && !llmOutput.toolCalls?.length) {
516
+ if (this.aborted.get(runId) || effectiveContext.abort?.aborted) {
517
+ hookCtx._stopped = true;
518
+ hookCtx._stopReason = "aborted";
519
+ break;
520
+ }
521
+ finalText = llmOutput.content;
522
+ this.pushMessage(hookCtx, {
523
+ role: "assistant",
524
+ content: llmOutput.content
525
+ });
526
+ break;
527
+ }
528
+ if (llmOutput.toolCalls?.length) {
529
+ const assistantParts = [];
530
+ if (llmOutput.content) {
531
+ assistantParts.push({
532
+ type: "text",
533
+ text: llmOutput.content
534
+ });
535
+ }
536
+ if (llmOutput.reasoning) {
537
+ assistantParts.push({
538
+ type: "reasoning",
539
+ text: llmOutput.reasoning,
540
+ reasoningType: "core"
541
+ });
542
+ }
543
+ for (const tc of llmOutput.toolCalls) {
544
+ let argsStr = "";
545
+ let argsObj = {};
546
+ if (tc.function?.arguments) {
547
+ if (typeof tc.function.arguments === "string") {
548
+ argsStr = tc.function.arguments;
549
+ try {
550
+ argsObj = JSON.parse(argsStr);
551
+ } catch {
552
+ argsObj = { _raw: argsStr };
553
+ }
554
+ } else {
555
+ argsObj = tc.function.arguments;
556
+ argsStr = JSON.stringify(argsObj);
557
+ }
558
+ } else if (tc.arguments) {
559
+ if (typeof tc.arguments === "string") {
560
+ argsStr = tc.arguments;
561
+ try {
562
+ argsObj = JSON.parse(argsStr);
563
+ } catch {
564
+ argsObj = { _raw: argsStr };
565
+ }
566
+ } else {
567
+ argsObj = tc.arguments;
568
+ argsStr = JSON.stringify(argsObj);
569
+ }
570
+ }
571
+ assistantParts.push({
572
+ type: "tool-call",
573
+ toolCallId: tc.id,
574
+ toolName: tc.function?.name || tc.name || "unknown",
575
+ input: argsObj,
576
+ toolCall: {
577
+ name: tc.function?.name || tc.name || "unknown",
578
+ arguments: argsStr
579
+ }
580
+ });
581
+ }
582
+ const assistantContent = llmOutput.content?.substring(0, 80) || "(no text)";
583
+ const toolCallNames = llmOutput.toolCalls?.map((tc) => tc.function?.name || tc.name).join(", ") || "none";
584
+ logger.debug(`[ReAct] Iteration ${iteration} Adding assistant message: text="${assistantContent}" toolCalls=[${toolCallNames}]`);
585
+ this.pushMessage(hookCtx, {
586
+ role: "assistant",
587
+ content: assistantParts
588
+ });
589
+ const allToolCalls = llmOutput.toolCalls;
590
+ let processedCount = 0;
591
+ for (const toolCall of allToolCalls) {
592
+ if (this.aborted.get(runId) || effectiveContext.abort?.aborted) {
593
+ hookCtx._stopped = true;
594
+ hookCtx._stopReason = "aborted";
595
+ this.addRemainingToolResults(hookCtx, allToolCalls, processedCount, "Execution aborted");
596
+ break;
597
+ }
598
+ const func = toolCall.function;
599
+ const tcName = func?.name || toolCall.name || "unknown";
600
+ const tcArgs = func?.arguments ? typeof func.arguments === "string" ? JSON.parse(func.arguments) : func.arguments : toolCall.arguments;
601
+ hookCtx.currentToolCall = {
602
+ id: toolCall.id,
603
+ name: tcName,
604
+ arguments: tcArgs
605
+ };
606
+ const doomKey = `${tcName}:${JSON.stringify(tcArgs)}`;
607
+ const agentCache = this.doomLoopCaches.get(runId) || new Map;
608
+ const doomCount = agentCache.get(doomKey) || 0;
609
+ if (doomCount >= agent.config.doomLoopThreshold) {
610
+ hookCtx.error = new Error(`Doom loop detected: ${tcName}`);
611
+ await this.executePluginHooks(agent, "on.error", hookCtx);
612
+ result.error = hookCtx.error.message;
613
+ this.addRemainingToolResults(hookCtx, allToolCalls, processedCount, "Execution aborted: Doom loop detected");
614
+ break;
615
+ }
616
+ agentCache.set(doomKey, doomCount + 1);
617
+ this.doomLoopCaches.set(runId, agentCache);
618
+ await this.executePluginHooks(agent, "agent:before.tool", hookCtx);
619
+ if (hookCtx._stopped) {
620
+ this.addRemainingToolResults(hookCtx, allToolCalls, processedCount, "Execution aborted by plugin hook");
621
+ break;
622
+ }
623
+ const toolResult = await this.executeTool(hookCtx);
624
+ hookCtx.toolResult = toolResult;
625
+ await this.executePluginHooks(agent, "agent:after.tool", hookCtx);
626
+ if (hookCtx._stopped) {
627
+ this.addRemainingToolResults(hookCtx, allToolCalls, processedCount + 1, "Execution aborted by plugin hook");
628
+ break;
629
+ }
630
+ const toolOutput = toolResult.success ? toolResult.result.output || "" : toolResult.result.error || "Unknown error";
631
+ const toolOutputPreview = typeof toolOutput === "string" ? toolOutput.substring(0, 50) : JSON.stringify(toolOutput).substring(0, 50);
632
+ logger.debug(`[ReAct] Iteration ${iteration} Adding tool message: tool=${toolResult.name} output="${toolOutputPreview}..."`);
633
+ this.pushMessage(hookCtx, {
634
+ role: "tool",
635
+ content: [{
636
+ type: "tool-result",
637
+ toolCallId: hookCtx.currentToolCall.id,
638
+ toolName: toolResult.name,
639
+ output: toolOutput
640
+ }]
641
+ });
642
+ result.toolCalls.push(hookCtx.currentToolCall);
643
+ processedCount++;
644
+ }
645
+ await this.executePluginHooks(agent, "agent:on.iteration", hookCtx);
646
+ }
647
+ } catch (error) {
648
+ logger.error(`Iteration ${iteration} error`, { error });
649
+ hookCtx.error = error instanceof Error ? error : new Error(String(error));
650
+ if (error instanceof Error && error instanceof ContextError && error.llmOutput) {
651
+ const llmOutput = error.llmOutput;
652
+ if (llmOutput.toolCalls?.length) {
653
+ const assistantParts = [];
654
+ if (llmOutput.content) {
655
+ assistantParts.push({
656
+ type: "text",
657
+ text: llmOutput.content
658
+ });
659
+ }
660
+ if (llmOutput.reasoning) {
661
+ assistantParts.push({
662
+ type: "reasoning",
663
+ text: llmOutput.reasoning,
664
+ reasoningType: "core"
665
+ });
666
+ }
667
+ for (const tc of llmOutput.toolCalls) {
668
+ assistantParts.push({
669
+ type: "tool-call",
670
+ toolCallId: tc.id,
671
+ toolName: tc.function?.name || tc.name || "unknown",
672
+ input: typeof tc.function?.arguments === "string" ? JSON.parse(tc.function.arguments) : tc.arguments || {}
673
+ });
674
+ }
675
+ this.pushMessage(hookCtx, {
676
+ role: "assistant",
677
+ content: assistantParts
678
+ });
679
+ } else if (llmOutput.content) {
680
+ const assistantParts = [];
681
+ if (llmOutput.content) {
682
+ assistantParts.push({
683
+ type: "text",
684
+ text: llmOutput.content
685
+ });
686
+ }
687
+ if (llmOutput.reasoning) {
688
+ assistantParts.push({
689
+ type: "reasoning",
690
+ text: llmOutput.reasoning,
691
+ reasoningType: "core"
692
+ });
693
+ }
694
+ this.pushMessage(hookCtx, {
695
+ role: "assistant",
696
+ content: assistantParts.length > 0 ? assistantParts : llmOutput.content
697
+ });
698
+ }
699
+ }
700
+ await this.executePluginHooks(agent, "agent:on.error", hookCtx);
701
+ if (!hookCtx._stopped) {
702
+ hookCtx._stopped = true;
703
+ if (error instanceof AskUserError) {
704
+ hookCtx._stopReason = "ask-user";
705
+ if (hookCtx.currentToolCall) {
706
+ this.pushMessage(hookCtx, {
707
+ role: "tool",
708
+ content: [{
709
+ type: "tool-result",
710
+ toolCallId: hookCtx.currentToolCall.id,
711
+ toolName: "ask_user",
712
+ output: JSON.stringify({
713
+ error: "AskUserError",
714
+ query: error.query,
715
+ message: error.message
716
+ })
717
+ }]
718
+ });
719
+ }
720
+ const errorInfo = {
721
+ query: error.query,
722
+ sessionId: error.sessionId,
723
+ nodeId: error.nodeId,
724
+ nodeType: error.nodeType
725
+ };
726
+ result.error = `__ASK_USER_ERROR__:${JSON.stringify(errorInfo)}`;
727
+ } else {
728
+ result.error = hookCtx.error.message;
729
+ if (error?.name === "AbortError") {
730
+ hookCtx._stopReason = hookCtx._stopReason || "aborted";
731
+ } else {
732
+ hookCtx._stopReason = "error";
733
+ }
734
+ if (hookCtx.currentToolCall) {
735
+ this.pushMessage(hookCtx, {
736
+ role: "tool",
737
+ content: [{
738
+ type: "tool-result",
739
+ toolCallId: hookCtx.currentToolCall.id,
740
+ toolName: hookCtx.currentToolCall.name,
741
+ output: JSON.stringify({ error: hookCtx.error.message })
742
+ }]
743
+ });
744
+ }
745
+ }
746
+ } else {
747
+ result.error = hookCtx.error.message;
748
+ if (hookCtx.currentToolCall) {
749
+ const errorMsg = hookCtx.error?.message || "Execution interrupted";
750
+ this.pushMessage(hookCtx, {
751
+ role: "tool",
752
+ content: [{
753
+ type: "tool-result",
754
+ toolCallId: hookCtx.currentToolCall.id,
755
+ toolName: hookCtx.currentToolCall.name,
756
+ output: JSON.stringify({ error: errorMsg })
757
+ }]
758
+ });
759
+ }
760
+ }
761
+ break;
762
+ }
763
+ }
764
+ result.finalText = finalText;
765
+ if (iteration >= agent.config.maxIterations && !result.finalText) {
766
+ result.finalText = "Maximum iterations reached.";
767
+ }
768
+ const reactContext = {
769
+ messages: hookCtx.messages,
770
+ sessionId: effectiveContext.sessionId,
771
+ summary: result.finalText
772
+ };
773
+ await this.executePluginHooks(agent, "agent:after.react", {
774
+ ...hookCtx,
775
+ ...reactContext
776
+ });
777
+ await this.executePluginHooks(agent, "agent:after.complete", hookCtx);
778
+ if (this.aborted.get(runId) === true || hookCtx._stopped) {
779
+ agent.status = "stopped";
780
+ } else {
781
+ agent.status = "idle";
782
+ }
783
+ this.aborted.delete(runId);
784
+ this.abortControllers.delete(runId);
785
+ if (result.error) {
786
+ this.pushEnvEvent({
787
+ type: "agent.error",
788
+ payload: {
789
+ error: result.error,
790
+ iterations: result.iterations,
791
+ stopReason: result.stopReason
792
+ }
793
+ });
794
+ } else {
795
+ this.pushEnvEvent({
796
+ type: "agent.completed",
797
+ payload: {
798
+ finalText: result.finalText,
799
+ iterations: result.iterations,
800
+ stopReason: result.stopReason
801
+ }
802
+ });
803
+ }
804
+ let newMessages = hookCtx.messages.slice(historyMessageCount);
805
+ logger.info(`Agent run completed: ${agentName}`, {
806
+ iterations: result.iterations,
807
+ hasError: !!result.error,
808
+ hookCtxMessages: hookCtx.messages.length,
809
+ historyMessageCount,
810
+ sessionId: effectiveContext.sessionId
811
+ });
812
+ await this.recordSessionMessages(effectiveContext.sessionId, newMessages);
813
+ return this.finalizeResult(result, hookCtx);
814
+ }
815
+ abort(agentName) {
816
+ for (const key of this.aborted.keys()) {
817
+ if (key.startsWith(agentName + ":")) {
818
+ this.aborted.set(key, true);
819
+ }
820
+ }
821
+ for (const [key, controller] of this.abortControllers) {
822
+ if (key.startsWith(agentName + ":")) {
823
+ controller.abort();
824
+ logger.debug(`[abort] AbortController.abort() called for run: ${key}`);
825
+ }
826
+ }
827
+ logger.info(`Agent aborted: ${agentName}`);
828
+ }
829
+ async buildMessages(ctx) {
830
+ const messages = [];
831
+ if (ctx.systemPrompt) {
832
+ messages.push({
833
+ role: "system",
834
+ content: ctx.systemPrompt
835
+ });
836
+ }
837
+ if (ctx.additionInfo) {
838
+ messages.push({
839
+ role: "user",
840
+ content: `额外信息:
841
+ ${ctx.additionInfo}`
842
+ });
843
+ }
844
+ messages.push(...ctx.messages);
845
+ return messages;
846
+ }
847
+ async invokeLLM(ctx) {
848
+ logger.debug("[invokeLLM] Starting LLM invocation");
849
+ if (this.llmComponent?.invoke) {
850
+ const messages = await this.buildMessages(ctx);
851
+ const convertedMessages = messages.map(toLLMMessage);
852
+ logger.debug(`[invokeLLM] Calling LLMComponent.invoke with ${convertedMessages.length} messages`);
853
+ try {
854
+ const result = await this.llmComponent.invoke({
855
+ messages: convertedMessages,
856
+ tools: ctx.tools.map((t) => ({
857
+ name: t.name,
858
+ description: t.description || "",
859
+ parameters: t.parameters ?? {}
860
+ })),
861
+ model: ctx.context.model,
862
+ context: {
863
+ sessionId: ctx.context.sessionId,
864
+ messageId: ctx.context.messageId
865
+ },
866
+ abortSignal: ctx.context.abort
867
+ });
868
+ logger.debug("[invokeLLM] LLMComponent.invoke returned successfully");
869
+ return {
870
+ content: result.output?.content || "",
871
+ reasoning: result.output?.reasoning,
872
+ toolCalls: result.output?.toolCalls?.map((tc) => ({
873
+ id: tc.id,
874
+ function: tc.function ? {
875
+ name: tc.function.name,
876
+ arguments: typeof tc.function.arguments === "string" ? tc.function.arguments : JSON.stringify(tc.function.arguments)
877
+ } : undefined,
878
+ name: tc.name,
879
+ arguments: tc.arguments
880
+ })),
881
+ finishReason: result.output?.finishReason
882
+ };
883
+ } catch (error) {
884
+ logger.error("[invokeLLM] LLMComponent.invoke threw an error:", error);
885
+ throw error;
886
+ }
887
+ }
888
+ logger.warn("[invokeLLM] No LLMComponent available, using mock");
889
+ return {
890
+ content: "Mock response: Hello!",
891
+ finishReason: "stop"
892
+ };
893
+ }
894
+ async executeTool(ctx) {
895
+ const toolCall = ctx.currentToolCall;
896
+ const toolName = toolCall.function?.name || toolCall.name || "unknown";
897
+ logger.debug(`[executeTool] Looking for tool: "${toolName}"`);
898
+ logger.debug(`[executeTool] Available tools: [${ctx.tools.map((t) => t.name).join(", ")}]`);
899
+ const tool = ctx.tools.find((t) => t.name === toolName);
900
+ if (!tool) {
901
+ this.pushEnvEvent({
902
+ type: "tool.error",
903
+ payload: {
904
+ error: `Tool not found: ${toolName}`,
905
+ toolName
906
+ }
907
+ });
908
+ return {
909
+ id: toolCall.id,
910
+ name: toolName,
911
+ success: false,
912
+ result: {
913
+ success: false,
914
+ output: "",
915
+ error: `Tool not found: ${toolName}`
916
+ }
917
+ };
918
+ }
919
+ try {
920
+ const toolContext = {
921
+ session_id: ctx.context.sessionId,
922
+ message_id: ctx.context.messageId,
923
+ abort: ctx.context.abort,
924
+ workdir: ctx.context.metadata?.workdir,
925
+ metadata: ctx.context.metadata
926
+ };
927
+ const request = {
928
+ name: toolName,
929
+ args: toolCall.arguments,
930
+ context: toolContext
931
+ };
932
+ let result;
933
+ if (this.toolComponent?.execute) {
934
+ result = await this.toolComponent.execute(request);
935
+ } else {
936
+ logger.debug(`[executeTool] No ToolComponent available, executing tool directly`);
937
+ result = await tool.execute(toolCall.arguments, toolContext);
938
+ }
939
+ this.pushEnvEvent({
940
+ type: "tool.result",
941
+ payload: {
942
+ id: toolCall.id,
943
+ name: toolName,
944
+ result,
945
+ success: result.success
946
+ }
947
+ });
948
+ return {
949
+ id: toolCall.id,
950
+ name: toolName,
951
+ success: result.success,
952
+ result
953
+ };
954
+ } catch (error) {
955
+ if (error instanceof AskUserError) {
956
+ throw error;
957
+ }
958
+ this.pushEnvEvent({
959
+ type: "tool.error",
960
+ payload: {
961
+ error: error instanceof Error ? error.message : String(error),
962
+ toolName
963
+ }
964
+ });
965
+ return {
966
+ id: toolCall.id,
967
+ name: toolName,
968
+ success: false,
969
+ result: {
970
+ success: false,
971
+ output: "",
972
+ error: error instanceof Error ? error.message : String(error)
973
+ }
974
+ };
975
+ }
976
+ }
977
+ async executePluginHooks(agent, point, ctx) {
978
+ const hooks = [];
979
+ for (const [name, plugin] of agent.plugins) {
980
+ for (const hook of plugin.hooks) {
981
+ if (hook.point === point) {
982
+ hooks.push({
983
+ plugin,
984
+ priority: hook.priority ?? 0,
985
+ execute: plugin.execute
986
+ });
987
+ }
988
+ }
989
+ }
990
+ hooks.sort((a, b) => b.priority - a.priority);
991
+ for (const { plugin, execute } of hooks) {
992
+ try {
993
+ const result = await execute(ctx);
994
+ if (!result.continue) {
995
+ ctx._stopped = true;
996
+ ctx._stopReason = `Plugin ${plugin.name} stopped execution`;
997
+ logger.info(`Hook ${point} stopped by plugin ${plugin.name}`);
998
+ break;
999
+ }
1000
+ if (result.action) {
1001
+ await this.handleHookAction(result.action, ctx);
1002
+ }
1003
+ } catch (error) {
1004
+ logger.error(`Hook ${point} error in plugin ${plugin.name}`, { error });
1005
+ ctx._errors = ctx._errors || [];
1006
+ ctx._errors.push({
1007
+ plugin: plugin.name,
1008
+ error: error instanceof Error ? error.message : String(error)
1009
+ });
1010
+ }
1011
+ }
1012
+ }
1013
+ async handleHookAction(action, ctx) {
1014
+ switch (action.type) {
1015
+ case "stop":
1016
+ ctx._stopped = true;
1017
+ ctx._stopReason = "stopped_by_hook";
1018
+ break;
1019
+ case "inject_message":
1020
+ if (action.payload && typeof action.payload === "object") {
1021
+ const msg = action.payload;
1022
+ ctx.messages.push(msg);
1023
+ }
1024
+ break;
1025
+ case "skip_tool":
1026
+ ctx._pendingAction = action;
1027
+ break;
1028
+ }
1029
+ }
1030
+ notifyMessageAdded(message) {
1031
+ logger.debug(`Message added: ${message.role}`);
1032
+ }
1033
+ finalizeResult(result, ctx) {
1034
+ return {
1035
+ ...result,
1036
+ stopped: ctx._stopped,
1037
+ stopReason: ctx._stopReason
1038
+ };
1039
+ }
1040
+ async recordSessionMessages(sessionId, allMessages = []) {
1041
+ if (!sessionId) {
1042
+ return;
1043
+ }
1044
+ try {
1045
+ const sessionComponent = this.env.getComponent("session");
1046
+ if (!sessionComponent) {
1047
+ logger.warn("SessionComponent not found, skipping session recording");
1048
+ return;
1049
+ }
1050
+ for (const msg of allMessages) {
1051
+ if (msg.role === "system") {
1052
+ continue;
1053
+ }
1054
+ if (msg.role === "assistant" || msg.role === "tool") {
1055
+ if (this.isEmptyMessage(msg.content)) {
1056
+ continue;
1057
+ }
1058
+ }
1059
+ await sessionComponent.addMessage(sessionId, this.messageConverter.fromModelMessage(msg, { sessionID: sessionId }));
1060
+ }
1061
+ } catch (err) {
1062
+ logger.warn(`Failed to record session messages: ${err}`);
1063
+ }
1064
+ }
1065
+ isEmptyMessage(content) {
1066
+ if (content === null || content === undefined) {
1067
+ return true;
1068
+ }
1069
+ if (typeof content === "string" && content.trim() === "") {
1070
+ return true;
1071
+ }
1072
+ if (Array.isArray(content) && content.length === 0) {
1073
+ return true;
1074
+ }
1075
+ return false;
1076
+ }
1077
+ pushEnvEvent(event) {
1078
+ if (this.env && "pushEnvEvent" in this.env) {
1079
+ try {
1080
+ const fullEvent = {
1081
+ id: `evt_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
1082
+ type: event.type,
1083
+ timestamp: Date.now(),
1084
+ metadata: {
1085
+ source: "agent",
1086
+ agent_name: this.name
1087
+ },
1088
+ payload: event.payload
1089
+ };
1090
+ this.env?.pushEnvEvent(fullEvent);
1091
+ } catch (err) {
1092
+ logger.warn(`[pushEnvEvent] Failed to push event: ${err}`);
1093
+ }
1094
+ }
1095
+ }
1096
+ async getConversationHistory(sessionComponent, sessionId, options = {}) {
1097
+ const minUserMessages = options.minUserMessages ?? 100;
1098
+ const filterHistory = options.filterHistory ?? false;
1099
+ const ctx = await sessionComponent.getContext(sessionId, {
1100
+ fullHistory: false,
1101
+ minUserMessages
1102
+ });
1103
+ let messages = ctx.messages;
1104
+ if (filterHistory) {
1105
+ messages = messages.filter((msg) => {
1106
+ if (msg.metadata?.type === "tool_call" || msg.metadata?.type === "tool_result") {
1107
+ return false;
1108
+ }
1109
+ return msg.role === "user" || msg.role === "assistant";
1110
+ });
1111
+ }
1112
+ return messages;
1113
+ }
1114
+ }
1115
+ __legacyDecorateClassTS([
1116
+ TracedAs("agent.component.run", { recordParams: true, recordResult: true, log: true })
1117
+ ], AgentComponent.prototype, "_run", null);
1118
+ __legacyDecorateClassTS([
1119
+ TracedAs("agent.component.invokeLLM", { recordParams: true, recordResult: true, log: true })
1120
+ ], AgentComponent.prototype, "invokeLLM", null);
1121
+ __legacyDecorateClassTS([
1122
+ TracedAs("agent.component.executeTool", { recordParams: true, recordResult: true, log: true })
1123
+ ], AgentComponent.prototype, "executeTool", null);
1124
+ __legacyDecorateClassTS([
1125
+ TracedAs("agent.component.recordSessionMessages", { recordParams: true, recordResult: true, log: true })
1126
+ ], AgentComponent.prototype, "recordSessionMessages", null);
1127
+ __legacyDecorateClassTS([
1128
+ TracedAs("agent.component.getConversationHistory", { recordParams: true, recordResult: true, log: true })
1129
+ ], AgentComponent.prototype, "getConversationHistory", null);
1130
+ export { AgentComponentConfigSchema, AgentComponent };