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,132 @@
1
+ # 受治理导出 Renderer
2
+
3
+ 更新时间:2026-07-27。
4
+
5
+ ## 适用边界
6
+
7
+ 业务 Module 可以在 `registerGovernedResources()` 的 `export.renderers` 中注册服务端
8
+ Renderer,把同一条受治理导出链生成 PDF、DOCX、XLSX 或其它受控格式。Renderer 是版式
9
+ 实现,不是新的授权或存储入口:
10
+
11
+ - 平台固化请求 Actor、Policy、查询、Scope 与 Renderer 版本;
12
+ - 平台处理审批、Durable Job、重试、取消、Artifact、TTL、失败清理和下载审计;
13
+ - Worker 在开始和读取每一页前重新检查用户、权限、Feature、License 与 Scope;
14
+ - Renderer 只能读取平台提供的 `AsyncIterable` 记录、水印、`AbortSignal` 和
15
+ `heartbeat()`,不能取得 Repository、BlobStore、Workflow、平台 Secret 或下载凭据。
16
+
17
+ 未声明 `renderers` 的已有 Module 保持 NDJSON 契约。声明 Renderer 后,请求必须显式提供
18
+ 已注册的 `formatKey`;缺少、未知或执行时未绑定的格式均 fail closed,不回退到 NDJSON。
19
+
20
+ ## 注册契约
21
+
22
+ 每个 Renderer 声明以下不可变元数据:
23
+
24
+ - `formatKey`:资源内稳定、唯一的小写格式 Key;
25
+ - `templateKey`:当前 Module 命名空间内的模板 Key;
26
+ - `templateVersion`:不可变模板版本;修改版式时递增,不覆盖历史版本;
27
+ - `inputSchemaKey`:当前 Manifest `jsonSchemas` 已登记的记录输入 Schema;
28
+ - `contentType` 与不含点号的 `filenameExtension`;
29
+ - `maxRecords`、`maxOutputBytes` 和 `timeoutSeconds`;
30
+ - `render()`:消费平台记录流并返回 `ReadableStream<Uint8Array>`。
31
+
32
+ 示例:
33
+
34
+ ```ts
35
+ host.registerGovernedResources([
36
+ {
37
+ policyKey: "reports.official.fields",
38
+ readPath: "/api/reports/official/:id",
39
+ revealPath: "/api/reports/official/:id/plaintext",
40
+ revealAuditAction: "reports.official.reveal",
41
+ authorize,
42
+ read,
43
+ export: {
44
+ basePath: "/api/reports/official/exports",
45
+ validateQuery,
46
+ readPage,
47
+ renderers: [
48
+ {
49
+ formatKey: "pdf",
50
+ templateKey: "reports.official.pdf",
51
+ templateVersion: "2026.07",
52
+ inputSchemaKey: "reports.official.input.v1",
53
+ contentType: "application/pdf",
54
+ filenameExtension: "pdf",
55
+ limits: {
56
+ maxRecords: 10_000,
57
+ maxOutputBytes: 20 * 1024 * 1024,
58
+ timeoutSeconds: 120,
59
+ },
60
+ async render({ records, watermark }, { signal, heartbeat }) {
61
+ return renderOfficialPdf({
62
+ records,
63
+ watermark,
64
+ signal,
65
+ heartbeat,
66
+ });
67
+ },
68
+ },
69
+ ],
70
+ },
71
+ },
72
+ ]);
73
+ ```
74
+
75
+ `renderOfficialPdf()` 属于业务 package,但必须是纯服务端流式 Renderer。它可以使用随
76
+ 业务 package 分发的模板和字体,不得在执行时绕回业务 Repository 补查数据,也不得自行
77
+ 上传、发布或签发下载链接。
78
+
79
+ ## 请求与版本固化
80
+
81
+ 创建请求的 body 在原有 `idempotencyKey`、`reason`、`query` 之外接受 `formatKey`。
82
+ 平台在校验 Host 注册后,把以下快照持久化并纳入请求 fingerprint:
83
+
84
+ - 格式、模板 Key 与模板版本;
85
+ - 输入 Schema Key;
86
+ - MIME 与扩展名;
87
+ - 记录、输出字节和超时上限。
88
+
89
+ 相同幂等键改选格式、模板或上限会形成语义冲突。Worker 执行时把持久化快照与当前 Host
90
+ 注册逐项比对;部署遗漏 Renderer 或模板版本漂移会终止任务,避免恢复任务静默套用另一套
91
+ 版式。
92
+
93
+ ## 流、取消与资源限制
94
+
95
+ 平台逐页调用业务 `readPage()`,在每页读取前重新授权,再把记录逐条交给 Renderer。
96
+ Renderer 应使用 `for await` 消费记录,不应先汇总完整数组。Renderer 未完整消费记录流
97
+ 即返回产物时,平台拒绝发布。
98
+
99
+ 平台同时施加以下硬边界:
100
+
101
+ - 超过 `maxRecords` 时终止记录流;
102
+ - 读取输出流时累计实际字节数,超过 `maxOutputBytes` 时终止;
103
+ - `timeoutSeconds` 到期或 Durable Job 取消时中止同一个 `AbortSignal`;
104
+ - 每页完成后更新 heartbeat 与 Durable Job progress;
105
+ - 渲染、流读取或 Artifact 发布失败时删除已经写入但尚未发布的 Blob。
106
+
107
+ Renderer 必须把 `signal` 继续传给支持取消的模板、压缩或文档库。忽略 Signal 的库仍会在
108
+ 平台读取输出时被终止,但可能延迟释放其内部 CPU 或内存,因此不应作为生产 Adapter。
109
+
110
+ ## Artifact 与审计
111
+
112
+ 发布后的 Durable Artifact 记录真实文件名、MIME、SHA-256、字节数,并在受控 metadata
113
+ 中记录 `formatKey`、`templateKey`、`templateVersion`、`inputSchemaKey` 和 Renderer
114
+ 返回的有限 `contentMetadata`。`contentMetadata` 只允许有界 JSON,不得包含记录原文、
115
+ 敏感字段、完整 ID 集或模板生成的正文。
116
+
117
+ 请求审计记录格式和模板版本;生成 intent 审计还记录输入 Schema 与 MIME;下载审计记录
118
+ 同一格式、模板版本和内容摘要。下载前仍重新检查 owner、Permission、Feature、审批、
119
+ TTL、Artifact 引用和 Blob 完整性,Renderer 不能改变这些顺序。
120
+
121
+ ## 测试要求
122
+
123
+ 业务 Renderer 至少覆盖:
124
+
125
+ - 正文、来源引用和水印内容,而不只断言文件存在;
126
+ - 请求缺少格式、未知格式、注册丢失和模板版本漂移;
127
+ - 多页记录按流消费,记录/输出上限与超时;
128
+ - 取消、权限撤销、Scope 变化、渲染失败和发布失败不留下可下载半成品;
129
+ - 下载 MIME、文件名、SHA-256、字节数与模板元数据一致。
130
+
131
+ PDF、DOCX、XLSX 应使用对应解析库回读断言正文和水印。平台的测试 Renderer 只证明 Port
132
+ 及治理生命周期;具体文档格式正确性由实现该格式的业务 Module 负责。
@@ -34,3 +34,8 @@ PUT /api/system/menus/:id/placement
34
34
  ## 扩展约束
