create-windy 0.3.2 → 0.3.5

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 (343) hide show
  1. package/README.md +27 -9
  2. package/dist/cli.js +825 -117
  3. package/package.json +1 -1
  4. package/template/.agents/skills/windy-business-module/SKILL.md +16 -3
  5. package/template/.windy-template.json +2 -2
  6. package/template/AGENTS.md +4 -0
  7. package/template/README.md +18 -11
  8. package/template/_gitignore +1 -0
  9. package/template/apps/agent-server/README.md +2 -0
  10. package/template/apps/agent-server/pyproject.toml +8 -0
  11. package/template/apps/agent-server/src/southwind_agent_server/adk_adapter.py +87 -10
  12. package/template/apps/agent-server/src/southwind_agent_server/adk_model.py +18 -3
  13. package/template/apps/agent-server/src/southwind_agent_server/adk_tools.py +78 -11
  14. package/template/apps/agent-server/src/southwind_agent_server/app.py +120 -115
  15. package/template/apps/agent-server/src/southwind_agent_server/artifact_input.py +153 -0
  16. package/template/apps/agent-server/src/southwind_agent_server/config.py +29 -0
  17. package/template/apps/agent-server/src/southwind_agent_server/contracts.py +81 -1
  18. package/template/apps/agent-server/src/southwind_agent_server/deterministic.py +8 -0
  19. package/template/apps/agent-server/src/southwind_agent_server/engine.py +28 -0
  20. package/template/apps/agent-server/src/southwind_agent_server/fingerprint.py +41 -0
  21. package/template/apps/agent-server/src/southwind_agent_server/http_helpers.py +62 -0
  22. package/template/apps/agent-server/src/southwind_agent_server/lease.py +15 -0
  23. package/template/apps/agent-server/src/southwind_agent_server/multimodal.py +76 -0
  24. package/template/apps/agent-server/src/southwind_agent_server/openai_engine.py +112 -20
  25. package/template/apps/agent-server/src/southwind_agent_server/openai_provider.py +14 -1
  26. package/template/apps/agent-server/src/southwind_agent_server/postgres_store.py +329 -0
  27. package/template/apps/agent-server/src/southwind_agent_server/postgres_store_backend.py +332 -0
  28. package/template/apps/agent-server/src/southwind_agent_server/provider_governance.py +64 -3
  29. package/template/apps/agent-server/src/southwind_agent_server/runtime_factory.py +68 -0
  30. package/template/apps/agent-server/src/southwind_agent_server/service.py +218 -56
  31. package/template/apps/agent-server/src/southwind_agent_server/signal_events.py +36 -0
  32. package/template/apps/agent-server/src/southwind_agent_server/sqlite_catalog.py +107 -0
  33. package/template/apps/agent-server/src/southwind_agent_server/sqlite_schema.py +65 -0
  34. package/template/apps/agent-server/src/southwind_agent_server/sqlite_serialization.py +16 -0
  35. package/template/apps/agent-server/src/southwind_agent_server/sqlite_store.py +89 -57
  36. package/template/apps/agent-server/src/southwind_agent_server/store.py +105 -2
  37. package/template/apps/agent-server/src/southwind_agent_server/store_cipher.py +40 -0
  38. package/template/apps/agent-server/src/southwind_agent_server/telemetry.py +89 -0
  39. package/template/apps/agent-server/src/southwind_agent_server/tool_host.py +72 -0
  40. package/template/apps/agent-server/tests/test_adk_adapter.py +6 -2
  41. package/template/apps/agent-server/tests/test_api.py +24 -1
  42. package/template/apps/agent-server/tests/test_artifact_input.py +110 -0
  43. package/template/apps/agent-server/tests/test_config.py +4 -0
  44. package/template/apps/agent-server/tests/test_fingerprint.py +10 -0
  45. package/template/apps/agent-server/tests/test_multimodal.py +51 -0
  46. package/template/apps/agent-server/tests/test_openai_provider.py +6 -2
  47. package/template/apps/agent-server/tests/test_postgres_store.py +131 -0
  48. package/template/apps/agent-server/tests/test_provider_governance.py +61 -0
  49. package/template/apps/agent-server/tests/test_sqlite_store.py +95 -10
  50. package/template/apps/agent-server/tests/test_telemetry.py +25 -0
  51. package/template/apps/agent-server/tests/test_tool_approval.py +28 -0
  52. package/template/apps/agent-server/uv.lock +165 -0
  53. package/template/apps/document-server/Dockerfile +19 -0
  54. package/template/apps/document-server/pyproject.toml +43 -0
  55. package/template/apps/document-server/src/southwind_document_server/__init__.py +1 -0
  56. package/template/apps/document-server/src/southwind_document_server/adapter.py +337 -0
  57. package/template/apps/document-server/src/southwind_document_server/app.py +151 -0
  58. package/template/apps/document-server/src/southwind_document_server/config.py +94 -0
  59. package/template/apps/document-server/src/southwind_document_server/contracts.py +103 -0
  60. package/template/apps/document-server/src/southwind_document_server/service.py +149 -0
  61. package/template/apps/document-server/src/southwind_document_server/store.py +185 -0
  62. package/template/apps/document-server/tests/__init__.py +1 -0
  63. package/template/apps/document-server/tests/test_config.py +42 -0
  64. package/template/apps/document-server/tests/test_service.py +140 -0
  65. package/template/apps/document-server/uv.lock +430 -0
  66. package/template/apps/embedding-server/Dockerfile +17 -0
  67. package/template/apps/embedding-server/pyproject.toml +44 -0
  68. package/template/apps/embedding-server/src/southwind_embedding_server/__init__.py +1 -0
  69. package/template/apps/embedding-server/src/southwind_embedding_server/adapter.py +254 -0
  70. package/template/apps/embedding-server/src/southwind_embedding_server/app.py +119 -0
  71. package/template/apps/embedding-server/src/southwind_embedding_server/config.py +120 -0
  72. package/template/apps/embedding-server/src/southwind_embedding_server/contracts.py +106 -0
  73. package/template/apps/embedding-server/src/southwind_embedding_server/error.py +6 -0
  74. package/template/apps/embedding-server/src/southwind_embedding_server/image_input.py +87 -0
  75. package/template/apps/embedding-server/tests/__init__.py +1 -0
  76. package/template/apps/embedding-server/tests/test_adapter.py +92 -0
  77. package/template/apps/embedding-server/tests/test_config.py +38 -0
  78. package/template/apps/embedding-server/uv.lock +449 -0
  79. package/template/apps/server/src/agent/background-operation-port.ts +37 -0
  80. package/template/apps/server/src/agent/background-operation.test.ts +231 -0
  81. package/template/apps/server/src/agent/background-operation.ts +252 -0
  82. package/template/apps/server/src/agent/drizzle-run-binding-repository.ts +114 -0
  83. package/template/apps/server/src/agent/execution-grants.ts +7 -1
  84. package/template/apps/server/src/agent/fake-runtime.test-support.ts +43 -0
  85. package/template/apps/server/src/agent/idempotency-key.test.ts +28 -0
  86. package/template/apps/server/src/agent/idempotency-key.ts +11 -0
  87. package/template/apps/server/src/agent/remote-runtime.test.ts +115 -1
  88. package/template/apps/server/src/agent/remote-runtime.ts +173 -5
  89. package/template/apps/server/src/agent/run-authorization.test-support.ts +9 -0
  90. package/template/apps/server/src/agent/run-authorization.test.ts +126 -0
  91. package/template/apps/server/src/agent/run-authorization.ts +180 -0
  92. package/template/apps/server/src/agent/run-binding-repository.ts +93 -0
  93. package/template/apps/server/src/agent/run-contracts.ts +88 -1
  94. package/template/apps/server/src/agent/run-definition-support.ts +58 -0
  95. package/template/apps/server/src/agent/run-errors.ts +25 -0
  96. package/template/apps/server/src/agent/run-facade.test.ts +57 -46
  97. package/template/apps/server/src/agent/run-facade.ts +185 -65
  98. package/template/apps/server/src/agent/run-release.ts +78 -0
  99. package/template/apps/server/src/agent/run-route-input.ts +169 -0
  100. package/template/apps/server/src/agent/run-routes.ts +63 -76
  101. package/template/apps/server/src/agent/runtime-bootstrap.ts +169 -13
  102. package/template/apps/server/src/agent/sandbox-client.ts +200 -0
  103. package/template/apps/server/src/agent/sandbox-protocol.ts +76 -0
  104. package/template/apps/server/src/agent/sandbox-registry.ts +205 -0
  105. package/template/apps/server/src/agent/sandbox-runtime.test.ts +137 -0
  106. package/template/apps/server/src/agent/sandbox-worker-server.ts +195 -0
  107. package/template/apps/server/src/agent/sandbox-worker.ts +12 -0
  108. package/template/apps/server/src/agent/tool-approval.test.ts +75 -0
  109. package/template/apps/server/src/agent/tool-approval.ts +115 -0
  110. package/template/apps/server/src/agent/tool-audit.ts +62 -0
  111. package/template/apps/server/src/agent/tool-host.test.ts +39 -11
  112. package/template/apps/server/src/agent/tool-host.ts +184 -17
  113. package/template/apps/server/src/agent/tool-registry.ts +52 -47
  114. package/template/apps/server/src/agent/vision-facade.test.ts +256 -0
  115. package/template/apps/server/src/agent/vision-input.ts +120 -0
  116. package/template/apps/server/src/ai-artifact/codec.test.ts +44 -0
  117. package/template/apps/server/src/ai-artifact/codec.ts +137 -0
  118. package/template/apps/server/src/ai-artifact/routes.ts +37 -0
  119. package/template/apps/server/src/ai-artifact/runtime.ts +205 -0
  120. package/template/apps/server/src/application-services.ts +62 -2
  121. package/template/apps/server/src/auth/reauthentication.test.ts +40 -0
  122. package/template/apps/server/src/auth/reauthentication.ts +19 -0
  123. package/template/apps/server/src/auth/runtime.ts +9 -1
  124. package/template/apps/server/src/data-access/context.ts +6 -4
  125. package/template/apps/server/src/data-access/scope-snapshot.ts +27 -0
  126. package/template/apps/server/src/data-governance/export/approval-port.ts +6 -3
  127. package/template/apps/server/src/data-governance/export/authorization-port.test.ts +23 -4
  128. package/template/apps/server/src/data-governance/export/authorization-port.ts +89 -25
  129. package/template/apps/server/src/data-governance/export/drizzle-repository.integration.test.ts +2 -0
  130. package/template/apps/server/src/data-governance/export/drizzle-repository.ts +1 -0
  131. package/template/apps/server/src/data-governance/export/job-runtime.test.ts +15 -4
  132. package/template/apps/server/src/data-governance/export/job-runtime.ts +68 -15
  133. package/template/apps/server/src/data-governance/export/ndjson-stream.ts +25 -6
  134. package/template/apps/server/src/data-governance/export/postgres-recovery.integration.test.ts +4 -2
  135. package/template/apps/server/src/data-governance/export/renderer-job-runtime.test.ts +235 -0
  136. package/template/apps/server/src/data-governance/export/renderer-runtime.ts +293 -0
  137. package/template/apps/server/src/data-governance/export/renderer-selection.test.ts +67 -0
  138. package/template/apps/server/src/data-governance/export/repository.test.ts +2 -0
  139. package/template/apps/server/src/data-governance/export/request-fingerprint.test.ts +13 -0
  140. package/template/apps/server/src/data-governance/export/request-fingerprint.ts +2 -0
  141. package/template/apps/server/src/data-governance/export/routes.ts +11 -1
  142. package/template/apps/server/src/data-governance/export/scope-snapshot.ts +6 -18
  143. package/template/apps/server/src/data-governance/export/service-support.ts +188 -0
  144. package/template/apps/server/src/data-governance/export/service.ts +90 -113
  145. package/template/apps/server/src/data-governance/export/source.ts +101 -0
  146. package/template/apps/server/src/data-governance/export/types.ts +27 -0
  147. package/template/apps/server/src/document/contracts.ts +76 -0
  148. package/template/apps/server/src/document/facade.ts +339 -0
  149. package/template/apps/server/src/document/remote-runtime.test.ts +96 -0
  150. package/template/apps/server/src/document/remote-runtime.ts +223 -0
  151. package/template/apps/server/src/document/routes.ts +193 -0
  152. package/template/apps/server/src/embedding/contracts.ts +83 -0
  153. package/template/apps/server/src/embedding/error.ts +10 -0
  154. package/template/apps/server/src/embedding/facade.ts +217 -0
  155. package/template/apps/server/src/embedding/input.ts +172 -0
  156. package/template/apps/server/src/embedding/remote-runtime.test.ts +66 -0
  157. package/template/apps/server/src/embedding/remote-runtime.ts +218 -0
  158. package/template/apps/server/src/embedding/routes.ts +152 -0
  159. package/template/apps/server/src/index.ts +40 -43
  160. package/template/apps/server/src/jobs/artifact-service.test.ts +14 -2
  161. package/template/apps/server/src/jobs/artifact-service.ts +10 -0
  162. package/template/apps/server/src/jobs/drizzle-execution-repository.ts +17 -18
  163. package/template/apps/server/src/jobs/drizzle-execution.integration.test.ts +19 -1
  164. package/template/apps/server/src/jobs/drizzle-mappers.ts +4 -1
  165. package/template/apps/server/src/jobs/drizzle-recovery-repository.ts +49 -2
  166. package/template/apps/server/src/jobs/drizzle-repository.ts +1 -0
  167. package/template/apps/server/src/jobs/execution-repository.ts +17 -0
  168. package/template/apps/server/src/jobs/execution.test.ts +34 -0
  169. package/template/apps/server/src/jobs/in-memory-control.ts +135 -0
  170. package/template/apps/server/src/jobs/in-memory-execution.ts +34 -65
  171. package/template/apps/server/src/jobs/legacy-service-runtime.ts +5 -2
  172. package/template/apps/server/src/jobs/repository.ts +3 -0
  173. package/template/apps/server/src/jobs/worker.ts +80 -41
  174. package/template/apps/server/src/module-host/ai-operation-port.ts +170 -0
  175. package/template/apps/server/src/module-host/durable-context.test.ts +312 -0
  176. package/template/apps/server/src/module-host/durable-context.ts +124 -0
  177. package/template/apps/server/src/module-host/durable-handler-registration.ts +72 -0
  178. package/template/apps/server/src/module-host/governed-export-route-support.ts +171 -0
  179. package/template/apps/server/src/module-host/governed-export-routes.test.ts +327 -0
  180. package/template/apps/server/src/module-host/governed-export-routes.ts +238 -0
  181. package/template/apps/server/src/module-host/governed-renderer-registration.test.ts +247 -0
  182. package/template/apps/server/src/module-host/governed-resource-routes.ts +331 -0
  183. package/template/apps/server/src/module-host/governed-resources.test.ts +344 -0
  184. package/template/apps/server/src/module-host/governed-resources.ts +203 -0
  185. package/template/apps/server/src/module-host/http-runtime.ts +95 -0
  186. package/template/apps/server/src/module-host/initialize-contracts.ts +14 -0
  187. package/template/apps/server/src/module-host/initialize.test.ts +49 -1
  188. package/template/apps/server/src/module-host/initialize.ts +39 -16
  189. package/template/apps/server/src/module-host/job-port.test.ts +262 -0
  190. package/template/apps/server/src/module-host/job-port.ts +334 -0
  191. package/template/apps/server/src/module-host/request-context.test.ts +88 -2
  192. package/template/apps/server/src/module-host/request-context.ts +56 -22
  193. package/template/apps/server/src/module-host/route-installer.test.ts +10 -0
  194. package/template/apps/server/src/module-host/route-installer.ts +36 -1
  195. package/template/apps/server/src/module-host/sandbox-tool-registration.ts +42 -0
  196. package/template/apps/server/src/module-host/tool-handlers.ts +67 -31
  197. package/template/apps/server/src/module-host.ts +1 -0
  198. package/template/apps/server/src/module-runtime-validation.ts +7 -3
  199. package/template/apps/server/src/speech/contracts.ts +76 -0
  200. package/template/apps/server/src/speech/facade.ts +316 -0
  201. package/template/apps/server/src/speech/remote-runtime.test.ts +88 -0
  202. package/template/apps/server/src/speech/remote-runtime.ts +227 -0
  203. package/template/apps/server/src/speech/routes.ts +180 -0
  204. package/template/apps/server/src/system/actor.ts +39 -0
  205. package/template/apps/server/src/system/route-helpers.ts +1 -0
  206. package/template/apps/server/src/workflow/service.ts +2 -1
  207. package/template/apps/speech-server/Dockerfile +22 -0
  208. package/template/apps/speech-server/pyproject.toml +43 -0
  209. package/template/apps/speech-server/src/southwind_speech_server/__init__.py +1 -0
  210. package/template/apps/speech-server/src/southwind_speech_server/adapter.py +249 -0
  211. package/template/apps/speech-server/src/southwind_speech_server/app.py +183 -0
  212. package/template/apps/speech-server/src/southwind_speech_server/config.py +100 -0
  213. package/template/apps/speech-server/src/southwind_speech_server/contracts.py +103 -0
  214. package/template/apps/speech-server/src/southwind_speech_server/errors.py +6 -0
  215. package/template/apps/speech-server/src/southwind_speech_server/normalizer.py +108 -0
  216. package/template/apps/speech-server/src/southwind_speech_server/output_validation.py +128 -0
  217. package/template/apps/speech-server/src/southwind_speech_server/service.py +162 -0
  218. package/template/apps/speech-server/src/southwind_speech_server/store.py +209 -0
  219. package/template/apps/speech-server/tests/__init__.py +1 -0
  220. package/template/apps/speech-server/tests/test_config.py +33 -0
  221. package/template/apps/speech-server/tests/test_service.py +154 -0
  222. package/template/apps/speech-server/uv.lock +430 -0
  223. package/template/apps/web/src/app/business-routes.ts +22 -0
  224. package/template/apps/web/src/components/common/AccessSnapshotBoundary.vue +112 -0
  225. package/template/apps/web/src/components/common/AccessSnapshotBoundary.webtest.ts +130 -0
  226. package/template/apps/web/src/components/common/AccessSnapshotNotice.vue +117 -0
  227. package/template/apps/web/src/components/common/FormDialog.vue +6 -0
  228. package/template/apps/web/src/components/common/ModalLayout.webtest.ts +13 -0
  229. package/template/apps/web/src/composables/access-snapshot-change.ts +131 -0
  230. package/template/apps/web/src/composables/access-snapshot-change.webtest.ts +103 -0
  231. package/template/apps/web/src/composables/useAccessSnapshot.ts +48 -2
  232. package/template/apps/web/src/composables/useAccessSnapshot.webtest.ts +54 -0
  233. package/template/apps/web/src/composables/useAccessSnapshotMonitor.ts +42 -0
  234. package/template/apps/web/src/layout/AppShell.vue +28 -25
  235. package/template/apps/web/src/layout/AppShell.webtest.ts +1 -0
  236. package/template/apps/web/src/router/business-routes.ts +68 -0
  237. package/template/apps/web/src/router/business-routes.webtest.ts +85 -0
  238. package/template/apps/web/src/router/index.ts +7 -0
  239. package/template/apps/web/src/router/shared-scaffold-neutrality.webtest.ts +12 -0
  240. package/template/apps/web/src/services/access-api.ts +5 -1
  241. package/template/apps/web/src/services/access-api.webtest.ts +35 -0
  242. package/template/docker-compose.yml +127 -0
  243. package/template/docs/architecture/ai-egress.md +12 -9
  244. package/template/docs/architecture/ai-runtime.md +23 -11
  245. package/template/docs/architecture/durable-jobs.md +25 -3
  246. package/template/docs/architecture/foundation-infrastructure.md +163 -0
  247. package/template/docs/architecture/module-host.md +115 -0
  248. package/template/docs/architecture/server-module-interface.md +39 -0
  249. package/template/docs/architecture/web-access-snapshot-resilience.md +60 -0
  250. package/template/docs/development/business-web-routes.md +66 -0
  251. package/template/docs/development/custom-login-page.md +3 -3
  252. package/template/docs/development/module-lifecycle.md +71 -0
  253. package/template/docs/operations/observability.md +5 -1
  254. package/template/docs/platform/agent-runtime.md +21 -11
  255. package/template/docs/platform/agent-tool-sandbox.md +58 -0
  256. package/template/docs/platform/agent-tools.md +5 -0
  257. package/template/docs/platform/document-ai-runtime.md +204 -0
  258. package/template/docs/platform/governed-export-renderers.md +132 -0
  259. package/template/docs/platform/navigation-registry.md +5 -0
  260. package/template/docs/platform/organization-membership.md +2 -1
  261. package/template/docs/platform/speech-ai-runtime.md +156 -0
  262. package/template/docs/platform/system-crud-api.md +7 -1
  263. package/template/docs/platform/vision-ai-runtime.md +97 -0
  264. package/template/docs/platform/web-system-crud.md +6 -0
  265. package/template/package.json +16 -2
  266. package/template/packages/ai-client/index.ts +4 -0
  267. package/template/packages/ai-client/package.json +5 -2
  268. package/template/packages/ai-client/src/agent/client/artifact.ts +26 -0
  269. package/template/packages/ai-client/src/agent/client/attach.test.ts +124 -0
  270. package/template/packages/ai-client/src/agent/client/client.ts +119 -7
  271. package/template/packages/ai-client/src/agent/client/run.ts +14 -0
  272. package/template/packages/ai-client/src/agent/client/types.ts +18 -0
  273. package/template/packages/ai-client/src/agent/client/vision.test.ts +53 -0
  274. package/template/packages/ai-client/src/agent/contracts/contracts.test.ts +1 -0
  275. package/template/packages/ai-client/src/agent/contracts/events.ts +33 -0
  276. package/template/packages/ai-client/src/agent/contracts/runs.ts +71 -0
  277. package/template/packages/ai-client/src/agent/index.ts +1 -0
  278. package/template/packages/ai-client/src/artifact-ref.ts +8 -0
  279. package/template/packages/ai-client/src/document/client.test.ts +114 -0
  280. package/template/packages/ai-client/src/document/client.ts +134 -0
  281. package/template/packages/ai-client/src/document/contracts.ts +152 -0
  282. package/template/packages/ai-client/src/document/error.ts +43 -0
  283. package/template/packages/ai-client/src/document/index.ts +3 -0
  284. package/template/packages/ai-client/src/document/run.ts +104 -0
  285. package/template/packages/ai-client/src/document/validation.ts +115 -0
  286. package/template/packages/ai-client/src/embedding/client.test.ts +77 -0
  287. package/template/packages/ai-client/src/embedding/client.ts +96 -0
  288. package/template/packages/ai-client/src/embedding/contracts.ts +46 -0
  289. package/template/packages/ai-client/src/embedding/error.ts +61 -0
  290. package/template/packages/ai-client/src/embedding/index.ts +3 -0
  291. package/template/packages/ai-client/src/embedding/validation.ts +117 -0
  292. package/template/packages/ai-client/src/speech/client.test.ts +135 -0
  293. package/template/packages/ai-client/src/speech/client.ts +104 -0
  294. package/template/packages/ai-client/src/speech/contracts.ts +129 -0
  295. package/template/packages/ai-client/src/speech/error.ts +43 -0
  296. package/template/packages/ai-client/src/speech/index.ts +3 -0
  297. package/template/packages/ai-client/src/speech/run.ts +133 -0
  298. package/template/packages/ai-client/src/speech/validation.ts +132 -0
  299. package/template/packages/config/package.json +2 -2
  300. package/template/packages/database/drizzle/0039_early_ezekiel_stane.sql +1 -0
  301. package/template/packages/database/drizzle/0040_colossal_baron_strucker.sql +63 -0
  302. package/template/packages/database/drizzle/0041_yummy_prowler.sql +21 -0
  303. package/template/packages/database/drizzle/0042_puzzling_rumiko_fujikawa.sql +27 -0
  304. package/template/packages/database/drizzle/meta/0039_snapshot.json +7755 -0
  305. package/template/packages/database/drizzle/meta/0040_snapshot.json +8150 -0
  306. package/template/packages/database/drizzle/meta/0041_snapshot.json +8323 -0
  307. package/template/packages/database/drizzle/meta/0042_snapshot.json +8541 -0
  308. package/template/packages/database/drizzle/meta/_journal.json +28 -0
  309. package/template/packages/database/package.json +2 -2
  310. package/template/packages/database/src/agent-runtime-schema.test.ts +54 -0
  311. package/template/packages/database/src/schema/agent-runtime.ts +149 -0
  312. package/template/packages/database/src/schema/common.ts +2 -14
  313. package/template/packages/database/src/schema/durable-jobs.ts +5 -0
  314. package/template/packages/database/src/schema/governed-exports.ts +17 -5
  315. package/template/packages/database/src/schema/index.ts +3 -0
  316. package/template/packages/database/src/schema-durable-recovery.test.ts +31 -0
  317. package/template/packages/database/src/schema-governed-exports.test.ts +21 -1
  318. package/template/packages/database/src/schema.test.ts +6 -23
  319. package/template/packages/jobs/package.json +3 -2
  320. package/template/packages/jobs/src/handlers.test.ts +13 -0
  321. package/template/packages/jobs/src/handlers.ts +7 -1
  322. package/template/packages/jobs/src/types.ts +4 -0
  323. package/template/packages/modules/package.json +2 -2
  324. package/template/packages/modules/src/ai-operation-composition.test-support.ts +165 -0
  325. package/template/packages/modules/src/ai-operation-composition.test.ts +91 -127
  326. package/template/packages/modules/src/ai-operation-composition.ts +59 -1
  327. package/template/packages/modules/src/manifest.ts +25 -1
  328. package/template/packages/modules/src/tool-composition.ts +18 -0
  329. package/template/packages/server-sdk/index.ts +50 -0
  330. package/template/packages/server-sdk/package.json +10 -4
  331. package/template/packages/server-sdk/src/ai-artifact-port.ts +34 -0
  332. package/template/packages/server-sdk/src/ai-operation-port.ts +65 -0
  333. package/template/packages/server-sdk/src/ai-operation-registration.ts +42 -1
  334. package/template/packages/server-sdk/src/background-ai-port.ts +43 -0
  335. package/template/packages/server-sdk/src/data-governance-registration.ts +116 -0
  336. package/template/packages/server-sdk/src/durable-handler.ts +29 -0
  337. package/template/packages/server-sdk/src/jobs-port.ts +69 -0
  338. package/template/packages/server-sdk/src/module-host.ts +16 -2
  339. package/template/packages/server-sdk/src/request-context.ts +6 -2
  340. package/template/packages/server-sdk/src/sandbox-tool.ts +21 -0
  341. package/template/packages/server-sdk/src/tool-registration.ts +2 -0
  342. package/template/packages/shared/package.json +1 -1
  343. package/template/packages/shared/src/rbac.ts +30 -0
