@ai-setting/roy-agent-core 1.6.9 → 1.6.11

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 (41) hide show
  1. package/dist/config/index.js +5 -3
  2. package/dist/env/agent/index.js +3 -3
  3. package/dist/env/commands/index.js +2 -2
  4. package/dist/env/event-source/index.js +3 -3
  5. package/dist/env/index.js +13 -13
  6. package/dist/env/llm/index.js +3 -2
  7. package/dist/env/log-trace/index.js +2 -2
  8. package/dist/env/mcp/index.js +2 -2
  9. package/dist/env/memory/index.js +2 -2
  10. package/dist/env/prompt/index.js +2 -2
  11. package/dist/env/session/index.js +2 -2
  12. package/dist/env/skill/index.js +2 -2
  13. package/dist/env/task/delegate/index.js +1 -1
  14. package/dist/env/task/index.js +3 -3
  15. package/dist/env/tool/index.js +2 -2
  16. package/dist/env/workflow/engine/index.js +2 -2
  17. package/dist/env/workflow/index.js +6 -6
  18. package/dist/env/workflow/tools/index.js +3 -3
  19. package/dist/index.js +20 -19
  20. package/dist/shared/@ai-setting/{roy-agent-core-e34xdjwa.js → roy-agent-core-06574wqa.js} +5 -4
  21. package/dist/shared/@ai-setting/{roy-agent-core-062gyaz8.js → roy-agent-core-0n2a8cbn.js} +48 -5
  22. package/dist/shared/@ai-setting/{roy-agent-core-brfryc0b.js → roy-agent-core-1gsnq4p2.js} +4 -196
  23. package/dist/shared/@ai-setting/{roy-agent-core-qdgaghhw.js → roy-agent-core-2ek596yd.js} +52 -12
  24. package/dist/shared/@ai-setting/{roy-agent-core-tbn8cerp.js → roy-agent-core-2yavqjsh.js} +1 -1
  25. package/dist/shared/@ai-setting/{roy-agent-core-7rsfynhz.js → roy-agent-core-38kbfarg.js} +1 -1
  26. package/dist/shared/@ai-setting/{roy-agent-core-np2vh6ya.js → roy-agent-core-3kbf53sh.js} +1 -1
  27. package/dist/shared/@ai-setting/{roy-agent-core-9zf4jmgh.js → roy-agent-core-3rs38pf7.js} +2 -2
  28. package/dist/shared/@ai-setting/{roy-agent-core-8bhncxep.js → roy-agent-core-5w9a1eqa.js} +43 -6
  29. package/dist/shared/@ai-setting/{roy-agent-core-qxhq8ven.js → roy-agent-core-7hh0brvs.js} +5 -0
  30. package/dist/shared/@ai-setting/{roy-agent-core-sd3v4kaq.js → roy-agent-core-ck0m8754.js} +34 -1
  31. package/dist/shared/@ai-setting/{roy-agent-core-g2ntbc33.js → roy-agent-core-jenchn33.js} +45 -2
  32. package/dist/shared/@ai-setting/{roy-agent-core-yk0n6j67.js → roy-agent-core-m38q2azm.js} +32 -10
  33. package/dist/shared/@ai-setting/{roy-agent-core-qyarxwzg.js → roy-agent-core-mb7b62sm.js} +52 -14
  34. package/dist/shared/@ai-setting/{roy-agent-core-jmzz2yxs.js → roy-agent-core-nw39k111.js} +1 -1
  35. package/dist/shared/@ai-setting/{roy-agent-core-kxtkz66a.js → roy-agent-core-rga3f0hm.js} +1 -1
  36. package/dist/shared/@ai-setting/{roy-agent-core-q1ksqes1.js → roy-agent-core-txsswwhm.js} +1 -1
  37. package/dist/shared/@ai-setting/{roy-agent-core-1qcpvtp8.js → roy-agent-core-xxgazz27.js} +1 -1
  38. package/dist/shared/@ai-setting/roy-agent-core-y3g3ar7a.js +229 -0
  39. package/dist/shared/@ai-setting/{roy-agent-core-w1e55apa.js → roy-agent-core-z7f8hyv7.js} +1 -1
  40. package/dist/shared/@ai-setting/{roy-agent-core-sk4xg1dw.js → roy-agent-core-zs31w092.js} +1 -1
  41. package/package.json +1 -1
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  AgentComponentAdapter,
9
9
  init_agent_component_adapter
