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
@@ -15,13 +15,26 @@ from .contracts import (
15
15
  )
16
16
 
17
17
 
18
+ @dataclass(frozen=True)
19
+ class PreparedArtifact:
20
+ media_type: str
21
+ data_url: str
22
+ byte_size: int
23
+ sha256: str
24
+
25
+
18
26
  @dataclass(frozen=True)
19
27
  class EngineRunRequest:
20
28
  run_id: str
21
29
  operation_key: str
22
30
  input: JsonValue
31
+ input_modalities: tuple[str, ...] = ("text",)
32
+ required_capabilities: tuple[str, ...] = ()
33
+ artifacts: tuple[PreparedArtifact, ...] = ()
23
34
  instructions: str = ""
24
35
  user_prompt: str = ""
36
+ output_schema_key: str = ""
37
+ output_schema: dict[str, JsonValue] | None = None
25
38
  allowed_tools: tuple[RuntimeToolDefinition, ...] = ()
26
39
  limits: RuntimeLimits = field(default_factory=RuntimeLimits)
27
40
  provider_egress: ProviderEgress = field(default_factory=ProviderEgress)
@@ -45,6 +58,14 @@ class ToolRequested:
45
58
  @dataclass(frozen=True)
46
59
  class ApprovalRequired:
47
60
  work_item_id: str
61
+ tool_call_id: str
62
+
63
+
64
+ @dataclass(frozen=True)
65
+ class ApprovalResolved:
66
+ work_item_id: str
67
+ tool_call_id: str
68
+ outcome: str
48
69
 
49
70
 
50
71
  @dataclass(frozen=True)
