plugin-agent-orchestrator 1.0.14 → 1.0.16

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 (34) hide show
  1. package/README.md +96 -0
  2. package/dist/externalVersion.js +6 -6
  3. package/dist/server/plugin.js +11 -1
  4. package/dist/server/services/CodeValidator.js +1 -0
  5. package/dist/server/services/SkillManager.js +0 -39
  6. package/dist/server/skill-hub/plugin.js +3 -3
  7. package/dist/server/skill-hub/tasks/SkillExecutionTask.d.ts +2 -0
  8. package/dist/server/skill-hub/tasks/SkillExecutionTask.js +122 -0
  9. package/dist/server/tools/delegate-task.js +22 -2
  10. package/dist/server/tools/external-rag-search.d.ts +42 -0
  11. package/dist/server/tools/external-rag-search.js +140 -0
  12. package/dist/server/tools/skill-execute.d.ts +1 -1
  13. package/dist/server/tools/skill-execute.js +1 -2
  14. package/package.json +1 -1
  15. package/src/client/index.tsx +1 -1
  16. package/src/client/plugin.tsx +54 -54
  17. package/src/client/skill-hub/index.tsx +75 -75
  18. package/src/server/migrations/20260423000000-add-progress-fields.ts +5 -5
  19. package/src/server/migrations/20260425000000-add-interaction-schema.ts +5 -5
  20. package/src/server/migrations/20260427000000-add-tracing-detail-fields.ts +5 -5
  21. package/src/server/migrations/20260427000000-change-packages-to-text.ts +7 -7
  22. package/src/server/migrations/20260427000001-change-other-json-to-text.ts +10 -10
  23. package/src/server/migrations/20260429000000-add-llm-fields.ts +2 -2
  24. package/src/server/migrations/20260429000000-fix-inputargs-json-to-text.ts +2 -2
  25. package/src/server/migrations/20260503000000-add-orchestrator-trace-fields.ts +2 -2
  26. package/src/server/plugin.ts +23 -13
  27. package/src/server/services/CodeValidator.ts +5 -5
  28. package/src/server/services/SkillManager.ts +12 -52
  29. package/src/server/services/WorkerEnvManager.ts +5 -5
  30. package/src/server/skill-hub/plugin.ts +61 -61
  31. package/src/server/skill-hub/tasks/SkillExecutionTask.ts +162 -16
  32. package/src/server/tools/delegate-task.ts +25 -1
  33. package/src/server/tools/external-rag-search.ts +128 -0
  34. package/src/server/tools/skill-execute.ts +1 -2