35
35
 
36
36
  新增页面时先在所属 Module Manifest 用同一能力 Key 注册 Feature、权限、菜单和 API 绑定,再新增 Router 页面。Router 契约测试会比较所有 `type=menu` 的 Manifest 路径与 Web 路由,避免出现“菜单有入口但页面不存在”或“页面绕过注册表”的漂移。
37
+
38
+ 客户业务页面不直接修改 shared-scaffold Router 或侧栏。页面实现注册到
39
+ project-owned 的 `apps/web/src/app/business-routes.ts`,平台 Router Adapter 统一补齐
40
+ Feature/RBAC Guard;侧栏仍从服务端 Manifest 快照生成。完整接入与升级边界见
41
+ [project-owned 业务 Web 路由](../development/business-web-routes.md)。
@@ -9,7 +9,8 @@ Windy V1 采用单组织、单租户的企业私有化模型。canonical schema
9
9
  - `roles.data_scope` 和 `roles.department_ids` 表示角色数据范围策略;
10
10
  - 岗位、兼职部门和多组织成员关系属于后续独立模型,不复用 `department_id` 暗中表达。
11
11
 
12
- 这些边界延续 [RuoYi-Vue 兼容与迁移设计](../adapters/ruoyi-vue-compatibility.md) 的 Adapter 原则,也与 [Starter 产品缺口分析](../product/starter-product-gap-analysis.md) 中“单组织 V1”和“数据权限必须进入查询约束”的结论一致。
12
+ 这些边界延续 [RuoYi-Vue 兼容与迁移设计](../adapters/ruoyi-vue-compatibility.md) 的
13
+ Adapter 原则;数据权限必须进入查询约束,不能只依赖 Web 菜单或按钮隐藏。
13
14
 
14
15
  ## 用户表单闭环
15
16
 
