okengine 0.23.2 → 0.24.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 (75) hide show
  1. package/AGENTS.md +5 -1
  2. package/manifest.v1.schema.json +53 -3
  3. package/package.json +2 -1
  4. package/site/content/docs/ai/mcp.mdx +1 -1
  5. package/site/content/docs/ai/skills.mdx +1 -1
  6. package/site/content/docs/elements/ai/decide.mdx +95 -417
  7. package/site/content/docs/elements/ai/deciders.mdx +154 -0
  8. package/site/content/docs/elements/ai/index.mdx +2 -1
  9. package/site/content/docs/elements/ai/meta.json +1 -1
  10. package/site/content/docs/reference/cli.mdx +2 -2
  11. package/site/content/docs/reference/configuration.mdx +2 -1
  12. package/site/content/docs/reference/fx.mdx +11 -9
  13. package/src/cli/agents-md.test.ts +8 -2
  14. package/src/cli/decide-certify.test.ts +166 -0
  15. package/src/cli/decide.ts +170 -3
  16. package/src/cli/decision-lock-watch.test.ts +4 -4
  17. package/src/cli/eval.ts +38 -59
  18. package/src/cli/mcp-from-console.ts +1 -1
  19. package/src/cli/registry.ts +45 -9
  20. package/src/compiler/decisions.extract.test.ts +86 -31
  21. package/src/compiler/effects-infer.ts +1 -0
  22. package/src/compiler/extract.ts +239 -24
  23. package/src/config/index.ts +6 -0
  24. package/src/console/server/decisions.test.ts +6 -1
  25. package/src/console/server/decisions.ts +32 -1
  26. package/src/console/ui-next/dist/assets/{access-page-zBMhZnFm.js → access-page-DX2dKLmq.js} +1 -1
  27. package/src/console/ui-next/dist/assets/{agent-disclosure-CBj9f7Ju.js → agent-disclosure-CiRvA3M9.js} +1 -1
  28. package/src/console/ui-next/dist/assets/{cache-glyph-D3MY49h3.js → cache-glyph-CC1yFJ8A.js} +1 -1
  29. package/src/console/ui-next/dist/assets/{call-pii-button-L9JxdBhp.js → call-pii-button-CLXQgIDD.js} +1 -1
  30. package/src/console/ui-next/dist/assets/{collapsible-BvFaX-Zt.js → collapsible-C0AThBZg.js} +1 -1
  31. package/src/console/ui-next/dist/assets/{decisions-page-DgB76m-X.js → decisions-page-Bf3AhTAa.js} +1 -1
  32. package/src/console/ui-next/dist/assets/{duration-tone-l1DSJ2Vz.js → duration-tone-Bptur2gX.js} +1 -1
  33. package/src/console/ui-next/dist/assets/{flows-page-Bb9t1lu6.js → flows-page-DRZVeTZU.js} +1 -1
  34. package/src/console/ui-next/dist/assets/{highlighted-json-DMvsi3Ti.js → highlighted-json-BKf0PjBK.js} +1 -1
  35. package/src/console/ui-next/dist/assets/{http-method-BwhJBTcQ.js → http-method-uhrnWrGC.js} +1 -1
  36. package/src/console/ui-next/dist/assets/{index-RhV2jT_7.js → index-Duxus_sG.js} +3 -3
  37. package/src/console/ui-next/dist/assets/{observability-page-BRfUILBq.js → observability-page-B-QM8X0O.js} +1 -1
  38. package/src/console/ui-next/dist/assets/{replica-lag-BsceAzIG.js → replica-lag-DuqHCANi.js} +1 -1
  39. package/src/console/ui-next/dist/assets/{request-meta-C6lTyCXp.js → request-meta-BTBZ3Ulc.js} +1 -1
  40. package/src/console/ui-next/dist/assets/{store-page-YmE806bJ.js → store-page-fpo7VxYb.js} +1 -1
  41. package/src/console/ui-next/dist/assets/{trace-detail-sheet-Di4irS49.js → trace-detail-sheet-DKtr1-K1.js} +1 -1
  42. package/src/console/ui-next/dist/assets/{tree-expand-toggle-DYeL6Rye.js → tree-expand-toggle-QeTceKKI.js} +1 -1
  43. package/src/console/ui-next/dist/assets/{units-page-07agasRA.js → units-page-ChCp8mOy.js} +1 -1
  44. package/src/console/ui-next/dist/assets/{vault-page-CHBck4n_.js → vault-page-CEYLXhUX.js} +1 -1
  45. package/src/console/ui-next/dist/index.html +1 -1
  46. package/src/console/ui-next/src/client.ts +8 -0
  47. package/src/console/ui-next/src/features/flows/decisions/decisions-page.tsx +16 -0
  48. package/src/elements/ai/deciders/presets.ts +182 -0
  49. package/src/elements/ai/decisions/bind.ts +6 -5
  50. package/src/elements/ai/decisions/catalog.ts +93 -0
  51. package/src/elements/ai/decisions/certificate.test.ts +47 -19
  52. package/src/elements/ai/decisions/certificate.ts +107 -24
  53. package/src/elements/ai/decisions/certify.ts +104 -9
  54. package/src/elements/ai/decisions/codec.test.ts +142 -0
  55. package/src/elements/ai/decisions/codec.ts +302 -0
  56. package/src/elements/ai/decisions/decide.test.ts +108 -31
  57. package/src/elements/ai/decisions/decider-runtime.test.ts +415 -0
  58. package/src/elements/ai/decisions/decider.types.test.ts +62 -0
  59. package/src/elements/ai/decisions/e2e.test.ts +20 -16
  60. package/src/elements/ai/decisions/http.ts +15 -7
  61. package/src/elements/ai/decisions/labels.test.ts +6 -1
  62. package/src/elements/ai/decisions/labels.ts +4 -3
  63. package/src/elements/ai/decisions/openai.live.test.ts +42 -0
  64. package/src/elements/ai/decisions/openrouter.live.test.ts +5 -1
  65. package/src/elements/ai/decisions/provider.ts +22 -1
  66. package/src/elements/ai/declare.ts +208 -51
  67. package/src/elements/ai.ts +1 -0
  68. package/src/index.ts +1 -0
  69. package/src/kernel/app.ts +8 -0
  70. package/src/kernel/decision-budget-entry.ts +11 -0
  71. package/src/kernel/element-registries.ts +3 -0
  72. package/src/kernel/fx-decide.ts +276 -88
  73. package/src/manifest/types.ts +38 -2
  74. package/src/release/measure.ts +47 -8
  75. package/src/test/create-test-app.ts +21 -1
