plugin-agent-orchestrator 1.0.22 → 1.0.25

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 (103) hide show
  1. package/client-v2.d.ts +2 -0
  2. package/client-v2.js +1 -0
  3. package/dist/client/index.js +1 -1
  4. package/dist/client-v2/214.723affb37c13bf7a.js +10 -0
  5. package/dist/client-v2/264.0533912e6c5ea2d7.js +10 -0
  6. package/dist/client-v2/41.1805b2edfaa4afe2.js +10 -0
  7. package/dist/client-v2/418.5ae055abf141820e.js +10 -0
  8. package/dist/client-v2/619.d99d3c9e61c99064.js +10 -0
  9. package/dist/client-v2/70.a15d7fcec7c41768.js +10 -0
  10. package/dist/client-v2/892.72db4161511c8a16.js +10 -0
  11. package/dist/client-v2/926.87f660b670d85bcc.js +10 -0
  12. package/dist/client-v2/index.js +10 -0
  13. package/dist/externalVersion.js +8 -6
  14. package/dist/locale/en-US.json +7 -0
  15. package/dist/locale/vi-VN.json +7 -0
  16. package/dist/locale/zh-CN.json +27 -0
  17. package/dist/server/migrations/20260615000000-normalize-ai-employee-tool-bindings.js +63 -0
  18. package/dist/server/plugin.js +32 -1
  19. package/dist/server/services/AgentHarness.js +52 -27
  20. package/dist/server/services/AgentLoopController.js +8 -2
  21. package/dist/server/services/AgentLoopService.js +1 -1
  22. package/dist/server/services/AgentRegistryService.js +53 -42
  23. package/dist/server/services/CircuitBreaker.js +7 -2
  24. package/dist/server/services/CodeValidator.js +48 -14
  25. package/dist/server/services/SandboxRunner.js +18 -14
  26. package/dist/server/skill-hub/plugin.js +44 -17
  27. package/dist/server/tools/delegate-task.js +7 -2
  28. package/dist/server/tools/skill-execute.js +33 -2
  29. package/dist/server/utils/ai-manager.js +51 -0
  30. package/dist/server/utils/ctx-utils.js +11 -0
  31. package/dist/server/utils/skill-settings.js +122 -0
  32. package/package.json +49 -45
  33. package/src/client/AIEmployeesContext.tsx +60 -19
  34. package/src/client/AgentRunsTab.tsx +769 -764
  35. package/src/client/HarnessProfilesTab.tsx +257 -247
  36. package/src/client/RulesTab.tsx +787 -716
  37. package/src/client/TracingTab.tsx +9 -6
  38. package/src/client/plugin.tsx +34 -27
  39. package/src/client/skill-hub/components/ExecutionHistory.tsx +9 -8
  40. package/src/client/skill-hub/components/GitSkillImport.tsx +12 -5
  41. package/src/client/skill-hub/components/LoopSettings.tsx +2 -2
  42. package/src/client/skill-hub/components/SkillEditor.tsx +2 -2
  43. package/src/client/skill-hub/components/SkillManager.tsx +2 -2
  44. package/src/client/skill-hub/components/SkillMetrics.tsx +157 -124
  45. package/src/client/skill-hub/components/SkillTestPanel.tsx +14 -13
  46. package/src/client/skill-hub/index.tsx +58 -51
  47. package/src/client/skill-hub/locale.ts +1 -1
  48. package/src/client/skill-hub/tools/InteractionSchemasProvider.tsx +132 -99
  49. package/src/client/skill-hub/tools/registerSkillLoopCards.ts +71 -58
  50. package/src/client/tools/PlanApprovalCard.tsx +3 -2
  51. package/src/client/tools/registerOrchestratorCards.ts +17 -7
  52. package/src/client-v2/components/AIEmployeeSelect.tsx +47 -0
  53. package/src/client-v2/components/AIEmployeesContext.tsx +110 -0
  54. package/src/client-v2/components/AgentRunsTab.tsx +767 -0
  55. package/src/client-v2/components/HarnessProfilesTab.tsx +254 -0
  56. package/src/client-v2/components/RulesTab.tsx +782 -0
  57. package/src/client-v2/components/TracingTab.tsx +432 -0
  58. package/src/client-v2/hooks/useApiRequest.ts +114 -0
  59. package/src/client-v2/index.tsx +1 -0
  60. package/src/client-v2/pages/AgentRunsPage.tsx +13 -0
  61. package/src/client-v2/pages/ExecutionHistoryPage.tsx +10 -0
  62. package/src/client-v2/pages/HarnessProfilesPage.tsx +10 -0
  63. package/src/client-v2/pages/LoopSettingsPage.tsx +10 -0
  64. package/src/client-v2/pages/RulesPage.tsx +13 -0
  65. package/src/client-v2/pages/SkillDefinitionsPage.tsx +10 -0
  66. package/src/client-v2/pages/SkillMetricsPage.tsx +10 -0
  67. package/src/client-v2/pages/TracingPage.tsx +13 -0
  68. package/src/client-v2/plugin.tsx +70 -0
  69. package/src/client-v2/skill-hub/components/ExecutionHistory.tsx +196 -0
  70. package/src/client-v2/skill-hub/components/FileLinkList.tsx +37 -0
  71. package/src/client-v2/skill-hub/components/GitSkillImport.tsx +539 -0
  72. package/src/client-v2/skill-hub/components/LoopSettings.tsx +331 -0
  73. package/src/client-v2/skill-hub/components/SkillEditor.tsx +453 -0
  74. package/src/client-v2/skill-hub/components/SkillManager.tsx +174 -0
  75. package/src/client-v2/skill-hub/components/SkillMetrics.tsx +157 -0
  76. package/src/client-v2/skill-hub/components/SkillTestPanel.tsx +135 -0
  77. package/src/client-v2/skill-hub/locale.ts +13 -0
  78. package/src/client-v2/skill-hub/tools/loopTemplates.ts +52 -0
  79. package/src/client-v2/skill-hub/utils/jsonFields.ts +41 -0
  80. package/src/client-v2/utils/jsonFields.ts +41 -0
  81. package/src/locale/en-US.json +7 -0
  82. package/src/locale/vi-VN.json +7 -0
  83. package/src/locale/zh-CN.json +27 -0
  84. package/src/server/__tests__/agent-registry-service.test.ts +147 -0
  85. package/src/server/__tests__/code-validator.test.ts +63 -0
  86. package/src/server/__tests__/skill-execute.test.ts +33 -0
  87. package/src/server/__tests__/skill-settings.test.ts +63 -0
  88. package/src/server/migrations/20260615000000-normalize-ai-employee-tool-bindings.ts +39 -0
  89. package/src/server/plugin.ts +62 -21
  90. package/src/server/services/AgentHarness.ts +49 -22
  91. package/src/server/services/AgentLoopController.ts +17 -6
  92. package/src/server/services/AgentLoopService.ts +1 -1
  93. package/src/server/services/AgentPlannerService.ts +10 -0
  94. package/src/server/services/AgentRegistryService.ts +89 -47
  95. package/src/server/services/CircuitBreaker.ts +10 -0
  96. package/src/server/services/CodeValidator.ts +237 -159
  97. package/src/server/services/SandboxRunner.ts +203 -189
  98. package/src/server/skill-hub/plugin.ts +933 -898
  99. package/src/server/tools/delegate-task.ts +12 -9
  100. package/src/server/tools/skill-execute.ts +194 -160
  101. package/src/server/utils/ai-manager.ts +24 -0
  102. package/src/server/utils/ctx-utils.ts +14 -0
  103. package/src/server/utils/skill-settings.ts +116 -0