@@ -0,0 +1,115 @@
1
+ import { createHash } from "node:crypto";
2
+ import type { ModuleAgentToolInvocation } from "@southwind-ai/server-sdk";
3
+ import type { RequestGuardContext } from "../guards.js";
4
+ import type { WorkflowService } from "../workflow/service.js";
5
+ import type { RegisteredTool } from "./tool-registry.js";
6
+
7
+ type ApprovalTool = Pick<
8
+ RegisteredTool,
9
+ "key" | "label" | "approval" | "approvalRoles" | "approvalTimeoutSeconds"
10
+ >;
11
+
12
+ export class AgentToolApprovalCoordinator {
13
+ constructor(private readonly workflow?: WorkflowService) {}
14
+
15
+ async requireApproved(
16
+ tool: ApprovalTool,
17
+ invocation: ModuleAgentToolInvocation,
18
+ context: RequestGuardContext,
19
+ ): Promise<string | undefined> {
20
+ if (tool.approval === "none") return undefined;
21
+ if (
22
+ !this.workflow ||
23
+ !tool.approvalRoles?.length ||
24
+ !tool.approvalTimeoutSeconds
25
+ ) {
26
+ throw new AgentToolApprovalError(
27
+ "APPROVAL_UNAVAILABLE",
28
+ "Agent Tool 审批服务不可用",
29
+ );
30
+ }
31
+ const idempotencyKey = approvalKey(invocation);
32
+ const workItemId = approvalWorkItemId(idempotencyKey);
33
+ const existing = await this.workflow.get(workItemId, context.actor);
34
+ const workItem =
35
+ existing ??
36
+ (await this.workflow.create(
37
+ {
38
+ id: workItemId,
39
+ title: `Agent 请求执行:${tool.label}`,
40
+ candidateRoles: [...tool.approvalRoles],
41
+ dueAt: new Date(
42
+ Date.parse(context.startedAt) + tool.approvalTimeoutSeconds * 1_000,
43
+ ).toISOString(),
44
+ target: {
45
+ type: "agent-tool-call",
46
+ id: `${invocation.runId}:${invocation.toolCallId}`,
47
+ route: `/system/workflow?workItemId=${encodeURIComponent(workItemId)}`,
48
+ },
49
+ idempotencyKey,
50
+ },
51
+ context.actor,
52
+ ));
53
+ const current =
54
+ (await this.workflow.get(workItem.id, context.actor)) ?? workItem;
55
+ if (current.status === "approved") return current.id;
56
+ if (current.status === "pending" || current.status === "claimed") {
57
+ throw new AgentToolApprovalPending(current.id);
58
+ }
59
+ throw new AgentToolApprovalError(
60
+ outcomeCode(current.status),
61
+ `Agent Tool 审批已${outcomeLabel(current.status)}`,
62
+ current.id,
63
+ );
64
+ }
65
+ }
66
+
67
+ export class AgentToolApprovalPending extends Error {
68
+ constructor(readonly workItemId: string) {
69
+ super("Agent Tool 等待人工审批");
70
+ this.name = "AgentToolApprovalPending";
71
+ }
72
+ }
73
+
74
+ export type AgentToolApprovalOutcome =
75
+ | "APPROVAL_REJECTED"
76
+ | "APPROVAL_CANCELLED"
77
+ | "APPROVAL_TIMED_OUT"
78
+ | "APPROVAL_UNAVAILABLE";
79
+
80
+ export class AgentToolApprovalError extends Error {
81
+ constructor(
82
+ readonly code: AgentToolApprovalOutcome,
83
+ message: string,
84
+ readonly workItemId?: string,
85
+ ) {
86
+ super(message);
87
+ this.name = "AgentToolApprovalError";
88
+ }
89
+ }
90
+
91
+ function approvalKey(invocation: ModuleAgentToolInvocation): string {
92
+ return `agent-tool:${createHash("sha256")
93
+ .update(
94
+ `${invocation.runId}\u0000${invocation.toolCallId}\u0000${invocation.toolKey}`,
95
+ )
96
+ .digest("hex")}`;
97
+ }
98
+
99
+ function approvalWorkItemId(idempotencyKey: string): string {
100
+ return `agent-tool-${idempotencyKey.slice("agent-tool:".length, 56)}`;
101
+ }
102
+
103
+ function outcomeCode(
104
+ status: "rejected" | "cancelled" | "timed-out",
105
+ ): AgentToolApprovalOutcome {
106
+ if (status === "rejected") return "APPROVAL_REJECTED";
107
+ if (status === "cancelled") return "APPROVAL_CANCELLED";
108
+ return "APPROVAL_TIMED_OUT";
109
+ }
110
+
111
+ function outcomeLabel(status: "rejected" | "cancelled" | "timed-out") {
112
+ if (status === "rejected") return "拒绝";
113
+ if (status === "cancelled") return "取消";
114
+ return "超时";
115
+ }
@@ -0,0 +1,62 @@
1
+ import type {
2
+ ModuleToolInput,
3
+ ModuleToolResult,
4
+ } from "@southwind-ai/server-sdk";
5
+ import type { AuditEvent } from "@southwind-ai/shared";
6
+ import { auditActor, type RequestGuardContext } from "../guards.js";
7
+ import type { RegisteredTool } from "./tool-registry.js";
8
+
9
+ export function toolJsonBytes(value: ModuleToolInput | ModuleToolResult) {
10
+ return new TextEncoder().encode(JSON.stringify(value)).byteLength;
11
+ }
12
+
13
+ export function toolEvent(
14
+ context: RequestGuardContext,
15
+ tool: RegisteredTool,
16
+ input: ModuleToolInput,
17
+ result: ModuleToolResult,
18
+ executionMode: "host" | "sandbox",
19
+ ): AuditEvent {
20
+ return {
21
+ id: crypto.randomUUID(),
22
+ action: tool.auditAction,
23
+ outcome: "success",
24
+ actor: auditActor(context),
25
+ target: { type: "agent-tool", id: tool.key, label: tool.label },
26
+ module: tool.module,
27
+ requestId: context.requestId,
28
+ metadata: {
29
+ inputBytes: toolJsonBytes(input),
30
+ outputBytes: toolJsonBytes(result),
31
+ executionMode,
32
+ },
33
+ occurredAt: new Date().toISOString(),
34
+ };
35
+ }
36
+
37
+ export function sandboxFailureEvent(
38
+ context: RequestGuardContext,
39
+ tool: RegisteredTool,
40
+ input: ModuleToolInput,
41
+ error: unknown,
42
+ ): AuditEvent {
43
+ const policyDenied =
44
+ error instanceof Error &&
45
+ "code" in error &&
46
+ error.code === "SANDBOX_POLICY_DENIED";
47
+ return {
48
+ id: crypto.randomUUID(),
49
+ action: tool.auditAction,
50
+ outcome: policyDenied ? "denied" : "failure",
51
+ actor: auditActor(context),
52
+ target: { type: "agent-tool", id: tool.key, label: tool.label },
53
+ module: tool.module,
54
+ requestId: context.requestId,
55
+ metadata: {
56
+ inputBytes: toolJsonBytes(input),
57
+ executionMode: "sandbox",
58
+ failureKind: policyDenied ? "policy-denied" : "business-failure",
59
+ },
60
+ occurredAt: new Date().toISOString(),
61
+ };
62
+ }
@@ -7,7 +7,9 @@ import { featureKey } from "@southwind-ai/shared";
7
7
  import { buildScopeContext } from "../data-access/context.js";
