okengine 0.21.1 → 0.23.0

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 (342) hide show
  1. package/AGENTS.md +11 -4
  2. package/LICENSE +202 -0
  3. package/NOTICE +2 -0
  4. package/README.md +15 -9
  5. package/manifest.v1.schema.json +54 -0
  6. package/package.json +53 -38
  7. package/site/content/docs/ai/mcp.mdx +13 -9
  8. package/site/content/docs/ai/skills.mdx +2 -2
  9. package/site/content/docs/client/calling.mdx +27 -19
  10. package/site/content/docs/client/index.mdx +1 -1
  11. package/site/content/docs/elements/ai/agents.mdx +61 -13
  12. package/site/content/docs/elements/ai/decide.mdx +536 -0
  13. package/site/content/docs/elements/ai/events.mdx +373 -0
  14. package/site/content/docs/elements/ai/index.mdx +9 -3
  15. package/site/content/docs/elements/ai/meta.json +1 -1
  16. package/site/content/docs/elements/ai/prompts.mdx +4 -2
  17. package/site/content/docs/elements/channel/email.mdx +1 -1
  18. package/site/content/docs/elements/channel/index.mdx +1 -1
  19. package/site/content/docs/elements/flow/http.mdx +4 -4
  20. package/site/content/docs/elements/flow/index.mdx +3 -3
  21. package/site/content/docs/elements/flow/meta.json +1 -1
  22. package/site/content/docs/elements/gate/auth.mdx +4 -1
  23. package/site/content/docs/elements/gate/tenancy.mdx +1 -1
  24. package/site/content/docs/elements/store/index.mdx +1 -1
  25. package/site/content/docs/elements/store/kv.mdx +5 -5
  26. package/site/content/docs/elements/vault/rotation.mdx +15 -0
  27. package/site/content/docs/plugins/otp.mdx +31 -31
  28. package/site/content/docs/recipes/dragonfly.mdx +5 -5
  29. package/site/content/docs/recipes/index.mdx +6 -6
  30. package/site/content/docs/recipes/mailpit.mdx +1 -1
  31. package/site/content/docs/recipes/meilisearch.mdx +1 -1
  32. package/site/content/docs/recipes/pgdog.mdx +1 -1
  33. package/site/content/docs/recipes/postgres.mdx +12 -8
  34. package/site/content/docs/recipes/redis.mdx +4 -4
  35. package/site/content/docs/reference/cli.mdx +2 -1
  36. package/site/content/docs/reference/configuration.mdx +11 -9
  37. package/site/content/docs/reference/errors.mdx +12 -2
  38. package/site/content/docs/reference/fx.mdx +35 -21
  39. package/site/content/docs/reference/idempotency.mdx +192 -0
  40. package/site/content/docs/reference/index.mdx +6 -1
  41. package/site/content/docs/reference/meta.json +2 -1
  42. package/site/content/docs/understand/meta.json +1 -1
  43. package/site/content/docs/{elements/flow → understand}/routing.mdx +11 -10
  44. package/site/content/docs/understand/the-architecture.mdx +14 -12
  45. package/site/content/docs/understand/try-it.mdx +3 -3
  46. package/src/auth/api-key-sql.test.ts +44 -0
  47. package/src/auth/api-key-sql.ts +1 -0
  48. package/src/auth/api-keys.ts +30 -12
  49. package/src/auth/config.ts +6 -2
  50. package/src/auth/gate-auth.test.ts +20 -0
  51. package/src/cli/agents-md.test.ts +25 -0
  52. package/src/cli/ask-vault-gaps.test.ts +38 -1
  53. package/src/cli/ask-vault-gaps.ts +35 -2
  54. package/src/cli/competitor-mention-removal.test.ts +3 -3
  55. package/src/cli/decide.ts +174 -0
  56. package/src/cli/decision-lock-watch.test.ts +45 -0
  57. package/src/cli/decision-lock-watch.ts +51 -0
  58. package/src/cli/dev-app-runner.ts +34 -8
  59. package/src/cli/dev-auth-secret.test.ts +49 -0
  60. package/src/cli/dev-auth-secret.ts +49 -0
  61. package/src/cli/dev-hot.test.ts +41 -0
  62. package/src/cli/dev-hot.ts +48 -0
  63. package/src/cli/dev.test.ts +1 -1
  64. package/src/cli/dev.ts +24 -6
  65. package/src/cli/docker-cli.test.ts +1 -1
  66. package/src/cli/eval.ts +142 -1
  67. package/src/cli/index.ts +14 -1
  68. package/src/cli/load-config.images.test.ts +12 -12
  69. package/src/cli/load-config.ts +2 -2
  70. package/src/cli/mcp-from-console.ts +48 -0
  71. package/src/cli/registry.ts +35 -1
  72. package/src/cli/vault-cmd.test.ts +23 -0
  73. package/src/cli/vault-cmd.ts +7 -0
  74. package/src/client/agent.ts +307 -0
  75. package/src/client/create.ts +18 -1
  76. package/src/client/transport.test.ts +245 -0
  77. package/src/client/transport.ts +133 -19
  78. package/src/client/types.ts +29 -3
  79. package/src/client-react/index.ts +7 -1
  80. package/src/client-react/use-agent-run.test.ts +271 -0
  81. package/src/client-react/use-agent-run.ts +193 -0
  82. package/src/compiler/ai-approval.test.ts +36 -0
  83. package/src/compiler/ai-repair.test.ts +22 -0
  84. package/src/compiler/decisions.extract.test.ts +164 -0
  85. package/src/compiler/effects-infer.ts +753 -17
  86. package/src/compiler/extract.test.ts +37 -0
  87. package/src/compiler/extract.ts +381 -24
  88. package/src/compiler/fixtures/skyport.expected.json +24 -0
  89. package/src/compiler/fx-follow.test.ts +164 -0
  90. package/src/compiler/fx-index.ts +399 -0
  91. package/src/compiler/response.ts +35 -2
  92. package/src/config/index.ts +21 -3
  93. package/src/console/server/ai-runs-flows.ts +269 -0
  94. package/src/console/server/ai-runs.test.ts +323 -0
  95. package/src/console/server/ai-runs.ts +562 -0
  96. package/src/console/server/ai.ts +12 -1
  97. package/src/console/server/app.ts +10 -1
  98. package/src/console/server/decisions-flows.ts +157 -0
  99. package/src/console/server/decisions.test.ts +66 -0
  100. package/src/console/server/decisions.ts +229 -0
  101. package/src/console/server/flows-invoke.test.ts +2 -2
  102. package/src/console/server/flows.ts +50 -2
  103. package/src/console/server/invoke-user-flow.ts +9 -0
  104. package/src/console/server/runs-ingest.ts +16 -0
  105. package/src/console/server/serve.ts +5 -0
  106. package/src/console/server/state.ts +25 -1
  107. package/src/console/server/store-stats.test.ts +47 -0
  108. package/src/console/server/store-stats.ts +92 -18
  109. package/src/console/ui-next/dist/assets/access-page-DDKkhT9v.js +4 -0
  110. package/src/console/ui-next/dist/assets/agent-disclosure-62Xts8Xi.js +1 -0
  111. package/src/console/ui-next/dist/assets/{cache-glyph-92uM5MO7.js → cache-glyph-DyeoKHKA.js} +1 -1
  112. package/src/console/ui-next/dist/assets/{call-pii-button-DtGVPtcs.js → call-pii-button-DvfpLXsU.js} +1 -1
  113. package/src/console/ui-next/dist/assets/{collapsible-DN7l6zmC.js → collapsible-BY03SeCg.js} +1 -1
  114. package/src/console/ui-next/dist/assets/confirm-sheet-DZfuJXP4.js +1 -0
  115. package/src/console/ui-next/dist/assets/copy-inline-button-BTjPVjRT.js +1 -0
  116. package/src/console/ui-next/dist/assets/decisions-page-CgkKlA56.js +1 -0
  117. package/src/console/ui-next/dist/assets/detail-header-Dk5LipF6.js +1 -0
  118. package/src/console/ui-next/dist/assets/dropdown-menu-CRGrj5JU.js +1 -0
  119. package/src/console/ui-next/dist/assets/duration-tone-Y6HLjyJ5.js +9 -0
  120. package/src/console/ui-next/dist/assets/element-icons-C6t8Vlml.js +1 -0
  121. package/src/console/ui-next/dist/assets/explorer-chrome-Dslh2yE8.js +1 -0
  122. package/src/console/ui-next/dist/assets/explorer-empty-CIVg7Jgb.js +1 -0
  123. package/src/console/ui-next/dist/assets/flows-page-DLPfNy-_.js +1 -0
  124. package/src/console/ui-next/dist/assets/{highlighted-json-BlAEVgNW.js → highlighted-json-D7nNzpgB.js} +1 -1
  125. package/src/console/ui-next/dist/assets/{http-method-BDf7OAHv.js → http-method-DdL19zzh.js} +1 -1
  126. package/src/console/ui-next/dist/assets/index-BlrN49Hs.css +2 -0
  127. package/src/console/ui-next/dist/assets/index-C0lc_s9d.js +58 -0
  128. package/src/console/ui-next/dist/assets/observability-page-CRlcyLCC.js +8 -0
  129. package/src/console/ui-next/dist/assets/{replica-lag-B3GLNVfF.js → replica-lag-Bb3FWUu9.js} +7 -7
  130. package/src/console/ui-next/dist/assets/request-meta-DYBMWhX8.js +1 -0
  131. package/src/console/ui-next/dist/assets/shortcut-keys-DTE1sjTC.js +1 -0
  132. package/src/console/ui-next/dist/assets/store-page-CcE-SXC8.js +41 -0
  133. package/src/console/ui-next/dist/assets/trace-detail-sheet-CKMSEQ4s.js +2 -0
  134. package/src/console/ui-next/dist/assets/tree-expand-toggle-QOfk0M0H.js +55 -0
  135. package/src/console/ui-next/dist/assets/units-page-DKC1CDDd.js +1 -0
  136. package/src/console/ui-next/dist/assets/use-vault-list-BAyQG8Re.js +1 -0
  137. package/src/console/ui-next/dist/assets/vault-page-B54v4Yit.js +2 -0
  138. package/src/console/ui-next/dist/index.html +4 -3
  139. package/src/console/ui-next/seed-parked-approval.ts +126 -0
  140. package/src/console/ui-next/src/client.ts +224 -1
  141. package/src/console/ui-next/src/components/explorer/detail-header.tsx +9 -0
  142. package/src/console/ui-next/src/components/explorer/explorer-start-toggle.tsx +5 -1
  143. package/src/console/ui-next/src/components/ui/sheet-form.tsx +21 -12
  144. package/src/console/ui-next/src/features/flows/decisions/decisions-page.tsx +216 -0
  145. package/src/console/ui-next/src/features/flows/decisions/resolve.test.ts +48 -0
  146. package/src/console/ui-next/src/features/flows/decisions/resolve.ts +111 -0
  147. package/src/console/ui-next/src/features/flows/flows-page.tsx +10 -0
  148. package/src/console/ui-next/src/features/flows/graph/element-map.ts +1 -0
  149. package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +6 -0
  150. package/src/console/ui-next/src/features/flows/traces/effect-summary.test.ts +24 -0
  151. package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +24 -0
  152. package/src/console/ui-next/src/features/flows/traces/http-status.ts +58 -0
  153. package/src/console/ui-next/src/features/flows/traces/request-client-card.tsx +355 -0
  154. package/src/console/ui-next/src/features/flows/traces/request-client.test.ts +114 -0
  155. package/src/console/ui-next/src/features/flows/traces/request-client.ts +423 -0
  156. package/src/console/ui-next/src/features/flows/traces/request-input-view.test.ts +52 -6
  157. package/src/console/ui-next/src/features/flows/traces/request-input-view.ts +85 -19
  158. package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +505 -80
  159. package/src/console/ui-next/src/features/flows/traces/trace-lanes.test.ts +61 -0
  160. package/src/console/ui-next/src/features/flows/traces/trace-lanes.ts +78 -0
  161. package/src/console/ui-next/src/features/flows/traces/trace-nav.test.ts +48 -0
  162. package/src/console/ui-next/src/features/flows/traces/trace-nav.ts +57 -0
  163. package/src/console/ui-next/src/features/flows/traces/trace-request-section.tsx +275 -96
  164. package/src/console/ui-next/src/features/flows/traces/traces-pane.tsx +16 -2
  165. package/src/console/ui-next/src/features/observability/detail/ai-runs.tsx +369 -0
  166. package/src/console/ui-next/src/features/observability/observability-page.tsx +31 -1
  167. package/src/console/ui-next/src/features/observability/state/observability-selection.ts +18 -3
  168. package/src/console/ui-next/src/features/store/performance/kv-performance-panel.tsx +12 -1
  169. package/src/console/ui-next/src/features/store/performance/performance-panel.tsx +14 -1
  170. package/src/console/ui-next/src/features/units/call/call-api-panel.tsx +1 -1
  171. package/src/console/ui-next/src/features/units/detail/flow-contract-panel.tsx +15 -2
  172. package/src/console/ui-next/src/features/units/explorer/units-tree.tsx +73 -18
  173. package/src/console/ui-next/src/features/units/lib/unit-tree.test.ts +21 -0
  174. package/src/console/ui-next/src/features/units/lib/unit-tree.ts +82 -0
  175. package/src/console/ui-next/src/features/units/units-page.tsx +25 -7
  176. package/src/console/ui-next/src/router.tsx +17 -0
  177. package/src/console/ui-next/ui-next-seed-runs.ts +23 -0
  178. package/src/console/ui-next/vite-console-kernel-plugin.ts +43 -3
  179. package/src/console/ui-next/vite.config.ts +9 -0
  180. package/src/docker/docker.test.ts +13 -13
  181. package/src/docker/images-config.test.ts +12 -12
  182. package/src/docker/recipes/dragonfly.ts +3 -2
  183. package/src/docker/recipes/redis.ts +1 -1
  184. package/src/docker/stack-id.test.ts +1 -1
  185. package/src/drivers/ai-anthropic.ts +212 -21
  186. package/src/drivers/ai-mock.ts +34 -1
  187. package/src/drivers/ai-openai-compatible.ts +67 -26
  188. package/src/drivers/ai-preconnect.ts +18 -0
  189. package/src/drivers/ai-stream.test.ts +62 -0
  190. package/src/drivers/ai-types.ts +20 -0
  191. package/src/drivers/journal-postgres.ts +455 -3
  192. package/src/drivers/meilisearch.ts +2 -0
  193. package/src/drivers/memory-ddl.test.ts +18 -0
  194. package/src/drivers/memory.ts +21 -1
  195. package/src/drivers/pg-rls.test.ts +31 -0
  196. package/src/drivers/pg-rls.ts +15 -0
  197. package/src/drivers/postgres.test.ts +9 -0
  198. package/src/drivers/postgres.ts +49 -11
  199. package/src/drivers/vault-builtin.test.ts +10 -0
  200. package/src/drivers/vault-builtin.ts +13 -1
  201. package/src/drivers/vault-remote-bag.ts +5 -1
  202. package/src/drivers/vault-types.ts +6 -1
  203. package/src/elements/ai/agent-event-slot.ts +27 -0
  204. package/src/elements/ai/approval-http.ts +207 -0
  205. package/src/elements/ai/approval.test.ts +741 -0
  206. package/src/elements/ai/approval.ts +228 -0
  207. package/src/elements/ai/decisions/bind.ts +163 -0
  208. package/src/elements/ai/decisions/certificate.test.ts +291 -0
  209. package/src/elements/ai/decisions/certificate.ts +377 -0
  210. package/src/elements/ai/decisions/certify.ts +314 -0
  211. package/src/elements/ai/decisions/decide.test.ts +953 -0
  212. package/src/elements/ai/decisions/e2e.test.ts +399 -0
  213. package/src/elements/ai/decisions/export.test.ts +120 -0
  214. package/src/elements/ai/decisions/export.ts +146 -0
  215. package/src/elements/ai/decisions/fixtures/openrouter-request.json +24 -0
  216. package/src/elements/ai/decisions/fixtures/openrouter-response.json +22 -0
  217. package/src/elements/ai/decisions/fixtures/typesafe-request.json +19 -0
  218. package/src/elements/ai/decisions/fixtures/typesafe-response.json +13 -0
  219. package/src/elements/ai/decisions/http.test.ts +154 -0
  220. package/src/elements/ai/decisions/http.ts +240 -0
  221. package/src/elements/ai/decisions/labels.test.ts +282 -0
  222. package/src/elements/ai/decisions/labels.ts +257 -0
  223. package/src/elements/ai/decisions/openrouter.live.test.ts +136 -0
  224. package/src/elements/ai/decisions/openrouter.ts +36 -0
  225. package/src/elements/ai/decisions/provider.ts +102 -0
  226. package/src/elements/ai/decisions/typesafe.ts +36 -0
  227. package/src/elements/ai/declare.ts +252 -1
  228. package/src/elements/ai/events.test.ts +379 -0
  229. package/src/elements/ai/events.ts +138 -0
  230. package/src/elements/ai/run-events.test.ts +461 -0
  231. package/src/elements/ai/run-events.ts +522 -0
  232. package/src/elements/ai/runtime.ts +1186 -105
  233. package/src/elements/ai/stream-turn.ts +214 -0
  234. package/src/elements/ai/stream.live.test.ts +76 -0
  235. package/src/elements/ai/subagent.test.ts +136 -0
  236. package/src/elements/ai.test.ts +497 -3
  237. package/src/elements/ai.ts +16 -1
  238. package/src/elements/clock/durable.ts +27 -1
  239. package/src/elements/store/emit-drizzle.ts +2 -2
  240. package/src/elements/store/live-default.test.ts +2 -0
  241. package/src/elements/store/live-http.test.ts +1 -0
  242. package/src/elements/store/resource-list-docs.test.ts +2 -2
  243. package/src/elements/store/resource.test.ts +3 -3
  244. package/src/elements/store/schema-decl.test.ts +1 -0
  245. package/src/elements/store/sql-condition.ts +24 -7
  246. package/src/elements/store/sql-session.test.ts +51 -0
  247. package/src/elements/store/sql-session.ts +111 -1
  248. package/src/elements/store/upsert-app.test.ts +1 -1
  249. package/src/elements/vault/audit.test.ts +137 -0
  250. package/src/elements/vault/audit.ts +106 -13
  251. package/src/elements/vault/boot-chain.ts +9 -1
  252. package/src/elements/vault/builtin-adapter.ts +33 -3
  253. package/src/i18n/catalogs/ar.ts +9 -0
  254. package/src/i18n/catalogs/en.ts +9 -0
  255. package/src/index.ts +2 -0
  256. package/src/kernel/abort-scope.ts +33 -2
  257. package/src/kernel/agent-event-store.ts +448 -0
  258. package/src/kernel/app.ts +294 -19
  259. package/src/kernel/auto-cache.test.ts +6 -6
  260. package/src/kernel/boot-bind/ai.ts +3 -0
  261. package/src/kernel/boot-bind/store.test.ts +26 -0
  262. package/src/kernel/boot-bind/store.ts +82 -6
  263. package/src/kernel/boot-bind/vault.ts +1 -0
  264. package/src/kernel/boot.ts +34 -5
  265. package/src/kernel/builtin-errors.ts +10 -0
  266. package/src/kernel/capability.ts +3 -0
  267. package/src/kernel/client-descriptor.ts +1 -0
  268. package/src/kernel/concurrency.test.ts +33 -0
  269. package/src/kernel/decision-label-store.ts +441 -0
  270. package/src/kernel/effects-stamping.test.ts +2 -2
  271. package/src/kernel/effects.test.ts +2 -1
  272. package/src/kernel/effects.ts +13 -1
  273. package/src/kernel/element-registries.ts +3 -0
  274. package/src/kernel/errors-compiler.ts +20 -0
  275. package/src/kernel/errors-text.ts +4 -0
  276. package/src/kernel/errors.ts +2 -0
  277. package/src/kernel/external-effects.test.ts +36 -0
  278. package/src/kernel/flow.test.ts +2 -3
  279. package/src/kernel/flow.ts +24 -0
  280. package/src/kernel/fx-decide.ts +761 -0
  281. package/src/kernel/fx-fetch.ts +5 -1
  282. package/src/kernel/fx.test.ts +12 -5
  283. package/src/kernel/fx.ts +316 -29
  284. package/src/kernel/http-frame.test.ts +94 -0
  285. package/src/kernel/http-frame.ts +203 -0
  286. package/src/kernel/idempotency-store.ts +578 -0
  287. package/src/kernel/idempotency.test.ts +556 -0
  288. package/src/kernel/idempotency.ts +304 -0
  289. package/src/kernel/index.ts +1 -0
  290. package/src/kernel/journal.ts +160 -0
  291. package/src/kernel/json-result.ts +10 -0
  292. package/src/kernel/pipeline.test.ts +45 -0
  293. package/src/kernel/sse-id.ts +32 -0
  294. package/src/manifest/diff.ts +1 -0
  295. package/src/manifest/types.ts +37 -2
  296. package/src/mcp/ai-tools.test.ts +202 -0
  297. package/src/mcp/authorization.ts +66 -0
  298. package/src/mcp/session.ts +3 -0
  299. package/src/mcp/tools.ts +168 -0
  300. package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
  301. package/src/plugins/otp.test.ts +65 -1
  302. package/src/plugins/otp.ts +59 -7
  303. package/src/release/absolute-regression.test.ts +63 -0
  304. package/src/release/http-graph.test.ts +27 -0
  305. package/src/release/http-graph.ts +95 -0
  306. package/src/release/index.ts +3 -0
  307. package/src/release/limits.ts +17 -2
  308. package/src/release/measure.ts +144 -28
  309. package/src/runs/collect.ts +4 -1
  310. package/src/runs/parquet.test.ts +27 -1
  311. package/src/runs/parquet.ts +19 -0
  312. package/src/runs/types.ts +31 -0
  313. package/src/runtime/json-code-block.test.ts +106 -47
  314. package/src/runtime/json-code-block.ts +1209 -46
  315. package/src/term.test.ts +13 -0
  316. package/src/term.ts +81 -49
  317. package/src/test/create-test-app.test.ts +3 -1
  318. package/src/test/create-test-app.ts +40 -0
  319. package/src/test/live-signals.test.ts +1 -0
  320. package/src/test/provisions.integration.test.ts +1 -0
  321. package/src/test/tenant-isolation.test.ts +1 -0
  322. package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +0 -1
  323. package/src/console/ui-next/dist/assets/access-page-Bgt9bq2r.js +0 -4
  324. package/src/console/ui-next/dist/assets/agent-disclosure-B43CXZZR.js +0 -1
  325. package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +0 -1
  326. package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +0 -1
  327. package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +0 -1
  328. package/src/console/ui-next/dist/assets/duration-tone-BmIR9FV8.js +0 -9
  329. package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +0 -1
  330. package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +0 -1
  331. package/src/console/ui-next/dist/assets/flows-page-BMHs-IzK.js +0 -1
  332. package/src/console/ui-next/dist/assets/index-BKpaes3n.js +0 -63
  333. package/src/console/ui-next/dist/assets/index-VxoEz295.css +0 -2
  334. package/src/console/ui-next/dist/assets/observability-page-WnVLI-0j.js +0 -4
  335. package/src/console/ui-next/dist/assets/request-meta-DMbnAe3f.js +0 -1
  336. package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +0 -1
  337. package/src/console/ui-next/dist/assets/store-page-KvFDingJ.js +0 -41
  338. package/src/console/ui-next/dist/assets/trace-detail-sheet-Htk8Cm9t.js +0 -2
  339. package/src/console/ui-next/dist/assets/tree-expand-toggle-CFMPWX4f.js +0 -55
  340. package/src/console/ui-next/dist/assets/units-page-C4NdNuxP.js +0 -1
  341. package/src/console/ui-next/dist/assets/use-vault-list-CT4-gajj.js +0 -1
  342. package/src/console/ui-next/dist/assets/vault-page-CBYl0LW_.js +0 -2
