plugin-agent-orchestrator 1.0.6 → 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.
Files changed (257) hide show
  1. package/README.md +16 -291
  2. package/dist/client/AIEmployeesContext.d.ts +7 -0
  3. package/dist/client/OrchestratorSettings.d.ts +2 -1
  4. package/dist/client/index.js +1 -1
  5. package/dist/client/plugin.d.ts +1 -0
  6. package/dist/client/skill-hub/components/ExecutionHistory.d.ts +2 -0
  7. package/dist/client/skill-hub/components/ExecutionProgress.d.ts +20 -0
  8. package/dist/client/skill-hub/components/GitSkillImport.d.ts +7 -0
  9. package/dist/client/skill-hub/components/SkillEditor.d.ts +7 -0
  10. package/dist/client/skill-hub/components/SkillManager.d.ts +2 -0
  11. package/dist/client/skill-hub/components/SkillMetrics.d.ts +2 -0
  12. package/dist/client/skill-hub/components/SkillTestPanel.d.ts +7 -0
  13. package/dist/client/skill-hub/index.d.ts +10 -0
  14. package/dist/client/skill-hub/locale.d.ts +3 -0
  15. package/dist/client/skill-hub/tools/InteractionSchemasProvider.d.ts +19 -0
  16. package/dist/client/skill-hub/tools/SkillHubCard.d.ts +3 -0
  17. package/dist/client/skill-hub/utils/jsonFields.d.ts +3 -0
  18. package/dist/externalVersion.js +6 -6
  19. package/dist/node_modules/adm-zip/LICENSE +21 -0
  20. package/dist/node_modules/adm-zip/adm-zip.js +1 -0
  21. package/dist/node_modules/adm-zip/headers/entryHeader.js +377 -0
  22. package/dist/node_modules/adm-zip/headers/index.js +2 -0
  23. package/dist/node_modules/adm-zip/headers/mainHeader.js +130 -0
  24. package/dist/node_modules/adm-zip/methods/deflater.js +33 -0
  25. package/dist/node_modules/adm-zip/methods/index.js +3 -0
  26. package/dist/node_modules/adm-zip/methods/inflater.js +34 -0
  27. package/dist/node_modules/adm-zip/methods/zipcrypto.js +175 -0
  28. package/dist/node_modules/adm-zip/package.json +1 -0
  29. package/dist/node_modules/adm-zip/util/constants.js +142 -0
  30. package/dist/node_modules/adm-zip/util/decoder.js +5 -0
  31. package/dist/node_modules/adm-zip/util/errors.js +63 -0
  32. package/dist/node_modules/adm-zip/util/fattr.js +76 -0
  33. package/dist/node_modules/adm-zip/util/index.js +5 -0
  34. package/dist/node_modules/adm-zip/util/utils.js +339 -0
  35. package/dist/node_modules/adm-zip/zipEntry.js +405 -0
  36. package/dist/node_modules/adm-zip/zipFile.js +446 -0
  37. package/dist/node_modules/simple-git/dist/cjs/index.js +7399 -0
  38. package/dist/node_modules/simple-git/dist/esm/index.js +4745 -0
  39. package/dist/node_modules/simple-git/dist/esm/package.json +3 -0
  40. package/dist/node_modules/simple-git/dist/src/lib/api.d.ts +13 -0
  41. package/dist/node_modules/simple-git/dist/src/lib/args/log-format.d.ts +9 -0
  42. package/dist/node_modules/simple-git/dist/src/lib/errors/git-construct-error.d.ts +15 -0
  43. package/dist/node_modules/simple-git/dist/src/lib/errors/git-error.d.ts +30 -0
  44. package/dist/node_modules/simple-git/dist/src/lib/errors/git-plugin-error.d.ts +7 -0
  45. package/dist/node_modules/simple-git/dist/src/lib/errors/git-response-error.d.ts +32 -0
  46. package/dist/node_modules/simple-git/dist/src/lib/errors/task-configuration-error.d.ts +12 -0
  47. package/dist/node_modules/simple-git/dist/src/lib/git-factory.d.ts +15 -0
  48. package/dist/node_modules/simple-git/dist/src/lib/git-logger.d.ts +21 -0
  49. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-branch-delete.d.ts +5 -0
  50. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-branch.d.ts +2 -0
  51. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-commit.d.ts +2 -0
  52. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-diff-summary.d.ts +3 -0
  53. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-fetch.d.ts +2 -0
  54. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-list-log-summary.d.ts +6 -0
  55. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-merge.d.ts +11 -0
  56. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-move.d.ts +2 -0
  57. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-pull.d.ts +6 -0
  58. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-push.d.ts +4 -0
  59. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-remote-messages.d.ts +5 -0
  60. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-remote-objects.d.ts +3 -0
  61. package/dist/node_modules/simple-git/dist/src/lib/plugins/abort-plugin.d.ts +3 -0
  62. package/dist/node_modules/simple-git/dist/src/lib/plugins/block-unsafe-operations-plugin.d.ts +3 -0
  63. package/dist/node_modules/simple-git/dist/src/lib/plugins/command-config-prefixing-plugin.d.ts +2 -0
  64. package/dist/node_modules/simple-git/dist/src/lib/plugins/completion-detection.plugin.d.ts +3 -0
  65. package/dist/node_modules/simple-git/dist/src/lib/plugins/custom-binary.plugin.d.ts +3 -0
  66. package/dist/node_modules/simple-git/dist/src/lib/plugins/error-detection.plugin.d.ts +7 -0
  67. package/dist/node_modules/simple-git/dist/src/lib/plugins/index.d.ts +11 -0
  68. package/dist/node_modules/simple-git/dist/src/lib/plugins/plugin-store.d.ts +11 -0
  69. package/dist/node_modules/simple-git/dist/src/lib/plugins/progress-monitor-plugin.d.ts +3 -0
  70. package/dist/node_modules/simple-git/dist/src/lib/plugins/simple-git-plugin.d.ts +48 -0
  71. package/dist/node_modules/simple-git/dist/src/lib/plugins/spawn-options-plugin.d.ts +3 -0
  72. package/dist/node_modules/simple-git/dist/src/lib/plugins/suffix-paths.plugin.d.ts +2 -0
  73. package/dist/node_modules/simple-git/dist/src/lib/plugins/timout-plugin.d.ts +3 -0
  74. package/dist/node_modules/simple-git/dist/src/lib/responses/BranchDeleteSummary.d.ts +12 -0
  75. package/dist/node_modules/simple-git/dist/src/lib/responses/BranchSummary.d.ts +14 -0
  76. package/dist/node_modules/simple-git/dist/src/lib/responses/CheckIgnore.d.ts +4 -0
  77. package/dist/node_modules/simple-git/dist/src/lib/responses/CleanSummary.d.ts +9 -0
  78. package/dist/node_modules/simple-git/dist/src/lib/responses/ConfigList.d.ts +13 -0
  79. package/dist/node_modules/simple-git/dist/src/lib/responses/DiffSummary.d.ts +10 -0
  80. package/dist/node_modules/simple-git/dist/src/lib/responses/FileStatusSummary.d.ts +9 -0
  81. package/dist/node_modules/simple-git/dist/src/lib/responses/GetRemoteSummary.d.ts +11 -0
  82. package/dist/node_modules/simple-git/dist/src/lib/responses/InitSummary.d.ts +9 -0
  83. package/dist/node_modules/simple-git/dist/src/lib/responses/MergeSummary.d.ts +16 -0
  84. package/dist/node_modules/simple-git/dist/src/lib/responses/PullSummary.d.ts +25 -0
  85. package/dist/node_modules/simple-git/dist/src/lib/responses/StatusSummary.d.ts +19 -0
  86. package/dist/node_modules/simple-git/dist/src/lib/responses/TagList.d.ts +7 -0
  87. package/dist/node_modules/simple-git/dist/src/lib/runners/git-executor-chain.d.ts +25 -0
  88. package/dist/node_modules/simple-git/dist/src/lib/runners/git-executor.d.ts +14 -0
  89. package/dist/node_modules/simple-git/dist/src/lib/runners/promise-wrapped.d.ts +2 -0
  90. package/dist/node_modules/simple-git/dist/src/lib/runners/scheduler.d.ts +11 -0
  91. package/dist/node_modules/simple-git/dist/src/lib/runners/tasks-pending-queue.d.ts +23 -0
  92. package/dist/node_modules/simple-git/dist/src/lib/simple-git-api.d.ts +20 -0
  93. package/dist/node_modules/simple-git/dist/src/lib/task-callback.d.ts +2 -0
  94. package/dist/node_modules/simple-git/dist/src/lib/tasks/apply-patch.d.ts +3 -0
  95. package/dist/node_modules/simple-git/dist/src/lib/tasks/branch.d.ts +7 -0
  96. package/dist/node_modules/simple-git/dist/src/lib/tasks/change-working-directory.d.ts +2 -0
  97. package/dist/node_modules/simple-git/dist/src/lib/tasks/check-ignore.d.ts +2 -0
  98. package/dist/node_modules/simple-git/dist/src/lib/tasks/check-is-repo.d.ts +9 -0
  99. package/dist/node_modules/simple-git/dist/src/lib/tasks/checkout.d.ts +2 -0
  100. package/dist/node_modules/simple-git/dist/src/lib/tasks/clean.d.ts +25 -0
  101. package/dist/node_modules/simple-git/dist/src/lib/tasks/clone.d.ts +9 -0
  102. package/dist/node_modules/simple-git/dist/src/lib/tasks/commit.d.ts +4 -0
  103. package/dist/node_modules/simple-git/dist/src/lib/tasks/config.d.ts +8 -0
  104. package/dist/node_modules/simple-git/dist/src/lib/tasks/count-objects.d.ts +12 -0
  105. package/dist/node_modules/simple-git/dist/src/lib/tasks/diff-name-status.d.ts +12 -0
  106. package/dist/node_modules/simple-git/dist/src/lib/tasks/diff.d.ts +5 -0
  107. package/dist/node_modules/simple-git/dist/src/lib/tasks/fetch.d.ts +4 -0
  108. package/dist/node_modules/simple-git/dist/src/lib/tasks/first-commit.d.ts +2 -0
  109. package/dist/node_modules/simple-git/dist/src/lib/tasks/grep.d.ts +12 -0
  110. package/dist/node_modules/simple-git/dist/src/lib/tasks/hash-object.d.ts +5 -0
  111. package/dist/node_modules/simple-git/dist/src/lib/tasks/init.d.ts +3 -0
  112. package/dist/node_modules/simple-git/dist/src/lib/tasks/log.d.ts +32 -0
  113. package/dist/node_modules/simple-git/dist/src/lib/tasks/merge.d.ts +4 -0
  114. package/dist/node_modules/simple-git/dist/src/lib/tasks/move.d.ts +3 -0
  115. package/dist/node_modules/simple-git/dist/src/lib/tasks/pull.d.ts +3 -0
  116. package/dist/node_modules/simple-git/dist/src/lib/tasks/push.d.ts +9 -0
  117. package/dist/node_modules/simple-git/dist/src/lib/tasks/remote.d.ts +8 -0
  118. package/dist/node_modules/simple-git/dist/src/lib/tasks/reset.d.ts +11 -0
  119. package/dist/node_modules/simple-git/dist/src/lib/tasks/show.d.ts +2 -0
  120. package/dist/node_modules/simple-git/dist/src/lib/tasks/stash-list.d.ts +4 -0
  121. package/dist/node_modules/simple-git/dist/src/lib/tasks/status.d.ts +3 -0
  122. package/dist/node_modules/simple-git/dist/src/lib/tasks/sub-module.d.ts +5 -0
  123. package/dist/node_modules/simple-git/dist/src/lib/tasks/tag.d.ts +18 -0
  124. package/dist/node_modules/simple-git/dist/src/lib/tasks/task.d.ts +14 -0
  125. package/dist/node_modules/simple-git/dist/src/lib/tasks/version.d.ts +9 -0
  126. package/dist/node_modules/simple-git/dist/src/lib/types/handlers.d.ts +21 -0
  127. package/dist/node_modules/simple-git/dist/src/lib/types/index.d.ts +136 -0
  128. package/dist/node_modules/simple-git/dist/src/lib/types/tasks.d.ts +19 -0
  129. package/dist/node_modules/simple-git/dist/src/lib/utils/argument-filters.d.ts +14 -0
  130. package/dist/node_modules/simple-git/dist/src/lib/utils/exit-codes.d.ts +10 -0
  131. package/dist/node_modules/simple-git/dist/src/lib/utils/git-output-streams.d.ts +7 -0
  132. package/dist/node_modules/simple-git/dist/src/lib/utils/index.d.ts +8 -0
  133. package/dist/node_modules/simple-git/dist/src/lib/utils/line-parser.d.ts +15 -0
  134. package/dist/node_modules/simple-git/dist/src/lib/utils/simple-git-options.d.ts +2 -0
  135. package/dist/node_modules/simple-git/dist/src/lib/utils/task-options.d.ts +13 -0
  136. package/dist/node_modules/simple-git/dist/src/lib/utils/task-parser.d.ts +5 -0
  137. package/dist/node_modules/simple-git/dist/src/lib/utils/util.d.ts +47 -0
  138. package/dist/node_modules/simple-git/dist/typings/errors.d.ts +5 -0
  139. package/dist/node_modules/simple-git/dist/typings/index.d.ts +14 -0
  140. package/dist/node_modules/simple-git/dist/typings/response.d.ts +556 -0
  141. package/dist/node_modules/simple-git/dist/typings/simple-git.d.ts +1033 -0
  142. package/dist/node_modules/simple-git/dist/typings/types.d.ts +22 -0
  143. package/dist/node_modules/simple-git/node_modules/debug/package.json +64 -0
  144. package/dist/node_modules/simple-git/node_modules/debug/src/browser.js +272 -0
  145. package/dist/node_modules/simple-git/node_modules/debug/src/common.js +292 -0
  146. package/dist/node_modules/simple-git/node_modules/debug/src/index.js +10 -0
  147. package/dist/node_modules/simple-git/node_modules/debug/src/node.js +263 -0
  148. package/dist/node_modules/simple-git/package.json +1 -0
  149. package/dist/node_modules/simple-git/promise.js +17 -0
  150. package/dist/server/collections/agent-execution-spans.d.ts +9 -0
  151. package/dist/server/collections/agent-execution-spans.js +152 -0
  152. package/dist/server/collections/orchestrator-config.js +16 -0
  153. package/dist/server/collections/orchestrator-logs.js +19 -2
  154. package/dist/server/collections/skill-definitions.d.ts +3 -0
  155. package/dist/server/collections/skill-definitions.js +158 -0
  156. package/dist/server/collections/skill-executions.d.ts +3 -0
  157. package/dist/server/collections/skill-executions.js +123 -0
  158. package/dist/server/collections/skill-worker-configs.d.ts +3 -0
  159. package/dist/server/collections/skill-worker-configs.js +115 -0
  160. package/dist/server/migrations/20260423000000-add-progress-fields.d.ts +4 -0
  161. package/dist/server/migrations/20260423000000-add-progress-fields.js +69 -0
  162. package/dist/server/migrations/20260425000000-add-interaction-schema.d.ts +4 -0
  163. package/dist/server/migrations/20260425000000-add-interaction-schema.js +61 -0
  164. package/dist/server/migrations/20260427000000-add-tracing-detail-fields.d.ts +7 -0
  165. package/dist/server/migrations/20260427000000-add-tracing-detail-fields.js +62 -0
  166. package/dist/server/migrations/20260427000000-change-packages-to-text.d.ts +4 -0
  167. package/dist/server/migrations/20260427000000-change-packages-to-text.js +70 -0
  168. package/dist/server/migrations/20260427000001-change-other-json-to-text.d.ts +4 -0
  169. package/dist/server/migrations/20260427000001-change-other-json-to-text.js +80 -0
  170. package/dist/server/migrations/20260429000000-add-llm-fields.d.ts +7 -0
  171. package/dist/server/migrations/20260429000000-add-llm-fields.js +68 -0
  172. package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.d.ts +16 -0
  173. package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.js +51 -0
  174. package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.d.ts +7 -0
  175. package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.js +57 -0
  176. package/dist/server/plugin.d.ts +3 -0
  177. package/dist/server/plugin.js +37 -1
  178. package/dist/server/resources/tracing.js +160 -12
  179. package/dist/server/services/CodeValidator.d.ts +32 -0
  180. package/dist/server/services/CodeValidator.js +205 -0
  181. package/dist/server/services/ExecutionSpanService.d.ts +44 -0
  182. package/dist/server/services/ExecutionSpanService.js +104 -0
  183. package/dist/server/services/FileManager.d.ts +28 -0
  184. package/dist/server/services/FileManager.js +151 -0
  185. package/dist/server/services/SandboxRunner.d.ts +41 -0
  186. package/dist/server/services/SandboxRunner.js +167 -0
  187. package/dist/server/services/SkillManager.d.ts +6 -0
  188. package/dist/server/services/SkillManager.js +640 -0
  189. package/dist/server/services/SkillRepositoryService.d.ts +22 -0
  190. package/dist/server/services/SkillRepositoryService.js +157 -0
  191. package/dist/server/services/WorkerEnvManager.d.ts +26 -0
  192. package/dist/server/services/WorkerEnvManager.js +120 -0
  193. package/dist/server/skill-hub/actions/git-import.d.ts +21 -0
  194. package/dist/server/skill-hub/actions/git-import.js +413 -0
  195. package/dist/server/skill-hub/mcp/McpController.d.ts +15 -0
  196. package/dist/server/skill-hub/mcp/McpController.js +111 -0
  197. package/dist/server/skill-hub/plugin.d.ts +58 -0
  198. package/dist/server/skill-hub/plugin.js +694 -0
  199. package/dist/server/skill-hub/sandbox-config.json +6 -0
  200. package/dist/server/skill-hub/tasks/SkillExecutionTask.d.ts +14 -0
  201. package/dist/server/skill-hub/tasks/SkillExecutionTask.js +267 -0
  202. package/dist/server/skill-hub/utils/json-fields.d.ts +7 -0
  203. package/dist/server/skill-hub/utils/json-fields.js +88 -0
  204. package/dist/server/tools/delegate-task.d.ts +4 -0
  205. package/dist/server/tools/delegate-task.js +832 -119
  206. package/dist/server/tools/skill-execute.d.ts +36 -0
  207. package/dist/server/tools/skill-execute.js +167 -0
  208. package/package.json +3 -1
  209. package/src/client/AIEmployeeSelect.tsx +1 -3
  210. package/src/client/AIEmployeesContext.tsx +28 -13
  211. package/src/client/OrchestratorSettings.tsx +43 -5
  212. package/src/client/RulesTab.tsx +368 -21
  213. package/src/client/TracingTab.tsx +316 -102
  214. package/src/client/plugin.tsx +39 -0
  215. package/src/client/skill-hub/components/ExecutionHistory.tsx +201 -0
  216. package/src/client/skill-hub/components/ExecutionProgress.tsx +55 -0
  217. package/src/client/skill-hub/components/GitSkillImport.tsx +555 -0
  218. package/src/client/skill-hub/components/SkillEditor.tsx +456 -0
  219. package/src/client/skill-hub/components/SkillManager.tsx +181 -0
  220. package/src/client/skill-hub/components/SkillMetrics.tsx +124 -0
  221. package/src/client/skill-hub/components/SkillTestPanel.tsx +144 -0
  222. package/src/client/skill-hub/index.tsx +75 -0
  223. package/src/client/skill-hub/locale.ts +16 -0
  224. package/src/client/skill-hub/tools/InteractionSchemasProvider.tsx +59 -0
  225. package/src/client/skill-hub/tools/SkillHubCard.tsx +78 -0
  226. package/src/client/skill-hub/utils/jsonFields.ts +37 -0
  227. package/src/server/collections/agent-execution-spans.ts +129 -0
  228. package/src/server/collections/orchestrator-config.ts +17 -0
  229. package/src/server/collections/orchestrator-logs.ts +19 -2
  230. package/src/server/collections/skill-definitions.ts +128 -0
  231. package/src/server/collections/skill-executions.ts +94 -0
  232. package/src/server/collections/skill-worker-configs.ts +86 -0
  233. package/src/server/migrations/20260423000000-add-progress-fields.ts +50 -0
  234. package/src/server/migrations/20260425000000-add-interaction-schema.ts +35 -0
  235. package/src/server/migrations/20260427000000-add-tracing-detail-fields.ts +41 -0
  236. package/src/server/migrations/20260427000000-change-packages-to-text.ts +47 -0
  237. package/src/server/migrations/20260427000001-change-other-json-to-text.ts +57 -0
  238. package/src/server/migrations/20260429000000-add-llm-fields.ts +46 -0
  239. package/src/server/migrations/20260429000000-fix-inputargs-json-to-text.ts +38 -0
  240. package/src/server/migrations/20260503000000-add-orchestrator-trace-fields.ts +32 -0
  241. package/src/server/plugin.ts +51 -3
  242. package/src/server/resources/tracing.ts +187 -16
  243. package/src/server/services/CodeValidator.ts +159 -0
  244. package/src/server/services/ExecutionSpanService.ts +106 -0
  245. package/src/server/services/FileManager.ts +144 -0
  246. package/src/server/services/SandboxRunner.ts +205 -0
  247. package/src/server/services/SkillManager.ts +623 -0
  248. package/src/server/services/SkillRepositoryService.ts +142 -0
  249. package/src/server/services/WorkerEnvManager.ts +113 -0
  250. package/src/server/skill-hub/actions/git-import.ts +486 -0
  251. package/src/server/skill-hub/mcp/McpController.ts +86 -0
  252. package/src/server/skill-hub/plugin.ts +771 -0
  253. package/src/server/skill-hub/sandbox-config.json +6 -0
  254. package/src/server/skill-hub/tasks/SkillExecutionTask.ts +297 -0
  255. package/src/server/skill-hub/utils/json-fields.ts +57 -0
  256. package/src/server/tools/delegate-task.ts +1085 -147
  257. package/src/server/tools/skill-execute.ts +157 -0