@@ -66,6 +87,7 @@ type EngineSignal = (
66
87
  OutputDelta
67
88
  | ToolRequested
68
89
  | ApprovalRequired
90
+ | ApprovalResolved
69
91
  | ToolCompleted
70
92
  | UsageReported
71
93
  | EngineCompleted
@@ -91,6 +113,12 @@ class AgentEngineAdapter(Protocol):
91
113
 
92
114
  def supports(self, operation_key: str) -> bool: ...
93
115
 
116
+ @property
117
+ def capabilities(self) -> tuple[str, ...]: ...
118
+
119
+ @property
120
+ def input_modalities(self) -> tuple[str, ...]: ...
121
+
94
122
  def execute(self, request: EngineRunRequest) -> AsyncIterator[EngineSignal]: ...
95
123
 
96
124
  async def cancel(self, run_id: str) -> None: ...
@@ -0,0 +1,41 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ from typing import cast
6
+
7
+ from .contracts import JsonValue, StartRunRequest
8
+
9
+
10
+ def resolved_release(request: StartRunRequest) -> dict[str, JsonValue]:
11
+ release = cast(dict[str, JsonValue], request.release.model_dump(by_alias=True))
12
+ if release["releaseId"] == "legacy":
13
+ operation_digest = hashlib.sha256(request.operation_key.encode()).hexdigest()
14
+ release["releaseId"] = f"legacy_{operation_digest[:40]}"
15
+ return release
16
+
17
+
18
+ def request_fingerprint(request: StartRunRequest) -> str:
19
+ encoded = json.dumps(
20
+ {
21
+ "operationKey": request.operation_key,
22
+ "input": request.input,
23
+ "artifacts": [
24
+ {
25
+ "sha256": artifact.sha256,
26
+ "mediaType": artifact.media_type,
27
+ "byteSize": artifact.byte_size,
28
+ }
29
+ for artifact in request.artifacts
30
+ ],
31
+ "requiredCapabilities": sorted(request.required_capabilities),
32
+ "inputModalities": sorted(request.input_modalities),
33
+ "outputSchemaKey": request.output_schema_key,
34
+ "outputSchema": request.output_schema,
35
+ "release": resolved_release(request),
36
+ },
37
+ ensure_ascii=False,
38
+ separators=(",", ":"),
39
+ sort_keys=True,
40
+ ).encode()
41
+ return hashlib.sha256(encoded).hexdigest()
@@ -0,0 +1,62 @@
1
+ from __future__ import annotations
2
+
3
+ import hmac
4
+ import uuid
5
+
6
+ from fastapi.responses import JSONResponse
7
+
8
+ from .contracts import AgentError
9
+
10
+
11
+ def provider_governance_snapshot(
12
+ value: dict[str, int | float | str | None],
13
+ ) -> dict[str, int | float | str | None]:
14
+ allowed = (
15
+ "status",
16
+ "retentionDays",
17
+ "retainedRecords",
18
+ "rejectedAttempts",
19
+ "redactedAttempts",
20
+ "lastAttemptAt",
21
+ "lastPurgeAt",
22
+ "lastDeletedRecords",
23
+ "totalDeletedRecords",
24
+ )
25
+ return {key: value.get(key) for key in allowed}
26
+
27
+
28
+ def authorized(provided: str | None, expected: str | None) -> bool:
29
+ if expected is None:
30
+ return True
31
+ if not expected or not provided or not provided.startswith("Bearer "):
32
+ return False
33
+ return hmac.compare_digest(provided.removeprefix("Bearer "), expected)
34
+
35
+
36
+ def parse_cursor(after: int | None, last_event_id: str | None) -> int:
37
+ header_cursor = 0
38
+ if last_event_id is not None:
39
+ if not last_event_id.isdigit():
40
+ raise ValueError
41
+ header_cursor = int(last_event_id)
42
+ return max(after or 0, header_cursor)
43
+
44
+
45
+ def safe_error(
46
+ status_code: int,
47
+ code: str,
48
+ message: str,
49
+ retryable: bool,
50
+ ) -> JSONResponse:
51
+ error = AgentError.model_validate(
52
+ {
53
+ "code": code,
54
+ "message": message,
55
+ "requestId": f"request_{uuid.uuid4().hex}",
56
+ "retryable": retryable,
57
+ }
58
+ )
59
+ return JSONResponse(
60
+ status_code=status_code,
61
+ content=error.model_dump(by_alias=True),
62
+ )
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+
5
+
6
+ def lease_failed(task: asyncio.Task[None]) -> bool:
7
+ return task.done() and not task.cancelled() and task.exception() is not None
8
+
9
+
10
+ def cancel_on_lease_loss(
11
+ lease_task: asyncio.Task[None],
12
+ execution_task: asyncio.Task[None],
13
+ ) -> None:
14
+ if lease_failed(lease_task):
15
+ execution_task.cancel()
@@ -0,0 +1,76 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+
6
+ from jsonschema import SchemaError, ValidationError, validate
7
+
8
+ from .contracts import JsonValue
9
+ from .engine import PreparedArtifact, SafeEngineError
10
+
11
+
12
+ def attach_artifacts(
13
+ messages: list[dict[str, JsonValue]],
14
+ artifacts: tuple[PreparedArtifact, ...],
15
+ ) -> list[dict[str, JsonValue]]:
16
+ if not artifacts:
17
+ return messages
18
+ result = [dict(message) for message in messages]
19
+ for message in result:
20
+ if message.get("role") != "user":
21
+ continue
22
+ text = message.get("content")
23
+ if not isinstance(text, str):
24
+ raise invalid("Agent Vision 用户消息结构无效")
25
+ parts: list[JsonValue] = [{"type": "text", "text": text}]
26
+ parts.extend(
27
+ {
28
+ "type": "image_url",
29
+ "image_url": {"url": artifact.data_url, "detail": "auto"},
30
+ }
31
+ for artifact in artifacts
32
+ )
33
+ message["content"] = parts
34
+ return result
35
+ raise invalid("Agent Vision 缺少用户消息")
36
+
37
+
38
+ def response_format(
39
+ output_schema_key: str,
40
+ output_schema: dict[str, JsonValue] | None,
41
+ ) -> JsonValue | None:
42
+ if output_schema is None:
43
+ return None
44
+ name = re.sub(r"[^a-zA-Z0-9_-]", "_", output_schema_key)[:64]
45
+ if not name:
46
+ raise invalid("结构化输出 Schema Key 无效")
47
+ return {
48
+ "type": "json_schema",
49
+ "json_schema": {
50
+ "name": name,
51
+ "strict": True,
52
+ "schema": output_schema,
53
+ },
54
+ }
55
+
56
+
57
+ def final_output(
58
+ text: str,
59
+ output_schema: dict[str, JsonValue] | None,
60
+ ) -> JsonValue:
61
+ if output_schema is None:
62
+ return {"text": text}
63
+ try:
64
+ value: JsonValue = json.loads(text)
65
+ validate(instance=value, schema=output_schema)
66
+ return value
67
+ except (json.JSONDecodeError, SchemaError, ValidationError):
68
+ raise SafeEngineError(
69
+ "OUTPUT_VALIDATION_FAILED",
70
+ "模型结构化输出不符合 Operation Schema",
71
+ retryable=False,
72
+ ) from None
73
+
74
+
75
+ def invalid(message: str) -> SafeEngineError:
76
+ return SafeEngineError("INVALID_INPUT", message, retryable=False)
@@ -7,6 +7,8 @@ from collections.abc import AsyncIterator
7
7
  from .contracts import JsonValue
8
8
  from .engine import (
9
9
  AgentEngineAdapter,
10
+ ApprovalRequired,
11
+ ApprovalResolved,
10
12
  EngineCompleted,
11
13
  EngineRunRequest,
12
14
  EngineSignal,
@@ -16,9 +18,16 @@ from .engine import (
16
18
  ToolRequested,
17
19
  UsageReported,
18
20
  )
21
+ from .multimodal import attach_artifacts, final_output
19
22
  from .openai_provider import OpenAiCompatibleProvider, ProviderToolCall
20
23
  from .provider_governance import ProviderRequestGovernance
21
- from .tool_host import ToolHostClient, ToolInvocation
24
+ from .tool_host import (
25
+ ToolApprovalPending,
26
+ ToolApprovalResolved,
27
+ ToolHostClient,
28
+ ToolInvocation,
29
+ canonical_tool_call_id,
30
+ )
22
31
 
23
32
 
24
33
  class OpenAiCompatibleEngineAdapter(AgentEngineAdapter):
@@ -33,6 +42,14 @@ class OpenAiCompatibleEngineAdapter(AgentEngineAdapter):
33
42
  self._governance = governance
34
43
  self._cancellations: dict[str, asyncio.Event] = {}
35
44
 
45
+ @property
46
+ def capabilities(self) -> tuple[str, ...]:
47
+ return self._provider.config.capabilities
48
+
49
+ @property
50
+ def input_modalities(self) -> tuple[str, ...]:
51
+ return self._provider.config.input_modalities
52
+
36
53
  def supports(self, operation_key: str) -> bool:
37
54
  return bool(operation_key.strip())
38
55
 
@@ -40,16 +57,24 @@ class OpenAiCompatibleEngineAdapter(AgentEngineAdapter):
40
57
  self,
41
58
  request: EngineRunRequest,
42
59
  ) -> AsyncIterator[EngineSignal]:
43
- validate_runtime_request(request, self._provider.config.deployment_key)
60
+ validate_runtime_request(
61
+ request,
62
+ self._provider.config.deployment_key,
63
+ self._provider.config.capabilities,
64
+ self._provider.config.input_modalities,
65
+ )
44
66
  cancellation = self._cancellations.setdefault(
45
67
  request.run_id,
46
68
  asyncio.Event(),
47
69
  )
48
70
  allowed = {tool.key for tool in request.allowed_tools}
49
- messages: list[dict[str, JsonValue]] = [
50
- {"role": "system", "content": request.instructions},
51
- {"role": "user", "content": request.user_prompt},
52
- ]
71
+ messages = attach_artifacts(
72
+ [
73
+ {"role": "system", "content": request.instructions},
74
+ {"role": "user", "content": request.user_prompt},
75
+ ],
76
+ request.artifacts,
77
+ )
53
78
  output_bytes = 0
54
79
  try:
55
80
  for attempt in range(1, self._provider.config.max_tool_rounds + 1):
@@ -63,13 +88,24 @@ class OpenAiCompatibleEngineAdapter(AgentEngineAdapter):
63
88
  tools=request.allowed_tools,
64
89
  policy=request.provider_data_policy,
65
90
  input_value=request.input,
66
- measure=lambda messages, tools: len(
67
- self._provider.request_body(messages, tools)
91
+ artifact_bytes=sum(
92
+ artifact.byte_size for artifact in request.artifacts
93
+ ),
94
+ output_schema=request.output_schema,
95
+ measure=lambda messages, tools, schema: len(
96
+ self._provider.request_body(
97
+ messages,
98
+ tools,
99
+ request.output_schema_key,
100
+ schema,
101
+ )
68
102
  ),
69
103
  )
70
104
  turn = await self._provider.complete_turn(
71
105
  governed.messages,
72
106
  governed.tools,
107
+ request.output_schema_key,
108
+ governed.output_schema,
73
109
  )
74
110
  if turn.tool_calls:
75
111
  messages.append(assistant_tool_message(turn.tool_calls))
@@ -92,7 +128,7 @@ class OpenAiCompatibleEngineAdapter(AgentEngineAdapter):
92
128
  )