10
- } from "./roy-agent-core-g2ntbc33.js";
10
+ } from "./roy-agent-core-jenchn33.js";
11
11
  import {
12
12
  TemplateResolver,
13
13
  init_template_resolver
@@ -1355,11 +1355,26 @@ function updateAgentSessionStatus(agentSessions, nodeId, status) {
1355
1355
  }
1356
1356
  return agentSessions.map((ref) => ref.nodeId === nodeId ? { ...ref, status } : ref);
1357
1357
  }
1358
+ function markAgentSessionCompleted(agentSessions, nodeId) {
1359
+ return updateAgentSessionStatus(agentSessions, nodeId, "completed");
1360
+ }
1361
+ function markAgentSessionFailed(agentSessions, nodeId) {
1362
+ return updateAgentSessionStatus(agentSessions, nodeId, "failed");
1363
+ }
1358
1364
  function markAllAgentSessionsCompleted(agentSessions) {
1365
+ return mapNonTerminal(agentSessions, "completed");
1366
+ }
1367
+ function markAllAgentSessionsStopped(agentSessions) {
1368
+ return mapNonTerminal(agentSessions, "stopped");
1369
+ }
1370
+ function markAllAgentSessionsFailed(agentSessions) {
1371
+ return mapNonTerminal(agentSessions, "failed");
1372
+ }
1373
+ function mapNonTerminal(agentSessions, terminalStatus) {
1359
1374
  if (!agentSessions?.length) {
1360
1375
  return agentSessions ?? [];
1361
1376
  }
1362
- return agentSessions.map((ref) => ref.status === "active" || ref.status === "paused" ? { ...ref, status: "completed" } : ref);
1377
+ return agentSessions.map((ref) => ref.status === "active" || ref.status === "paused" ? { ...ref, status: terminalStatus } : ref);
1363
1378
  }
1364
1379
  var init_agent_session_metadata = () => {};
1365
1380
 
