plugin-agent-orchestrator 1.0.13 → 1.0.14
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 +16 -291
- package/dist/client/AIEmployeesContext.d.ts +7 -0
- package/dist/client/OrchestratorSettings.d.ts +2 -1
- package/dist/client/index.js +1 -1
- package/dist/client/plugin.d.ts +1 -0
- package/dist/client/skill-hub/components/ExecutionHistory.d.ts +2 -0
- package/dist/client/skill-hub/components/ExecutionProgress.d.ts +20 -0
- package/dist/client/skill-hub/components/GitSkillImport.d.ts +7 -0
- package/dist/client/skill-hub/components/SkillEditor.d.ts +7 -0
- package/dist/client/skill-hub/components/SkillManager.d.ts +2 -0
- package/dist/client/skill-hub/components/SkillMetrics.d.ts +2 -0
- package/dist/client/skill-hub/components/SkillTestPanel.d.ts +7 -0
- package/dist/client/skill-hub/index.d.ts +10 -0
- package/dist/client/skill-hub/locale.d.ts +3 -0
- package/dist/client/skill-hub/tools/InteractionSchemasProvider.d.ts +19 -0
- package/dist/client/skill-hub/tools/SkillHubCard.d.ts +3 -0
- package/dist/client/skill-hub/utils/jsonFields.d.ts +3 -0
- package/dist/externalVersion.js +6 -6
- package/dist/node_modules/adm-zip/LICENSE +21 -0
- package/dist/node_modules/adm-zip/adm-zip.js +1 -0
- package/dist/node_modules/adm-zip/headers/entryHeader.js +377 -0
- package/dist/node_modules/adm-zip/headers/index.js +2 -0
- package/dist/node_modules/adm-zip/headers/mainHeader.js +130 -0
- package/dist/node_modules/adm-zip/methods/deflater.js +33 -0
- package/dist/node_modules/adm-zip/methods/index.js +3 -0
- package/dist/node_modules/adm-zip/methods/inflater.js +34 -0
- package/dist/node_modules/adm-zip/methods/zipcrypto.js +175 -0
- package/dist/node_modules/adm-zip/package.json +1 -0
- package/dist/node_modules/adm-zip/util/constants.js +142 -0
- package/dist/node_modules/adm-zip/util/decoder.js +5 -0
- package/dist/node_modules/adm-zip/util/errors.js +63 -0
- package/dist/node_modules/adm-zip/util/fattr.js +76 -0
- package/dist/node_modules/adm-zip/util/index.js +5 -0
- package/dist/node_modules/adm-zip/util/utils.js +339 -0
- package/dist/node_modules/adm-zip/zipEntry.js +405 -0
- package/dist/node_modules/adm-zip/zipFile.js +446 -0
- package/dist/node_modules/simple-git/dist/cjs/index.js +7399 -0
- package/dist/node_modules/simple-git/dist/esm/index.js +4745 -0
- package/dist/node_modules/simple-git/dist/esm/package.json +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/api.d.ts +13 -0
- package/dist/node_modules/simple-git/dist/src/lib/args/log-format.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/errors/git-construct-error.d.ts +15 -0
- package/dist/node_modules/simple-git/dist/src/lib/errors/git-error.d.ts +30 -0
- package/dist/node_modules/simple-git/dist/src/lib/errors/git-plugin-error.d.ts +7 -0
- package/dist/node_modules/simple-git/dist/src/lib/errors/git-response-error.d.ts +32 -0
- package/dist/node_modules/simple-git/dist/src/lib/errors/task-configuration-error.d.ts +12 -0
- package/dist/node_modules/simple-git/dist/src/lib/git-factory.d.ts +15 -0
- package/dist/node_modules/simple-git/dist/src/lib/git-logger.d.ts +21 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-branch-delete.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-branch.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-commit.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-diff-summary.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-fetch.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-list-log-summary.d.ts +6 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-merge.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-move.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-pull.d.ts +6 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-push.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-remote-messages.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-remote-objects.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/abort-plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/block-unsafe-operations-plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/command-config-prefixing-plugin.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/completion-detection.plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/custom-binary.plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/error-detection.plugin.d.ts +7 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/index.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/plugin-store.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/progress-monitor-plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/simple-git-plugin.d.ts +48 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/spawn-options-plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/suffix-paths.plugin.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/timout-plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/BranchDeleteSummary.d.ts +12 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/BranchSummary.d.ts +14 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/CheckIgnore.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/CleanSummary.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/ConfigList.d.ts +13 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/DiffSummary.d.ts +10 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/FileStatusSummary.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/GetRemoteSummary.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/InitSummary.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/MergeSummary.d.ts +16 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/PullSummary.d.ts +25 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/StatusSummary.d.ts +19 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/TagList.d.ts +7 -0
- package/dist/node_modules/simple-git/dist/src/lib/runners/git-executor-chain.d.ts +25 -0
- package/dist/node_modules/simple-git/dist/src/lib/runners/git-executor.d.ts +14 -0
- package/dist/node_modules/simple-git/dist/src/lib/runners/promise-wrapped.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/runners/scheduler.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/runners/tasks-pending-queue.d.ts +23 -0
- package/dist/node_modules/simple-git/dist/src/lib/simple-git-api.d.ts +20 -0
- package/dist/node_modules/simple-git/dist/src/lib/task-callback.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/apply-patch.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/branch.d.ts +7 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/change-working-directory.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/check-ignore.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/check-is-repo.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/checkout.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/clean.d.ts +25 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/clone.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/commit.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/config.d.ts +8 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/count-objects.d.ts +12 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/diff-name-status.d.ts +12 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/diff.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/fetch.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/first-commit.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/grep.d.ts +12 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/hash-object.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/init.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/log.d.ts +32 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/merge.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/move.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/pull.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/push.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/remote.d.ts +8 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/reset.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/show.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/stash-list.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/status.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/sub-module.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/tag.d.ts +18 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/task.d.ts +14 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/version.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/types/handlers.d.ts +21 -0
- package/dist/node_modules/simple-git/dist/src/lib/types/index.d.ts +136 -0
- package/dist/node_modules/simple-git/dist/src/lib/types/tasks.d.ts +19 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/argument-filters.d.ts +14 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/exit-codes.d.ts +10 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/git-output-streams.d.ts +7 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/index.d.ts +8 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/line-parser.d.ts +15 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/simple-git-options.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/task-options.d.ts +13 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/task-parser.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/util.d.ts +47 -0
- package/dist/node_modules/simple-git/dist/typings/errors.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/typings/index.d.ts +14 -0
- package/dist/node_modules/simple-git/dist/typings/response.d.ts +556 -0
- package/dist/node_modules/simple-git/dist/typings/simple-git.d.ts +1033 -0
- package/dist/node_modules/simple-git/dist/typings/types.d.ts +22 -0
- package/dist/node_modules/simple-git/node_modules/debug/package.json +64 -0
- package/dist/node_modules/simple-git/node_modules/debug/src/browser.js +272 -0
- package/dist/node_modules/simple-git/node_modules/debug/src/common.js +292 -0
- package/dist/node_modules/simple-git/node_modules/debug/src/index.js +10 -0
- package/dist/node_modules/simple-git/node_modules/debug/src/node.js +263 -0
- package/dist/node_modules/simple-git/package.json +1 -0
- package/dist/node_modules/simple-git/promise.js +17 -0
- package/dist/server/collections/agent-execution-spans.d.ts +9 -0
- package/dist/server/collections/agent-execution-spans.js +152 -0
- package/dist/server/collections/orchestrator-config.js +6 -0
- package/dist/server/collections/skill-definitions.d.ts +3 -0
- package/dist/server/collections/skill-definitions.js +158 -0
- package/dist/server/collections/skill-executions.d.ts +3 -0
- package/dist/server/collections/skill-executions.js +123 -0
- package/dist/server/collections/skill-worker-configs.d.ts +3 -0
- package/dist/server/collections/skill-worker-configs.js +115 -0
- package/dist/server/migrations/20260423000000-add-progress-fields.d.ts +4 -0
- package/dist/server/migrations/20260423000000-add-progress-fields.js +69 -0
- package/dist/server/migrations/20260425000000-add-interaction-schema.d.ts +4 -0
- package/dist/server/migrations/20260425000000-add-interaction-schema.js +61 -0
- package/dist/server/migrations/20260427000000-change-packages-to-text.d.ts +4 -0
- package/dist/server/migrations/20260427000000-change-packages-to-text.js +70 -0
- package/dist/server/migrations/20260427000001-change-other-json-to-text.d.ts +4 -0
- package/dist/server/migrations/20260427000001-change-other-json-to-text.js +80 -0
- package/dist/server/migrations/20260429000000-add-llm-fields.js +8 -0
- package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.d.ts +16 -0
- package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.js +51 -0
- package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.d.ts +7 -0
- package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.js +57 -0
- package/dist/server/plugin.d.ts +3 -0
- package/dist/server/plugin.js +37 -1
- package/dist/server/resources/tracing.js +154 -11
- package/dist/server/services/CodeValidator.d.ts +32 -0
- package/dist/server/services/CodeValidator.js +205 -0
- package/dist/server/services/ExecutionSpanService.d.ts +44 -0
- package/dist/server/services/ExecutionSpanService.js +104 -0
- package/dist/server/services/FileManager.d.ts +28 -0
- package/dist/server/services/FileManager.js +151 -0
- package/dist/server/services/SandboxRunner.d.ts +41 -0
- package/dist/server/services/SandboxRunner.js +167 -0
- package/dist/server/services/SkillManager.d.ts +6 -0
- package/dist/server/services/SkillManager.js +640 -0
- package/dist/server/services/SkillRepositoryService.d.ts +22 -0
- package/dist/server/services/SkillRepositoryService.js +157 -0
- package/dist/server/services/WorkerEnvManager.d.ts +26 -0
- package/dist/server/services/WorkerEnvManager.js +120 -0
- package/dist/server/skill-hub/actions/git-import.d.ts +21 -0
- package/dist/server/skill-hub/actions/git-import.js +413 -0
- package/dist/server/skill-hub/mcp/McpController.d.ts +15 -0
- package/dist/server/skill-hub/mcp/McpController.js +111 -0
- package/dist/server/skill-hub/plugin.d.ts +58 -0
- package/dist/server/skill-hub/plugin.js +694 -0
- package/dist/server/skill-hub/sandbox-config.json +6 -0
- package/dist/server/skill-hub/tasks/SkillExecutionTask.d.ts +14 -0
- package/dist/server/skill-hub/tasks/SkillExecutionTask.js +267 -0
- package/dist/server/skill-hub/utils/json-fields.d.ts +7 -0
- package/dist/server/skill-hub/utils/json-fields.js +88 -0
- package/dist/server/tools/delegate-task.d.ts +4 -0
- package/dist/server/tools/delegate-task.js +606 -104
- package/dist/server/tools/skill-execute.d.ts +36 -0
- package/dist/server/tools/skill-execute.js +167 -0
- package/package.json +3 -1
- package/src/client/AIEmployeeSelect.tsx +1 -3
- package/src/client/AIEmployeesContext.tsx +28 -13
- package/src/client/OrchestratorSettings.tsx +43 -5
- package/src/client/RulesTab.tsx +253 -32
- package/src/client/TracingTab.tsx +277 -213
- package/src/client/plugin.tsx +39 -0
- package/src/client/skill-hub/components/ExecutionHistory.tsx +201 -0
- package/src/client/skill-hub/components/ExecutionProgress.tsx +55 -0
- package/src/client/skill-hub/components/GitSkillImport.tsx +555 -0
- package/src/client/skill-hub/components/SkillEditor.tsx +456 -0
- package/src/client/skill-hub/components/SkillManager.tsx +181 -0
- package/src/client/skill-hub/components/SkillMetrics.tsx +124 -0
- package/src/client/skill-hub/components/SkillTestPanel.tsx +144 -0
- package/src/client/skill-hub/index.tsx +75 -0
- package/src/client/skill-hub/locale.ts +16 -0
- package/src/client/skill-hub/tools/InteractionSchemasProvider.tsx +59 -0
- package/src/client/skill-hub/tools/SkillHubCard.tsx +78 -0
- package/src/client/skill-hub/utils/jsonFields.ts +37 -0
- package/src/server/collections/agent-execution-spans.ts +129 -0
- package/src/server/collections/orchestrator-config.ts +7 -0
- package/src/server/collections/skill-definitions.ts +128 -0
- package/src/server/collections/skill-executions.ts +94 -0
- package/src/server/collections/skill-worker-configs.ts +86 -0
- package/src/server/migrations/20260423000000-add-progress-fields.ts +50 -0
- package/src/server/migrations/20260425000000-add-interaction-schema.ts +35 -0
- package/src/server/migrations/20260427000000-change-packages-to-text.ts +47 -0
- package/src/server/migrations/20260427000001-change-other-json-to-text.ts +57 -0
- package/src/server/migrations/20260429000000-add-llm-fields.ts +9 -0
- package/src/server/migrations/20260429000000-fix-inputargs-json-to-text.ts +38 -0
- package/src/server/migrations/20260503000000-add-orchestrator-trace-fields.ts +32 -0
- package/src/server/plugin.ts +51 -3
- package/src/server/resources/tracing.ts +182 -15
- package/src/server/services/CodeValidator.ts +159 -0
- package/src/server/services/ExecutionSpanService.ts +106 -0
- package/src/server/services/FileManager.ts +144 -0
- package/src/server/services/SandboxRunner.ts +205 -0
- package/src/server/services/SkillManager.ts +623 -0
- package/src/server/services/SkillRepositoryService.ts +142 -0
- package/src/server/services/WorkerEnvManager.ts +113 -0
- package/src/server/skill-hub/actions/git-import.ts +486 -0
- package/src/server/skill-hub/mcp/McpController.ts +86 -0
- package/src/server/skill-hub/plugin.ts +771 -0
- package/src/server/skill-hub/sandbox-config.json +6 -0
- package/src/server/skill-hub/tasks/SkillExecutionTask.ts +297 -0
- package/src/server/skill-hub/utils/json-fields.ts +57 -0
- package/src/server/tools/delegate-task.ts +803 -127
- package/src/server/tools/skill-execute.ts +157 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
|
2
|
+
import { Card, Table, Typography, Space, Row, Col, Statistic, Progress } from 'antd';
|
|
3
|
+
import { SyncOutlined, CheckCircleOutlined, CloseCircleOutlined, ClockCircleOutlined } from '@ant-design/icons';
|
|
4
|
+
import { useAPIClient } from '@nocobase/client';
|
|
5
|
+
import { useT } from '../locale';
|
|
6
|
+
|
|
7
|
+
const { Title, Text } = Typography;
|
|
8
|
+
|
|
9
|
+
export const SkillMetrics: React.FC = () => {
|
|
10
|
+
const api = useAPIClient();
|
|
11
|
+
const t = useT();
|
|
12
|
+
const [executions, setExecutions] = useState<any[]>([]);
|
|
13
|
+
const [loading, setLoading] = useState(false);
|
|
14
|
+
|
|
15
|
+
const fetchExecutions = useCallback(async () => {
|
|
16
|
+
setLoading(true);
|
|
17
|
+
try {
|
|
18
|
+
// Fetch up to 1000 recent executions to calculate basic metrics
|
|
19
|
+
const { data } = await api.request({
|
|
20
|
+
url: 'skillExecutions:list',
|
|
21
|
+
params: {
|
|
22
|
+
pageSize: 1000,
|
|
23
|
+
sort: ['-createdAt'],
|
|
24
|
+
appends: ['skill'],
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
const rawData = data?.data?.data ?? data?.data ?? [];
|
|
28
|
+
setExecutions(Array.isArray(rawData) ? rawData : []);
|
|
29
|
+
} catch {
|
|
30
|
+
// ignore
|
|
31
|
+
} finally {
|
|
32
|
+
setLoading(false);
|
|
33
|
+
}
|
|
34
|
+
}, [api]);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
fetchExecutions();
|
|
38
|
+
}, [fetchExecutions]);
|
|
39
|
+
|
|
40
|
+
const metrics = useMemo(() => {
|
|
41
|
+
const total = executions.length;
|
|
42
|
+
const succeeded = executions.filter((e) => e.status === 'succeeded').length;
|
|
43
|
+
const failed = executions.filter((e) => e.status === 'failed').length;
|
|
44
|
+
const timeout = executions.filter((e) => e.status === 'timeout').length;
|
|
45
|
+
const canceled = executions.filter((e) => e.status === 'canceled').length;
|
|
46
|
+
|
|
47
|
+
// Group by skill
|
|
48
|
+
const bySkill: Record<string, any> = {};
|
|
49
|
+
executions.forEach((e) => {
|
|
50
|
+
const skillName = e.skill?.title || e.skill?.name || 'Unknown';
|
|
51
|
+
if (!bySkill[skillName]) {
|
|
52
|
+
bySkill[skillName] = { name: skillName, total: 0, succeeded: 0, failed: 0, timeout: 0, canceled: 0, totalDuration: 0, durationCount: 0 };
|
|
53
|
+
}
|
|
54
|
+
bySkill[skillName].total += 1;
|
|
55
|
+
bySkill[skillName][e.status] = (bySkill[skillName][e.status] || 0) + 1;
|
|
56
|
+
if (e.durationMs) {
|
|
57
|
+
bySkill[skillName].totalDuration += e.durationMs;
|
|
58
|
+
bySkill[skillName].durationCount += 1;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const skillData = Object.values(bySkill).map((s) => ({
|
|
63
|
+
...s,
|
|
64
|
+
successRate: s.total > 0 ? (s.succeeded / s.total) * 100 : 0,
|
|
65
|
+
avgDuration: s.durationCount > 0 ? (s.totalDuration / s.durationCount / 1000).toFixed(2) : 0,
|
|
66
|
+
})).sort((a: any, b: any) => b.total - a.total);
|
|
67
|
+
|
|
68
|
+
return { total, succeeded, failed, timeout, canceled, skillData };
|
|
69
|
+
}, [executions]);
|
|
70
|
+
|
|
71
|
+
const columns = [
|
|
72
|
+
{ title: t('Skill'), dataIndex: 'name', key: 'name', width: 200 },
|
|
73
|
+
{ title: t('Total Runs'), dataIndex: 'total', key: 'total', width: 100 },
|
|
74
|
+
{
|
|
75
|
+
title: t('Success Rate'),
|
|
76
|
+
dataIndex: 'successRate',
|
|
77
|
+
key: 'successRate',
|
|
78
|
+
width: 150,
|
|
79
|
+
render: (val: number) => <Progress percent={Math.round(val)} size="small" status={val === 100 ? 'success' : val > 50 ? 'active' : 'exception'} />
|
|
80
|
+
},
|
|
81
|
+
{ title: t('Success'), dataIndex: 'succeeded', key: 'succeeded', width: 100 },
|
|
82
|
+
{ title: t('Failed'), dataIndex: 'failed', key: 'failed', width: 100 },
|
|
83
|
+
{ title: t('Timeout'), dataIndex: 'timeout', key: 'timeout', width: 100 },
|
|
84
|
+
{ title: t('Avg Duration (s)'), dataIndex: 'avgDuration', key: 'avgDuration', width: 120 },
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<Space direction="vertical" size="large" style={{ width: '100%', padding: '0 16px' }}>
|
|
89
|
+
<Row gutter={16}>
|
|
90
|
+
<Col span={6}>
|
|
91
|
+
<Card size="small">
|
|
92
|
+
<Statistic title="Total Executions (Recent)" value={metrics.total} prefix={<SyncOutlined />} />
|
|
93
|
+
</Card>
|
|
94
|
+
</Col>
|
|
95
|
+
<Col span={6}>
|
|
96
|
+
<Card size="small">
|
|
97
|
+
<Statistic title="Succeeded" value={metrics.succeeded} valueStyle={{ color: '#3f8600' }} prefix={<CheckCircleOutlined />} />
|
|
98
|
+
</Card>
|
|
99
|
+
</Col>
|
|
100
|
+
<Col span={6}>
|
|
101
|
+
<Card size="small">
|
|
102
|
+
<Statistic title="Failed" value={metrics.failed} valueStyle={{ color: '#cf1322' }} prefix={<CloseCircleOutlined />} />
|
|
103
|
+
</Card>
|
|
104
|
+
</Col>
|
|
105
|
+
<Col span={6}>
|
|
106
|
+
<Card size="small">
|
|
107
|
+
<Statistic title="Timeout/Canceled" value={metrics.timeout + metrics.canceled} valueStyle={{ color: '#faad14' }} prefix={<ClockCircleOutlined />} />
|
|
108
|
+
</Card>
|
|
109
|
+
</Col>
|
|
110
|
+
</Row>
|
|
111
|
+
|
|
112
|
+
<Card title={t('Metrics by Skill (Recent)')}>
|
|
113
|
+
<Table
|
|
114
|
+
dataSource={metrics.skillData}
|
|
115
|
+
columns={columns}
|
|
116
|
+
rowKey="name"
|
|
117
|
+
loading={loading}
|
|
118
|
+
pagination={false}
|
|
119
|
+
size="middle"
|
|
120
|
+
/>
|
|
121
|
+
</Card>
|
|
122
|
+
</Space>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Modal, Input, Button, Alert, Typography, Space, Spin } from 'antd';
|
|
3
|
+
import { useAPIClient, Upload } from '@nocobase/client';
|
|
4
|
+
import { useT } from '../locale';
|
|
5
|
+
import { parseJsonText } from '../utils/jsonFields';
|
|
6
|
+
|
|
7
|
+
const { TextArea } = Input;
|
|
8
|
+
|
|
9
|
+
interface SkillTestPanelProps {
|
|
10
|
+
skill: any;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const SkillTestPanel: React.FC<SkillTestPanelProps> = ({ skill, onClose }) => {
|
|
15
|
+
const api = useAPIClient();
|
|
16
|
+
const t = useT();
|
|
17
|
+
const inputSchema = parseJsonText(skill.inputSchema, null);
|
|
18
|
+
const [input, setInput] = useState(
|
|
19
|
+
inputSchema?.properties
|
|
20
|
+
? JSON.stringify(
|
|
21
|
+
Object.fromEntries(
|
|
22
|
+
Object.keys(inputSchema.properties).map((k) => [k, '']),
|
|
23
|
+
),
|
|
24
|
+
null,
|
|
25
|
+
2,
|
|
26
|
+
)
|
|
27
|
+
: '{}',
|
|
28
|
+
);
|
|
29
|
+
const [running, setRunning] = useState(false);
|
|
30
|
+
const [result, setResult] = useState<any>(null);
|
|
31
|
+
const [error, setError] = useState('');
|
|
32
|
+
|
|
33
|
+
const handleRun = async () => {
|
|
34
|
+
setRunning(true);
|
|
35
|
+
setResult(null);
|
|
36
|
+
setError('');
|
|
37
|
+
|
|
38
|
+
let parsedInput;
|
|
39
|
+
try {
|
|
40
|
+
parsedInput = JSON.parse(input);
|
|
41
|
+
} catch {
|
|
42
|
+
setError(t('Invalid JSON input'));
|
|
43
|
+
setRunning(false);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const { data } = await api.request({
|
|
49
|
+
url: 'skillHub:test',
|
|
50
|
+
method: 'POST',
|
|
51
|
+
data: { skillId: skill.id, input: parsedInput },
|
|
52
|
+
});
|
|
53
|
+
const responseData = data?.data?.data || data?.data || data;
|
|
54
|
+
setResult(responseData);
|
|
55
|
+
} catch (err: any) {
|
|
56
|
+
setError(err?.response?.data?.errors?.[0]?.message || err.message || t('Execution failed'));
|
|
57
|
+
} finally {
|
|
58
|
+
setRunning(false);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Modal
|
|
64
|
+
open
|
|
65
|
+
title={`${t('Test Skill')}: ${skill.title}`}
|
|
66
|
+
onCancel={onClose}
|
|
67
|
+
footer={[
|
|
68
|
+
<Button key="close" onClick={onClose}>
|
|
69
|
+
{t('Close')}
|
|
70
|
+
</Button>,
|
|
71
|
+
<Button key="run" type="primary" onClick={handleRun} loading={running}>
|
|
72
|
+
{t('Run')}
|
|
73
|
+
</Button>,
|
|
74
|
+
]}
|
|
75
|
+
width={640}
|
|
76
|
+
destroyOnClose
|
|
77
|
+
>
|
|
78
|
+
<Space direction="vertical" style={{ width: '100%' }} size="middle">
|
|
79
|
+
<div>
|
|
80
|
+
<Typography.Text strong>{t('Input (JSON)')}</Typography.Text>
|
|
81
|
+
<TextArea
|
|
82
|
+
rows={6}
|
|
83
|
+
value={input}
|
|
84
|
+
onChange={(e) => setInput(e.target.value)}
|
|
85
|
+
style={{ fontFamily: 'monospace', fontSize: 13, marginTop: 4 }}
|
|
86
|
+
/>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
{running && <Spin tip={t('Running skill on worker...')} />}
|
|
90
|
+
|
|
91
|
+
{error && <Alert type="error" message={error} showIcon />}
|
|
92
|
+
|
|
93
|
+
{result && (
|
|
94
|
+
<>
|
|
95
|
+
<Alert
|
|
96
|
+
type={result.status === 'succeeded' ? 'success' : 'error'}
|
|
97
|
+
message={result.status === 'succeeded' ? t('Succeeded') : t('Failed')}
|
|
98
|
+
description={`Duration: ${result.durationMs || 0}ms`}
|
|
99
|
+
showIcon
|
|
100
|
+
/>
|
|
101
|
+
|
|
102
|
+
{result.stdout && (
|
|
103
|
+
<div>
|
|
104
|
+
<Typography.Text strong>stdout:</Typography.Text>
|
|
105
|
+
<pre style={{ background: '#f5f5f5', padding: 8, maxHeight: 200, overflow: 'auto', fontSize: 12 }}>
|
|
106
|
+
{result.stdout}
|
|
107
|
+
</pre>
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
110
|
+
|
|
111
|
+
{result.stderr && (
|
|
112
|
+
<div>
|
|
113
|
+
<Typography.Text strong type="danger">stderr:</Typography.Text>
|
|
114
|
+
<pre style={{ background: '#fff2f0', padding: 8, maxHeight: 200, overflow: 'auto', fontSize: 12 }}>
|
|
115
|
+
{result.stderr}
|
|
116
|
+
</pre>
|
|
117
|
+
</div>
|
|
118
|
+
)}
|
|
119
|
+
|
|
120
|
+
{result.files?.length > 0 && (
|
|
121
|
+
<div>
|
|
122
|
+
<Typography.Text strong>{t('Output Files')}:</Typography.Text>
|
|
123
|
+
<div style={{ marginTop: 8 }}>
|
|
124
|
+
<Upload.ReadPretty
|
|
125
|
+
value={result.files.map((f: any, i: number) => ({
|
|
126
|
+
id: `test-${f.name}-${i}`,
|
|
127
|
+
title: f.name,
|
|
128
|
+
filename: f.name,
|
|
129
|
+
extname: f.name.includes('.') ? `.${f.name.split('.').pop()}` : '',
|
|
130
|
+
url: f.downloadUrl,
|
|
131
|
+
status: 'done'
|
|
132
|
+
}))}
|
|
133
|
+
multiple={true}
|
|
134
|
+
showFileName={true}
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
)}
|
|
139
|
+
</>
|
|
140
|
+
)}
|
|
141
|
+
</Space>
|
|
142
|
+
</Modal>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
@@ -0,0 +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;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useApp } from '@nocobase/client';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
export const namespace = 'plugin-agent-orchestrator';
|
|
4
|
+
|
|
5
|
+
export function useT() {
|
|
6
|
+
const app = useApp();
|
|
7
|
+
return useCallback(
|
|
8
|
+
(str: string, options?: any): string =>
|
|
9
|
+
app.i18n.t(str, { ns: [namespace, 'client'], ...options }) as unknown as string,
|
|
10
|
+
[app.i18n]
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function tStr(key: string) {
|
|
15
|
+
return `{{t(${JSON.stringify(key)}, { ns: ['${namespace}', 'client'], nsMode: 'fallback' })}}`;
|
|
16
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React, { createContext, useContext, useEffect, useState } from 'react';
|
|
2
|
+
import { useAPIClient } from '@nocobase/client';
|
|
3
|
+
import { parseJsonText } from '../utils/jsonFields';
|
|
4
|
+
|
|
5
|
+
export type InteractionSchema = {
|
|
6
|
+
type: 'form' | 'select' | 'confirm';
|
|
7
|
+
prompt: string;
|
|
8
|
+
options?: { label: string; value: string | number }[];
|
|
9
|
+
fields?: Record<string, { type?: string; title?: string; required?: boolean; enum?: any[] }>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const Ctx = createContext<Map<string, InteractionSchema>>(new Map());
|
|
13
|
+
|
|
14
|
+
export const useInteractionSchemas = () => useContext(Ctx);
|
|
15
|
+
|
|
16
|
+
const sanitize = (name: string) =>
|
|
17
|
+
name
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/[^a-z0-9_]/g, '_')
|
|
20
|
+
.replace(/_+/g, '_')
|
|
21
|
+
.replace(/^_|_$/g, '');
|
|
22
|
+
|
|
23
|
+
export const InteractionSchemasProvider: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
|
|
24
|
+
const api = useAPIClient();
|
|
25
|
+
const [map, setMap] = useState<Map<string, InteractionSchema>>(new Map());
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
let cancelled = false;
|
|
29
|
+
api
|
|
30
|
+
.request({
|
|
31
|
+
url: 'skillDefinitions:list',
|
|
32
|
+
params: {
|
|
33
|
+
filter: { enabled: true },
|
|
34
|
+
fields: ['name', 'autoCall', 'interactionSchema'],
|
|
35
|
+
pageSize: 200,
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
.then(({ data }) => {
|
|
39
|
+
if (cancelled) return;
|
|
40
|
+
const next = new Map<string, InteractionSchema>();
|
|
41
|
+
const list = data?.data ?? [];
|
|
42
|
+
for (const s of list) {
|
|
43
|
+
if (s.autoCall) continue;
|
|
44
|
+
const schema = parseJsonText<InteractionSchema | null>(s.interactionSchema, null);
|
|
45
|
+
if (!schema) continue;
|
|
46
|
+
next.set(sanitize(s.name), schema);
|
|
47
|
+
}
|
|
48
|
+
setMap(next);
|
|
49
|
+
})
|
|
50
|
+
.catch(() => {
|
|
51
|
+
// silently ignore — user may lack permission to list definitions
|
|
52
|
+
});
|
|
53
|
+
return () => {
|
|
54
|
+
cancelled = true;
|
|
55
|
+
};
|
|
56
|
+
}, [api]);
|
|
57
|
+
|
|
58
|
+
return <Ctx.Provider value={map}>{children}</Ctx.Provider>;
|
|
59
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Form, Input, Select, Radio, InputNumber, Button, Space, Card, Typography } from 'antd';
|
|
3
|
+
import { ToolsUIProperties } from '@nocobase/client';
|
|
4
|
+
import { useInteractionSchemas } from './InteractionSchemasProvider';
|
|
5
|
+
|
|
6
|
+
export const SkillHubCard: React.FC<ToolsUIProperties> = ({ toolCall, decisions }) => {
|
|
7
|
+
const schemas = useInteractionSchemas();
|
|
8
|
+
const [form] = Form.useForm();
|
|
9
|
+
|
|
10
|
+
const skillKey = toolCall.name.replace(/^skill_hub_/, '');
|
|
11
|
+
const schema = schemas.get(skillKey);
|
|
12
|
+
|
|
13
|
+
const interrupted = toolCall.invokeStatus === 'init' || toolCall.invokeStatus === 'interrupted';
|
|
14
|
+
if (!schema || !interrupted) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const onSubmit = async () => {
|
|
19
|
+
const values = await form.validateFields();
|
|
20
|
+
const args = schema.type === 'select' ? values : { ...(toolCall.args as any), ...values };
|
|
21
|
+
await decisions.edit(args);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const renderField = (key: string, f: any) => {
|
|
25
|
+
if (f?.enum) {
|
|
26
|
+
return <Select options={f.enum.map((v: any) => ({ value: v, label: String(v) }))} />;
|
|
27
|
+
}
|
|
28
|
+
if (f?.type === 'number' || f?.type === 'integer') {
|
|
29
|
+
return <InputNumber style={{ width: '100%' }} />;
|
|
30
|
+
}
|
|
31
|
+
return <Input />;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Card size="small" style={{ marginTop: 8 }}>
|
|
36
|
+
<Typography.Paragraph style={{ marginBottom: 12 }}>{schema.prompt}</Typography.Paragraph>
|
|
37
|
+
|
|
38
|
+
{schema.type !== 'confirm' && (
|
|
39
|
+
<Form
|
|
40
|
+
form={form}
|
|
41
|
+
layout="vertical"
|
|
42
|
+
initialValues={(toolCall.args as Record<string, any>) || {}}
|
|
43
|
+
style={{ marginBottom: 8 }}
|
|
44
|
+
>
|
|
45
|
+
{schema.type === 'select' && (
|
|
46
|
+
<Form.Item name="choice" rules={[{ required: true }]}>
|
|
47
|
+
<Radio.Group>
|
|
48
|
+
{(schema.options ?? []).map((o) => (
|
|
49
|
+
<Radio key={String(o.value)} value={o.value}>
|
|
50
|
+
{o.label}
|
|
51
|
+
</Radio>
|
|
52
|
+
))}
|
|
53
|
+
</Radio.Group>
|
|
54
|
+
</Form.Item>
|
|
55
|
+
)}
|
|
56
|
+
{schema.type === 'form' &&
|
|
57
|
+
Object.entries(schema.fields ?? {}).map(([key, f]) => (
|
|
58
|
+
<Form.Item
|
|
59
|
+
key={key}
|
|
60
|
+
name={key}
|
|
61
|
+
label={f.title || key}
|
|
62
|
+
rules={[{ required: !!f.required }]}
|
|
63
|
+
>
|
|
64
|
+
{renderField(key, f)}
|
|
65
|
+
</Form.Item>
|
|
66
|
+
))}
|
|
67
|
+
</Form>
|
|
68
|
+
)}
|
|
69
|
+
|
|
70
|
+
<Space>
|
|
71
|
+
<Button type="primary" onClick={schema.type === 'confirm' ? () => decisions.approve() : onSubmit}>
|
|
72
|
+
Run
|
|
73
|
+
</Button>
|
|
74
|
+
<Button onClick={() => decisions.reject('user_cancel')}>Cancel</Button>
|
|
75
|
+
</Space>
|
|
76
|
+
</Card>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function parseJsonText<T = any>(value: any, fallback: T): T {
|
|
2
|
+
if (value === undefined || value === null || value === '') return fallback;
|
|
3
|
+
if (typeof value !== 'string') return value;
|
|
4
|
+
|
|
5
|
+
const trimmed = value.trim();
|
|
6
|
+
const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
7
|
+
const json = fenced ? fenced[1].trim() : trimmed;
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
let parsed = JSON.parse(json);
|
|
11
|
+
if (typeof parsed === 'string') {
|
|
12
|
+
const innerTrimmed = parsed.trim();
|
|
13
|
+
const innerFenced = innerTrimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
14
|
+
const innerJson = innerFenced ? innerFenced[1].trim() : innerTrimmed;
|
|
15
|
+
try {
|
|
16
|
+
parsed = JSON.parse(innerJson);
|
|
17
|
+
} catch {}
|
|
18
|
+
}
|
|
19
|
+
return parsed;
|
|
20
|
+
} catch {
|
|
21
|
+
return fallback;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function formatJsonText(value: any, fallback: any = null): string {
|
|
26
|
+
const parsed = parseJsonText(value, undefined);
|
|
27
|
+
const normalized = parsed === undefined ? (value === undefined || value === null || value === '' ? fallback : value) : parsed;
|
|
28
|
+
if (normalized === undefined || normalized === null) return '';
|
|
29
|
+
if (typeof normalized === 'string') return normalized;
|
|
30
|
+
return JSON.stringify(normalized, null, 2);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function stringifyJsonText(value: any, fallback: any = null): string {
|
|
34
|
+
const parsed = parseJsonText(value, undefined);
|
|
35
|
+
const normalized = parsed === undefined ? (value === undefined || value === null || value === '' ? fallback : value) : parsed;
|
|
36
|
+
return `\`\`\`json\n${JSON.stringify(normalized, null, 2)}\n\`\`\``;
|
|
37
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { defineCollection } from '@nocobase/database';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Unified execution graph for agent orchestration.
|
|
5
|
+
*
|
|
6
|
+
* A root run can contain sub-agent spans and child tool/skill spans. Skill Hub
|
|
7
|
+
* keeps its own sandbox execution records; this collection stores the flow
|
|
8
|
+
* relationship and links to those records when applicable.
|
|
9
|
+
*/
|
|
10
|
+
export default defineCollection({
|
|
11
|
+
name: 'agentExecutionSpans',
|
|
12
|
+
title: 'Agent Execution Spans',
|
|
13
|
+
fields: [
|
|
14
|
+
{
|
|
15
|
+
name: 'id',
|
|
16
|
+
type: 'bigInt',
|
|
17
|
+
autoIncrement: true,
|
|
18
|
+
primaryKey: true,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'rootRunId',
|
|
22
|
+
type: 'string',
|
|
23
|
+
length: 100,
|
|
24
|
+
allowNull: false,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'parentSpanId',
|
|
28
|
+
type: 'string',
|
|
29
|
+
length: 100,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'type',
|
|
33
|
+
type: 'string',
|
|
34
|
+
length: 30,
|
|
35
|
+
comment: 'sub_agent, tool, skill, dispatch',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'status',
|
|
39
|
+
type: 'string',
|
|
40
|
+
length: 20,
|
|
41
|
+
comment: 'running, success, error, canceled, timeout',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'leaderUsername',
|
|
45
|
+
type: 'string',
|
|
46
|
+
length: 100,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'employeeUsername',
|
|
50
|
+
type: 'string',
|
|
51
|
+
length: 100,
|
|
52
|
+
comment: 'The AI Employee currently executing this span',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'toolName',
|
|
56
|
+
type: 'string',
|
|
57
|
+
length: 200,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'title',
|
|
61
|
+
type: 'string',
|
|
62
|
+
length: 500,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'input',
|
|
66
|
+
type: 'json',
|
|
67
|
+
defaultValue: {},
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'output',
|
|
71
|
+
type: 'text',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'error',
|
|
75
|
+
type: 'text',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'durationMs',
|
|
79
|
+
type: 'integer',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'startedAt',
|
|
83
|
+
type: 'date',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'endedAt',
|
|
87
|
+
type: 'date',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'orchestratorLogId',
|
|
91
|
+
type: 'bigInt',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'skillExecutionId',
|
|
95
|
+
type: 'bigInt',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: 'metadata',
|
|
99
|
+
type: 'json',
|
|
100
|
+
defaultValue: {},
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'userId',
|
|
104
|
+
type: 'bigInt',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'createdAt',
|
|
108
|
+
type: 'date',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'updatedAt',
|
|
112
|
+
type: 'date',
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
indexes: [
|
|
116
|
+
{
|
|
117
|
+
fields: ['rootRunId'],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
fields: ['parentSpanId'],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
fields: ['type'],
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
fields: ['status'],
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
});
|
|
@@ -39,6 +39,13 @@ export default defineCollection({
|
|
|
39
39
|
defaultValue: 120000,
|
|
40
40
|
comment: 'Timeout in ms for sub-agent execution',
|
|
41
41
|
},
|
|
42
|
+
{
|
|
43
|
+
name: 'recursionLimit',
|
|
44
|
+
type: 'integer',
|
|
45
|
+
defaultValue: 50,
|
|
46
|
+
comment:
|
|
47
|
+
'Max LangGraph reasoning steps (tool-call + LLM-step iterations) per delegation. Lower = safer; higher = more complex multi-step tasks. Default 50.',
|
|
48
|
+
},
|
|
42
49
|
{
|
|
43
50
|
name: 'llmService',
|
|
44
51
|
type: 'string',
|