@@ -0,0 +1,156 @@
1
+ # Speech AI Runtime
2
+
3
+ 更新时间:2026-07-27。
4
+
5
+ Windy 的首个 Speech Runtime 只提供基于授权 `ArtifactRef` 的批量转写。实时 ASR、
6
+ TTS 和 Dictation 不在本切片内。业务模块持有音频资产、原消息关系、人工校正、翻译和
7
+ 业务状态;平台持有身份授权、Operation 路由、运行时协议、配额与审计。
8
+
9
+ 未安装或未配置 Speech Server 时,Speech Operation 稳定返回
10
+ `CAPABILITY_UNAVAILABLE`,不会回落到文本 Agent,也不阻止普通业务、Document 或文本
11
+ Agent 启动。
12
+
13
+ ## 安全调用链
14
+
15
+ 1. 业务模块注册音频资源的 `ModuleResourceFileAccessPolicy`,从 project-owned
16
+ Repository 回查 `resourceId`、`fileId` 与当前 Actor 的真实关系。
17
+ 2. 模块路由调用 `context.aiArtifacts.issue(...)` 换取加密、短时、opaque
18
+ `ArtifactRef`。
19
+ 3. `@southwind-ai/ai-client/speech` 只把 Artifact 与领域选项提交到同源 Southwind
20
+ Server。
21
+ 4. Server 重新检查 Feature、Permission、License、数据范围、能力摘要和 Artifact
22
+ 元数据,并按 Actor + Operation 作用域化幂等键。
23
+ 5. Speech Server 从自身固定的内网 Artifact Endpoint 下载源文件;请求不能指定 URL。
24
+ 6. Speech Server 使用 FFmpeg 把常见音频/视频容器归一化为 16 kHz、单声道、
25
+ PCM S16LE WAV,再调用已配置的本地/内网 Adapter。
26
+
27
+ 禁止业务 Server 运行 Whisper/ASR/转码进程、直连语音 Provider,或把音频、Base64、
28
+ Blob Key、宿主路径、模型名、Endpoint 和 Secret 交给文本 Agent。
29
+
30
+ ## Manifest 与 Module Handler
31
+
32
+ `kind=speech` Operation 必须声明:
33
+
34
+ - Feature、Permission、Audit、输入/输出 Schema;
35
+ - `speech.transcribe.batch` 及需要的 `speech.normalize`、`speech.vad`、
36
+ `speech.timestamps` capability;
37
+ - 数据分类、Deployment 与 Provider 出网策略;
38
+ - 输入/输出字节、处理时长、最大稳定分段数 `maxUnits` 和媒体时长
39
+ `maxMediaDurationSeconds`。
40
+
41
+ ```ts
42
+ const operation = {
43
+ key: "evidence.audio.transcribe",
44
+ kind: "speech",
45
+ featureKey: "evidence.audio.transcribe",
46
+ permissionKey: "evidence.audio.transcribe.execute",
47
+ auditAction: "evidence.audio.transcribe.execute",
48
+ inputSchemaKey: "evidence.audio.transcribe.input.v1",
49
+ outputSchemaKey: "evidence.audio.transcribe.output.v1",
50
+ requiredCapabilities: [
51
+ "speech.transcribe.batch",
52
+ "speech.normalize",
53
+ "speech.vad",
54
+ "speech.timestamps",
55
+ ],
56
+ allowedToolKeys: [],
57
+ dataClassification: "sensitive",
58
+ execution: "background",
59
+ providerEgress: { mode: "forbidden" },
60
+ limits: {
61
+ maxDurationSeconds: 1800,
62
+ maxInputBytes: 512 * 1024 * 1024,
63
+ maxOutputBytes: 32 * 1024 * 1024,
64
+ maxUnits: 100000,
65
+ maxMediaDurationSeconds: 8 * 60 * 60,
66
+ },
67
+ } as const;
68
+ ```
69
+
70
+ 同一 Operation 注册 `prepareSpeech`。Handler 只校验并收敛语言、VAD 与时间戳等领域
71
+ 选项,不选择模型或 Deployment。受控出网时,选项先经过
72
+ `providerDataPolicy.inputFields` 裁剪/DLP;完全断网时 Adapter 仍只接受本地/内网地址。
73
+
74
+ ## 输入、输出与事件
75
+
76
+ 首批接受 FFmpeg 可探测且 MIME 属于 allowlist 的 MP3、M4A/MP4、WAV、OGG、FLAC、
77
+ WebM 音频或含音轨的视频。归一化失败、时长超限或内容损坏都返回稳定错误,不把 FFmpeg
78
+ stderr 暴露给业务。
79
+
80
+ 选项:
81
+
82
+ ```ts
83
+ {
84
+ language?: string;
85
+ vad?: {
86
+ enabled: boolean;
87
+ minSpeechMs?: number;
88
+ maxSilenceMs?: number;
89
+ };
90
+ timestamps?: "segment" | "word";
91
+ }
92
+ ```
93
+
94
+ Adapter 返回的分段会被 Runtime 重新校验和规范化:
95
+
96
+ - 稳定 ID 为 `segment-000001` 递增;
97
+ - segment 与 word 时间戳单调、非负且不超过素材时长;
98
+ - 文本不能为空,置信度必须在 0–1;
99
+ - 分段总数受 `maxUnits` 与 Runtime 双重配额约束;
100
+ - 输出只保留标量 metadata,并明确记录归一化格式。
101
+
102
+ 事件协议:
103
+
104
+ ```text
105
+ run.started
106
+ speech.segment.completed
107
+ run.completed | run.failed | run.cancelled
108
+ ```
109
+
110
+ 每个事件有单调 sequence。客户端断线后用 cursor 恢复;取消会写入终态并取消归一化或
111
+ Adapter 协程。相同幂等键和相同语义返回原 Run,语义漂移返回 `RUN_CONFLICT`。
112
+
113
+ ## 结果 Artifact
114
+
115
+ 完成后提供两个互补接口:
116
+
117
+ ```text
118
+ GET /api/speech/runs/:runId/result
119
+ GET /api/speech/runs/:runId/artifact
120
+ ```
121
+
122
+ `result` 返回结构化转写及 Artifact 元数据;`artifact` 返回 Speech Server 持久化的同一
123
+ canonical JSON 字节流,包含 `content-length` 与 `x-content-sha256`。Artifact 下载仍需
124
+ 平台 Run 所有权授权,使用 `private, no-store`,不暴露 Speech Server 路径或数据库。
125
+
126
+ 结果包含 `durationMs`、可选语言、稳定 segments、词级时间戳、置信度和 metadata。
127
+ 业务可以在通过输出 Schema 后把结果导入自己的事实表、保存来源回链并进入人工校正;
128
+ 平台不会替业务保存消息关系或翻译状态。
129
+
130
+ ## 部署
131
+
132
+ 选择 `system.agent` 的 Starter 会分发独立 Speech Server。配置:
133
+
134
+ ```dotenv
135
+ PLATFORM_ENABLE_AI=true
136
+ AGENT_SERVER_INTERNAL_TOKEN=<随机内部令牌>
137
+ AI_ARTIFACT_ENCRYPTION_SECRET=<至少 32 字符>
138
+ SPEECH_SERVER_URL=http://speech-server:8091
139
+ SPEECH_ARTIFACT_URL=http://server:9747/api/internal/ai/artifacts
140
+ SPEECH_ADAPTER_URL=http://asr.internal:9001
141
+ SPEECH_ADAPTER_TOKEN=<可选内部令牌>
142
+ SPEECH_ADAPTER_CAPABILITIES=speech.transcribe.batch,speech.normalize,speech.vad,speech.timestamps
143
+ SPEECH_MAX_UNITS=100000
144
+ SPEECH_MAX_MEDIA_DURATION_SECONDS=86400
145
+ ```
146
+
147
+ 受控 Provider 还需配置 `SPEECH_DEPLOYMENT_KEY`,且必须与 Manifest 完全一致。启动:
148
+
149
+ ```bash
150
+ bun run dev:speech
151
+ ```
152
+
153
+ Speech Server 自有 SQLite 保存 Run、cursor、终态转写和结果 Artifact,适合单副本。
154
+ 健康检查需要内部 Bearer Token,只返回 capability 与非敏感 limits。Adapter、FFmpeg
155
+ 或 FFprobe 不可用时返回 unavailable;完全断网 profile 使用已包含 FFmpeg 的镜像和
156
+ 本地/内网 ASR Adapter,运行时不需要公网。
@@ -95,7 +95,13 @@ GET /api/system/audit-logs
95
95
  - 配置 `DATABASE_URL` 后,系统资源使用 Drizzle Repository,启动时会按 `id` / `key` 幂等写入默认种子数据,不覆盖已有记录。