@@ -1710,8 +1725,13 @@ var init_engine = __esm(() => {
1710
1725
  const sessionState = this.activeSessions.get(sessionId);
1711
1726
  if (!sessionState) {
1712
1727
  if (this.sessionComponent) {
1728
+ const metadata = await this.getSessionMetadata(sessionId);
1713
1729
  await this.sessionComponent.update(sessionId, {
1714
- metadata: { status: "stopped" }
1730
+ metadata: {
1731
+ ...metadata,
1732
+ status: "stopped",
1733
+ agentSessions: markAllAgentSessionsStopped(metadata.agentSessions)
1734
+ }
1715
1735
  });
1716
1736
  }
1717
1737
  return;
@@ -1722,7 +1742,11 @@ var init_engine = __esm(() => {
1722
1742
  if (this.sessionComponent) {
1723
1743
  const metadata = await this.getSessionMetadata(sessionId);
1724
1744
  await this.sessionComponent.update(sessionId, {
1725
- metadata: { ...metadata, status: "stopped" }
1745
+ metadata: {
1746
+ ...metadata,
1747
+ status: "stopped",
1748
+ agentSessions: markAllAgentSessionsStopped(metadata.agentSessions)
1749
+ }
1726
1750
  });
1727
1751
  }
1728
1752
  await sessionState.eventBus.publish(createWorkflowEvent("workflow.stopped", this.getRunIdFromSessionId(sessionId), {
@@ -1749,10 +1773,28 @@ var init_engine = __esm(() => {
1749
1773
  sessionState.workflowHistory.push(...messages);
1750
1774
  }
1751
1775
  }
1776
+ if (this.sessionComponent) {
1777
+ const metadata = await this.getSessionMetadata(sessionId);
1778
+ await this.sessionComponent.update(sessionId, {
1779
+ metadata: {
1780
+ ...metadata,
1781
+ agentSessions: markAgentSessionCompleted(metadata.agentSessions, event.node_id)
1782
+ }
1783
+ });
1784
+ }
1752
1785
  });
1753
1786
  eventBus.on("node.failed", async (event) => {
1754
1787
  if (event.type !== "node.failed")
1755
1788
  return;
1789
+ if (this.sessionComponent) {
1790
+ const metadata = await this.getSessionMetadata(sessionId);
1791
+ await this.sessionComponent.update(sessionId, {
1792
+ metadata: {
1793
+ ...metadata,
1794
+ agentSessions: markAgentSessionFailed(metadata.agentSessions, event.node_id)
1795
+ }
1796
+ });
1797
+ }
1756
1798
  scheduler.markFailed(event.node_id);
1757
1799
  await this.failWorkflow(sessionState, new Error(event.error.message));
1758
1800
  });
@@ -2173,7 +2215,8 @@ var init_engine = __esm(() => {
2173
2215
  ...metadata,
2174
2216
  status: "failed",
2175
2217
  failedAt: Date.now(),
2176
- durationMs
2218
+ durationMs,
2219
+ agentSessions: markAllAgentSessionsFailed(metadata.agentSessions)
2177
2220
  }
2178
2221
  });
2179
2222
  }
@@ -1,10 +1,9 @@
1
+ import {
2
+ EnvSource
3
+ } from "./roy-agent-core-y3g3ar7a.js";
1
4
  import {
2
5
  XDG_PATHS
3
6
  } from "./roy-agent-core-qxnbvgwe.js";
4
- import {
5
- fromEnvKey,
6
- toEnvKey
7
- } from "./roy-agent-core-qxhq8ven.js";
8
7
  import {
9
8
  BaseComponent
10
9
  } from "./roy-agent-core-j62bjagf.js";
@@ -426,197 +425,6 @@ class FileSource {
426
425
  }
427
426
  }
428
427
 
429
- // src/config/env-source.ts
430
- class EnvSource {
431
- name = "env";
432
- priority = 20;
433
- prefix;
434
- transform;
435
- pollInterval;
436
- watchers = new Set;
437
- pollTimer;
438
- lastValues = new Map;
439
- watchEnabled = true;
440
- constructor(options = {}) {
441
- this.prefix = options.prefix ?? "";
442
- this.transform = options.transform;
443
- this.pollInterval = options.pollInterval;
444
- this.watchEnabled = options.watch ?? true;
445
- }
446
- getEnvKey(key) {
447
- return toEnvKey(key, this.prefix);
448
- }
449
- getInternalKey(envKey) {
450
- return fromEnvKey(envKey, this.prefix);
451
- }
452
- read(key) {
453
- const envKey = this.getEnvKey(key);
454
- const value = process.env[envKey];
455
- if (value === undefined) {
456
- return;
457
- }
458
- if (this.transform) {
459
- return this.transform(value, key);
460
- }
461
- return value;
462
- }
463
- write(key, value) {
464
- const envKey = this.getEnvKey(key);
465
- const oldValue = process.env[envKey];
466
- const stringValue = String(value);
467
- process.env[envKey] = stringValue;
468
- const event = {
469
- type: oldValue === undefined ? "add" : "change",
470
- key,
471
- oldValue: oldValue !== undefined ? this.transformValue(oldValue, key) : undefined,
472
- newValue: this.transformValue(stringValue, key),
473
- source: this.name,
474
- timestamp: Date.now()
475
- };
476
- this.notifyWatchers(event);
477
- return true;
478
- }
479
- delete(key) {
480
- const envKey = this.getEnvKey(key);
481
- const oldValue = process.env[envKey];
482
- if (oldValue === undefined) {
483
- return false;
484
- }
485
- delete process.env[envKey];
486
- const event = {
487
- type: "delete",
488
- key,
489
- oldValue: this.transformValue(oldValue, key),
490
- newValue: undefined,
491
- source: this.name,
492
- timestamp: Date.now()
493
- };
494
- this.notifyWatchers(event);
495
- return true;
496
- }
497
- list() {
498
- const result = [];
499
- const prefix = this.prefix.toUpperCase();
500
- for (const envKey of Object.keys(process.env)) {
501
- if (prefix && !envKey.startsWith(prefix)) {
502
- continue;
503
- }
504
- const key = this.getInternalKey(envKey);
505
- const value = process.env[envKey];
506
- if (value !== undefined) {
507
- result.push({
508
- key,
509
- value: this.transformValue(value, key)
510
- });
511
- }
512
- }
513
- return result;
514
- }
515
- watch(callback) {
516
- this.watchers.add(callback);
517
- if (!this.watchEnabled) {
518
- return () => {
519
- this.watchers.delete(callback);
520
- };
521
- }
522
- this.ensurePolling();
523
- this.recordCurrentValues();
524
- return () => {
525
- this.watchers.delete(callback);
526
- if (this.watchers.size === 0) {
527
- this.stopPolling();
528
- }
529
- };
530
- }
531
- ensurePolling() {
532
- if (this.pollTimer !== undefined) {
533
- return;
534
- }
535
- const interval = this.pollInterval ?? 1000;
536
- this.pollTimer = setInterval(() => {
537
- this.checkForChanges();
538
- }, interval);
539
- }
540
- stopPolling() {
541
- if (this.pollTimer) {
542
- clearInterval(this.pollTimer);
543
- this.pollTimer = undefined;
544
- }
545
- }
546
- recordCurrentValues() {
547
- this.lastValues.clear();
548
- const entries = this.list();
549
- for (const entry of entries) {
550
- const envKey = this.getEnvKey(entry.key);
551
- const value = process.env[envKey];
552
- if (value !== undefined) {
553
- this.lastValues.set(envKey, value);
554
- }
555
- }
556
- }
557
- checkForChanges() {
558
- const currentEntries = this.list();
559
- const currentValues = new Map;
560
- for (const entry of currentEntries) {
561
- const envKey = this.getEnvKey(entry.key);
562
- const value = process.env[envKey];
563
- if (value !== undefined) {
564
- currentValues.set(envKey, value);
565
- }
566
- }
567
- for (const [envKey, oldValue] of this.lastValues.entries()) {
568
- if (!currentValues.has(envKey)) {
569
- const key = this.getInternalKey(envKey);
570
- this.notifyWatchers({
571
- type: "delete",
572
- key,
573
- oldValue: this.transformValue(oldValue, key),
574
- newValue: undefined,
575
- source: this.name,
576
- timestamp: Date.now()
577
- });
578
- }
579
- }
580
- for (const [envKey, newValue] of currentValues.entries()) {
581
- const key = this.getInternalKey(envKey);
582
- const oldValue = this.lastValues.get(envKey);
583
- if (oldValue === undefined) {
584
- this.notifyWatchers({
585
- type: "add",
586
- key,
587
- oldValue: undefined,
588
- newValue: this.transformValue(newValue, key),
589
- source: this.name,
590
- timestamp: Date.now()
591
- });
592
- } else if (oldValue !== newValue) {
593
- this.notifyWatchers({
594
- type: "change",
595
- key,
596
- oldValue: this.transformValue(oldValue, key),
597
- newValue: this.transformValue(newValue, key),
598
- source: this.name,
599
- timestamp: Date.now()
600
- });
601
- }
602
- }
603
- this.lastValues = currentValues;
604
- }
605
- transformValue(value, key) {
606
- if (this.transform) {
607
- return this.transform(value, key);
608
- }
609
- return value;
610
- }
611
- notifyWatchers(event) {
612
- this.watchers.forEach((cb) => cb(event));
613
- }
614
- close() {
615
- this.stopPolling();
616
- this.watchers.clear();
617
- }
618
- }
619
-
620
428
  // src/config/protocol-resolver.ts
621
429
  var PROTOCOL_PATTERN = /^\$\{([^:]+):\/\/([^:#]+)(?:#([^:-]+))?(?::-(.*))?\}$/;
622
430
 
@@ -1246,4 +1054,4 @@ class ConfigComponent extends BaseComponent {
1246
1054
  }
1247
1055
  }
1248
1056
 
1249
- export { parseJSONC, substituteEnvVars, parseJSONCWithEnv, substituteProtocolRefs, parseJSONCWithProtocols, FileSource, EnvSource, ConfigSourceNotFoundError, ConfigFileNotFoundError, MemorySource, ConfigComponent };
1057
+ export { parseJSONC, substituteEnvVars, parseJSONCWithEnv, substituteProtocolRefs, parseJSONCWithProtocols, FileSource, ConfigSourceNotFoundError, ConfigFileNotFoundError, MemorySource, ConfigComponent };
@@ -4,7 +4,7 @@ import {
4
4
  } from "./roy-agent-core-y5ymc4f8.js";
5
5
  import {
6
6
  envKeyToConfigKey
7
- } from "./roy-agent-core-qxhq8ven.js";
7
+ } from "./roy-agent-core-7hh0brvs.js";
8
8
  import {
9
9
  BaseComponent
10
10
  } from "./roy-agent-core-j62bjagf.js";
@@ -616,6 +616,50 @@ function matchEventType(eventType, patterns) {
616
616
  }
617
617
  return false;
618
618
  }
619
+ function buildLarkRecommendedAction(opts) {
620
+ const { profile, chatType, appId, chatId, messageId } = opts;
621
+ const profileFlag = profile ? `--profile ${profile} ` : "";
622
+ const profileWarn = profile ? `(⚠️ 必须用 profile="${profile}" 调 lark-cli;openId per-app 隔离,换 profile 会失败)` : "";
623
+ const isGroup = chatType === "group";
624
+ const scopeHint = isGroup ? '群聊消息;回复到 replyTo.chatId。如需 @mention 发件人,请在 Markdown 正文开头加 <at user_id="<senderId>"/>' : "p2p 私聊消息;回复到 replyTo.chatId";
625
+ const scopeWord = isGroup ? "群聊" : "p2p 私聊";
626
+ const action = [
627
+ `处理飞书 ${scopeWord}消息并以机器人身份回复${profileWarn}。`,
628
+ `scope: ${scopeHint}。`,
629
+ ``,
630
+ `## 安全传 Markdown(必读,避免飞书收到字面 $ 和字面反斜杠+n)`,
631
+ `多行 / 复杂 Markdown 必须先写入临时 .md 文件,再 cat 出来当 --markdown 的值。`,
632
+ `原因:agent 工具调用层不做 shell 展开。`,
633
+ ``,
634
+ `推荐调用模板(4 步缺一不可,照抄):`,
635
+ ` reply_file="$(mktemp /tmp/lark-reply.XXXXXX.md)" # 1. 唯一文件名(避免并发覆盖)`,
636
+ ` trap 'rm -f "$reply_file"' EXIT # 2. 注册退出清理(无论成败都删,避免 /tmp 累积)`,
637
+ ` cat > "$reply_file" <<'LARK_REPLY_EOF' # 3. 写入 Markdown(heredoc 单引号防 shell 展开)`,
638
+ ` ...(这里是回复的 Markdown 内容,可以多行 / 含特殊字符)`,
639
+ ` LARK_REPLY_EOF`,
640
+ ` lark-cli ${profileFlag}im +messages-reply --message-id <取自 replyTo.messageId> --as bot --markdown "$(cat "$reply_file")" # 4. 真正调用`,
641
+ ``,
642
+ `## 禁止(用 words 描述,避免被 LLM 当字面 trap 抄)`,
643
+ `- 禁止把多行 Markdown 直接拼进 --markdown 参数`,
644
+ `- 禁止 bash ANSI-C 引号语法(特征:dollar 符号紧跟单引号的引号形式)`,
645
+ `- 禁止字面反斜杠+n(即 \\n 两个字符,不是 0x0A 控制字符)`,
646
+ `- 禁止 stdin 形式传 Markdown(--markdown 后接一个短横线作为值的写法)`,
647
+ `- 禁止 at-file 形式传 Markdown(--markdown 后接 @ 符号加文件名的写法)`,
648
+ ``,
649
+ `## 必须使用 replyTo 里给定的值`,
650
+ `profile / chatId / messageId / --as bot 必须原样取自 recommendedAction.replyTo;不要凭印象自己拼接。`
651
+ ].join(`
652
+ `);
653
+ return {
654
+ action,
655
+ replyTo: {
656
+ appId,
657
+ profile,
658
+ chatId,
659
+ messageId
660
+ }
661
+ };
662
+ }
619
663
  function extractMetadata(rawEvent, eventType) {
620
664
  const event = rawEvent;
621
665
  const metadata = {};
@@ -654,17 +698,13 @@ function extractMetadata(rawEvent, eventType) {
654
698
  let recommendedAction;
655
699
  if (eventType === "im.message.receive_v1" || event.type === "im.message.receive_v1") {
656
700
  const profile2 = event.profile;
657
- const profileFlag = profile2 ? `--profile ${profile2} ` : "";
658
- const profileHint = profile2 ? `(⚠️ 必须使用 profile="${profile2}" 调用 lark-cli,否则会因 openId 跨 app 失败)` : "";
659
- recommendedAction = {
660
- action: `处理飞书消息并以机器人身份回复${profileHint},例如:lark-cli ${profileFlag}im +messages-reply --message-id "xxxxid" --as bot --markdown "Markdown 格式回复内容"`,
661
- replyTo: {
662
- appId: metadata.appId,
663
- profile: profile2,
664
- chatId: metadata.chatId,
665
- messageId: metadata.messageId
666
- }
667
- };
701
+ recommendedAction = buildLarkRecommendedAction({
702
+ profile: profile2,
703
+ chatType: metadata.chatType,
704
+ appId: metadata.appId,
705
+ chatId: metadata.chatId,
706
+ messageId: metadata.messageId
707
+ });
668
708
  }
669
709
  const profile = event.profile;
670
710
  const replyChannel = {
@@ -3,7 +3,7 @@ import {
3
3
  } from "./roy-agent-core-g1s2h0e5.js";
4
4
  import {
5
5
  envKeyToConfigKey
6
- } from "./roy-agent-core-qxhq8ven.js";
6
+ } from "./roy-agent-core-7hh0brvs.js";
7
7
  import {
8
8
  BaseComponent
9
9
  } from "./roy-agent-core-j62bjagf.js";
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  envKeyToConfigKey,
9
9
  toEnvKey
10
- } from "./roy-agent-core-qxhq8ven.js";
10
+ } from "./roy-agent-core-7hh0brvs.js";
11
11
  import {
12
12
  BaseComponent
13
13
  } from "./roy-agent-core-j62bjagf.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  envKeyToConfigKey,
3
3
  toEnvKey
4
- } from "./roy-agent-core-qxhq8ven.js";
4
+ } from "./roy-agent-core-7hh0brvs.js";
5
5
  import {
6
6
  BaseComponent
7
7
  } from "./roy-agent-core-j62bjagf.js";
@@ -8,7 +8,7 @@ import {
8
8
  BackgroundTaskManager,
9
9
  createDelegateTool,
10
10
  createStopTool
11
- } from "./roy-agent-core-8bhncxep.js";
11
+ } from "./roy-agent-core-5w9a1eqa.js";
12
12
  import {
13
13
  SQLiteTaskStore,
14
14
  getDefaultTaskDbPath
@@ -37,7 +37,7 @@ import {
37
37
  } from "./roy-agent-core-1pg0fepg.js";
38
38
  import {
39
39
  envKeyToConfigKey
40
- } from "./roy-agent-core-qxhq8ven.js";
40
+ } from "./roy-agent-core-7hh0brvs.js";
41
41
  import {
42
42
  BaseComponent
43
43
  } from "./roy-agent-core-j62bjagf.js";