8
8
  import { createRequestGuardContext } from "../guards.js";
9
9
  import { createServerRuntime } from "../runtime.js";
10
- import { ExecutionGrantStore } from "./execution-grants.js";
10
+ import type { InitializedModuleHosts } from "../module-host.js";
11
+ import { createTestRunAuthorizationStore } from "./run-authorization.test-support.js";
12
+ import { buildAgentRuntimeRelease } from "./run-release.js";
11
13
  import {
12
14
  AgentToolHostError,
13
15
  attachExecutionGrant,
@@ -37,7 +39,7 @@ const operation: ModuleAiOperationDefinition = {
37
39
 
38
40
  describe("受限 Agent Tool Host", () => {
39
41
  test("只接受 Grant 绑定 Operation 的 allowedToolKeys", async () => {
40
- const fixture = createFixture();
42
+ const fixture = await createFixture();
41
43
  const invocation = attachExecutionGrant(
42
44
  {
43
45
  runId: "run_1",
@@ -56,7 +58,7 @@ describe("受限 Agent Tool Host", () => {
56
58
  });
57
59
 
58
60
  test("未知 Tool fail closed 且客户端不能提供权限事实", async () => {
59
- const fixture = createFixture({
61
+ const fixture = await createFixture({
60
62
  allowedToolKeys: ["business.unknown"],
61
63
  });
62
64
  const invocation = attachExecutionGrant(
@@ -78,7 +80,7 @@ describe("受限 Agent Tool Host", () => {
78
80
  });
79
81
 
80
82
  test("Tool 不继承 Provider 出网权限且未知网络模式 fail closed", async () => {
81
- const fixture = createFixture({
83
+ const fixture = await createFixture({
82
84
  providerEgress: {
83
85
  mode: "configured-endpoint",
84
86
  deploymentKey: "ai.openai-compatible",
@@ -103,7 +105,7 @@ describe("受限 Agent Tool Host", () => {
103
105
  });
104
106
 
105
107
  test("使用宿主颁发 Actor 与 Scope 执行 Handler", async () => {
106
- const fixture = createFixture();
108
+ const fixture = await createFixture();
107
109
  const result = await fixture.host.execute(
108
110
  attachExecutionGrant(
109
111
  {
@@ -132,7 +134,9 @@ describe("受限 Agent Tool Host", () => {
132
134
  });
133
135
  });
134
136
 
135
- function createFixture(overrides: Partial<ModuleAiOperationDefinition> = {}) {
137
+ async function createFixture(
138
+ overrides: Partial<ModuleAiOperationDefinition> = {},
139
+ ) {
136
140
  const currentOperation = { ...operation, ...overrides };
137
141
  const module = manifest(currentOperation);
138
142
  const runtime = createServerRuntime(
@@ -163,9 +167,30 @@ function createFixture(overrides: Partial<ModuleAiOperationDefinition> = {}) {
163
167
  resolveLicense: () => ({ status: "valid" }),
164
168
  },
165
169
  );
166
- const grants = new ExecutionGrantStore();
167
- const grant = grants.issue(currentOperation, context);
168
- grants.bindRun(grant.token, "run_1");
170
+ const hosts = {
171
+ aiOperationHandlers: [],
172
+ } as unknown as InitializedModuleHosts;
173
+ const authorizations = createTestRunAuthorizationStore();
174
+ const grant = await authorizations.issue({
175
+ operationKey: currentOperation.key,
176
+ releaseId: buildAgentRuntimeRelease(
177
+ [module],
178
+ module,
179
+ currentOperation,
180
+ undefined,
181
+ ).releaseId,
182
+ idempotencyKey: "tool-host-test",
183
+ authorizationSnapshot: {
184
+ permissionKey: currentOperation.permissionKey,
185
+ featureKey: currentOperation.featureKey,
186
+ allowedToolKeys: [...currentOperation.allowedToolKeys],
187
+ toolNetworkMode: ((
188
+ currentOperation.toolNetworkPolicy as { mode?: string } | undefined
189
+ )?.mode ?? "forbidden") as "forbidden",
190
+ },
191
+ context,
192
+ });
193
+ await authorizations.bind(grant, "run_1");
169
194
  const called: unknown[] = [];
170
195
  const handlers = new Map([
171
196
  [
@@ -197,12 +222,15 @@ function createFixture(overrides: Partial<ModuleAiOperationDefinition> = {}) {
197
222
  return {
198
223
  called,
199
224
  grant,
200
- grants,
225
+ grants: authorizations,
201
226
  host: new RestrictedAgentToolHost(
202
227
  [module],
228
+ hosts,
203
229
  new GovernedToolRegistry([module], handlers, runtime),
204
230
  runtime,
205
- grants,
231
+ authorizations,
232
+ undefined,
233
+ async () => context.actor,
206
234
  ),
207
235
  };
208
236
  }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  resolveToolNetworkPolicy,
3
+ type ModuleAiOperationDefinition,
3
4
  type ModuleManifest,
4
5
  } from "@southwind-ai/modules";
5
6
  import type {
@@ -11,47 +12,148 @@ import type { FeatureFlagDefinition } from "@southwind-ai/shared";
11
12
  import { evaluateAccessGuards } from "../access-guards.js";
12
13
  import type { createServerRuntime } from "../runtime.js";
13
14
  import { findFeature } from "../route-guards.js";
14
- import type { ExecutionGrantStore } from "./execution-grants.js";
15
+ import type { RequestActor, RequestGuardContext } from "../guards.js";
16
+ import type { InitializedModuleHosts } from "../module-host.js";
17
+ import {
18
+ AgentRunAuthorizationError,
19
+ type AgentRunAuthorizationStore,
20
+ } from "./run-authorization.js";
21
+ import { buildAgentRuntimeRelease } from "./run-release.js";
15
22
  import { GovernedToolRegistry, ToolExecutionError } from "./tool-registry.js";
23
+ import {
24
+ AgentToolApprovalCoordinator,
25
+ AgentToolApprovalError,
26
+ AgentToolApprovalPending,
27
+ } from "./tool-approval.js";
28
+ import type { WorkflowService } from "../workflow/service.js";
16
29
 
17
30
  type ServerRuntime = ReturnType<typeof createServerRuntime>;
18
31
 
19
32
  export class RestrictedAgentToolHost implements ModuleAgentToolHostPort {
20
33
  readonly #features: FeatureFlagDefinition[];
34
+ readonly #operations: Map<string, CurrentAgentOperation>;
35
+ readonly #approvals: AgentToolApprovalCoordinator;
36
+ readonly #executions = new Map<
37
+ string,
38
+ Promise<{ value: ModuleAiJsonValue }>
39
+ >();
21
40
 
22
41
  constructor(
23
42
  modules: readonly ModuleManifest[],
43
+ hosts: InitializedModuleHosts,
24
44
  private readonly tools: GovernedToolRegistry,
25
45
  private readonly runtime: ServerRuntime,
26
- private readonly grants: ExecutionGrantStore,
46
+ private readonly authorizations: AgentRunAuthorizationStore,
47
+ workflow?: WorkflowService,
48
+ private readonly resolveActor: (
49
+ actorId: string,
50
+ ) => Promise<RequestActor | undefined> = async () => undefined,
27
51
  ) {
28
52
  this.#features = modules.flatMap(({ features }) => features);
53
+ const handlers = new Map(
54
+ hosts.aiOperationHandlers.map(({ registration }) => [
55
+ registration.operationKey,
56
+ registration,
57
+ ]),
58
+ );
59
+ this.#operations = new Map(
60
+ modules.flatMap((module) =>
61
+ (module.aiOperations ?? [])
62
+ .filter((definition) => definition.kind === "agent")
63
+ .map((definition) => [
64
+ definition.key,
65
+ {
66
+ definition,
67
+ releaseId: buildAgentRuntimeRelease(
68
+ modules,
69
+ module,
70
+ definition,
71
+ handlers.get(definition.key),
72
+ ).releaseId,
73
+ },
74
+ ]),
75
+ ),
76
+ );
77
+ this.#approvals = new AgentToolApprovalCoordinator(workflow);
29
78
  }
30
79
 
31
80
  async execute(invocation: ModuleAgentToolInvocation) {
32
- const grant = this.grants.require(
33
- readGrantToken(invocation),
34
- invocation.runId,
35
- );
36
- if (resolveToolNetworkPolicy(grant.operation).mode !== "forbidden") {
81
+ let binding;
82
+ try {
83
+ binding = await this.authorizations.authorizeTool(
84
+ readGrantToken(invocation),
85
+ invocation.runId,
86
+ );
87
+ } catch (error) {
88
+ if (error instanceof AgentRunAuthorizationError) {
89
+ throw new AgentToolHostError("TOOL_DENIED", error.message);
90
+ }
91
+ throw error;
92
+ }
93
+ const current = this.#operations.get(binding.operationKey);
94
+ const currentNetworkMode = current
95
+ ? safeToolNetworkMode(current.definition)
96
+ : undefined;
97
+ if (current && currentNetworkMode !== "forbidden") {
98
+ throw new AgentToolHostError(
99
+ "TOOL_DENIED",
100
+ "Tool 网络策略不受当前 Host 支持",
101
+ );
102
+ }
103
+ if (
104
+ !current ||
105
+ current.releaseId !== binding.releaseId ||
106
+ !sameOperationAuthorization(
107
+ current.definition,
108
+ currentNetworkMode,
109
+ binding,
110
+ )
111
+ ) {
112
+ throw new AgentToolHostError(
113
+ "TOOL_DENIED",
114
+ "Agent Operation 版本不再可用",
115
+ );
116
+ }
117
+ if (binding.authorizationSnapshot.toolNetworkMode !== "forbidden") {
37
118
  throw new AgentToolHostError(
38
119
  "TOOL_DENIED",
39
120
  "Tool 网络策略不受当前 Host 支持",
40
121
  );
41
122
  }
42
- if (!grant.operation.allowedToolKeys.includes(invocation.toolKey)) {
123
+ if (
124
+ !binding.authorizationSnapshot.allowedToolKeys.includes(
125
+ invocation.toolKey,
126
+ )
127
+ ) {
43
128
  throw new AgentToolHostError("TOOL_DENIED", "Operation 未授权该 Tool");
44
129
  }
130
+ const actor = await this.resolveActor(binding.actorId);
131
+ if (!actor || actor.id !== binding.actorId || actor.type === "anonymous") {
132
+ throw new AgentToolHostError("TOOL_DENIED", "Agent Run Actor 当前不可用");
133
+ }
45
134
  const context = await this.runtime.createGuardContextForActor(
46
135
  new Request("http://agent-tool.internal"),
47
- grant.context.actor,
136
+ actor,
48
137
  );
138
+ try {
139
+ this.authorizations.assertCurrentScope(binding, context);
140
+ } catch (error) {
141
+ if (error instanceof AgentRunAuthorizationError) {
142
+ throw new AgentToolHostError("TOOL_DENIED", error.message);
143
+ }
144
+ throw error;
145
+ }
49
146
  const operationDecision = await evaluateAccessGuards(
50
147
  this.runtime,
51
148
  context,
52
149
  {
53
- permission: { permissionKey: grant.operation.permissionKey },
54
- feature: findFeature(this.#features, grant.operation.featureKey),
150
+ permission: {
151
+ permissionKey: binding.authorizationSnapshot.permissionKey,
152
+ },
153
+ feature: findFeature(
154
+ this.#features,
155
+ binding.authorizationSnapshot.featureKey,
156
+ ),
55
157
  },
56
158
  );
57
159
  if (!operationDecision.decision.allowed) {
@@ -60,20 +162,85 @@ export class RestrictedAgentToolHost implements ModuleAgentToolHostPort {
60
162
  "Agent Operation 当前无权继续执行",
61
163
  );
62
164
  }
165
+ const definition = this.tools.definition(invocation.toolKey);
166
+ if (!definition) {
167
+ throw new AgentToolHostError("TOOL_DENIED", "Agent Tool 不存在");
168
+ }
63
169
  try {
64
- const result = await this.tools.execute(
65
- invocation.toolKey,
66
- invocation.arguments,
67
- context,
68
- );
69
- return { value: toJsonValue(result) };
170
+ await this.#approvals.requireApproved(definition, invocation, context);
171
+ return await this.executeOnce(invocation, context);
70
172
  } catch (error) {
173
+ if (
174
+ error instanceof AgentToolApprovalPending ||
175
+ error instanceof AgentToolApprovalError
176
+ ) {
177
+ throw error;
178
+ }
71
179
  if (error instanceof ToolExecutionError) {
72
180
  throw new AgentToolHostError("TOOL_DENIED", error.message);
73
181
  }
74
182
  throw error;
75
183
  }
76
184
  }
185
+
186
+ private executeOnce(
187
+ invocation: ModuleAgentToolInvocation,
188
+ context: RequestGuardContext,
189
+ ): Promise<{ value: ModuleAiJsonValue }> {
190
+ const key = `${invocation.runId}\u0000${invocation.toolCallId}`;
191
+ const existing = this.#executions.get(key);
192
+ if (existing) return existing;
193
+ if (this.#executions.size >= 10_000) {
194
+ throw new AgentToolHostError(
195
+ "TOOL_DENIED",
196
+ "Agent Tool 幂等缓存容量已满",
197
+ );
198
+ }
199
+ const execution = this.tools
200
+ .execute(
201
+ invocation.toolKey,
202
+ invocation.arguments,
203
+ context,
204
+ invocation.toolCallId,
205
+ )
206
+ .then((result) => ({ value: toJsonValue(result) }));
207
+ this.#executions.set(key, execution);
208
+ execution.catch(() => this.#executions.delete(key));
209
+ return execution;
210
+ }
211
+ }
212
+
213
+ interface CurrentAgentOperation {
214
+ readonly definition: ModuleAiOperationDefinition;
215
+ readonly releaseId: string;
216
+ }
217
+
218
+ function sameOperationAuthorization(
219
+ definition: ModuleAiOperationDefinition,
220
+ networkMode: "forbidden" | undefined,
221
+ binding: Awaited<ReturnType<AgentRunAuthorizationStore["authorizeTool"]>>,
222
+ ): boolean {
223
+ const snapshot = binding.authorizationSnapshot;
224
+ return (
225
+ definition.permissionKey === snapshot.permissionKey &&
226
+ definition.featureKey === snapshot.featureKey &&
227
+ networkMode === snapshot.toolNetworkMode &&
228
+ definition.allowedToolKeys.length === snapshot.allowedToolKeys.length &&
229
+ definition.allowedToolKeys.every(
230
+ (key, index) => key === snapshot.allowedToolKeys[index],
231
+ )
232
+ );
233
+ }
234
+
235
+ function safeToolNetworkMode(
236
+ definition: ModuleAiOperationDefinition,
237
+ ): "forbidden" | undefined {
238
+ try {
239
+ const mode = resolveToolNetworkPolicy(definition).mode;
240
+ return mode === "forbidden" ? mode : undefined;
241
+ } catch {
242
+ return undefined;
243
+ }
77
244
  }
78
245
 
79
246
  export class AgentToolHostError extends Error {