@@ -1,54 +1,54 @@
1
- import { Plugin } from '@nocobase/client';
2
- import { OrchestratorSettings } from './OrchestratorSettings';
3
-
4
- import { InteractionSchemasProvider } from './skill-hub/tools/InteractionSchemasProvider';
5
- import { SkillHubCard } from './skill-hub/tools/SkillHubCard';
6
- import { parseJsonText } from './skill-hub/utils/jsonFields';
7
-
8
- const sanitize = (name: string) =>
9
- name
10
- .toLowerCase()
11
- .replace(/[^a-z0-9_]/g, '_')
12
- .replace(/_+/g, '_')
13
- .replace(/^_|_$/g, '');
14
-
15
- export class PluginAgentOrchestratorClient extends Plugin {
16
- async load() {
17
- this.app.use(InteractionSchemasProvider);
18
-
19
- // Register under the "AI" settings group for consistency with other AI plugins
20
- this.app.pluginSettingsManager.add('ai.orchestrator', {
21
- title: 'Agent Orchestrator',
22
- icon: 'ApartmentOutlined',
23
- Component: OrchestratorSettings,
24
- });
25
-
26
- await this.registerSkillUiCards();
27
- }
28
-
29
- private async registerSkillUiCards() {
30
- const toolsManager = this.app.aiManager?.toolsManager;
31
- if (!toolsManager) return;
32
-
33
- try {
34
- const { data } = await this.app.apiClient.request({
35
- url: 'skillDefinitions:list',
36
- params: {
37
- filter: { enabled: true },
38
- fields: ['name', 'autoCall', 'interactionSchema'],
39
- pageSize: 200,
40
- },
41
- });
42
- const list = (data as any)?.data ?? [];
43
- for (const s of list) {
44
- if (s.autoCall) continue;
45
- if (!parseJsonText(s.interactionSchema, null)) continue;
46
- toolsManager.registerTools(`skill_hub_${sanitize(s.name)}`, { ui: { card: SkillHubCard } });
47
- }
48
- } catch {
49
- // user without ACL or backend unavailable — skip silently
50
- }
51
- }
52
- }
53
-
54
- export default PluginAgentOrchestratorClient;
1
+ import { Plugin } from '@nocobase/client';
2
+ import { OrchestratorSettings } from './OrchestratorSettings';
3
+
4
+ import { InteractionSchemasProvider } from './skill-hub/tools/InteractionSchemasProvider';
5
+ import { SkillHubCard } from './skill-hub/tools/SkillHubCard';
6
+ import { parseJsonText } from './skill-hub/utils/jsonFields';
7
+
8
+ const sanitize = (name: string) =>
9
+ name
10
+ .toLowerCase()
11
+ .replace(/[^a-z0-9_]/g, '_')
12
+ .replace(/_+/g, '_')
13
+ .replace(/^_|_$/g, '');
14
+
15
+ export class PluginAgentOrchestratorClient extends Plugin {
16
+ async load() {
17
+ (this as any).app.use(InteractionSchemasProvider);
18
+
19
+ // Register under the "AI" settings group for consistency with other AI plugins
20
+ (this as any).app.pluginSettingsManager.add('ai.orchestrator', {
21
+ title: 'Agent Orchestrator',
22
+ icon: 'ApartmentOutlined',
23
+ Component: OrchestratorSettings,
24
+ });
25
+
26
+ await this.registerSkillUiCards();
27
+ }
28
+
29
+ private async registerSkillUiCards() {
30
+ const toolsManager = (this as any).app.aiManager?.toolsManager;
31
+ if (!toolsManager) return;
32
+
33
+ try {
34
+ const { data } = await (this as any).app.apiClient.request({
35
+ url: 'skillDefinitions:list',
36
+ params: {
37
+ filter: { enabled: true },
38
+ fields: ['name', 'autoCall', 'interactionSchema'],
39
+ pageSize: 200,
40
+ },
41
+ });
42
+ const list = (data as any)?.data ?? [];
43
+ for (const s of list) {
44
+ if (s.autoCall) continue;
45
+ if (!parseJsonText(s.interactionSchema, null)) continue;
46
+ toolsManager.registerTools(`skill_hub_${sanitize(s.name)}`, { ui: { card: SkillHubCard } });
47
+ }
48
+ } catch {
49
+ // user without ACL or backend unavailable — skip silently
50
+ }
51
+ }
52
+ }
53
+
54
+ export default PluginAgentOrchestratorClient;
@@ -1,75 +1,75 @@
1
- import { Plugin } from '@nocobase/client';
2
- import { SkillManager } from './components/SkillManager';
3
- import { ExecutionHistory } from './components/ExecutionHistory';
4
-
5
- import { SkillMetrics } from './components/SkillMetrics';
6
- import { InteractionSchemasProvider } from './tools/InteractionSchemasProvider';
7
- import { SkillHubCard } from './tools/SkillHubCard';
8
- import { parseJsonText } from './utils/jsonFields';
9
-
10
- const sanitize = (name: string) =>
11
- name
12
- .toLowerCase()
13
- .replace(/[^a-z0-9_]/g, '_')
14
- .replace(/_+/g, '_')
15
- .replace(/^_|_$/g, '');
16
-
17
- export class PluginSkillHubClient extends Plugin {
18
- async load() {
19
- this.app.use(InteractionSchemasProvider);
20
-
21
- this.app.pluginSettingsManager.add('skill-hub', {
22
- title: this.t('Skill Hub'),
23
- icon: 'CodeOutlined',
24
- });
25
-
26
- this.app.pluginSettingsManager.add('skill-hub.definitions', {
27
- title: this.t('Skill Definitions'),
28
- Component: SkillManager,
29
- aclSnippet: 'pm.skill-hub',
30
- });
31
-
32
- this.app.pluginSettingsManager.add('skill-hub.executions', {
33
- title: this.t('Execution History'),
34
- Component: ExecutionHistory,
35
- aclSnippet: 'pm.skill-hub',
36
- });
37
-
38
- this.app.pluginSettingsManager.add('skill-hub.metrics', {
39
- title: this.t('Dashboard Metrics'),
40
- Component: SkillMetrics,
41
- aclSnippet: 'pm.skill-hub',
42
- });
43
-
44
-
45
-
46
- await this.registerSkillUiCards();
47
- }
48
-
49
- private async registerSkillUiCards() {
50
- const toolsManager = this.app.aiManager?.toolsManager;
51
- if (!toolsManager) return;
52
-
53
- try {
54
- const { data } = await this.app.apiClient.request({
55
- url: 'skillDefinitions:list',
56
- params: {
57
- filter: { enabled: true },
58
- fields: ['name', 'autoCall', 'interactionSchema'],
59
- pageSize: 200,
60
- },
61
- });
62
- const list = (data as any)?.data ?? [];
63
- for (const s of list) {
64
- if (s.autoCall) continue;
65
- if (!parseJsonText(s.interactionSchema, null)) continue;
66
- toolsManager.registerTools(`skill_hub_${sanitize(s.name)}`, { ui: { card: SkillHubCard } });
67
- }
68
- } catch {
69
- // user without ACL or backend unavailable — skip silently
70
- }
71
- }
72
- }
73
-
74
- export { SkillManager, ExecutionHistory, SkillMetrics };
75
- export default PluginSkillHubClient;
1
+ import { Plugin } from '@nocobase/client';
2
+ import { SkillManager } from './components/SkillManager';
3
+ import { ExecutionHistory } from './components/ExecutionHistory';
4
+
5
+ import { SkillMetrics } from './components/SkillMetrics';
6
+ import { InteractionSchemasProvider } from './tools/InteractionSchemasProvider';
7
+ import { SkillHubCard } from './tools/SkillHubCard';
8
+ import { parseJsonText } from './utils/jsonFields';
9
+
10
+ const sanitize = (name: string) =>
11
+ name
12
+ .toLowerCase()
13
+ .replace(/[^a-z0-9_]/g, '_')
14
+ .replace(/_+/g, '_')
15
+ .replace(/^_|_$/g, '');
16
+
17
+ export class PluginSkillHubClient extends Plugin {
18
+ async load() {
19
+ (this as any).app.use(InteractionSchemasProvider);
20
+
21
+ (this as any).app.pluginSettingsManager.add('skill-hub', {
22
+ title: (this as any).t('Skill Hub'),
23
+ icon: 'CodeOutlined',
24
+ });
25
+
26
+ (this as any).app.pluginSettingsManager.add('skill-hub.definitions', {
27
+ title: (this as any).t('Skill Definitions'),
28
+ Component: SkillManager,
29
+ aclSnippet: 'pm.skill-hub',
30
+ });
31
+
32
+ (this as any).app.pluginSettingsManager.add('skill-hub.executions', {
33
+ title: (this as any).t('Execution History'),
34
+ Component: ExecutionHistory,
35
+ aclSnippet: 'pm.skill-hub',
36
+ });
37
+
38
+ (this as any).app.pluginSettingsManager.add('skill-hub.metrics', {
39
+ title: (this as any).t('Dashboard Metrics'),
40
+ Component: SkillMetrics,
41
+ aclSnippet: 'pm.skill-hub',
42
+ });
43
+
44
+
45
+
46
+ await this.registerSkillUiCards();
47
+ }
48
+
49
+ private async registerSkillUiCards() {
50
+ const toolsManager = (this as any).app.aiManager?.toolsManager;
51
+ if (!toolsManager) return;
52
+
53
+ try {
54
+ const { data } = await (this as any).app.apiClient.request({
55
+ url: 'skillDefinitions:list',
56
+ params: {
57
+ filter: { enabled: true },
58
+ fields: ['name', 'autoCall', 'interactionSchema'],
59
+ pageSize: 200,
60
+ },
61
+ });
62
+ const list = (data as any)?.data ?? [];
63
+ for (const s of list) {
64
+ if (s.autoCall) continue;
65
+ if (!parseJsonText(s.interactionSchema, null)) continue;
66
+ toolsManager.registerTools(`skill_hub_${sanitize(s.name)}`, { ui: { card: SkillHubCard } });
67
+ }
68
+ } catch {
69
+ // user without ACL or backend unavailable — skip silently
70
+ }
71
+ }
72
+ }
73
+
74
+ export { SkillManager, ExecutionHistory, SkillMetrics };
75
+ export default PluginSkillHubClient;
@@ -2,8 +2,8 @@ import { Migration } from '@nocobase/server';
2
2
 
