okengine 0.22.0 → 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.
- package/AGENTS.md +7 -0
- package/manifest.v1.schema.json +44 -0
- package/package.json +32 -19
- package/site/content/docs/ai/mcp.mdx +13 -9
- package/site/content/docs/ai/skills.mdx +1 -1
- package/site/content/docs/elements/ai/agents.mdx +61 -13
- package/site/content/docs/elements/ai/decide.mdx +536 -0
- package/site/content/docs/elements/ai/events.mdx +373 -0
- package/site/content/docs/elements/ai/index.mdx +9 -3
- package/site/content/docs/elements/ai/meta.json +1 -1
- package/site/content/docs/elements/ai/prompts.mdx +4 -2
- package/site/content/docs/elements/gate/auth.mdx +4 -1
- package/site/content/docs/elements/store/index.mdx +1 -1
- package/site/content/docs/elements/store/kv.mdx +5 -5
- package/site/content/docs/recipes/dragonfly.mdx +5 -5
- package/site/content/docs/recipes/index.mdx +6 -6
- package/site/content/docs/recipes/postgres.mdx +12 -8
- package/site/content/docs/recipes/redis.mdx +4 -4
- package/site/content/docs/reference/cli.mdx +2 -1
- package/site/content/docs/reference/configuration.mdx +9 -7
- package/site/content/docs/reference/fx.mdx +7 -6
- package/src/auth/api-key-sql.test.ts +44 -0
- package/src/auth/api-key-sql.ts +1 -0
- package/src/auth/api-keys.ts +30 -12
- package/src/auth/config.ts +6 -2
- package/src/auth/gate-auth.test.ts +20 -0
- package/src/cli/agents-md.test.ts +25 -0
- package/src/cli/ask-vault-gaps.test.ts +38 -1
- package/src/cli/ask-vault-gaps.ts +35 -2
- package/src/cli/decide.ts +174 -0
- package/src/cli/decision-lock-watch.test.ts +45 -0
- package/src/cli/decision-lock-watch.ts +51 -0
- package/src/cli/dev-app-runner.ts +34 -8
- package/src/cli/dev-auth-secret.test.ts +49 -0
- package/src/cli/dev-auth-secret.ts +49 -0
- package/src/cli/dev-hot.test.ts +41 -0
- package/src/cli/dev-hot.ts +48 -0
- package/src/cli/dev.test.ts +1 -1
- package/src/cli/dev.ts +24 -6
- package/src/cli/eval.ts +142 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/load-config.images.test.ts +2 -2
- package/src/cli/load-config.ts +1 -1
- package/src/cli/mcp-from-console.ts +48 -0
- package/src/cli/registry.ts +35 -1
- package/src/client/agent.ts +307 -0
- package/src/client/transport.test.ts +20 -0
- package/src/client/transport.ts +2 -1
- package/src/client/types.ts +1 -1
- package/src/client-react/index.ts +7 -1
- package/src/client-react/use-agent-run.test.ts +271 -0
- package/src/client-react/use-agent-run.ts +193 -0
- package/src/compiler/ai-approval.test.ts +36 -0
- package/src/compiler/ai-repair.test.ts +22 -0
- package/src/compiler/decisions.extract.test.ts +164 -0
- package/src/compiler/effects-infer.ts +27 -1
- package/src/compiler/extract.ts +268 -12
- package/src/compiler/response.ts +35 -2
- package/src/config/index.ts +21 -3
- package/src/console/server/ai-runs-flows.ts +269 -0
- package/src/console/server/ai-runs.test.ts +323 -0
- package/src/console/server/ai-runs.ts +562 -0
- package/src/console/server/ai.ts +12 -1
- package/src/console/server/app.ts +10 -1
- package/src/console/server/decisions-flows.ts +157 -0
- package/src/console/server/decisions.test.ts +66 -0
- package/src/console/server/decisions.ts +229 -0
- package/src/console/server/flows.ts +50 -2
- package/src/console/server/invoke-user-flow.ts +9 -0
- package/src/console/server/runs-ingest.ts +16 -0
- package/src/console/server/serve.ts +5 -0
- package/src/console/server/state.ts +25 -1
- package/src/console/server/store-stats.test.ts +47 -0
- package/src/console/server/store-stats.ts +92 -18
- package/src/console/ui-next/dist/assets/access-page-DDKkhT9v.js +4 -0
- package/src/console/ui-next/dist/assets/{agent-disclosure-Bkohc_8X.js → agent-disclosure-62Xts8Xi.js} +1 -1
- package/src/console/ui-next/dist/assets/{cache-glyph-rL0lHxat.js → cache-glyph-DyeoKHKA.js} +1 -1
- package/src/console/ui-next/dist/assets/{call-pii-button-Deo4PP18.js → call-pii-button-DvfpLXsU.js} +1 -1
- package/src/console/ui-next/dist/assets/{collapsible-CoJ6amHf.js → collapsible-BY03SeCg.js} +1 -1
- package/src/console/ui-next/dist/assets/confirm-sheet-DZfuJXP4.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-BTjPVjRT.js +1 -0
- package/src/console/ui-next/dist/assets/decisions-page-CgkKlA56.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-Dk5LipF6.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-CRGrj5JU.js +1 -0
- package/src/console/ui-next/dist/assets/duration-tone-Y6HLjyJ5.js +9 -0
- package/src/console/ui-next/dist/assets/element-icons-C6t8Vlml.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-chrome-Dslh2yE8.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-CIVg7Jgb.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-DLPfNy-_.js +1 -0
- package/src/console/ui-next/dist/assets/{highlighted-json-CPYBzDh0.js → highlighted-json-D7nNzpgB.js} +1 -1
- package/src/console/ui-next/dist/assets/{http-method-DTPevKmM.js → http-method-DdL19zzh.js} +1 -1
- package/src/console/ui-next/dist/assets/index-BlrN49Hs.css +2 -0
- package/src/console/ui-next/dist/assets/index-C0lc_s9d.js +58 -0
- package/src/console/ui-next/dist/assets/observability-page-CRlcyLCC.js +8 -0
- package/src/console/ui-next/dist/assets/{replica-lag-BM27lXld.js → replica-lag-Bb3FWUu9.js} +7 -7
- package/src/console/ui-next/dist/assets/request-meta-DYBMWhX8.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-DTE1sjTC.js +1 -0
- package/src/console/ui-next/dist/assets/store-page-CcE-SXC8.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CKMSEQ4s.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-QOfk0M0H.js +55 -0
- package/src/console/ui-next/dist/assets/units-page-DKC1CDDd.js +1 -0
- package/src/console/ui-next/dist/assets/use-vault-list-BAyQG8Re.js +1 -0
- package/src/console/ui-next/dist/assets/vault-page-B54v4Yit.js +2 -0
- package/src/console/ui-next/dist/index.html +4 -3
- package/src/console/ui-next/seed-parked-approval.ts +126 -0
- package/src/console/ui-next/src/client.ts +224 -1
- package/src/console/ui-next/src/components/explorer/detail-header.tsx +9 -0
- package/src/console/ui-next/src/components/explorer/explorer-start-toggle.tsx +5 -1
- package/src/console/ui-next/src/components/ui/sheet-form.tsx +21 -12
- package/src/console/ui-next/src/features/flows/decisions/decisions-page.tsx +216 -0
- package/src/console/ui-next/src/features/flows/decisions/resolve.test.ts +48 -0
- package/src/console/ui-next/src/features/flows/decisions/resolve.ts +111 -0
- package/src/console/ui-next/src/features/flows/flows-page.tsx +10 -0
- package/src/console/ui-next/src/features/flows/graph/element-map.ts +1 -0
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +6 -0
- package/src/console/ui-next/src/features/flows/traces/effect-summary.test.ts +24 -0
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +24 -0
- package/src/console/ui-next/src/features/flows/traces/http-status.ts +58 -0
- package/src/console/ui-next/src/features/flows/traces/request-client-card.tsx +355 -0
- package/src/console/ui-next/src/features/flows/traces/request-client.test.ts +114 -0
- package/src/console/ui-next/src/features/flows/traces/request-client.ts +423 -0
- package/src/console/ui-next/src/features/flows/traces/request-input-view.test.ts +52 -6
- package/src/console/ui-next/src/features/flows/traces/request-input-view.ts +85 -19
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +505 -80
- package/src/console/ui-next/src/features/flows/traces/trace-lanes.test.ts +61 -0
- package/src/console/ui-next/src/features/flows/traces/trace-lanes.ts +78 -0
- package/src/console/ui-next/src/features/flows/traces/trace-nav.test.ts +48 -0
- package/src/console/ui-next/src/features/flows/traces/trace-nav.ts +57 -0
- package/src/console/ui-next/src/features/flows/traces/trace-request-section.tsx +275 -96
- package/src/console/ui-next/src/features/flows/traces/traces-pane.tsx +16 -2
- package/src/console/ui-next/src/features/observability/detail/ai-runs.tsx +369 -0
- package/src/console/ui-next/src/features/observability/observability-page.tsx +31 -1
- package/src/console/ui-next/src/features/observability/state/observability-selection.ts +18 -3
- package/src/console/ui-next/src/features/store/performance/kv-performance-panel.tsx +12 -1
- package/src/console/ui-next/src/features/store/performance/performance-panel.tsx +14 -1
- package/src/console/ui-next/src/features/units/call/call-api-panel.tsx +1 -1
- package/src/console/ui-next/src/features/units/detail/flow-contract-panel.tsx +6 -2
- package/src/console/ui-next/src/features/units/explorer/units-tree.tsx +73 -18
- package/src/console/ui-next/src/features/units/lib/unit-tree.test.ts +21 -0
- package/src/console/ui-next/src/features/units/lib/unit-tree.ts +82 -0
- package/src/console/ui-next/src/features/units/units-page.tsx +25 -7
- package/src/console/ui-next/src/router.tsx +17 -0
- package/src/console/ui-next/ui-next-seed-runs.ts +23 -0
- package/src/console/ui-next/vite-console-kernel-plugin.ts +43 -3
- package/src/console/ui-next/vite.config.ts +9 -0
- package/src/docker/recipes/dragonfly.ts +3 -2
- package/src/docker/recipes/redis.ts +1 -1
- package/src/drivers/ai-anthropic.ts +212 -21
- package/src/drivers/ai-mock.ts +34 -1
- package/src/drivers/ai-openai-compatible.ts +67 -26
- package/src/drivers/ai-preconnect.ts +18 -0
- package/src/drivers/ai-stream.test.ts +62 -0
- package/src/drivers/ai-types.ts +20 -0
- package/src/drivers/journal-postgres.ts +289 -2
- package/src/drivers/memory-ddl.test.ts +18 -0
- package/src/drivers/memory.ts +21 -1
- package/src/drivers/pg-rls.test.ts +31 -0
- package/src/drivers/pg-rls.ts +15 -0
- package/src/drivers/postgres.test.ts +9 -0
- package/src/drivers/postgres.ts +49 -11
- package/src/elements/ai/agent-event-slot.ts +27 -0
- package/src/elements/ai/approval-http.ts +207 -0
- package/src/elements/ai/approval.test.ts +741 -0
- package/src/elements/ai/approval.ts +228 -0
- package/src/elements/ai/decisions/bind.ts +163 -0
- package/src/elements/ai/decisions/certificate.test.ts +291 -0
- package/src/elements/ai/decisions/certificate.ts +377 -0
- package/src/elements/ai/decisions/certify.ts +314 -0
- package/src/elements/ai/decisions/decide.test.ts +953 -0
- package/src/elements/ai/decisions/e2e.test.ts +399 -0
- package/src/elements/ai/decisions/export.test.ts +120 -0
- package/src/elements/ai/decisions/export.ts +146 -0
- package/src/elements/ai/decisions/fixtures/openrouter-request.json +24 -0
- package/src/elements/ai/decisions/fixtures/openrouter-response.json +22 -0
- package/src/elements/ai/decisions/fixtures/typesafe-request.json +19 -0
- package/src/elements/ai/decisions/fixtures/typesafe-response.json +13 -0
- package/src/elements/ai/decisions/http.test.ts +154 -0
- package/src/elements/ai/decisions/http.ts +240 -0
- package/src/elements/ai/decisions/labels.test.ts +282 -0
- package/src/elements/ai/decisions/labels.ts +257 -0
- package/src/elements/ai/decisions/openrouter.live.test.ts +136 -0
- package/src/elements/ai/decisions/openrouter.ts +36 -0
- package/src/elements/ai/decisions/provider.ts +102 -0
- package/src/elements/ai/decisions/typesafe.ts +36 -0
- package/src/elements/ai/declare.ts +252 -1
- package/src/elements/ai/events.test.ts +379 -0
- package/src/elements/ai/events.ts +138 -0
- package/src/elements/ai/run-events.test.ts +461 -0
- package/src/elements/ai/run-events.ts +522 -0
- package/src/elements/ai/runtime.ts +1186 -105
- package/src/elements/ai/stream-turn.ts +214 -0
- package/src/elements/ai/stream.live.test.ts +76 -0
- package/src/elements/ai/subagent.test.ts +136 -0
- package/src/elements/ai.test.ts +497 -3
- package/src/elements/ai.ts +16 -1
- package/src/elements/clock/durable.ts +27 -1
- package/src/elements/store/sql-session.test.ts +51 -0
- package/src/elements/store/sql-session.ts +111 -1
- package/src/i18n/catalogs/ar.ts +5 -0
- package/src/i18n/catalogs/en.ts +5 -0
- package/src/index.ts +2 -0
- package/src/kernel/agent-event-store.ts +448 -0
- package/src/kernel/app.ts +103 -1
- package/src/kernel/boot-bind/ai.ts +3 -0
- package/src/kernel/boot-bind/store.test.ts +26 -0
- package/src/kernel/boot-bind/store.ts +82 -6
- package/src/kernel/boot.ts +15 -4
- package/src/kernel/builtin-errors.ts +2 -0
- package/src/kernel/capability.ts +3 -0
- package/src/kernel/decision-label-store.ts +441 -0
- package/src/kernel/effects.test.ts +2 -1
- package/src/kernel/effects.ts +13 -1
- package/src/kernel/element-registries.ts +3 -0
- package/src/kernel/errors-text.ts +4 -0
- package/src/kernel/errors.ts +2 -0
- package/src/kernel/flow.test.ts +2 -3
- package/src/kernel/fx-decide.ts +761 -0
- package/src/kernel/fx.test.ts +12 -5
- package/src/kernel/fx.ts +312 -29
- package/src/kernel/http-frame.test.ts +94 -0
- package/src/kernel/http-frame.ts +203 -0
- package/src/kernel/journal.ts +104 -0
- package/src/kernel/json-result.ts +10 -0
- package/src/kernel/pipeline.test.ts +45 -0
- package/src/kernel/sse-id.ts +32 -0
- package/src/manifest/diff.ts +1 -0
- package/src/manifest/types.ts +29 -2
- package/src/mcp/ai-tools.test.ts +202 -0
- package/src/mcp/authorization.ts +66 -0
- package/src/mcp/session.ts +3 -0
- package/src/mcp/tools.ts +168 -0
- package/src/release/http-graph.test.ts +2 -0
- package/src/release/http-graph.ts +5 -0
- package/src/release/measure.ts +39 -14
- package/src/runs/collect.ts +4 -1
- package/src/runs/parquet.test.ts +27 -1
- package/src/runs/parquet.ts +19 -0
- package/src/runs/types.ts +31 -0
- package/src/runtime/json-code-block.test.ts +106 -47
- package/src/runtime/json-code-block.ts +1209 -46
- package/src/term.test.ts +13 -0
- package/src/term.ts +81 -49
- package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +0 -1
- package/src/console/ui-next/dist/assets/access-page-Ze6ckjdd.js +0 -4
- package/src/console/ui-next/dist/assets/copy-inline-button-CWG5_ZOh.js +0 -1
- package/src/console/ui-next/dist/assets/detail-header-b_ZzIsmU.js +0 -1
- package/src/console/ui-next/dist/assets/dropdown-menu-nwXEO1Ac.js +0 -1
- package/src/console/ui-next/dist/assets/duration-tone-BbQ_8z50.js +0 -9
- package/src/console/ui-next/dist/assets/element-icons-CwyLpVXz.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-C8sSCqYT.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-D2E7BtKK.js +0 -1
- package/src/console/ui-next/dist/assets/index-VxoEz295.css +0 -2
- package/src/console/ui-next/dist/assets/index-vTuwmeQz.js +0 -58
- package/src/console/ui-next/dist/assets/observability-page-SJTSzHFJ.js +0 -4
- package/src/console/ui-next/dist/assets/request-meta-BjFT7DNl.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-CUNegEV4.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-Qj9ThRE-.js +0 -41
- package/src/console/ui-next/dist/assets/trace-detail-sheet-Cmitq3da.js +0 -2
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CbDIB-7x.js +0 -55
- package/src/console/ui-next/dist/assets/units-page-_PuYqFty.js +0 -1
- package/src/console/ui-next/dist/assets/use-vault-list-Cs45Czkt.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-BOMr0go9.js +0 -2
package/src/kernel/app.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* pipeline, and wires `fx.call` to untriggered (and triggered) flows.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { bindAgentApprovalFlows } from "../elements/ai/approval-http.ts";
|
|
9
10
|
import { compileRoute } from "../compiler/dynamic.ts";
|
|
10
11
|
import type { CompiledRoute } from "../compiler/aot.ts";
|
|
11
12
|
import { encodeExecuteResult, encodeFailure } from "../compiler/response.ts";
|
|
@@ -67,6 +68,7 @@ import {
|
|
|
67
68
|
import { GATE_PUBLIC_NAME } from "../elements/gate/flatten.ts";
|
|
68
69
|
import type { JsonCodeAuth } from "../runtime/json-code-block.ts";
|
|
69
70
|
import { resolveDurationMs } from "./elapsed.ts";
|
|
71
|
+
import { captureHttpFrame } from "./http-frame.ts";
|
|
70
72
|
import { fail, throwOke, OkeError } from "./errors.ts";
|
|
71
73
|
import { FLOW_NAME_DUPLICATE, FLOW_UNNAMED } from "./errors-flow-name.ts";
|
|
72
74
|
import { ONCE_SIGNAL_MULTI_FLOW } from "./errors-once-signal.ts";
|
|
@@ -217,6 +219,39 @@ function loadClientDescriptor(): typeof import("./client-descriptor.ts") {
|
|
|
217
219
|
return lazyRequire(import.meta.dir, ["client", "descriptor"].join("-"));
|
|
218
220
|
}
|
|
219
221
|
|
|
222
|
+
/** Decision HTTP flows. A static `import()` still lands on every HTTP bundle. */
|
|
223
|
+
function loadDecisionBind(): typeof import("../elements/ai/decisions/bind.ts") {
|
|
224
|
+
return lazyRequire(`${import.meta.dir}/../elements/ai/decisions`, ["bi", "nd"].join(""));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Decision lockfile. Loaded only when the manifest declares decisions. */
|
|
228
|
+
function loadDecisionCertificate(): typeof import("../elements/ai/decisions/certificate.ts") {
|
|
229
|
+
return lazyRequire(`${import.meta.dir}/../elements/ai/decisions`, ["certificate"].join(""));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Decision label opener. Loaded only when the manifest declares decisions. */
|
|
233
|
+
function loadDecisionLabels(): typeof import("../elements/ai/decisions/labels.ts") {
|
|
234
|
+
return lazyRequire(`${import.meta.dir}/../elements/ai/decisions`, ["lab", "els"].join(""));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Drift-flag registration. Loaded only when the manifest declares decisions. */
|
|
238
|
+
function loadDecisionLabelStore(): typeof import("./decision-label-store.ts") {
|
|
239
|
+
return lazyRequire(import.meta.dir, ["decision", "label", "store"].join("-"));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** `fx.decide` gate hook. Loaded only when the manifest declares decisions. */
|
|
243
|
+
function loadFxDecideModule(): typeof import("./fx-decide.ts") {
|
|
244
|
+
return lazyRequire(import.meta.dir, ["fx", "decide"].join("-"));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Full boot graph (drivers, elements). A static `import()` string is still
|
|
249
|
+
* bundled into every HTTP app; the stem stays computed.
|
|
250
|
+
*/
|
|
251
|
+
function loadBoot(): typeof import("./boot.ts") {
|
|
252
|
+
return lazyRequire(import.meta.dir, ["bo", "ot"].join(""));
|
|
253
|
+
}
|
|
254
|
+
|
|
220
255
|
/** Options for {@link oke}. */
|
|
221
256
|
export interface OkeOptions {
|
|
222
257
|
/** Application name (Manifest `app`). */
|
|
@@ -1095,6 +1130,8 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1095
1130
|
// contribute auth-method Bindings before traffic (plan Phase 2).
|
|
1096
1131
|
const router: Router<Binding> = smart;
|
|
1097
1132
|
|
|
1133
|
+
bindAgentApprovalFlows(adoptBinding);
|
|
1134
|
+
|
|
1098
1135
|
function adoptBinding(b: Binding): void {
|
|
1099
1136
|
adopted.push(b);
|
|
1100
1137
|
registerFlow(b.flow);
|
|
@@ -1115,6 +1152,24 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1115
1152
|
|
|
1116
1153
|
/** Once-per-app: system `_oke_search_embed_*` CDC bindings from Manifest. */
|
|
1117
1154
|
let searchEmbedFlowsBound = false;
|
|
1155
|
+
let decisionFlowsBound = false;
|
|
1156
|
+
|
|
1157
|
+
/**
|
|
1158
|
+
* Register the decision aggregate, drift monitor, and candidate route
|
|
1159
|
+
* when any decision declares autonomy.
|
|
1160
|
+
*
|
|
1161
|
+
* @param manifest - Boot manifest
|
|
1162
|
+
*/
|
|
1163
|
+
async function ensureDecisionFlows(manifest: BootOptions["manifest"] | undefined): Promise<void> {
|
|
1164
|
+
if (decisionFlowsBound || !manifest) return;
|
|
1165
|
+
const { bindDecisionFlows, manifestHasDecisionAutonomy } = loadDecisionBind();
|
|
1166
|
+
if (!manifestHasDecisionAutonomy(manifest)) {
|
|
1167
|
+
decisionFlowsBound = true;
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
bindDecisionFlows(adoptBinding, manifest);
|
|
1171
|
+
decisionFlowsBound = true;
|
|
1172
|
+
}
|
|
1118
1173
|
/**
|
|
1119
1174
|
* Auto-register hybrid-search embed CDC flows when any `.embed()` column
|
|
1120
1175
|
* exists. Lazy-loads search-bind so edge graphs without search stay lean.
|
|
@@ -1339,6 +1394,19 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1339
1394
|
...durableResumeFx(),
|
|
1340
1395
|
...(gateConfig.auth?.tenant ? (loadAppTenant().w(5, gateConfig.auth) as object) : {}),
|
|
1341
1396
|
...(existing?.tenant ? { tenant: { id: existing.tenant } } : {}),
|
|
1397
|
+
callHandler: async (name, callInput) => {
|
|
1398
|
+
const target = flowsByName.get(name);
|
|
1399
|
+
if (!target) return undefined;
|
|
1400
|
+
const inner = await execute(
|
|
1401
|
+
target,
|
|
1402
|
+
callInput,
|
|
1403
|
+
{ kind: "internal" } satisfies InternalTrigger,
|
|
1404
|
+
{ parentId: runId },
|
|
1405
|
+
);
|
|
1406
|
+
if (inner.failure) return inner.failure;
|
|
1407
|
+
if (inner.ctx.error !== undefined) throw inner.ctx.error;
|
|
1408
|
+
return inner.output;
|
|
1409
|
+
},
|
|
1342
1410
|
},
|
|
1343
1411
|
});
|
|
1344
1412
|
} catch (err) {
|
|
@@ -1367,7 +1435,7 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1367
1435
|
}
|
|
1368
1436
|
|
|
1369
1437
|
async function doBoot(overrides?: Partial<BootOptions>): Promise<BootResult> {
|
|
1370
|
-
const { bootApplication, resolveElementNeeds } =
|
|
1438
|
+
const { bootApplication, resolveElementNeeds } = loadBoot();
|
|
1371
1439
|
const { assertHttpGatePosture } = await import("../elements/gate/boot.ts");
|
|
1372
1440
|
const { assertPluginNeeds, buildAvailableNeedTokens } = await import("./plugin-needs.ts");
|
|
1373
1441
|
const dockerFlag =
|
|
@@ -1388,6 +1456,7 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1388
1456
|
}
|
|
1389
1457
|
|
|
1390
1458
|
const unguardedHttp = overrides?.unguardedHttp ?? gateConfig.unguardedHttp ?? "deny";
|
|
1459
|
+
await ensureDecisionFlows(overrides?.manifest ?? options.manifest);
|
|
1391
1460
|
// Auth bindings are in `adopted` — missing posture fails with GateBootError.
|
|
1392
1461
|
assertHttpGatePosture(adopted, { unguardedHttp, env: bootEnv });
|
|
1393
1462
|
|
|
@@ -1557,6 +1626,26 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
1557
1626
|
// Built-in hybrid search — auto-register durable embed CDC flows when the
|
|
1558
1627
|
// Manifest declares any `.embed()` column (writer flows stay embed-free).
|
|
1559
1628
|
await ensureSearchEmbedFlows(overrides?.manifest ?? options.manifest);
|
|
1629
|
+
const decisionManifest = overrides?.manifest ?? options.manifest;
|
|
1630
|
+
const declaredDecisions = decisionManifest?.ai?.decisions;
|
|
1631
|
+
if (declaredDecisions && Object.keys(declaredDecisions).length > 0) {
|
|
1632
|
+
const { loadDecisionLockfile, setDecisionDrift } = loadDecisionCertificate();
|
|
1633
|
+
const { openDecisionLabelStore } = loadDecisionLabels();
|
|
1634
|
+
const { setDeclaredDriftDecisions } = loadDecisionLabelStore();
|
|
1635
|
+
const { setDecisionGateAllow } = loadFxDecideModule();
|
|
1636
|
+
const root = overrides?.rootDir ?? options.rootDir ?? process.env["OKE_ROOT_DIR"];
|
|
1637
|
+
if (!root) {
|
|
1638
|
+
throw new Error(
|
|
1639
|
+
"oke boot: decisions are declared but rootDir and OKE_ROOT_DIR are unset, so the decision lockfile cannot load.",
|
|
1640
|
+
);
|
|
1641
|
+
}
|
|
1642
|
+
await loadDecisionLockfile(root);
|
|
1643
|
+
setDeclaredDriftDecisions(Object.keys(declaredDecisions));
|
|
1644
|
+
if (result.journal && result.journal.store.decisions) {
|
|
1645
|
+
await openDecisionLabelStore(result.journal.store, setDecisionDrift);
|
|
1646
|
+
}
|
|
1647
|
+
if (result.gate) setDecisionGateAllow((names, ctx) => result.gate!.allow(names, ctx));
|
|
1648
|
+
}
|
|
1560
1649
|
// otp() provider / app mode capability — fail loud at boot, never silent downgrade.
|
|
1561
1650
|
if (result.channel) {
|
|
1562
1651
|
const { assertOtpPluginCapability } = await import("../auth/otp-capability.ts");
|
|
@@ -2257,6 +2346,14 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
2257
2346
|
: durationMs;
|
|
2258
2347
|
if (journalSession) {
|
|
2259
2348
|
inflightRuns.delete(journalSession.runId);
|
|
2349
|
+
const parked = streamOut?.parked;
|
|
2350
|
+
if (parked) {
|
|
2351
|
+
ctx.state.sleeping = {
|
|
2352
|
+
wakeAt: parked.wakeAt,
|
|
2353
|
+
label: parked.label,
|
|
2354
|
+
runId: journalSession.runId,
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2260
2357
|
const sleeping = ctx.state.sleeping as
|
|
2261
2358
|
| { readonly wakeAt: number; readonly label: string; readonly runId: string }
|
|
2262
2359
|
| undefined;
|
|
@@ -2277,6 +2374,8 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
2277
2374
|
fx,
|
|
2278
2375
|
error: terminalErr,
|
|
2279
2376
|
});
|
|
2377
|
+
} else if (parked && sleeping) {
|
|
2378
|
+
await journalSession.commit("sleeping", { wakeAt: sleeping.wakeAt });
|
|
2280
2379
|
} else if (!sleeping) {
|
|
2281
2380
|
await journalSession.commit("completed", {
|
|
2282
2381
|
output: streamOut ? { streamed: true } : result.output,
|
|
@@ -2309,6 +2408,9 @@ export function oke(options: OkeOptions): OkeApp {
|
|
|
2309
2408
|
? { output: streamOut ? { streamed: true } : result.output }
|
|
2310
2409
|
: {}),
|
|
2311
2410
|
...(parentId !== undefined ? { parentId } : {}),
|
|
2411
|
+
...(trigger.kind === "http" && extras?.request
|
|
2412
|
+
? { http: captureHttpFrame(extras.request, result.response) }
|
|
2413
|
+
: {}),
|
|
2312
2414
|
},
|
|
2313
2415
|
archiveCleartext,
|
|
2314
2416
|
);
|
|
@@ -14,6 +14,7 @@ import type { AiDriver, AiOpenOptions } from "../../drivers/ai-types.ts";
|
|
|
14
14
|
import { createAiRuntime, type AiRuntime } from "../../elements/ai.ts";
|
|
15
15
|
import type { GateRuntime } from "../../elements/gate.ts";
|
|
16
16
|
import type { VaultRuntime } from "../../elements/vault.ts";
|
|
17
|
+
import type { JournalStore } from "../journal.ts";
|
|
17
18
|
import type { BootOptions } from "../boot.ts";
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -33,6 +34,7 @@ export function bindAi(
|
|
|
33
34
|
env: ConfigEnv = "test",
|
|
34
35
|
docker = false,
|
|
35
36
|
vault?: VaultRuntime,
|
|
37
|
+
journalStore?: JournalStore,
|
|
36
38
|
): AiRuntime {
|
|
37
39
|
const id = resolveAiDriverId(options, env, docker);
|
|
38
40
|
const driver =
|
|
@@ -48,6 +50,7 @@ export function bindAi(
|
|
|
48
50
|
},
|
|
49
51
|
gates: options.ai?.gates ?? gate,
|
|
50
52
|
now,
|
|
53
|
+
...(journalStore ? { journalStore } : {}),
|
|
51
54
|
});
|
|
52
55
|
}
|
|
53
56
|
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
resolveIndexDriverId,
|
|
14
14
|
resolveKvDriverId,
|
|
15
15
|
resolveSqlDriverId,
|
|
16
|
+
sqlBindingForDecl,
|
|
16
17
|
} from "./store.ts";
|
|
17
18
|
|
|
18
19
|
describe("bindStore driver resolution", () => {
|
|
@@ -99,6 +100,31 @@ describe("bindStore driver resolution", () => {
|
|
|
99
100
|
});
|
|
100
101
|
});
|
|
101
102
|
|
|
103
|
+
describe("sqlBindingForDecl", () => {
|
|
104
|
+
test("pool.max and replica URLs land on the binding; min is ignored", () => {
|
|
105
|
+
const binding = sqlBindingForDecl("db", "postgres://primary/db", {
|
|
106
|
+
driver: "postgres",
|
|
107
|
+
pool: { max: 20, min: 2 },
|
|
108
|
+
replicas: ["postgres://ro-1/db", "postgres://ro-2/db"],
|
|
109
|
+
});
|
|
110
|
+
expect(binding).toEqual({
|
|
111
|
+
name: "db",
|
|
112
|
+
primary: { url: "postgres://primary/db", pool: { max: 20 } },
|
|
113
|
+
replicas: [
|
|
114
|
+
{ url: "postgres://ro-1/db", pool: { max: 20 } },
|
|
115
|
+
{ url: "postgres://ro-2/db", pool: { max: 20 } },
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("a string pin keeps the URL and omits pool and replicas", () => {
|
|
121
|
+
expect(sqlBindingForDecl("db", "memory://", "memory")).toEqual({
|
|
122
|
+
name: "db",
|
|
123
|
+
primary: { url: "memory://" },
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
102
128
|
describe("bindStore durable KV routing", () => {
|
|
103
129
|
const prev = {
|
|
104
130
|
redis: process.env.REDIS_URL,
|
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
* Lazy store binder — loaded only when Store is declared.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
driverRefId,
|
|
7
|
+
resolveDomainDdlMode,
|
|
8
|
+
resolveDriverId,
|
|
9
|
+
resolveDriverRef,
|
|
10
|
+
type ConfigEnv,
|
|
11
|
+
type DriverRef,
|
|
12
|
+
} from "../../config/index.ts";
|
|
6
13
|
import {
|
|
7
14
|
STORE_FILES_DEFAULTS,
|
|
8
15
|
STORE_KV_DEFAULTS,
|
|
@@ -18,6 +25,7 @@ import { redisDriver } from "../../drivers/redis.ts";
|
|
|
18
25
|
import { s3Driver } from "../../drivers/s3.ts";
|
|
19
26
|
import type { FilesDriver, IndexDriver, KvDriver, SqlDriver } from "../../drivers/types.ts";
|
|
20
27
|
import { createStoreRuntime, type StoreRuntime } from "../../elements/store.ts";
|
|
28
|
+
import type { SqlRuntimeBinding } from "../../elements/store/runtime.ts";
|
|
21
29
|
import type { StoreDecl } from "../../elements/store/declare.ts";
|
|
22
30
|
import { emitBootWarn } from "../../runtime/boot-warn.ts";
|
|
23
31
|
import type { BootOptions } from "../boot.ts"; // type-only — no cycle at runtime
|
|
@@ -129,17 +137,15 @@ export function bindStore(
|
|
|
129
137
|
warnKvMemoryDurable(durableKvDecls.map((d) => d.name));
|
|
130
138
|
}
|
|
131
139
|
|
|
132
|
-
const
|
|
140
|
+
const sqlRef = resolveSqlDriverRef(options, env, docker);
|
|
141
|
+
const sqlBindings: Record<string, SqlRuntimeBinding> = {};
|
|
133
142
|
const kvBindings: Record<string, { url?: string }> = {};
|
|
134
143
|
const filesBindings: Record<string, { root?: string }> = {};
|
|
135
144
|
const indexBindings: Record<string, { url?: string; apiKey?: string }> = {};
|
|
136
145
|
|
|
137
146
|
for (const decl of options.stores ?? []) {
|
|
138
147
|
if (isSqlDecl(decl)) {
|
|
139
|
-
sqlBindings[decl.name] =
|
|
140
|
-
name: decl.name,
|
|
141
|
-
primary: { url: sqlUrl },
|
|
142
|
-
};
|
|
148
|
+
sqlBindings[decl.name] = sqlBindingForDecl(decl.name, sqlUrl, sqlRef);
|
|
143
149
|
} else if (isKvDecl(decl)) {
|
|
144
150
|
if (decl.durable === true) {
|
|
145
151
|
kvBindings[decl.name] = {};
|
|
@@ -210,6 +216,76 @@ export function resolveSqlDriverId(options: BootOptions, env: ConfigEnv, docker:
|
|
|
210
216
|
return resolveDriverId(options.config?.drivers?.store?.sql, env, STORE_SQL_DEFAULTS)!;
|
|
211
217
|
}
|
|
212
218
|
|
|
219
|
+
/**
|
|
220
|
+
* Rich SQL driver ref for the active env. A docker `OKE_SQL_DRIVER` override
|
|
221
|
+
* that changes the protocol drops `pool` / `replicas` — those belong to the
|
|
222
|
+
* configured driver, not the override.
|
|
223
|
+
*
|
|
224
|
+
* @param options - Boot options
|
|
225
|
+
* @param env - Active environment
|
|
226
|
+
* @param docker - Docker mode
|
|
227
|
+
*/
|
|
228
|
+
function resolveSqlDriverRef(
|
|
229
|
+
options: BootOptions,
|
|
230
|
+
env: ConfigEnv,
|
|
231
|
+
docker: boolean,
|
|
232
|
+
): DriverRef | undefined {
|
|
233
|
+
const configured = resolveDriverRef(options.config?.drivers?.store?.sql, env, STORE_SQL_DEFAULTS);
|
|
234
|
+
const fromEnv = process.env.OKE_SQL_DRIVER?.trim();
|
|
235
|
+
if (docker && fromEnv && fromEnv !== driverRefId(configured)) return fromEnv;
|
|
236
|
+
return configured;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Primary URL plus documented `pool.max` and read-replica URLs.
|
|
241
|
+
*
|
|
242
|
+
* `pool.min` is ignored — Bun.SQL has no minimum pool size. Unset `max`
|
|
243
|
+
* leaves pool sizing to the postgres driver default of 8.
|
|
244
|
+
*
|
|
245
|
+
* @param name - Store declaration name
|
|
246
|
+
* @param url - Primary connection URL
|
|
247
|
+
* @param ref - Active driver pin (string or rich object)
|
|
248
|
+
*/
|
|
249
|
+
export function sqlBindingForDecl(
|
|
250
|
+
name: string,
|
|
251
|
+
url: string,
|
|
252
|
+
ref: DriverRef | undefined,
|
|
253
|
+
): SqlRuntimeBinding {
|
|
254
|
+
const max = driverPoolMax(ref);
|
|
255
|
+
const pool = max !== undefined ? { pool: { max } } : {};
|
|
256
|
+
const replicas = driverReplicaUrls(ref).map((replicaUrl) => ({
|
|
257
|
+
url: replicaUrl,
|
|
258
|
+
...pool,
|
|
259
|
+
}));
|
|
260
|
+
return {
|
|
261
|
+
name,
|
|
262
|
+
primary: { url, ...pool },
|
|
263
|
+
...(replicas.length > 0 ? { replicas } : {}),
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Positive finite `pool.max` from a rich driver ref.
|
|
269
|
+
*
|
|
270
|
+
* @param ref - Driver pin
|
|
271
|
+
*/
|
|
272
|
+
function driverPoolMax(ref: DriverRef | undefined): number | undefined {
|
|
273
|
+
if (ref === undefined || typeof ref === "string") return undefined;
|
|
274
|
+
const max = ref.pool?.max;
|
|
275
|
+
if (typeof max !== "number" || !Number.isFinite(max) || max < 1) return undefined;
|
|
276
|
+
return Math.floor(max);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Replica connection strings from a rich driver ref. Non-strings are dropped.
|
|
281
|
+
*
|
|
282
|
+
* @param ref - Driver pin
|
|
283
|
+
*/
|
|
284
|
+
function driverReplicaUrls(ref: DriverRef | undefined): readonly string[] {
|
|
285
|
+
if (ref === undefined || typeof ref === "string" || ref.replicas === undefined) return [];
|
|
286
|
+
return ref.replicas.filter((item): item is string => typeof item === "string" && item.length > 0);
|
|
287
|
+
}
|
|
288
|
+
|
|
213
289
|
/**
|
|
214
290
|
* @param options - Boot options
|
|
215
291
|
* @param env - Active env
|
package/src/kernel/boot.ts
CHANGED
|
@@ -282,9 +282,14 @@ export function resolveElementNeeds(options: BootOptions): ElementNeeds {
|
|
|
282
282
|
const considerFlow = (f: AnyFlowDef): void => {
|
|
283
283
|
const e = f.effects;
|
|
284
284
|
if (f.durable === true) journal = true;
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
285
|
+
const touchesStore = [...(e?.reads ?? []), ...(e?.writes ?? [])].some(
|
|
286
|
+
(ref) =>
|
|
287
|
+
ref.startsWith("sql:") ||
|
|
288
|
+
ref.startsWith("kv:") ||
|
|
289
|
+
ref.startsWith("files:") ||
|
|
290
|
+
ref.startsWith("index:"),
|
|
291
|
+
);
|
|
292
|
+
if (touchesStore) store = true;
|
|
288
293
|
if ((e?.emits?.length ?? 0) > 0) signal = true;
|
|
289
294
|
if ((e?.secrets?.length ?? 0) > 0) vault = true;
|
|
290
295
|
if ((e?.sends?.length ?? 0) > 0) channel = true;
|
|
@@ -548,6 +553,12 @@ export async function bootApplication(input: BootOptions = {}): Promise<BootResu
|
|
|
548
553
|
if (clockRt) void Promise.resolve(clockRt.tick()).catch(ignoreBenignSql);
|
|
549
554
|
if (journal && durableResume) void Promise.resolve(durableResume()).catch(ignoreBenignSql);
|
|
550
555
|
if (fleet) void fleet.maybeHeartbeat().catch(ignoreBenignSql);
|
|
556
|
+
const stem = ["run", "events"].join("-");
|
|
557
|
+
void import(`../elements/ai/${stem}.ts`)
|
|
558
|
+
.then((mod: typeof import("../elements/ai/run-events.ts")) =>
|
|
559
|
+
mod.sweepInstalledAgentEvents(),
|
|
560
|
+
)
|
|
561
|
+
.catch(ignoreBenignSql);
|
|
551
562
|
}, period);
|
|
552
563
|
schedulerTimer.unref?.();
|
|
553
564
|
}
|
|
@@ -567,7 +578,7 @@ export async function bootApplication(input: BootOptions = {}): Promise<BootResu
|
|
|
567
578
|
// 6. AI
|
|
568
579
|
let ai = pre.ai;
|
|
569
580
|
if (needs.ai && !ai) {
|
|
570
|
-
ai = aiBind!.bindAi(options, gate, now, env, docker, vault);
|
|
581
|
+
ai = aiBind!.bindAi(options, gate, now, env, docker, vault, journal?.store);
|
|
571
582
|
}
|
|
572
583
|
|
|
573
584
|
// 7. Runs
|
|
@@ -25,6 +25,7 @@ export const BUILTIN_ERROR_STATUS = {
|
|
|
25
25
|
IdempotencyKeyInvalid: 400,
|
|
26
26
|
IdempotencyKeyReused: 422,
|
|
27
27
|
IdempotencyInProgress: 409,
|
|
28
|
+
JournalLeaseBusy: 409,
|
|
28
29
|
} as const;
|
|
29
30
|
|
|
30
31
|
/** Built-in error code (including `DatabaseError`). */
|
|
@@ -94,6 +95,7 @@ export type BuiltinErrorMap = {
|
|
|
94
95
|
readonly IdempotencyKeyInvalid: Record<string, never>;
|
|
95
96
|
readonly IdempotencyKeyReused: Record<string, never>;
|
|
96
97
|
readonly IdempotencyInProgress: { readonly retryAfter?: number };
|
|
98
|
+
readonly JournalLeaseBusy: { readonly retryAfter?: number };
|
|
97
99
|
};
|
|
98
100
|
|
|
99
101
|
/**
|
package/src/kernel/capability.ts
CHANGED
|
@@ -21,6 +21,7 @@ const UNDECLARED_KEY: Readonly<Record<EffectKind, keyof typeof OKE_ERRORS>> = {
|
|
|
21
21
|
secret: "UNDECLARED_SECRET",
|
|
22
22
|
call: "UNDECLARED_CALL",
|
|
23
23
|
fetch: "UNDECLARED_FETCH",
|
|
24
|
+
decide: "UNDECLARED_DECIDE",
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
/** Maps effect kind → the corresponding `Effects` field. */
|
|
@@ -34,6 +35,7 @@ const EFFECTS_FIELD: Readonly<Record<EffectKind, keyof Effects>> = {
|
|
|
34
35
|
secret: "secrets",
|
|
35
36
|
call: "calls",
|
|
36
37
|
fetch: "fetches",
|
|
38
|
+
decide: "decides",
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
/**
|
|
@@ -91,6 +93,7 @@ export function createCapabilityToken(flow: string, declared?: Effects): Capabil
|
|
|
91
93
|
secret: new Set(effects.secrets ?? []),
|
|
92
94
|
call: new Set(effects.calls ?? []),
|
|
93
95
|
fetch: new Set(effects.fetches ?? []),
|
|
96
|
+
decide: new Set(effects.decides ?? []),
|
|
94
97
|
};
|
|
95
98
|
|
|
96
99
|
return {
|