@ai-setting/roy-agent-core 1.5.88 → 1.5.90

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 (48) hide show
  1. package/dist/env/agent/index.js +8 -8
  2. package/dist/env/event-source/index.js +12 -4
  3. package/dist/env/index.js +20 -15
  4. package/dist/env/llm/index.js +4 -2
  5. package/dist/env/prompt/index.js +2 -1
  6. package/dist/env/session/index.js +3 -4
  7. package/dist/env/session/storage/index.js +2 -2
  8. package/dist/env/task/delegate/index.js +3 -2
  9. package/dist/env/task/index.js +4 -3
  10. package/dist/env/task/plugins/index.js +7 -4
  11. package/dist/env/tool/built-in/index.js +2 -1
  12. package/dist/env/tool/index.js +11 -8
  13. package/dist/env/workflow/engine/index.js +5 -3
  14. package/dist/env/workflow/index.js +6 -4
  15. package/dist/env/workflow/nodes/index.js +1 -1
  16. package/dist/env/workflow/tools/index.js +7 -1
  17. package/dist/env/workflow/utils/index.js +5 -0
  18. package/dist/index.js +144 -32
  19. package/dist/shared/@ai-setting/{roy-agent-core-r0m0at3x.js → roy-agent-core-0r4ndyn9.js} +119 -7
  20. package/dist/shared/@ai-setting/{roy-agent-core-jymz9fzp.js → roy-agent-core-2c8eraxq.js} +126 -41
  21. package/dist/shared/@ai-setting/{roy-agent-core-0y64qaac.js → roy-agent-core-32m0nb9j.js} +119 -30
  22. package/dist/shared/@ai-setting/roy-agent-core-4yq23m5g.js +421 -0
  23. package/dist/shared/@ai-setting/{roy-agent-core-h2d1s8yd.js → roy-agent-core-5ykms33a.js} +1 -1
  24. package/dist/shared/@ai-setting/{roy-agent-core-mmkyydw7.js → roy-agent-core-83d035pp.js} +91 -579
  25. package/dist/shared/@ai-setting/roy-agent-core-8wd3qwx5.js +35 -0
  26. package/dist/shared/@ai-setting/{roy-agent-core-yx0vw1aw.js → roy-agent-core-8zjntsbb.js} +102 -32
  27. package/dist/shared/@ai-setting/{roy-agent-core-29fh9mxg.js → roy-agent-core-bwjpte58.js} +1 -2
  28. package/dist/shared/@ai-setting/{roy-agent-core-vneyghpg.js → roy-agent-core-ddq5hcp5.js} +1 -1
  29. package/dist/shared/@ai-setting/{roy-agent-core-qhhxx2x2.js → roy-agent-core-ds5f75pg.js} +2 -1
  30. package/dist/shared/@ai-setting/{roy-agent-core-4cdtdxqx.js → roy-agent-core-ewr1nw7t.js} +1 -1
  31. package/dist/shared/@ai-setting/roy-agent-core-hvdfgvfz.js +114 -0
  32. package/dist/shared/@ai-setting/{roy-agent-core-3arrpf7n.js → roy-agent-core-hxsbegfc.js} +229 -9
  33. package/dist/shared/@ai-setting/{roy-agent-core-9y09xfav.js → roy-agent-core-j0107ww1.js} +6 -418
  34. package/dist/shared/@ai-setting/{roy-agent-core-6mk0m4t3.js → roy-agent-core-m683wd1n.js} +283 -15
  35. package/dist/shared/@ai-setting/{roy-agent-core-bgw4dq11.js → roy-agent-core-mw4ty0ba.js} +44 -5
  36. package/dist/shared/@ai-setting/{roy-agent-core-7z4xtrmw.js → roy-agent-core-nqzt9ne4.js} +53 -0
  37. package/dist/shared/@ai-setting/roy-agent-core-pt7as39r.js +0 -0
  38. package/dist/shared/@ai-setting/{roy-agent-core-6n7xwv4v.js → roy-agent-core-rkz8r2sx.js} +5 -3
  39. package/dist/shared/@ai-setting/{roy-agent-core-c1j7ev4e.js → roy-agent-core-txwf64pd.js} +70 -0
  40. package/dist/shared/@ai-setting/{roy-agent-core-7fdzfsm6.js → roy-agent-core-w0kb72ve.js} +42 -213
  41. package/dist/shared/@ai-setting/roy-agent-core-w6bmrgap.js +581 -0
  42. package/dist/shared/@ai-setting/{roy-agent-core-qhjb153z.js → roy-agent-core-xnxyzaw4.js} +27 -4
  43. package/dist/shared/@ai-setting/roy-agent-core-yanpq5gb.js +116 -0
  44. package/dist/shared/@ai-setting/{roy-agent-core-hc20420t.js → roy-agent-core-z240ts1r.js} +27 -3
  45. package/dist/shared/@ai-setting/{roy-agent-core-q7sqeax6.js → roy-agent-core-zky9jse4.js} +163 -3
  46. package/package.json +1 -1
  47. package/dist/shared/@ai-setting/roy-agent-core-x3gtyqax.js +0 -378
  48. /package/dist/shared/@ai-setting/{roy-agent-core-4f3976cd.js → roy-agent-core-k5hxvaf0.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TaskTagPlugin,
3
3
  createLarkCliTaskNotifyHook
4
- } from "./roy-agent-core-7fdzfsm6.js";
4
+ } from "./roy-agent-core-w0kb72ve.js";
5
5
  import {
6
6
  envKeyToConfigKey
7
7
  } from "./roy-agent-core-qxhq8ven.js";
