plugin-agent-orchestrator 1.0.27 → 1.0.32

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 (110) hide show
  1. package/README.md +9 -7
  2. package/dist/client/index.js +1 -1
  3. package/dist/client-v2/{214.723affb37c13bf7a.js → 214.79650a549273f163.js} +1 -1
  4. package/dist/client-v2/264.718a107e43fc163c.js +10 -0
  5. package/dist/client-v2/373.f5d5292e53c4e832.js +10 -0
  6. package/dist/client-v2/{41.1805b2edfaa4afe2.js → 41.ba6e080cc0488143.js} +1 -1
  7. package/dist/client-v2/418.29e713f79131eece.js +10 -0
  8. package/dist/client-v2/619.bd3c5698b40705c3.js +10 -0
  9. package/dist/client-v2/677.a991ce0250ff5c77.js +10 -0
  10. package/dist/client-v2/{70.a15d7fcec7c41768.js → 70.bda9518881c05360.js} +1 -1
  11. package/dist/client-v2/925.f5370de8f6632d65.js +10 -0
  12. package/dist/client-v2/index.js +1 -1
  13. package/dist/externalVersion.js +7 -10
  14. package/dist/locale/en-US.json +94 -25
  15. package/dist/locale/vi-VN.json +94 -25
  16. package/dist/locale/zh-CN.json +94 -25
  17. package/dist/server/collections/agent-execution-spans.js +37 -0
  18. package/dist/server/collections/agent-harness-profiles.js +2 -2
  19. package/dist/server/collections/agent-memory-contexts.js +125 -0
  20. package/dist/server/collections/orchestrator-logs.js +2 -2
  21. package/dist/server/migrations/20260425000000-add-interaction-schema.js +3 -1
  22. package/dist/server/migrations/20260427000000-change-packages-to-text.js +3 -1
  23. package/dist/server/migrations/20260427000001-change-other-json-to-text.js +6 -2
  24. package/dist/server/migrations/20260524001000-add-plan-approval-and-harness-profiles.js +21 -19
  25. package/dist/server/migrations/20260621000000-native-policy-profile-defaults.js +193 -0
  26. package/dist/server/plugin.js +128 -74
  27. package/dist/server/resources/agent-monitor.js +454 -0
  28. package/dist/server/services/AgentHarness.js +24 -499
  29. package/dist/server/services/AgentMemoryContextService.js +216 -0
  30. package/dist/server/services/ExecutionSpanService.js +2 -2
  31. package/dist/server/services/NativeSubAgentObserver.js +413 -0
  32. package/dist/server/skill-hub/mcp/McpController.js +16 -5
  33. package/dist/server/skill-hub/plugin.js +81 -5
  34. package/dist/server/skill-hub/tasks/SkillExecutionTask.js +9 -3
  35. package/dist/server/tools/delegate-task.js +11 -589
  36. package/dist/server/utils/skill-settings.js +18 -1
  37. package/package.json +47 -49
  38. package/src/client/AIEmployeesContext.tsx +5 -18
  39. package/src/client/AgentRunsTab.tsx +2 -771
  40. package/src/client/HarnessProfilesTab.tsx +2 -257
  41. package/src/client/OrchestratorSettings.tsx +97 -106
  42. package/src/client/RulesTab.tsx +2 -788
  43. package/src/client/plugin.tsx +0 -2
  44. package/src/client/skill-hub/components/ExecutionHistory.tsx +200 -202
  45. package/src/client/skill-hub/components/ExecutionProgress.tsx +51 -55
  46. package/src/client/skill-hub/components/LoopSettings.tsx +331 -331
  47. package/src/client/skill-hub/components/SkillEditor.tsx +43 -39
  48. package/src/client/skill-hub/components/SkillManager.tsx +194 -181
  49. package/src/client/skill-hub/components/SkillTestPanel.tsx +141 -145
  50. package/src/client/skill-hub/locale.ts +16 -16
  51. package/src/client/skill-hub/tools/SkillHubCard.tsx +104 -109
  52. package/src/client/skill-hub/tools/loopTemplates.ts +52 -52
  53. package/src/client/skill-hub/utils/jsonFields.ts +7 -3
  54. package/src/client-v2/components/AIEmployeesContext.tsx +3 -16
  55. package/src/client-v2/components/AgentRunsTab.tsx +182 -455
  56. package/src/client-v2/components/HarnessProfilesTab.tsx +34 -31
  57. package/src/client-v2/components/RulesTab.tsx +2 -782
  58. package/src/client-v2/components/TracingTab.tsx +1 -1
  59. package/src/client-v2/hooks/useApiRequest.ts +8 -1
  60. package/src/client-v2/pages/RulesPage.tsx +2 -2
  61. package/src/client-v2/plugin.tsx +3 -3
  62. package/src/locale/en-US.json +94 -25
  63. package/src/locale/vi-VN.json +94 -25
  64. package/src/locale/zh-CN.json +94 -25
  65. package/src/server/__tests__/native-sub-agent-observer.test.ts +246 -0
  66. package/src/server/__tests__/skill-settings.test.ts +6 -6
  67. package/src/server/__tests__/smoke.test.ts +1 -0
  68. package/src/server/collections/agent-execution-spans.ts +37 -0
  69. package/src/server/collections/agent-harness-profiles.ts +59 -59
  70. package/src/server/collections/agent-loop-events.ts +71 -71
  71. package/src/server/collections/agent-loop-steps.ts +144 -144
  72. package/src/server/collections/agent-memory-contexts.ts +95 -0
  73. package/src/server/collections/orchestrator-logs.ts +4 -4
  74. package/src/server/collections/skill-definitions.ts +111 -111
  75. package/src/server/collections/skill-executions.ts +106 -106
  76. package/src/server/collections/skill-loop-configs.ts +65 -65
  77. package/src/server/migrations/20260423000000-add-progress-fields.ts +14 -14
  78. package/src/server/migrations/20260425000000-add-interaction-schema.ts +3 -1
  79. package/src/server/migrations/20260427000000-change-packages-to-text.ts +4 -2
  80. package/src/server/migrations/20260427000001-change-other-json-to-text.ts +9 -5
  81. package/src/server/migrations/20260524000000-add-agent-loop-fields-to-skill-executions.ts +30 -30
  82. package/src/server/migrations/20260524001000-add-plan-approval-and-harness-profiles.ts +145 -142
  83. package/src/server/migrations/20260615000000-normalize-ai-employee-tool-bindings.ts +2 -2
  84. package/src/server/migrations/20260621000000-native-policy-profile-defaults.ts +193 -0
  85. package/src/server/plugin.ts +151 -94
  86. package/src/server/resources/agent-monitor.ts +482 -0
  87. package/src/server/services/AgentHarness.ts +38 -623
  88. package/src/server/services/AgentMemoryContextService.ts +256 -0
  89. package/src/server/services/AgentPlanValidator.ts +73 -73
  90. package/src/server/services/ExecutionSpanService.ts +6 -2
  91. package/src/server/services/FileManager.ts +144 -144
  92. package/src/server/services/NativeSubAgentObserver.ts +507 -0
  93. package/src/server/services/SkillManager.ts +583 -583
  94. package/src/server/services/SkillRepositoryService.ts +5 -7
  95. package/src/server/services/TokenTracker.ts +3 -3
  96. package/src/server/services/WorkerEnvManager.ts +1 -2
  97. package/src/server/skill-hub/actions/git-import.ts +5 -7
  98. package/src/server/skill-hub/mcp/McpController.ts +41 -14
  99. package/src/server/skill-hub/plugin.ts +89 -6
  100. package/src/server/skill-hub/tasks/SkillExecutionTask.ts +470 -460
  101. package/src/server/skill-hub/utils/json-fields.ts +1 -1
  102. package/src/server/tools/delegate-task.ts +13 -847
  103. package/src/server/utils/skill-settings.ts +24 -6
  104. package/dist/client-v2/264.0533912e6c5ea2d7.js +0 -10
  105. package/dist/client-v2/418.5ae055abf141820e.js +0 -10
  106. package/dist/client-v2/619.d99d3c9e61c99064.js +0 -10
  107. package/dist/client-v2/892.72db4161511c8a16.js +0 -10
  108. package/dist/client-v2/926.87f660b670d85bcc.js +0 -10
  109. package/src/client/tools/PlanApprovalCard.tsx +0 -176
  110. package/src/client/tools/registerOrchestratorCards.ts +0 -17