3
3
  export default class AddProgressFieldsMigration extends Migration {
4
4
  async up() {
5
- const queryInterface = this.db.sequelize.getQueryInterface();
6
- const tablePrefix = this.db.options.tablePrefix || '';
5
+ const queryInterface = (this as any).db.sequelize.getQueryInterface();
6
+ const tablePrefix = (this as any).db.options.tablePrefix || '';
7
7
  const tableName = `${tablePrefix}skillWorkerConfigs`;
8
8
 
9
9
  try {
@@ -14,7 +14,7 @@ export default class AddProgressFieldsMigration extends Migration {
14
14
 
15
15
  // Force NocoBase fields metadata to recognize the physical columns exists
16
16
  // so it won't crash trying to ADD COLUMN during db.sync()
17
- const fieldRepo = this.db.getRepository('fields');
17
+ const fieldRepo = (this as any).db.getRepository('fields');
18
18
  const collectionName = 'skillWorkerConfigs';
19
19
 
20
20
  const fieldsToSync = [
@@ -40,11 +40,11 @@ export default class AddProgressFieldsMigration extends Migration {
40
40
  interface: f.type,
41
41
  }
42
42
  });
43
- this.app.logger.info(`[skill-hub] Restored NocoBase metadata for preexisting column ${f.name}`);
43
+ (this as any).app.logger.info(`[skill-hub] Restored NocoBase metadata for preexisting column ${f.name}`);
44
44
  }
45
45
  }
46
46
  } catch (error) {
47
- this.app.logger.error(`[skill-hub] Failed to check progress fields: ${error.message}`);
47
+ (this as any).app.logger.error(`[skill-hub] Failed to check progress fields: ${error.message}`);
48
48
  }