@@ -192,6 +192,249 @@ var timerHandler = {
192
192
  }
193
193
  };
194
194
 
195
+ // src/env/event-source/bounty-im-handler.ts
196
+ function readBountyIMConfig(config) {
197
+ const topLevelAddress = config.address;
198
+ const topLevelUrl = config.imServerUrl;
199
+ const optionsAddress = config.options?.address;
200
+ const optionsUrl = config.options?.imServerUrl;
201
+ return {
202
+ address: topLevelAddress || optionsAddress,
203
+ imServerUrl: topLevelUrl || optionsUrl
204
+ };
205
+ }
206
+ function readBountyIMTlsSkipVerify(config) {
207
+ const topLevel = config.tlsSkipVerify;
208
+ const fromOptions = config.options?.tlsSkipVerify;
209
+ const raw = topLevel !== undefined ? topLevel : fromOptions;
210
+ return raw === true;
211
+ }
212
+ function shouldWriteBunTlsSkipEnv(tlsSkipVerify, isBunRuntimeOverride) {
213
+ const isBun = isBunRuntimeOverride ?? typeof Bun !== "undefined";
214
+ return tlsSkipVerify === true && isBun;
215
+ }
216
+
217
+ class BountyIMInstance {
218
+ config;
219
+ status = "created";
220
+ ws = null;
221
+ buffer = "";
222
+ eventHandler;
223
+ constructor(config) {
224
+ this.config = config;
225
+ }
226
+ getCurrentAddress() {
227
+ const { address } = readBountyIMConfig(this.config);
228
+ return address || "unknown";
229
+ }
230
+ getStatus() {
231
+ return this.status;
232
+ }
233
+ async start() {
234
+ if (this.status === "running")
235
+ return;
236
+ this.setStatus("starting");
237
+ const { address, imServerUrl } = readBountyIMConfig(this.config);
238
+ if (!imServerUrl) {
239
+ throw new Error("imServerUrl is required for bounty-im event source");
240
+ }
241
+ const wsUrl = new URL(imServerUrl);
242
+ if (address) {
243
+ wsUrl.searchParams.set("address", address);
244
+ }
245
+ console.log(`[BountyIM] Connecting to ${wsUrl.toString()}...`);
246
+ try {
247
+ const { WebSocket } = await import("ws");
248
+ const tlsSkipVerify = readBountyIMTlsSkipVerify(this.config);
249
+ const isWss = imServerUrl.startsWith("wss://");
250
+ if (isWss && shouldWriteBunTlsSkipEnv(tlsSkipVerify)) {
251
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
252
+ }
253
+ this.ws = new WebSocket(wsUrl.toString(), {
254
+ headers: this.config.headers,
255
+ rejectUnauthorized: !tlsSkipVerify
256
+ });
257
+ this.ws.on("open", () => {
258
+ console.log(`[BountyIM] Connected${address ? ` as ${address}` : ""}`);
259
+ this.setStatus("running");
260
+ });
261
+ this.ws.on("message", (data) => {
262
+ this.handleMessage(data.toString());
263
+ });
264
+ this.ws.on("error", (error) => {
265
+ console.error(`[BountyIM] Error:`, error.message);
266
+ this.setStatus("error");
267
+ });
268
+ this.ws.on("close", () => {
269
+ console.log(`[BountyIM] Connection closed`);
270
+ this.setStatus("stopped");
271
+ });
272
+ } catch (error) {
273
+ this.setStatus("error");
274
+ throw new Error(`Failed to connect to Bounty IM server: ${error}`);
275
+ }
276
+ }
277
+ async stop() {
278
+ if (this.status === "stopped" || this.status === "created")
279
+ return;
280
+ this.setStatus("stopping");
281
+ if (this.ws) {
282
+ this.ws.close();
283
+ this.ws = null;
284
+ }
285
+ this.setStatus("stopped");
286
+ }
287
+ onEvent(handler) {
288
+ this.eventHandler = handler;
289
+ }
290
+ offEvent() {
291
+ this.eventHandler = undefined;
292
+ }
293
+ setStatus(status) {
294
+ this.status = status;
295
+ }
296
+ handleMessage(data) {
297
+ this.buffer += data;
298
+ try {
299
+ JSON.parse(this.buffer);
300
+ this.processLine(this.buffer);
301
+ this.buffer = "";
302
+ } catch {}
303
+ }
304
+ processLine(rawData) {
305
+ try {
306
+ let rawEvent;
307
+ try {
308
+ rawEvent = JSON.parse(rawData);
309
+ } catch {
310
+ rawEvent = {
311
+ event: "message",
312
+ data: { content: { type: "text", body: rawData } }
313
+ };
314
+ }
315
+ const evt = rawEvent;
316
+ const msg = evt.data || {};
317
+ if (evt.event !== "message") {
318
+ return;
319
+ }
320
+ const eventType = `bounty-im.${evt.event || "message"}`;
321
+ const fromAddress = msg.from || "unknown";
322
+ const currentAddress = this.getCurrentAddress();
323
+ const toAddress = msg.to || currentAddress;
324
+ if (msg.to && msg.to !== currentAddress) {
325
+ console.warn(`[BountyIM] Warning: message.to (${msg.to}) !== current address (${currentAddress})`);
326
+ }
327
+ const msgContent = msg.content;
328
+ const content = msgContent?.type === "text" ? String(msgContent.body || "") : "";
329
+ const { imServerUrl } = readBountyIMConfig(this.config);
330
+ const agent = this.config.handleRule?.agent;
331
+ const metadata = {
332
+ eventType,
333
+ senderId: fromAddress,
334
+ chatId: toAddress,
335
+ agent
336
+ };
337
+ let recommendedAction;
338
+ if (evt.event === "message") {
339
+ recommendedAction = {
340
+ action: `处理消息并通过 bounty com send 回复发件人。使用格式:bounty com send -f ${toAddress} -t ${fromAddress} -b "回复内容"`,
341
+ replyTo: {
342
+ chatId: fromAddress
343
+ }
344
+ };
345
+ }
346
+ const replyChannel = {
347
+ type: "bounty-im",
348
+ chatId: fromAddress,
349
+ params: {
350
+ from: toAddress,
351
+ to: fromAddress,
352
+ imServerUrl
353
+ }
354
+ };
355
+ const displayMessage = content ? `[From ${fromAddress}] ${content}
356
+
357
+ \uD83D\uDCA1 回复: bounty com send -f ${toAddress} -t ${fromAddress} -b "回复内容"` : this.formatMessage(rawEvent);
358
+ const event = {
359
+ id: `es-${this.config.id}-${Date.now()}`,
360
+ type: eventType,
361
+ timestamp: Date.now(),
362
+ metadata: {
363
+ source: "event-source",
364
+ sourceId: this.config.id,
365
+ agent
366
+ },
367
+ payload: {
368
+ sourceId: this.config.id,
369
+ sourceType: "bounty-im",
370
+ rawEvent,
371
+ message: displayMessage,
372
+ metadata,
373
+ recommendedAction,
374
+ replyChannel,
375
+ timestamp: Date.now()
376
+ }
377
+ };
378
+ this.eventHandler?.(event);
379
+ if (msg.id && this.ws) {
380
+ try {
381
+ const ackPayload = JSON.stringify({
382
+ event: "ack",
383
+ data: { messageIds: [msg.id] }
384
+ });
385
+ this.ws.send(ackPayload);
386
+ console.log(`[BountyIM] 已发送 ACK for message: ${msg.id}`);
387
+ } catch (ackErr) {
388
+ console.error(`[BountyIM] 发送 ACK 失败:`, ackErr);
389
+ }
390
+ }
391
+ } catch (err) {
392
+ console.error(`[BountyIM] Error processing message:`, err);
393
+ }
394
+ }
395
+ formatMessage(rawEvent) {
396
+ const evt = rawEvent;
397
+ if (evt.event === "connected") {
398
+ return `✅ 已连接到 bounty IM 服务器`;
399
+ }
400
+ if (evt.event === "message") {
401
+ const msg = evt.data || {};
402
+ const from = msg.from || "unknown";
403
+ let content = "未知内容";
404
+ if (msg.content?.type === "text") {
405
+ content = String(msg.content?.body || "");
406
+ }
407
+ return `[${from}] ${content}`;
408
+ }
409
+ return `事件: ${evt.event || "unknown"}`;
410
+ }
411
+ }
412
+ var bountyIMHandler = {
413
+ type: "bounty-im",
414
+ validateConfig(config) {
415
+ const errors = [];
416
+ if (!config.id)
417
+ errors.push("EventSource ID is required");
418
+ if (!config.name)
419
+ errors.push("EventSource name is required");
420
+ const { address, imServerUrl } = readBountyIMConfig(config);
421
+ if (!address) {
422
+ errors.push("Bounty IM address is required (top-level address or options.address)");
423
+ } else if (!/^[\w-]+@[\w.-]+$/.test(address)) {
424
+ errors.push("Bounty IM address format invalid (expected: agent-id@host)");
425
+ }
426
+ if (!imServerUrl) {
427
+ errors.push("Bounty IM imServerUrl is required (top-level imServerUrl or options.imServerUrl)");
428
+ } else if (!imServerUrl.startsWith("ws://") && !imServerUrl.startsWith("wss://")) {
429
+ errors.push("Bounty IM imServerUrl must start with ws:// or wss://");
430
+ }
431
+ return errors;
432
+ },
433
+ createInstance(config) {
434
+ return new BountyIMInstance(config);
435
+ }
436
+ };
437
+
195
438
  // src/env/event-source/event-source-handlers.ts
