create-windy 0.5.2 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (589) hide show
  1. package/dist/cli.js +370 -156
  2. package/package.json +2 -1
  3. package/template/.windy-template.json +2 -2
  4. package/template/apps/agent-server/README.md +25 -6
  5. package/template/apps/agent-server/src/southwind_agent_server/adk_adapter.py +15 -2
  6. package/template/apps/agent-server/src/southwind_agent_server/app.py +13 -34
  7. package/template/apps/agent-server/src/southwind_agent_server/config.py +49 -0
  8. package/template/apps/agent-server/src/southwind_agent_server/contracts.py +13 -0
  9. package/template/apps/agent-server/src/southwind_agent_server/engine_capacity.py +31 -0
  10. package/template/apps/agent-server/src/southwind_agent_server/fingerprint.py +5 -0
  11. package/template/apps/agent-server/src/southwind_agent_server/health_routes.py +50 -0
  12. package/template/apps/agent-server/src/southwind_agent_server/openai_engine.py +11 -2
  13. package/template/apps/agent-server/src/southwind_agent_server/openai_provider.py +3 -9
  14. package/template/apps/agent-server/src/southwind_agent_server/postgres_store.py +5 -0
  15. package/template/apps/agent-server/src/southwind_agent_server/readiness_pin.py +37 -0
  16. package/template/apps/agent-server/src/southwind_agent_server/run_admission.py +64 -0
  17. package/template/apps/agent-server/src/southwind_agent_server/run_capacity.py +59 -0
  18. package/template/apps/agent-server/src/southwind_agent_server/service.py +42 -43
  19. package/template/apps/agent-server/src/southwind_agent_server/service_errors.py +4 -0
  20. package/template/apps/agent-server/src/southwind_agent_server/service_execution.py +31 -0
  21. package/template/apps/agent-server/src/southwind_agent_server/service_tasks.py +34 -0
  22. package/template/apps/agent-server/src/southwind_agent_server/sqlite_catalog.py +11 -0
  23. package/template/apps/agent-server/src/southwind_agent_server/store.py +6 -0
  24. package/template/apps/agent-server/src/southwind_agent_server/vision_probe.py +87 -0
  25. package/template/apps/agent-server/src/southwind_agent_server/vision_requirement.py +28 -0
  26. package/template/apps/agent-server/src/southwind_agent_server/vlm_readiness.py +247 -0
  27. package/template/apps/agent-server/tests/test_api.py +16 -3
  28. package/template/apps/agent-server/tests/test_openai_provider.py +21 -4
  29. package/template/apps/agent-server/tests/test_postgres_store.py +3 -0
  30. package/template/apps/agent-server/tests/test_run_capacity.py +110 -0
  31. package/template/apps/agent-server/tests/test_runtime_factory_readiness.py +37 -0
  32. package/template/apps/agent-server/tests/test_sqlite_store.py +3 -0
  33. package/template/apps/agent-server/tests/test_vision_readiness_enforcement.py +72 -0
  34. package/template/apps/agent-server/tests/test_vlm_readiness.py +106 -0
  35. package/template/apps/document-server/src/southwind_document_server/adapter.py +117 -205
  36. package/template/apps/document-server/src/southwind_document_server/adapter_errors.py +13 -0
  37. package/template/apps/document-server/src/southwind_document_server/app.py +62 -14
  38. package/template/apps/document-server/src/southwind_document_server/artifacts.py +27 -0
  39. package/template/apps/document-server/src/southwind_document_server/config.py +96 -2
  40. package/template/apps/document-server/src/southwind_document_server/contracts.py +168 -13
  41. package/template/apps/document-server/src/southwind_document_server/fingerprint.py +128 -0
  42. package/template/apps/document-server/src/southwind_document_server/grants.py +81 -0
  43. package/template/apps/document-server/src/southwind_document_server/multipart_output.py +265 -0
  44. package/template/apps/document-server/src/southwind_document_server/output_validation.py +202 -0
  45. package/template/apps/document-server/src/southwind_document_server/progress.py +27 -0
  46. package/template/apps/document-server/src/southwind_document_server/readiness.py +280 -0
  47. package/template/apps/document-server/src/southwind_document_server/readiness_contracts.py +280 -0
  48. package/template/apps/document-server/src/southwind_document_server/readiness_http.py +87 -0
  49. package/template/apps/document-server/src/southwind_document_server/readiness_support.py +120 -0
  50. package/template/apps/document-server/src/southwind_document_server/request_validation.py +48 -0
  51. package/template/apps/document-server/src/southwind_document_server/service.py +297 -96
  52. package/template/apps/document-server/src/southwind_document_server/service_recovery.py +183 -0
  53. package/template/apps/document-server/src/southwind_document_server/sink.py +316 -0
  54. package/template/apps/document-server/src/southwind_document_server/store.py +301 -141
  55. package/template/apps/document-server/src/southwind_document_server/store_events.py +40 -0
  56. package/template/apps/document-server/src/southwind_document_server/store_models.py +62 -0
  57. package/template/apps/document-server/src/southwind_document_server/store_recovery.py +247 -0
  58. package/template/apps/document-server/src/southwind_document_server/store_schema.py +50 -0
  59. package/template/apps/document-server/tests/recovery_support.py +230 -0
  60. package/template/apps/document-server/tests/support.py +210 -0
  61. package/template/apps/document-server/tests/test_adapter.py +251 -0
  62. package/template/apps/document-server/tests/test_config.py +43 -0
  63. package/template/apps/document-server/tests/test_contracts.py +80 -0
  64. package/template/apps/document-server/tests/test_fingerprint.py +125 -0
  65. package/template/apps/document-server/tests/test_grants.py +46 -0
  66. package/template/apps/document-server/tests/test_handshake.py +154 -0
  67. package/template/apps/document-server/tests/test_integration.py +192 -0
  68. package/template/apps/document-server/tests/test_multipart_security.py +259 -0
  69. package/template/apps/document-server/tests/test_readiness.py +311 -0
  70. package/template/apps/document-server/tests/test_readiness_contracts.py +131 -0
  71. package/template/apps/document-server/tests/test_recovery.py +222 -0
  72. package/template/apps/document-server/tests/test_recovery_faults.py +101 -0
  73. package/template/apps/document-server/tests/test_recovery_races.py +283 -0
  74. package/template/apps/document-server/tests/test_service.py +16 -13
  75. package/template/apps/document-server/tests/test_service_artifacts.py +296 -0
  76. package/template/apps/document-server/tests/test_sink.py +253 -0
  77. package/template/apps/document-server/tests/test_store.py +199 -0
  78. package/template/apps/embedding-server/pyproject.toml +5 -0
  79. package/template/apps/embedding-server/src/southwind_embedding_server/adapter.py +38 -2
  80. package/template/apps/embedding-server/src/southwind_embedding_server/app.py +135 -20
  81. package/template/apps/embedding-server/src/southwind_embedding_server/config.py +138 -4
  82. package/template/apps/embedding-server/src/southwind_embedding_server/contracts.py +13 -0
  83. package/template/apps/embedding-server/src/southwind_embedding_server/image_input.py +16 -5
  84. package/template/apps/embedding-server/src/southwind_embedding_server/pin_cli.py +62 -0
  85. package/template/apps/embedding-server/src/southwind_embedding_server/readiness.py +259 -0
  86. package/template/apps/embedding-server/src/southwind_embedding_server/readiness_contracts.py +221 -0
  87. package/template/apps/embedding-server/src/southwind_embedding_server/readiness_http.py +91 -0
  88. package/template/apps/embedding-server/src/southwind_embedding_server/run_cipher.py +31 -0
  89. package/template/apps/embedding-server/src/southwind_embedding_server/run_service.py +150 -0
  90. package/template/apps/embedding-server/src/southwind_embedding_server/run_store.py +250 -0
  91. package/template/apps/embedding-server/tests/test_adapter.py +25 -0
  92. package/template/apps/embedding-server/tests/test_config.py +13 -0
  93. package/template/apps/embedding-server/tests/test_readiness.py +202 -0
  94. package/template/apps/embedding-server/tests/test_run_http.py +257 -0
  95. package/template/apps/embedding-server/tests/test_run_service.py +202 -0
  96. package/template/apps/embedding-server/uv.lock +71 -0
  97. package/template/apps/server/Dockerfile +13 -0
  98. package/template/apps/server/package.json +1 -0
  99. package/template/apps/server/src/agent/drizzle-screenshot-intake-repository.integration.test.ts +286 -0
  100. package/template/apps/server/src/agent/drizzle-screenshot-intake-repository.ts +175 -0
  101. package/template/apps/server/src/agent/persistent-screenshot-intake-producer.ts +320 -0
  102. package/template/apps/server/src/agent/remote-runtime.ts +8 -1
  103. package/template/apps/server/src/agent/required-environment.ts +5 -0
  104. package/template/apps/server/src/agent/run-attach.ts +41 -0
  105. package/template/apps/server/src/agent/run-audit.ts +49 -0
  106. package/template/apps/server/src/agent/run-contracts.ts +6 -1
  107. package/template/apps/server/src/agent/run-facade.ts +67 -68
  108. package/template/apps/server/src/agent/run-route-input.ts +26 -1
  109. package/template/apps/server/src/agent/run-route-screenshot-context.test.ts +13 -0
  110. package/template/apps/server/src/agent/run-routes.ts +1 -0
  111. package/template/apps/server/src/agent/runtime-bootstrap-report.test.ts +1 -1
  112. package/template/apps/server/src/agent/runtime-bootstrap.ts +112 -60
  113. package/template/apps/server/src/agent/runtime-readiness-sources.test.ts +27 -0
  114. package/template/apps/server/src/agent/runtime-readiness-sources.ts +31 -0
  115. package/template/apps/server/src/agent/runtime-reporting-bootstrap.ts +40 -0
  116. package/template/apps/server/src/agent/screenshot-context-admission.test.ts +249 -0
  117. package/template/apps/server/src/agent/screenshot-context-attestation.ts +60 -0
  118. package/template/apps/server/src/agent/screenshot-intake-authorization.ts +29 -0
  119. package/template/apps/server/src/agent/screenshot-intake-bootstrap.ts +59 -0
  120. package/template/apps/server/src/agent/screenshot-intake-durable.ts +53 -0
  121. package/template/apps/server/src/agent/screenshot-intake-errors.ts +9 -0
  122. package/template/apps/server/src/agent/screenshot-intake-producer.ts +41 -0
  123. package/template/apps/server/src/agent/screenshot-intake-record.ts +44 -0
  124. package/template/apps/server/src/agent/screenshot-intake-recovery.ts +106 -0
  125. package/template/apps/server/src/agent/screenshot-intake-repository.ts +64 -0
  126. package/template/apps/server/src/agent/screenshot-intake-reservation.ts +24 -0
  127. package/template/apps/server/src/agent/screenshot-intake-routes.ts +171 -0
  128. package/template/apps/server/src/agent/screenshot-intake-runtime-types.ts +6 -0
  129. package/template/apps/server/src/agent/screenshot-intake-sweep.ts +26 -0
  130. package/template/apps/server/src/agent/screenshot-intake-test-support.ts +91 -0
  131. package/template/apps/server/src/agent/screenshot-intake-v2-validation.ts +176 -0
  132. package/template/apps/server/src/agent/screenshot-intake-v2.test.ts +345 -0
  133. package/template/apps/server/src/agent/screenshot-intake-v2.ts +348 -0
  134. package/template/apps/server/src/agent/screenshot-png.ts +15 -0
  135. package/template/apps/server/src/agent/screenshot-run-binding.ts +49 -0
  136. package/template/apps/server/src/agent/unavailable-routes.ts +9 -0
  137. package/template/apps/server/src/agent/vision-facade.test.ts +98 -8
  138. package/template/apps/server/src/agent/vision-input.ts +5 -2
  139. package/template/apps/server/src/agent/vision-readiness-pin.ts +32 -0
  140. package/template/apps/server/src/agent/vision-readiness.ts +58 -0
  141. package/template/apps/server/src/ai-artifact/runtime-reference.test.ts +135 -0
  142. package/template/apps/server/src/ai-artifact/runtime.ts +134 -5
  143. package/template/apps/server/src/ai-output-artifact/cleanup.ts +214 -0
  144. package/template/apps/server/src/ai-output-artifact/contracts.ts +152 -0
  145. package/template/apps/server/src/ai-output-artifact/drizzle-cleanup.ts +37 -0
  146. package/template/apps/server/src/ai-output-artifact/drizzle-complete.ts +71 -0
  147. package/template/apps/server/src/ai-output-artifact/drizzle-grant-cleanup.ts +45 -0
  148. package/template/apps/server/src/ai-output-artifact/drizzle-grants.ts +109 -0
  149. package/template/apps/server/src/ai-output-artifact/drizzle-mapping.ts +77 -0
  150. package/template/apps/server/src/ai-output-artifact/drizzle-readiness.ts +46 -0
  151. package/template/apps/server/src/ai-output-artifact/drizzle-repository.ts +350 -0
  152. package/template/apps/server/src/ai-output-artifact/drizzle-seal.ts +64 -0
  153. package/template/apps/server/src/ai-output-artifact/grant.ts +30 -0
  154. package/template/apps/server/src/ai-output-artifact/host-registry.ts +53 -0
  155. package/template/apps/server/src/ai-output-artifact/memory-cleanup.ts +47 -0
  156. package/template/apps/server/src/ai-output-artifact/memory-grants.ts +98 -0
  157. package/template/apps/server/src/ai-output-artifact/memory-readiness.ts +26 -0
  158. package/template/apps/server/src/ai-output-artifact/memory-repository.ts +348 -0
  159. package/template/apps/server/src/ai-output-artifact/policy.test.ts +67 -0
  160. package/template/apps/server/src/ai-output-artifact/policy.ts +125 -0
  161. package/template/apps/server/src/ai-output-artifact/postgres-test-support.ts +147 -0
  162. package/template/apps/server/src/ai-output-artifact/postgres.integration.test.ts +349 -0
  163. package/template/apps/server/src/ai-output-artifact/reference-codec.ts +128 -0
  164. package/template/apps/server/src/ai-output-artifact/repository-grant-invariants.test-support.ts +165 -0
  165. package/template/apps/server/src/ai-output-artifact/repository-invariants.test-support.ts +239 -0
  166. package/template/apps/server/src/ai-output-artifact/repository-invariants.test.ts +18 -0
  167. package/template/apps/server/src/ai-output-artifact/repository.ts +107 -0
  168. package/template/apps/server/src/ai-output-artifact/route-input.ts +173 -0
  169. package/template/apps/server/src/ai-output-artifact/routes-delete.test.ts +287 -0
  170. package/template/apps/server/src/ai-output-artifact/routes-grant.test.ts +116 -0
  171. package/template/apps/server/src/ai-output-artifact/routes-nonblocking-body.test.ts +136 -0
  172. package/template/apps/server/src/ai-output-artifact/routes-security.test.ts +176 -0
  173. package/template/apps/server/src/ai-output-artifact/routes-storage-error.test.ts +105 -0
  174. package/template/apps/server/src/ai-output-artifact/routes.test-support.ts +84 -0
  175. package/template/apps/server/src/ai-output-artifact/routes.test.ts +198 -0
  176. package/template/apps/server/src/ai-output-artifact/routes.ts +280 -0
  177. package/template/apps/server/src/ai-output-artifact/service-completion.ts +60 -0
  178. package/template/apps/server/src/ai-output-artifact/service-grants.test.ts +169 -0
  179. package/template/apps/server/src/ai-output-artifact/service-grants.ts +217 -0
  180. package/template/apps/server/src/ai-output-artifact/service-input.ts +175 -0
  181. package/template/apps/server/src/ai-output-artifact/service-read.ts +89 -0
  182. package/template/apps/server/src/ai-output-artifact/service-recovery.test.ts +238 -0
  183. package/template/apps/server/src/ai-output-artifact/service-support.ts +240 -0
  184. package/template/apps/server/src/ai-output-artifact/service.test.ts +283 -0
  185. package/template/apps/server/src/ai-output-artifact/service.ts +334 -0
  186. package/template/apps/server/src/ai-output-artifact/storage-recovery.ts +33 -0
  187. package/template/apps/server/src/ai-output-artifact/storage-writer.ts +103 -0
  188. package/template/apps/server/src/ai-output-artifact/test-support.ts +161 -0
  189. package/template/apps/server/src/ai-runtime-readiness/deployment-pin.ts +69 -0
  190. package/template/apps/server/src/ai-runtime-readiness/health-response.ts +92 -0
  191. package/template/apps/server/src/ai-runtime-readiness/operation-port-trust.test.ts +66 -0
  192. package/template/apps/server/src/ai-runtime-readiness/operation-port.test-support.ts +143 -0
  193. package/template/apps/server/src/ai-runtime-readiness/operation-port.test.ts +193 -0
  194. package/template/apps/server/src/ai-runtime-readiness/operation-port.ts +172 -0
  195. package/template/apps/server/src/ai-runtime-readiness/trust-store.ts +61 -0
  196. package/template/apps/server/src/app/ai-screenshot-intake-binding.ts +22 -0
  197. package/template/apps/server/src/app/document-output-artifact-bindings.ts +5 -0
  198. package/template/apps/server/src/app/speech-output-artifact-bindings.ts +5 -0
  199. package/template/apps/server/src/application-services.ts +9 -3
  200. package/template/apps/server/src/audit/redaction.ts +1 -0
  201. package/template/apps/server/src/audit/reliable-writer.test.ts +8 -0
  202. package/template/apps/server/src/auth/password-change-license-restriction.test.ts +156 -0
  203. package/template/apps/server/src/document/cancel-response.ts +33 -0
  204. package/template/apps/server/src/document/contracts.ts +6 -0
  205. package/template/apps/server/src/document/errors.ts +11 -0
  206. package/template/apps/server/src/document/facade-cancel.test.ts +226 -0
  207. package/template/apps/server/src/document/facade-cancel.ts +110 -0
  208. package/template/apps/server/src/document/facade-grant-handoff.test.ts +113 -0
  209. package/template/apps/server/src/document/facade-idempotency.test.ts +195 -0
  210. package/template/apps/server/src/document/facade-invocation.ts +46 -0
  211. package/template/apps/server/src/document/facade-output-artifact.test.ts +310 -0
  212. package/template/apps/server/src/document/facade-read-response.ts +116 -0
  213. package/template/apps/server/src/document/facade-readiness.test.ts +95 -0
  214. package/template/apps/server/src/document/facade-support.ts +297 -0
  215. package/template/apps/server/src/document/facade.ts +164 -173
  216. package/template/apps/server/src/document/output-artifact-composition.test.ts +64 -0
  217. package/template/apps/server/src/document/output-artifact-composition.ts +78 -0
  218. package/template/apps/server/src/document/output-artifact-fingerprint.contract.test.ts +110 -0
  219. package/template/apps/server/src/document/output-artifact-fingerprint.ts +150 -0
  220. package/template/apps/server/src/document/output-artifact-host-registry.ts +44 -0
  221. package/template/apps/server/src/document/output-artifact-host.test.ts +332 -0
  222. package/template/apps/server/src/document/output-artifact-host.ts +331 -0
  223. package/template/apps/server/src/document/output-artifact-manifest.test-support.ts +71 -0
  224. package/template/apps/server/src/document/output-artifact-publish.test-support.ts +48 -0
  225. package/template/apps/server/src/document/output-artifact-readiness-probe.ts +347 -0
  226. package/template/apps/server/src/document/output-artifact-readiness-timeout.ts +30 -0
  227. package/template/apps/server/src/document/output-artifact-readiness.test.ts +264 -0
  228. package/template/apps/server/src/document/output-artifact-readiness.ts +87 -0
  229. package/template/apps/server/src/document/output-artifact-route-composition.test.ts +27 -0
  230. package/template/apps/server/src/document/output-artifact-route-composition.ts +14 -0
  231. package/template/apps/server/src/document/output-artifact-runtime.test-support.ts +8 -0
  232. package/template/apps/server/src/document/output-artifact-runtime.test.ts +124 -0
  233. package/template/apps/server/src/document/output-artifact-runtime.ts +275 -0
  234. package/template/apps/server/src/document/output-artifact.test-support.ts +350 -0
  235. package/template/apps/server/src/document/remote-response.ts +162 -0
  236. package/template/apps/server/src/document/remote-runtime.test.ts +100 -4
  237. package/template/apps/server/src/document/remote-runtime.ts +37 -85
  238. package/template/apps/server/src/document/routes-read-response.test.ts +267 -0
  239. package/template/apps/server/src/document/routes.test.ts +109 -0
  240. package/template/apps/server/src/document/routes.ts +23 -14
  241. package/template/apps/server/src/embedding/audit.ts +46 -0
  242. package/template/apps/server/src/embedding/contracts.ts +19 -1
  243. package/template/apps/server/src/embedding/drizzle-run-binding-repository.integration.test.ts +100 -0
  244. package/template/apps/server/src/embedding/drizzle-run-binding-repository.ts +102 -0
  245. package/template/apps/server/src/embedding/facade-readiness.test.ts +307 -0
  246. package/template/apps/server/src/embedding/facade-types.ts +18 -0
  247. package/template/apps/server/src/embedding/facade.ts +248 -115
  248. package/template/apps/server/src/embedding/operation-authorization.ts +23 -0
  249. package/template/apps/server/src/embedding/readiness-admission.ts +26 -0
  250. package/template/apps/server/src/embedding/remote-runtime.test.ts +103 -0
  251. package/template/apps/server/src/embedding/remote-runtime.ts +98 -0
  252. package/template/apps/server/src/embedding/routes.test.ts +118 -0
  253. package/template/apps/server/src/embedding/routes.ts +98 -0
  254. package/template/apps/server/src/embedding/run-artifact.ts +18 -0
  255. package/template/apps/server/src/embedding/run-authorization.test.ts +133 -0
  256. package/template/apps/server/src/embedding/run-authorization.ts +91 -0
  257. package/template/apps/server/src/embedding/run-binding-repository.ts +75 -0
  258. package/template/apps/server/src/embedding/run-fingerprint.test.ts +78 -0
  259. package/template/apps/server/src/embedding/run-fingerprint.ts +48 -0
  260. package/template/apps/server/src/embedding/terminal-observer.test.ts +26 -0
  261. package/template/apps/server/src/embedding/terminal-observer.ts +44 -0
  262. package/template/apps/server/src/index.ts +38 -31
  263. package/template/apps/server/src/module-host/ai-operation-port.test.ts +72 -0
  264. package/template/apps/server/src/module-host/ai-operation-port.ts +46 -3
  265. package/template/apps/server/src/module-host/ai-operation-speech-normalize.test.ts +186 -0
  266. package/template/apps/server/src/module-host/durable-context.ts +194 -16
  267. package/template/apps/server/src/module-host/durable-handler-registration.ts +1 -0
  268. package/template/apps/server/src/module-host/durable-storage-filesystem-restart.test.ts +265 -0
  269. package/template/apps/server/src/module-host/durable-storage-write.test.ts +345 -0
  270. package/template/apps/server/src/module-host/http-runtime.ts +25 -0
  271. package/template/apps/server/src/module-host/initialize-contracts.ts +18 -1
  272. package/template/apps/server/src/module-host/initialize.test.ts +18 -0
  273. package/template/apps/server/src/module-host/initialize.ts +42 -2
  274. package/template/apps/server/src/module-host/module-secret-audit-version.test.ts +73 -0
  275. package/template/apps/server/src/module-host/module-secret-binding-resolution.ts +60 -0
  276. package/template/apps/server/src/module-host/module-secret-durable.test.ts +206 -0
  277. package/template/apps/server/src/module-host/module-secret-port.test-support.ts +125 -0
  278. package/template/apps/server/src/module-host/module-secret-port.test.ts +161 -0
  279. package/template/apps/server/src/module-host/module-secret-port.ts +249 -0
  280. package/template/apps/server/src/module-host/module-secret-result.test.ts +324 -0
  281. package/template/apps/server/src/module-host/module-secret-result.ts +274 -0
  282. package/template/apps/server/src/module-host/module-secret-tool-boundary.test.ts +143 -0
  283. package/template/apps/server/src/module-host/project-composition.ts +1 -0
  284. package/template/apps/server/src/module-host/report-staging-port.ts +55 -0
  285. package/template/apps/server/src/module-host/report-staging-registration.test.ts +104 -0
  286. package/template/apps/server/src/module-host/request-context.ts +58 -1
  287. package/template/apps/server/src/module-host/route-declaration.ts +11 -4
  288. package/template/apps/server/src/module-host/route-installer.test-fixture.ts +246 -0
  289. package/template/apps/server/src/module-host/route-installer.test.ts +47 -211
  290. package/template/apps/server/src/module-host/route-installer.ts +192 -21
  291. package/template/apps/server/src/module-host/route-registration.test.ts +44 -4
  292. package/template/apps/server/src/module-host/runtime-composition.ts +2 -0
  293. package/template/apps/server/src/module-host/scoped-host.ts +84 -0
  294. package/template/apps/server/src/module-host/screenshot-artifact-ref.ts +91 -0
  295. package/template/apps/server/src/module-host/screenshot-intake-composition.test.ts +292 -0
  296. package/template/apps/server/src/module-host/screenshot-intake-deadline.ts +38 -0
  297. package/template/apps/server/src/module-host/screenshot-intake-plan.ts +75 -0
  298. package/template/apps/server/src/module-host/screenshot-intake-port.ts +297 -0
  299. package/template/apps/server/src/module-host/screenshot-intake-security.test.ts +311 -0
  300. package/template/apps/server/src/module-host/screenshot-intake-store.ts +76 -0
  301. package/template/apps/server/src/module-host/screenshot-intake-test-support.ts +68 -0
  302. package/template/apps/server/src/module-host/secret-bindings.test.ts +167 -0
  303. package/template/apps/server/src/module-host/secret-bindings.ts +184 -0
  304. package/template/apps/server/src/module-host/storage-authorization-binding.test.ts +242 -0
  305. package/template/apps/server/src/module-host/storage-port.test.ts +8 -1
  306. package/template/apps/server/src/module-host/storage-port.ts +84 -8
  307. package/template/apps/server/src/module-host/storage-restart-fixture.test-support.ts +242 -0
  308. package/template/apps/server/src/module-host/storage-restart-postgres.integration.test.ts +280 -0
  309. package/template/apps/server/src/module-host/storage-scope-drift-http.test.ts +68 -0
  310. package/template/apps/server/src/module-host/storage-scope.ts +52 -1
  311. package/template/apps/server/src/module-host/storage-stream-route.test.ts +282 -0
  312. package/template/apps/server/src/module-host/storage-write-error.test.ts +174 -0
  313. package/template/apps/server/src/module-host/storage-write-error.ts +62 -0
  314. package/template/apps/server/src/module-host/storage-write-port.test.ts +323 -0
  315. package/template/apps/server/src/module-host/storage-write-port.ts +320 -0
  316. package/template/apps/server/src/module-host/storage-write-unavailable.ts +21 -0
  317. package/template/apps/server/src/module-host/storage-writer-retention.test.ts +109 -0
  318. package/template/apps/server/src/module-host/user-directory-composition.test.ts +1 -0
  319. package/template/apps/server/src/module-preflight-secret.test.ts +79 -0
  320. package/template/apps/server/src/module-preflight.ts +5 -0
  321. package/template/apps/server/src/platform-http-runtime.ts +16 -4
  322. package/template/apps/server/src/report-staging/archive-frame-stream.test.ts +209 -0
  323. package/template/apps/server/src/report-staging/archive-frame-stream.ts +341 -0
  324. package/template/apps/server/src/report-staging/archive-process.test.ts +302 -0
  325. package/template/apps/server/src/report-staging/archive-process.ts +257 -0
  326. package/template/apps/server/src/report-staging/archive-volumes.ts +30 -0
  327. package/template/apps/server/src/report-staging/cancellation.ts +13 -0
  328. package/template/apps/server/src/report-staging/contracts.ts +94 -0
  329. package/template/apps/server/src/report-staging/drizzle-lifecycle.ts +278 -0
  330. package/template/apps/server/src/report-staging/drizzle-mapping.ts +140 -0
  331. package/template/apps/server/src/report-staging/drizzle-repository.integration.test.ts +346 -0
  332. package/template/apps/server/src/report-staging/drizzle-repository.ts +255 -0
  333. package/template/apps/server/src/report-staging/drizzle-seal.integration.test.ts +267 -0
  334. package/template/apps/server/src/report-staging/drizzle-seal.ts +177 -0
  335. package/template/apps/server/src/report-staging/filesystem-cleanup.test.ts +68 -0
  336. package/template/apps/server/src/report-staging/filesystem-cleanup.ts +102 -0
  337. package/template/apps/server/src/report-staging/filesystem-errors.ts +15 -0
  338. package/template/apps/server/src/report-staging/filesystem-identifiers.ts +19 -0
  339. package/template/apps/server/src/report-staging/filesystem-io.test.ts +85 -0
  340. package/template/apps/server/src/report-staging/filesystem-io.ts +206 -0
  341. package/template/apps/server/src/report-staging/filesystem-scan.ts +85 -0
  342. package/template/apps/server/src/report-staging/filesystem-store.ts +346 -0
  343. package/template/apps/server/src/report-staging/heartbeat.test.ts +47 -0
  344. package/template/apps/server/src/report-staging/heartbeat.ts +53 -0
  345. package/template/apps/server/src/report-staging/manifest-stream.ts +46 -0
  346. package/template/apps/server/src/report-staging/memory-repository.ts +256 -0
  347. package/template/apps/server/src/report-staging/metadata-catalog.ts +89 -0
  348. package/template/apps/server/src/report-staging/metadata-spool-paths.ts +195 -0
  349. package/template/apps/server/src/report-staging/metadata-spool-schema.ts +54 -0
  350. package/template/apps/server/src/report-staging/metadata-spool.test.ts +214 -0
  351. package/template/apps/server/src/report-staging/metadata-spool.ts +305 -0
  352. package/template/apps/server/src/report-staging/native/archive-frame-helper.c +309 -0
  353. package/template/apps/server/src/report-staging/path-policy.test.ts +127 -0
  354. package/template/apps/server/src/report-staging/path-policy.ts +263 -0
  355. package/template/apps/server/src/report-staging/repository-fence.test.ts +114 -0
  356. package/template/apps/server/src/report-staging/repository.ts +75 -0
  357. package/template/apps/server/src/report-staging/runtime.ts +31 -0
  358. package/template/apps/server/src/report-staging/sealed-file.test.ts +34 -0
  359. package/template/apps/server/src/report-staging/sealed-file.ts +137 -0
  360. package/template/apps/server/src/report-staging/service-input-limits.test.ts +62 -0
  361. package/template/apps/server/src/report-staging/service-input.ts +204 -0
  362. package/template/apps/server/src/report-staging/service-lifecycle.test.ts +132 -0
  363. package/template/apps/server/src/report-staging/service-read-fence.test.ts +37 -0
  364. package/template/apps/server/src/report-staging/service-read.ts +172 -0
  365. package/template/apps/server/src/report-staging/service-support.ts +149 -0
  366. package/template/apps/server/src/report-staging/service.test-fixture.ts +226 -0
  367. package/template/apps/server/src/report-staging/service.test.ts +314 -0
  368. package/template/apps/server/src/report-staging/service.ts +255 -0
  369. package/template/apps/server/src/report-staging/supervised-process.ts +194 -0
  370. package/template/apps/server/src/speech/contracts.ts +8 -0
  371. package/template/apps/server/src/speech/errors.ts +10 -0
  372. package/template/apps/server/src/speech/facade-contract.ts +49 -0
  373. package/template/apps/server/src/speech/facade-output.test.ts +299 -0
  374. package/template/apps/server/src/speech/facade-output.ts +298 -0
  375. package/template/apps/server/src/speech/facade-validation.ts +127 -0
  376. package/template/apps/server/src/speech/facade.ts +185 -151
  377. package/template/apps/server/src/speech/fingerprint.test.ts +42 -0
  378. package/template/apps/server/src/speech/fingerprint.ts +28 -0
  379. package/template/apps/server/src/speech/output-artifact-binding.test.ts +11 -0
  380. package/template/apps/server/src/speech/output-artifact-binding.ts +30 -0
  381. package/template/apps/server/src/speech/output-artifact-error.ts +9 -0
  382. package/template/apps/server/src/speech/output-artifact-host.test-support.ts +73 -0
  383. package/template/apps/server/src/speech/output-artifact-host.test.ts +302 -0
  384. package/template/apps/server/src/speech/output-artifact-host.ts +279 -0
  385. package/template/apps/server/src/speech/output-artifact-policy.ts +114 -0
  386. package/template/apps/server/src/speech/output-artifact-replay.ts +91 -0
  387. package/template/apps/server/src/speech/remote-response.ts +158 -0
  388. package/template/apps/server/src/speech/remote-runtime.test.ts +90 -0
  389. package/template/apps/server/src/speech/remote-runtime.ts +36 -78
  390. package/template/apps/server/src/speech/routes.ts +60 -16
  391. package/template/apps/server/src/startup-finalization.ts +52 -0
  392. package/template/apps/server/src/startup-preflight.ts +2 -0
  393. package/template/apps/server/src/startup-shutdown.test.ts +69 -0
  394. package/template/apps/server/src/startup-shutdown.ts +61 -0
  395. package/template/apps/server/src/storage/drizzle-upload-purge.ts +61 -0
  396. package/template/apps/server/src/storage/drizzle-upload-references.ts +23 -0
  397. package/template/apps/server/src/storage/drizzle-upload-repository.integration.test.ts +103 -0
  398. package/template/apps/server/src/storage/drizzle-upload-repository.ts +109 -14
  399. package/template/apps/server/src/storage/host-runtime.ts +15 -0
  400. package/template/apps/server/src/storage/routes-stream-cancellation.test.ts +154 -0
  401. package/template/apps/server/src/storage/routes.test.ts +13 -2
  402. package/template/apps/server/src/storage/routes.ts +57 -18
  403. package/template/apps/server/src/storage/runtime.ts +17 -4
  404. package/template/apps/server/src/system/route-types.ts +5 -1
  405. package/template/apps/server/src/system/system-resource-monitoring.test.ts +47 -0
  406. package/template/apps/server/src/system/system-resource-monitoring.ts +60 -10
  407. package/template/apps/server/src/work-order/routes.test.ts +1 -0
  408. package/template/apps/speech-server/src/southwind_speech_server/adapter.py +58 -17
  409. package/template/apps/speech-server/src/southwind_speech_server/app.py +24 -17
  410. package/template/apps/speech-server/src/southwind_speech_server/bounded_json.py +60 -0
  411. package/template/apps/speech-server/src/southwind_speech_server/config.py +122 -2
  412. package/template/apps/speech-server/src/southwind_speech_server/contracts.py +58 -0
  413. package/template/apps/speech-server/src/southwind_speech_server/errors.py +8 -0
  414. package/template/apps/speech-server/src/southwind_speech_server/normalizer.py +14 -0
  415. package/template/apps/speech-server/src/southwind_speech_server/output_artifact.py +190 -0
  416. package/template/apps/speech-server/src/southwind_speech_server/output_validation.py +54 -0
  417. package/template/apps/speech-server/src/southwind_speech_server/pin_cli.py +83 -0
  418. package/template/apps/speech-server/src/southwind_speech_server/readiness.py +266 -0
  419. package/template/apps/speech-server/src/southwind_speech_server/readiness_contracts.py +268 -0
  420. package/template/apps/speech-server/src/southwind_speech_server/readiness_http.py +91 -0
  421. package/template/apps/speech-server/src/southwind_speech_server/readiness_local.py +161 -0
  422. package/template/apps/speech-server/src/southwind_speech_server/readiness_support.py +106 -0
  423. package/template/apps/speech-server/src/southwind_speech_server/service.py +118 -13
  424. package/template/apps/speech-server/src/southwind_speech_server/store.py +7 -0
  425. package/template/apps/speech-server/tests/test_bounded_json.py +55 -0
  426. package/template/apps/speech-server/tests/test_config.py +22 -0
  427. package/template/apps/speech-server/tests/test_output_artifact.py +60 -0
  428. package/template/apps/speech-server/tests/test_output_validation.py +44 -0
  429. package/template/apps/speech-server/tests/test_readiness.py +315 -0
  430. package/template/apps/speech-server/tests/test_readiness_http.py +48 -0
  431. package/template/apps/speech-server/tests/test_readiness_local.py +43 -0
  432. package/template/apps/speech-server/tests/test_service.py +211 -36
  433. package/template/apps/web/src/pages/system/components/OperationGpuMonitor.vue +2 -1
  434. package/template/apps/web/src/pages/system/components/OperationGpuMonitor.webtest.ts +29 -0
  435. package/template/apps/web/src/pages/system/components/OperationServiceMonitor.vue +2 -1
  436. package/template/apps/web/src/pages/system/components/OperationServiceMonitor.webtest.ts +4 -1
  437. package/template/docker-compose.yml +49 -1
  438. package/template/docs/architecture/ai-runtime-readiness.md +504 -0
  439. package/template/docs/architecture/ai-runtime.md +20 -4
  440. package/template/docs/architecture/durable-jobs.md +54 -5
  441. package/template/docs/architecture/module-host.md +72 -9
  442. package/template/docs/architecture/module-manifest-composition.md +5 -2
  443. package/template/docs/architecture/module-secret-resolution.md +250 -0
  444. package/template/docs/architecture/object-storage.md +144 -3
  445. package/template/docs/architecture/report-staging.md +158 -0
  446. package/template/docs/architecture/server-module-interface.md +29 -0
  447. package/template/docs/architecture/speech-variants.md +45 -0
  448. package/template/docs/platform/agent-tools.md +16 -0
  449. package/template/docs/platform/document-ai-runtime.md +199 -17
  450. package/template/docs/platform/module-configuration.md +5 -0
  451. package/template/docs/platform/speech-ai-runtime.md +34 -5
  452. package/template/docs/platform/vision-ai-runtime.md +46 -1
  453. package/template/package.json +4 -1
  454. package/template/packages/ai-client/package.json +1 -1
  455. package/template/packages/ai-client/src/agent/client/client.ts +3 -0
  456. package/template/packages/ai-client/src/agent/client/index.ts +1 -0
  457. package/template/packages/ai-client/src/agent/client/screenshot.test.ts +40 -0
  458. package/template/packages/ai-client/src/agent/client/screenshot.ts +146 -0
  459. package/template/packages/ai-client/src/agent/client/types.ts +2 -0
  460. package/template/packages/ai-client/src/agent/contracts/runs.ts +1 -0
  461. package/template/packages/ai-client/src/embedding/client.test.ts +52 -0
  462. package/template/packages/ai-client/src/embedding/client.ts +69 -0
  463. package/template/packages/ai-client/src/embedding/contracts.ts +47 -0
  464. package/template/packages/ai-client/src/embedding/index.ts +1 -0
  465. package/template/packages/ai-client/src/embedding/run.ts +130 -0
  466. package/template/packages/ai-client/src/speech/client.test.ts +26 -0
  467. package/template/packages/ai-client/src/speech/client.ts +25 -1
  468. package/template/packages/ai-client/src/speech/contracts.ts +19 -0
  469. package/template/packages/config/package.json +2 -2
  470. package/template/packages/database/drizzle/0048_illegal_magneto.sql +11 -0
  471. package/template/packages/database/drizzle/0049_right_lenny_balinger.sql +79 -0
  472. package/template/packages/database/drizzle/0050_greedy_sister_grimm.sql +92 -0
  473. package/template/packages/database/drizzle/0051_lame_shockwave.sql +19 -0
  474. package/template/packages/database/drizzle/0052_tiresome_komodo.sql +1 -0
  475. package/template/packages/database/drizzle/0053_calm_victor_mancha.sql +1 -0
  476. package/template/packages/database/drizzle/0054_tough_thanos.sql +29 -0
  477. package/template/packages/database/drizzle/meta/0048_snapshot.json +8852 -0
  478. package/template/packages/database/drizzle/meta/0049_snapshot.json +9410 -0
  479. package/template/packages/database/drizzle/meta/0050_snapshot.json +10115 -0
  480. package/template/packages/database/drizzle/meta/0051_snapshot.json +10257 -0
  481. package/template/packages/database/drizzle/meta/0052_snapshot.json +10263 -0
  482. package/template/packages/database/drizzle/meta/0053_snapshot.json +10270 -0
  483. package/template/packages/database/drizzle/meta/0054_snapshot.json +10468 -0
  484. package/template/packages/database/drizzle/meta/_journal.json +49 -0
  485. package/template/packages/database/package.json +2 -2
  486. package/template/packages/database/src/agent-runtime-schema.test.ts +15 -0
  487. package/template/packages/database/src/ai-output-artifacts.test.ts +57 -0
  488. package/template/packages/database/src/schema/agent-runtime.ts +43 -0
  489. package/template/packages/database/src/schema/ai-output-artifacts.ts +182 -0
  490. package/template/packages/database/src/schema/embedding-runtime.ts +62 -0
  491. package/template/packages/database/src/schema/file-storage.ts +18 -0
  492. package/template/packages/database/src/schema/index.ts +3 -0
  493. package/template/packages/database/src/schema/report-staging.ts +212 -0
  494. package/template/packages/database/src/schema.test.ts +19 -0
  495. package/template/packages/jobs/package.json +2 -2
  496. package/template/packages/modules/index.ts +2 -0
  497. package/template/packages/modules/package.json +1 -1
  498. package/template/packages/modules/src/ai-operation-composition.test.ts +37 -0
  499. package/template/packages/modules/src/ai-operation-composition.ts +4 -0
  500. package/template/packages/modules/src/ai-operation-readiness-contract.test.ts +38 -0
  501. package/template/packages/modules/src/ai-operation-readiness-contract.ts +34 -0
  502. package/template/packages/modules/src/ai-screenshot-context.test.ts +72 -0
  503. package/template/packages/modules/src/ai-screenshot-context.ts +50 -0
  504. package/template/packages/modules/src/capability-audit-validation.ts +20 -0
  505. package/template/packages/modules/src/capability-guard-validation.ts +41 -0
  506. package/template/packages/modules/src/composition.ts +11 -0
  507. package/template/packages/modules/src/manifest.ts +48 -0
  508. package/template/packages/modules/src/secret-composition.test.ts +308 -0
  509. package/template/packages/modules/src/secret-composition.ts +176 -0
  510. package/template/packages/modules/src/system-api-control-plane.ts +17 -1
  511. package/template/packages/modules/src/system-module-catalog.test.ts +52 -0
  512. package/template/packages/modules/src/system-module-catalog.ts +1 -1
  513. package/template/packages/server-sdk/contracts/ai-runtime-readiness/v1/document-python-parity.json +12 -0
  514. package/template/packages/server-sdk/contracts/ai-runtime-readiness/v1/document.json +70 -0
  515. package/template/packages/server-sdk/contracts/ai-runtime-readiness/v1/embedding.json +68 -0
  516. package/template/packages/server-sdk/contracts/ai-runtime-readiness/v1/speech.json +80 -0
  517. package/template/packages/server-sdk/contracts/ai-runtime-readiness/v1/vlm.json +70 -0
  518. package/template/packages/server-sdk/contracts/document-runtime/v1/fingerprint-fixture.json +101 -0
  519. package/template/packages/server-sdk/index.ts +109 -0
  520. package/template/packages/server-sdk/package.json +23 -4
  521. package/template/packages/server-sdk/src/ai-runtime-readiness-capture.ts +168 -0
  522. package/template/packages/server-sdk/src/ai-runtime-readiness-digest.ts +49 -0
  523. package/template/packages/server-sdk/src/ai-runtime-readiness-identity.ts +16 -0
  524. package/template/packages/server-sdk/src/ai-runtime-readiness-keys.ts +23 -0
  525. package/template/packages/server-sdk/src/ai-runtime-readiness-limits.ts +141 -0
  526. package/template/packages/server-sdk/src/ai-runtime-readiness-projection.ts +326 -0
  527. package/template/packages/server-sdk/src/ai-runtime-readiness-requirement.ts +31 -0
  528. package/template/packages/server-sdk/src/ai-runtime-readiness-time.ts +16 -0
  529. package/template/packages/server-sdk/src/ai-runtime-readiness-trust.ts +84 -0
  530. package/template/packages/server-sdk/src/ai-runtime-readiness-validation-values.ts +147 -0
  531. package/template/packages/server-sdk/src/ai-runtime-readiness-validation.ts +299 -0
  532. package/template/packages/server-sdk/src/ai-runtime-readiness-values.ts +42 -0
  533. package/template/packages/server-sdk/src/ai-runtime-readiness.adversarial-input.contract.test.ts +146 -0
  534. package/template/packages/server-sdk/src/ai-runtime-readiness.contract-support.ts +139 -0
  535. package/template/packages/server-sdk/src/ai-runtime-readiness.contract.test.ts +314 -0
  536. package/template/packages/server-sdk/src/ai-runtime-readiness.digest-safety.contract.test.ts +131 -0
  537. package/template/packages/server-sdk/src/ai-runtime-readiness.fail-closed.contract.test.ts +215 -0
  538. package/template/packages/server-sdk/src/ai-runtime-readiness.identity.contract.test.ts +138 -0
  539. package/template/packages/server-sdk/src/ai-runtime-readiness.input-safety.contract.test.ts +314 -0
  540. package/template/packages/server-sdk/src/ai-runtime-readiness.public-api.test.ts +18 -0
  541. package/template/packages/server-sdk/src/ai-runtime-readiness.python-parity.contract.test.ts +160 -0
  542. package/template/packages/server-sdk/src/ai-runtime-readiness.trust.contract.test.ts +135 -0
  543. package/template/packages/server-sdk/src/ai-runtime-readiness.ts +198 -0
  544. package/template/packages/server-sdk/src/ai-screenshot-intake-port.ts +58 -0
  545. package/template/packages/server-sdk/src/data-governance-registration.ts +1 -3
  546. package/template/packages/server-sdk/src/durable-handler.ts +12 -0
  547. package/template/packages/server-sdk/src/module-adapter.test.ts +10 -0
  548. package/template/packages/server-sdk/src/module-adapter.ts +3 -0
  549. package/template/packages/server-sdk/src/module-host.ts +8 -0
  550. package/template/packages/server-sdk/src/report-staging-context-compatibility.test.ts +25 -0
  551. package/template/packages/server-sdk/src/report-staging-port.ts +190 -0
  552. package/template/packages/server-sdk/src/request-context.ts +27 -1
  553. package/template/packages/server-sdk/src/route-definition.ts +6 -0
  554. package/template/packages/server-sdk/src/secret-binding.test.ts +66 -0
  555. package/template/packages/server-sdk/src/secret-binding.ts +54 -0
  556. package/template/packages/server-sdk/src/secret-context-compatibility.test.ts +77 -0
  557. package/template/packages/server-sdk/src/secret-port.ts +80 -0
  558. package/template/packages/server-sdk/src/storage-port.ts +129 -9
  559. package/template/packages/server-sdk/src/storage-v052-source-compatibility.test.ts +61 -0
  560. package/template/packages/shared/index.ts +5 -0
  561. package/template/packages/shared/package.json +4 -1
  562. package/template/packages/shared/src/ai-operation-readiness.test.ts +75 -0
  563. package/template/packages/shared/src/ai-operation-readiness.ts +170 -0
  564. package/template/packages/shared/src/license-catalog.ts +14 -9
  565. package/template/packages/shared/src/screenshot-context-digest.test.ts +46 -0
  566. package/template/packages/shared/src/screenshot-context-digest.ts +72 -0
  567. package/template/packages/shared/src/stable-key.ts +26 -0
  568. package/template/packages/shared/tsconfig.json +16 -0
  569. package/template/packages/storage/index.ts +2 -0
  570. package/template/packages/storage/package.json +1 -1
  571. package/template/packages/storage/src/in-memory-upload-repository.ts +105 -2
  572. package/template/packages/storage/src/local-file-blob-store.test.ts +58 -0
  573. package/template/packages/storage/src/local-file-blob-store.ts +5 -71
  574. package/template/packages/storage/src/local-file-blob-writer.ts +96 -0
  575. package/template/packages/storage/src/upload-abort-recovery.test.ts +234 -0
  576. package/template/packages/storage/src/upload-abort.ts +130 -0
  577. package/template/packages/storage/src/upload-cleanup-race.test.ts +207 -0
  578. package/template/packages/storage/src/upload-cleanup.ts +85 -0
  579. package/template/packages/storage/src/upload-completion.ts +52 -0
  580. package/template/packages/storage/src/upload-purge.test.ts +163 -0
  581. package/template/packages/storage/src/upload-purge.ts +261 -0
  582. package/template/packages/storage/src/upload-repository-v052-compatibility.test.ts +31 -0
  583. package/template/packages/storage/src/upload-repository.ts +61 -0
  584. package/template/packages/storage/src/upload-service-recovery.test.ts +296 -0
  585. package/template/packages/storage/src/upload-service.ts +138 -150
  586. package/template/packages/storage/src/upload-streams.ts +126 -30
  587. package/template/packages/storage/src/upload-types.ts +13 -0
  588. package/template/packages/storage/src/upload-validation.ts +127 -0
  589. package/template/scripts/provision-speech-readiness.ts +147 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-windy",