96
96
  - Feature Flag 是受控资源:Key 和元数据由 Module Manifest 幂等同步,API 只允许修改 `enabled` / `visible`,不提供创建、导入或删除入口。Manifest 移除的 Key 会归档保留历史状态。
97
97
  - Feature Guard 在配置数据库时按请求、按 Key 读取运行态;同一请求缓存结果,下一请求重新读取。开发无数据库时回退 Manifest,生产无数据库或读取失败时 fail closed。
98
- - CRUD 成功和权限拒绝会先进入进程内审计 sink;配置 `DATABASE_URL` 后由可靠写入器写入 PostgreSQL `audit_logs`。普通事件持续失败时业务继续并告警;用户、角色、License 与 Feature Flag 等关键变更必须落库或进入本地原子恢复队列。策略、状态和恢复步骤见 [平台审计可靠写入](./audit-reliability.md)。
98
+ - CRUD 成功和权限拒绝会先进入进程内审计 sink;配置 `DATABASE_URL` 后由可靠写入器写入 PostgreSQL `audit_logs`。普通事件持续失败时业务继续并告警;用户、角色、License 与 Feature Flag 等关键变更必须落库或进入本地原子恢复队列。
99
+
100
+ <!-- @windy-module system.audit begin -->
101
+
102
+ 策略、状态和恢复步骤见 [平台审计可靠写入](./audit-reliability.md)。
103
+ <!-- @windy-module system.audit end -->
104
+
99
105
  - 密码登录、服务端会话、退出和吊销已闭环;通用用户 CRUD 不读写或返回密码 hash,密码更新走受权限保护的认证 API。
100
106
 