196
439
  init_global_hook_manager();
197
440
  import { spawn } from "child_process";
@@ -259,18 +502,24 @@ function extractMetadata(rawEvent, eventType) {
259
502
  }
260
503
  let recommendedAction;
261
504
  if (eventType === "im.message.receive_v1" || event.type === "im.message.receive_v1") {
505
+ const profile2 = event.profile;
506
+ const profileFlag = profile2 ? `--profile ${profile2} ` : "";
507
+ const profileHint = profile2 ? `(⚠️ 必须使用 profile="${profile2}" 调用 lark-cli,否则会因 openId 跨 app 失败)` : "";
262
508
  recommendedAction = {
263
- action: '处理飞书消息并以机器人身份回复,比如lark-cli im +messages-reply --message-id "xxxxid" --as bot --text "回复内容"',
509
+ action: `处理飞书消息并以机器人身份回复${profileHint},例如:lark-cli ${profileFlag}im +messages-reply --message-id "xxxxid" --as bot --text "回复内容"`,
264
510
  replyTo: {
265
511
  appId: metadata.appId,
512
+ profile: profile2,
266
513
  chatId: metadata.chatId,
267
514
  messageId: metadata.messageId
268
515
  }
269
516
  };
270
517
  }
518
+ const profile = event.profile;
271
519
  const replyChannel = {
272
520
  type: "lark-cli",
273
521
  appId: metadata.appId,
522
+ profile,
274
523
  chatId: messageData?.chat_id,
275
524
  messageId: messageData?.message_id
276
525
  };