@@ -13,14 +13,34 @@ import {
13
13
  Tag,
14
14
  Typography,
15
15
  Alert,
16
+ Collapse,
17
+ Empty,
18
+ Select,
16
19
  } from 'antd';
17
- import { PlusOutlined, EditOutlined, DeleteOutlined, SwapRightOutlined } from '@ant-design/icons';
20
+ import {
21
+ PlusOutlined,
22
+ EditOutlined,
23
+ DeleteOutlined,
24
+ SwapRightOutlined,
25
+ WarningOutlined,
26
+ ThunderboltOutlined,
27
+ } from '@ant-design/icons';
18
28
  import { useAPIClient, useRequest } from '@nocobase/client';
19
29
  import { AIEmployeeSelect } from './AIEmployeeSelect';
20
30
  import { useAIEmployees } from './AIEmployeesContext';
21
31
 
22
32
  const { Text } = Typography;
23
33
 
34
+ /**
35
+ * Mirrors server-side `sanitizeToolPart` in delegate-task.ts so we can compute
36
+ * the expected delegation tool names here and detect when the leader hasn't
37
+ * added them to its skillSettings.
38
+ */
39
+ const sanitizeToolPart = (value: string) => (value || '').replace(/[^a-zA-Z0-9_-]/g, '_');
40
+ const expectedDelegateToolName = (leader: string, sub: string) =>
41
+ `delegate_${sanitizeToolPart(leader)}_to_${sanitizeToolPart(sub)}`;
42
+ const expectedDispatchToolName = (leader: string) => `dispatch_subagents_${sanitizeToolPart(leader)}`;
43
+
24
44
  export const RulesTab: React.FC = () => {
25
45
  const api = useAPIClient();
26
46
  const [visible, setVisible] = useState(false);
@@ -34,8 +54,99 @@ export const RulesTab: React.FC = () => {
34
54
  },
35
55
  });