101
107
  <!-- @windy-module system.license begin -->
@@ -0,0 +1,97 @@
1
+ # Vision AI Runtime
2
+
3
+ 更新时间:2026-07-27。
4
+
5
+ Windy 的首个 Vision 切片在现有 Agent canonical Run 上增加受治理的图片 Artifact 输入,
6
+ 用于图片内容理解和结构化视觉提取。它不新增由业务选择模型的 `vision` kind:
7
+ `agent.vision.*` 仍是 `kind=agent` 的流式语义;`document.parse.multimodal` 仍是
8
+ `kind=document` 的异步页级语义。相同 VLM Deployment 可以承载两者,但不能混用
9
+ 路由、结果契约或业务状态。
10
+
11
+ ## 不变量
12
+
13
+ - 浏览器和业务模块只提交平台签发的 opaque `ArtifactRef`,不能提交 URL、Base64、
14
+ BlobStore Key、宿主路径、模型名或 Provider Endpoint。
15
+ - Southwind Server 在 Feature、Permission、License、数据范围通过后重新打开资源,
16
+ 校验 MIME、字节数与 SHA-256,再为 Agent Server 轮换短时引用。
17
+ - Agent Server 只从固定 `AI_ARTIFACT_URL` 内网入口读取图片,拒绝调用方 URL。
18
+ - 只接受 JPEG、PNG、WebP;解码后强制检查图片数量、总字节与单图像素。
19
+ - 图片解码后统一转成无 EXIF/ICC/文件名的 PNG,再作为 OpenAI-compatible
20
+ `image_url` typed content part 发送;不会拼接进文本 Prompt。
21
+ - 每次 Provider attempt 都要求 `artifact-content` allowlist、执行字段 DLP,并记录
22
+ Deployment、Operation、Run、attempt、分类、发送字节和 allow/redact/reject 决策。
23
+
24
+ ## Manifest
25
+
26
+ Vision Operation 必须显式声明输入模态、能力和双重资源上限:
27
+
28
+ ```ts
29
+ {
30
+ key: "evidence.image.inspect",
31
+ kind: "agent",
32
+ inputModalities: ["text", "image"],
33
+ requiredCapabilities: ["text-generation", "vision"],
34
+ providerEgress: {
35
+ mode: "configured-endpoint",
36
+ deploymentKey: "ai.openai-compatible"
37
+ },
38
+ providerDataPolicy: {
39
+ inputFields: [/* project-owned JSON Pointer allowlist */],
40
+ envelopeFields: [
41
+ { field: "instructions", classification: "internal", dlpAction: "reject" },
42
+ { field: "user-prompt", classification: "internal", dlpAction: "redact" },
43
+ { field: "artifact-content", classification: "sensitive", dlpAction: "reject" },
44
+ { field: "output-schema", classification: "internal", dlpAction: "reject" },
45
+ { field: "provider-output", classification: "sensitive", dlpAction: "redact" }
46
+ ]
47
+ },
48
+ limits: {
49
+ maxDurationSeconds: 120,
50
+ maxInputBytes: 32 * 1024 * 1024,
51
+ maxOutputBytes: 1024 * 1024,
52
+ maxArtifacts: 8,
53
+ maxPixelsPerArtifact: 24_000_000
54
+ }
55
+ }
56
+ ```
57
+
58
+ 未声明 `image`、数量或像素上限时,Manifest 组合直接失败。运行时还会把
59
+ `kind=agent`、`inputModalities` 和 `requiredCapabilities` 发给 Agent Server;当前
60
+ Deployment 缺少任一项时返回 `MODEL_ROUTE_UNAVAILABLE`,不能静默落到文本模型。
61
+
62
+ ## 结构化输出
63
+
64
+ Module Handler 可以在执行计划中提供受限 JSON Schema:
65
+
66
+ ```ts
67
+ return {
68
+ instructions: "只根据图片中可见内容提取,不推测身份。",
69
+ userPrompt: "提取票据字段并标出无法确认的值。",
70
+ outputSchema: {
71
+ type: "object",
72
+ additionalProperties: false,
73
+ required: ["fields"],
74
+ properties: {
75
+ fields: { type: "array", items: { type: "object" } },
76
+ },
77
+ },
78
+ };
79
+ ```
80
+
81
+ 平台限制 Schema 为 256 KiB,并以 Manifest `outputSchemaKey` 关联审计。Agent Server
82
+ 通过 OpenAI-compatible `response_format=json_schema` 发送,终态前再次用 JSON Schema
83
+ 校验;无效 JSON 或不匹配结果以 `OUTPUT_VALIDATION_FAILED` 结束,不能把未经校验的对象
84
+ 交给业务。业务仍须用 `AgentOperation.parseOutput` 收窄远端值并保存来源回链、人工复核
85
+ 和领域状态。
86
+
87
+ ## 部署
88
+
89
+ ```dotenv
90
+ AI_ARTIFACT_URL=http://server:9747/api/internal/ai/artifacts
91
+ AI_PROVIDER_CAPABILITIES=text-generation,vision
92
+ AI_PROVIDER_INPUT_MODALITIES=text,image
93
+ ```
94
+
95
+ VLM 可以是 localhost、内网或经 allowlist 授权的 HTTPS Deployment。完全断网环境使用
96
+ 本地/内网 OpenAI-compatible VLM;图片回取与 Provider 调用均不需要公网。未配置 VLM
97
+ 能力时普通文本 Agent、Document、Speech 和非 AI 业务继续独立运行。
@@ -89,7 +89,13 @@ VITE_DEV_ADMIN_TOKEN=<显式开发 Token>
89
89
  - 系统资源表和字典后台任务表加载时保留表头与列宽,并显示带 `animate-pulse` 的骨架行;加载失败和空数据仍使用各自独立状态。
