@ai-setting/roy-agent-core 1.5.40 → 1.5.42

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.
@@ -522,7 +522,6 @@ ${content}`;
522
522
  sendLarkMessage(options) {
523
523
  return new Promise((resolve, reject) => {
524
524
  const { chatId, messageId, content } = options;
525
- const contentJson = JSON.stringify({ text: content });
526
525
  let args;
527
526
  if (messageId) {
528
527
  args = [
@@ -530,8 +529,8 @@ ${content}`;
530
529
  "+messages-reply",
531
530
  "--message-id",
532
531
  messageId,
533
- "--text",
534
- contentJson,
532
+ "--markdown",
533
+ content,
535
534
  "--as",
536
535
  "bot"
537
536
  ];
@@ -541,8 +540,8 @@ ${content}`;
541
540
  "+messages-send",
542
541
  "--chat-id",
543
542
  chatId,
544
- "--text",
545
- contentJson
543
+ "--markdown",
544
+ content
546
545
  ];
547
546
  }
548
547
  const proc = spawn("lark-cli", args, {
@@ -596,35 +595,38 @@ ${content}`;
596
595
  }
597
596
  }
598
597
  formatTaskCreated(task) {
599
- const lines = [
600
- `**标题**: ${task.title || "无标题"}`
601
- ];
598
+ const lines = [];
599
+ if (task.title) {
600
+ lines.push(`- **标题**: ${task.title}`);
601
+ }
602
602
  if (task.description) {
603
- lines.push(`**描述**: ${task.description.substring(0, 100)}${task.description.length > 100 ? "..." : ""}`);
603
+ const desc = task.description.substring(0, 100) + (task.description.length > 100 ? "..." : "");
604
+ lines.push(`- **描述**: ${desc}`);
604
605
  }
605
606
  if (task.priority) {
606
- lines.push(`**优先级**: ${task.priority}`);
607
+ lines.push(`- **优先级**: ${task.priority}`);
607
608
  }
608
609
  return lines.join(`
609
610
  `);
610
611
  }