package/src/cli/eval.ts CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { resolve } from "node:path";
6
6
  import { parseEvalJsonl, runPromptEvals, type EvalCase } from "../elements/ai/eval.ts";
7
+ import type { DecisionResponse } from "../elements/ai/decisions/provider.ts";
7
8
  import type { Manifest } from "../manifest/types.ts";
8
9
 
9
10
  /** Options for {@link runOkeEval}. */
@@ -96,17 +97,157 @@ export async function runOkeEval(options: OkeEvalOptions = {}): Promise<number>
96
97
  */
97
98
  export async function evalCli(args: string[]): Promise<number> {
98
99
  let manifestPath: string | undefined;
100
+ let certify = false;
99
101
  for (let i = 0; i < args.length; i++) {
100
102
  const a = args[i]!;
101
103
  if (a === "--manifest" || a === "-m") {
102
104
  manifestPath = args[++i];
105
+ } else if (a === "--certify") {
106
+ certify = true;
103
107
  } else if (a === "--help" || a === "-h") {
104
- console.log(`oke eval [--manifest oke.manifest.json]
108
+ console.log(`oke eval [--manifest oke.manifest.json] [--certify]
105
109
 
106
110
  Run prompt eval sets declared in the Manifest. Fails CI on regression.
111
+ --certify builds a decision certificate from each decision seed file.
107
112
  `);
108
113
  return 0;
109
114
  }
110
115
  }
116
+ if (certify) return runOkeCertify({ manifestPath });
111
117
  return runOkeEval({ manifestPath });
112
118
  }
119
+
120
+ /**
121
+ * Build certificates from decision seed files. Prompt evals are not run.
122
+ *
123
+ * @param options - Manifest path
124
+ */
125
+ export async function runOkeCertify(
126
+ options: {
127
+ readonly manifestPath?: string;
128
+ readonly manifest?: Manifest;
129
+ readonly root?: string;
130
+ readonly evaluate?: (input: unknown) => Promise<DecisionResponse>;
131
+ } = {},
132
+ ): Promise<number> {
133
+ const { certifySeed } = await import("../elements/ai/decisions/certify.ts");
134
+ const { aiDecisionRegistry } = await import("../kernel/element-registries.ts");
135
+ const { DECISION_LOCK_FILENAME, parseDecisionLockfile } =
136
+ await import("../elements/ai/decisions/certificate.ts");
137
+ const { resolveStartEntry } = await import("./start.ts");
138
+ const root = resolve(options.root ?? process.env["OKE_ROOT_DIR"] ?? ".");
139
+ process.env["OKE_ROOT_DIR"] ??= root;
140
+ let manifest = options.manifest;
141
+ if (!manifest) {
142
+ try {
143
+ const entry = await resolveStartEntry(root);
144
+ await import(entry);
145
+ } catch (err) {
146
+ console.error(
147
+ `oke eval: failed to load the app: ${err instanceof Error ? err.message : String(err)}`,
148
+ );
149
+ return 1;
150
+ }
151
+ const path = resolve(root, options.manifestPath ?? "oke.manifest.json");
152
+ const file = Bun.file(path);
153
+ if (!(await file.exists())) {
154
+ console.error(`oke eval: manifest not found: ${path}`);
155
+ return 1;
156
+ }
157
+ manifest = (await file.json()) as Manifest;
158
+ }
159
+ const decisions = manifest.ai?.decisions ?? {};
160
+ const names = Object.keys(decisions);
161
+ if (names.length === 0) {
162
+ process.stdout.write("oke eval: no decisions declared\n");
163
+ return 0;
164
+ }
165
+ const injected = options.evaluate;
166
+ const lockPath = resolve(root, DECISION_LOCK_FILENAME);
167
+ const existingFile = Bun.file(lockPath);
168
+ const current = (await existingFile.exists())
169
+ ? parseDecisionLockfile(await existingFile.json())
170
+ : undefined;
171
+ const next = { decisions: { ...(current?.decisions ?? {}) } };
172
+ for (const name of names) {
173
+ const decision = decisions[name];
174
+ if (!decision?.evals) {
175
+ process.stdout.write(`oke eval: skip ${name} (no evals)\n`);
176
+ continue;
177
+ }
178
+ const decl = aiDecisionRegistry.find((item) => item.name === name);
179
+ if (!decl) {
180
+ console.error(`oke eval: decision "${name}" is not loaded`);
181
+ return 1;
182
+ }
183
+ const text = await Bun.file(resolve(root, decision.evals)).text();
184
+ const evaluate = injected ?? (await providerForDecision(decl));
185
+ next.decisions[name] = await certifySeed({
186
+ model: decl.model ?? decision.model ?? "",
187
+ maxError: decision.autonomy?.maxError ?? 0.05,
188
+ delta: decision.autonomy?.risk ?? decl.autonomy?.risk ?? 0.1,
189
+ jsonl: text,
190
+ ask: decl.ask,
191
+ evaluate,
192
+ });
193
+ }
194
+ await Bun.write(lockPath, `${JSON.stringify(next, null, 2)}\n`);
195
+ const { setDecisionDrift } = await import("../elements/ai/decisions/certificate.ts");
196
+ const { persistDecisionDrift } = await import("../elements/ai/decisions/labels.ts");
197
+ for (const name of names) {
198
+ setDecisionDrift(name, false);
199
+ persistDecisionDrift(name, false);
200
+ }
201
+ return 0;
202
+ }
203
+
204
+ async function providerForDecision(
205
+ decl: import("../elements/ai/declare.ts").AiDecisionDecl,
206
+ ): Promise<(input: unknown) => Promise<DecisionResponse>> {
207
+ const typesafe = decl.driverId === "typesafe";
208
+ const keyName = typesafe ? "TYPESAFE_API_KEY" : "OPENROUTER_API_KEY";
209
+ const apiKey = process.env[keyName];
210
+ if (!apiKey) throw new Error(`oke eval: secret "${keyName}" is not configured`);
211
+ const { createTypesafeDecisionProvider, TYPESAFE_JEV_MODEL } =
212
+ await import("../elements/ai/decisions/typesafe.ts");
213
+ const { createOpenRouterDecisionProvider, OPENROUTER_JEV_MODEL } =
214
+ await import("../elements/ai/decisions/openrouter.ts");
215
+ const provider = typesafe
216
+ ? createTypesafeDecisionProvider(apiKey)
217
+ : createOpenRouterDecisionProvider(apiKey);
218
+ const model = decl.model ?? (typesafe ? TYPESAFE_JEV_MODEL : OPENROUTER_JEV_MODEL);
219
+ return (input) =>
220
+ provider.evaluate({
221
+ model,
222
+ state: input,
223
+ questions: wireFromDecl(decl),
224
+ });
225
+ }
226
+
227
+ function wireFromDecl(
228
+ decl: import("../elements/ai/declare.ts").AiDecisionDecl,
229
+ ): import("../elements/ai/decisions/provider.ts").DecisionRequest["questions"] {
230
+ const questions: Record<string, import("../elements/ai/decisions/provider.ts").WireQuestion> = {};
231
+ for (const [id, question] of Object.entries(decl.ask)) {
232
+ if (question.kind === "choice") {
233
+ questions[id] = {
234
+ type: "choice",
235
+ instructions: question.instructions,
236
+ criteria: { ...question.options, none_of_these: null },
237
+ };
238
+ } else if (question.kind === "score") {
239
+ questions[id] = {
240
+ type: "score",
241
+ instructions: question.instructions,
242
+ criteria: question.levels,
243
+ };
244
+ } else {
245
+ questions[id] = {
246
+ type: "noul",
247
+ instructions: question.instructions,
248
+ ...(question.criteria !== undefined ? { criteria: question.criteria } : {}),
249
+ };
250
+ }
251
+ }
252
+ return questions;
253
+ }
package/src/cli/index.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  * Bare `oke` (TTY) → interactive Ink TUI. `oke <command>` runs directly.
6
6
  */
7
7
 
8
+ import type { VaultAuditConfig } from "../elements/vault/types.ts";
8
9
  import { aiCli } from "./ai.ts";
9
10
  import { branchCli } from "./branch.ts";
10
11
  import { buildCli } from "./build.ts";
@@ -15,6 +16,7 @@ import { dbCli } from "./db.ts";
15
16
  import { devCli } from "./dev.ts";
16
17
  import { doctorCli } from "./doctor.ts";
17
18
  import { dockerCli } from "./docker.ts";
19
+ import { decideCli } from "./decide.ts";
18
20
  import { evalCli } from "./eval.ts";
19
21
  import { EXIT_CODE_HELP, EXIT_OK, EXIT_USAGE } from "./exit.ts";
20
22
  import { gatesListCli } from "./gates-list.ts";
@@ -28,6 +30,7 @@ import { stackCli } from "./stack.ts";
28
30
  import { startCli } from "./start.ts";
29
31
  import { testCli } from "./test.ts";
30
32
  import { upgradeCli } from "./upgrade.ts";
33
+ import { loadOkeConfig } from "./load-config.ts";
31
34
  import { vaultCli } from "./vault-cmd.ts";
32
35
 
33
36
  const rawArgv = process.argv.slice(2);
@@ -90,7 +93,13 @@ if (cmd === "client" && sub === "add") {
90
93
  }
91
94
 
92
95
  if (cmd === "vault") {
93
- process.exit(await vaultCli(sub ? [sub, ...rest] : rest));
96
+ let audit: VaultAuditConfig | undefined;
97
+ try {
98
+ audit = (await loadOkeConfig()).config.vault?.audit;
99
+ } catch {
100
+ audit = undefined;
101
+ }
102
+ process.exit(await vaultCli(sub ? [sub, ...rest] : rest, audit === undefined ? {} : { audit }));
94
103
  }
95
104
 
96
105
  if (cmd === "docker") {
@@ -109,6 +118,10 @@ if (cmd === "eval") {
109
118
  process.exit(await evalCli(sub ? [sub, ...rest] : rest));
110
119
  }
111
120
 
121
+ if (cmd === "decide") {
122
+ process.exit(await decideCli(sub ? [sub, ...rest] : rest));
123
+ }
124
+
112
125
  if (cmd === "ai") {
113
126
  process.exit(await aiCli(sub ? [sub, ...rest] : rest));
114
127
  }
@@ -18,19 +18,19 @@ describe("flattenImagesConfig", () => {
18
18
  sql: "postgres:18-alpine",
19
19
  kv: "redis:8-alpine",
20
20
  files: "rustfs/rustfs:1.0.0",
21
- index: "getmeili/meilisearch:v1.53",
21
+ index: "getmeili/meilisearch:v1.54",
22
22
  },
23
- channel: { email: "axllent/mailpit:v1.31.1" },
24
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
23
+ channel: { email: "axllent/mailpit:v1.31.2" },
24
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.59",
25
25
  proxy: "caddy:2-alpine",
26
26
  }),
27
27
  ).toEqual({
28
28
  "store.sql": "postgres:18-alpine",
29
29
  "store.kv": "redis:8-alpine",
30
30
  "store.files": "rustfs/rustfs:1.0.0",
31
- "store.index": "getmeili/meilisearch:v1.53",
32
- "channel.email": "axllent/mailpit:v1.31.1",
33
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
31
+ "store.index": "getmeili/meilisearch:v1.54",
32
+ "channel.email": "axllent/mailpit:v1.31.2",
33
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.59",
34
34
  proxy: "caddy:2-alpine",
35
35
  });
36
36
  });
@@ -53,8 +53,8 @@ describe("defaultImagesFromConfig", () => {
53
53
  });
54
54
  expect(images).toEqual({
55
55
  "store.sql": "postgres:18-alpine",
56
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
57
- "store.kv": "redis:8-alpine",
56
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.59",
57
+ "store.kv": "docker.dragonflydb.io/dragonflydb/dragonfly:v2.0.0",
58
58
  });
59
59
  });
60
60
 
@@ -68,7 +68,7 @@ describe("defaultImagesFromConfig", () => {
68
68
  },
69
69
  });
70
70
  expect(images["store.sql"]).toBe("pgvector/pgvector:pg17");
71
- expect(images.pgdog).toBe("ghcr.io/pgdogdev/pgdog:v0.1.57");
71
+ expect(images.pgdog).toBe("ghcr.io/pgdogdev/pgdog:v0.1.59");
72
72
  });
73
73
 
74
74
  test("clock postgres alone pulls store.sql image", () => {
@@ -79,7 +79,7 @@ describe("defaultImagesFromConfig", () => {
79
79
  });
80
80
  expect(images).toEqual({
81
81
  "store.sql": "postgres:18-alpine",
82
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
82
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.59",
83
83
  });
84
84
  });
85
85
 
@@ -91,7 +91,7 @@ describe("defaultImagesFromConfig", () => {
91
91
  });
92
92
  expect(images).toEqual({
93
93
  "store.sql": "postgres:18-alpine",
94
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
94
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.59",
95
95
  });
96
96
  });
97
97
 
@@ -129,7 +129,7 @@ describe("resolveImages", () => {
129
129
  },
130
130
  });
131
131
  expect(images["store.sql"]).toBe("postgres:18-alpine");
132
- expect(images["store.kv"]).toBe("redis:8-alpine");
132
+ expect(images["store.kv"]).toBe("docker.dragonflydb.io/dragonflydb/dragonfly:v2.0.0");
133
133
  expect(images["store.kv.durable"]).toBeUndefined();
134
134
  });
135
135
  });
@@ -15,8 +15,8 @@ import type { Manifest } from "../manifest/types.ts";
15
15
  /** Default image pins when `images` is omitted but prod drivers need containers. */
16
16
  const DEFAULT_SQL_IMAGE = "postgres:18-alpine";
17
17
  const DEFAULT_PGVECTOR_IMAGE = "pgvector/pgvector:pg17";
18
- const DEFAULT_PGDOG_IMAGE = "ghcr.io/pgdogdev/pgdog:v0.1.57";
19
- const DEFAULT_KV_IMAGE = "redis:8-alpine";
18
+ const DEFAULT_PGDOG_IMAGE = "ghcr.io/pgdogdev/pgdog:v0.1.59";
19
+ const DEFAULT_KV_IMAGE = "docker.dragonflydb.io/dragonflydb/dragonfly:v2.0.0";
20
20
 
21
21
  /**
22
22
  * Prefer `dev` then `prod` for a driver map (compose infra ≈ production).
@@ -22,6 +22,10 @@ export interface McpConsoleSurface {
22
22
  readonly cwd: string;
23
23
  /** Clock shared with Console. */
24
24
  readonly now: () => number;
25
+ /** Journal that holds agent events and parked approvals. */
26
+ readonly journalStore?: import("../kernel/journal.ts").JournalStore | null;
27
+ /** In-process agent ledger. The follow log is the durable source. */
28
+ readonly aiRuntime?: import("../elements/ai.ts").AiRuntime | null;
25
29
  }
26
30
 
27
31
  /**
@@ -33,6 +37,50 @@ export function mcpContextFromConsole(state: McpConsoleSurface): McpContext {
33
37
  return {
34
38
  getManifest: () => state.manifest,
35
39
  listRuns: () => state.listRuns(),
40
+ listAgentRuns: async () => {
41
+ const { loadConsoleAgentRuns } = await import("../console/server/ai-runs.ts");
42
+ return loadConsoleAgentRuns({
43
+ runtime: state.aiRuntime ?? null,
44
+ store: state.journalStore ?? null,
45
+ now: state.now(),
46
+ });
47
+ },
48
+ getAgentRun: async (runId) => {
49
+ const { loadConsoleAgentRun } = await import("../console/server/ai-runs.ts");
50
+ const run = await loadConsoleAgentRun(
51
+ {
52
+ runtime: state.aiRuntime ?? null,
53
+ store: state.journalStore ?? null,
54
+ now: state.now(),
55
+ },
56
+ runId,
57
+ );
58
+ if (!run) return undefined;
59
+ return { run, events: run.events };
60
+ },
61
+ listApprovals: async () => {
62
+ const { loadApprovalQueue } = await import("../console/server/ai-runs.ts");
63
+ return loadApprovalQueue(state.journalStore ?? null, state.now());
64
+ },
65
+ listDecisions: async (tenant) => {
66
+ const { loadDecisionQueue, projectMcpDecisions, candidateMetrics } =
67
+ await import("../console/server/decisions.ts");
68
+ const { listDecisionCandidates, loadDecisionCandidate } =
69
+ await import("../elements/ai/decisions/labels.ts");
70
+ const names = await listDecisionCandidates();
71
+ const fitted: Record<string, Record<string, number>> = {};
72
+ for (const name of names) {
73
+ const metrics = candidateMetrics(await loadDecisionCandidate(name));
74
+ if (metrics) fitted[name] = metrics;
75
+ }
76
+ const queue = await loadDecisionQueue(state.journalStore ?? null, state.now(), tenant);
77
+ const pending: Record<string, number> = {};
78
+ for (const row of queue) {
79
+ if (row.status !== "pending" || row.labelOnly) continue;
80
+ pending[row.decision] = (pending[row.decision] ?? 0) + 1;
81
+ }
82
+ return projectMcpDecisions(state.manifest, pending, fitted);
83
+ },
36
84
  proposeStructural: async (input) =>
37
85
  emitStructuralDiff({
38
86
  cwd: state.cwd,
@@ -550,7 +550,41 @@ export const OKE_COMMANDS: readonly CliCommand[] = [
550
550
  name: "eval",
551
551
  summary: "prompt eval sets (CI gate)",
552
552
  leaf: true,
553
- flags: [MANIFEST, HELP],
553
+ flags: [
554
+ MANIFEST,
555
+ {
556
+ long: "--certify",
557
+ takesValue: false,
558
+ summary: "Build a decision certificate from the seed file",
559
+ },
560
+ HELP,
561
+ ],
562
+ },
563
+ {
564
+ name: "decide",
565
+ summary: "promote a decision certificate",
566
+ subcommands: [
567
+ {
568
+ name: "promote",
569
+ summary: "Fetch the operator candidate and write the app lockfile",
570
+ positionals: "<name>",
571
+ flags: [
572
+ {
573
+ long: "--origin",
574
+ takesValue: true,
575
+ valueName: "url",
576
+ summary: "App origin that serves the candidate",
577
+ },
578
+ {
579
+ long: "--lock",
580
+ takesValue: true,
581
+ valueName: "path",
582
+ summary: "Lockfile path (default oke-decisions.lock.json)",
583
+ },
584
+ HELP,
585
+ ],
586
+ },
587
+ ],
554
588
  },
555
589
  {
556
590
  name: "ai",
@@ -282,6 +282,29 @@ describe("oke vault audit", () => {
282
282
  await h.close();
283
283
  }
284
284
  });
285
+
286
+ test("audit verify refuses a webhook sink", async () => {
287
+ const sql = createMemoryVaultSql();
288
+ const errors: string[] = [];
289
+ const original = console.error;
290
+ console.error = (...args: unknown[]) => {
291
+ errors.push(args.map((part) => String(part)).join(" "));
292
+ };
293
+ try {
294
+ const code = await vaultCli(["audit", "verify"], {
295
+ sql,
296
+ env: {},
297
+ stdinIsTTY: false,
298
+ audit: { sink: "webhook", webhookUrl: "https://audit.example/hook" },
299
+ write: () => undefined,
300
+ });
301
+ expect(code).toBe(1);
302
+ expect(errors.join("\n")).toContain('audit.sink "db"');
303
+ } finally {
304
+ console.error = original;
305
+ await sql.close();
306
+ }
307
+ });
285
308
  });
286
309
 
287
310
  describe("oke vault backup / restore", () => {
@@ -24,6 +24,7 @@ import type { SqlConnection } from "../drivers/types.ts";
24
24
  import { openBuiltinVaultAdapter, VAULT_MASTER_KEY_ENV } from "../drivers/vault-builtin.ts";
25
25
  import { parseDotenv, formatDotenv } from "../drivers/vault-dotenv-parse.ts";
26
26
  import type { BuiltinVaultAdapter } from "../elements/vault/builtin-adapter.ts";
27
+ import type { VaultAuditConfig } from "../elements/vault/types.ts";
27
28
  import { promptHidden, readStdinSecure } from "./vault-secure-input.ts";
28
29
 
29
30
  /** Env var for the *new* master key when resuming an interrupted `rotate-master`. */
@@ -70,6 +71,11 @@ export interface VaultCmdOptions {
70
71
  * closes a connection it did not open.
71
72
  */
72
73
  readonly sql?: SqlConnection;
74
+ /**
75
+ * `vault.audit` from `oke.config.ts`. The `oke` binary loads this; tests
76
+ * pass it directly. Omitted means the SQL hash chain.
77
+ */
78
+ readonly audit?: VaultAuditConfig;
73
79
  }
74
80
 
75
81
  /**
@@ -332,6 +338,7 @@ async function withVault<T>(
332
338
  masterKey,
333
339
  ...(flags.url === undefined ? {} : { url: flags.url }),
334
340
  ...(options.sql === undefined ? {} : { connection: options.sql }),
341
+ ...(options.audit === undefined ? {} : { audit: options.audit }),
335
342
  });
336
343
  try {
337
344
  return await run(opened.adapter);