create-windy 0.8.3 → 0.9.1

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 (505) hide show
  1. package/dist/cli.js +838 -560
  2. package/package.json +1 -1
  3. package/template/.windy-template.json +2 -2
  4. package/template/apps/agent-server/Dockerfile +92 -22
  5. package/template/apps/agent-server/README.md +47 -85
  6. package/template/apps/agent-server/documents/office.py +216 -0
  7. package/template/apps/agent-server/documents/query_report.py +136 -0
  8. package/template/apps/agent-server/documents/smoke.py +177 -0
  9. package/template/apps/agent-server/documents/test_boundaries.py +185 -0
  10. package/template/apps/agent-server/host-contracts.ts +56 -0
  11. package/template/apps/agent-server/install-native.ts +167 -0
  12. package/template/apps/agent-server/main.ts +179 -0
  13. package/template/apps/agent-server/native/EXTENSIONS.md +46 -0
  14. package/template/apps/agent-server/native/admission.ts +73 -0
  15. package/template/apps/agent-server/native/authorization.test.ts +176 -0
  16. package/template/apps/agent-server/native/authorization.ts +118 -0
  17. package/template/apps/agent-server/native/boundary-io.ts +93 -0
  18. package/template/apps/agent-server/native/boundary-product.ts +107 -0
  19. package/template/apps/agent-server/native/boundary-project.test.ts +247 -0
  20. package/template/apps/agent-server/native/boundary-project.ts +188 -0
  21. package/template/apps/agent-server/native/boundary.ts +188 -0
  22. package/template/apps/agent-server/native/compaction-policy.test.ts +175 -0
  23. package/template/apps/agent-server/native/config.ts +95 -0
  24. package/template/apps/agent-server/native/conversation-instructions.ts +9 -0
  25. package/template/apps/agent-server/native/extensions.test.ts +190 -0
  26. package/template/apps/agent-server/native/extensions.ts +31 -0
  27. package/template/apps/agent-server/native/host-profile.test.ts +91 -0
  28. package/template/apps/agent-server/native/host-profile.ts +33 -0
  29. package/template/apps/agent-server/native/host-test-fixture.ts +13 -0
  30. package/template/apps/agent-server/native/http.ts +129 -0
  31. package/template/apps/agent-server/native/lifecycle.test.ts +285 -0
  32. package/template/apps/agent-server/native/lifecycle.ts +136 -0
  33. package/template/apps/agent-server/native/manager.ts +292 -0
  34. package/template/apps/agent-server/native/native.test.ts +207 -0
  35. package/template/apps/agent-server/native/office-preview.test.ts +50 -0
  36. package/template/apps/agent-server/native/office-preview.ts +25 -0
  37. package/template/apps/agent-server/native/parallel-harness.ts +242 -0
  38. package/template/apps/agent-server/native/parallel-mcp-fixture.ts +97 -0
  39. package/template/apps/agent-server/native/parallel.test.ts +256 -0
  40. package/template/apps/agent-server/native/profile-composition.test.ts +147 -0
  41. package/template/apps/agent-server/native/profile.ts +307 -0
  42. package/template/apps/agent-server/native/request.ts +61 -0
  43. package/template/apps/agent-server/native/session-conflict.test.ts +235 -0
  44. package/template/apps/agent-server/native/session-conflict.ts +21 -0
  45. package/template/apps/agent-server/native/shared-skills.test.ts +128 -0
  46. package/template/apps/agent-server/native/shared-skills.ts +240 -0
  47. package/template/apps/agent-server/native/socket-lifecycle.test.ts +48 -0
  48. package/template/apps/agent-server/native/socket.ts +130 -0
  49. package/template/apps/agent-server/native/storage-lifecycle.test.ts +217 -0
  50. package/template/apps/agent-server/native/storage.ts +188 -0
  51. package/template/apps/agent-server/native/stream-authorization.test.ts +89 -0
  52. package/template/apps/agent-server/native/worker.ts +77 -0
  53. package/template/apps/agent-server/native-download.test.ts +119 -0
  54. package/template/apps/agent-server/native-download.ts +145 -0
  55. package/template/apps/agent-server/package.json +63 -0
  56. package/template/apps/agent-server/plugins/access.mjs +126 -0
  57. package/template/apps/agent-server/plugins/branding/README.md +9 -0
  58. package/template/apps/agent-server/plugins/branding/brand.css +85 -0
  59. package/template/apps/agent-server/plugins/branding/client.js +338 -0
  60. package/template/apps/agent-server/plugins/branding/index.mjs +35 -0
  61. package/template/apps/agent-server/plugins/branding/loading.d.mts +2 -0
  62. package/template/apps/agent-server/plugins/branding/loading.mjs +66 -0
  63. package/template/apps/agent-server/plugins/branding/loading.test.ts +89 -0
  64. package/template/apps/agent-server/plugins/branding/package.json +21 -0
  65. package/template/apps/agent-server/plugins/branding.test.ts +294 -0
  66. package/template/apps/agent-server/plugins/compaction.mjs +83 -0
  67. package/template/apps/agent-server/plugins/compaction.test.ts +91 -0
  68. package/template/apps/agent-server/plugins/confine-network.py +57 -0
  69. package/template/apps/agent-server/plugins/default-skills.test.ts +62 -0
  70. package/template/apps/agent-server/plugins/downloads/README.md +28 -0
  71. package/template/apps/agent-server/plugins/downloads/client.js +126 -0
  72. package/template/apps/agent-server/plugins/downloads/downloads.test.ts +222 -0
  73. package/template/apps/agent-server/plugins/downloads/index.d.mts +19 -0
  74. package/template/apps/agent-server/plugins/downloads/index.mjs +180 -0
  75. package/template/apps/agent-server/plugins/downloads/package.json +20 -0
  76. package/template/apps/agent-server/plugins/drop-overlay/README.md +24 -0
  77. package/template/apps/agent-server/plugins/drop-overlay/drop-overlay.test.ts +199 -0
  78. package/template/apps/agent-server/plugins/drop-overlay/index.d.mts +8 -0
  79. package/template/apps/agent-server/plugins/drop-overlay/index.mjs +12 -0
  80. package/template/apps/agent-server/plugins/drop-overlay/style.css +102 -0
  81. package/template/apps/agent-server/plugins/locale/client.js +61 -0
  82. package/template/apps/agent-server/plugins/locale/index.d.mts +9 -0
  83. package/template/apps/agent-server/plugins/locale/index.mjs +16 -0
  84. package/template/apps/agent-server/plugins/locale/locale.test.ts +217 -0
  85. package/template/apps/agent-server/plugins/locale/package.json +19 -0
  86. package/template/apps/agent-server/plugins/parallel.mjs +146 -0
  87. package/template/apps/agent-server/plugins/preset-registry.d.mts +2 -0
  88. package/template/apps/agent-server/plugins/preset-registry.mjs +41 -0
  89. package/template/apps/agent-server/plugins/preset-registry.test.ts +46 -0
  90. package/template/apps/agent-server/plugins/questions.d.mts +25 -0
  91. package/template/apps/agent-server/plugins/questions.mjs +142 -0
  92. package/template/apps/agent-server/plugins/questions.test.ts +105 -0
  93. package/template/apps/agent-server/plugins/settings/README.md +17 -0
  94. package/template/apps/agent-server/plugins/settings/client.js +102 -0
  95. package/template/apps/agent-server/plugins/settings/index.mjs +17 -0
  96. package/template/apps/agent-server/plugins/settings/package.json +19 -0
  97. package/template/apps/agent-server/plugins/settings/settings.test.ts +129 -0
  98. package/template/apps/agent-server/plugins/settings-controller.d.mts +4 -0
  99. package/template/apps/agent-server/plugins/settings-controller.mjs +31 -0
  100. package/template/apps/agent-server/plugins/settings-controller.test.ts +17 -0
  101. package/template/apps/agent-server/plugins/settings-dispatch.test.ts +34 -0
  102. package/template/apps/agent-server/plugins/shared-skills.d.mts +15 -0
  103. package/template/apps/agent-server/plugins/shared-skills.mjs +82 -0
  104. package/template/apps/agent-server/plugins/shared-skills.test.ts +51 -0
  105. package/template/apps/agent-server/plugins/skill-library/README.md +11 -0
  106. package/template/apps/agent-server/plugins/skill-library/archive.test.ts +43 -0
  107. package/template/apps/agent-server/plugins/skill-library/bundle.mjs +234 -0
  108. package/template/apps/agent-server/plugins/skill-library/client-chunks.test.ts +107 -0
  109. package/template/apps/agent-server/plugins/skill-library/client-form-mount.test.ts +139 -0
  110. package/template/apps/agent-server/plugins/skill-library/client-form.test.ts +261 -0
  111. package/template/apps/agent-server/plugins/skill-library/client-ui.test.ts +268 -0
  112. package/template/apps/agent-server/plugins/skill-library/client-use.test.ts +158 -0
  113. package/template/apps/agent-server/plugins/skill-library/client.editor.js +93 -0
  114. package/template/apps/agent-server/plugins/skill-library/client.form.js +316 -0
  115. package/template/apps/agent-server/plugins/skill-library/client.js +348 -0
  116. package/template/apps/agent-server/plugins/skill-library/client.request.js +52 -0
  117. package/template/apps/agent-server/plugins/skill-library/client.transfer.js +48 -0
  118. package/template/apps/agent-server/plugins/skill-library/client.use.js +46 -0
  119. package/template/apps/agent-server/plugins/skill-library/default-roots.test.ts +84 -0
  120. package/template/apps/agent-server/plugins/skill-library/draft.d.mts +17 -0
  121. package/template/apps/agent-server/plugins/skill-library/draft.mjs +152 -0
  122. package/template/apps/agent-server/plugins/skill-library/draft.test.ts +287 -0
  123. package/template/apps/agent-server/plugins/skill-library/index.d.mts +49 -0
  124. package/template/apps/agent-server/plugins/skill-library/index.mjs +226 -0
  125. package/template/apps/agent-server/plugins/skill-library/package.json +24 -0
  126. package/template/apps/agent-server/plugins/skill-library/presentation/README.md +27 -0
  127. package/template/apps/agent-server/plugins/skill-library/presentation/UPSTREAM.md +54 -0
  128. package/template/apps/agent-server/plugins/skill-library/presentation/boot.test.ts +150 -0
  129. package/template/apps/agent-server/plugins/skill-library/presentation/client.js +146 -0
  130. package/template/apps/agent-server/plugins/skill-library/presentation/client.test.ts +195 -0
  131. package/template/apps/agent-server/plugins/skill-library/presentation/index.d.mts +9 -0
  132. package/template/apps/agent-server/plugins/skill-library/presentation/index.mjs +30 -0
  133. package/template/apps/agent-server/plugins/skill-library/presentation/metadata.test.ts +82 -0
  134. package/template/apps/agent-server/plugins/skill-library/presentation/package.json +21 -0
  135. package/template/apps/agent-server/plugins/skill-library/presentation/react-boot.test.ts +162 -0
  136. package/template/apps/agent-server/plugins/skill-library/skills.test.ts +342 -0
  137. package/template/apps/agent-server/plugins/skill-library/storage.mjs +293 -0
  138. package/template/apps/agent-server/plugins/skill-library/style.css +229 -0
  139. package/template/apps/agent-server/plugins/skill-library/test-fixture.ts +77 -0
  140. package/template/apps/agent-server/plugins/skill-library/workflow.d.mts +18 -0
  141. package/template/apps/agent-server/plugins/skill-library/workflow.mjs +189 -0
  142. package/template/apps/agent-server/plugins/skill-library/workflow.test.ts +164 -0
  143. package/template/apps/agent-server/plugins/skills/README.md +5 -0
  144. package/template/apps/agent-server/plugins/skills/windy-data-summary/SKILL.md +14 -0
  145. package/template/apps/agent-server/plugins/skills/windy-extension-guide/SKILL.md +14 -0
  146. package/template/apps/agent-server/plugins/skills/windy-office/SKILL.md +14 -0
  147. package/template/apps/agent-server/plugins/skills/windy-skill-capture/SKILL.md +14 -0
  148. package/template/apps/agent-server/plugins/skills/windy-source-compare/SKILL.md +14 -0
  149. package/template/apps/agent-server/plugins/subprocess.mjs +40 -0
  150. package/template/apps/agent-server/plugins/theme/README.md +18 -0
  151. package/template/apps/agent-server/plugins/theme/client.js +18 -0
  152. package/template/apps/agent-server/plugins/theme/index.d.mts +9 -0
  153. package/template/apps/agent-server/plugins/theme/index.mjs +18 -0
  154. package/template/apps/agent-server/plugins/theme/package.json +19 -0
  155. package/template/apps/agent-server/plugins/theme/source-tokens.ts +82 -0
  156. package/template/apps/agent-server/plugins/theme/sync-tokens.ts +12 -0
  157. package/template/apps/agent-server/plugins/theme/theme.test.ts +193 -0
  158. package/template/apps/agent-server/plugins/theme/tokens.json +166 -0
  159. package/template/apps/agent-server/plugins/tool-catalog/README.md +79 -0
  160. package/template/apps/agent-server/plugins/tool-catalog/categories.mjs +111 -0
  161. package/template/apps/agent-server/plugins/tool-catalog/categories.test.ts +118 -0
  162. package/template/apps/agent-server/plugins/tool-catalog/client-cache.test.ts +264 -0
  163. package/template/apps/agent-server/plugins/tool-catalog/client.js +333 -0
  164. package/template/apps/agent-server/plugins/tool-catalog/client.test.ts +136 -0
  165. package/template/apps/agent-server/plugins/tool-catalog/discovery.d.mts +42 -0
  166. package/template/apps/agent-server/plugins/tool-catalog/discovery.mjs +242 -0
  167. package/template/apps/agent-server/plugins/tool-catalog/discovery.test.ts +229 -0
  168. package/template/apps/agent-server/plugins/tool-catalog/index.d.mts +5 -0
  169. package/template/apps/agent-server/plugins/tool-catalog/index.mjs +91 -0
  170. package/template/apps/agent-server/plugins/tool-catalog/package.json +23 -0
  171. package/template/apps/agent-server/plugins/tool-catalog/presentation.d.mts +21 -0
  172. package/template/apps/agent-server/plugins/tool-catalog/presentation.mjs +153 -0
  173. package/template/apps/agent-server/plugins/tool-catalog/presentation.test.ts +166 -0
  174. package/template/apps/agent-server/plugins/tool-catalog/routes.test.ts +209 -0
  175. package/template/apps/agent-server/plugins/tool-catalog/style.css +155 -0
  176. package/template/apps/agent-server/plugins/tool-catalog/use-tool.test.ts +160 -0
  177. package/template/apps/agent-server/plugins/tool-presentation/README.md +7 -0
  178. package/template/apps/agent-server/plugins/tool-presentation/build-client.ts +29 -0
  179. package/template/apps/agent-server/plugins/tool-presentation/client.js +312 -0
  180. package/template/apps/agent-server/plugins/tool-presentation/client.results.js +9 -0
  181. package/template/apps/agent-server/plugins/tool-presentation/client.test.ts +178 -0
  182. package/template/apps/agent-server/plugins/tool-presentation/index.mjs +10 -0
  183. package/template/apps/agent-server/plugins/tool-presentation/package.json +24 -0
  184. package/template/apps/agent-server/plugins/tool-presentation/result-discovery.mjs +43 -0
  185. package/template/apps/agent-server/plugins/tool-presentation/result-model.d.mts +51 -0
  186. package/template/apps/agent-server/plugins/tool-presentation/result-model.mjs +96 -0
  187. package/template/apps/agent-server/plugins/workspace/README.md +5 -0
  188. package/template/apps/agent-server/plugins/workspace/index.mjs +8 -0
  189. package/template/apps/agent-server/plugins/workspace/package.json +10 -0
  190. package/template/apps/agent-server/plugins/workspace/style.css +124 -0
  191. package/template/apps/agent-server/project/host.ts +13 -0
  192. package/template/apps/agent-server/runtime/artifacts.ts +115 -0
  193. package/template/apps/agent-server/runtime/audit.nodecheck.ts +60 -0
  194. package/template/apps/agent-server/runtime/capacity.ts +61 -0
  195. package/template/apps/agent-server/runtime/client-completion-budget.nodecheck.ts +92 -0
  196. package/template/apps/agent-server/runtime/compatibility.ts +33 -0
  197. package/template/apps/agent-server/runtime/completions.ts +320 -0
  198. package/template/apps/agent-server/runtime/config.ts +246 -0
  199. package/template/apps/agent-server/runtime/context-budget.ts +70 -0
  200. package/template/apps/agent-server/runtime/context-plugin.ts +306 -0
  201. package/template/apps/agent-server/runtime/context.nodecheck.ts +241 -0
  202. package/template/apps/agent-server/runtime/contracts.ts +201 -0
  203. package/template/apps/agent-server/runtime/dsh-engine.ts +196 -0
  204. package/template/apps/agent-server/runtime/evaluation-plugin.ts +115 -0
  205. package/template/apps/agent-server/runtime/evaluation.nodecheck.ts +194 -0
  206. package/template/apps/agent-server/runtime/events.ts +71 -0
  207. package/template/apps/agent-server/runtime/governance.ts +194 -0
  208. package/template/apps/agent-server/runtime/index.ts +339 -0
  209. package/template/apps/agent-server/runtime/internal-output.ts +37 -0
  210. package/template/apps/agent-server/runtime/isolation.nodecheck.ts +287 -0
  211. package/template/apps/agent-server/runtime/model-payload.ts +97 -0
  212. package/template/apps/agent-server/runtime/model-plugin.ts +308 -0
  213. package/template/apps/agent-server/runtime/model-route.ts +34 -0
  214. package/template/apps/agent-server/runtime/model-usage.ts +51 -0
  215. package/template/apps/agent-server/runtime/model-wire.ts +45 -0
  216. package/template/apps/agent-server/runtime/native-authorization.nodecheck.ts +126 -0
  217. package/template/apps/agent-server/runtime/native-completion.nodecheck.ts +81 -0
  218. package/template/apps/agent-server/runtime/output-validation.ts +66 -0
  219. package/template/apps/agent-server/runtime/production-capacity.nodecheck.ts +121 -0
  220. package/template/apps/agent-server/runtime/questions-workflow.nodecheck.ts +249 -0
  221. package/template/apps/agent-server/runtime/report-breakdown.ts +79 -0
  222. package/template/apps/agent-server/runtime/reporting.ts +219 -0
  223. package/template/apps/agent-server/runtime/run-completion.ts +39 -0
  224. package/template/apps/agent-server/runtime/run-request-digest.ts +18 -0
  225. package/template/apps/agent-server/runtime/runtime-test-fixtures.ts +264 -0
  226. package/template/apps/agent-server/runtime/runtime.nodecheck.ts +150 -0
  227. package/template/apps/agent-server/runtime/store-idempotency.nodecheck.ts +74 -0
  228. package/template/apps/agent-server/runtime/store.ts +324 -0
  229. package/template/apps/agent-server/runtime/structured-output-mode.nodecheck.ts +51 -0
  230. package/template/apps/agent-server/runtime/tool-name.ts +6 -0
  231. package/template/apps/agent-server/runtime/tool-plugin.ts +201 -0
  232. package/template/apps/agent-server/runtime/vision-readiness.ts +200 -0
  233. package/template/apps/agent-server/scripts/confinement-check.mjs +103 -0
  234. package/template/apps/agent-server/scripts/coordinator-check.mjs +344 -0
  235. package/template/apps/agent-server/scripts/documents-delivery-check.mjs +309 -0
  236. package/template/apps/agent-server/scripts/office-preview-check.mjs +92 -0
  237. package/template/apps/agent-server/scripts/test-confinement.ts +58 -0
  238. package/template/apps/agent-server/scripts/test-coordinator.ts +36 -0
  239. package/template/apps/agent-server/scripts/test-runtime.ts +46 -0
  240. package/template/apps/agent-server/tsconfig.json +21 -0
  241. package/template/apps/server/Dockerfile +3 -0
  242. package/template/apps/server/package.json +5 -1
  243. package/template/apps/server/scripts/check-dsh-platform-example.ts +251 -0
  244. package/template/apps/server/src/agent/dsh-runtime-wire.test.ts +33 -0
  245. package/template/apps/server/src/agent/governance-runtime.ts +41 -0
  246. package/template/apps/server/src/agent/remote-runtime-response.ts +1 -1
  247. package/template/apps/server/src/agent/run-contracts.ts +1 -0
  248. package/template/apps/server/src/agent/run-definition-support.ts +9 -0
  249. package/template/apps/server/src/agent/runtime-tool-composition.ts +2 -0
  250. package/template/apps/server/src/agent/workflow-runtime-bootstrap.ts +9 -0
  251. package/template/apps/server/src/agent-skills/access.ts +88 -0
  252. package/template/apps/server/src/agent-skills/bootstrap.ts +49 -0
  253. package/template/apps/server/src/agent-skills/builtin-registration.ts +83 -0
  254. package/template/apps/server/src/agent-skills/builtins.ts +19 -0
  255. package/template/apps/server/src/agent-skills/bundle-zip.ts +163 -0
  256. package/template/apps/server/src/agent-skills/bundle.test.ts +79 -0
  257. package/template/apps/server/src/agent-skills/bundle.ts +133 -0
  258. package/template/apps/server/src/agent-skills/contracts.ts +46 -0
  259. package/template/apps/server/src/agent-skills/drizzle-repository.ts +125 -0
  260. package/template/apps/server/src/agent-skills/input.ts +29 -0
  261. package/template/apps/server/src/agent-skills/postgres.integration.test.ts +348 -0
  262. package/template/apps/server/src/agent-skills/read-routes.test.ts +116 -0
  263. package/template/apps/server/src/agent-skills/reader.ts +108 -0
  264. package/template/apps/server/src/agent-skills/repository.ts +105 -0
  265. package/template/apps/server/src/agent-skills/routes.ts +176 -0
  266. package/template/apps/server/src/agent-skills/service.test.ts +295 -0
  267. package/template/apps/server/src/agent-skills/service.ts +301 -0
  268. package/template/apps/server/src/agent-workflow/preset-registry.test.ts +137 -0
  269. package/template/apps/server/src/agent-workflow/preset-registry.ts +191 -0
  270. package/template/apps/server/src/agent-workflow/preset-routes.test.ts +94 -0
  271. package/template/apps/server/src/agent-workflow/preset-routes.ts +45 -0
  272. package/template/apps/server/src/ai-runtime-report/service.test.ts +10 -7
  273. package/template/apps/server/src/ai-runtime-report/service.ts +1 -1
  274. package/template/apps/server/src/app/agent-workflow-presets.ts +4 -0
  275. package/template/apps/server/src/app/dsh-skill-draft-audit.test.ts +195 -0
  276. package/template/apps/server/src/app/dsh-skill-draft-audit.ts +115 -0
  277. package/template/apps/server/src/app/dsh-workbench-audit.test.ts +71 -0
  278. package/template/apps/server/src/app/dsh-workbench-audit.ts +34 -0
  279. package/template/apps/server/src/app/dsh-workbench-handshake.test.ts +63 -0
  280. package/template/apps/server/src/app/dsh-workbench-handshake.ts +48 -0
  281. package/template/apps/server/src/app/dsh-workbench-http.test.ts +96 -0
  282. package/template/apps/server/src/app/dsh-workbench-lan-origin.test.ts +114 -0
  283. package/template/apps/server/src/app/dsh-workbench-launch.test.ts +70 -0
  284. package/template/apps/server/src/app/dsh-workbench-origin.test.ts +54 -0
  285. package/template/apps/server/src/app/dsh-workbench-proxy.ts +205 -0
  286. package/template/apps/server/src/app/dsh-workbench-session-conflict.test.ts +61 -0
  287. package/template/apps/server/src/app/dsh-workbench-session.ts +59 -0
  288. package/template/apps/server/src/app/dsh-workbench-socket-audit.test.ts +115 -0
  289. package/template/apps/server/src/app/dsh-workbench-socket.test.ts +246 -0
  290. package/template/apps/server/src/app/dsh-workbench-socket.ts +272 -0
  291. package/template/apps/server/src/app/dsh-workbench-test-support.ts +158 -0
  292. package/template/apps/server/src/app/dsh-workbench.test.ts +213 -0
  293. package/template/apps/server/src/app/dsh-workbench.ts +279 -0
  294. package/template/apps/server/src/app/workbench-public-origin.ts +16 -0
  295. package/template/apps/server/src/data-governance/user-plaintext-routes.test.ts +3 -0
  296. package/template/apps/server/src/http-app.ts +31 -0
  297. package/template/apps/server/src/mcp/adapter.ts +1 -0
  298. package/template/apps/server/src/module-composition.test.ts +23 -0
  299. package/template/apps/server/src/module-composition.ts +9 -2
  300. package/template/apps/server/src/observability/bootstrap.ts +12 -0
  301. package/template/apps/server/src/observability/diagnostic-failure-recorder.ts +94 -0
  302. package/template/apps/server/src/observability/diagnostic-http-contract.test.ts +42 -0
  303. package/template/apps/server/src/observability/diagnostic-index.test.ts +89 -0
  304. package/template/apps/server/src/observability/diagnostic-index.ts +88 -0
  305. package/template/apps/server/src/observability/diagnostic-repository.ts +67 -0
  306. package/template/apps/server/src/platform-app-bootstrap.ts +42 -0
  307. package/template/apps/server/src/platform-http-runtime.ts +6 -0
  308. package/template/apps/server/src/runtime-development.test.ts +25 -0
  309. package/template/apps/server/src/runtime-development.ts +6 -44
  310. package/template/apps/server/src/system/diagnostic-routes.test.ts +78 -0
  311. package/template/apps/server/src/system/diagnostic-routes.ts +66 -0
  312. package/template/apps/web/Dockerfile +9 -1
  313. package/template/apps/web/dev/start.ts +21 -10
  314. package/template/apps/web/dsh-workbench-location.ts +21 -0
  315. package/template/apps/web/dsh-workbench-proxy.test.ts +121 -0
  316. package/template/apps/web/dsh-workbench-proxy.ts +194 -0
  317. package/template/apps/web/package.json +3 -1
  318. package/template/apps/web/server.ts +27 -6
  319. package/template/apps/web/src/composables/useLoginFlow.ts +13 -1
  320. package/template/apps/web/src/pages/errors/PlatformErrorPage.vue +6 -0
  321. package/template/apps/web/src/pages/errors/PlatformErrorPage.webtest.ts +14 -1
  322. package/template/apps/web/src/pages/errors/error-page-extension.ts +1 -0
  323. package/template/apps/web/src/pages/system/AgentNativePage.vue +44 -0
  324. package/template/apps/web/src/pages/system/AgentWorkflowPage.vue +20 -7
  325. package/template/apps/web/src/pages/system/DiagnosticLookupPage.vue +56 -0
  326. package/template/apps/web/src/pages/system/DiagnosticLookupPage.webtest.ts +99 -0
  327. package/template/apps/web/src/pages/system/SystemAgentSkillsPage.vue +88 -0
  328. package/template/apps/web/src/pages/system/components/DiagnosticRecordDetails.vue +52 -0
  329. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillDetailDialog.vue +166 -0
  330. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillGovernanceActionDialog.vue +51 -0
  331. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillImportDialog.vue +320 -0
  332. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillImportDialog.webtest.ts +96 -0
  333. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillsTable.vue +69 -0
  334. package/template/apps/web/src/pages/system/components/agent-workflow/WorkflowPresetCatalog.vue +82 -0
  335. package/template/apps/web/src/pages/system/components/agent-workflow/WorkflowPresetCatalog.webtest.ts +57 -0
  336. package/template/apps/web/src/pages/system/composables/useAgentSkillsGovernance.ts +105 -0
  337. package/template/apps/web/src/pages/system/composables/useAgentWorkflowPresets.ts +44 -0
  338. package/template/apps/web/src/pages/system/composables/useDiagnosticLookup.ts +64 -0
  339. package/template/apps/web/src/router/error-navigation.ts +3 -1
  340. package/template/apps/web/src/router/error-navigation.webtest.ts +14 -2
  341. package/template/apps/web/src/router/index.ts +8 -49
  342. package/template/apps/web/src/router/platform-admin-pages.ts +79 -0
  343. package/template/apps/web/src/router/platform-admin-route-bindings.ts +8 -0
  344. package/template/apps/web/src/services/agent-skills-api.ts +55 -0
  345. package/template/apps/web/src/services/agent-workflow-api.ts +12 -0
  346. package/template/apps/web/src/services/diagnostics-api.ts +12 -0
  347. package/template/apps/web/src/services/http.ts +18 -0
  348. package/template/apps/web/src/services/http.webtest.ts +51 -0
  349. package/template/apps/web/vite.config.ts +39 -0
  350. package/template/deploy/dsh/README.md +5 -0
  351. package/template/deploy/dsh/documents/README.md +9 -0
  352. package/template/deploy/dsh/documents/requirements.in +6 -0
  353. package/template/deploy/dsh/documents/requirements.lock +72 -0
  354. package/template/docker-compose.yml +24 -10
  355. package/template/docs/adr/0004-embedded-dsh-runtime.md +9 -0
  356. package/template/docs/architecture/agent-admin-workbench-implementation.md +73 -0
  357. package/template/docs/architecture/agent-admin-workbench-plan.md +41 -0
  358. package/template/docs/architecture/agent-harness.md +2 -0
  359. package/template/docs/architecture/agent-runtime-compatibility.md +2 -0
  360. package/template/docs/architecture/embedded-dsh-integration.md +44 -0
  361. package/template/docs/development/dsh-plugins.md +55 -0
  362. package/template/docs/operations/dsh-agent-migration.md +98 -0
  363. package/template/docs/platform/agent-production-store.md +5 -78
  364. package/template/docs/platform/agent-runtime-observability.md +2 -0
  365. package/template/docs/platform/agent-runtime.md +2 -0
  366. package/template/docs/platform/agent-skills.md +25 -0
  367. package/template/package.json +4 -3
  368. package/template/packages/database/drizzle/0064_dsh_skills_diagnostics.sql +42 -0
  369. package/template/packages/database/drizzle/meta/0064_snapshot.json +15349 -0
  370. package/template/packages/database/drizzle/meta/_journal.json +7 -0
  371. package/template/packages/database/package.json +2 -2
  372. package/template/packages/database/src/schema/agent-skills.ts +65 -0
  373. package/template/packages/database/src/schema/diagnostics.ts +27 -0
  374. package/template/packages/database/src/schema/index.ts +8 -0
  375. package/template/packages/modules/package.json +1 -1
  376. package/template/packages/modules/src/system-admin-routes.ts +24 -0
  377. package/template/packages/modules/src/system-admin-ui-catalog.ts +17 -10
  378. package/template/packages/modules/src/system-agent-admin-bindings.ts +2 -0
  379. package/template/packages/modules/src/system-agent-admin-menus.ts +20 -0
  380. package/template/packages/modules/src/system-agent-audit-actions.ts +3 -0
  381. package/template/packages/modules/src/system-agent-dsh.ts +119 -0
  382. package/template/packages/modules/src/system-api-permissions.ts +9 -0
  383. package/template/packages/modules/src/system-audit-actions.ts +11 -0
  384. package/template/packages/modules/src/system-features.ts +5 -0
  385. package/template/packages/modules/src/system-module-audit-selection.ts +25 -0
  386. package/template/packages/modules/src/system-module-catalog.ts +12 -32
  387. package/template/packages/modules/src/system-modules.ts +14 -3
  388. package/template/packages/modules/src/system-permissions.ts +10 -0
  389. package/template/packages/server-sdk/package.json +2 -2
  390. package/template/packages/shared/index.ts +12 -0
  391. package/template/packages/shared/package.json +1 -1
  392. package/template/packages/shared/src/agent-skills.ts +68 -0
  393. package/template/packages/shared/src/agent-workflow-presets.ts +26 -0
  394. package/template/packages/shared/src/diagnostics.ts +13 -0
  395. package/template/packages/shared/src/rbac.ts +1 -0
  396. package/template/apps/agent-server/install-python-dependencies.sh +0 -92
  397. package/template/apps/agent-server/pyproject.toml +0 -51
  398. package/template/apps/agent-server/src/southwind_agent_server/__init__.py +0 -5
  399. package/template/apps/agent-server/src/southwind_agent_server/app.py +0 -344
  400. package/template/apps/agent-server/src/southwind_agent_server/approval_resolution.py +0 -30
  401. package/template/apps/agent-server/src/southwind_agent_server/artifact_input.py +0 -153
  402. package/template/apps/agent-server/src/southwind_agent_server/asgi.py +0 -8
  403. package/template/apps/agent-server/src/southwind_agent_server/attempt_context.py +0 -199
  404. package/template/apps/agent-server/src/southwind_agent_server/attempt_context_projection.py +0 -203
  405. package/template/apps/agent-server/src/southwind_agent_server/client_completion_contracts.py +0 -61
  406. package/template/apps/agent-server/src/southwind_agent_server/client_completion_governance.py +0 -82
  407. package/template/apps/agent-server/src/southwind_agent_server/client_completion_routes.py +0 -121
  408. package/template/apps/agent-server/src/southwind_agent_server/client_completion_runtime.py +0 -158
  409. package/template/apps/agent-server/src/southwind_agent_server/config.py +0 -267
  410. package/template/apps/agent-server/src/southwind_agent_server/context_message_digest.py +0 -24
  411. package/template/apps/agent-server/src/southwind_agent_server/context_version_contracts.py +0 -71
  412. package/template/apps/agent-server/src/southwind_agent_server/context_version_port.py +0 -307
  413. package/template/apps/agent-server/src/southwind_agent_server/contracts.py +0 -297
  414. package/template/apps/agent-server/src/southwind_agent_server/deterministic.py +0 -63
  415. package/template/apps/agent-server/src/southwind_agent_server/engine.py +0 -134
  416. package/template/apps/agent-server/src/southwind_agent_server/engine_capacity.py +0 -31
  417. package/template/apps/agent-server/src/southwind_agent_server/engine_identity.py +0 -2
  418. package/template/apps/agent-server/src/southwind_agent_server/fingerprint.py +0 -61
  419. package/template/apps/agent-server/src/southwind_agent_server/health_routes.py +0 -93
  420. package/template/apps/agent-server/src/southwind_agent_server/http_helpers.py +0 -62
  421. package/template/apps/agent-server/src/southwind_agent_server/lease.py +0 -15
  422. package/template/apps/agent-server/src/southwind_agent_server/multimodal.py +0 -76
  423. package/template/apps/agent-server/src/southwind_agent_server/openai_engine.py +0 -329
  424. package/template/apps/agent-server/src/southwind_agent_server/openai_engine_validation.py +0 -165
  425. package/template/apps/agent-server/src/southwind_agent_server/openai_provider.py +0 -345
  426. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_insert.py +0 -37
  427. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_queries.py +0 -235
  428. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_replay.py +0 -44
  429. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_status.py +0 -83
  430. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_store.py +0 -336
  431. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_summary.py +0 -304
  432. package/template/apps/agent-server/src/southwind_agent_server/postgres_store.py +0 -335
  433. package/template/apps/agent-server/src/southwind_agent_server/postgres_store_backend.py +0 -333
  434. package/template/apps/agent-server/src/southwind_agent_server/provider_audit.py +0 -144
  435. package/template/apps/agent-server/src/southwind_agent_server/provider_governance.py +0 -309
  436. package/template/apps/agent-server/src/southwind_agent_server/provider_output_guidance.py +0 -34
  437. package/template/apps/agent-server/src/southwind_agent_server/readiness_pin.py +0 -37
  438. package/template/apps/agent-server/src/southwind_agent_server/report_lifecycle.py +0 -218
  439. package/template/apps/agent-server/src/southwind_agent_server/report_metrics.py +0 -149
  440. package/template/apps/agent-server/src/southwind_agent_server/report_presenter.py +0 -300
  441. package/template/apps/agent-server/src/southwind_agent_server/report_routes.py +0 -132
  442. package/template/apps/agent-server/src/southwind_agent_server/report_store.py +0 -298
  443. package/template/apps/agent-server/src/southwind_agent_server/report_store_protocol.py +0 -75
  444. package/template/apps/agent-server/src/southwind_agent_server/report_types.py +0 -118
  445. package/template/apps/agent-server/src/southwind_agent_server/run_admission.py +0 -64
  446. package/template/apps/agent-server/src/southwind_agent_server/run_capacity.py +0 -59
  447. package/template/apps/agent-server/src/southwind_agent_server/runtime_budget.py +0 -74
  448. package/template/apps/agent-server/src/southwind_agent_server/runtime_compatibility.py +0 -89
  449. package/template/apps/agent-server/src/southwind_agent_server/runtime_factory.py +0 -105
  450. package/template/apps/agent-server/src/southwind_agent_server/runtime_logging.py +0 -57
  451. package/template/apps/agent-server/src/southwind_agent_server/service.py +0 -325
  452. package/template/apps/agent-server/src/southwind_agent_server/service_control.py +0 -64
  453. package/template/apps/agent-server/src/southwind_agent_server/service_errors.py +0 -4
  454. package/template/apps/agent-server/src/southwind_agent_server/service_execution.py +0 -34
  455. package/template/apps/agent-server/src/southwind_agent_server/service_tasks.py +0 -34
  456. package/template/apps/agent-server/src/southwind_agent_server/signal_events.py +0 -53
  457. package/template/apps/agent-server/src/southwind_agent_server/sqlite_catalog.py +0 -118
  458. package/template/apps/agent-server/src/southwind_agent_server/sqlite_errors.py +0 -2
  459. package/template/apps/agent-server/src/southwind_agent_server/sqlite_schema.py +0 -73
  460. package/template/apps/agent-server/src/southwind_agent_server/sqlite_serialization.py +0 -16
  461. package/template/apps/agent-server/src/southwind_agent_server/sqlite_store.py +0 -350
  462. package/template/apps/agent-server/src/southwind_agent_server/sse.py +0 -41
  463. package/template/apps/agent-server/src/southwind_agent_server/store.py +0 -255
  464. package/template/apps/agent-server/src/southwind_agent_server/store_cipher.py +0 -40
  465. package/template/apps/agent-server/src/southwind_agent_server/structured_logging.py +0 -145
  466. package/template/apps/agent-server/src/southwind_agent_server/telemetry.py +0 -93
  467. package/template/apps/agent-server/src/southwind_agent_server/tool_host.py +0 -152
  468. package/template/apps/agent-server/src/southwind_agent_server/trajectory.py +0 -137
  469. package/template/apps/agent-server/src/southwind_agent_server/unavailable_engine.py +0 -58
  470. package/template/apps/agent-server/src/southwind_agent_server/vision_probe.py +0 -87
  471. package/template/apps/agent-server/src/southwind_agent_server/vision_requirement.py +0 -28
  472. package/template/apps/agent-server/src/southwind_agent_server/vlm_readiness.py +0 -247
  473. package/template/apps/agent-server/tests/__init__.py +0 -1
  474. package/template/apps/agent-server/tests/openai_provider_test_support.py +0 -131
  475. package/template/apps/agent-server/tests/test_api.py +0 -305
  476. package/template/apps/agent-server/tests/test_artifact_input.py +0 -110
  477. package/template/apps/agent-server/tests/test_client_completion.py +0 -230
  478. package/template/apps/agent-server/tests/test_config.py +0 -106
  479. package/template/apps/agent-server/tests/test_fingerprint.py +0 -10
  480. package/template/apps/agent-server/tests/test_multimodal.py +0 -81
  481. package/template/apps/agent-server/tests/test_openai_provider.py +0 -320
  482. package/template/apps/agent-server/tests/test_postgres_report_status.py +0 -59
  483. package/template/apps/agent-server/tests/test_postgres_report_summary.py +0 -298
  484. package/template/apps/agent-server/tests/test_postgres_store.py +0 -135
  485. package/template/apps/agent-server/tests/test_provider_attempt_reporting.py +0 -140
  486. package/template/apps/agent-server/tests/test_provider_governance.py +0 -276
  487. package/template/apps/agent-server/tests/test_report_attempt_lifecycle.py +0 -126
  488. package/template/apps/agent-server/tests/test_report_resilience.py +0 -183
  489. package/template/apps/agent-server/tests/test_report_routes.py +0 -143
  490. package/template/apps/agent-server/tests/test_report_store.py +0 -347
  491. package/template/apps/agent-server/tests/test_report_summary_parity.py +0 -116
  492. package/template/apps/agent-server/tests/test_report_terminal_sync.py +0 -177
  493. package/template/apps/agent-server/tests/test_run_capacity.py +0 -112
  494. package/template/apps/agent-server/tests/test_run_operational_logging.py +0 -114
  495. package/template/apps/agent-server/tests/test_runtime_compatibility.py +0 -119
  496. package/template/apps/agent-server/tests/test_runtime_factory_readiness.py +0 -52
  497. package/template/apps/agent-server/tests/test_sqlite_store.py +0 -182
  498. package/template/apps/agent-server/tests/test_structured_logging.py +0 -142
  499. package/template/apps/agent-server/tests/test_telemetry.py +0 -25
  500. package/template/apps/agent-server/tests/test_tool_approval.py +0 -28
  501. package/template/apps/agent-server/tests/test_tool_structured_output.py +0 -347
  502. package/template/apps/agent-server/tests/test_trajectory.py +0 -91
  503. package/template/apps/agent-server/tests/test_vision_readiness_enforcement.py +0 -72
  504. package/template/apps/agent-server/tests/test_vlm_readiness.py +0 -106
  505. package/template/apps/agent-server/uv.lock +0 -831