90
90
  - 全局水印与业务页面范围默认开启。管理员在“全局设置”中维护总开关、低/中/高密度,并勾选用户名、姓名、手机号、邮箱或最多 80 个字符的自定义内容;保存写入审计并立即成为所有用户的只读策略。客户端按旋转文本包围盒自动计算平铺尺寸与安全间距,长内容和高密度模式也不会相互重叠。用户应用端不提供开关,也不使用 localStorage。`system.watermark` Feature 控制最终生效态,管理区另需 `system.watermark.read/manage` 权限。水印使用专用审计顶层覆盖 Sidebar、Drawer、Overlay 和 Modal,同时保持 `pointer-events-none`。服务端只向当前用户自己的会话响应补充这些身份字段。
91
91
  - 站内通知由 PostgreSQL `platform_notifications`、`notification_revisions`、`notification_reads` 和 `notification_favorites` 持久化;管理人员可在 `/system/notifications` 广播发布、修改、查看版本历史和归档,用户从 Header 收件箱阅读正文并幂等写入相互独立的已读、收藏回执。修改会生成带服务端时间和 Actor 的完整不可变快照,无内容变化不增加版本。普通用户 API 支持关键词、分类、已读和收藏的服务端组合筛选,列表与 `total` 使用同一可见性范围。归档是生命周期操作,不物理删除通知、版本或回执。
92
+
93
+ <!-- @windy-module system.bulk-data begin -->
94
+
92
95
  - 字典页已切换为后台 NDJSON 导入导出,展示本人任务状态、进度、重试和终态文件下载;其它系统资源仍保留小数据同步 JSON 入口。详细契约见 [批量导入导出后台任务](./bulk-data-jobs.md)。当前 artifact 存在 10 MiB、50,000 行和 256 KiB 单行上限,扩大容量前需要对象存储 Adapter。
96
+
97
+ <!-- @windy-module system.bulk-data end -->
98
+
93
99
  - 审计日志配置 `DATABASE_URL` 后读取 PostgreSQL `audit_logs`。可靠写入器提供有界重试、降级状态、关键事件本地恢复队列和健康信息;页面仍只读,且不会展示恢复队列中的事件正文。
94
100
  - 运维页的定时任务来自真实代码注册和 PostgreSQL 状态,不允许在线编辑任务代码。当前基线的 `stale` 只做观察告警和人工处置提示,不会自动终止或重试。
95
101
 
@@ -16,6 +16,9 @@
16
16
  "dev:web": "bun run --cwd apps/web dev",
17
17
  "dev:server": "bun run --cwd apps/server dev",
18
18
  "dev:agent": "docker compose --profile agent up --build",
19
+ "dev:document": "PLATFORM_ENABLE_AI=true DOCUMENT_SERVER_URL=http://document-server:8090 docker compose --profile agent --profile document up --build",
20
+ "dev:speech": "PLATFORM_ENABLE_AI=true SPEECH_SERVER_URL=http://speech-server:8091 docker compose --profile agent --profile speech up --build",
21
+ "dev:embedding": "PLATFORM_ENABLE_AI=true EMBEDDING_SERVER_URL=http://embedding-server:8092 docker compose --profile agent --profile embedding up --build",
19
22
  "dev:adk-web": "docker compose --profile agent-debug up --build adk-web-debug",
20
23
  "dev:search": "OPENSEARCH_URL=http://opensearch:9200 docker compose --profile search up --build",
21
24
  "dev:license": "bun run --cwd apps/license dev",
@@ -37,19 +40,30 @@
37
40
  "test:db:license-bootstrap": "bun run scripts/license-bootstrap-postgres-regression.ts",
38
41
  "test:db:migrations": "bun run scripts/database-migration-regression.ts",
39
42
  "test:db:config": "bun run scripts/module-configuration-postgres-regression.ts",
43
+ "test:db:release": "bun run test:db:migrations && bun run test:db:auth && bun run test:db:data-scope && bun run test:db:organization && bun run test:db:notification && bun run test:db:governance && bun run test:db:legacy-license && bun run test:db:license-bootstrap && bun run test:db:config",
40
44
  "test:redis:health": "bun run scripts/redis-health-regression.ts",