93
129
  yield OutputDelta(delta)
94
130
  yield UsageReported(turn.usage or {"source": "unknown"})
95
- yield EngineCompleted({"text": turn.text})
131
+ yield EngineCompleted(final_output(turn.text, governed.output_schema))
96
132
  return
97
133
  raise SafeEngineError(
98
134
  "BUDGET_EXCEEDED",
@@ -119,18 +155,60 @@ class OpenAiCompatibleEngineAdapter(AgentEngineAdapter):
119
155
  retryable=False,
120
156
  )
121
157
  arguments = parse_arguments(call.arguments)
122
- yield ToolRequested(call.call_id, call.name)
123
- result = await self._tool_host.execute(
124
- request.tool_host_url,
125
- ToolInvocation(
126
- request.run_id,
127
- call.call_id,
128
- call.name,
129
- arguments,
130
- request.execution_grant,
131
- ),
158
+ tool_call_id = canonical_tool_call_id(
159
+ request.run_id,
160
+ call.name,
161
+ arguments,
132
162
  )
133
- yield ToolCompleted(call.call_id)
163
+ yield ToolRequested(tool_call_id, call.name)
164
+ invocation = ToolInvocation(
165
+ request.run_id,
166
+ tool_call_id,
167
+ call.name,
168
+ arguments,
169
+ request.execution_grant,
170
+ )
171
+ approval: ToolApprovalPending | None = None
172
+ while True:
173
+ cancelled(cancellation)
174
+ try:
175
+ result = await self._tool_host.execute(
176
+ request.tool_host_url,
177
+ invocation,
178
+ )
179
+ if approval:
180
+ yield ApprovalResolved(
181
+ approval.work_item_id,
182
+ tool_call_id,
183
+ "approved",
184
+ )
185
+ break
186
+ except ToolApprovalPending as pending:
187
+ if approval is None:
188
+ approval = pending
189
+ yield ApprovalRequired(
190
+ pending.work_item_id,
191
+ tool_call_id,
192
+ )
193
+ elif pending.work_item_id != approval.work_item_id:
194
+ raise SafeEngineError(
195
+ "TOOL_DENIED",
196
+ "Agent Tool 审批标识漂移",
197
+ retryable=False,
198
+ ) from None
199
+ await asyncio.sleep(2)
200
+ except ToolApprovalResolved as resolved:
201
+ yield ApprovalResolved(
202
+ resolved.work_item_id,
203
+ tool_call_id,
204
+ resolved.outcome,
205
+ )
206
+ raise SafeEngineError(
207
+ "TOOL_DENIED",
208
+ "Agent Tool 审批未通过",
209
+ retryable=False,
210
+ ) from None
211
+ yield ToolCompleted(tool_call_id)
134
212
  messages.append(
135
213
  {
136
214
  "role": "tool",
@@ -158,6 +236,8 @@ class OpenAiCompatibleEngineAdapter(AgentEngineAdapter):
158
236
  def validate_runtime_request(
159
237
  request: EngineRunRequest,
160
238
  provider_deployment_key: str,
239
+ provider_capabilities: tuple[str, ...],
240
+ provider_input_modalities: tuple[str, ...],
161
241
  ) -> None:
162
242
  if (
163
243
  not request.instructions.strip()
@@ -170,6 +250,18 @@ def validate_runtime_request(
170
250
  "Agent Operation 运行计划不完整",
171
251
  retryable=False,
172
252
  )
253
+ if set(request.required_capabilities) - set(provider_capabilities):
254
+ raise SafeEngineError(
255
+ "MODEL_ROUTE_UNAVAILABLE",
256
+ "模型 Deployment 缺少 Operation 所需能力",
257
+ retryable=True,
258
+ )
259
+ if set(request.input_modalities) - set(provider_input_modalities):
260
+ raise SafeEngineError(
261
+ "MODEL_ROUTE_UNAVAILABLE",
262
+ "模型 Deployment 不支持 Operation 输入模态",
263
+ retryable=True,
264
+ )
173
265
  if (
174
266
  request.provider_egress.mode != "configured-endpoint"
175
267
  or request.provider_egress.deployment_key != provider_deployment_key
@@ -12,6 +12,7 @@ from .config import (
12
12
  )
13
13
  from .contracts import AgentErrorCode, JsonValue, RuntimeToolDefinition
14
14
  from .engine import SafeEngineError
15
+ from .multimodal import response_format
15
16
 
16
17
 
17
18
  @dataclass
@@ -58,8 +59,15 @@ class OpenAiCompatibleProvider:
58
59
  self,
59
60
  messages: list[dict[str, JsonValue]],
60
61
  tools: tuple[RuntimeToolDefinition, ...],
62
+ output_schema_key: str = "",
63
+ output_schema: dict[str, JsonValue] | None = None,
61
64
  ) -> ProviderTurn:
62
- body = self.request_body(messages, tools)
65
+ body = self.request_body(
66
+ messages,
67
+ tools,
68
+ output_schema_key,
69
+ output_schema,
70
+ )
63
71
  turn = ProviderTurn()
64
72
  async with self._client() as client:
65
73
  try:
@@ -83,6 +91,8 @@ class OpenAiCompatibleProvider:
83
91
  self,
84
92
  messages: list[dict[str, JsonValue]],
85
93
  tools: tuple[RuntimeToolDefinition, ...],
94
+ output_schema_key: str = "",
95
+ output_schema: dict[str, JsonValue] | None = None,
86
96
  ) -> bytes:
87
97
  payload: dict[str, JsonValue] = {
88
98
  "model": self.config.model,
@@ -92,6 +102,9 @@ class OpenAiCompatibleProvider:
92
102
  }
93
103
  if tools:
94
104
  payload["tools"] = [tool_schema(tool) for tool in tools]
105
+ structured = response_format(output_schema_key, output_schema)
106
+ if structured is not None:
107
+ payload["response_format"] = structured
95
108
  return json.dumps(
96
109
  payload,
97
110
  ensure_ascii=False,