49
49
  }
50
50
  }
@@ -2,15 +2,15 @@ import { Migration } from '@nocobase/server';
2
2
 
3
3
  export default class AddInteractionSchemaMigration extends Migration {
4
4
  async up() {
5
- const queryInterface = this.db.sequelize.getQueryInterface();
6
- const tableName = `${this.db.options.tablePrefix || ''}skillDefinitions`;
5
+ const queryInterface = (this as any).db.sequelize.getQueryInterface();
6
+ const tableName = `${(this as any).db.options.tablePrefix || ''}skillDefinitions`;
7
7
 
8
8
  try {
9
9
  const tableExists = await queryInterface.tableExists(tableName);
10
10
  if (!tableExists) return;
11
11
 
12
12
  const tableDesc = await queryInterface.describeTable(tableName);
13
- const fieldRepo = this.db.getRepository('fields');
13
+ const fieldRepo = (this as any).db.getRepository('fields');
14
14
  const collectionName = 'skillDefinitions';
15
15
 
16
16
  const fieldMeta = await fieldRepo.findOne({
@@ -26,10 +26,10 @@ export default class AddInteractionSchemaMigration extends Migration {
26
26
  interface: 'textarea',
27
27
  },
28
28
  });
29
- this.app.logger.info('[skill-hub] Restored NocoBase metadata for preexisting column interactionSchema');
29
+ (this as any).app.logger.info('[skill-hub] Restored NocoBase metadata for preexisting column interactionSchema');
30
30
  }
31
31
  } catch (error) {
32
- this.app.logger.error(`[skill-hub] Failed to check interactionSchema field: ${error.message}`);
32
+ (this as any).app.logger.error(`[skill-hub] Failed to check interactionSchema field: ${error.message}`);
33
33
  }
34
34
  }
35
35
  }