@@ -291,7 +540,14 @@ class LarkCliInstance {
291
540
  if (this.status === "running")
292
541
  return;
293
542
  await this.loadPlugins();
294
- const command = this.config.command || "lark-cli event consume im.message.receive_v1 --as bot";
543
+ const profile = this.config.profile;
544
+ const profileFlag = profile ? `--profile ${profile} ` : "";
545
+ let command;
546
+ if (this.config.command) {
547
+ command = this.config.command.replace(/^(lark-cli)(\s+|$)/, (_, head, tail) => `${head} ${profileFlag.trim()}${tail}`);
548
+ } else {
549
+ command = `lark-cli ${profileFlag}event consume im.message.receive_v1 --as bot`;
550
+ }
295
551
  this.child = spawn("exec " + command, [], {
296
552
  shell: true,
297
553
  stdio: ["pipe", "pipe", "pipe"],
@@ -530,7 +786,12 @@ class LarkCliInstance {
530
786
  if (this.config.eventTypes?.length && !matchEventType(eventType, this.config.eventTypes)) {
531
787
  return;
532
788
  }
533
- const { metadata, replyChannel, recommendedAction } = extractMetadata(rawEvent, eventType);
789
+ const enrichedEvent = {
790
+ ...rawEvent,
791
+ profile: this.config.profile,
792
+ eventSourceId: this.config.id
793
+ };
794
+ const { metadata, replyChannel, recommendedAction } = extractMetadata(enrichedEvent, eventType);
534
795
  const message = JSON.stringify({
535
796
  rawData,
536
797
  recommendedAction
@@ -598,18 +859,21 @@ class LarkCliInstance {
598
859
  if (!replyChannel || !replyChannel.chatId && !replyChannel.messageId) {
599
860
  return;
600
861
  }
862
+ const profile = replyChannel.profile;
601
863
  return {
602
864
  type: replyChannel.type,
603
865
  messageId: replyChannel.messageId,
604
866
  chatId: replyChannel.chatId,
605
867
  userId: replyChannel.params?.userId,
868
+ profile,
606
869
  identity: "bot",
607
870
  sendText: async (text) => {
608
871
  await this.sendLarkMessage({
609
872
  chatId: replyChannel.chatId,
610
873
  userId: replyChannel.params?.userId,
611
874
  content: text,
612
- as: "bot"
875
+ as: "bot",
876
+ profile
613
877
  });
614
878
  },
615
879
  sendMarkdown: async (markdown) => {
@@ -618,7 +882,8 @@ class LarkCliInstance {
618
882
  userId: replyChannel.params?.userId,
619
883
  content: markdown,
620
884
  as: "bot",
621
- format: "markdown"
885
+ format: "markdown",
886
+ profile
622
887
  });
623
888
  },
624
889
  sendMessage: async (content) => {
@@ -626,7 +891,8 @@ class LarkCliInstance {
626
891
  chatId: replyChannel.chatId,
627
892
  userId: replyChannel.params?.userId,
628
893
  content: JSON.stringify(content),
629
- as: "bot"
894
+ as: "bot",
895
+ profile
630
896
  });
631
897
  },
632
898
  reply: async (content) => {
@@ -634,7 +900,8 @@ class LarkCliInstance {
634
900
  await this.sendLarkMessage({
635
901
  messageId: replyChannel.messageId,
636
902
  content: JSON.stringify(content),
637
- as: "bot"
903
+ as: "bot",
904
+ profile
638
905
  });
639
906
  }
640
907
  }
@@ -642,7 +909,7 @@ class LarkCliInstance {
642
909
  }
643
910
  async sendLarkMessage(options) {
644
911
  return new Promise((resolve, reject) => {
645
- const { chatId, userId, messageId, content, as: identity, format = "text" } = options;
912
+ const { chatId, userId, messageId, content, as: identity, format = "text", profile } = options;
646
913
  const contentFlag = format === "markdown" ? "--markdown" : "--text";
647
914
  const args = ["im", "+messages-send", "--as", identity];
648
915
  if (messageId) {
@@ -655,6 +922,9 @@ class LarkCliInstance {
655
922
  reject(new Error("No target specified for sending message"));
656
923
  return;
657
924
  }
925
+ if (profile) {
926
+ args.unshift("--profile", profile);
927
+ }
658
928
  const proc = spawn("lark-cli", args, {
659
929
  shell: false,
660
930
  stdio: ["pipe", "pipe", "pipe"]
@@ -691,9 +961,6 @@ var larkCliHandler = {
691
961
  type: "lark-cli",
692
962
  validateConfig(config) {
693
963
  const errors = [];
694
- if (!config.command) {
695
- errors.push("command is optional, will use default: lark-cli event consume im.message.receive_v1 --as bot");
696
- }
697
964
  return errors;
698
965
  },
699
966
  createInstance(config) {
@@ -702,7 +969,8 @@ var larkCliHandler = {
702
969
  };
703
970
  var builtInHandlers = [
704
971
  larkCliHandler,
705
- timerHandler
972
+ timerHandler,
973
+ bountyIMHandler
706
974
  ];
707
975
  function getBuiltInHandler(type) {
708
976
  return builtInHandlers.find((h) => h.type === type);
@@ -804,7 +1072,7 @@ class EventSourceComponent extends BaseComponent {
804
1072
  }
805
1073
  }
806
1074
  async executeInitHooks() {
807
- const { EventSourceInitHooks } = await import("./roy-agent-core-vneyghpg.js");
1075
+ const { EventSourceInitHooks } = await import("./roy-agent-core-ddq5hcp5.js");
808
1076
  await EventSourceInitHooks.execute(this);
809
1077
  }
810
1078
  registerHandler(handler) {
@@ -1146,4 +1414,4 @@ __legacyDecorateClassTS([
1146
1414
  TracedAs("event-source.update", { recordParams: false, log: false })
1147
1415
  ], EventSourceComponent.prototype, "update", null);
1148
1416
 
1149
- export { TimerInstance, timerHandler, larkCliHandler, builtInHandlers, getBuiltInHandler, EventSourceComponent };
1417
+ export { TimerInstance, timerHandler, BountyIMInstance, bountyIMHandler, larkCliHandler, builtInHandlers, getBuiltInHandler, EventSourceComponent };
@@ -1,6 +1,10 @@
1
+ import {
2
+ ProcessRegistry,
3
+ runWithProcessRegistryAsync
4
+ } from "./roy-agent-core-hvdfgvfz.js";
1
5
  import {
2
6
  DEFAULT_SUBAGENT_PROMPT
3
- } from "./roy-agent-core-7z4xtrmw.js";
7
+ } from "./roy-agent-core-nqzt9ne4.js";
4
8
  import {
5
9
  TaskHookPoints
6
10
  } from "./roy-agent-core-92z6t4he.js";
@@ -245,6 +249,7 @@ class BackgroundTaskManager {
245
249
  tasks = new Map;
246
250
  abortControllers = new Map;
247
251
  progressTimers = new Map;
252
+ processRegistries = new Map;
248
253
  constructor(env) {
249
254
  this.env = env;
250
255
  }
@@ -303,6 +308,8 @@ class BackgroundTaskManager {
303
308
  throw new Error("Failed to create sub-session");
304
309
  }
305
310
  const abortController = new AbortController;
311
+ const processRegistry = new ProcessRegistry;
312
+ this.processRegistries.set(taskIdGen, processRegistry);
306
313
  const task = {
307
314
  id: taskIdGen,
308
315
  subSessionId: subSession.id,
@@ -349,7 +356,8 @@ class BackgroundTaskManager {
349
356
  if (!subSession) {
350
357
  throw new Error(`Sub session not found: ${task.subSessionId}`);
351
358
  }
352
- const result = await this.executeWithAbort(subSession, prompt, timeoutMs, abortController?.signal, task.similarTaskIds);
359
+ const taskRegistry = this.processRegistries.get(taskId);
360
+ const result = await this.executeWithAbort(subSession, prompt, timeoutMs, abortController?.signal, task.similarTaskIds, taskRegistry);
353
361
  if (abortController?.signal.aborted) {
354
362
  logger.info(`[BackgroundTaskManager] Task was aborted`, { taskId });
355
363
  return;
@@ -465,7 +473,7 @@ class BackgroundTaskManager {
465
473
  this.progressTimers.delete(taskId);
466
474
  }
467
475
  }
468
- async executeWithAbort(subSession, prompt, timeoutMs, signal, similarTaskIds) {
476
+ async executeWithAbort(subSession, prompt, timeoutMs, signal, similarTaskIds, processRegistry) {
469
477
  const metadata = subSession.info?.metadata || {};
470
478
  const taskId = metadata.task_id;
471
479
  const taskDescription = metadata.task_description || "";
@@ -575,7 +583,17 @@ Use these as guidance to improve task execution efficiency.`;
575
583
  const isWorkflowAgent = registry?.get(subagentType)?.type === "workflow";
576
584
  const delegateQuery = isWorkflowAgent ? prompt : fullPrompt;
577
585
  return new Promise((resolve, reject) => {
586
+ const killProcessTreeSafely = () => {
587
+ try {
588
+ processRegistry?.killAll();
589
+ } catch (err) {
590
+ logger.warn(`[delegate] ProcessRegistry.killAll failed`, {
591
+ error: err instanceof Error ? err.message : String(err)
592
+ });
593
+ }
594
+ };
578
595
  const timer = setTimeout(() => {
596
+ killProcessTreeSafely();
579
597
  reject(new Error(`Task execution timeout after ${timeoutMs}ms`));
580
598
  try {
581
599
  agentComponent?.abort?.(subagentType);
@@ -590,14 +608,17 @@ Use these as guidance to improve task execution efficiency.`;
590
608
  agentComp.abort(subagentType);
591
609
  }
592
610
  } catch {}
611
+ killProcessTreeSafely();
593
612
  reject(new Error("Task execution stopped"));
594
613
  });
595
- this.env.handle_query?.(delegateQuery, {
614
+ const invokeHandleQuery = () => this.env.handle_query?.(delegateQuery, {
596
615
  sessionId,
597
616
  deniedTools: deniedTools.length > 0 ? deniedTools : undefined,
598
617
  agentType: subagentType,
599
618
  abort: signal
600
- })?.then((result) => {
619
+ });
620
+ const wrappedPromise = processRegistry ? runWithProcessRegistryAsync(processRegistry, () => invokeHandleQuery()) : Promise.resolve(invokeHandleQuery());
621
+ wrappedPromise?.then((result) => {
601
622
  clearTimeout(timer);
602
623
  resolve(result);
603
624
  }).catch((error) => {
@@ -621,6 +642,14 @@ Use these as guidance to improve task execution efficiency.`;
621
642
  task.status = "stopped";
622
643
  task.abortController?.abort();
623
644
  task.completedAt = Date.now();
645
+ try {
646
+ this.processRegistries.get(taskId)?.killAll();
647
+ } catch (err) {
648
+ logger.warn(`[delegate] stopTask killAll failed`, {
649
+ taskId,
650
+ error: err instanceof Error ? err.message : String(err)
651
+ });
652
+ }
624
653
  const stoppedPayload = {
625
654
  backgroundTaskId: task.id,
626
655
  subSessionId: task.subSessionId,
@@ -646,6 +675,16 @@ Use these as guidance to improve task execution efficiency.`;
646
675
  logger.debug(`[BackgroundTaskManager] Aborted task: ${taskId}`);
647
676
  }
648
677
  this.abortControllers.clear();
678
+ for (const [, registry] of this.processRegistries) {
679
+ try {
680
+ registry.killAll();
681
+ } catch (err) {
682
+ logger.warn(`[BackgroundTaskManager] dispose registry.killAll failed`, {
683
+ error: err instanceof Error ? err.message : String(err)
684
+ });
685
+ }
686
+ }
687
+ this.processRegistries.clear();
649
688
  this.tasks.clear();
650
689
  logger.info(`[BackgroundTaskManager] Disposed`);
651
690
  }
@@ -193,6 +193,59 @@ class AgentRegistry {
193
193
  };
194
194
  this.agents.set(name, agent);
195
195
  }
196
+ registerWorkflowExtractAgent() {
197
+ const name = "workflow-extract";
198
+ if (this.agents.has(name))
199
+ return;
200
+ const agent = {
201
+ name,
202
+ type: "sub",
203
+ description: "Workflow 提取子智能体 — 从父 task 的对话历史中分析需求,迭代式生成并验证 Workflow YAML",
204
+ systemPromptRef: "workflow-extract",
205
+ allowedTools: [
206
+ "workflow_get",
207
+ "workflow_list",
208
+ "workflow_add",
209
+ "workflow_validate"
210
+ ],
211
+ deniedTools: [],
212
+ maxIterations: 10,
213
+ filterHistory: false
214
+ };
215
+ this.agents.set(name, agent);
216
+ }
217
+ registerCompactAgent() {
218
+ const name = "compact";
219
+ if (this.agents.has(name))
220
+ return;
221
+ const agent = {
222
+ name,
223
+ type: "sub",
224
+ description: "压缩子智能体 — 从父 session 的历史消息中提取结构化 checkpoint JSON",
225
+ systemPromptRef: "compact",
226
+ allowedTools: ["workflow_submit_output"],
227
+ deniedTools: [],
228
+ maxIterations: 1,
229
+ filterHistory: false
230
+ };
231
+ this.agents.set(name, agent);
232
+ }
233
+ registerCompactHintAgent() {
234
+ const name = "compact-hint";
235
+ if (this.agents.has(name))
236
+ return;
237
+ const agent = {
238
+ name,
239
+ type: "sub",
240
+ description: "压缩提示子智能体 — 分析父 session 历史,生成场景化压缩指导提示",
241
+ systemPromptRef: "compact-hint",
242
+ allowedTools: ["workflow_submit_output"],
243
+ deniedTools: [],
244
+ maxIterations: 1,
245
+ filterHistory: false
246
+ };
247
+ this.agents.set(name, agent);
248
+ }
196
249
  async load() {
197
250
  try {
198
251
  return await this.loadFromDirectory(this.configDir);
@@ -6,7 +6,7 @@ import {
6
6
  WorkflowEngine,
7
7
  exports_engine,
8
8
  init_engine
9
- } from "./roy-agent-core-9y09xfav.js";
9
+ } from "./roy-agent-core-j0107ww1.js";
10
10
  import {
11
11
  askUserTool,
12
12
  createRunWorkflowTool,
@@ -16,8 +16,9 @@ import {
16
16
  createWorkflowRunStatusTool,
17
17
  createWorkflowRunStopTool,
18
18
  createWorkflowSearchTool,
19
- createWorkflowTagListTool
20
- } from "./roy-agent-core-0y64qaac.js";
19
+ createWorkflowTagListTool,
20
+ createWorkflowValidateTool
21
+ } from "./roy-agent-core-32m0nb9j.js";
21
22
  import {
22
23
  WorkflowService
23
24
  } from "./roy-agent-core-tq9528d3.js";
@@ -213,6 +214,7 @@ class WorkflowComponent extends BaseComponent {
213
214
  createWorkflowGetTool(this.workflowService),
214
215
  createWorkflowListTool(this.workflowService),
215
216
  createWorkflowAddTool(this.workflowService),
217
+ createWorkflowValidateTool(this.workflowService),
216
218
  createWorkflowSearchTool(this.workflowService),
217
219
  createWorkflowTagListTool(this.workflowService),
218
220
  createRunWorkflowTool(this.workflowService),