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.
- package/README.md +9 -7
- package/dist/client/index.js +1 -1
- package/dist/client-v2/{214.723affb37c13bf7a.js → 214.79650a549273f163.js} +1 -1
- package/dist/client-v2/264.718a107e43fc163c.js +10 -0
- package/dist/client-v2/373.f5d5292e53c4e832.js +10 -0
- package/dist/client-v2/{41.1805b2edfaa4afe2.js → 41.ba6e080cc0488143.js} +1 -1
- package/dist/client-v2/418.29e713f79131eece.js +10 -0
- package/dist/client-v2/619.bd3c5698b40705c3.js +10 -0
- package/dist/client-v2/677.a991ce0250ff5c77.js +10 -0
- package/dist/client-v2/{70.a15d7fcec7c41768.js → 70.bda9518881c05360.js} +1 -1
- package/dist/client-v2/925.f5370de8f6632d65.js +10 -0
- package/dist/client-v2/index.js +1 -1
- package/dist/externalVersion.js +7 -10
- package/dist/locale/en-US.json +94 -25
- package/dist/locale/vi-VN.json +94 -25
- package/dist/locale/zh-CN.json +94 -25
- package/dist/server/collections/agent-execution-spans.js +37 -0
- package/dist/server/collections/agent-harness-profiles.js +2 -2
- package/dist/server/collections/agent-memory-contexts.js +125 -0
- package/dist/server/collections/orchestrator-logs.js +2 -2
- package/dist/server/migrations/20260425000000-add-interaction-schema.js +3 -1
- package/dist/server/migrations/20260427000000-change-packages-to-text.js +3 -1
- package/dist/server/migrations/20260427000001-change-other-json-to-text.js +6 -2
- package/dist/server/migrations/20260524001000-add-plan-approval-and-harness-profiles.js +21 -19
- package/dist/server/migrations/20260621000000-native-policy-profile-defaults.js +193 -0
- package/dist/server/plugin.js +128 -74
- package/dist/server/resources/agent-monitor.js +454 -0
- package/dist/server/services/AgentHarness.js +24 -499
- package/dist/server/services/AgentMemoryContextService.js +216 -0
- package/dist/server/services/ExecutionSpanService.js +2 -2
- package/dist/server/services/NativeSubAgentObserver.js +413 -0
- package/dist/server/skill-hub/mcp/McpController.js +16 -5
- package/dist/server/skill-hub/plugin.js +81 -5
- package/dist/server/skill-hub/tasks/SkillExecutionTask.js +9 -3
- package/dist/server/tools/delegate-task.js +11 -589
- package/dist/server/utils/skill-settings.js +18 -1
- package/package.json +47 -49
- package/src/client/AIEmployeesContext.tsx +5 -18
- package/src/client/AgentRunsTab.tsx +2 -771
- package/src/client/HarnessProfilesTab.tsx +2 -257
- package/src/client/OrchestratorSettings.tsx +97 -106
- package/src/client/RulesTab.tsx +2 -788
- package/src/client/plugin.tsx +0 -2
- package/src/client/skill-hub/components/ExecutionHistory.tsx +200 -202
- package/src/client/skill-hub/components/ExecutionProgress.tsx +51 -55
- package/src/client/skill-hub/components/LoopSettings.tsx +331 -331
- package/src/client/skill-hub/components/SkillEditor.tsx +43 -39
- package/src/client/skill-hub/components/SkillManager.tsx +194 -181
- package/src/client/skill-hub/components/SkillTestPanel.tsx +141 -145
- package/src/client/skill-hub/locale.ts +16 -16
- package/src/client/skill-hub/tools/SkillHubCard.tsx +104 -109
- package/src/client/skill-hub/tools/loopTemplates.ts +52 -52
- package/src/client/skill-hub/utils/jsonFields.ts +7 -3
- package/src/client-v2/components/AIEmployeesContext.tsx +3 -16
- package/src/client-v2/components/AgentRunsTab.tsx +182 -455
- package/src/client-v2/components/HarnessProfilesTab.tsx +34 -31
- package/src/client-v2/components/RulesTab.tsx +2 -782
- package/src/client-v2/components/TracingTab.tsx +1 -1
- package/src/client-v2/hooks/useApiRequest.ts +8 -1
- package/src/client-v2/pages/RulesPage.tsx +2 -2
- package/src/client-v2/plugin.tsx +3 -3
- package/src/locale/en-US.json +94 -25
- package/src/locale/vi-VN.json +94 -25
- package/src/locale/zh-CN.json +94 -25
- package/src/server/__tests__/native-sub-agent-observer.test.ts +246 -0
- package/src/server/__tests__/skill-settings.test.ts +6 -6
- package/src/server/__tests__/smoke.test.ts +1 -0
- package/src/server/collections/agent-execution-spans.ts +37 -0
- package/src/server/collections/agent-harness-profiles.ts +59 -59
- package/src/server/collections/agent-loop-events.ts +71 -71
- package/src/server/collections/agent-loop-steps.ts +144 -144
- package/src/server/collections/agent-memory-contexts.ts +95 -0
- package/src/server/collections/orchestrator-logs.ts +4 -4
- package/src/server/collections/skill-definitions.ts +111 -111
- package/src/server/collections/skill-executions.ts +106 -106
- package/src/server/collections/skill-loop-configs.ts +65 -65
- package/src/server/migrations/20260423000000-add-progress-fields.ts +14 -14
- package/src/server/migrations/20260425000000-add-interaction-schema.ts +3 -1
- package/src/server/migrations/20260427000000-change-packages-to-text.ts +4 -2
- package/src/server/migrations/20260427000001-change-other-json-to-text.ts +9 -5
- package/src/server/migrations/20260524000000-add-agent-loop-fields-to-skill-executions.ts +30 -30
- package/src/server/migrations/20260524001000-add-plan-approval-and-harness-profiles.ts +145 -142
- package/src/server/migrations/20260615000000-normalize-ai-employee-tool-bindings.ts +2 -2
- package/src/server/migrations/20260621000000-native-policy-profile-defaults.ts +193 -0
- package/src/server/plugin.ts +151 -94
- package/src/server/resources/agent-monitor.ts +482 -0
- package/src/server/services/AgentHarness.ts +38 -623
- package/src/server/services/AgentMemoryContextService.ts +256 -0
- package/src/server/services/AgentPlanValidator.ts +73 -73
- package/src/server/services/ExecutionSpanService.ts +6 -2
- package/src/server/services/FileManager.ts +144 -144
- package/src/server/services/NativeSubAgentObserver.ts +507 -0
- package/src/server/services/SkillManager.ts +583 -583
- package/src/server/services/SkillRepositoryService.ts +5 -7
- package/src/server/services/TokenTracker.ts +3 -3
- package/src/server/services/WorkerEnvManager.ts +1 -2
- package/src/server/skill-hub/actions/git-import.ts +5 -7
- package/src/server/skill-hub/mcp/McpController.ts +41 -14
- package/src/server/skill-hub/plugin.ts +89 -6
- package/src/server/skill-hub/tasks/SkillExecutionTask.ts +470 -460
- package/src/server/skill-hub/utils/json-fields.ts +1 -1
- package/src/server/tools/delegate-task.ts +13 -847
- package/src/server/utils/skill-settings.ts +24 -6
- package/dist/client-v2/264.0533912e6c5ea2d7.js +0 -10
- package/dist/client-v2/418.5ae055abf141820e.js +0 -10
- package/dist/client-v2/619.d99d3c9e61c99064.js +0 -10
- package/dist/client-v2/892.72db4161511c8a16.js +0 -10
- package/dist/client-v2/926.87f660b670d85bcc.js +0 -10
- package/src/client/tools/PlanApprovalCard.tsx +0 -176
- package/src/client/tools/registerOrchestratorCards.ts +0 -17
|
@@ -1,142 +1,145 @@
|
|
|
1
|
-
import { DataTypes } from '@nocobase/database';
|
|
2
|
-
import { Migration } from '@nocobase/server';
|
|
3
|
-
|
|
4
|
-
export default class AddPlanApprovalAndHarnessProfiles extends Migration {
|
|
5
|
-
on = 'afterLoad';
|
|
6
|
-
appVersion = '>=0.1.0';
|
|
7
|
-
|
|
8
|
-
async up() {
|
|
9
|
-
const db = (this as any).db;
|
|
10
|
-
const queryInterface = db.sequelize.getQueryInterface();
|
|
11
|
-
const tablePrefix = db.options.tablePrefix || '';
|
|
12
|
-
|
|
13
|
-
await this.addRunColumns(queryInterface, `${tablePrefix}agentLoopRuns`);
|
|
14
|
-
await this.addStepColumns(queryInterface, `${tablePrefix}agentLoopSteps`);
|
|
15
|
-
await this.addConfigColumns(queryInterface, `${tablePrefix}orchestratorConfig`);
|
|
16
|
-
await this.ensureHarnessProfiles(queryInterface, `${tablePrefix}agentHarnessProfiles`);
|
|
17
|
-
await this.seedDefaultProfiles();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async addRunColumns(queryInterface: any, tableName: string) {
|
|
21
|
-
const tableExists = await queryInterface.tableExists(tableName).catch(() => false);
|
|
22
|
-
if (!tableExists) return;
|
|
23
|
-
const tableDesc = await queryInterface.describeTable(tableName);
|
|
24
|
-
const addIfMissing = async (name: string, spec: any) => {
|
|
25
|
-
if (tableDesc[name]) return;
|
|
26
|
-
await queryInterface.addColumn(tableName, name, spec);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
await addIfMissing('approvalStatus', { type: DataTypes.STRING(30), allowNull: true, defaultValue: 'none' });
|
|
30
|
-
await addIfMissing('approvedById', { type: DataTypes.BIGINT, allowNull: true });
|
|
31
|
-
await addIfMissing('approvedAt', { type: DataTypes.DATE, allowNull: true });
|
|
32
|
-
await addIfMissing('rejectionReason', { type: DataTypes.TEXT, allowNull: true });
|
|
33
|
-
await addIfMissing('changeRequest', { type: DataTypes.TEXT, allowNull: true });
|
|
34
|
-
await addIfMissing('planVersion', { type: DataTypes.INTEGER, allowNull: true, defaultValue: 1 });
|
|
35
|
-
await addIfMissing('planSource', { type: DataTypes.STRING(50), allowNull: true });
|
|
36
|
-
await addIfMissing('plannerModel', { type: DataTypes.STRING(100), allowNull: true });
|
|
37
|
-
await addIfMissing('lockedBy', { type: DataTypes.STRING(100), allowNull: true });
|
|
38
|
-
await addIfMissing('lockedUntil', { type: DataTypes.DATE, allowNull: true });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async addStepColumns(queryInterface: any, tableName: string) {
|
|
42
|
-
const tableExists = await queryInterface.tableExists(tableName).catch(() => false);
|
|
43
|
-
if (!tableExists) return;
|
|
44
|
-
const tableDesc = await queryInterface.describeTable(tableName);
|
|
45
|
-
if (!tableDesc.dependencyPolicy) {
|
|
46
|
-
await queryInterface.addColumn(tableName, 'dependencyPolicy', {
|
|
47
|
-
type: DataTypes.STRING(30),
|
|
48
|
-
allowNull: true,
|
|
49
|
-
defaultValue: 'require_success',
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async addConfigColumns(queryInterface: any, tableName: string) {
|
|
55
|
-
const tableExists = await queryInterface.tableExists(tableName).catch(() => false);
|
|
56
|
-
if (!tableExists) return;
|
|
57
|
-
const tableDesc = await queryInterface.describeTable(tableName);
|
|
58
|
-
if (!tableDesc.harnessTag) {
|
|
59
|
-
await queryInterface.addColumn(tableName, 'harnessTag', {
|
|
60
|
-
type: DataTypes.STRING(100),
|
|
61
|
-
allowNull: true,
|
|
62
|
-
defaultValue: 'default',
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async ensureHarnessProfiles(queryInterface: any, tableName: string) {
|
|
68
|
-
const tableExists = await queryInterface.tableExists(tableName).catch(() => false);
|
|
69
|
-
if (tableExists) return;
|
|
70
|
-
await queryInterface.createTable(tableName, {
|
|
71
|
-
id: { type: DataTypes.BIGINT, primaryKey: true, autoIncrement: true },
|
|
72
|
-
tag: { type: DataTypes.STRING(100), allowNull: false, unique: true },
|
|
73
|
-
title: { type: DataTypes.STRING(200), allowNull: true },
|
|
74
|
-
description: { type: DataTypes.TEXT, allowNull: true },
|
|
75
|
-
enabled: { type: DataTypes.BOOLEAN, allowNull: true, defaultValue: true },
|
|
76
|
-
settings: { type: DataTypes.JSON, allowNull: true, defaultValue: {} },
|
|
77
|
-
createdAt: { type: DataTypes.DATE, allowNull: true },
|
|
78
|
-
updatedAt: { type: DataTypes.DATE, allowNull: true },
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async seedDefaultProfiles() {
|
|
83
|
-
const repo = (this as any).db.getRepository('agentHarnessProfiles');
|
|
84
|
-
if (!repo) return;
|
|
85
|
-
const profiles = [
|
|
86
|
-
{
|
|
87
|
-
tag: 'default',
|
|
88
|
-
title: 'Default',
|
|
89
|
-
description: '
|
|
90
|
-
settings: {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
1
|
+
import { DataTypes } from '@nocobase/database';
|
|
2
|
+
import { Migration } from '@nocobase/server';
|
|
3
|
+
|
|
4
|
+
export default class AddPlanApprovalAndHarnessProfiles extends Migration {
|
|
5
|
+
on = 'afterLoad';
|
|
6
|
+
appVersion = '>=0.1.0';
|
|
7
|
+
|
|
8
|
+
async up() {
|
|
9
|
+
const db = (this as any).db;
|
|
10
|
+
const queryInterface = db.sequelize.getQueryInterface();
|
|
11
|
+
const tablePrefix = db.options.tablePrefix || '';
|
|
12
|
+
|
|
13
|
+
await this.addRunColumns(queryInterface, `${tablePrefix}agentLoopRuns`);
|
|
14
|
+
await this.addStepColumns(queryInterface, `${tablePrefix}agentLoopSteps`);
|
|
15
|
+
await this.addConfigColumns(queryInterface, `${tablePrefix}orchestratorConfig`);
|
|
16
|
+
await this.ensureHarnessProfiles(queryInterface, `${tablePrefix}agentHarnessProfiles`);
|
|
17
|
+
await this.seedDefaultProfiles();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async addRunColumns(queryInterface: any, tableName: string) {
|
|
21
|
+
const tableExists = await queryInterface.tableExists(tableName).catch(() => false);
|
|
22
|
+
if (!tableExists) return;
|
|
23
|
+
const tableDesc = await queryInterface.describeTable(tableName);
|
|
24
|
+
const addIfMissing = async (name: string, spec: any) => {
|
|
25
|
+
if (tableDesc[name]) return;
|
|
26
|
+
await queryInterface.addColumn(tableName, name, spec);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
await addIfMissing('approvalStatus', { type: DataTypes.STRING(30), allowNull: true, defaultValue: 'none' });
|
|
30
|
+
await addIfMissing('approvedById', { type: DataTypes.BIGINT, allowNull: true });
|
|
31
|
+
await addIfMissing('approvedAt', { type: DataTypes.DATE, allowNull: true });
|
|
32
|
+
await addIfMissing('rejectionReason', { type: DataTypes.TEXT, allowNull: true });
|
|
33
|
+
await addIfMissing('changeRequest', { type: DataTypes.TEXT, allowNull: true });
|
|
34
|
+
await addIfMissing('planVersion', { type: DataTypes.INTEGER, allowNull: true, defaultValue: 1 });
|
|
35
|
+
await addIfMissing('planSource', { type: DataTypes.STRING(50), allowNull: true });
|
|
36
|
+
await addIfMissing('plannerModel', { type: DataTypes.STRING(100), allowNull: true });
|
|
37
|
+
await addIfMissing('lockedBy', { type: DataTypes.STRING(100), allowNull: true });
|
|
38
|
+
await addIfMissing('lockedUntil', { type: DataTypes.DATE, allowNull: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async addStepColumns(queryInterface: any, tableName: string) {
|
|
42
|
+
const tableExists = await queryInterface.tableExists(tableName).catch(() => false);
|
|
43
|
+
if (!tableExists) return;
|
|
44
|
+
const tableDesc = await queryInterface.describeTable(tableName);
|
|
45
|
+
if (!tableDesc.dependencyPolicy) {
|
|
46
|
+
await queryInterface.addColumn(tableName, 'dependencyPolicy', {
|
|
47
|
+
type: DataTypes.STRING(30),
|
|
48
|
+
allowNull: true,
|
|
49
|
+
defaultValue: 'require_success',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async addConfigColumns(queryInterface: any, tableName: string) {
|
|
55
|
+
const tableExists = await queryInterface.tableExists(tableName).catch(() => false);
|
|
56
|
+
if (!tableExists) return;
|
|
57
|
+
const tableDesc = await queryInterface.describeTable(tableName);
|
|
58
|
+
if (!tableDesc.harnessTag) {
|
|
59
|
+
await queryInterface.addColumn(tableName, 'harnessTag', {
|
|
60
|
+
type: DataTypes.STRING(100),
|
|
61
|
+
allowNull: true,
|
|
62
|
+
defaultValue: 'default',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async ensureHarnessProfiles(queryInterface: any, tableName: string) {
|
|
68
|
+
const tableExists = await queryInterface.tableExists(tableName).catch(() => false);
|
|
69
|
+
if (tableExists) return;
|
|
70
|
+
await queryInterface.createTable(tableName, {
|
|
71
|
+
id: { type: DataTypes.BIGINT, primaryKey: true, autoIncrement: true },
|
|
72
|
+
tag: { type: DataTypes.STRING(100), allowNull: false, unique: true },
|
|
73
|
+
title: { type: DataTypes.STRING(200), allowNull: true },
|
|
74
|
+
description: { type: DataTypes.TEXT, allowNull: true },
|
|
75
|
+
enabled: { type: DataTypes.BOOLEAN, allowNull: true, defaultValue: true },
|
|
76
|
+
settings: { type: DataTypes.JSON, allowNull: true, defaultValue: {} },
|
|
77
|
+
createdAt: { type: DataTypes.DATE, allowNull: true },
|
|
78
|
+
updatedAt: { type: DataTypes.DATE, allowNull: true },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async seedDefaultProfiles() {
|
|
83
|
+
const repo = (this as any).db.getRepository('agentHarnessProfiles');
|
|
84
|
+
if (!repo) return;
|
|
85
|
+
const profiles = [
|
|
86
|
+
{
|
|
87
|
+
tag: 'default',
|
|
88
|
+
title: 'Default',
|
|
89
|
+
description: 'Default native observer and memory policy for normal AI employee work.',
|
|
90
|
+
settings: {
|
|
91
|
+
nativeObserverEnabled: true,
|
|
92
|
+
memoryInjectionEnabled: true,
|
|
93
|
+
memoryScopes: ['public', 'user', 'agent_user'],
|
|
94
|
+
knowledgeScopes: ['public', 'private'],
|
|
95
|
+
maxMemoryContextChars: 6000,
|
|
96
|
+
tracingRetentionDays: 30,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
tag: 'safe',
|
|
101
|
+
title: 'Safe',
|
|
102
|
+
description:
|
|
103
|
+
'Conservative native observer policy with private context enabled only for matching user/agent pairs.',
|
|
104
|
+
settings: {
|
|
105
|
+
nativeObserverEnabled: true,
|
|
106
|
+
memoryInjectionEnabled: true,
|
|
107
|
+
memoryScopes: ['public', 'user', 'agent_user'],
|
|
108
|
+
knowledgeScopes: ['public', 'private'],
|
|
109
|
+
maxMemoryContextChars: 4000,
|
|
110
|
+
tracingRetentionDays: 14,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
tag: 'file-heavy',
|
|
115
|
+
title: 'File Heavy',
|
|
116
|
+
description: 'Native observer policy for agents that need more context while working with files and artifacts.',
|
|
117
|
+
settings: {
|
|
118
|
+
nativeObserverEnabled: true,
|
|
119
|
+
memoryInjectionEnabled: true,
|
|
120
|
+
memoryScopes: ['public', 'user', 'agent_user'],
|
|
121
|
+
knowledgeScopes: ['public', 'private'],
|
|
122
|
+
maxMemoryContextChars: 8000,
|
|
123
|
+
tracingRetentionDays: 30,
|
|
124
|
+
preferFileTools: true,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
for (const profile of profiles) {
|
|
129
|
+
const existing = await repo.findOne({ filter: { tag: profile.tag } });
|
|
130
|
+
if (existing) continue;
|
|
131
|
+
await repo.create({
|
|
132
|
+
values: {
|
|
133
|
+
...profile,
|
|
134
|
+
enabled: true,
|
|
135
|
+
createdAt: new Date(),
|
|
136
|
+
updatedAt: new Date(),
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async down() {
|
|
143
|
+
// No rollback: new nullable columns and the profile table are backward compatible.
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -33,7 +33,7 @@ export default class NormalizeAIEmployeeToolBindings extends Migration {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
async down() {
|
|
36
|
-
// No rollback: this only
|
|
37
|
-
//
|
|
36
|
+
// No rollback: this only normalizes current tool-shaped entries and removes
|
|
37
|
+
// retired custom orchestrator tools that are no longer registered.
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { DataTypes } from '@nocobase/database';
|
|
2
|
+
import { Migration } from '@nocobase/server';
|
|
3
|
+
import { normalizeAIEmployeeSkillSettings } from '../utils/skill-settings';
|
|
4
|
+
|
|
5
|
+
type ProfileSeed = {
|
|
6
|
+
tag: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
settings: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const nativePolicyProfiles: ProfileSeed[] = [
|
|
13
|
+
{
|
|
14
|
+
tag: 'default',
|
|
15
|
+
title: 'Default',
|
|
16
|
+
description: 'Default native observer and memory policy for normal AI employee work.',
|
|
17
|
+
settings: {
|
|
18
|
+
nativeObserverEnabled: true,
|
|
19
|
+
memoryInjectionEnabled: true,
|
|
20
|
+
memoryScopes: ['public', 'user', 'agent_user'],
|
|
21
|
+
knowledgeScopes: ['public', 'private'],
|
|
22
|
+
maxMemoryContextChars: 6000,
|
|
23
|
+
tracingRetentionDays: 30,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
tag: 'safe',
|
|
28
|
+
title: 'Safe',
|
|
29
|
+
description: 'Conservative native observer policy with private context enabled only for matching user/agent pairs.',
|
|
30
|
+
settings: {
|
|
31
|
+
nativeObserverEnabled: true,
|
|
32
|
+
memoryInjectionEnabled: true,
|
|
33
|
+
memoryScopes: ['public', 'user', 'agent_user'],
|
|
34
|
+
knowledgeScopes: ['public', 'private'],
|
|
35
|
+
maxMemoryContextChars: 4000,
|
|
36
|
+
tracingRetentionDays: 14,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
tag: 'file-heavy',
|
|
41
|
+
title: 'File Heavy',
|
|
42
|
+
description: 'Native observer policy for agents that need more context while working with files and artifacts.',
|
|
43
|
+
settings: {
|
|
44
|
+
nativeObserverEnabled: true,
|
|
45
|
+
memoryInjectionEnabled: true,
|
|
46
|
+
memoryScopes: ['public', 'user', 'agent_user'],
|
|
47
|
+
knowledgeScopes: ['public', 'private'],
|
|
48
|
+
maxMemoryContextChars: 8000,
|
|
49
|
+
tracingRetentionDays: 30,
|
|
50
|
+
preferFileTools: true,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
function readModelValue(record: unknown, key: string) {
|
|
56
|
+
const model = record as { get?: (name: string) => unknown; [key: string]: unknown };
|
|
57
|
+
return typeof model?.get === 'function' ? model.get(key) : model?.[key];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function asObject(value: unknown) {
|
|
61
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : {};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function dropRetiredPolicyKeys(settings: Record<string, unknown>) {
|
|
65
|
+
const retired = new Set([
|
|
66
|
+
'requirePlanApproval',
|
|
67
|
+
'allowSubAgents',
|
|
68
|
+
'allowToolCalls',
|
|
69
|
+
'maxParallelSubAgents',
|
|
70
|
+
'maxControllerSteps',
|
|
71
|
+
'requireVerification',
|
|
72
|
+
]);
|
|
73
|
+
return Object.fromEntries(Object.entries(settings).filter(([key]) => !retired.has(key)));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function normalizeOptionalString(value: unknown) {
|
|
77
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function buildContextKey(record: Record<string, unknown>) {
|
|
81
|
+
const scope = normalizeOptionalString(record.scope);
|
|
82
|
+
const userPart = scope === 'public' ? 'public' : String(record.userId || '');
|
|
83
|
+
const agentPart = normalizeOptionalString(record.aiEmployeeUsername) || '*';
|
|
84
|
+
return `${scope}:${userPart}:${agentPart}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export default class NativePolicyProfileDefaults extends Migration {
|
|
88
|
+
on = 'afterLoad';
|
|
89
|
+
appVersion = '>=0.1.0';
|
|
90
|
+
|
|
91
|
+
async up() {
|
|
92
|
+
await this.ensureNativePolicyProfiles();
|
|
93
|
+
await this.ensureAgentMemoryContextKeys();
|
|
94
|
+
await this.normalizeAIEmployeeToolBindings();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private async ensureNativePolicyProfiles() {
|
|
98
|
+
const repo = (this as unknown as { db: { getRepository: (name: string) => any } }).db.getRepository(
|
|
99
|
+
'agentHarnessProfiles',
|
|
100
|
+
);
|
|
101
|
+
if (!repo) return;
|
|
102
|
+
|
|
103
|
+
for (const profile of nativePolicyProfiles) {
|
|
104
|
+
const existing = await repo.findOne({ filter: { tag: profile.tag } });
|
|
105
|
+
if (!existing) {
|
|
106
|
+
await repo.create({
|
|
107
|
+
values: {
|
|
108
|
+
...profile,
|
|
109
|
+
enabled: true,
|
|
110
|
+
createdAt: new Date(),
|
|
111
|
+
updatedAt: new Date(),
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const currentSettings = asObject(readModelValue(existing, 'settings'));
|
|
118
|
+
const nextSettings = {
|
|
119
|
+
...profile.settings,
|
|
120
|
+
...dropRetiredPolicyKeys(currentSettings),
|
|
121
|
+
};
|
|
122
|
+
await existing.update({
|
|
123
|
+
settings: nextSettings,
|
|
124
|
+
updatedAt: new Date(),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private async ensureAgentMemoryContextKeys() {
|
|
130
|
+
const db = (this as any).db;
|
|
131
|
+
const queryInterface = db.sequelize.getQueryInterface();
|
|
132
|
+
const tableName = `${db.options.tablePrefix || ''}agentMemoryContexts`;
|
|
133
|
+
const tableExists = await queryInterface
|
|
134
|
+
.describeTable(tableName)
|
|
135
|
+
.then(() => true)
|
|
136
|
+
.catch(() => false);
|
|
137
|
+
if (!tableExists) return;
|
|
138
|
+
|
|
139
|
+
const tableDesc = await queryInterface.describeTable(tableName);
|
|
140
|
+
if (!tableDesc.contextKey) {
|
|
141
|
+
await queryInterface.addColumn(tableName, 'contextKey', {
|
|
142
|
+
type: DataTypes.STRING(300),
|
|
143
|
+
allowNull: true,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const repo = db.getRepository('agentMemoryContexts');
|
|
148
|
+
const rows = await repo.find({});
|
|
149
|
+
for (const row of rows) {
|
|
150
|
+
const data = row.toJSON?.() || row;
|
|
151
|
+
if (!normalizeOptionalString(data.scope)) continue;
|
|
152
|
+
const contextKey = normalizeOptionalString(data.contextKey) || buildContextKey(data);
|
|
153
|
+
if (!contextKey) continue;
|
|
154
|
+
if (contextKey !== data.contextKey) {
|
|
155
|
+
await row.update({ contextKey });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
await queryInterface
|
|
160
|
+
.changeColumn(tableName, 'contextKey', {
|
|
161
|
+
type: DataTypes.STRING(300),
|
|
162
|
+
allowNull: false,
|
|
163
|
+
})
|
|
164
|
+
.catch(() => {});
|
|
165
|
+
|
|
166
|
+
await queryInterface
|
|
167
|
+
.addIndex(tableName, ['contextKey'], {
|
|
168
|
+
unique: true,
|
|
169
|
+
name: `${tableName}_contextKey_unique`,
|
|
170
|
+
})
|
|
171
|
+
.catch(() => {});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private async normalizeAIEmployeeToolBindings() {
|
|
175
|
+
const repo = (this as unknown as { db: { getRepository: (name: string) => any } }).db.getRepository('aiEmployees');
|
|
176
|
+
if (!repo) return;
|
|
177
|
+
|
|
178
|
+
const rows = await repo.find({});
|
|
179
|
+
for (const row of rows) {
|
|
180
|
+
const skillSettings = row.get?.('skillSettings') ?? row.skillSettings;
|
|
181
|
+
const normalized = normalizeAIEmployeeSkillSettings(skillSettings);
|
|
182
|
+
if (!normalized.changed) continue;
|
|
183
|
+
await row.update({
|
|
184
|
+
skillSettings: normalized.skillSettings,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async down() {
|
|
190
|
+
// No rollback: these defaults only add native policy keys and normalize
|
|
191
|
+
// context keys required by the current unique constraint.
|
|
192
|
+
}
|
|
193
|
+
}
|