41
45
  "test:vault:signing": "bun run scripts/vault-signing-regression.ts",
42
46
  "test:docker:license-signing": "bun run scripts/license-signing-compose-regression.ts",
43
47
  "test:ops:recovery": "bun run scripts/production-recovery-regression.ts",
44
48
  "test:ops:amd64": "bun run scripts/linux-amd64-container-regression.ts",
49
+ "test:ops:tool-sandbox": "bun run scripts/tool-sandbox-isolation-regression.ts",
45
50
  "ops:db": "bun run scripts/production-database.ts",
46
51
  "ops:release": "bun run scripts/production-release.ts",
47
- "test:release:evidence": "bun run scripts/release-evidence.ts",
52
+ "test:merge": "bun run scripts/merge-gate.ts",
53
+ "release:verify": "bun run scripts/release-verify.ts",
48
54
  "test:packages:pack": "bun run scripts/platform-package-release.ts",
49
- "test:agent": "uv run --directory apps/agent-server pytest && uv run --directory apps/agent-server ruff check . && uv run --directory apps/agent-server ruff format --check . && uv run --directory apps/agent-server mypy",
55
+ "test:agent": "uv run --directory apps/agent-server pytest",
56
+ "test:document": "uv run --directory apps/document-server pytest",
57
+ "test:speech": "uv run --directory apps/speech-server pytest",
58
+ "test:embedding": "uv run --directory apps/embedding-server pytest",
59
+ "check:agent": "uv run --directory apps/agent-server ruff check . && uv run --directory apps/agent-server ruff format --check . && uv run --directory apps/agent-server mypy",
60
+ "check:document": "uv run --directory apps/document-server ruff check . && uv run --directory apps/document-server ruff format --check . && uv run --directory apps/document-server mypy",
61
+ "check:speech": "uv run --directory apps/speech-server ruff check . && uv run --directory apps/speech-server ruff format --check . && uv run --directory apps/speech-server mypy",
62
+ "check:embedding": "uv run --directory apps/embedding-server ruff check . && uv run --directory apps/embedding-server ruff format --check . && uv run --directory apps/embedding-server mypy",
50
63
  "typecheck": "bun run --cwd apps/web typecheck && bun run --cwd apps/server typecheck && bun run --cwd apps/license typecheck && bun run --cwd apps/signing-service typecheck && bun run --cwd packages/ai-client typecheck && bun run --cwd packages/license-sdk typecheck && bun run --cwd packages/jobs typecheck && bun run --cwd packages/server-sdk typecheck && bun run --cwd packages/storage typecheck && bun run --cwd packages/database typecheck && bun run --cwd packages/crud-generator typecheck && bun run --cwd packages/create-windy typecheck",
51
64
  "lint": "oxlint .",
52
65
  "format": "oxfmt",
66
+ "check:static": "bun run lint && bun run typecheck && bun run check:agent && bun run check:document && bun run check:speech && bun run check:embedding",
53
67
  "format:staged": "lint-staged",
54
68
  "test": "bun test --path-ignore-patterns='packages/create-windy/template/**' && bun run --cwd apps/web test"
55
69
  },
@@ -1 +1,5 @@
1
1
  export * from "./src/agent/index.js";
2
+ export type { ArtifactRef } from "./src/artifact-ref.js";
3
+ export * from "./src/document/index.js";
4
+ export * from "./src/embedding/index.js";
5
+ export * from "./src/speech/index.js";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@southwind-ai/ai-client",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "engines": {
@@ -18,7 +18,10 @@
18
18
  "exports": {
19
19
  ".": "./index.ts",
20
20
  "./agent": "./src/agent/index.ts",
21
- "./contracts": "./src/agent/contracts/index.ts"
21
+ "./contracts": "./src/agent/contracts/index.ts",
22
+ "./document": "./src/document/index.ts",
23
+ "./embedding": "./src/embedding/index.ts",
24
+ "./speech": "./src/speech/index.ts"
22
25
  },