@@ -1,23 +1,135 @@
1
1
  import { Plugin } from '@nocobase/server';
2
2
  import path from 'path';
3
- import { createDelegateToolsProvider } from './tools/delegate-task';
4
3
  import { createExternalRagSearchTool } from './tools/external-rag-search';
5
- import { createOrchestratorPlanTools } from './tools/orchestrator-plan';
6
4
  import { registerTracingResource } from './resources/tracing';
7
- import { registerAgentLoopResource } from './resources/agent-loop';
8
- import { getRunEventBus } from './services/RunEventBus';
5
+ import { registerAgentMonitorResource } from './resources/agent-monitor';
9
6
  import SkillHubSubFeature from './skill-hub/plugin';
10
- import { AgentLoopService } from './services/AgentLoopService';
11
- import { isAdminUser, currentUserId } from './utils/ctx-utils';
7
+ import { NativeSubAgentObserver } from './services/NativeSubAgentObserver';
8
+ import { asObject, isAdminUser, currentUserId } from './utils/ctx-utils';
12
9
  import { getAIToolsManager } from './utils/ai-manager';
13
10
 
11
+ function normalizeOptionalString(value: unknown) {
12
+ return typeof value === 'string' ? value.trim() : '';
13
+ }
14
+
15
+ function readModelValue(record: unknown, key: string) {
16
+ const model = record as { get?: (name: string) => unknown; [key: string]: unknown };
17
+ return typeof model?.get === 'function' ? model.get(key) : model?.[key];
18
+ }
19
+
20
+ function buildAgentMemoryContextKey(values: { scope: string; userId?: unknown; aiEmployeeUsername?: string }) {
21
+ const userPart = values.scope === 'public' ? 'public' : String(values.userId || '');
22
+ const agentPart = values.aiEmployeeUsername || '*';
23
+ return `${values.scope}:${userPart}:${agentPart}`;
24
+ }
25
+
26
+ async function validateAgentMemoryContextValues(ctx: any) {
27
+ const actionName = ctx.action?.actionName;
28
+ const values = ctx.action?.params?.values || {};
29
+ let nextValues = values;
30
+ let currentId = ctx.action?.params?.filterByTk;
31
+
32
+ if (actionName === 'update' && ctx.action?.params?.filterByTk) {
33
+ const existing = await ctx.db.getRepository('agentMemoryContexts').findOne({
34
+ filter: { id: ctx.action.params.filterByTk },
35
+ });
36
+ currentId = readModelValue(existing, 'id') || currentId;
37
+ nextValues = {
38
+ ...(existing?.toJSON?.() || existing || {}),
39
+ ...values,
40
+ };
41
+ }
42
+
43
+ const scope = normalizeOptionalString(nextValues.scope);
44
+ const userId = nextValues.userId;
45
+ const aiEmployeeUsername = normalizeOptionalString(nextValues.aiEmployeeUsername);
46
+
47
+ if (!['public', 'user', 'agent_user'].includes(scope)) {
48
+ ctx.throw(400, 'scope must be one of: public, user, agent_user.');
49
+ return;
50
+ }
51
+
52
+ if (scope === 'public' && userId != null && userId !== '') {
53
+ ctx.throw(400, 'scope="public" requires userId to be empty.');
54
+ return;
55
+ }
56
+
57
+ if ((scope === 'user' || scope === 'agent_user') && (userId == null || userId === '')) {
58
+ ctx.throw(400, `scope="${scope}" requires userId.`);
59
+ return;
60
+ }
61
+
62
+ if (scope === 'agent_user' && !aiEmployeeUsername) {
63
+ ctx.throw(400, 'scope="agent_user" requires aiEmployeeUsername.');
64
+ return;
65
+ }
66
+
67
+ const normalizedValues = {
68
+ ...values,
69
+ scope,
70
+ userId: scope === 'public' ? null : userId,
71
+ aiEmployeeUsername,
72
+ contextKey: buildAgentMemoryContextKey({
73
+ scope,
74
+ userId: scope === 'public' ? null : userId,
75
+ aiEmployeeUsername,
76
+ }),
77
+ };
78
+
79
+ const repo = ctx.db.getRepository('agentMemoryContexts');
80
+ const duplicate =
81
+ (await repo.findOne({
82
+ filter: { contextKey: normalizedValues.contextKey },
83
+ })) ||
84
+ (await repo.findOne({
85
+ filter: {
86
+ scope,
87
+ userId: normalizedValues.userId,
88
+ aiEmployeeUsername,
89
+ },
90
+ }));
91
+ const duplicateId = readModelValue(duplicate, 'id');
92
+ if (duplicateId && String(duplicateId) !== String(currentId || '')) {
93
+ ctx.throw(400, 'An agent memory context already exists for this scope, user, and AI employee.');
94
+ return;
95
+ }
96
+
97
+ ctx.action.params.values = normalizedValues;
98
+ }
99
+
100
+ async function resolveTracingRetentionDays(plugin: { db: any; app: any }) {
101
+ const envDays = Number(process.env.ORCHESTRATOR_LOG_RETENTION_DAYS);
102
+ if (Number.isFinite(envDays) && envDays > 0) return envDays;
103
+
104
+ try {
105
+ const defaultProfile = await plugin.db.getRepository('agentHarnessProfiles').findOne({
106
+ filter: {
107
+ tag: 'default',
108
+ enabled: true,
109
+ },
110
+ });
111
+ const settings = asObject(readModelValue(defaultProfile, 'settings'));
112
+ const profileDays = Number(settings.tracingRetentionDays);
113
+ if (Number.isFinite(profileDays) && profileDays > 0) {
114
+ return profileDays;
115
+ }
116
+ } catch (error) {
117
+ plugin.app.logger?.warn?.('[AgentOrchestrator] Failed to load tracing retention policy', error);
118
+ }
119
+
120
+ return 30;
121
+ }
122
+
14
123
  export class PluginAgentOrchestratorServer extends Plugin {
15
124
  skillHub: SkillHubSubFeature;
16
- agentLoopService: AgentLoopService;
125
+ nativeObserver: NativeSubAgentObserver;
126
+ private readonly installNativeObserver = () => {
127
+ this.nativeObserver?.install();
128
+ };
17
129
 
18
130
  async afterAdd() {
19
131
  this.skillHub = new SkillHubSubFeature(this);
20
- this.agentLoopService = new AgentLoopService(this);
132
+ this.nativeObserver = new NativeSubAgentObserver(this);
21
133
  }
22
134
 
23
135
  async beforeLoad() {
@@ -40,11 +152,11 @@ export class PluginAgentOrchestratorServer extends Plugin {
40
152
  actions: [
41
153
  'orchestratorConfig:*',
42
154
  'orchestratorTracing:*',
43
- 'agentLoops:*',
155
+ 'agentMonitor:*',
156
+ 'agentMemoryContexts:*',
44
157
  'agentLoopRuns:*',
45
158
  'agentLoopSteps:*',
46
159
  'agentLoopEvents:*',
47
- 'agentLoopEventsStream:*',
48
160
  'agentHarnessProfiles:*',
49
161
  'agentExecutionSpans:*',
50
162
  'skillDefinitions:*',
@@ -69,6 +181,7 @@ export class PluginAgentOrchestratorServer extends Plugin {
69
181
  this.app.acl.allow('skillHub', 'test', 'loggedIn');
70
182
  this.app.acl.allow('skillHub', 'download', 'loggedIn');
71
183
  this.app.acl.allow('skillHub', 'listTemplates', 'loggedIn');
184
+ this.app.acl.allow('agentMonitor', ['list', 'get'], 'loggedIn');
72
185
 
73
186
  // Data scoping for skillExecutions: a logged-in non-admin user may only
74
187
  // read their own executions. Rows hold inputArgs / stdout / output files,
@@ -90,87 +203,28 @@ export class PluginAgentOrchestratorServer extends Plugin {
90
203
  { tag: 'orchestrator-skill-executions-scope', after: 'acl' },
91
204
  );
92
205
 
93
- // --- Register Dynamic Tools ---
94
- // Each configured sub-agent becomes a callable tool for its leader.
95
- // Uses createReactAgent (LangGraph public API) instead of private AIEmployee class.
96
- // Tools are registered via app.aiManager.toolsManager (public API from @nocobase/ai core).
206
+ this.app.resourceManager.use(
207
+ async (ctx, next) => {
208
+ const { resourceName, actionName } = ctx.action || {};
209
+ if (resourceName === 'agentMemoryContexts' && (actionName === 'create' || actionName === 'update')) {
210
+ await validateAgentMemoryContextValues(ctx);
211
+ }
212
+ await next();
213
+ },
214
+ { tag: 'orchestrator-agent-memory-context-policy', after: 'acl' },
215
+ );
216
+
217
+ // --- Register External Tool Only ---
218
+ // Native @nocobase/plugin-ai owns sub-agent dispatch. The orchestrator no
219
+ // longer registers delegate_* / dispatch_subagents_* tools or controller
220
+ // plan tools; Skill Hub still registers its own AI tools from its subfeature.
97
221
  const toolsManager = getAIToolsManager(this.app);
98
- toolsManager.registerTools(createOrchestratorPlanTools(this, this.agentLoopService));
99
222
  toolsManager.registerTools(createExternalRagSearchTool(this));
100
- toolsManager.registerDynamicTools(createDelegateToolsProvider(this));
101
-
102
- // --- Register Agent Loop Resource ---
103
- registerAgentLoopResource(this, this.agentLoopService);
104
-
105
- // --- Register SSE Event Stream Resource (Phase 6) ---
106
- this.app.resource({
107
- name: 'agentLoopEventsStream',
108
- actions: {
109
- async stream(ctx, next) {
110
- const runId = ctx.action.params?.runId || ctx.query?.runId || ctx.request.query?.runId;
111
- if (!runId) {
112
- ctx.throw(400, 'runId query parameter is required.');
113
- return;
114
- }
115
-
116
- // Ownership check: a non-admin user may only stream events for a run
117
- // they started. Run events can echo step inputs/outputs, so an
118
- // unscoped stream would leak another user's run activity.
119
- if (!isAdminUser(ctx)) {
120
- const userId = currentUserId(ctx);
121
- const run = await ctx.db.getRepository('agentLoopRuns').findOne({
122
- filter: { id: runId },
123
- });
124
- if (!run) {
125
- ctx.throw(404, 'Run not found.');
126
- return;
127
- }
128
- const ownerId = run.get ? run.get('userId') : run.userId;
129
- if (!userId || String(ownerId) !== String(userId)) {
130
- ctx.throw(403, 'You cannot stream events for this run.');
131
- return;
132
- }
133
- }
134
223
 
135
- ctx.type = 'text/event-stream';
136
- ctx.set('Cache-Control', 'no-cache');
137
- ctx.set('Connection', 'keep-alive');
138
- ctx.set('X-Accel-Buffering', 'no');
139
-
140
- const unsubscribe = getRunEventBus().subscribe(runId, (event: any) => {
141
- try {
142
- ctx.res.write(`data: ${JSON.stringify(event)}\n\n`);
143
- } catch {
144
- unsubscribe();
145
- }
146
- });
147
-
148
- const keepalive = setInterval(() => {
149
- try {
150
- ctx.res.write(': keepalive\n\n');
151
- } catch {
152
- clearInterval(keepalive);
153
- unsubscribe();
154
- }
155
- }, 15000);
156
-
157
- ctx.req.on('close', () => {
158
- clearInterval(keepalive);
159
- unsubscribe();
160
- });
161
-
162
- ctx.req.on('error', () => {
163
- clearInterval(keepalive);
164
- unsubscribe();
165
- });
166
-
167
- ctx.res.writeHead(200);
168
- ctx.res.write(': connected\n\n');
169
-
170
- await next();
171
- },
172
- },
173
- });
224
+ // --- Native plugin-ai Monitor Resource ---
225
+ registerAgentMonitorResource(this);
226
+ this.installNativeObserver();
227
+ this.app.on?.('afterStart', this.installNativeObserver);
174
228
 
175
229
  // --- Register Tracing Resource (Phase 5) ---
176
230
  // Custom read-only resource for the Swarm Tracing admin page.
@@ -183,8 +237,7 @@ export class PluginAgentOrchestratorServer extends Plugin {
183
237
  cronTime: '0 30 2 * * *',
184
238
  onTick: async () => {
185
239
  try {
186
- const days = Number(process.env.ORCHESTRATOR_LOG_RETENTION_DAYS || 30);
187
- if (!Number.isFinite(days) || days <= 0) return;
240
+ const days = await resolveTracingRetentionDays(this);
188
241
  const cutoff = new Date(Date.now() - days * 86400000);
189
242
  const repo = this.db.getRepository('orchestratorLogs');
190
243
  const spansRepo = this.db.getRepository('agentExecutionSpans');
@@ -207,9 +260,8 @@ export class PluginAgentOrchestratorServer extends Plugin {
207
260
  },
208
261
  });
209
262
 
210
- // NOTE: The createReactAgent approach does NOT create aiConversation records,
211
- // so there is no need for a middleware to hide "headless" conversations.
212
- // If future versions need conversation logging, add it here.
263
+ // Native sub-agent conversations are owned by @nocobase/plugin-ai. This
264
+ // plugin only observes their execution spans and policy context.
213
265
  }
214
266
 
215
267
  async install() {
@@ -217,10 +269,15 @@ export class PluginAgentOrchestratorServer extends Plugin {
217
269
  }
218
270
 
219
271
  async afterEnable() {}
220
- async afterDisable() {}
272
+ async afterDisable() {
273
+ this.nativeObserver?.uninstall();
274
+ }
221
275
  async remove() {}
222
276
 
223
277
  async beforeStop() {
278
+ this.app.off?.('afterStart', this.installNativeObserver);
279
+ this.app.removeListener?.('afterStart', this.installNativeObserver);
280
+ this.nativeObserver?.uninstall();
224
281
  await this.skillHub.beforeStop();
225
282
  }
226
283
  }