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,96 @@
1
+ import type {
2
+ EmbeddingClient,
3
+ EmbeddingFetch,
4
+ EmbeddingOperation,
5
+ EmbeddingInput,
6
+ } from "./contracts.js";
7
+ import { EmbeddingClientError, embeddingHttpError } from "./error.js";
8
+ import { normalizeInputs, parseBatchResult } from "./validation.js";
9
+
10
+ export interface EmbeddingClientOptions {
11
+ readonly baseUrl: string | URL;
12
+ readonly path?: string;
13
+ readonly fetch?: EmbeddingFetch;
14
+ }
15
+
16
+ export class HttpEmbeddingClient implements EmbeddingClient {
17
+ readonly #baseUrl: URL;
18
+ readonly #path: string;
19
+ readonly #fetch: EmbeddingFetch;
20
+
21
+ constructor(options: EmbeddingClientOptions) {
22
+ this.#baseUrl = new URL(options.baseUrl);
23
+ if (!["http:", "https:"].includes(this.#baseUrl.protocol)) {
24
+ throw invalidConfiguration("Embedding Client 只允许 HTTP 或 HTTPS");
25
+ }
26
+ this.#path = options.path ?? "/api/embeddings";
27
+ this.#fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
28
+ }
29
+
30
+ async embed<Options>(
31
+ operation: EmbeddingOperation<Options>,
32
+ input: {
33
+ readonly items: readonly EmbeddingInput[];
34
+ readonly options?: Options;
35
+ },
36
+ context: { readonly idempotencyKey: string; readonly signal?: AbortSignal },
37
+ ) {
38
+ if (!operation.key.trim() || !context.idempotencyKey.trim()) {
39
+ throw invalidConfiguration("Embedding Operation 与幂等键不能为空");
40
+ }
41
+ const items = normalizeInputs(input.items);
42
+ const options =
43
+ input.options === undefined
44
+ ? undefined
45
+ : (operation.parseOptions?.(input.options) ?? input.options);
46
+ let response: Response;
47
+ try {
48
+ response = await this.#fetch(new URL(this.#path, this.#baseUrl), {
49
+ method: "POST",
50
+ headers: {
51
+ "content-type": "application/json",
52
+ "idempotency-key": context.idempotencyKey,
53
+ },
54
+ body: JSON.stringify({
55
+ operationKey: operation.key,
56
+ items,
57
+ ...(options === undefined ? {} : { options }),
58
+ }),
59
+ signal: context.signal,
60
+ });
61
+ } catch (error) {
62
+ throw new EmbeddingClientError(
63
+ context.signal?.aborted ? "RUN_CANCELLED" : "RUNTIME_UNAVAILABLE",
64
+ context.signal?.aborted
65
+ ? "Embedding 请求已取消"
66
+ : "Embedding Runtime 暂不可用",
67
+ !context.signal?.aborted,
68
+ undefined,
69
+ { cause: error },
70
+ );
71
+ }
72
+ if (!response.ok) {
73
+ throw await embeddingHttpError(response, "Embedding 请求失败");
74
+ }
75
+ const result = parseBatchResult(await response.json());
76
+ if (
77
+ result.items.length !== items.length ||
78
+ result.items.some((item, index) => item.id !== items[index]?.id)
79
+ ) {
80
+ throw new EmbeddingClientError(
81
+ "INVALID_RESPONSE",
82
+ "Embedding 响应输入顺序不一致",
83
+ false,
84
+ );
85
+ }
86
+ return result;
87
+ }
88
+ }
89
+
90
+ export function createEmbeddingClient(options: EmbeddingClientOptions) {
91
+ return new HttpEmbeddingClient(options);
92
+ }
93
+
94
+ function invalidConfiguration(message: string) {
95
+ return new EmbeddingClientError("INVALID_CONFIGURATION", message, false);
96
+ }
@@ -0,0 +1,46 @@
1
+ import type { ArtifactRef } from "../artifact-ref.js";
2
+
3
+ export type EmbeddingFetch = (
4
+ input: string | URL | Request,
5
+ init?: RequestInit,
6
+ ) => Promise<Response>;
7
+
8
+ export interface EmbeddingOperation<Options> {
9
+ readonly key: string;
10
+ parseOptions?(value: Options): Options;
11
+ }
12
+
13
+ export type EmbeddingInput =
14
+ | { readonly id: string; readonly text: string }
15
+ | { readonly id: string; readonly source: ArtifactRef };
16
+
17
+ export interface EmbeddingVector {
18
+ readonly id: string;
19
+ readonly vector: readonly number[];
20
+ readonly inputSha256: string;
21
+ }
22
+
23
+ export interface EmbeddingMetadata {
24
+ readonly deploymentAlias: string;
25
+ readonly model: string;
26
+ readonly version: string;
27
+ readonly dimensions: number;
28
+ readonly normalized: boolean;
29
+ }
30
+
31
+ export interface EmbeddingBatchResult {
32
+ readonly batchId: string;
33
+ readonly items: readonly EmbeddingVector[];
34
+ readonly metadata: EmbeddingMetadata;
35
+ }
36
+
37
+ export interface EmbeddingClient {
38
+ embed<Options>(
39
+ operation: EmbeddingOperation<Options>,
40
+ input: {
41
+ readonly items: readonly EmbeddingInput[];
42
+ readonly options?: Options;
43
+ },
44
+ context: { readonly idempotencyKey: string; readonly signal?: AbortSignal },
45
+ ): Promise<EmbeddingBatchResult>;
46
+ }
@@ -0,0 +1,61 @@
1
+ export class EmbeddingClientError extends Error {
2
+ constructor(
3
+ readonly code:
4
+ | "INVALID_CONFIGURATION"
5
+ | "INVALID_INPUT"
6
+ | "FORBIDDEN"
7
+ | "CAPABILITY_UNAVAILABLE"
8
+ | "RUNTIME_UNAVAILABLE"
9
+ | "RUN_CANCELLED"
10
+ | "BUDGET_EXCEEDED"
11
+ | "RUN_CONFLICT"
12
+ | "INVALID_RESPONSE",
13
+ message: string,
14
+ readonly retryable: boolean,
15
+ readonly requestId?: string,
16
+ options?: ErrorOptions,
17
+ ) {
18
+ super(message, options);
19
+ this.name = "EmbeddingClientError";
20
+ }
21
+ }
22
+
23
+ export async function embeddingHttpError(response: Response, fallback: string) {
24
+ try {
25
+ const value = (await response.json()) as Record<string, unknown>;
26
+ if (
27
+ typeof value.code === "string" &&
28
+ typeof value.message === "string" &&
29
+ typeof value.retryable === "boolean" &&
30
+ value.message.length <= 200
31
+ ) {
32
+ return new EmbeddingClientError(
33
+ knownCode(value.code),
34
+ value.message,
35
+ value.retryable,
36
+ typeof value.requestId === "string" ? value.requestId : undefined,
37
+ );
38
+ }
39
+ } catch {
40
+ // 不透传不可信正文。
41
+ }
42
+ return new EmbeddingClientError(
43
+ "RUNTIME_UNAVAILABLE",
44
+ `${fallback}(HTTP ${response.status})`,
45
+ response.status >= 500,
46
+ );
47
+ }
48
+
49
+ function knownCode(code: string): EmbeddingClientError["code"] {
50
+ return [
51
+ "INVALID_INPUT",
52
+ "FORBIDDEN",
53
+ "CAPABILITY_UNAVAILABLE",
54
+ "RUNTIME_UNAVAILABLE",
55
+ "RUN_CANCELLED",
56
+ "BUDGET_EXCEEDED",
57
+ "RUN_CONFLICT",
58
+ ].includes(code)
59
+ ? (code as EmbeddingClientError["code"])
60
+ : "RUNTIME_UNAVAILABLE";
61
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./client.js";
2
+ export * from "./contracts.js";
3
+ export * from "./error.js";
@@ -0,0 +1,117 @@
1
+ import type { EmbeddingBatchResult, EmbeddingInput } from "./contracts.js";
2
+ import { EmbeddingClientError } from "./error.js";
3
+
4
+ export function normalizeInputs(
5
+ inputs: readonly EmbeddingInput[],
6
+ ): readonly EmbeddingInput[] {
7
+ if (!inputs.length) invalid("Embedding 输入不能为空");
8
+ const ids = new Set<string>();
9
+ return inputs.map((input) => {
10
+ if (!input.id.trim() || ids.has(input.id))
11
+ invalid("Embedding ID 无效或重复");
12
+ ids.add(input.id);
13
+ if ("text" in input) {
14
+ if (!input.text.trim()) invalid("Embedding 文本不能为空");
15
+ return { id: input.id, text: input.text };
16
+ }
17
+ const source = input.source;
18
+ if (
19
+ !source.value.trim() ||
20
+ /^[a-z][a-z0-9+.-]*:\/\//i.test(source.value) ||
21
+ !source.mediaType.trim() ||
22
+ !Number.isSafeInteger(source.byteSize) ||
23
+ source.byteSize < 1 ||
24
+ !/^[a-f0-9]{64}$/.test(source.sha256)
25
+ ) {
26
+ invalid("Embedding ArtifactRef 无效");
27
+ }
28
+ return {
29
+ id: input.id,
30
+ source: {
31
+ value: source.value,
32
+ mediaType: source.mediaType,
33
+ byteSize: source.byteSize,
34
+ sha256: source.sha256,
35
+ ...(source.expiresAt ? { expiresAt: source.expiresAt } : {}),
36
+ },
37
+ };
38
+ });
39
+ }
40
+
41
+ export function parseBatchResult(value: unknown): EmbeddingBatchResult {
42
+ const root = record(value, "EmbeddingResult");
43
+ const metadata = record(root.metadata, "EmbeddingResult.metadata");
44
+ const dimensions = integer(
45
+ metadata.dimensions,
46
+ "EmbeddingResult.metadata.dimensions",
47
+ 1,
48
+ );
49
+ if (typeof metadata.normalized !== "boolean") {
50
+ invalid("EmbeddingResult.metadata.normalized");
51
+ }
52
+ if (!Array.isArray(root.items) || !root.items.length) {
53
+ invalid("EmbeddingResult.items");
54
+ }
55
+ const ids = new Set<string>();
56
+ const items = root.items.map((raw, index) => {
57
+ const item = record(raw, `EmbeddingResult.items[${index}]`);
58
+ const id = text(item.id, `EmbeddingResult.items[${index}].id`);
59
+ if (ids.has(id)) invalid(`EmbeddingResult.items[${index}].id`);
60
+ ids.add(id);
61
+ if (
62
+ !Array.isArray(item.vector) ||
63
+ item.vector.length !== dimensions ||
64
+ item.vector.some(
65
+ (entry) => typeof entry !== "number" || !Number.isFinite(entry),
66
+ )
67
+ ) {
68
+ invalid(`EmbeddingResult.items[${index}].vector`);
69
+ }
70
+ const inputSha256 = text(
71
+ item.inputSha256,
72
+ `EmbeddingResult.items[${index}].inputSha256`,
73
+ );
74
+ if (!/^[a-f0-9]{64}$/.test(inputSha256)) {
75
+ invalid(`EmbeddingResult.items[${index}].inputSha256`);
76
+ }
77
+ return { id, vector: item.vector as number[], inputSha256 };
78
+ });
79
+ return {
80
+ batchId: text(root.batchId, "EmbeddingResult.batchId"),
81
+ items,
82
+ metadata: {
83
+ deploymentAlias: text(
84
+ metadata.deploymentAlias,
85
+ "EmbeddingResult.metadata.deploymentAlias",
86
+ ),
87
+ model: text(metadata.model, "EmbeddingResult.metadata.model"),
88
+ version: text(metadata.version, "EmbeddingResult.metadata.version"),
89
+ dimensions,
90
+ normalized: metadata.normalized,
91
+ },
92
+ };
93
+ }
94
+
95
+ function record(value: unknown, path: string): Record<string, unknown> {
96
+ if (!value || typeof value !== "object" || Array.isArray(value))
97
+ invalid(path);
98
+ return value as Record<string, unknown>;
99
+ }
100
+
101
+ function text(value: unknown, path: string) {
102
+ if (typeof value !== "string" || !value.trim()) invalid(path);
103
+ return value;
104
+ }
105
+
106
+ function integer(value: unknown, path: string, minimum: number) {
107
+ if (!Number.isSafeInteger(value) || Number(value) < minimum) invalid(path);
108
+ return Number(value);
109
+ }
110
+
111
+ function invalid(path: string): never {
112
+ throw new EmbeddingClientError(
113
+ "INVALID_RESPONSE",
114
+ `Embedding 响应字段无效:${path}`,
115
+ false,
116
+ );
117
+ }
@@ -0,0 +1,135 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { createSpeechAiClient } from "./client.js";
3
+ import type { SpeechTranscriptionResult } from "./contracts.js";
4
+ import { SpeechClientError } from "./error.js";
5
+
6
+ const source = {
7
+ value: "artifact_opaque",
8
+ mediaType: "audio/mpeg",
9
+ byteSize: 128,
10
+ sha256: "a".repeat(64),
11
+ };
12
+
13
+ describe("Speech AI Client", () => {
14
+ test("提交、分段事件、结果 Artifact 与取消使用稳定批量协议", async () => {
15
+ const requests: Array<{ url: string; init?: RequestInit }> = [];
16
+ const client = createSpeechAiClient({
17
+ baseUrl: "https://windy.example",
18
+ fetch: async (input, init) => {
19
+ const url = String(input);
20
+ requests.push({ url, init });
21
+ if (url.endsWith("/api/speech/runs")) {
22
+ return Response.json({
23
+ runId: "speech-run-1",
24
+ status: "accepted",
25
+ eventsUrl: "/api/speech/runs/speech-run-1/events",
26
+ });
27
+ }
28
+ if (url.includes("/events")) {
29
+ return new Response(
30
+ [
31
+ 'data: {"type":"run.started","runId":"speech-run-1","sequence":1}',
32
+ "",
33
+ 'data: {"type":"speech.segment.completed","runId":"speech-run-1","sequence":2,"completedSegments":1,"totalSegments":1,"endMs":2500}',
34
+ "",
35
+ 'data: {"type":"run.completed","runId":"speech-run-1","sequence":3}',
36
+ "",
37
+ "",
38
+ ].join("\n"),
39
+ );
40
+ }
41
+ if (url.endsWith("/result")) {
42
+ return Response.json({
43
+ output: {
44
+ language: "zh",
45
+ durationMs: 2500,
46
+ segments: [],
47
+ metadata: { engine: "local" },
48
+ artifact: {
49
+ mediaType: "application/json",
50
+ byteSize: 64,
51
+ sha256: "b".repeat(64),
52
+ },
53
+ },
54
+ });
55
+ }
56
+ if (url.endsWith("/artifact")) {
57
+ return new Response('{"segments":[]}', {
58
+ headers: {
59
+ "content-type": "application/json",
60
+ "content-length": "15",
61
+ "x-content-sha256": "b".repeat(64),
62
+ },
63
+ });
64
+ }
65
+ return Response.json({ runId: "speech-run-1", status: "cancelled" });
66
+ },
67
+ });
68
+ const run = await client.transcribe(
69
+ {
70
+ key: "speech.transcribe.batch",
71
+ parseOutput(value) {
72
+ return value as SpeechTranscriptionResult;
73
+ },
74
+ },
75
+ {
76
+ source,
77
+ options: {
78
+ language: "zh",
79
+ timestamps: "segment",
80
+ vad: { enabled: true },
81
+ },
82
+ },
83
+ { idempotencyKey: "speech-1" },
84
+ );
85
+
86
+ const events = [];
87
+ for await (const event of run.events) events.push(event);
88
+ expect(events.map(({ type }) => type)).toEqual([
89
+ "run.started",
90
+ "speech.segment.completed",
91
+ "run.completed",
92
+ ]);
93
+ expect((await run.result()).durationMs).toBe(2500);
94
+ expect((await run.artifact()).sha256).toBe("b".repeat(64));
95
+ await run.cancel("不再需要");
96
+ expect(JSON.parse(String(requests[0]?.init?.body))).toEqual({
97
+ operationKey: "speech.transcribe.batch",
98
+ source,
99
+ options: {
100
+ language: "zh",
101
+ timestamps: "segment",
102
+ vad: { enabled: true },
103
+ },
104
+ });
105
+ expect(requests[0]?.init?.headers).toMatchObject({
106
+ "idempotency-key": "speech-1",
107
+ });
108
+ });
109
+
110
+ test("拒绝无效 ArtifactRef 和跨 Origin events URL", async () => {
111
+ const client = createSpeechAiClient({
112
+ baseUrl: "https://windy.example",
113
+ fetch: async () =>
114
+ Response.json({
115
+ runId: "speech-run-1",
116
+ status: "accepted",
117
+ eventsUrl: "https://evil.example/events",
118
+ }),
119
+ });
120
+ await expect(
121
+ client.transcribe(
122
+ { key: "speech.transcribe.batch", parseOutput: (value) => value },
123
+ { source: { ...source, sha256: "invalid" } },
124
+ { idempotencyKey: "speech-invalid" },
125
+ ),
126
+ ).rejects.toBeInstanceOf(SpeechClientError);
127
+ await expect(
128
+ client.transcribe(
129
+ { key: "speech.transcribe.batch", parseOutput: (value) => value },
130
+ { source },
131
+ { idempotencyKey: "speech-origin" },
132
+ ),
133
+ ).rejects.toBeInstanceOf(SpeechClientError);
134
+ });
135
+ });
@@ -0,0 +1,104 @@
1
+ import type {
2
+ SpeechAiClient,
3
+ SpeechFetch,
4
+ SpeechOperation,
5
+ SpeechRun,
6
+ SubmitTranscriptionInput,
7
+ } from "./contracts.js";
8
+ import { SpeechClientError, speechHttpError } from "./error.js";
9
+ import { HttpSpeechRun } from "./run.js";
10
+ import { parseArtifactRef, parseCreatedRun } from "./validation.js";
11
+
12
+ export interface SpeechClientOptions {
13
+ readonly baseUrl: string | URL;
14
+ readonly runsPath?: string;
15
+ readonly fetch?: SpeechFetch;
16
+ }
17
+
18
+ export class HttpSpeechAiClient implements SpeechAiClient {
19
+ private readonly baseUrl: URL;
20
+ private readonly runsPath: string;
21
+ private readonly fetch: SpeechFetch;
22
+
23
+ constructor(options: SpeechClientOptions) {
24
+ this.baseUrl = new URL(options.baseUrl);
25
+ if (!["http:", "https:"].includes(this.baseUrl.protocol)) {
26
+ throw new SpeechClientError(
27
+ "INVALID_CONFIGURATION",
28
+ "Speech Client 只允许 HTTP 或 HTTPS",
29
+ false,
30
+ );
31
+ }
32
+ this.runsPath = options.runsPath ?? "/api/speech/runs";
33
+ this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
34
+ }
35
+
36
+ async transcribe<Options, Output>(
37
+ operation: SpeechOperation<Options, Output>,
38
+ input: SubmitTranscriptionInput<Options>,
39
+ context: { idempotencyKey: string; signal?: AbortSignal },
40
+ ): Promise<SpeechRun<Output>> {
41
+ if (!operation.key.trim() || !context.idempotencyKey.trim()) {
42
+ throw new SpeechClientError(
43
+ "INVALID_CONFIGURATION",
44
+ "Speech Operation 与幂等键不能为空",
45
+ false,
46
+ );
47
+ }
48
+ const source = parseArtifactRef(input.source);
49
+ const options = input.options
50
+ ? (operation.parseOptions?.(input.options) ?? input.options)
51
+ : undefined;
52
+ let response: Response;
53
+ try {
54
+ response = await this.fetch(this.endpoint(this.runsPath), {
55
+ method: "POST",
56
+ headers: {
57
+ "content-type": "application/json",
58
+ "idempotency-key": context.idempotencyKey,
59
+ },
60
+ body: JSON.stringify({ operationKey: operation.key, source, options }),
61
+ signal: context.signal,
62
+ });
63
+ } catch (error) {
64
+ throw new SpeechClientError(
65
+ context.signal?.aborted ? "RUN_CANCELLED" : "RUNTIME_UNAVAILABLE",
66
+ context.signal?.aborted
67
+ ? "创建转写任务已取消"
68
+ : "Speech Runtime 暂不可用",
69
+ !context.signal?.aborted,
70
+ undefined,
71
+ { cause: error },
72
+ );
73
+ }
74
+ if (!response.ok) throw await speechHttpError(response, "创建转写任务失败");
75
+ const created = parseCreatedRun(await response.json());
76
+ const runPath = `${this.runsPath}/${encodeURIComponent(created.runId)}`;
77
+ return new HttpSpeechRun({
78
+ id: created.runId,
79
+ eventsUrl: this.endpoint(created.eventsUrl),
80
+ resultUrl: this.endpoint(`${runPath}/result`),
81
+ artifactUrl: this.endpoint(`${runPath}/artifact`),
82
+ cancelUrl: this.endpoint(`${runPath}/cancel`),
83
+ fetch: this.fetch,
84
+ signal: context.signal,
85
+ parseOutput: operation.parseOutput,
86
+ });
87
+ }
88
+
89
+ private endpoint(path: string): URL {
90
+ const endpoint = new URL(path, this.baseUrl);
91
+ if (endpoint.origin !== this.baseUrl.origin) {
92
+ throw new SpeechClientError(
93
+ "INVALID_RESPONSE",
94
+ "Speech Runtime 返回了不受信任的 Endpoint",
95
+ false,
96
+ );
97
+ }
98
+ return endpoint;
99
+ }
100
+ }
101
+
102
+ export function createSpeechAiClient(options: SpeechClientOptions) {
103
+ return new HttpSpeechAiClient(options);
104
+ }
@@ -0,0 +1,129 @@
1
+ import type { ArtifactRef } from "../artifact-ref.js";
2
+
3
+ export type SpeechFetch = (
4
+ input: string | URL | Request,
5
+ init?: RequestInit,
6
+ ) => Promise<Response>;
7
+
8
+ export interface BatchTranscriptionOptions {
9
+ readonly language?: string;
10
+ readonly vad?: {
11
+ readonly enabled: boolean;
12
+ readonly minSpeechMs?: number;
13
+ readonly maxSilenceMs?: number;
14
+ };
15
+ readonly timestamps?: "segment" | "word";
16
+ }
17
+
18
+ export interface SpeechOperation<Options, Output> {
19
+ readonly key: string;
20
+ parseOutput(value: unknown): Output;
21
+ parseOptions?(value: Options): Options;
22
+ }
23
+
24
+ export interface SubmitTranscriptionInput<Options> {
25
+ readonly source: ArtifactRef;
26
+ readonly options?: Options & BatchTranscriptionOptions;
27
+ }
28
+
29
+ export interface SpeechWord {
30
+ readonly text: string;
31
+ readonly startMs: number;
32
+ readonly endMs: number;
33
+ readonly confidence?: number;
34
+ }
35
+
36
+ export interface SpeechSegment {
37
+ readonly id: string;
38
+ readonly text: string;
39
+ readonly startMs: number;
40
+ readonly endMs: number;
41
+ readonly confidence?: number;
42
+ readonly language?: string;
43
+ readonly words?: readonly SpeechWord[];
44
+ }
45
+
46
+ export interface SpeechResultArtifactMetadata {
47
+ readonly mediaType: "application/json";
48
+ readonly byteSize: number;
49
+ readonly sha256: string;
50
+ }
51
+
52
+ export interface SpeechTranscriptionResult {
53
+ readonly language?: string;
54
+ readonly durationMs: number;
55
+ readonly segments: readonly SpeechSegment[];
56
+ readonly metadata: Readonly<Record<string, string | number | boolean>>;
57
+ readonly artifact: SpeechResultArtifactMetadata;
58
+ }
59
+
60
+ export interface OpenedSpeechResultArtifact extends SpeechResultArtifactMetadata {
61
+ readonly body: ReadableStream<Uint8Array>;
62
+ }
63
+
64
+ export type SpeechRunStatus =
65
+ | "accepted"
66
+ | "running"
67
+ | "completed"
68
+ | "failed"
69
+ | "cancelled";
70
+
71
+ export type SpeechEvent =
72
+ | {
73
+ readonly type: "run.started" | "run.completed" | "run.cancelled";
74
+ readonly runId: string;
75
+ readonly sequence: number;
76
+ }
77
+ | {
78
+ readonly type: "speech.segment.completed";
79
+ readonly runId: string;
80
+ readonly sequence: number;
81
+ readonly completedSegments: number;
82
+ readonly totalSegments: number;
83
+ readonly endMs: number;
84
+ }
85
+ | {
86
+ readonly type: "run.failed";
87
+ readonly runId: string;
88
+ readonly sequence: number;
89
+ readonly error: SpeechErrorPayload;
90
+ };
91
+
92
+ export interface SpeechErrorPayload {
93
+ readonly code: SpeechErrorCode;
94
+ readonly message: string;
95
+ readonly requestId: string;
96
+ readonly retryable: boolean;
97
+ }
98
+
99
+ export type SpeechErrorCode =
100
+ | "OPERATION_NOT_FOUND"
101
+ | "OPERATION_DISABLED"
102
+ | "INVALID_INPUT"
103
+ | "FORBIDDEN"
104
+ | "LICENSE_NOT_ALLOWED"
105
+ | "ARTIFACT_UNAVAILABLE"
106
+ | "ARTIFACT_EXPIRED"
107
+ | "CAPABILITY_UNAVAILABLE"
108
+ | "RUNTIME_UNAVAILABLE"
109
+ | "BUDGET_EXCEEDED"
110
+ | "OUTPUT_VALIDATION_FAILED"
111
+ | "RUN_CONFLICT"
112
+ | "RUN_TIMEOUT"
113
+ | "RUN_CANCELLED";
114
+
115
+ export interface SpeechRun<Output> {
116
+ readonly id: string;
117
+ readonly events: AsyncIterable<SpeechEvent>;
118
+ result(): Promise<Output>;
119
+ artifact(): Promise<OpenedSpeechResultArtifact>;
120
+ cancel(reason?: string): Promise<void>;
121
+ }
122
+
123
+ export interface SpeechAiClient {
124
+ transcribe<Options, Output>(
125
+ operation: SpeechOperation<Options, Output>,
126
+ input: SubmitTranscriptionInput<Options>,
127
+ context: { idempotencyKey: string; signal?: AbortSignal },
128
+ ): Promise<SpeechRun<Output>>;
129
+ }