36
56
 
57
+ const { data: llmServicesData, loading: llmLoading } = useRequest({
58
+ url: 'ai:listAllEnabledModels',
59
+ });
60
+
61
+ const llmServices = React.useMemo(() => {
62
+ const raw = (llmServicesData as any)?.data ?? llmServicesData;
63
+ if (Array.isArray(raw)) return raw;
64
+ return Array.isArray(raw?.data) ? raw.data : [];
65
+ }, [llmServicesData]);
66
+
37
67
  // P3 FIX: Use shared context instead of duplicate API call
38
- const { employeeMap } = useAIEmployees();
68
+ const { employeeMap, skillsMap, refresh: refreshEmployees } = useAIEmployees();
69
+ const rules = React.useMemo(() => {
70
+ const rows = (data as any)?.data;
71
+ return Array.isArray(rows) ? rows : [];
72
+ }, [data]);
73
+
74
+ const handleAddSkillToEmployee = async (employeeUsername: string, toolName: string) => {
75
+ try {
76
+ // Re-fetch the leader to merge its current skills (skillsMap may be stale).
77
+ const leaderResp = await api.request({
78
+ url: 'aiEmployees:get',
79
+ params: { filterByTk: employeeUsername },
80
+ });
81
+ const leader = (leaderResp as any)?.data?.data;
82
+ if (!leader) {
83
+ message.error('Could not load AI employee.');
84
+ return;
85
+ }
86
+ const existing = Array.isArray(leader.skillSettings?.skills) ? leader.skillSettings.skills : [];
87
+ if (existing.some((s: any) => (typeof s === 'string' ? s : s?.name) === toolName)) {
88
+ message.info('Skill already present.');
89
+ await refreshEmployees();
90
+ return;
91
+ }
92
+ const nextSkills = [...existing, { name: toolName, autoCall: false }];
93
+ await api.request({
94
+ url: 'aiEmployees:update',
95
+ method: 'put',
96
+ params: { filterByTk: employeeUsername },
97
+ data: { skillSettings: { ...(leader.skillSettings || {}), skills: nextSkills } },
98
+ });
99
+ message.success(`Added "${toolName}" to ${employeeUsername}'s skills.`);
100
+ await refreshEmployees();
101
+ } catch (e: any) {
102
+ message.error(`Auto-assign failed: ${e?.message || 'unknown error'}`);
103
+ }
104
+ };
105
+
106
+ const handleAutoAssignSkill = async (record: any) => {
107
+ await handleAddSkillToEmployee(
108
+ record.leaderUsername,
109
+ expectedDelegateToolName(record.leaderUsername, record.subAgentUsername),
110
+ );
111
+ };
112
+
113
+ const handleAutoAssignDispatchSkill = async (leaderUsername: string) => {
114
+ await handleAddSkillToEmployee(leaderUsername, expectedDispatchToolName(leaderUsername));
115
+ };
116
+
117
+ const subAgentLeaderCount = React.useMemo(() => {
118
+ const counts = new Map<string, Set<string>>();
119
+ for (const rule of rules) {
120
+ const set = counts.get(rule.subAgentUsername) || new Set<string>();
121
+ set.add(rule.leaderUsername);
122
+ counts.set(rule.subAgentUsername, set);
123
+ }
124
+ return counts;
125
+ }, [rules]);
126
+
127
+ const aliasConflicts = React.useMemo(() => {
128
+ return Array.from(subAgentLeaderCount.entries())
129
+ .filter(([, leaders]) => leaders.size > 1)
130
+ .map(([sub, leaders]) => ({ sub, leaders: Array.from(leaders) }));
131
+ }, [subAgentLeaderCount]);
132
+
133
+ const groupedRules = React.useMemo(() => {
134
+ const groups = new Map<string, any[]>();
135
+ for (const rule of rules) {
136
+ const key = rule.leaderUsername || 'unknown';
137
+ let items = groups.get(key);
138
+ if (!items) {
139
+ items = [];
140
+ groups.set(key, items);
141
+ }
142
+ items.push(rule);
143
+ }
144
+
145
+ return Array.from(groups.entries()).map(([leaderUsername, items]) => ({
146
+ leaderUsername,
147
+ items,
148
+ }));
149
+ }, [rules]);
39
150
 