611
612
  formatTaskUpdate(task, changes) {
612
- const lines = [
613
- `**标题**: ${task.title || "无标题"}`,
614
- `**ID**: ${task.id}`
615
- ];
613
+ const lines = [];
614
+ if (task.title) {
615
+ lines.push(`- **标题**: ${task.title}`);
616
+ }
617
+ lines.push(`- **ID**: ${task.id}`);
616
618
  if (changes?.status) {
617
- lines.push(`**状态**: ${changes.status}`);
619
+ lines.push(`- **状态**: ${changes.status}`);
618
620
  }
619
621
  if (changes?.progress !== undefined) {
620
- lines.push(`**进度**: ${changes.progress}%`);
622
+ lines.push(`- **进度**: ${changes.progress}%`);
621
623
  }
622
624
  if (changes?.current_status) {
623
- lines.push(`**当前状态**: ${changes.current_status}`);
625
+ lines.push(`- **当前状态**: ${changes.current_status}`);
624
626
  }
625
627
  const changeKeys = Object.keys(changes || {}).filter((k) => !["status", "progress", "current_status"].includes(k));
626
628
  if (changeKeys.length > 0) {
627
- lines.push(`**变更**: ${changeKeys.join(", ")}`);
629
+ lines.push(`- **变更**: ${changeKeys.join(", ")}`);
628
630
  }
629
631
  return lines.join(`
630
632
  `);
@@ -2,6 +2,9 @@ import {
2
2
  AskUserError,
3
3
  init_workflow_hil
4
4
  } from "./roy-agent-core-e25xkv53.js";
5
+ import {
6
+ AgentRegistry
7
+ } from "./roy-agent-core-7t05apnp.js";
5
8
  import {
6
9
  ContextError
7
10
  } from "./roy-agent-core-ctdhjv68.js";
@@ -166,6 +169,7 @@ class AgentComponent extends BaseComponent {
166
169
  configWatcher;
167
170
  messageConverter = new SessionMessageConverter;
168
171
  _constructorConfig;
172
+ registry;
169
173
  runCounter = 0;
170
174
  constructor(options = {}) {
171
175
  super();
@@ -185,6 +189,7 @@ class AgentComponent extends BaseComponent {
185
189
  }
186
190
  this.configComponent = options.configComponent;
187
191
  await this.registerConfig(options);
192
+ await this.initRegistry(options.configComponent);
188
193
  this.setStatus("running");
189
194
  }
190
195
  async registerConfig(options) {
@@ -271,6 +276,63 @@ class AgentComponent extends BaseComponent {
271
276
  newValue: event.newValue
272
277
  });
273
278
  }
279
+ async initRegistry(configComponent) {
280
+ try {
281
+ this.registry = new AgentRegistry({
282
+ configComponent,
283
+ resolvePromptComponent: () => this.env?.getComponent?.("prompt") ?? null
284
+ });
285
+ const loadedCount = await this.registry.load();
286
+ logger.info(`[AgentComponent] Loaded ${loadedCount} agents from config directory`);
287
+ for (const agentDef of this.registry.list()) {
288
+ if (!this.agents.has(agentDef.name)) {
289
+ const systemPrompt = await this.registry.getSystemPrompt(agentDef.name);
290
+ this.registerAgent(agentDef.name, {
291
+ type: agentDef.type,
292
+ systemPrompt,
293
+ allowedTools: agentDef.allowedTools,
294
+ deniedTools: agentDef.deniedTools,
295
+ model: agentDef.model,
296
+ maxIterations: agentDef.maxIterations
297
+ });
298
+ logger.debug(`[AgentComponent] Registered agent from config: ${agentDef.name}`);
299
+ }
300
+ }
301
+ } catch (error) {
302
+ logger.warn(`[AgentComponent] Failed to initialize AgentRegistry: ${error}`);
303
+ }
304
+ }
305
+ async syncRegistryAgentsFromConfig() {
306
+ if (!this.registry) {
307
+ return;
308
+ }
309
+ for (const agentDef of this.registry.list()) {
310
+ const systemPrompt = await this.registry.getSystemPrompt(agentDef.name);
311
+ const existing = this.agents.get(agentDef.name);
312
+ if (existing) {
313
+ existing.config.systemPrompt = systemPrompt;
314
+ } else {
315
+ this.registerAgent(agentDef.name, {
316
+ type: agentDef.type,
317
+ systemPrompt,
318
+ allowedTools: agentDef.allowedTools,
319
+ deniedTools: agentDef.deniedTools,
320
+ model: agentDef.model,
321
+ maxIterations: agentDef.maxIterations
322
+ });
323
+ }
324
+ logger.debug(`[AgentComponent] Synced registry agent: ${agentDef.name}`);
325
+ }
326
+ }
327
+ getRegistry() {
328
+ return this.registry;
329
+ }
330
+ getAgentFromRegistry(name) {
331
+ return this.registry?.get(name);
332
+ }
333
+ listAgentsFromRegistry() {
334
+ return this.registry?.list() ?? [];
335
+ }
274
336
  async onStop() {
275
337
  logger.info("[AgentComponent] Stopping and cleaning up resources...");
276
338
  for (const [name, agent] of this.agents) {
@@ -1048,6 +1048,14 @@ class ConfigComponent extends BaseComponent {
1048
1048
  }
1049
1049
  this.sourceUnwatchFns.clear();
1050
1050
  }
1051
+ shutdown() {
1052
+ this.unwatchAll();
1053
+ this.persistQueue.clear();
1054
+ }
1055
+ async onStop() {
1056
+ this.shutdown();
1057
+ await super.onStop();
1058
+ }
1051
1059
  getSources() {
1052
1060
  return [...this.sources];
1053
1061
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TaskTagPlugin,
3
3
  createLarkCliTaskNotifyHook
4
- } from "./roy-agent-core-2x07feb7.js";
4
+ } from "./roy-agent-core-e9fdm13a.js";
5
5
  import {
6
6
  envKeyToConfigKey
7
7
  } from "./roy-agent-core-qxhq8ven.js";
@@ -318,10 +318,25 @@ class McpLoader {
318
318
  return;
319
319
  try {
320
320
  await entry.client.close();
321
- this.clients.delete(name);
322
- logger2.info(`[McpLoader] Disconnected from ${name}`);
323
321
  } catch (error) {
324
- logger2.warn(`[McpLoader] Error disconnecting from ${name}`, { error });
322
+ logger2.warn(`[McpLoader] Error closing client for ${name}`, { error });
323
+ }
324
+ await this.closeTransport(entry.transport, name);
325
+ this.clients.delete(name);
326
+ logger2.info(`[McpLoader] Disconnected from ${name}`);
327
+ }
328
+ async closeTransport(transport, name) {
329
+ try {
330
+ const transportAny = transport;
331
+ if (typeof transportAny.close === "function") {
332
+ await transportAny.close();
333
+ }
334
+ const child = transportAny._process ?? transportAny.process;
335
+ if (child?.pid && !child.killed) {
336
+ child.kill?.("SIGTERM");
337
+ }
338
+ } catch (error) {
339
+ logger2.warn(`[McpLoader] Error closing transport for ${name}`, { error });
325
340
  }
326
341
  }
327
342
  async disconnectAll() {
@@ -1,3 +1,6 @@
1
+ import {
2
+ DEFAULT_SUBAGENT_PROMPT
3
+ } from "./roy-agent-core-7t05apnp.js";
1
4
  import {
2
5
  TaskHookPoints
3
6
  } from "./roy-agent-core-92z6t4he.js";
@@ -12,6 +15,54 @@ import {
12
15
  // src/env/task/delegate/delegate-tool.ts
13
16
  init_logger();
14
17
  import { z } from "zod";
18
+
19
+ // src/env/task/delegate/subagent-resolver.ts
20
+ function isKnownSubagentType(subagentType, registry) {
21
+ if (getSubAgentSpec(subagentType)) {
22
+ return true;
23
+ }
24
+ return registry?.hasAgent(subagentType) ?? false;
25
+ }
26
+ async function resolveSubAgentConfig(subagentType, options = {}) {
27
+ const getBuiltIn = options.getBuiltIn ?? getSubAgentSpec;
28
+ const builtIn = getBuiltIn(subagentType);
29
+ const agentDef = options.registry?.get(subagentType);
30
+ if (!builtIn && !agentDef) {
31
+ return;
32
+ }
33
+ if (agentDef) {
34
+ return resolveFromRegistry(subagentType, agentDef, builtIn, options.registry);
35
+ }
36
+ return {
37
+ subagentType,
38
+ description: builtIn.description,
39
+ basePrompt: builtIn.promptOverride || DEFAULT_SUBAGENT_PROMPT,
40
+ allowedTools: builtIn.allowedTools,
41
+ deniedTools: builtIn.deniedTools ?? ["delegate_task", "stop_task"],
42
+ fromRegistry: false
43
+ };
44
+ }
45
+ async function resolveFromRegistry(subagentType, agentDef, builtIn, registry) {
46
+ const resolvedPrompt = registry ? await registry.getSystemPrompt(subagentType) : agentDef.systemPrompt;
47
+ return {
48
+ subagentType,
49
+ description: agentDef.description || builtIn?.description || "Custom agent",
50
+ basePrompt: resolvedPrompt || builtIn?.promptOverride || DEFAULT_SUBAGENT_PROMPT,
51
+ allowedTools: agentDef.allowedTools ?? builtIn?.allowedTools,
52
+ deniedTools: agentDef.deniedTools ?? builtIn?.deniedTools ?? ["delegate_task", "stop_task"],
53
+ fromRegistry: true
54
+ };
55
+ }
56
+ function listKnownSubagentDescriptions(registry) {
57
+ const builtInLines = builtInSubAgents.map((agent) => `- ${agent.id}: ${agent.description}`);
58
+ const registryAgents = registry?.listAgentsByType("sub") ?? [];
59
+ const customLines = registryAgents.filter((agent) => !builtInSubAgents.some((builtIn) => builtIn.id === agent.name)).map((agent) => `- ${agent.name}: ${agent.description || "Custom agent"}`);
60
+ const lines = [...builtInLines, ...customLines];
61
+ return lines.join(`
62
+ `);
63
+ }
64
+
65
+ // src/env/task/delegate/delegate-tool.ts
15
66
  var logger = createLogger("task:delegate");
16
67
  var BackgroundTaskEventTypes = {
17
68
  STARTED: "task.background.started",
@@ -99,10 +150,6 @@ var builtInSubAgents = [
99
150
  function getSubAgentSpec(id) {
100
151
  return builtInSubAgents.find((agent) => agent.id === id);
101
152
  }
102
- function getSubAgentToolDescription() {
103
- return builtInSubAgents.map((agent) => `- ${agent.id}: ${agent.description}`).join(`
104
- `);
105
- }
106
153
  function ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools) {
107
154
  let agentInstance = agentComponent.getAgent(subagentType);
108
155
  if (!agentInstance) {
@@ -341,24 +388,20 @@ class BackgroundTaskManager {
341
388
  }
342
389
  }
343
390
  async executeWithAbort(subSession, prompt, timeoutMs, signal) {
344
- return new Promise((resolve, reject) => {
345
- const timer = setTimeout(() => {
346
- reject(new Error(`Task execution timeout after ${timeoutMs}ms`));
347
- }, timeoutMs);
348
- signal?.addEventListener("abort", () => {
349
- clearTimeout(timer);
350
- reject(new Error("Task execution stopped"));
351
- });
352
- const metadata = subSession.info?.metadata || {};
353
- const taskId = metadata.task_id;
354
- const taskDescription = metadata.task_description || "";
355
- const sessionId = subSession.id;
356
- const subagentType = metadata.subagent_type || "general";
357
- const subAgent = getSubAgentSpec(subagentType);
358
- let basePrompt = subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
359
- const deniedTools = subAgent?.deniedTools || [];
360
- let fullPrompt = basePrompt.replace(/{task_description}/g, taskDescription || "N/A");
361
- fullPrompt += `
391
+ const metadata = subSession.info?.metadata || {};
392
+ const taskId = metadata.task_id;
393
+ const taskDescription = metadata.task_description || "";
394
+ const sessionId = subSession.id;
395
+ const subagentType = metadata.subagent_type || "general";
396
+ const agentComponent = this.env?.getComponent?.("agent");
397
+ const registry = agentComponent?.getRegistry?.();
398
+ const resolved = await resolveSubAgentConfig(subagentType, { registry });
399
+ const subAgent = getSubAgentSpec(subagentType);
400
+ const basePrompt = resolved?.basePrompt || subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
401
+ const deniedTools = resolved?.deniedTools || subAgent?.deniedTools || [];
402
+ const allowedTools = resolved?.allowedTools || subAgent?.allowedTools;
403
+ let fullPrompt = basePrompt.replace(/{task_description}/g, taskDescription || "N/A");
404
+ fullPrompt += `
362
405
 
363
406
  ---
364
407
 
@@ -377,18 +420,31 @@ ${prompt}
377
420
  - 使用可用工具完成任务
378
421
  - 返回清晰的任务执行结果摘要
379
422
  - 适时调用 task_operation_create 记录进展`;
380
- const agentComponent = this.env?.getComponent?.("agent");
381
- if (!agentComponent) {
423
+ if (!agentComponent) {
424
+ throw new Error("AgentComponent not found");
425
+ }
426
+ const subAgentForRegister = subAgent ? { ...subAgent, allowedTools } : allowedTools ? {
427
+ id: subagentType,
428
+ name: subagentType,
429
+ mode: "subagent",
430
+ description: resolved?.description || "Custom agent",
431
+ allowedTools,
432
+ deniedTools
433
+ } : undefined;
434
+ ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgentForRegister, deniedTools);
435
+ return new Promise((resolve, reject) => {
436
+ const timer = setTimeout(() => {
437
+ reject(new Error(`Task execution timeout after ${timeoutMs}ms`));
438
+ }, timeoutMs);
439
+ signal?.addEventListener("abort", () => {
382
440
  clearTimeout(timer);
383
- reject(new Error("AgentComponent not found"));
384
- return;
385
- }
386
- ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools);
441
+ reject(new Error("Task execution stopped"));
442
+ });
387
443
  this.env.handle_query?.(fullPrompt, {
388
444
  sessionId,
389
445
  deniedTools: deniedTools.length > 0 ? deniedTools : undefined,
390
446
  agentType: subagentType
391
- }).then((result) => {
447
+ })?.then((result) => {
392
448
  clearTimeout(timer);
393
449
  resolve(result);
394
450
  }).catch((error) => {
@@ -450,7 +506,7 @@ function createDelegateTool(taskComponent) {
450
506
  description: `Launch a new sub-agent to handle complex, multistep tasks autonomously.
451
507
 
452
508
  Available agent types:
453
- ${getSubAgentToolDescription()}
509
+ ${listKnownSubagentDescriptions()}
454
510
 
455
511
  When using the delegate_task tool, you must specify a subagent_type parameter to select which agent type to use.
456
512
 
@@ -477,8 +533,9 @@ When using the delegate_task tool, you must specify a subagent_type parameter to
477
533
  const { description, prompt, subagent_type = "general", background = false, timeout, cleanup, task_id, reason } = params;
478
534
  const parentSessionId = ctx.session_id || "default";
479
535
  logger.info(`[delegate_task] Called: description=${description}, subagent_type=${subagent_type}, background=${background}, task_id=${task_id}`);
480
- const subAgent = getSubAgentSpec(subagent_type);
481
- if (!subAgent) {
536
+ const agentComponent = taskComponent.env?.getComponent?.("agent");
537
+ const registry = agentComponent?.getRegistry?.();
538
+ if (!isKnownSubagentType(subagent_type, registry)) {
482
539
  return {
483
540
  success: false,
484
541
  output: "",
@@ -558,9 +615,13 @@ async function handleSyncTask(taskComponent, parentSessionId, description, promp
558
615
  metadata: { execution_time_ms: Date.now() - startTime }
559
616
  };
560
617
  }
618
+ const agentComponent = taskComponent.env?.getComponent?.("agent");
619
+ const registry = agentComponent?.getRegistry?.();
620
+ const resolved = await resolveSubAgentConfig(subagentType, { registry });
561
621
  const subAgent = getSubAgentSpec(subagentType);
562
- let basePrompt = subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
563
- const deniedTools = subAgent?.deniedTools || [];
622
+ let basePrompt = resolved?.basePrompt || subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
623
+ const deniedTools = resolved?.deniedTools || subAgent?.deniedTools || [];
624
+ const allowedTools = resolved?.allowedTools || subAgent?.allowedTools;
564
625
  let fullPrompt = basePrompt.replace(/{task_description}/g, description || "N/A");
565
626
  fullPrompt += `
566
627
 
@@ -581,7 +642,6 @@ ${prompt}
581
642
  - 使用可用工具完成任务
582
643
  - 返回清晰的任务执行结果摘要
583
644
  - 适时调用 task_operation_create 记录进展`;
584
- const agentComponent = taskComponent.env?.getComponent?.("agent");
585
645
  if (!agentComponent) {
586
646
  return {
587
647
  success: false,
@@ -590,7 +650,15 @@ ${prompt}
590
650
  metadata: { execution_time_ms: Date.now() - startTime }
591
651
  };
592
652
  }
593
- ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools);
653
+ const subAgentForRegister = subAgent ? { ...subAgent, allowedTools } : allowedTools ? {
654
+ id: subagentType,
655
+ name: subagentType,
656
+ mode: "subagent",
657
+ description: resolved?.description || "Custom agent",
658
+ allowedTools,
659
+ deniedTools
660
+ } : undefined;
661
+ ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgentForRegister, deniedTools);
594
662
  const timeoutMs = timeout || DEFAULT_TIMEOUT;
595
663
  let result;
596
664
  try {