3
- "version": "0.5.2",
3
+ "version": "0.6.1",
4
4
  "description": "创建单组织、单租户、私有部署优先的 Windy 企业 Dashboard Starter",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,6 +14,7 @@
14
14
  ],
15
15
  "scripts": {
16
16
  "build": "bun build src/cli.ts --target=bun --format=esm --outdir=dist",
17
+ "regression:update-candidate": "bun run src/candidate-update-regression.ts",
17
18
  "template:sync": "bun run src/sync-template.ts",
18
19
  "prepack": "bun run template:sync && bun run build",
19
20
  "postpack": "bun run src/clean-template.ts",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "templateCommit": "b4fdd1a323b9445461c149ce93191292283bce6b",
4
- "generatorVersion": "0.5.2",
3
+ "templateCommit": "a035c896c8821fe9a2f3ef3aca9d30b7ec1fb096",
4
+ "generatorVersion": "0.6.1",
5
5
  "modules": [
6
6
  {
7
7
  "name": "system",
@@ -1,9 +1,9 @@
1
1
  # Southwind AI Agent Server
2
2
 
3
- Python 3.12 Agent Runtime。HTTP 层只公开 Southwind AI canonical Agent
4
- contracts。真实业务 Run 在内部通过 Google ADK 2.5 的 Runner、Session、LlmAgent 和
5
- Event 执行;ADK 类型不会越过 `AgentEngineAdapter`。模型调用继续复用受治理的
6
- OpenAI-compatible `/chat/completions` Provider。
3
+ Python 3.12 Agent 运行时。HTTP 层只公开 Southwind AI 的 canonical Agent 契约;真实业务
4
+ Run 在内部通过 Google ADK 2.5 的 Runner、Session、LlmAgent 和 Event 执行,ADK 类型不会
5
+ 越过 `AgentEngineAdapter`。模型调用继续复用受治理的 OpenAI-compatible
6
+ `/chat/completions` Provider。
7
7
 
8
8
  ```bash
9
9
  uv sync --frozen
@@ -13,7 +13,7 @@ uv run ruff format --check .
13
13
  uv run mypy
14
14
  ```
15
15
 
16
- HTTP Interface:
16
+ HTTP 接口:
17
17
 
18
18
  - `POST /api/agent/runs`
19
19
  - `GET /api/agent/runs/:runId/events`
@@ -40,8 +40,27 @@ export AI_PROVIDER_AUDIT_RETENTION_DAYS='90'
40
40
  uv run uvicorn southwind_agent_server.app:app
41
41
  ```
42
42
 
43
+ VLM Operation readiness 比 Endpoint 可达性更严格。必须固定 Deployment 事实并声明
44
+ 图片 offer;否则 `/health/vlm-ready` 返回 V1 `unavailable` snapshot,视觉 Operation 保持
45
+ 关闭:
46
+
47
+ ```bash
48
+ export AI_PROVIDER_CAPABILITIES='text-generation,vision'
49
+ export AI_PROVIDER_INPUT_MODALITIES='text,image'
50
+ export AI_PROVIDER_DEPLOYMENT_IDENTITY='windy-deployment-v1_<uuid-v4>'
51
+ export AI_PROVIDER_RELEASE_DIGEST='sha256:<64-lowercase-hex>'
52
+ export AI_PROVIDER_READINESS_TTL_SECONDS='60'
53
+ export AI_PROVIDER_MAX_CONCURRENT_RUNS='1'
54
+ export AI_PROVIDER_MAX_QUEUE_DEPTH='0'
55
+ ```
56
+
57
+ Readiness 请求用固定的一像素合成图片调用已配置的 `/chat/completions`,并要求有界
58
+ 结构化结果。它不会调用 `/models`,不会读取客户截图,也不会把用户 Artifact、URL、Run
59
+ ID、Prompt 或 Provider 输出放进 health payload。`offersDigest` 始终按公开 V1 算法由
60
+ 实际 offer 计算,不能由环境变量伪造。
61
+
43
62
  公网 URL 必须使用 HTTPS 且 Host 精确命中 allowlist;本机、容器服务名和内网地址允许
44
- HTTP。Provider 请求包含连接和总超时、响应大小限制、错误脱敏与 `/models`
63
+ HTTP。Provider 请求包含连接和总超时、响应大小限制、错误脱敏与 VLM 合成图片
45
64
  readiness。缺少 URL/Model 时回退
46
65
  未配置的 `AdkEngineAdapter` 并返回 unavailable,不调用模型。测试另使用
47
66
  `DeterministicEngineAdapter`。每个 ADK Tool 只声明 Operation 已允许的 Key;其执行
@@ -32,6 +32,7 @@ from .provider_governance import ProviderRequestGovernance
32
32
  from .report_store import AgentRuntimeReportStore
33
33
  from .report_types import CacheStatus, UsageFacts, UsageSource
34
34
  from .tool_host import ToolHostClient, canonical_tool_call_id
35
+ from .vlm_readiness import VlmReadinessProbe, unavailable_vlm_snapshot
35
36
 
36
37
 
37
38
  class AdkEngineAdapter(AgentEngineAdapter):
@@ -58,6 +59,14 @@ class AdkEngineAdapter(AgentEngineAdapter):
58
59
  def input_modalities(self) -> tuple[str, ...]:
59
60
  return self._provider.config.input_modalities if self._provider else ()
60
61
 
62
+ @property
63
+ def max_concurrent_runs(self) -> int:
64
+ return self._provider.config.max_concurrent_runs if self._provider else 1
65
+
66
+ @property
67
+ def max_queue_depth(self) -> int:
68
+ return self._provider.config.max_queue_depth if self._provider else 0
69
+
61
70
  def supports(self, operation_key: str) -> bool:
62
71
  return bool(operation_key.strip())
63
72
 
@@ -183,8 +192,12 @@ class AdkEngineAdapter(AgentEngineAdapter):
183
192
  cancellation.set()
184
193
 
185
194
  async def health(self) -> None:
186
- provider, _, _ = self._configured()
187
- await provider.health()
195
+ self._configured()
196
+
197
+ async def readiness(self) -> dict[str, object]:
198
+ if not self._provider:
199
+ return unavailable_vlm_snapshot(configured=False)
200
+ return await VlmReadinessProbe(self._provider.config, self._provider).inspect()
188
201
 
189
202
  def governance_health(self) -> dict[str, int | float | str | None]:
190
203
  _, _, governance = self._configured()
@@ -23,6 +23,8 @@ from .contracts import (
23
23
  StartRunResponse,
24
24
  )
25
25
  from .engine import AgentEngineAdapter, SafeEngineError
26
+ from .engine_capacity import engine_capacity
27
+ from .health_routes import install_health_routes
26
28
  from .http_helpers import (
27
29
  authorized,
28
30
  parse_cursor,
@@ -36,15 +38,13 @@ from .runtime_factory import (
36
38
  default_report_store,
37
39
  default_store,
38
40
  )
39
- from .service import (
40
- AgentRunService,
41
- OperationNotFoundError,
42
- RunNotFoundError,
43
- )
41
+ from .service import AgentRunService
42
+ from .service_errors import OperationNotFoundError, RunNotFoundError
44
43
  from .sqlite_store import RunStoreCapacityError
45
44
  from .sse import event_stream
46
45
  from .store import IdempotencyConflictError, ReleaseNotFoundError, RunStore
47
46
  from .telemetry import configure_telemetry
47
+ from .vision_requirement import require_vision_readiness
48
48
 
49
49
 
50
50
  def create_app(
@@ -58,6 +58,7 @@ def create_app(
58
58
  configure_telemetry()
59
59
  runtime_report_store = report_store or default_report_store()
60
60
  runtime_engine = engine or default_engine(runtime_report_store)
61
+ capacity = engine_capacity(runtime_engine)
61
62
  runtime = AgentRunService(
62
63
  runtime_engine,
63
64
  store or default_store(),
@@ -73,6 +74,8 @@ def create_app(
73
74
  if internal_token
74
75
  else None
75
76
  ),
77
+ max_concurrent_runs=capacity.max_concurrent_runs,
78
+ max_queue_depth=capacity.max_queue_depth,
76
79
  )
77
80
 
78
81
  @asynccontextmanager
@@ -92,35 +95,7 @@ def create_app(
92
95
  create_report_router(runtime_report_store, internal_token)
93
96
  )
94
97
 
95
- @application.get("/health/live")
96
- async def live() -> dict[str, str]:
97
- return {"status": "live"}
98
-
99
- @application.get("/health/ready", response_model=None)
100
- async def ready() -> dict[str, object] | JSONResponse:
101
- health = getattr(runtime_engine, "health", None)
102
- if not health:
103
- return safe_error(
104
- 503,
105
- "RUNTIME_UNAVAILABLE",
106
- "Agent Runtime 尚未配置",
107
- True,
108
- )
109
- try:
110
- await runtime.probe()
111
- await health()
112
- return {
113
- "status": "ready",
114
- "capabilities": list(runtime_engine.capabilities),
115
- "inputModalities": list(runtime_engine.input_modalities),
116
- }
117
- except Exception:
118
- return safe_error(
119
- 503,
120
- "PROVIDER_UNAVAILABLE",
121
- "模型服务暂不可用",
122
- True,
123
- )
98
+ install_health_routes(application, runtime, runtime_engine)
124
99
 
125
100
  @application.get("/health/provider-governance", response_model=None)
126
101
  async def provider_governance_health(
@@ -219,6 +194,10 @@ def create_app(
219
194
  return safe_error(403, "FORBIDDEN", "内部调用认证失败", False)
220
195
  if not idempotency_key.strip():
221
196
  return safe_error(400, "INVALID_INPUT", "幂等键不能为空", False)
197
+ try:
198
+ await require_vision_readiness(runtime_engine, request)
199
+ except SafeEngineError as error:
200
+ return safe_error(503, error.code, error.safe_message, error.retryable)
222
201
  record = await runtime.start(
223
202
  request,
224
203
  idempotency_key,
@@ -35,11 +35,20 @@ class OpenAiCompatibleConfig:
35
35
  connect_timeout_seconds: float = 5.0
36
36
  request_timeout_seconds: float = 60.0
37
37
  max_response_bytes: int = 2 * 1024 * 1024
38
+ max_duration_seconds: int = 300
39
+ max_input_bytes: int = 67_108_864
40
+ max_artifacts: int = 16
41
+ max_pixels_per_artifact: int = 100_000_000
38
42
  max_tool_rounds: int = 8
39
43
  https_host_allowlist: tuple[str, ...] = ()
40
44
  deployment_key: str = "ai.openai-compatible"
41
45
  capabilities: tuple[str, ...] = ("text-generation",)
42
46
  input_modalities: tuple[str, ...] = ("text",)
47
+ readiness_deployment_identity: str | None = None
48
+ readiness_release_digest: str | None = None
49
+ readiness_ttl_seconds: int = 60
50
+ max_concurrent_runs: int = 1
51
+ max_queue_depth: int = 0
43
52
 
44
53
  def __post_init__(self) -> None:
45
54
  normalized = normalize_base_url(self.base_url)
@@ -91,6 +100,26 @@ class OpenAiCompatibleConfig:
91
100
  1_024,
92
101
  16 * 1024 * 1024,
93
102
  ),
103
+ max_duration_seconds=read_integer(
104
+ environment, "AI_PROVIDER_MAX_DURATION_SECONDS", 300, 1, 300
105
+ ),
106
+ max_input_bytes=read_integer(
107
+ environment,
108
+ "AI_PROVIDER_MAX_INPUT_BYTES",
109
+ 67_108_864,
110
+ 1_024,
111
+ 67_108_864,
112
+ ),
113
+ max_artifacts=read_integer(
114
+ environment, "AI_PROVIDER_MAX_ARTIFACTS", 16, 1, 16
115
+ ),
116
+ max_pixels_per_artifact=read_integer(
117
+ environment,
118
+ "AI_PROVIDER_MAX_PIXELS_PER_ARTIFACT",
119
+ 100_000_000,
120
+ 1,
121
+ 100_000_000,
122
+ ),
94
123
  capabilities=read_csv(
95
124
  environment,
96
125
  "AI_PROVIDER_CAPABILITIES",
@@ -101,6 +130,21 @@ class OpenAiCompatibleConfig:
101
130
  "AI_PROVIDER_INPUT_MODALITIES",
102
131
  ("text",),
103
132
  ),
133
+ readiness_deployment_identity=optional_value(
134
+ environment, "AI_PROVIDER_DEPLOYMENT_IDENTITY"
135
+ ),
136
+ readiness_release_digest=optional_value(
137
+ environment, "AI_PROVIDER_RELEASE_DIGEST"
138
+ ),
139
+ readiness_ttl_seconds=read_integer(
140
+ environment, "AI_PROVIDER_READINESS_TTL_SECONDS", 60, 1, 300
141
+ ),
142
+ max_concurrent_runs=read_integer(
143
+ environment, "AI_PROVIDER_MAX_CONCURRENT_RUNS", 1, 1, 1_000
144
+ ),
145
+ max_queue_depth=read_integer(
146
+ environment, "AI_PROVIDER_MAX_QUEUE_DEPTH", 0, 0, 10_000
147
+ ),
104
148
  )
105
149
 
106
150
 
@@ -216,3 +260,8 @@ def read_csv(
216
260
  if not values or len(values) > 32:
217
261
  raise ValueError(f"{key} 无效")
218
262
  return values
263
+
264
+
265
+ def optional_value(environment: Mapping[str, str], key: str) -> str | None:
266
+ value = environment.get(key, "").strip()
267
+ return value or None
@@ -139,6 +139,18 @@ class RuntimeRelease(CanonicalModel):
139
139
  manifest_digest: str = Field(pattern=r"^[a-f0-9]{64}$")
140
140
 
141
141
 
142
+ class VlmReadinessPin(CanonicalModel):
143
+ key: str = Field(min_length=1, max_length=160)
144
+ identity: str = Field(
145
+ pattern=(
146
+ r"^windy-deployment-v1_[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-"
147
+ r"[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
148
+ )
149
+ )
150
+ release_digest: str = Field(pattern=r"^sha256:[a-f0-9]{64}$")
151
+ offers_digest: str = Field(pattern=r"^sha256:[a-f0-9]{64}$")
152
+
153
+
142
154
  class RunReportingContext(CanonicalModel):
143
155
  """Trusted platform metadata for reporting, never an authorization fact."""
144
156
 
@@ -180,6 +192,7 @@ class StartRunRequest(CanonicalModel):
180
192
  tool_network_policy: ToolNetworkPolicy = Field(default_factory=ToolNetworkPolicy)
181
193
  execution_grant: str = ""
182
194
  tool_host_url: str = ""
195
+ readiness_pin: VlmReadinessPin | None = None
183
196
  release: RuntimeRelease = Field(default_factory=legacy_release)
184
197
  trace_id: str = Field(default="", max_length=160)
185
198
  reporting: RunReportingContext | None = None
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Protocol, runtime_checkable
5
+
6
+ from .engine import AgentEngineAdapter
7
+
8
+
9
+ @dataclass(frozen=True)
10
+ class EngineCapacity:
11
+ max_concurrent_runs: int
12
+ max_queue_depth: int
13
+
14
+
15
+ @runtime_checkable
16
+ class ResourceLimitedEngine(Protocol):
17
+ @property
18
+ def max_concurrent_runs(self) -> int: ...
19
+
20
+ @property
21
+ def max_queue_depth(self) -> int: ...
22
+
23
+
24
+ def engine_capacity(engine: AgentEngineAdapter) -> EngineCapacity:
25
+ if not isinstance(engine, ResourceLimitedEngine):
26
+ return EngineCapacity(1, 0)
27
+ concurrent = engine.max_concurrent_runs
28
+ queued = engine.max_queue_depth
29
+ if concurrent < 1 or queued < 0:
30
+ raise ValueError("Agent Engine 容量声明无效")
31
+ return EngineCapacity(concurrent, queued)
@@ -33,6 +33,11 @@ def request_fingerprint(request: StartRunRequest) -> str:
33
33
  "outputSchemaKey": request.output_schema_key,
34
34
  "outputSchema": request.output_schema,
35
35
  "release": resolved_release(request),
36
+ "readinessPin": (
37
+ request.readiness_pin.model_dump(by_alias=True)
38
+ if request.readiness_pin
39
+ else None
40
+ ),
36
41
  },
37
42
  ensure_ascii=False,
38
43
  separators=(",", ":"),
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ from fastapi import FastAPI
4
+ from fastapi.responses import JSONResponse
5
+
6
+ from .http_helpers import safe_error
7
+ from .service import AgentRunService
8
+ from .vlm_readiness import unavailable_vlm_snapshot
9
+
10
+
11
+ def install_health_routes(
12
+ application: FastAPI, runtime: AgentRunService, engine: object
13
+ ) -> None:
14
+ @application.get("/health/live")
15
+ async def live() -> dict[str, str]:
16
+ return {"status": "live"}
17
+
18
+ @application.get("/health/ready", response_model=None)
19
+ async def ready() -> dict[str, object] | JSONResponse:
20
+ try:
21
+ await runtime.probe()
22
+ return {"status": "ready"}
23
+ except Exception:
24
+ return safe_error(
25
+ 503,
26
+ "RUNTIME_UNAVAILABLE",
27
+ "Agent Run 存储暂不可用",
28
+ True,
29
+ )
30
+
31
+ @application.get("/health/vlm-ready", response_model=None)
32
+ async def vlm_ready() -> dict[str, object] | JSONResponse:
33
+ readiness = getattr(engine, "readiness", None)
34
+ if not readiness:
35
+ return JSONResponse(
36
+ unavailable_vlm_snapshot(configured=False), status_code=503
37
+ )
38
+ try:
39
+ await runtime.probe()
40
+ snapshot = await readiness()
41
+ status = 200 if snapshot.get("status") == "ready" else 503
42
+ return JSONResponse(snapshot, status_code=status)
43
+ except Exception:
44
+ return JSONResponse(
45
+ unavailable_vlm_snapshot(
46
+ configured=True,
47
+ failure_code="CONNECTION_FAILED",
48
+ ),
49
+ status_code=503,
50
+ )
@@ -49,6 +49,7 @@ from .tool_host import (
49
49
  ToolInvocation,
50
50
  canonical_tool_call_id,
51
51
  )
52
+ from .vlm_readiness import VlmReadinessProbe
52
53
 
53
54
 
54
55
  class OpenAiCompatibleEngineAdapter(AgentEngineAdapter):
@@ -73,6 +74,14 @@ class OpenAiCompatibleEngineAdapter(AgentEngineAdapter):
73
74
  def input_modalities(self) -> tuple[str, ...]:
74
75
  return self._provider.config.input_modalities
75
76
 
77
+ @property
78
+ def max_concurrent_runs(self) -> int:
79
+ return self._provider.config.max_concurrent_runs
80
+
81
+ @property
82
+ def max_queue_depth(self) -> int:
83
+ return self._provider.config.max_queue_depth
84
+
76
85
  def supports(self, operation_key: str) -> bool:
77
86
  return bool(operation_key.strip())
78
87
 
@@ -293,8 +302,8 @@ class OpenAiCompatibleEngineAdapter(AgentEngineAdapter):
293
302
  if event is not None:
294
303
  event.set()
295
304
 
296
- async def health(self) -> None:
297
- await self._provider.health()
305
+ async def readiness(self) -> dict[str, object]:
306
+ return await VlmReadinessProbe(self._provider.config, self._provider).inspect()
298
307
 
299
308
  def governance_health(self) -> dict[str, int | float | str | None]:
300
309
  return self._governance.health()
@@ -15,6 +15,7 @@ from .contracts import AgentErrorCode, JsonValue, RuntimeToolDefinition
15
15
  from .engine import SafeEngineError
16
16
  from .multimodal import response_format
17
17
  from .report_types import UsageFacts
18
+ from .vision_probe import probe_vision
18
19
 
19
20
 
20
21
  @dataclass
@@ -48,15 +49,8 @@ class OpenAiCompatibleProvider:
48
49
  self._resolver = resolver
49
50
  self._transport = transport
50
51
 
51
- async def health(self) -> None:
52
- async with self._client() as client:
53
- try:
54
- response = await client.get("/models")
55
- await self._bounded_body(response)
56
- except httpx.HTTPError as error:
57
- raise provider_failure(error) from None
58
- if not response.is_success:
59
- raise provider_status_failure(response.status_code)
52
+ async def probe_vision(self) -> None:
53
+ await probe_vision(self)
60
54
 
61
55
  async def complete_turn(
62
56
  self,
@@ -124,6 +124,11 @@ class PostgresRunStore:
124
124
  async with self._pool.connection() as connection:
125
125
  return await self._backend.read(connection, run_id)
126
126
 
127
+ async def get_by_idempotency(self, idempotency_key: str) -> RunRecord | None:
128
+ await self._backend.ready()
129
+ async with self._pool.connection() as connection:
130
+ return await self._backend.by_idempotency(connection, idempotency_key)
131
+
127
132
  async def append(
128
133
  self,
129
134
  run_id: str,
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Protocol
4
+
5
+
6
+ class ReadinessEngine(Protocol):
7
+ async def readiness(self) -> dict[str, object]: ...
8
+
9
+
10
+ async def readiness_pin_matches(engine: object, expected: dict[str, object]) -> bool:
11
+ readiness = getattr(engine, "readiness", None)
12
+ if not readiness:
13
+ return False
14
+ try:
15
+ snapshot = await readiness()
16
+ except Exception:
17
+ return False
18
+ deployment = snapshot.get("deployment") if isinstance(snapshot, dict) else None
19
+ probe = snapshot.get("downstreamProbe") if isinstance(snapshot, dict) else None
20
+ probe_names = {
21
+ "identity": "deploymentIdentity",
22
+ "releaseDigest": "releaseDigest",
23
+ "offersDigest": "offersDigest",
24
+ }
25
+ return bool(
26
+ isinstance(snapshot, dict)
27
+ and snapshot.get("status") == "ready"
28
+ and isinstance(deployment, dict)
29
+ and isinstance(probe, dict)
30
+ and probe.get("status") == "passed"
31
+ and all(deployment.get(key) == value for key, value in expected.items())
32
+ and all(
33
+ probe.get(probe_names[key]) == value
34
+ for key, value in expected.items()
35
+ if key in probe_names
36
+ )
37
+ )
@@ -0,0 +1,64 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from dataclasses import dataclass
5
+
6
+ from .contracts import JsonValue
7
+ from .engine import SafeEngineError
8
+ from .run_capacity import (
9
+ RunCapacity,
10
+ RunCapacityReservation,
11
+ RunCapacityUnavailable,
12
+ )
13
+ from .store import IdempotencyConflictError, RunRecord, RunStore
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class RunAdmissionResult:
18
+ record: RunRecord
19
+ reservation: RunCapacityReservation | None
20
+
21
+
22
+ class RunAdmission:
23
+ def __init__(self, store: RunStore, capacity: RunCapacity) -> None:
24
+ self._store = store
25
+ self._capacity = capacity
26
+ self._lock = asyncio.Lock()
27
+
28
+ async def admit(
29
+ self,
30
+ candidate: RunRecord,
31
+ invocation: JsonValue,
32
+ ) -> RunAdmissionResult:
33
+ async with self._lock:
34
+ current = await self._store.get_by_idempotency(candidate.idempotency_key)
35
+ if current:
36
+ if current.fingerprint != candidate.fingerprint:
37
+ raise IdempotencyConflictError
38
+ return RunAdmissionResult(current, None)
39
+ try:
40
+ reservation = await self._capacity.reserve()
41
+ except RunCapacityUnavailable:
42
+ raise SafeEngineError(
43
+ "RUNTIME_UNAVAILABLE",
44
+ "VLM Runtime 容量已满",
45
+ retryable=True,
46
+ ) from None
47
+ try:
48
+ record, created = await self._store.create_or_get(
49
+ candidate,
50
+ invocation,
51
+ )
52
+ except Exception:
53
+ await reservation.release()
54
+ raise
55
+ if not created:
56
+ await reservation.release()
57
+ return RunAdmissionResult(record, None)
58
+ return RunAdmissionResult(record, reservation)
59
+
60
+ async def reserve_recovery(self) -> RunCapacityReservation | None:
61
+ try:
62
+ return await self._capacity.reserve()
63
+ except RunCapacityUnavailable:
64
+ return None
@@ -0,0 +1,59 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+
5
+
6
+ class RunCapacityUnavailable(Exception):
7
+ pass
8
+
9
+
10
+ class RunCapacity:
11
+ def __init__(self, max_concurrent_runs: int, max_queue_depth: int) -> None:
12
+ if max_concurrent_runs < 1 or max_queue_depth < 0:
13
+ raise ValueError("Agent Run 容量配置无效")
14
+ self._maximum = max_concurrent_runs
15
+ self._queue_maximum = max_queue_depth
16
+ self._active = 0
17
+ self._queued = 0
18
+ self._condition = asyncio.Condition()
19
+
20
+ async def reserve(self) -> RunCapacityReservation:
21
+ async with self._condition:
22
+ if self._active + self._queued >= self._maximum + self._queue_maximum:
23
+ raise RunCapacityUnavailable
24
+ self._queued += 1
25
+ return RunCapacityReservation(self)
26
+
27
+ async def enter(self, reservation: RunCapacityReservation) -> None:
28
+ async with self._condition:
29
+ while self._active >= self._maximum:
30
+ await self._condition.wait()
31
+ if reservation.released or reservation.entered:
32
+ raise RuntimeError("Agent Run 容量票据状态无效")
33
+ self._queued -= 1
34
+ self._active += 1
35
+ reservation.entered = True
36
+
37
+ async def release(self, reservation: RunCapacityReservation) -> None:
38
+ async with self._condition:
39
+ if reservation.released:
40
+ return
41
+ if reservation.entered:
42
+ self._active -= 1
43
+ else:
44
+ self._queued -= 1
45
+ reservation.released = True
46
+ self._condition.notify_all()
47
+
48
+
49
+ class RunCapacityReservation:
50
+ def __init__(self, capacity: RunCapacity) -> None:
51
+ self._capacity = capacity
52
+ self.entered = False
53
+ self.released = False
54
+
55
+ async def enter(self) -> None:
56
+ await self._capacity.enter(self)
57
+
58
+ async def release(self) -> None:
59
+ await self._capacity.release(self)