23
26
  "publishConfig": {
24
27
  "access": "public"
@@ -0,0 +1,26 @@
1
+ import type { ArtifactRef } from "../../artifact-ref.js";
2
+ import { AgentClientError } from "./error.js";
3
+
4
+ export function parseAgentArtifactRef(value: ArtifactRef): ArtifactRef {
5
+ if (
6
+ !value.value.trim() ||
7
+ /^[a-z][a-z0-9+.-]*:\/\//i.test(value.value) ||
8
+ !value.mediaType.trim() ||
9
+ !Number.isSafeInteger(value.byteSize) ||
10
+ value.byteSize < 0 ||
11
+ !/^[a-f0-9]{64}$/.test(value.sha256)
12
+ ) {
13
+ throw new AgentClientError(
14
+ "INVALID_CONFIGURATION",
15
+ "Agent ArtifactRef 无效",
16
+ false,
17
+ );
18
+ }
19
+ return {
20
+ value: value.value,
21
+ mediaType: value.mediaType,
22
+ byteSize: value.byteSize,
23
+ sha256: value.sha256,
24
+ ...(value.expiresAt ? { expiresAt: value.expiresAt } : {}),
25
+ };
26
+ }
@@ -0,0 +1,124 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import {
3
+ createAgentCaller,
4
+ defineAgentOperation,
5
+ type AgentEvent,
6
+ } from "@southwind-ai/ai-client";
7
+ import type { AgentFetch } from "./types.js";
8
+
9
+ const operation = defineAgentOperation<null, { answer: string }>(
10
+ "support.answer",
11
+ (value) => value as { answer: string },
12
+ );
13
+
14
+ describe("Agent Run attach", () => {
15
+ test("从游标之后恢复同一个 live Run", async () => {
16
+ const fake = plannedFetch([
17
+ () =>
18
+ Response.json({
19
+ runId: "run-live",
20
+ status: "running",
21
+ lastSequence: 3,
22
+ eventsUrl:
23
+ "/api/agent/runs/run-live/events?operationKey=support.answer",
24
+ }),
25
+ () =>
26
+ sse([
27
+ event({
28
+ type: "output.delta",
29
+ runId: "run-live",
30
+ sequence: 3,
31
+ text: "A",
32
+ }),
33
+ event({ type: "run.completed", runId: "run-live", sequence: 4 }),
34
+ ]),
35
+ () =>
36
+ Response.json({
37
+ runId: "run-live",
38
+ status: "completed",
39
+ output: { answer: "A" },
40
+ }),
41
+ ]);
42
+ const caller = createAgentCaller({
43
+ baseUrl: "https://agent.internal",
44
+ fetch: fake.fetch,
45
+ });
46
+
47
+ const run = await caller.attach(operation, "run-live", { cursor: 2 });
48
+ const collected = collect(run.events);
49
+
50
+ await expect(run.result()).resolves.toEqual({ answer: "A" });
51
+ expect((await collected).map(({ sequence }) => sequence)).toEqual([3, 4]);
52
+ expect(JSON.parse(String(fake.calls[0]?.init?.body))).toEqual({
53
+ operationKey: "support.answer",
54
+ cursor: 2,
55
+ });
56
+ expect(fake.calls[1]?.url.searchParams.get("after")).toBe("2");
57
+ expect(fake.calls[2]?.url.searchParams.get("operationKey")).toBe(
58
+ "support.answer",
59
+ );
60
+ });
61
+
62
+ test("终态游标可直接读取结果且不重新连接事件流", async () => {
63
+ const fake = plannedFetch([
64
+ () =>
65
+ Response.json({
66
+ runId: "run-done",
67
+ status: "completed",
68
+ lastSequence: 4,
69
+ terminalEvent: {
70
+ type: "run.completed",
71
+ runId: "run-done",
72
+ sequence: 4,
73
+ },
74
+ eventsUrl:
75
+ "/api/agent/runs/run-done/events?operationKey=support.answer",
76
+ }),
77
+ () =>
78
+ Response.json({
79
+ runId: "run-done",
80
+ status: "completed",
81
+ output: { answer: "完成" },
82
+ }),
83
+ ]);
84
+ const caller = createAgentCaller({
85
+ baseUrl: "https://agent.internal",
86
+ fetch: fake.fetch,
87
+ });
88
+
89
+ const run = await caller.resume(operation, "run-done", { cursor: 4 });
90
+
91
+ await expect(run.result()).resolves.toEqual({ answer: "完成" });
92
+ expect(fake.calls).toHaveLength(2);
93
+ });
94
+ });
95
+
96
+ function plannedFetch(plans: Array<(url: URL) => Response>) {
97
+ const calls: Array<{ url: URL; init?: RequestInit }> = [];
98
+ const fetch: AgentFetch = async (input, init) => {
99
+ const url = new URL(
100
+ input instanceof Request ? input.url : input.toString(),
101
+ );
102
+ calls.push({ url, init });
103
+ const plan = plans[calls.length - 1];
104
+ if (!plan) throw new Error(`unexpected fetch ${url}`);
105
+ return plan(url);
106
+ };
107
+ return { calls, fetch };
108
+ }
109
+
110
+ function sse(frames: string[]): Response {
111
+ return new Response(frames.join(""), {
112
+ headers: { "content-type": "text/event-stream" },
113
+ });
114
+ }
115
+
116
+ function event(value: AgentEvent): string {
117
+ return `id: ${value.sequence}\nevent: ${value.type}\ndata: ${JSON.stringify(value)}\n\n`;
118
+ }
119
+
120
+ async function collect(events: AsyncIterable<AgentEvent>) {
121
+ const values: AgentEvent[] = [];
122
+ for await (const value of events) values.push(value);
123
+ return values;
124
+ }