@@ -5,9 +5,9 @@ export default class AddTracingDetailFieldsMigration extends Migration {
5
5
  appVersion = '<=2.x';
6
6
 
7
7
  async up() {
8
- const queryInterface = this.db.sequelize.getQueryInterface();
9
- const DataTypes = this.db.sequelize.constructor['DataTypes'];
10
- const tableName = `${this.db.options.tablePrefix || ''}orchestratorLogs`;
8
+ const queryInterface = (this as any).db.sequelize.getQueryInterface();
9
+ const DataTypes = (this as any).db.sequelize.constructor['DataTypes'];
10
+ const tableName = `${(this as any).db.options.tablePrefix || ''}orchestratorLogs`;
11
11
 
12
12
  const tableExists = await queryInterface
13
13
  .describeTable(tableName)
@@ -31,8 +31,8 @@ export default class AddTracingDetailFieldsMigration extends Migration {
31
31
  }
32
32
 
33
33
  async down() {
34
- const queryInterface = this.db.sequelize.getQueryInterface();
35
- const tableName = `${this.db.options.tablePrefix || ''}orchestratorLogs`;
34
+ const queryInterface = (this as any).db.sequelize.getQueryInterface();
35
+ const tableName = `${(this as any).db.options.tablePrefix || ''}orchestratorLogs`;
36
36
 
37
37
  for (const column of ['context', 'trace', 'messages']) {
38
38
  await queryInterface.removeColumn(tableName, column).catch(() => {});
@@ -2,8 +2,8 @@ import { Migration } from '@nocobase/server';
2
2
 
3
3
  export default class ChangePackagesToTextMigration extends Migration {
4
4
  async up() {
5
- const queryInterface = this.db.sequelize.getQueryInterface();
6
- const tableName = `${this.db.options.tablePrefix || ''}skillDefinitions`;
5
+ const queryInterface = (this as any).db.sequelize.getQueryInterface();
6
+ const tableName = `${(this as any).db.options.tablePrefix || ''}skillDefinitions`;
7
7
 
8
8
  try {
9
9
  const tableExists = await queryInterface.tableExists(tableName);
@@ -11,15 +11,15 @@ export default class ChangePackagesToTextMigration extends Migration {
11
11
 
12
12
  const tableDesc = await queryInterface.describeTable(tableName);
13
13
  const columnsToChange = ['packages', 'inputSchema', 'interactionSchema'];
14
- const fieldRepo = this.db.getRepository('fields');
14
+ const fieldRepo = (this as any).db.getRepository('fields');
15
15
  const collectionName = 'skillDefinitions';
16
16
 
17
17
  for (const col of columnsToChange) {
18
18
  if (tableDesc[col]) {
19
19
  // Change physical column type in Postgres if needed
20
- const dialect = this.db.sequelize.getDialect();
20
+ const dialect = (this as any).db.sequelize.getDialect();
21
21
  if (dialect === 'postgres') {
22
- await this.db.sequelize.query(`ALTER TABLE "${tableName}" ALTER COLUMN "${col}" TYPE text USING "${col}"::text;`);
22
+ await (this as any).db.sequelize.query(`ALTER TABLE "${tableName}" ALTER COLUMN "${col}" TYPE text USING "${col}"::text;`);
23
23
  } else {
24
24
  await queryInterface.changeColumn(tableName, col, {
25
25
  type: 'TEXT',
@@ -37,11 +37,11 @@ export default class ChangePackagesToTextMigration extends Migration {
37
37
  values: { type: 'text' },
38
38
  });
39
39
  }
40
- this.app.logger.info(`[skill-hub] Changed ${col} column type to text to support markdown`);
40
+ (this as any).app.logger.info(`[skill-hub] Changed ${col} column type to text to support markdown`);
41
41
  }
42
42
  }
43
43
  } catch (error) {
44
- this.app.logger.error(`[skill-hub] Failed to change packages field type: ${error.message}`);
44
+ (this as any).app.logger.error(`[skill-hub] Failed to change packages field type: ${error.message}`);
45
45
  }
46
46
  }
47
47
  }
@@ -2,11 +2,11 @@ import { Migration } from '@nocobase/server';
2
2
 
3
3
  export default class ChangeOtherJsonToTextMigration extends Migration {
4
4
  async up() {
5
- const queryInterface = this.db.sequelize.getQueryInterface();
6
- const dialect = this.db.sequelize.getDialect();
7
- const fieldRepo = this.db.getRepository('fields');
5
+ const queryInterface = (this as any).db.sequelize.getQueryInterface();
6
+ const dialect = (this as any).db.sequelize.getDialect();
7
+ const fieldRepo = (this as any).db.getRepository('fields');
8
8
 
9
- const tablePrefix = this.db.options.tablePrefix || '';
9
+ const tablePrefix = (this as any).db.options.tablePrefix || '';
10
10
 
11
11
  // 1. skillWorkerConfigs
12
12
  const workerTableName = `${tablePrefix}skillWorkerConfigs`;
@@ -18,18 +18,18 @@ export default class ChangeOtherJsonToTextMigration extends Migration {
18
18
  for (const col of columns) {
19
19
  if (tableDesc[col]) {
20
20
  if (dialect === 'postgres') {
21
- await this.db.sequelize.query(`ALTER TABLE "${workerTableName}" ALTER COLUMN "${col}" TYPE text USING "${col}"::text;`);
21
+ await (this as any).db.sequelize.query(`ALTER TABLE "${workerTableName}" ALTER COLUMN "${col}" TYPE text USING "${col}"::text;`);
22
22
  } else {
23
23
  await queryInterface.changeColumn(workerTableName, col, { type: 'TEXT' });
24
24
  }
25
25
  const fieldMeta = await fieldRepo.findOne({ filter: { name: col, collectionName: 'skillWorkerConfigs' } });
26
26
  if (fieldMeta) await fieldRepo.update({ filterByTk: fieldMeta.get('id'), values: { type: 'text' } });
27
- this.app.logger.info(`[skill-hub] Changed ${col} in skillWorkerConfigs to text`);
27
+ (this as any).app.logger.info(`[skill-hub] Changed ${col} in skillWorkerConfigs to text`);
28
28
  }
29
29
  }
30
30
  }
31
31
  } catch (e) {
32
- this.app.logger.warn(`[skill-hub] Failed to migrate skillWorkerConfigs: ${e.message}`);
32
+ (this as any).app.logger.warn(`[skill-hub] Failed to migrate skillWorkerConfigs: ${e.message}`);
33
33
  }
34
34
 
35
35
  // 2. skillExecutions
@@ -41,17 +41,17 @@ export default class ChangeOtherJsonToTextMigration extends Migration {
41
41
 
42
42
  if (tableDesc[col]) {
43
43
  if (dialect === 'postgres') {
44
- await this.db.sequelize.query(`ALTER TABLE "${execTableName}" ALTER COLUMN "${col}" TYPE text USING "${col}"::text;`);
44
+ await (this as any).db.sequelize.query(`ALTER TABLE "${execTableName}" ALTER COLUMN "${col}" TYPE text USING "${col}"::text;`);
45
45
  } else {
46
46
  await queryInterface.changeColumn(execTableName, col, { type: 'TEXT' });
47
47
  }
48
48
  const fieldMeta = await fieldRepo.findOne({ filter: { name: col, collectionName: 'skillExecutions' } });
49
49
  if (fieldMeta) await fieldRepo.update({ filterByTk: fieldMeta.get('id'), values: { type: 'text' } });
50
- this.app.logger.info(`[skill-hub] Changed ${col} in skillExecutions to text`);
50
+ (this as any).app.logger.info(`[skill-hub] Changed ${col} in skillExecutions to text`);
51
51
  }
52
52
  }
53
53
  } catch (e) {
54
- this.app.logger.warn(`[skill-hub] Failed to migrate skillExecutions: ${e.message}`);
54
+ (this as any).app.logger.warn(`[skill-hub] Failed to migrate skillExecutions: ${e.message}`);
55
55
  }
56
56
  }
57
57
  }
@@ -5,8 +5,8 @@ export default class AddLlmFieldsToOrchestratorConfig extends Migration {
5
5
  appVersion = '>=0.1.0';
6
6
 
7
7
  async up() {
8
- const queryInterface = this.db.sequelize.getQueryInterface();
9
- const tablePrefix = this.db.options.tablePrefix || '';
8
+ const queryInterface = (this as any).db.sequelize.getQueryInterface();
9
+ const tablePrefix = (this as any).db.options.tablePrefix || '';
10
10
  const tableName = `${tablePrefix}orchestratorConfig`;
11
11
 
12
12
  const tableExists = await queryInterface.tableExists(tableName);
@@ -14,7 +14,7 @@ export default class FixInputArgsJsonToText extends Migration {
14
14
  appVersion = '>=0.1.0';
15
15
 
16
16
  async up() {
17
- const queryInterface = this.db.sequelize.getQueryInterface();
17
+ const queryInterface = (this as any).db.sequelize.getQueryInterface();
18
18
 
19
19
  // Check current column type
20
20
  const tableDesc = await queryInterface.describeTable('skillExecutions').catch(() => null);
@@ -25,7 +25,7 @@ export default class FixInputArgsJsonToText extends Migration {
25
25
 
26
26
  // Only migrate if still json type
27
27
  if (col.type && col.type.toLowerCase().includes('json')) {
28
- await this.db.sequelize.query(
28
+ await (this as any).db.sequelize.query(
29
29
  `ALTER TABLE "skillExecutions" ALTER COLUMN "inputArgs" TYPE text USING "inputArgs"::text`,
30
30
  );
31
31
  console.log('[skill-hub] Migration: converted skillExecutions.inputArgs from json to text');
@@ -5,8 +5,8 @@ export default class AddOrchestratorTraceFieldsToSkillExecutions extends Migrati
5
5
  appVersion = '>=0.1.0';
6
6
 
7
7
  async up() {
8
- const queryInterface = this.db.sequelize.getQueryInterface();
9
- const tablePrefix = this.db.options.tablePrefix || '';
8
+ const queryInterface = (this as any).db.sequelize.getQueryInterface();
9
+ const tablePrefix = (this as any).db.options.tablePrefix || '';
10
10
  const tableName = `${tablePrefix}skillExecutions`;
11
11
  const tableExists = await queryInterface.tableExists(tableName).catch(() => false);
12
12
  if (!tableExists) return;
@@ -1,6 +1,7 @@
1
1
  import { Plugin } from '@nocobase/server';
2
2
  import path from 'path';
3
3
  import { createDelegateToolsProvider } from './tools/delegate-task';
4
+ import { createExternalRagSearchTool } from './tools/external-rag-search';
4
5
  import { registerTracingResource } from './resources/tracing';
5
6
  import SkillHubSubFeature from './skill-hub/plugin';
6
7
 
@@ -13,10 +14,10 @@ export class PluginAgentOrchestratorServer extends Plugin {
13
14
 
14
15
  async beforeLoad() {
15
16
  // Import collection definitions
16
- this.db.import({ directory: path.resolve(__dirname, 'collections') });
17
+ (this as any).db.import({ directory: path.resolve(__dirname, 'collections') });
17
18
 
18
- this.db.addMigrations({
19
- namespace: this.name,
19
+ (this as any).db.addMigrations({
20
+ namespace: (this as any).name,
20
21
  directory: path.resolve(__dirname, 'migrations'),
21
22
  context: { plugin: this },
22
23
  });
@@ -26,16 +27,25 @@ export class PluginAgentOrchestratorServer extends Plugin {
26
27
  await this.skillHub.load();
27
28
 
28
29
  // --- ACL ---
29
- this.app.acl.registerSnippet({
30
- name: `pm.${this.name}`,
31
- actions: ['orchestratorConfig:*', 'orchestratorTracing:*', 'agentExecutionSpans:*', 'skillDefinitions:*', 'skillExecutions:*', 'skillHub:*', 'skillWorkerConfigs:*'],
30
+ (this as any).app.acl.registerSnippet({
31
+ name: `pm.${(this as any).name}`,
32
+ actions: [
33
+ 'orchestratorConfig:*',
34
+ 'orchestratorTracing:*',
35
+ 'agentExecutionSpans:*',
36
+ 'skillDefinitions:*',
37
+ 'skillExecutions:*',
38
+ 'skillHub:*',
39
+ 'skillWorkerConfigs:*',
40
+ ],
32
41
  });
33
42
 
34
43
  // --- Register Dynamic Tools ---
35
44
  // Each configured sub-agent becomes a callable tool for its leader.
36
45
  // Uses createReactAgent (LangGraph public API) instead of private AIEmployee class.
37
46
  // Tools are registered via app.aiManager.toolsManager (public API from @nocobase/ai core).
38
- const toolsManager = this.app.aiManager.toolsManager;
47
+ const toolsManager = (this as any).app.aiManager.toolsManager;
48
+ toolsManager.registerTools(createExternalRagSearchTool(this));
39
49
  toolsManager.registerDynamicTools(createDelegateToolsProvider(this));
40
50
 
41
51
  // --- Register Tracing Resource (Phase 5) ---
@@ -45,15 +55,15 @@ export class PluginAgentOrchestratorServer extends Plugin {
45
55
  // --- Log Retention ---
46
56
  // Daily prune of orchestratorLogs / agentExecutionSpans to keep tables bounded.
47
57
  // Override window via env: ORCHESTRATOR_LOG_RETENTION_DAYS (default 30).
48
- this.app.cronJobManager.addJob({
58
+ (this as any).app.cronJobManager.addJob({
49
59
  cronTime: '0 30 2 * * *',
50
60
  onTick: async () => {
51
61
  try {
52
62
  const days = Number(process.env.ORCHESTRATOR_LOG_RETENTION_DAYS || 30);
53
63
  if (!Number.isFinite(days) || days <= 0) return;
54
64
  const cutoff = new Date(Date.now() - days * 86400000);
55
- const repo = this.db.getRepository('orchestratorLogs');
56
- const spansRepo = this.db.getRepository('agentExecutionSpans');
65
+ const repo = (this as any).db.getRepository('orchestratorLogs');
66
+ const spansRepo = (this as any).db.getRepository('agentExecutionSpans');
57
67
  const deletedLogs = repo
58
68
  ? await repo.destroy({
59
69
  filter: { createdAt: { $lt: cutoff.toISOString() } },
@@ -64,11 +74,11 @@ export class PluginAgentOrchestratorServer extends Plugin {
64
74
  filter: { createdAt: { $lt: cutoff.toISOString() } },
65
75
  })
66
76
  : 0;
67
- this.app.log.info(
77
+ (this as any).app.log.info(
68
78
  `[AgentOrchestrator] Pruned ${deletedLogs} orchestratorLogs and ${deletedSpans} agentExecutionSpans rows older than ${days} day(s).`,
69
79
  );
70
80
  } catch (e) {
71
- this.app.log.error('[AgentOrchestrator] Log retention job failed', e);
81
+ (this as any).app.log.error('[AgentOrchestrator] Log retention job failed', e);
72
82
  }
73
83
  },
74
84
  });
@@ -85,7 +95,7 @@ export class PluginAgentOrchestratorServer extends Plugin {
85
95
  async afterEnable() {}
86
96
  async afterDisable() {}
87
97
  async remove() {}
88
-
98
+
89
99
  async beforeStop() {
90
100
  await this.skillHub.beforeStop();
91
101
  }
@@ -40,10 +40,10 @@ const NODE_BUILTINS = [
40
40
  const PYTHON_BUILTINS = [
41
41
  'os', 'sys', 'json', 'math', 'datetime', 'collections', 'itertools',
42
42
  'functools', 'pathlib', 'typing', 'io', 'csv', 're', 'string', 'textwrap',
43
- 'decimal', 'fractions', 'random', 'statistics', 'copy', 'enum', 'dataclasses',
44
- 'abc', 'contextlib', 'operator', 'time', 'calendar', 'locale', 'struct',
45
- 'hashlib', 'base64', 'binascii', 'codecs', 'unicodedata', 'pprint',
46
- 'warnings', 'traceback', 'logging', 'unittest', 'argparse',
43
+ 'decimal', 'fractions', 'random', 'statistics', 'copy', 'enum', 'dataclasses',
44
+ 'abc', 'contextlib', 'operator', 'time', 'calendar', 'locale', 'struct',
45
+ 'hashlib', 'base64', 'binascii', 'codecs', 'unicodedata', 'pprint',
46
+ 'warnings', 'traceback', 'logging', 'unittest', 'argparse', 'ast',
47
47
  'tempfile', 'xml', 'zipfile',
48
48
  // Pre-installed local packages (trusted, bundled with plugin)
49
49
  'svg_to_pptx',
@@ -154,6 +154,6 @@ export class CodeValidationError extends Error {
154
154
  public matchedPattern: string,
155
155
  ) {
156
156
  super(`Code validation failed: ${message}`);
157
- this.name = 'CodeValidationError';
157
+ (this as any).name = 'CodeValidationError';
158
158
  }
159
159
  }