@@ -296,24 +296,48 @@ class BackgroundTaskManager {
296
296
  detachWorkflowRun(bgTaskId, workflowRunId) {
297
297
  this.workflowRunRegistries.get(bgTaskId)?.delete(workflowRunId);
298
298
  }
299
- async propagateStopToWorkflowRuns(bgTaskId, reason) {
299
+ replaceWorkflowRun(bgTaskId, oldRunId, newRunId) {
300
+ if (!bgTaskId)
301
+ return;
300
302
  const set = this.workflowRunRegistries.get(bgTaskId);
301
- if (!set || set.size === 0)
303
+ if (!set)
302
304
  return;
305
+ if (oldRunId) {
306
+ set.delete(oldRunId);
307
+ }
308
+ if (newRunId) {
309
+ set.add(newRunId);
310
+ }
311
+ }
312
+ async propagateStopToWorkflowRuns(bgTaskId, reason) {
313
+ const set = this.workflowRunRegistries.get(bgTaskId);
314
+ if (!set || set.size === 0) {
315
+ return { runIds: [], stopResults: [] };
316
+ }
303
317
  const runIds = Array.from(set);
304
318
  logger.info(`[BackgroundTaskManager] propagateStopToWorkflowRuns count=${runIds.length} bgTaskId=${bgTaskId}`);
319
+ const stopResults = [];
305
320
  for (const runId of runIds) {
306
321
  if (typeof this.workflowService?.stopRun !== "function") {
307
322
  logger.warn(`[BackgroundTaskManager] workflowService not injected; cannot stop ${runId}`);
323
+ stopResults.push({
324
+ runId,
325
+ success: false,
326
+ error: "workflowService not injected"
327
+ });
308
328
  continue;
309
329
  }
310
330
  try {
311
331
  await this.workflowService.stopRun(runId, reason);
332
+ stopResults.push({ runId, success: true });
312
333
  } catch (err) {
313
- logger.warn(`[BackgroundTaskManager] workflowService.stopRun(${runId}) failed (likely already terminal): ${err instanceof Error ? err.message : String(err)}`);
334
+ const errMsg = err instanceof Error ? err.message : String(err);
335
+ logger.warn(`[BackgroundTaskManager] workflowService.stopRun(${runId}) failed (likely already terminal): ${errMsg}`);
336
+ stopResults.push({ runId, success: false, error: errMsg });
314
337
  }
315
338
  }
316
339
  set.clear();
340
+ return { runIds, stopResults };
317
341
  }
318
342
  static DEFAULT_WORKFLOW_ENTRY_AGENT = "workflow-runner";
319
343
  resolveEntryAgent(subagentType) {
@@ -758,7 +782,7 @@ Use these as guidance to improve task execution efficiency.`;
758
782
  error: err instanceof Error ? err.message : String(err)
759
783
  });
760
784
  }
761
- await this.propagateStopToWorkflowRuns(taskId, "Task stopped by user");
785
+ const { runIds, stopResults } = await this.propagateStopToWorkflowRuns(taskId, "Task stopped by user");
762
786
  const stoppedPayload = {
763
787
  backgroundTaskId: task.id,
764
788
  subSessionId: task.subSessionId,
@@ -770,7 +794,13 @@ Use these as guidance to improve task execution efficiency.`;
770
794
  associatedTaskId: task.associatedTaskId
771
795
  };
772
796
  this.publishBackgroundEvent(BackgroundTaskEventTypes.STOPPED, stoppedPayload, task.parentSessionId);
773
- return { success: true, task, message: "Task has been stopped" };
797
+ return {
798
+ success: true,
799
+ task,
800
+ message: "Task has been stopped",
801
+ attached_workflow_run_ids: runIds,
802
+ workflow_stop_results: stopResults
803
+ };
774
804
  }
775
805
  getTask(taskId) {
776
806
  return this.tasks.get(taskId);
@@ -817,11 +847,18 @@ __legacyDecorateClassTS([
817
847
  })
818
848
  ], BackgroundTaskManager.prototype, "detachWorkflowRun", null);