@@ -11,12 +11,14 @@ module.exports = {
11
11
  "react": "18.2.0",
12
12
  "antd": "5.24.2",
13
13
  "@ant-design/icons": "5.6.1",
14
- "@nocobase/client": "2.0.60",
15
- "@nocobase/server": "2.0.60",
16
- "@nocobase/database": "2.0.60",
14
+ "ahooks": "3.7.8",
15
+ "@nocobase/client-v2": "2.1.6",
16
+ "@nocobase/client": "2.1.6",
17
+ "@nocobase/server": "2.1.6",
18
+ "@nocobase/database": "2.1.6",
17
19
  "@langchain/langgraph": "0.2.74",
18
20
  "@langchain/core": "0.3.80",
19
- "@nocobase/actions": "2.0.60",
20
- "@nocobase/plugin-ai": "2.0.60",
21
- "@nocobase/ai": "2.0.60"
21
+ "@nocobase/ai": "2.1.6",
22
+ "@nocobase/actions": "2.1.6",
23
+ "@nocobase/plugin-ai": "2.1.6"
22
24
  };
@@ -1,6 +1,13 @@
1
1
  {
2
2
  "Agent Orchestrator": "Agent Orchestrator",
3
3
  "Orchestration Rules": "Orchestration Rules",
4
+ "Execution Tracing": "Execution Tracing",
5
+ "Agent Runs": "Agent Runs",
6
+ "Harness Profiles": "Harness Profiles",
7
+ "Skill Hub Definitions": "Skill Hub Definitions",
8
+ "Execution History": "Execution History",
9
+ "Skill Review Settings": "Skill Review Settings",
10
+ "Metrics": "Metrics",
4
11
  "Swarm Tracing": "Swarm Tracing",
5
12
  "Leader (Orchestrator)": "Leader (Orchestrator)",
6
13
  "Sub-Agent": "Sub-Agent",
@@ -1,6 +1,13 @@
1
1
  {
2
2
  "Agent Orchestrator": "Điều phối Agent",
3
3
  "Orchestration Rules": "Quy tắc điều phối",
4
+ "Execution Tracing": "Truy vết thực thi",
5
+ "Agent Runs": "Lượt chạy Agent",
6
+ "Harness Profiles": "Hồ sơ Harness",
7
+ "Skill Hub Definitions": "Định nghĩa Skill Hub",
8
+ "Execution History": "Lịch sử thực thi",
9
+ "Skill Review Settings": "Cài đặt duyệt Skill",
10
+ "Metrics": "Số liệu",
4
11
  "Swarm Tracing": "Truy vết Swarm",
5
12
  "Leader (Orchestrator)": "Leader (Điều phối viên)",
6
13
  "Sub-Agent": "Agent con",
@@ -0,0 +1,27 @@
1
+ {
2
+ "Agent Orchestrator": "智能体编排",
3
+ "Orchestration Rules": "编排规则",
4
+ "Execution Tracing": "执行追踪",
5
+ "Agent Runs": "智能体运行",
6
+ "Harness Profiles": "Harness 配置",
7
+ "Skill Hub Definitions": "技能中心定义",
8
+ "Execution History": "执行历史",
9
+ "Skill Review Settings": "技能审核设置",
10
+ "Metrics": "指标",
11
+ "Swarm Tracing": "集群追踪",
12
+ "Leader (Orchestrator)": "主控(编排者)",
13
+ "Sub-Agent": "子智能体",
14
+ "Max Delegation Depth": "最大委派深度",
15
+ "Timeout (ms)": "超时时间(毫秒)",
16
+ "Enabled": "已启用",
17
+ "New Rule": "新建规则",
18
+ "Edit Orchestration Rule": "编辑编排规则",
19
+ "New Orchestration Rule": "新建编排规则",
20
+ "Rule created": "规则已创建",
21
+ "Rule updated": "规则已更新",
22
+ "Rule deleted": "规则已删除",
23
+ "Sub-Agent Conversation": "子智能体对话",
24
+ "Task Summary": "任务摘要",
25
+ "Parent Session": "父会话",
26
+ "No sub-agent executions yet": "暂无子智能体执行记录"
27
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var normalize_ai_employee_tool_bindings_exports = {};
28
+ __export(normalize_ai_employee_tool_bindings_exports, {
29
+ default: () => NormalizeAIEmployeeToolBindings
30
+ });
31
+ module.exports = __toCommonJS(normalize_ai_employee_tool_bindings_exports);
32
+ var import_server = require("@nocobase/server");
33
+ var import_skill_settings = require("../utils/skill-settings");
34
+ class NormalizeAIEmployeeToolBindings extends import_server.Migration {
35
+ on = "afterLoad";
36
+ appVersion = ">=0.1.0";
37
+ async up() {
38
+ var _a, _b, _c, _d;
39
+ const repo = this.db.getRepository(
40
+ "aiEmployees"
41
+ );
42
+ if (!repo) return;
43
+ const rows = await repo.find({});
44
+ let updated = 0;
45
+ for (const row of rows) {
46
+ const skillSettings = ((_a = row.get) == null ? void 0 : _a.call(row, "skillSettings")) ?? row.skillSettings;
47
+ const normalized = (0, import_skill_settings.normalizeAIEmployeeSkillSettings)(skillSettings);
48
+ if (!normalized.changed) continue;
49
+ await row.update({
50
+ skillSettings: normalized.skillSettings
51
+ });
52
+ updated += 1;
53
+ }
54
+ if (updated > 0) {
55
+ (_d = (_c = (_b = this.app) == null ? void 0 : _b.logger) == null ? void 0 : _c.info) == null ? void 0 : _d.call(
56
+ _c,
57
+ `[AgentOrchestrator] Normalized AI employee tool bindings (${updated}).`
58
+ );
59
+ }
60
+ }
61
+ async down() {
62
+ }
63
+ }
@@ -50,6 +50,8 @@ var import_agent_loop = require("./resources/agent-loop");
50
50
  var import_RunEventBus = require("./services/RunEventBus");
51
51
  var import_plugin = __toESM(require("./skill-hub/plugin"));
52
52
  var import_AgentLoopService = require("./services/AgentLoopService");
53
+ var import_ctx_utils = require("./utils/ctx-utils");
54
+ var import_ai_manager = require("./utils/ai-manager");
53
55
  class PluginAgentOrchestratorServer extends import_server.Plugin {
54
56
  skillHub;
55
57
  agentLoopService;
@@ -95,7 +97,21 @@ class PluginAgentOrchestratorServer extends import_server.Plugin {
95
97
  this.app.acl.allow("skillHub", "test", "loggedIn");
96
98
  this.app.acl.allow("skillHub", "download", "loggedIn");
97
99
  this.app.acl.allow("skillHub", "listTemplates", "loggedIn");
98
- const toolsManager = this.app.aiManager.toolsManager;
100
+ this.app.resourceManager.use(
101
+ async (ctx, next) => {
102
+ const { resourceName, actionName } = ctx.action || {};
103
+ if (resourceName === "skillExecutions" && (actionName === "list" || actionName === "get")) {
104
+ if (!(0, import_ctx_utils.isAdminUser)(ctx)) {
105
+ const userId = (0, import_ctx_utils.currentUserId)(ctx);
106
+ const ownerFilter = userId ? { triggeredById: userId } : { triggeredById: null };
107
+ ctx.action.mergeParams({ filter: ownerFilter });
108
+ }
109
+ }
110
+ await next();
111
+ },
112
+ { tag: "orchestrator-skill-executions-scope", after: "acl" }
113
+ );
114
+ const toolsManager = (0, import_ai_manager.getAIToolsManager)(this.app);
99
115
  toolsManager.registerTools((0, import_orchestrator_plan.createOrchestratorPlanTools)(this, this.agentLoopService));
100
116
  toolsManager.registerTools((0, import_external_rag_search.createExternalRagSearchTool)(this));
101
117
  toolsManager.registerDynamicTools((0, import_delegate_task.createDelegateToolsProvider)(this));
@@ -110,6 +126,21 @@ class PluginAgentOrchestratorServer extends import_server.Plugin {
110
126
  ctx.throw(400, "runId query parameter is required.");
111
127
  return;
112
128
  }
129
+ if (!(0, import_ctx_utils.isAdminUser)(ctx)) {
130
+ const userId = (0, import_ctx_utils.currentUserId)(ctx);
131
+ const run = await ctx.db.getRepository("agentLoopRuns").findOne({
132
+ filter: { id: runId }
133
+ });
134
+ if (!run) {
135
+ ctx.throw(404, "Run not found.");
136
+ return;
137
+ }
138
+ const ownerId = run.get ? run.get("userId") : run.userId;
139
+ if (!userId || String(ownerId) !== String(userId)) {
140
+ ctx.throw(403, "You cannot stream events for this run.");
141
+ return;
142
+ }
143
+ }
113
144
  ctx.type = "text/event-stream";
114
145
  ctx.set("Cache-Control", "no-cache");
115
146
  ctx.set("Connection", "keep-alive");
@@ -38,7 +38,9 @@ var import_TokenTracker = require("./TokenTracker");
38
38
  var import_ContextAggregator = require("./ContextAggregator");
39
39
  var import_CircuitBreaker = require("./CircuitBreaker");
40
40
  var import_ctx_utils = require("../utils/ctx-utils");
41
+ var import_skill_settings = require("../utils/skill-settings");
41
42
  var import_logging = require("../utils/logging");
43
+ var import_ai_manager = require("../utils/ai-manager");
42
44
  const ORCHESTRATOR_DEPTH_KEY = "__orchestratorDepth";
43
45
  const ORCHESTRATOR_PATH_KEY = "__orchestratorPath";
44
46
  function sanitizeToolPart(value) {
@@ -48,11 +50,11 @@ function buildDelegateToolName(leaderUsername, subAgentUsername) {
48
50
  return `delegate_${sanitizeToolPart(leaderUsername)}_to_${sanitizeToolPart(subAgentUsername)}`;
49
51
  }
50
52
  class AgentHarness {
51
- constructor(plugin, registryService) {
53
+ constructor(plugin, registryService, tokenTracker) {
52
54
  this.plugin = plugin;
53
55
  this.registryService = registryService;
54
56
  this.spanService = new import_ExecutionSpanService.ExecutionSpanService(plugin);
55
- this.tokenTracker = new import_TokenTracker.TokenTracker(plugin);
57
+ this.tokenTracker = tokenTracker || new import_TokenTracker.TokenTracker(plugin);
56
58
  this.contextAggregator = new import_ContextAggregator.ContextAggregator(plugin);
57
59
  }
58
60
  spanService;
@@ -117,25 +119,26 @@ class AgentHarness {
117
119
  2e4
118
120
  );
119
121
  const circuitBreaker = (0, import_CircuitBreaker.getCircuitBreaker)({ appLog: this.app });
120
- if (!circuitBreaker.isAllowed(target)) {
121
- const state = circuitBreaker.getState(target);
122
+ const circuitKey = (0, import_CircuitBreaker.subAgentCircuitKey)(run.leaderUsername, target);
123
+ if (!circuitBreaker.isAllowed(circuitKey)) {
124
+ const state = circuitBreaker.getState(circuitKey);
122
125
  throw new Error(
123
126
  `Sub-agent "${target}" circuit is open (${(state == null ? void 0 : state.failures) || 0} failures). Retry after the recovery timeout.`
124
127
  );
125
128
  }
126
129
  try {
127
130
  const result = await this.invokeNamedTool(run, step, toolName, { task, context }, settings, options);
128
- circuitBreaker.recordSuccess(target);
131
+ circuitBreaker.recordSuccess(circuitKey);
129
132
  return result;
130
133
  } catch (e) {
131
134
  if ((e == null ? void 0 : e.message) !== "requires_approval") {
132
- circuitBreaker.recordFailure(target);
135
+ circuitBreaker.recordFailure(circuitKey);
133
136
  }
134
137
  throw e;
135
138
  }
136
139
  }
137
140
  async invokeNamedTool(run, step, toolName, args, settings, options) {
138
- var _a, _b, _c, _d, _e;
141
+ var _a, _b, _c;
139
142
  if (String(toolName).startsWith("orchestrator_")) {
140
143
  throw new Error(`Tool step "${step.planKey}" cannot call internal orchestrator control tool "${toolName}".`);
141
144
  }
@@ -149,25 +152,34 @@ class AgentHarness {
149
152
  throw new Error(`Tool "${toolName}" is on the denied list for harness profile.`);
150
153
  }
151
154
  }
152
- const toolsManager = (_b = (_a = this.app) == null ? void 0 : _a.aiManager) == null ? void 0 : _b.toolsManager;
153
- const tool = await ((_c = toolsManager == null ? void 0 : toolsManager.getTools) == null ? void 0 : _c.call(toolsManager, toolName));
155
+ const toolsManager = (0, import_ai_manager.tryGetAIToolsManager)(this.app);
156
+ const tool = await ((_a = toolsManager == null ? void 0 : toolsManager.getTools) == null ? void 0 : _a.call(toolsManager, toolName));
154
157
  if (!(tool == null ? void 0 : tool.invoke)) {
155
158
  throw new Error(`Tool "${toolName}" was not found or is missing standard invoke handler.`);
156
159
  }
157
160
  const isDelegationTool = await this.registryService.isRegisteredDelegationTool(toolName);
158
- const isStepAlreadyApproved = ((_d = step == null ? void 0 : step.approval) == null ? void 0 : _d.approved) === true;
161
+ const isStepAlreadyApproved = ((_b = step == null ? void 0 : step.approval) == null ? void 0 : _b.approved) === true;
159
162
  if (!isDelegationTool && !isStepAlreadyApproved && (tool.defaultPermission === "ASK" || settings.requireApprovalRiskLevel && tool.riskLevel && tool.riskLevel >= settings.requireApprovalRiskLevel)) {
160
163
  throw new Error("requires_approval");
161
164
  }
162
165
  const ctx = options.ctx || {};
163
166
  const previousEmployee = ctx._currentAIEmployee;
164
- const previousStateEmployee = (_e = ctx.state) == null ? void 0 : _e.currentAIEmployee;
167
+ const previousStateEmployee = (_c = ctx.state) == null ? void 0 : _c.currentAIEmployee;
165
168
  if (run.leaderUsername) {
166
169
  ctx._currentAIEmployee = run.leaderUsername;
167
170
  ctx.state = { ...ctx.state || {}, currentAIEmployee: run.leaderUsername };
168
171
  }
172
+ const previousRuntime = ctx.runtime;
173
+ const toolCallId = `agent-loop-${run.id}-${step.id}`;
174
+ const runtime = {
175
+ toolCallId,
176
+ writer: (chunk) => {
177
+ this.app.log.trace(`[AgentHarness] Tool output:`, chunk);
178
+ }
179
+ };
180
+ ctx.runtime = runtime;
169
181
  try {
170
- const result = await tool.invoke(ctx, args, `agent-loop-${run.id}-${step.id}`);
182
+ const result = await tool.invoke(ctx, args, runtime);
171
183
  if ((result == null ? void 0 : result.status) === "error") {
172
184
  throw new Error(result.content || `Tool "${toolName}" returned an error.`);
173
185
  }
@@ -177,6 +189,11 @@ class AgentHarness {
177
189
  result
178
190
  };
179
191
  } finally {
192
+ if (previousRuntime === void 0) {
193
+ delete ctx.runtime;
194
+ } else {
195
+ ctx.runtime = previousRuntime;
196
+ }
180
197
  if (previousEmployee === void 0) {
181
198
  delete ctx._currentAIEmployee;
182
199
  } else {
@@ -192,7 +209,7 @@ class AgentHarness {
192
209
  }
193
210
  }
194
211
  async runSubAgent(ctx, options) {
195
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
212
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
196
213
  const {
197
214
  leaderUsername,
198
215
  subAgentUsername,
@@ -211,6 +228,7 @@ class AgentHarness {
211
228
  agentLoopRunId,
212
229
  agentLoopStepId
213
230
  } = options;
231
+ const effectiveRootRunId = rootRunId || `run_${Date.now()}`;
214
232
  const startTime = Date.now();
215
233
  const currentDepth = options.currentDepth ?? 0;
216
234
  const currentPath = options.currentPath ?? [leaderUsername];
@@ -223,7 +241,7 @@ class AgentHarness {
223
241
  }
224
242
  ];
225
243
  const executionSpan = await this.spanService.create({
226
- rootRunId: rootRunId || `run_${Date.now()}`,
244
+ rootRunId: effectiveRootRunId,
227
245
  parentSpanId,
228
246
  type: "sub_agent",
229
247
  status: "running",
@@ -274,18 +292,17 @@ class AgentHarness {
274
292
  model: modelSettings.model
275
293
  });
276
294
  const chatModel = provider.createModel();
277
- const coreToolsManager = ctx.app.aiManager.toolsManager;
295
+ const coreToolsManager = (0, import_ai_manager.getAIToolsManager)(ctx.app);
278
296
  const allTools = await coreToolsManager.listTools();
279
- const employeeSkills = (((_e = subAgentEmployee.skillSettings) == null ? void 0 : _e.skills) ?? []).map(
280
- (s) => typeof s === "string" ? { name: s, autoCall: false } : { name: s == null ? void 0 : s.name, autoCall: (s == null ? void 0 : s.autoCall) === true }
281
- ).filter((s) => Boolean(s.name));
282
- const employeeSkillMap = new Map(employeeSkills.map((s) => [s.name, s]));
297
+ const normalizedSkillSettings = (0, import_skill_settings.normalizeAIEmployeeSkillSettings)(subAgentEmployee.skillSettings).skillSettings;
298
+ const employeeTools = normalizedSkillSettings.tools.filter((tool) => Boolean(tool.name));
299
+ const employeeToolMap = new Map(employeeTools.map((tool) => [tool.name, tool]));
283
300
  const langchainTools = [];
284
301
  for (const toolEntry of allTools) {
285
302
  const entryName = toolEntry.definition.name;
286
303
  if (!entryName) continue;
287
- const employeeSkill = employeeSkillMap.get(entryName);
288
- if (!employeeSkill || employeeSkill.autoCall !== true || toolEntry.defaultPermission !== "ALLOW") {
304
+ const employeeTool = employeeToolMap.get(entryName);
305
+ if (!employeeTool || employeeTool.autoCall !== true || toolEntry.execution === "frontend") {
289
306
  continue;
290
307
  }
291
308
  langchainTools.push(
@@ -306,7 +323,7 @@ class AgentHarness {
306
323
  const toolStartedAt = Date.now();
307
324
  const isSkillHubTool = entryName === "skill_hub_execute" || entryName.startsWith("skill_hub_");
308
325
  const toolSpan = await this.spanService.create({
309
- rootRunId: rootRunId || `run_${Date.now()}`,
326
+ rootRunId: effectiveRootRunId,
310
327
  parentSpanId: executionSpanId,
311
328
  type: isSkillHubTool ? "skill" : "tool",
312
329
  status: "running",
@@ -325,7 +342,7 @@ class AgentHarness {
325
342
  });
326
343
  const toolSpanId = (toolSpan == null ? void 0 : toolSpan.id) ? String(toolSpan.id) : void 0;
327
344
  (0, import_ExecutionSpanService.setOrchestratorTraceContext)(invokeCtx, {
328
- rootRunId,
345
+ rootRunId: effectiveRootRunId,
329
346
  spanId: toolSpanId,
330
347
  parentSpanId: executionSpanId,
331
348
  toolCallId: `orch-${toolCallId}`,
@@ -342,8 +359,16 @@ class AgentHarness {
342
359
  toolName: toolEntry.definition.name,
343
360
  args: toolArgs
344
361
  });
362
+ const subToolCallId = `orch-${toolCallId}`;
363
+ const runtime = {
364
+ toolCallId: subToolCallId,
365
+ writer: (chunk) => {
366
+ this.app.log.trace(`[AgentHarness] Tool output:`, chunk);
367
+ }
368
+ };
369
+ invokeCtx.runtime = runtime;
345
370
  try {
346
- const res = await toolEntry.invoke(invokeCtx, toolArgs, `orch-${toolCallId}`);
371
+ const res = await toolEntry.invoke(invokeCtx, toolArgs, runtime);
347
372
  const output = (0, import_ctx_utils.trimText)((res == null ? void 0 : res.content) ?? (res == null ? void 0 : res.result) ?? res, 5e4);
348
373
  trace.push({
349
374
  type: "tool_result",
@@ -388,13 +413,13 @@ class AgentHarness {
388
413
  llm: chatModel,
389
414
  tools: langchainTools
390
415
  });
391
- let systemPrompt = ((_f = subAgentEmployee.chatSettings) == null ? void 0 : _f.systemPrompt) || subAgentEmployee.bio || `You are an AI assistant named "${subAgentEmployee.nickname || subAgentUsername}". ${subAgentEmployee.about || ""}`;
416
+ let systemPrompt = ((_e = subAgentEmployee.chatSettings) == null ? void 0 : _e.systemPrompt) || subAgentEmployee.bio || `You are an AI assistant named "${subAgentEmployee.nickname || subAgentUsername}". ${subAgentEmployee.about || ""}`;
392
417
  try {
393
418
  const kbPlugin = ctx.app.pm.get("plugin-knowledge-base");
394
419
  if (kbPlugin == null ? void 0 : kbPlugin.sessionContext) {
395
- const sessionId = ((_i = (_h = (_g = ctx.action) == null ? void 0 : _g.params) == null ? void 0 : _h.values) == null ? void 0 : _i.sessionId) || ((_k = (_j = ctx.action) == null ? void 0 : _j.params) == null ? void 0 : _k.sessionId) || ((_l = ctx.state) == null ? void 0 : _l.sessionId);
420
+ const sessionId = ((_h = (_g = (_f = ctx.action) == null ? void 0 : _f.params) == null ? void 0 : _g.values) == null ? void 0 : _h.sessionId) || ((_j = (_i = ctx.action) == null ? void 0 : _i.params) == null ? void 0 : _j.sessionId) || ((_k = ctx.state) == null ? void 0 : _k.sessionId);
396
421
  const contextSummary = await kbPlugin.sessionContext.buildSummary(
397
- { rootRunId, ...sessionId ? { sessionId } : {} },
422
+ { rootRunId: effectiveRootRunId, ...sessionId ? { sessionId } : {} },
398
423
  6e3
399
424
  );
400
425
  if (contextSummary) {
@@ -670,7 +670,7 @@ class AgentLoopController {
670
670
  const target = step.target || "";
671
671
  if (target) {
672
672
  const circuitBreaker = (0, import_CircuitBreaker.getCircuitBreaker)();
673
- const state = circuitBreaker.getState(target);
673
+ const state = circuitBreaker.getState((0, import_CircuitBreaker.subAgentCircuitKey)(run.leaderUsername, target));
674
674
  const attempt = Number(step.attempt || 0);
675
675
  const shouldRoute = (state == null ? void 0 : state.state) === "open" || state && state.failures >= 2 && attempt >= 1;
676
676
  if (shouldRoute) {
@@ -846,6 +846,8 @@ class AgentLoopController {
846
846
  const results = await Promise.allSettled(
847
847
  runningSteps.map((step) => this.harness.executeStep(snapshot.run, step, options))
848
848
  );
849
+ let batchBackoffMs = 0;
850
+ let approvalBreak = false;
849
851
  for (let i = 0; i < results.length; i++) {
850
852
  const runningStep = runningSteps[i];
851
853
  const result = results[i];
@@ -862,6 +864,7 @@ class AgentLoopController {
862
864
  { prompt: `Execution of step "${runningStep.title}" requires permission.` },
863
865
  { userId: options.userId, reason: "Dynamic tool approval required by policy." }
864
866
  );
867
+ approvalBreak = true;
865
868
  break;
866
869
  }
867
870
  snapshot = await this.failStep(runningStep.id, (error == null ? void 0 : error.message) || String(error), {
@@ -874,10 +877,13 @@ class AgentLoopController {
874
877
  const baseDelay = 1e3;
875
878
  const maxDelay = 6e4;
876
879
  const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay);
877
- await new Promise((resolve) => setTimeout(resolve, delay));
880
+ batchBackoffMs = Math.max(batchBackoffMs, delay);
878
881
  }
879
882
  }
880
883
  }
884
+ if (!approvalBreak && batchBackoffMs > 0) {
885
+ await new Promise((resolve) => setTimeout(resolve, batchBackoffMs));
886
+ }
881
887
  snapshot = await this.getRunSnapshot(runId);
882
888
  if (snapshot.run.status === "waiting_user") {
883
889
  break;
@@ -43,8 +43,8 @@ class AgentLoopService {
43
43
  this.plannerService = new import_AgentPlannerService.AgentPlannerService();
44
44
  this.validator = new import_AgentPlanValidator.AgentPlanValidator();
45
45
  this.repository = new import_AgentLoopRepository.AgentLoopRepository(plugin);
46
- this.harness = new import_AgentHarness.AgentHarness(plugin, this.registryService);
47
46
  const tokenTracker = new import_TokenTracker.TokenTracker(plugin);
47
+ this.harness = new import_AgentHarness.AgentHarness(plugin, this.registryService, tokenTracker);
48
48
  this.controller = new import_AgentLoopController.AgentLoopController(
49
49
  this.registryService,
50
50
  this.plannerService,
@@ -30,6 +30,33 @@ __export(AgentRegistryService_exports, {
30
30
  });
31
31
  module.exports = __toCommonJS(AgentRegistryService_exports);
32
32
  var import_ctx_utils = require("../utils/ctx-utils");
33
+ function extractModelRef(value) {
34
+ if (!value) return void 0;
35
+ const isValid = (m) => Boolean((m == null ? void 0 : m.llmService) && (m == null ? void 0 : m.model));
36
+ if (value.enabled) {
37
+ const models = Array.isArray(value.models) ? value.models : [];
38
+ const first = models.find(isValid);
39
+ if (first) {
40
+ return { llmService: first.llmService, model: first.model };
41
+ }
42
+ }
43
+ if (isValid(value)) {
44
+ return { llmService: value.llmService, model: value.model };
45
+ }
46
+ return void 0;
47
+ }
48
+ function sanitizeToolPart(value) {
49
+ return (value || "").replace(/[^a-zA-Z0-9_-]/g, "_");
50
+ }
51
+ function buildDelegateToolName(leaderUsername, subAgentUsername) {
52
+ return `delegate_${sanitizeToolPart(leaderUsername)}_to_${sanitizeToolPart(subAgentUsername)}`;
53
+ }
54
+ function buildDispatchToolName(leaderUsername) {
55
+ return `dispatch_subagents_${sanitizeToolPart(leaderUsername)}`;
56
+ }
57
+ function buildLegacyDelegateToolName(subAgentUsername) {
58
+ return `delegate_to_${sanitizeToolPart(subAgentUsername)}`;
59
+ }
33
60
  class AgentRegistryService {
34
61
  constructor(plugin) {
35
62
  this.plugin = plugin;
@@ -85,22 +112,22 @@ class AgentRegistryService {
85
112
  if (!subAgent) {
86
113
  throw new Error(`Sub-agent "${subAgentUsername}" was not found.`);
87
114
  }
88
- const hasModelSettings = (val) => {
89
- return Boolean((val == null ? void 0 : val.llmService) && (val == null ? void 0 : val.model));
90
- };
91
- let modelSettings = hasModelSettings(dynamicValues) ? dynamicValues : void 0;
92
- if (!modelSettings) {
93
- if (hasModelSettings(subAgent.modelSettings)) {
94
- modelSettings = subAgent.modelSettings;
95
- }
115
+ const dynamic = extractModelRef(dynamicValues);
116
+ if (dynamic) {
117
+ return dynamic;
96
118
  }
97
- if (!modelSettings && leaderUsername) {
119
+ const subAgentModel = extractModelRef(subAgent.modelSettings);
120
+ if (subAgentModel) {
121
+ return subAgentModel;
122
+ }
123
+ if (leaderUsername) {
98
124
  const leader = await this.getAIEmployee(leaderUsername);
99
- if (leader && hasModelSettings(leader.modelSettings)) {
100
- modelSettings = leader.modelSettings;
125
+ const leaderModel = extractModelRef(leader == null ? void 0 : leader.modelSettings);
126
+ if (leaderModel) {
127
+ return leaderModel;
101
128
  }
102
129
  }
103
- return modelSettings;
130
+ return void 0;
104
131
  }
105
132
  /**
106
133
  * Find alternative sub-agents for the same leader, excluding a specific one.
@@ -140,42 +167,26 @@ class AgentRegistryService {
140
167
  try {
141
168
  const configRepo = this.db.getRepository("orchestratorConfig");
142
169
  if (!configRepo) return false;
170
+ const configs = await configRepo.find({
171
+ filter: { enabled: true }
172
+ });
173
+ if (!configs || configs.length === 0) return false;
143
174
  if (toolName.startsWith("dispatch_subagents_")) {
144
- const leader = toolName.substring("dispatch_subagents_".length);
145
- const count = await configRepo.count({
146
- filter: {
147
- leaderUsername: leader,
148
- enabled: true
149
- }
150
- });
151
- return count > 0;
152
- }
153
- if (toolName.startsWith("delegate_") && toolName.includes("_to_")) {
154
- const parts = toolName.substring("delegate_".length).split("_to_");
155
- if (parts.length === 2) {
156
- const [leader, subAgent] = parts;
157
- const count = await configRepo.count({
158
- filter: {
159
- leaderUsername: leader,
160
- subAgentUsername: subAgent,
161
- enabled: true
162
- }
163
- });
164
- if (count > 0) return true;
165
- }
175
+ return configs.some((config) => buildDispatchToolName(config.leaderUsername || "") === toolName);
166
176
  }
167
177
  if (toolName.startsWith("delegate_to_")) {
168
- const subAgent = toolName.substring("delegate_to_".length);
169
- const configs = await configRepo.find({
170
- filter: {
171
- subAgentUsername: subAgent,
172
- enabled: true
173
- }
174
- });
175
- if ((configs == null ? void 0 : configs.length) === 1) {
178
+ const matchingConfigs = configs.filter(
179
+ (config) => buildLegacyDelegateToolName(config.subAgentUsername || "") === toolName
180
+ );
181
+ if (matchingConfigs.length === 1) {
176
182
  return true;
177
183
  }
178
184
  }
185
+ if (toolName.startsWith("delegate_") && toolName.includes("_to_")) {
186
+ return configs.some(
187
+ (config) => buildDelegateToolName(config.leaderUsername || "", config.subAgentUsername || "") === toolName
188
+ );
189
+ }
179
190
  return false;
180
191
  } catch {
181
192
  return false;
@@ -27,7 +27,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
27
27
  var CircuitBreaker_exports = {};
28
28
  __export(CircuitBreaker_exports, {
29
29
  CircuitBreakerRegistry: () => CircuitBreakerRegistry,
30
- getCircuitBreaker: () => getCircuitBreaker
30
+ getCircuitBreaker: () => getCircuitBreaker,
31
+ subAgentCircuitKey: () => subAgentCircuitKey
31
32
  });
32
33
  module.exports = __toCommonJS(CircuitBreaker_exports);
33
34
  class CircuitBreakerRegistry {
@@ -106,6 +107,9 @@ class CircuitBreakerRegistry {
106
107
  return Array.from(this.circuits.keys());
107
108
  }
108
109
  }
110
+ function subAgentCircuitKey(leaderUsername, target) {
111
+ return leaderUsername ? `${leaderUsername}::${target}` : target;
112
+ }
109
113
  let globalInstance = null;
110
114
  function getCircuitBreaker(options) {
111
115
  if (!globalInstance) {
@@ -116,5 +120,6 @@ function getCircuitBreaker(options) {
116
120
  // Annotate the CommonJS export names for ESM import in node:
117
121
  0 && (module.exports = {
118
122
  CircuitBreakerRegistry,
119
- getCircuitBreaker
123
+ getCircuitBreaker,
124
+ subAgentCircuitKey
120
125
  });