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.
- package/client-v2.d.ts +2 -0
- package/client-v2.js +1 -0
- package/dist/client/index.js +1 -1
- package/dist/client-v2/214.723affb37c13bf7a.js +10 -0
- package/dist/client-v2/264.0533912e6c5ea2d7.js +10 -0
- package/dist/client-v2/41.1805b2edfaa4afe2.js +10 -0
- package/dist/client-v2/418.5ae055abf141820e.js +10 -0
- package/dist/client-v2/619.d99d3c9e61c99064.js +10 -0
- package/dist/client-v2/70.a15d7fcec7c41768.js +10 -0
- package/dist/client-v2/892.72db4161511c8a16.js +10 -0
- package/dist/client-v2/926.87f660b670d85bcc.js +10 -0
- package/dist/client-v2/index.js +10 -0
- package/dist/externalVersion.js +8 -6
- package/dist/locale/en-US.json +7 -0
- package/dist/locale/vi-VN.json +7 -0
- package/dist/locale/zh-CN.json +27 -0
- package/dist/server/migrations/20260615000000-normalize-ai-employee-tool-bindings.js +63 -0
- package/dist/server/plugin.js +32 -1
- package/dist/server/services/AgentHarness.js +52 -27
- package/dist/server/services/AgentLoopController.js +8 -2
- package/dist/server/services/AgentLoopService.js +1 -1
- package/dist/server/services/AgentRegistryService.js +53 -42
- package/dist/server/services/CircuitBreaker.js +7 -2
- package/dist/server/services/CodeValidator.js +48 -14
- package/dist/server/services/SandboxRunner.js +18 -14
- package/dist/server/skill-hub/plugin.js +44 -17
- package/dist/server/tools/delegate-task.js +7 -2
- package/dist/server/tools/skill-execute.js +33 -2
- package/dist/server/utils/ai-manager.js +51 -0
- package/dist/server/utils/ctx-utils.js +11 -0
- package/dist/server/utils/skill-settings.js +122 -0
- package/package.json +49 -45
- package/src/client/AIEmployeesContext.tsx +60 -19
- package/src/client/AgentRunsTab.tsx +769 -764
- package/src/client/HarnessProfilesTab.tsx +257 -247
- package/src/client/RulesTab.tsx +787 -716
- package/src/client/TracingTab.tsx +9 -6
- package/src/client/plugin.tsx +34 -27
- package/src/client/skill-hub/components/ExecutionHistory.tsx +9 -8
- package/src/client/skill-hub/components/GitSkillImport.tsx +12 -5
- package/src/client/skill-hub/components/LoopSettings.tsx +2 -2
- package/src/client/skill-hub/components/SkillEditor.tsx +2 -2
- package/src/client/skill-hub/components/SkillManager.tsx +2 -2
- package/src/client/skill-hub/components/SkillMetrics.tsx +157 -124
- package/src/client/skill-hub/components/SkillTestPanel.tsx +14 -13
- package/src/client/skill-hub/index.tsx +58 -51
- package/src/client/skill-hub/locale.ts +1 -1
- package/src/client/skill-hub/tools/InteractionSchemasProvider.tsx +132 -99
- package/src/client/skill-hub/tools/registerSkillLoopCards.ts +71 -58
- package/src/client/tools/PlanApprovalCard.tsx +3 -2
- package/src/client/tools/registerOrchestratorCards.ts +17 -7
- package/src/client-v2/components/AIEmployeeSelect.tsx +47 -0
- package/src/client-v2/components/AIEmployeesContext.tsx +110 -0
- package/src/client-v2/components/AgentRunsTab.tsx +767 -0
- package/src/client-v2/components/HarnessProfilesTab.tsx +254 -0
- package/src/client-v2/components/RulesTab.tsx +782 -0
- package/src/client-v2/components/TracingTab.tsx +432 -0
- package/src/client-v2/hooks/useApiRequest.ts +114 -0
- package/src/client-v2/index.tsx +1 -0
- package/src/client-v2/pages/AgentRunsPage.tsx +13 -0
- package/src/client-v2/pages/ExecutionHistoryPage.tsx +10 -0
- package/src/client-v2/pages/HarnessProfilesPage.tsx +10 -0
- package/src/client-v2/pages/LoopSettingsPage.tsx +10 -0
- package/src/client-v2/pages/RulesPage.tsx +13 -0
- package/src/client-v2/pages/SkillDefinitionsPage.tsx +10 -0
- package/src/client-v2/pages/SkillMetricsPage.tsx +10 -0
- package/src/client-v2/pages/TracingPage.tsx +13 -0
- package/src/client-v2/plugin.tsx +70 -0
- package/src/client-v2/skill-hub/components/ExecutionHistory.tsx +196 -0
- package/src/client-v2/skill-hub/components/FileLinkList.tsx +37 -0
- package/src/client-v2/skill-hub/components/GitSkillImport.tsx +539 -0
- package/src/client-v2/skill-hub/components/LoopSettings.tsx +331 -0
- package/src/client-v2/skill-hub/components/SkillEditor.tsx +453 -0
- package/src/client-v2/skill-hub/components/SkillManager.tsx +174 -0
- package/src/client-v2/skill-hub/components/SkillMetrics.tsx +157 -0
- package/src/client-v2/skill-hub/components/SkillTestPanel.tsx +135 -0
- package/src/client-v2/skill-hub/locale.ts +13 -0
- package/src/client-v2/skill-hub/tools/loopTemplates.ts +52 -0
- package/src/client-v2/skill-hub/utils/jsonFields.ts +41 -0
- package/src/client-v2/utils/jsonFields.ts +41 -0
- package/src/locale/en-US.json +7 -0
- package/src/locale/vi-VN.json +7 -0
- package/src/locale/zh-CN.json +27 -0
- package/src/server/__tests__/agent-registry-service.test.ts +147 -0
- package/src/server/__tests__/code-validator.test.ts +63 -0
- package/src/server/__tests__/skill-execute.test.ts +33 -0
- package/src/server/__tests__/skill-settings.test.ts +63 -0
- package/src/server/migrations/20260615000000-normalize-ai-employee-tool-bindings.ts +39 -0
- package/src/server/plugin.ts +62 -21
- package/src/server/services/AgentHarness.ts +49 -22
- package/src/server/services/AgentLoopController.ts +17 -6
- package/src/server/services/AgentLoopService.ts +1 -1
- package/src/server/services/AgentPlannerService.ts +10 -0
- package/src/server/services/AgentRegistryService.ts +89 -47
- package/src/server/services/CircuitBreaker.ts +10 -0
- package/src/server/services/CodeValidator.ts +237 -159
- package/src/server/services/SandboxRunner.ts +203 -189
- package/src/server/skill-hub/plugin.ts +933 -898
- package/src/server/tools/delegate-task.ts +12 -9
- package/src/server/tools/skill-execute.ts +194 -160
- package/src/server/utils/ai-manager.ts +24 -0
- package/src/server/utils/ctx-utils.ts +14 -0
- package/src/server/utils/skill-settings.ts +116 -0
package/dist/externalVersion.js
CHANGED
|
@@ -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
|
-
"
|
|
15
|
-
"@nocobase/
|
|
16
|
-
"@nocobase/
|
|
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/
|
|
20
|
-
"@nocobase/
|
|
21
|
-
"@nocobase/ai": "2.
|
|
21
|
+
"@nocobase/ai": "2.1.6",
|
|
22
|
+
"@nocobase/actions": "2.1.6",
|
|
23
|
+
"@nocobase/plugin-ai": "2.1.6"
|
|
22
24
|
};
|
package/dist/locale/en-US.json
CHANGED
|
@@ -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",
|
package/dist/locale/vi-VN.json
CHANGED
|
@@ -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
|
+
}
|
package/dist/server/plugin.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
121
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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 = (
|
|
153
|
-
const tool = await ((
|
|
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 = ((
|
|
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 = (
|
|
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,
|
|
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
|
|
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:
|
|
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
|
|
295
|
+
const coreToolsManager = (0, import_ai_manager.getAIToolsManager)(ctx.app);
|
|
278
296
|
const allTools = await coreToolsManager.listTools();
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
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
|
|
288
|
-
if (!
|
|
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:
|
|
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,
|
|
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 = ((
|
|
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 = ((
|
|
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
|
-
|
|
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
|
|
89
|
-
|
|
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
|
-
|
|
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
|
-
|
|
100
|
-
|
|
125
|
+
const leaderModel = extractModelRef(leader == null ? void 0 : leader.modelSettings);
|
|
126
|
+
if (leaderModel) {
|
|
127
|
+
return leaderModel;
|
|
101
128
|
}
|
|
102
129
|
}
|
|
103
|
-
return
|
|
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
|
-
|
|
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
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
});
|