@@ -54,7 +54,7 @@ export const EXPORT_BUILD_EXTERNALS = [
54
54
  ] as const;
55
55
 
56
56
  /** How a sample is gated. */
57
- export type BudgetGate = "absolute" | "regression";
57
+ export type BudgetGate = "absolute" | "regression" | "report";
58
58
 
59
59
  /** Report section headings. */
60
60
  const GROUP_HEADINGS: Readonly<Record<BudgetGroup, string>> = {
@@ -239,6 +239,26 @@ export async function measureHttpPingAppBytes(): Promise<HttpPingBudgetSample> {
239
239
  /**
240
240
  * Gzip size of the kernel edge profile bundle.
241
241
  */
242
+ /**
243
+ * Gzip size of the lazy decision module. Reported, not gated.
244
+ */
245
+ export async function measureDecisionChunkGzipBytes(): Promise<number> {
246
+ const entry = `${import.meta.dir}/../kernel/decision-budget-entry.ts`;
247
+ const result = await Bun.build({
248
+ entrypoints: [entry],
249
+ minify: true,
250
+ target: "bun",
251
+ format: "esm",
252
+ });
253
+ if (!result.success) {
254
+ throw new Error(`decision chunk build failed:\n${result.logs.map(String).join("\n")}`);
255
+ }
256
+ const artifact = result.outputs[0];
257
+ if (!artifact) throw new Error("decision chunk build produced no output");
258
+ const raw = await artifact.arrayBuffer();
259
+ return Bun.gzipSync(new Uint8Array(raw)).byteLength;
260
+ }
261
+
242
262
  export async function measureKernelEdgeGzipBytes(): Promise<number> {
243
263
  try {
244
264
  return await gzipKernelEdgeInProcess();
@@ -640,13 +660,19 @@ export async function measureAllBudgets(): Promise<BudgetsSnapshot> {
640
660
  "ms",
641
661
  );
642
662
  const coldStartMedianMs = await measureColdStartMedianMs(coldCeiling ?? COLD_START_BUDGET_MS);
643
- const [kernelEdgeGzipBytes, clientGzipBytes, consoleInitialGzipBytes, httpPing] =
644
- await Promise.all([
645
- measureKernelEdgeGzipBytes(),
646
- measureClientGzipBytes(),
647
- measureConsoleInitialGzipBytes(),
648
- measureHttpPingAppBytes(),
649
- ]);
663
+ const [
664
+ kernelEdgeGzipBytes,
665
+ clientGzipBytes,
666
+ consoleInitialGzipBytes,
667
+ httpPing,
668
+ decisionChunkGzipBytes,
669
+ ] = await Promise.all([
670
+ measureKernelEdgeGzipBytes(),
671
+ measureClientGzipBytes(),
672
+ measureConsoleInitialGzipBytes(),
673
+ measureHttpPingAppBytes(),
674
+ measureDecisionChunkGzipBytes(),
675
+ ]);
650
676
  const routingP99Ms = measureRoutingP99Ms();
651
677
 
652
678
  const budgets: BudgetSample[] = [
@@ -660,6 +686,16 @@ export async function measureAllBudgets(): Promise<BudgetsSnapshot> {
660
686
  "core",
661
687
  previous,
662
688
  ),
689
+ sample(
690
+ "decisionChunkGzipBytes",
691
+ "Decision module",
692
+ decisionChunkGzipBytes,
693
+ decisionChunkGzipBytes,
694
+ "bytes",
695
+ "report",
696
+ "core",
697
+ previous,
698
+ ),
663
699
  sample(
664
700
  "clientGzipBytes",
665
701
  "Client runtime",
@@ -860,6 +896,9 @@ function sample(
860
896
  previous?: ReadonlyMap<string, number>,
861
897
  ): BudgetSample {
862
898
  const rounded = unit === "bytes" ? Math.round(value) : Math.round(value * 1000) / 1000;
899
+ if (gate === "report") {
900
+ return { id, label, value: rounded, limit: rounded, unit, gate, group, ok: true };
901
+ }
863
902
  const regressionLimit =
864
903
  gate === "absolute" ? absoluteRegressionCeiling(previous?.get(id), limit, unit) : undefined;
865
904
  return {
@@ -23,7 +23,13 @@ import {
23
23
  type ChannelInbox,
24
24
  type ChannelInboxEntry,
25
25
  } from "../drivers/index.ts";
26
- import { createAiRuntime, type AiPromptDecl, type AiRuntime } from "../elements/ai.ts";
26
+ import {
27
+ createAiRuntime,
28
+ type AiDecisionDecl,
29
+ type AiPromptDecl,
30
+ type AiRuntime,
31
+ } from "../elements/ai.ts";
32
+ import { setDecisionScript, type DecisionScriptAnswer } from "../kernel/fx-decide.ts";
27
33
  import { createChannelRuntime, type DeliveryReceipt } from "../elements/channel.ts";
28
34
  import { createTestClockRuntime } from "../elements/clock.ts";
29
35
  import type { GateDecl } from "../elements/gate.ts";
@@ -154,6 +160,16 @@ export interface TestAi {
154
160
  * @param output - JSON-serialisable output
155
161
  */
156
162
  mock(prompt: AiPromptDecl | string, output: unknown): void;
163
+ /**
164
+ * Script one decision. `{ refusal: string }` is the test signal and is not stored.
165
+ *
166
+ * @param decision - Decision decl or name
167
+ * @param answers - Probabilities, or a refusal, per question
168
+ */
169
+ decide(
170
+ decision: AiDecisionDecl | string,
171
+ answers: Readonly<Record<string, DecisionScriptAnswer>>,
172
+ ): void;
157
173
  /** Accumulated AI cost across asks in this harness. */
158
174
  cost(): number;
159
175
  }
@@ -461,6 +477,10 @@ export async function createTestApp<App extends OkeApp>(
461
477
  cost() {
462
478
  return aiCost;
463
479
  },
480
+ decide(decision, answers) {
481
+ const name = typeof decision === "string" ? decision : decision.name;
482
+ setDecisionScript(name, answers);
483
+ },
464
484
  },
465
485
  effects: {
466
486
  of(id) {