@@ -0,0 +1,74 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { RuntimeStore } from "./store.js";
4
+ import { digest, runSchema } from "./contracts.js";
5
+
6
+ function request(traceId: string) {
7
+ return runSchema.parse({
8
+ operationKey: "system.example.extraction",
9
+ input: { sourceId: "synthetic-source" },
10
+ userPrompt: "合成测试笔录",
11
+ providerEgress: { mode: "forbidden" },
12
+ providerDataPolicy: { inputFields: [], envelopeFields: [] },
13
+ toolNetworkPolicy: { mode: "forbidden" },
14
+ executionGrant: "same-actor-scoped-grant",
15
+ release: { releaseId: "release-1" },
16
+ traceId,
17
+ });
18
+ }
19
+
20
+ test("durable retry with a new request trace reattaches the same run", () => {
21
+ const store = new RuntimeStore(":memory:");
22
+ try {
23
+ const first = store.create(request("attempt-1"), "same-job-unit");
24
+ const replay = store.create(request("attempt-2"), "same-job-unit");
25
+ assert.equal(replay.fresh, false);
26
+ assert.equal(replay.run.id, first.run.id);
27
+ for (const changed of [
28
+ { userPrompt: "different input" },
29
+ { executionGrant: "other-actor-grant" },
30
+ { release: { releaseId: "release-2" } },
31
+ {
32
+ providerDataPolicy: {
33
+ inputFields: [],
34
+ envelopeFields: [
35
+ {
36
+ field: "user-prompt",
37
+ classification: "public",
38
+ dlpAction: "reject" as const,
39
+ },
40
+ ],
41
+ },
42
+ },
43
+ ]) {
44
+ assert.throws(
45
+ () =>
46
+ store.create(
47
+ { ...request("attempt-3"), ...changed },
48
+ "same-job-unit",
49
+ ),
50
+ /幂等键已用于其他请求/,
51
+ );
52
+ }
53
+ } finally {
54
+ store.db.close();
55
+ }
56
+ });
57
+
58
+ test("legacy persisted request digest recovers without deleting the old run", () => {
59
+ const store = new RuntimeStore(":memory:");
60
+ try {
61
+ const body = request("legacy-attempt");
62
+ const first = store.create(body, "legacy-job");
63
+ store.db
64
+ .prepare("UPDATE runs SET digest=? WHERE id=?")
65
+ .run(digest(body), first.run.id);
66
+ assert.equal(
67
+ store.create(request("recovery-attempt"), "legacy-job").run.id,
68
+ first.run.id,
69
+ );
70
+ assert.equal(store.events(first.run.id).length, 1);
71
+ } finally {
72
+ store.db.close();
73
+ }
74
+ });
@@ -0,0 +1,324 @@
1
+ import { DatabaseSync } from "node:sqlite";
2
+ import { mkdirSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import { randomUUID } from "node:crypto";
5
+ import {
6
+ SafeError,
7
+ type CanonicalEvent,
8
+ type RunRequest,
9
+ type RunStatus,
10
+ } from "./contracts.js";
11
+ import {
12
+ matchesRunRequestDigest,
13
+ runRequestDigest,
14
+ } from "./run-request-digest.js";
15
+ export interface StoredRun {
16
+ id: string;
17
+ status: RunStatus;
18
+ request: RunRequest;
19
+ output?: unknown;
20
+ createdAt: string;
21
+ }
22
+ export class RuntimeStore {
23
+ readonly db: DatabaseSync;
24
+ private readonly listeners = new Map<string, Set<() => void>>();
25
+ private readonly activeAuthority = new Map<string, string>();
26
+ constructor(
27
+ path: string,
28
+ private readonly providerAuditRetentionDays = 190,
29
+ ) {
30
+ if (
31
+ !Number.isSafeInteger(providerAuditRetentionDays) ||
32
+ providerAuditRetentionDays < 1 ||
33
+ providerAuditRetentionDays > 3650
34
+ )
35
+ throw new Error("AI_PROVIDER_AUDIT_RETENTION_DAYS invalid");
36
+ if (path !== ":memory:")
37
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
38
+ this.db = new DatabaseSync(path);
39
+ this.db.exec(`PRAGMA journal_mode=WAL; PRAGMA busy_timeout=5000;
40
+ CREATE TABLE IF NOT EXISTS runs(id TEXT PRIMARY KEY, idempotency TEXT UNIQUE NOT NULL, digest TEXT NOT NULL, status TEXT NOT NULL, request TEXT NOT NULL, output TEXT, created_at TEXT NOT NULL);
41
+ CREATE TABLE IF NOT EXISTS events(run_id TEXT NOT NULL, sequence INTEGER NOT NULL, value TEXT NOT NULL, PRIMARY KEY(run_id,sequence));
42
+ CREATE TABLE IF NOT EXISTS attempts(run_id TEXT NOT NULL, sequence INTEGER NOT NULL, value TEXT NOT NULL, PRIMARY KEY(run_id,sequence));
43
+ CREATE TABLE IF NOT EXISTS provider_audit(id INTEGER PRIMARY KEY, value TEXT NOT NULL, created_at TEXT NOT NULL);
44
+ CREATE TABLE IF NOT EXISTS provider_audit_retention(singleton INTEGER PRIMARY KEY CHECK(singleton=1), last_purge_at REAL, last_deleted INTEGER NOT NULL, total_deleted INTEGER NOT NULL);
45
+ INSERT OR IGNORE INTO provider_audit_retention VALUES(1,NULL,0,0);`);
46
+ const cutoff = new Date(Date.now() - 90 * 86400000).toISOString();
47
+ this.db
48
+ .prepare(
49
+ "DELETE FROM events WHERE run_id IN (SELECT id FROM runs WHERE created_at<?)",
50
+ )
51
+ .run(cutoff);
52
+ this.db
53
+ .prepare(
54
+ "DELETE FROM attempts WHERE run_id IN (SELECT id FROM runs WHERE created_at<?)",
55
+ )
56
+ .run(cutoff);
57
+ this.db.prepare("DELETE FROM runs WHERE created_at<?").run(cutoff);
58
+ this.purgeExpiredAudit();
59
+ const interrupted = this.db
60
+ .prepare(
61
+ "SELECT id FROM runs WHERE status IN ('accepted','running','awaiting-approval')",
62
+ )
63
+ .all() as { id: string }[];
64
+ for (const row of interrupted)
65
+ this.event(
66
+ row.id,
67
+ "run.failed",
68
+ {
69
+ error: {
70
+ code: "STREAM_INTERRUPTED",
71
+ message: "服务重启中断执行,请重新发起",
72
+ retryable: true,
73
+ requestId: `request_${randomUUID()}`,
74
+ },
75
+ },
76
+ "failed",
77
+ );
78
+ }
79
+ create(request: RunRequest, key: string): { run: StoredRun; fresh: boolean } {
80
+ const existing = this.db
81
+ .prepare("SELECT id,digest,request FROM runs WHERE idempotency=?")
82
+ .get(key) as { id: string; digest: string; request: string } | undefined;
83
+ if (existing) {
84
+ if (!matchesRunRequestDigest(request, existing.digest, existing.request))
85
+ throw new SafeError("RUN_CONFLICT", "幂等键已用于其他请求");
86
+ return { run: this.get(existing.id), fresh: false };
87
+ }
88
+ const run: StoredRun = {
89
+ id: `run_${randomUUID().replaceAll("-", "")}`,
90
+ request,
91
+ status: "accepted",
92
+ createdAt: new Date().toISOString(),
93
+ };
94
+ const size = this.db
95
+ .prepare("SELECT COUNT(*) AS count FROM runs")
96
+ .get() as { count: number };
97
+ if (size.count >= 10000)
98
+ throw new SafeError(
99
+ "BUDGET_EXCEEDED",
100
+ "Agent Run 留存容量已满",
101
+ true,
102
+ 429,
103
+ );
104
+ this.db
105
+ .prepare(
106
+ "INSERT INTO runs(id,idempotency,digest,status,request,created_at) VALUES(?,?,?,?,?,?)",
107
+ )
108
+ .run(
109
+ run.id,
110
+ key,
111
+ runRequestDigest(request),
112
+ run.status,
113
+ JSON.stringify({ ...request, executionGrant: "" }),
114
+ run.createdAt,
115
+ );
116
+ this.activeAuthority.set(run.id, request.executionGrant);
117
+ this.event(run.id, "run.accepted");
118
+ return { run, fresh: true };
119
+ }
120
+ get(id: string): StoredRun {
121
+ const row = this.db.prepare("SELECT * FROM runs WHERE id=?").get(id) as
122
+ | {
123
+ id: string;
124
+ status: RunStatus;
125
+ request: string;
126
+ output: string | null;
127
+ created_at: string;
128
+ }
129
+ | undefined;
130
+ if (!row)
131
+ throw new SafeError("RUN_CONFLICT", "Agent Run 不存在", false, 404);
132
+ return {
133
+ id: row.id,
134
+ status: row.status,
135
+ request: {
136
+ ...JSON.parse(row.request),
137
+ executionGrant: this.activeAuthority.get(id) ?? "",
138
+ },
139
+ output: row.output ? JSON.parse(row.output) : undefined,
140
+ createdAt: row.created_at,
141
+ };
142
+ }
143
+ events(id: string, after = 0): CanonicalEvent[] {
144
+ return (
145
+ this.db
146
+ .prepare(
147
+ "SELECT value FROM events WHERE run_id=? AND sequence>? ORDER BY sequence",
148
+ )
149
+ .all(id, after) as { value: string }[]
150
+ ).map((row) => JSON.parse(row.value));
151
+ }
152
+ event(
153
+ id: string,
154
+ type: string,
155
+ fields: Record<string, unknown> = {},
156
+ status?: RunStatus,
157
+ ) {
158
+ const row = this.db
159
+ .prepare(
160
+ "SELECT COALESCE(MAX(sequence),0)+1 AS seq FROM events WHERE run_id=?",
161
+ )
162
+ .get(id) as { seq: number };
163
+ const value: CanonicalEvent = {
164
+ type,
165
+ runId: id,
166
+ sequence: row.seq,
167
+ ...fields,
168
+ };
169
+ this.db.exec("BEGIN IMMEDIATE");
170
+ try {
171
+ this.db
172
+ .prepare("INSERT INTO events VALUES(?,?,?)")
173
+ .run(id, row.seq, JSON.stringify(value));
174
+ if (status)
175
+ this.db.prepare("UPDATE runs SET status=? WHERE id=?").run(status, id);
176
+ this.db.exec("COMMIT");
177
+ } catch (error) {
178
+ this.db.exec("ROLLBACK");
179
+ throw error;
180
+ }
181
+ if (status && terminal(status)) this.activeAuthority.delete(id);
182
+ for (const listener of this.listeners.get(id) ?? []) listener();
183
+ return value;
184
+ }
185
+ complete(id: string, output: unknown, attestation: unknown) {
186
+ this.db
187
+ .prepare("UPDATE runs SET output=? WHERE id=?")
188
+ .run(JSON.stringify(output), id);
189
+ this.event(id, "run.completed", { attestation }, "completed");
190
+ }
191
+ audit(value: Record<string, unknown>) {
192
+ this.purgeExpiredAudit();
193
+ this.db
194
+ .prepare("INSERT INTO provider_audit(value,created_at) VALUES(?,?)")
195
+ .run(JSON.stringify(value), new Date().toISOString());
196
+ }
197
+ private purgeExpiredAudit() {
198
+ const now = Date.now(),
199
+ cutoff = new Date(
200
+ now - this.providerAuditRetentionDays * 86400000,
201
+ ).toISOString();
202
+ this.db.exec("BEGIN IMMEDIATE");
203
+ try {
204
+ const result = this.db
205
+ .prepare("DELETE FROM provider_audit WHERE created_at<?")
206
+ .run(cutoff);
207
+ this.db
208
+ .prepare(
209
+ "UPDATE provider_audit_retention SET last_purge_at=?, last_deleted=?, total_deleted=total_deleted+? WHERE singleton=1",
210
+ )
211
+ .run(now / 1000, result.changes, result.changes);
212
+ this.db.exec("COMMIT");
213
+ } catch (error) {
214
+ this.db.exec("ROLLBACK");
215
+ throw error;
216
+ }
217
+ }
218
+ startAttempt(
219
+ runId: string,
220
+ sequence: number,
221
+ deploymentKey: string,
222
+ model: string,
223
+ ) {
224
+ const value = {
225
+ attemptId: `${runId}_attempt_${sequence}`,
226
+ sequence,
227
+ toolRound: sequence,
228
+ deploymentKey,
229
+ requestedModel: model,
230
+ reportedModel: null,
231
+ model,
232
+ outcome: "running",
233
+ cacheStatus: "unknown",
234
+ usageSource: "unknown",
235
+ inputTokens: null,
236
+ outputTokens: null,
237
+ cachedInputTokens: null,
238
+ reasoningTokens: null,
239
+ totalTokens: null,
240
+ firstTokenLatencyMs: null,
241
+ durationMs: null,
242
+ safeErrorCode: null,
243
+ startedAt: new Date().toISOString(),
244
+ finishedAt: null,
245
+ };
246
+ this.db
247
+ .prepare("INSERT INTO attempts VALUES(?,?,?)")
248
+ .run(runId, sequence, JSON.stringify(value));
249
+ }
250
+ finishAttempt(
251
+ runId: string,
252
+ sequence: number,
253
+ fields: Record<string, unknown>,
254
+ ) {
255
+ const row = this.db
256
+ .prepare("SELECT value FROM attempts WHERE run_id=? AND sequence=?")
257
+ .get(runId, sequence) as { value: string };
258
+ const value = JSON.parse(row.value) as { startedAt: string };
259
+ this.db
260
+ .prepare("UPDATE attempts SET value=? WHERE run_id=? AND sequence=?")
261
+ .run(
262
+ JSON.stringify({
263
+ ...value,
264
+ ...fields,
265
+ finishedAt: new Date().toISOString(),
266
+ durationMs: Math.max(0, Date.now() - Date.parse(value.startedAt)),
267
+ }),
268
+ runId,
269
+ sequence,
270
+ );
271
+ }
272
+ attempts(runId: string): Record<string, unknown>[] {
273
+ return (
274
+ this.db
275
+ .prepare("SELECT value FROM attempts WHERE run_id=? ORDER BY sequence")
276
+ .all(runId) as { value: string }[]
277
+ ).map((row) => JSON.parse(row.value));
278
+ }
279
+ auditHealth() {
280
+ const row = this.db
281
+ .prepare(
282
+ "SELECT COUNT(*) AS count, MAX(created_at) AS last, COALESCE(SUM(json_extract(value,'$.decision')='reject'),0) AS rejected, COALESCE(SUM(json_extract(value,'$.decision')='redact'),0) AS redacted FROM provider_audit",
283
+ )
284
+ .get() as {
285
+ count: number;
286
+ last: string | null;
287
+ rejected: number;
288
+ redacted: number;
289
+ };
290
+ const retention = this.db
291
+ .prepare("SELECT * FROM provider_audit_retention WHERE singleton=1")
292
+ .get() as {
293
+ last_purge_at: number | null;
294
+ last_deleted: number;
295
+ total_deleted: number;
296
+ };
297
+ return {
298
+ status: "healthy",
299
+ retentionDays: this.providerAuditRetentionDays,
300
+ retainedRecords: row.count,
301
+ rejectedAttempts: row.rejected,
302
+ redactedAttempts: row.redacted,
303
+ lastAttemptAt: row.last,
304
+ lastPurgeAt: retention.last_purge_at,
305
+ lastDeletedRecords: retention.last_deleted,
306
+ totalDeletedRecords: retention.total_deleted,
307
+ };
308
+ }
309
+ subscribe(id: string, listener: () => void) {
310
+ const set = this.listeners.get(id) ?? new Set();
311
+ set.add(listener);
312
+ this.listeners.set(id, set);
313
+ return () => {
314
+ set.delete(listener);
315
+ if (!set.size) this.listeners.delete(id);
316
+ };
317
+ }
318
+ close() {
319
+ this.activeAuthority.clear();
320
+ this.db.close();
321
+ }
322
+ }
323
+ export const terminal = (status: RunStatus) =>
324
+ ["completed", "failed", "cancelled"].includes(status);
@@ -0,0 +1,51 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { configFromEnvironment } from "./config.js";
4
+ import {
5
+ runtime,
6
+ input,
7
+ request,
8
+ providerPayloads,
9
+ } from "./runtime-test-fixtures.js";
10
+
11
+ test("structured output defaults to strict schema and rejects unknown modes", () => {
12
+ assert.equal(configFromEnvironment({}).structuredOutputMode, "json_schema");
13
+ assert.throws(
14
+ () => configFromEnvironment({ QWEN_STRUCTURED_OUTPUT_MODE: "relaxed" }),
15
+ /QWEN_STRUCTURED_OUTPUT_MODE invalid/,
16
+ );
17
+ });
18
+
19
+ for (const invalid of [false, true]) {
20
+ test(`explicit JSON mode retains full schema and ${invalid ? "rejects invalid" : "accepts valid"} provider output`, async () => {
21
+ const handler = runtime({ QWEN_STRUCTURED_OUTPUT_MODE: "json_object" });
22
+ try {
23
+ const body = input();
24
+ if (invalid)
25
+ body.outputSchema = {
26
+ type: "object",
27
+ properties: { answer: { type: "integer" } },
28
+ required: ["answer"],
29
+ additionalProperties: false,
30
+ };
31
+ const start = await handler(request("/api/agent/runs", "POST", body));
32
+ assert.equal(start?.status, 200);
33
+ const run = (await start!.json()) as { eventsUrl: string };
34
+ const response = await handler(request(run.eventsUrl));
35
+ const events = await response!.text();
36
+ assert.match(
37
+ events,
38
+ invalid ? /OUTPUT_VALIDATION_FAILED/ : /event: run.completed/,
39
+ );
40
+ const payload = providerPayloads.at(-1)!;
41
+ assert.deepEqual(payload.response_format, { type: "json_object" });
42
+ assert.ok(
43
+ JSON.stringify(payload.messages).includes(
44
+ JSON.stringify(body.outputSchema).replaceAll('"', '\\"'),
45
+ ),
46
+ );
47
+ } finally {
48
+ await handler.close();
49
+ }
50
+ });
51
+ }
@@ -0,0 +1,6 @@
1
+ import { createHash } from "node:crypto";
2
+ /** Stable provider-portable name; the original business key stays at Tool Host. */
3
+ export function businessToolName(key: string): string {
4
+ const label = key.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 35) || "tool";
5
+ return `business_${label}_${createHash("sha256").update(key).digest("hex").slice(0, 16)}`;
6
+ }
@@ -0,0 +1,201 @@
1
+ import type { Context } from "@deepseek-ai/cordis";
2
+ import type { JsonValue } from "@deepseek-ai/dsh-util-values";
3
+ import { digest, SafeError, type RunRequest } from "./contracts.js";
4
+ import type { RuntimeConfig } from "./config.js";
5
+ import type { RuntimeStore } from "./store.js";
6
+ import type { ExecutionBudget } from "./model-plugin.js";
7
+ import { businessToolName } from "./tool-name.js";
8
+ export interface ToolSource {
9
+ toolCallId: string;
10
+ toolKey: string;
11
+ toolLabel: string;
12
+ preview: {
13
+ contentType: "application/json";
14
+ content: string;
15
+ byteSize: number;
16
+ truncated: boolean;
17
+ };
18
+ snapshotDigest: string;
19
+ }
20
+ export function registerBusinessTools(
21
+ ctx: Context,
22
+ request: RunRequest,
23
+ runId: string,
24
+ config: RuntimeConfig,
25
+ store: RuntimeStore,
26
+ budget: ExecutionBudget,
27
+ sources: ToolSource[],
28
+ ) {
29
+ for (const tool of request.allowedTools)
30
+ ctx.tools.register({
31
+ name: businessToolName(tool.key),
32
+ description: `业务工具 ${tool.key}(实际调用名 ${businessToolName(tool.key)})。${tool.label}: ${tool.description}`,
33
+ parameters: tool.inputSchema,
34
+ output: {
35
+ schema: {},
36
+ render: (_args, value) => [
37
+ { type: "text", text: JSON.stringify(value) },
38
+ ],
39
+ },
40
+ async execute(args, execution) {
41
+ if (++budget.toolCalls > (request.limits.maxToolCalls ?? 32))
42
+ throw new SafeError("BUDGET_EXCEEDED", "工具调用次数达到上限");
43
+ if (
44
+ !request.executionGrant ||
45
+ request.toolNetworkPolicy.mode !== "forbidden"
46
+ )
47
+ throw new SafeError("TOOL_DENIED", "业务工具未获授权");
48
+ const host = new URL(request.toolHostUrl || config.toolHostUrl),
49
+ allowed = new URL(config.toolHostUrl);
50
+ if (
51
+ host.origin !== allowed.origin ||
52
+ host.pathname.replace(/\/$/, "") !==
53
+ allowed.pathname.replace(/\/$/, "") ||
54
+ host.username ||
55
+ host.password ||
56
+ host.search ||
57
+ host.hash
58
+ )
59
+ throw new SafeError("TOOL_DENIED", "业务 Tool Host 不在授权范围");
60
+ const callId = `tool_${digest({ runId, toolKey: tool.key, arguments: args }).slice(7, 47)}`;
61
+ store.event(runId, "tool.requested", {
62
+ toolCallId: callId,
63
+ toolKey: tool.key,
64
+ toolLabel: tool.label,
65
+ });
66
+ let approval: string | undefined;
67
+ const deadline =
68
+ Date.now() +
69
+ Math.min(
70
+ (tool.approvalTimeoutSeconds ?? 300) * 1000,
71
+ request.limits.maxDurationSeconds * 1000,
72
+ );
73
+ for (;;) {
74
+ execution.signal.throwIfAborted();
75
+ const response = await fetch(
76
+ `${host.href.replace(/\/$/, "")}/api/internal/agent/tools/execute`,
77
+ {
78
+ method: "POST",
79
+ signal: execution.signal,
80
+ redirect: "error",
81
+ headers: {
82
+ authorization: `Bearer ${config.internalToken}`,
83
+ "content-type": "application/json",
84
+ },
85
+ body: JSON.stringify({
86
+ executionGrant: request.executionGrant,
87
+ runId,
88
+ toolCallId: callId,
89
+ toolKey: tool.key,
90
+ arguments: args,
91
+ }),
92
+ },
93
+ );
94
+ const bytes = await boundedBody(
95
+ response,
96
+ request.limits.maxOutputBytes,
97
+ );
98
+ let body: Record<string, unknown>;
99
+ try {
100
+ body = JSON.parse(bytes);
101
+ } catch {
102
+ throw new SafeError("TOOL_DENIED", "业务 Tool Host 响应无效");
103
+ }
104
+ if (
105
+ response.status === 202 &&
106
+ body.code === "APPROVAL_REQUIRED" &&
107
+ typeof body.workItemId === "string"
108
+ ) {
109
+ if (!approval) {
110
+ approval = body.workItemId;
111
+ store.event(
112
+ runId,
113
+ "approval.required",
114
+ { workItemId: approval, toolCallId: callId },
115
+ "awaiting-approval",
116
+ );
117
+ }
118
+ if (Date.now() >= deadline)
119
+ throw new SafeError("RUN_TIMEOUT", "等待审批超时");
120
+ await abortableDelay(500, execution.signal);
121
+ continue;
122
+ }
123
+ if (approval)
124
+ store.event(
125
+ runId,
126
+ "approval.resolved",
127
+ {
128
+ workItemId: approval,
129
+ toolCallId: callId,
130
+ outcome: response.ok ? "approved" : "rejected",
131
+ },
132
+ "running",
133
+ );
134
+ if (!response.ok || !("value" in body))
135
+ throw new SafeError("TOOL_DENIED", "业务工具执行被拒绝");
136
+ const encoded = JSON.stringify(body.value),
137
+ byteSize = Buffer.byteLength(encoded);
138
+ const preview = {
139
+ contentType: "application/json" as const,
140
+ content: byteSize <= 8192 ? encoded : encoded.slice(0, 2048),
141
+ byteSize,
142
+ truncated: byteSize > 8192,
143
+ };
144
+ const snapshotDigest = digest(body.value);
145
+ if (sources.length < 12)
146
+ sources.push({
147
+ toolCallId: callId,
148
+ toolKey: tool.key,
149
+ toolLabel: tool.label,
150
+ preview,
151
+ snapshotDigest,
152
+ });
153
+ store.event(runId, "tool.completed", {
154
+ toolCallId: callId,
155
+ sourcePreview: preview,
156
+ sourceSnapshotDigest: snapshotDigest,
157
+ });
158
+ return body.value as JsonValue;
159
+ }
160
+ },
161
+ });
162
+ }
163
+ export async function boundedBody(
164
+ response: Response,
165
+ max: number,
166
+ ): Promise<string> {
167
+ if (!response.body) throw new SafeError("TOOL_DENIED", "上游响应为空");
168
+ const reader = response.body.getReader(),
169
+ parts: Uint8Array[] = [];
170
+ let size = 0;
171
+ try {
172
+ for (;;) {
173
+ const chunk = await reader.read();
174
+ if (chunk.done) break;
175
+ size += chunk.value.length;
176
+ if (size > max)
177
+ throw new SafeError("BUDGET_EXCEEDED", "上游响应超过上限");
178
+ parts.push(chunk.value);
179
+ }
180
+ } finally {
181
+ await reader.cancel();
182
+ }
183
+ return Buffer.concat(parts).toString("utf8");
184
+ }
185
+ function abortableDelay(ms: number, signal: AbortSignal): Promise<void> {
186
+ return new Promise((resolve, reject) => {
187
+ if (signal.aborted) {
188
+ reject(signal.reason);
189
+ return;
190
+ }
191
+ const onAbort = () => {
192
+ clearTimeout(timer);
193
+ reject(signal.reason);
194
+ };
195
+ const timer = setTimeout(() => {
196
+ signal.removeEventListener("abort", onAbort);
197
+ resolve();
198
+ }, ms);
199
+ signal.addEventListener("abort", onAbort, { once: true });
200
+ });
201
+ }