40
151
  const handleOpen = (record?: any) => {
41
152
  setEditingRecord(record);
@@ -43,7 +154,7 @@ export const RulesTab: React.FC = () => {
43
154
  form.setFieldsValue(record);
44
155
  } else {
45
156
  form.resetFields();
46
- form.setFieldsValue({ enabled: true, maxDepth: 1, timeout: 120000 });
157
+ form.setFieldsValue({ enabled: true, maxDepth: 1, timeout: 120000, recursionLimit: 50 });
47
158
  }
48
159
  setVisible(true);
49
160
  };
@@ -104,9 +215,7 @@ export const RulesTab: React.FC = () => {
104
215
  title: 'Leader (Orchestrator)',
105
216
  dataIndex: 'leaderUsername',
106
217
  key: 'leaderUsername',
107
- render: (username: string) => (
108
- <Tag color="blue">{employeeMap.get(username) || username}</Tag>
109
- ),
218
+ render: (username: string) => <Tag color="blue">{employeeMap.get(username) || username}</Tag>,
110
219
  },
111
220
  {
112
221
  title: '',
@@ -118,9 +227,7 @@ export const RulesTab: React.FC = () => {
118
227
  title: 'Sub-Agent',
119
228
  dataIndex: 'subAgentUsername',
120
229
  key: 'subAgentUsername',
121
- render: (username: string) => (
122
- <Tag color="green">{employeeMap.get(username) || username}</Tag>
123
- ),
230
+ render: (username: string) => <Tag color="green">{employeeMap.get(username) || username}</Tag>,
124
231
  },
125
232
  {
126
233
  title: 'Max Depth',
@@ -136,6 +243,30 @@ export const RulesTab: React.FC = () => {
136
243
  width: 100,
137
244
  render: (v: number) => `${((v ?? 120000) / 1000).toFixed(0)}s`,
138
245
  },
246
+ {
247
+ title: 'LLM Override',
248
+ key: 'llmOverride',
249
+ width: 140,
250
+ render: (_: any, record: any) => {
251
+ if (record.llmService && record.model) {
252
+ const svc = llmServices.find((s: any) => s.llmService === record.llmService);
253
+ const svcName = svc ? svc.llmServiceTitle : record.llmService;
254
+ return (
255
+ <Space direction="vertical" size={0}>
256
+ <Text style={{ fontSize: 12 }}>{svcName}</Text>
257
+ <Text type="secondary" style={{ fontSize: 12 }}>
258
+ {record.model}
259
+ </Text>
260
+ </Space>
261
+ );
262
+ }
263
+ return (
264
+ <Text type="secondary" style={{ fontSize: 12 }}>
265
+ Inherited
266
+ </Text>
267
+ );
268
+ },
269
+ },
139
270
  {
140
271
  title: 'Enabled',
141
272
  dataIndex: 'enabled',
@@ -157,6 +288,41 @@ export const RulesTab: React.FC = () => {
157
288
  />
158
289
  ),
159
290
  },
291
+ {
292
+ title: 'Skill',
293
+ key: 'skill',
294
+ width: 150,
295
+ render: (_: any, record: any) => {
296
+ const expected = expectedDelegateToolName(record.leaderUsername, record.subAgentUsername);
297
+ const leaderSkills = skillsMap.get(record.leaderUsername);
298
+ if (!leaderSkills) {
299
+ return (
300
+ <Text type="secondary" style={{ fontSize: 12 }}>
301
+
302
+ </Text>
303
+ );
304
+ }
305
+ const present = leaderSkills.has(expected);
306
+ if (present) {
307
+ return <Tag color="success">Assigned</Tag>;
308
+ }
309
+ return (
310
+ <Space size={4}>
311
+ <Tag icon={<WarningOutlined />} color="warning">
312
+ Missing
313
+ </Tag>
314
+ <Button
315
+ type="link"
316
+ size="small"
317
+ icon={<ThunderboltOutlined />}
318
+ onClick={() => handleAutoAssignSkill(record)}
319
+ >
320
+ Auto-add
321
+ </Button>
322
+ </Space>
323
+ );
324
+ },
325
+ },
160
326
  {
161
327
  title: 'Actions',
162
328
  key: 'actions',
@@ -178,6 +344,28 @@ export const RulesTab: React.FC = () => {
178
344
 
179
345
  const leaderUsername = Form.useWatch('leaderUsername', form);
180
346
 
347
+ const missingSkillCount = React.useMemo(() => {
348
+ return rules.reduce((acc: number, r: any) => {
349
+ const leaderSkills = skillsMap.get(r.leaderUsername);
350
+ if (!leaderSkills) return acc;
351
+ const expected = expectedDelegateToolName(r.leaderUsername, r.subAgentUsername);
352
+ return leaderSkills.has(expected) ? acc : acc + 1;
353
+ }, 0);
354
+ }, [rules, skillsMap]);
355
+
356
+ const missingDispatchSkills = React.useMemo(() => {
357
+ return groupedRules
358
+ .map((group) => {
359
+ const leaderSkills = skillsMap.get(group.leaderUsername);
360
+ if (!leaderSkills) return null;
361
+ const toolName = expectedDispatchToolName(group.leaderUsername);
362
+ return leaderSkills.has(toolName)
363
+ ? null
364
+ : { leaderUsername: group.leaderUsername, toolName, count: group.items.length };
365
+ })
366
+ .filter(Boolean) as Array<{ leaderUsername: string; toolName: string; count: number }>;
367
+ }, [groupedRules, skillsMap]);
368
+
181
369
  return (
182
370
  <div>
183
371
  <Alert
@@ -193,20 +381,125 @@ export const RulesTab: React.FC = () => {
193
381
  }
194
382
  />
195
383
 
384
+ {missingSkillCount > 0 && (
385
+ <Alert
386
+ type="warning"
387
+ showIcon
388
+ style={{ marginBottom: 16 }}
389
+ message={`${missingSkillCount} rule${missingSkillCount > 1 ? 's' : ''} missing required skill assignment`}
390
+ description={
391
+ <Text type="secondary">
392
+ The Leader employee hasn&apos;t added the corresponding{' '}
393
+ <Text code>delegate_&lt;leader&gt;_to_&lt;sub&gt;</Text> tool to its skillSettings, so the LLM cannot
394
+ actually call these sub-agents. Use the <b>Auto-add</b> button in the Skill column to fix.
395
+ </Text>
396
+ }
397
+ />
398
+ )}
399
+
400
+ {missingDispatchSkills.length > 0 && (
401
+ <Alert
402
+ type="warning"
403
+ showIcon
404
+ style={{ marginBottom: 16 }}
405
+ message={`${missingDispatchSkills.length} leader${
406
+ missingDispatchSkills.length > 1 ? 's' : ''
407
+ } missing dispatch skill assignment`}
408
+ description={
409
+ <Space direction="vertical" size={6}>
410
+ <Text type="secondary">
411
+ The fan-out tool lets a Leader dispatch multiple independent sub-tasks in one call. Add it to the
412
+ Leader&apos;s skills to enable the new multi-agent flow.
413
+ </Text>
414
+ {missingDispatchSkills.map(({ leaderUsername, toolName, count }) => (
415
+ <Space key={leaderUsername} size={8} wrap>
416
+ <Tag color="blue">{employeeMap.get(leaderUsername) || leaderUsername}</Tag>
417
+ <Text type="secondary">
418
+ {count} sub-agent{count > 1 ? 's' : ''}
419
+ </Text>
420
+ <Text code>{toolName}</Text>
421
+ <Button
422
+ type="link"
423
+ size="small"
424
+ icon={<ThunderboltOutlined />}
425
+ onClick={() => handleAutoAssignDispatchSkill(leaderUsername)}
426
+ >
427
+ Auto-add
428
+ </Button>
429
+ </Space>
430
+ ))}
431
+ </Space>
432
+ }
433
+ />
434
+ )}
435
+
436
+ {aliasConflicts.length > 0 && (
437
+ <Alert
438
+ type="warning"
439
+ showIcon
440
+ style={{ marginBottom: 16 }}
441
+ message="Legacy delegate_to_<sub> alias is no longer registered for these sub-agents"
442
+ description={
443
+ <Space direction="vertical" size={2}>
444
+ {aliasConflicts.map(({ sub, leaders }) => (
445
+ <Text key={sub} type="secondary">
446
+ <Tag color="green">{employeeMap.get(sub) || sub}</Tag>
447
+ has multiple leaders ({leaders.map((l) => employeeMap.get(l) || l).join(', ')}). The legacy alias is
448
+ dropped to avoid ambiguity — leaders must use <Text code>delegate_&lt;leader&gt;_to_&lt;sub&gt;</Text>{' '}
449
+ in their skills.
450
+ </Text>
451
+ ))}
452
+ </Space>
453
+ }
454
+ />
455
+ )}
456
+
196
457
  <Card bordered={false}>
197
458
  <div style={{ marginBottom: 16, display: 'flex', justifyContent: 'flex-end' }}>
198
459
  <Button type="primary" icon={<PlusOutlined />} onClick={() => handleOpen()}>
199
460
  New Rule
200
461
  </Button>
201
462
  </div>
202
- <Table
203
- rowKey="id"
204
- loading={loading}
205
- dataSource={(data as any)?.data || []}
206
- columns={columns}
207
- pagination={{ hideOnSinglePage: true, pageSize: 20 }}
208
- size="middle"
209
- />
463
+ {groupedRules.length ? (
464
+ <Collapse
465
+ bordered={false}
466
+ defaultActiveKey={groupedRules.map((group) => group.leaderUsername)}
467
+ items={groupedRules.map((group) => ({
468
+ key: group.leaderUsername,
469
+ label: (
470
+ <Space>
471
+ <Tag color="blue">{employeeMap.get(group.leaderUsername) || group.leaderUsername}</Tag>
472
+ <Text type="secondary">
473
+ {group.items.length} sub-agent{group.items.length > 1 ? 's' : ''}
474
+ </Text>
475
+ {missingDispatchSkills.some((item) => item.leaderUsername === group.leaderUsername) && (
476
+ <Tag color="warning">Dispatch missing</Tag>
477
+ )}
478
+ </Space>
479
+ ),
480
+ children: (
481
+ <Table
482
+ rowKey="id"
483
+ loading={loading}
484
+ dataSource={group.items}
485
+ columns={columns}
486
+ pagination={false}
487
+ size="middle"
488
+ />
489
+ ),
490
+ }))}
491
+ />
492
+ ) : (
493
+ <Table
494
+ rowKey="id"
495
+ loading={loading}
496
+ dataSource={[]}
497
+ columns={columns}
498
+ pagination={false}
499
+ size="middle"
500
+ locale={{ emptyText: <Empty description="No orchestration rules yet" /> }}
501
+ />
502
+ )}
210
503
  </Card>
211
504
 
212
505
  <Drawer
@@ -240,10 +533,7 @@ export const RulesTab: React.FC = () => {
240
533
  rules={[{ required: true, message: 'Please select a Sub-Agent' }]}
241
534
  tooltip="The AI Employee that will receive delegated tasks"
242
535
  >
243
- <AIEmployeeSelect
244
- placeholder="Select Sub-Agent AI Employee..."
245
- exclude={leaderUsername}
246
- />
536
+ <AIEmployeeSelect placeholder="Select Sub-Agent AI Employee..." exclude={leaderUsername} />
247
537
  </Form.Item>
248
538
 
249
539
  <Form.Item
@@ -262,6 +552,63 @@ export const RulesTab: React.FC = () => {
262
552
  <InputNumber min={10000} max={600000} step={10000} style={{ width: '100%' }} />
263
553
  </Form.Item>
264
554
 
555
+ <Form.Item
556
+ name="recursionLimit"
557
+ label="Recursion Limit"
558
+ tooltip="Max LangGraph reasoning steps per delegation. Higher = more complex multi-step tasks; lower = stricter cap on token usage. Default 50."
559
+ >
560
+ <InputNumber min={5} max={200} step={5} style={{ width: '100%' }} />
561
+ </Form.Item>
562
+
563
+ <Form.Item
564
+ name="llmService"
565
+ label="Override LLM Service"
566
+ tooltip="Optional: Provider name. Leave empty to inherit from Leader."
567
+ >
568
+ <Select
569
+ allowClear
570
+ placeholder="Inherit from Leader"
571
+ loading={llmLoading}
572
+ options={llmServices.map((svc: any) => ({
573
+ label: svc.llmServiceTitle || svc.llmService,
574
+ value: svc.llmService,
575
+ }))}
576
+ onChange={() => form.setFieldValue('model', undefined)}
577
+ />
578
+ </Form.Item>
579
+
580
+ <Form.Item
581
+ noStyle
582
+ shouldUpdate={(prevValues, currentValues) => prevValues.llmService !== currentValues.llmService}
583
+ >
584
+ {() => {
585
+ const selectedServiceId = form.getFieldValue('llmService');
586
+ const selectedService = llmServices.find((s: any) => s.llmService === selectedServiceId);
587
+ const availableModels = Array.isArray(selectedService?.enabledModels)
588
+ ? selectedService.enabledModels
589
+ : [];
590
+
591
+ return (
592
+ <Form.Item
593
+ name="model"
594
+ label="Override Model"
595
+ tooltip="Optional: Model name. Leave empty to inherit from Leader."
596
+ rules={[{ required: !!selectedServiceId, message: 'Please select a model' }]}
597
+ >
598
+ <Select
599
+ allowClear
600
+ placeholder={selectedServiceId ? 'Select a model' : 'Inherit from Leader'}
601
+ disabled={!selectedServiceId}
602
+ options={availableModels.map((m: any) => ({
603
+ label: m.label,
604
+ value: m.value,
605
+ }))}
606
+ />
607
+ </Form.Item>
608
+ );
609
+ }}
610
+ </Form.Item>
611
+
265
612
  <Form.Item name="enabled" label="Enabled" valuePropName="checked">
266
613
  <Switch />
267
614
  </Form.Item>