819
849
  __legacyDecorateClassTS([
820
- TracedAs("task.background.propagateStopToWorkflowRuns", {
850
+ TracedAs("task.background.replaceWorkflowRun", {
821
851
  recordParams: true,
822
852
  recordResult: false,
823
853
  log: true
824
854
  })
855
+ ], BackgroundTaskManager.prototype, "replaceWorkflowRun", null);
856
+ __legacyDecorateClassTS([
857
+ TracedAs("task.background.propagateStopToWorkflowRuns", {
858
+ recordParams: true,
859
+ recordResult: true,
860
+ log: true
861
+ })
825
862
  ], BackgroundTaskManager.prototype, "propagateStopToWorkflowRuns", null);
826
863
  __legacyDecorateClassTS([
827
864
  TracedAs("task.background.resolveEntryAgent", { recordParams: true, recordResult: true })
@@ -3,6 +3,11 @@ function toEnvKey(key, prefix) {
3
3
  let keyNormalized = key.replace(/[.-]/g, "_");
4
4
  keyNormalized = keyNormalized.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/_+/g, "_").toUpperCase();
5
5
  if (prefix) {
6
+ const prefixCore = prefix.toUpperCase().replace(/^_+|_+$/g, "");
7
+ const prefixCoreWithSep = `${prefixCore}_`;
8
+ if (prefixCore && keyNormalized.startsWith(prefixCoreWithSep)) {
9
+ return keyNormalized;
10
+ }
6
11
  const separator = prefix.endsWith("_") ? "" : "_";
7
12
  return `${prefix}${separator}${keyNormalized}`;
8
13
  }
@@ -1,3 +1,6 @@
1
+ import {
2
+ EnvSource
3
+ } from "./roy-agent-core-y3g3ar7a.js";
1
4
  import {
2
5
  invoke
3
6
  } from "./roy-agent-core-dcd1s7ct.js";
@@ -8,7 +11,7 @@ import {
8
11
  import {
9
12
  envKeyToConfigKey,
10
13
  toEnvKey
11
- } from "./roy-agent-core-qxhq8ven.js";
14
+ } from "./roy-agent-core-7hh0brvs.js";
12
15
  import {
13
16
  BaseComponent
14
17
  } from "./roy-agent-core-j62bjagf.js";
@@ -541,12 +544,42 @@ class LLMComponent extends BaseComponent {
541
544
  await configComponent.set(configKey, value);
542
545
  }
543
546
  }
547
+ if (envSource instanceof EnvSource) {
548
+ const knownKeys = new Set([
549
+ "llm.defaultModel",
550
+ "llm.defaultProvider",
551
+ "llm.temperature",
552
+ "llm.maxTokens",
553
+ "llm.topP",
554
+ "llm.stream",
555
+ "llm.options",
556
+ "llm.default",
557
+ "llm.providers",
558
+ "llm.limits",
559
+ "llm.capabilities"
560
+ ]);
561
+ envSource.validateUnrecognizedEnvVars({
562
+ componentName: "llm",
563
+ knownKeys,
564
+ logger: {
565
+ warn: (msg) => logger.warn(msg)
566
+ }
567
+ });
568
+ }
544
569
  if (config) {
545
570
  const flatConfig = this.flattenConfig(config);
546
571
  for (const [key, value] of Object.entries(flatConfig)) {
547
572
  await configComponent.set(key, value);
548
573
  }
549
574
  }
575
+ const configuredProviders = configComponent.get("llm.providers");
576
+ const configuredDefaultProvider = configComponent.get("llm.defaultProvider");
577
+ if (typeof configuredDefaultProvider === "string" && configuredProviders && typeof configuredProviders === "object" && Object.keys(configuredProviders).length > 0) {
578
+ const providerKeys = Object.keys(configuredProviders);
579
+ if (!providerKeys.includes(configuredDefaultProvider)) {
580
+ throw new Error(`[LLM] Invalid llm.defaultProvider: "${configuredDefaultProvider}". ` + `Known providers: ${providerKeys.join(", ")}. ` + `Add it to llm.providers first, or remove the env var / config entry.`);
581
+ }
582
+ }
550
583
  this.registerConfigWatcher(configComponent);
551
584
  }
552
585
  flattenConfig(obj, prefix = "llm") {