@agent-native/core 0.84.0 → 0.84.2

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 (152) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +13 -0
  3. package/corpus/core/docs/content/evals.mdx +34 -12
  4. package/corpus/core/docs/content/locales/ar-SA/evals.mdx +7 -0
  5. package/corpus/core/docs/content/locales/de-DE/evals.mdx +8 -0
  6. package/corpus/core/docs/content/locales/es-ES/evals.mdx +8 -0
  7. package/corpus/core/docs/content/locales/fr-FR/evals.mdx +8 -0
  8. package/corpus/core/docs/content/locales/hi-IN/evals.mdx +8 -0
  9. package/corpus/core/docs/content/locales/ja-JP/evals.mdx +7 -0
  10. package/corpus/core/docs/content/locales/ko-KR/evals.mdx +7 -0
  11. package/corpus/core/docs/content/locales/pt-BR/evals.mdx +8 -0
  12. package/corpus/core/docs/content/locales/zh-CN/evals.mdx +7 -0
  13. package/corpus/core/docs/content/locales/zh-TW/evals.mdx +7 -0
  14. package/corpus/core/docs/design/durable-agent-runs.md +34 -35
  15. package/corpus/core/package.json +1 -1
  16. package/corpus/core/src/agent/engine/builder-engine.ts +81 -9
  17. package/corpus/core/src/agent/run-manager.ts +8 -7
  18. package/corpus/core/src/cli/design-connect.ts +175 -0
  19. package/corpus/core/src/cli/skills.ts +5 -7
  20. package/corpus/core/src/client/AgentPanel.tsx +8 -0
  21. package/corpus/core/src/client/MultiTabAssistantChat.tsx +4 -1
  22. package/corpus/core/src/client/agent-chat-adapter.ts +45 -15
  23. package/corpus/core/src/client/sse-event-processor.ts +31 -4
  24. package/corpus/core/src/eval/define-eval.ts +4 -1
  25. package/corpus/core/src/eval/report.ts +23 -8
  26. package/corpus/core/src/eval/runner.ts +41 -6
  27. package/corpus/core/src/eval/types.ts +11 -0
  28. package/corpus/core/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +15 -17
  29. package/corpus/templates/content/AGENTS.md +9 -2
  30. package/corpus/templates/content/actions/_database-row-batch.ts +230 -0
  31. package/corpus/templates/content/actions/_database-utils.ts +17 -9
  32. package/corpus/templates/content/actions/_notion-action-utils.ts +26 -0
  33. package/corpus/templates/content/actions/connect-notion-status.ts +13 -4
  34. package/corpus/templates/content/actions/create-and-link-notion-page.ts +23 -0
  35. package/corpus/templates/content/actions/delete-database-items.ts +55 -0
  36. package/corpus/templates/content/actions/delete-document.ts +4 -4
  37. package/corpus/templates/content/actions/disconnect-notion.ts +16 -0
  38. package/corpus/templates/content/actions/duplicate-database-item.ts +1 -1
  39. package/corpus/templates/content/actions/duplicate-database-items.ts +191 -0
  40. package/corpus/templates/content/actions/link-notion-page.ts +10 -7
  41. package/corpus/templates/content/actions/list-notion-links.ts +3 -4
  42. package/corpus/templates/content/actions/pull-notion-page.ts +7 -9
  43. package/corpus/templates/content/actions/push-notion-page.ts +7 -9
  44. package/corpus/templates/content/actions/refresh-notion-sync-status.ts +24 -0
  45. package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +23 -0
  46. package/corpus/templates/content/actions/search-notion-pages.ts +67 -0
  47. package/corpus/templates/content/actions/unlink-notion-page.ts +23 -0
  48. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +27 -34
  49. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +16 -13
  50. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +10 -10
  51. package/corpus/templates/content/app/components/editor/NotionConflictBanner.tsx +1 -1
  52. package/corpus/templates/content/app/components/editor/NotionSyncBar.tsx +18 -9
  53. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +27 -34
  54. package/corpus/templates/content/app/components/editor/database/navigation-state.ts +10 -4
  55. package/corpus/templates/content/app/components/sidebar/NotionButton.tsx +32 -17
  56. package/corpus/templates/content/app/hooks/use-content-database.ts +35 -0
  57. package/corpus/templates/content/app/hooks/use-notion.ts +108 -99
  58. package/corpus/templates/content/package.json +3 -0
  59. package/corpus/templates/content/parity/README.md +69 -0
  60. package/corpus/templates/content/parity/eval-scenarios.ts +118 -0
  61. package/corpus/templates/content/parity/exceptions.allowlist.ts +17 -0
  62. package/corpus/templates/content/parity/matrix.md +28 -0
  63. package/corpus/templates/content/parity/matrix.ts +606 -0
  64. package/corpus/templates/content/parity/matrix.types.ts +42 -0
  65. package/corpus/templates/content/parity/parity-evals.eval.ts +4 -0
  66. package/corpus/templates/content/parity/render-matrix.ts +90 -0
  67. package/corpus/templates/content/parity/scenario-to-eval.ts +57 -0
  68. package/corpus/templates/content/shared/api.ts +11 -0
  69. package/corpus/templates/design/actions/apply-motion-edit.ts +50 -18
  70. package/corpus/templates/design/actions/get-motion-timeline.ts +4 -14
  71. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +156 -12
  72. package/corpus/templates/design/app/components/design/MotionDock.tsx +2 -3
  73. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +217 -75
  74. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +39 -39
  75. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +558 -37
  76. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +75 -3
  77. package/corpus/templates/design/app/components/design/types.ts +13 -0
  78. package/corpus/templates/design/app/components/layout/Layout.tsx +1 -0
  79. package/corpus/templates/design/app/i18n/zh-TW.ts +17 -0
  80. package/corpus/templates/design/app/i18n-data.ts +245 -0
  81. package/corpus/templates/design/app/pages/DesignEditor.tsx +762 -153
  82. package/corpus/templates/design/changelog/2026-06-30-copying-or-dragging-screen-elements-onto-the-infinite-canvas.md +6 -0
  83. package/corpus/templates/design/changelog/2026-06-30-design-questions-now-use-tighter-editor-typography-and-contr.md +6 -0
  84. package/corpus/templates/design/changelog/2026-06-30-element-drags-can-be-cancelled-with-escape-before-they-commi.md +6 -0
  85. package/corpus/templates/design/changelog/2026-06-30-pending-visual-style-edits-now-warn-before-you-leave-the-edi.md +6 -0
  86. package/corpus/templates/design/changelog/2026-06-30-visual-style-drags-stay-live-while-pending-edits-can-be-appl.md +6 -0
  87. package/corpus/templates/design/changelog/2026-07-01-design-chat-no-longer-shows-a-redundant-context-tab-above-the-composer.md +6 -0
  88. package/corpus/templates/design/changelog/2026-07-01-motion-track-creation-no-longer-fails-in-local-editors.md +6 -0
  89. package/corpus/templates/design/server/plugins/db.ts +10 -0
  90. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  91. package/dist/agent/engine/builder-engine.js +61 -10
  92. package/dist/agent/engine/builder-engine.js.map +1 -1
  93. package/dist/agent/run-manager.d.ts +8 -7
  94. package/dist/agent/run-manager.d.ts.map +1 -1
  95. package/dist/agent/run-manager.js +8 -7
  96. package/dist/agent/run-manager.js.map +1 -1
  97. package/dist/cli/design-connect.d.ts +2 -0
  98. package/dist/cli/design-connect.d.ts.map +1 -1
  99. package/dist/cli/design-connect.js +140 -0
  100. package/dist/cli/design-connect.js.map +1 -1
  101. package/dist/cli/skills.d.ts.map +1 -1
  102. package/dist/cli/skills.js +5 -7
  103. package/dist/cli/skills.js.map +1 -1
  104. package/dist/client/AgentPanel.d.ts +5 -1
  105. package/dist/client/AgentPanel.d.ts.map +1 -1
  106. package/dist/client/AgentPanel.js +4 -4
  107. package/dist/client/AgentPanel.js.map +1 -1
  108. package/dist/client/MultiTabAssistantChat.d.ts +3 -1
  109. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  110. package/dist/client/MultiTabAssistantChat.js +2 -2
  111. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  112. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  113. package/dist/client/agent-chat-adapter.js +37 -14
  114. package/dist/client/agent-chat-adapter.js.map +1 -1
  115. package/dist/client/sse-event-processor.d.ts +14 -1
  116. package/dist/client/sse-event-processor.d.ts.map +1 -1
  117. package/dist/client/sse-event-processor.js +21 -5
  118. package/dist/client/sse-event-processor.js.map +1 -1
  119. package/dist/collab/routes.d.ts +1 -1
  120. package/dist/eval/define-eval.d.ts.map +1 -1
  121. package/dist/eval/define-eval.js +2 -1
  122. package/dist/eval/define-eval.js.map +1 -1
  123. package/dist/eval/report.d.ts.map +1 -1
  124. package/dist/eval/report.js +19 -4
  125. package/dist/eval/report.js.map +1 -1
  126. package/dist/eval/runner.d.ts.map +1 -1
  127. package/dist/eval/runner.js +38 -6
  128. package/dist/eval/runner.js.map +1 -1
  129. package/dist/eval/types.d.ts +11 -0
  130. package/dist/eval/types.d.ts.map +1 -1
  131. package/dist/eval/types.js.map +1 -1
  132. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  133. package/dist/observability/routes.d.ts +2 -2
  134. package/dist/progress/routes.d.ts +1 -1
  135. package/dist/resources/handlers.d.ts +3 -3
  136. package/dist/server/transcribe-voice.d.ts +1 -1
  137. package/dist/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +15 -17
  138. package/docs/content/evals.mdx +34 -12
  139. package/docs/content/locales/ar-SA/evals.mdx +7 -0
  140. package/docs/content/locales/de-DE/evals.mdx +8 -0
  141. package/docs/content/locales/es-ES/evals.mdx +8 -0
  142. package/docs/content/locales/fr-FR/evals.mdx +8 -0
  143. package/docs/content/locales/hi-IN/evals.mdx +8 -0
  144. package/docs/content/locales/ja-JP/evals.mdx +7 -0
  145. package/docs/content/locales/ko-KR/evals.mdx +7 -0
  146. package/docs/content/locales/pt-BR/evals.mdx +8 -0
  147. package/docs/content/locales/zh-CN/evals.mdx +7 -0
  148. package/docs/content/locales/zh-TW/evals.mdx +7 -0
  149. package/docs/design/durable-agent-runs.md +34 -35
  150. package/package.json +1 -1
  151. package/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +15 -17
  152. package/corpus/templates/content/server/routes/api/notion/disconnect.post.ts +0 -12
@@ -53,6 +53,19 @@ async function runScorer(scorer, run, runner, threshold) {
53
53
  /** Run a single eval: invoke the agent, then score with each scorer. */
54
54
  export async function scoreEval(evalCase, runner, opts = {}) {
55
55
  const threshold = opts.thresholdOverride ?? evalCase.threshold ?? DEFAULT_EVAL_THRESHOLD;
56
+ if (evalCase.skipReason) {
57
+ return {
58
+ eval: evalCase.name,
59
+ threshold,
60
+ scores: [],
61
+ status: "skipped",
62
+ skipReason: evalCase.skipReason,
63
+ // Keep the legacy boolean gate friendly: skipped rows do not fail CI.
64
+ passed: true,
65
+ avgScore: 0,
66
+ durationMs: 0,
67
+ };
68
+ }
56
69
  let run;
57
70
  if (evalCase.run) {
58
71
  run = await evalCase.run({
@@ -76,6 +89,7 @@ export async function scoreEval(evalCase, runner, opts = {}) {
76
89
  scores,
77
90
  // A run that errored, or any sub-threshold scorer, fails the case.
78
91
  passed: run.ok && scores.every((s) => s.passed),
92
+ status: run.ok && scores.every((s) => s.passed) ? "passed" : "failed",
79
93
  avgScore,
80
94
  durationMs: run.durationMs,
81
95
  error: run.ok ? undefined : run.error,
@@ -87,14 +101,17 @@ export async function runEvals(evals, runner, opts = {}) {
87
101
  for (const evalCase of evals) {
88
102
  const row = await scoreEval(evalCase, runner, opts);
89
103
  results.push(row);
90
- if (opts.persist)
104
+ if (opts.persist && row.status !== "skipped") {
91
105
  await persistEvalRow(row).catch(() => { });
106
+ }
92
107
  }
93
108
  const passed = results.filter((r) => r.passed).length;
109
+ const skipped = results.filter((r) => r.status === "skipped").length;
94
110
  return {
95
111
  total: results.length,
96
112
  passed,
97
- failed: results.length - passed,
113
+ failed: results.filter((r) => r.status !== "skipped" && !r.passed).length,
114
+ skipped,
98
115
  results,
99
116
  };
100
117
  }
@@ -227,11 +244,14 @@ export async function runEvalSuite(opts = {}) {
227
244
  files = loaded.files;
228
245
  evals = loaded.evals;
229
246
  }
247
+ const needsRunner = evals.some((evalCase) => !evalCase.skipReason);
230
248
  const runner = opts.runner ??
231
- (await createAgentRunner({
232
- actions: opts.actions ?? (await discoverActions(cwd)),
233
- systemPrompt: opts.systemPrompt,
234
- }));
249
+ (needsRunner
250
+ ? await createAgentRunner({
251
+ actions: opts.actions ?? (await discoverActions(cwd)),
252
+ systemPrompt: opts.systemPrompt,
253
+ })
254
+ : createInertRunner());
235
255
  const report = await runEvals(evals, runner, {
236
256
  thresholdOverride: opts.thresholdOverride,
237
257
  persist: opts.persist ?? true,
@@ -253,4 +273,16 @@ async function discoverActions(cwd) {
253
273
  return {};
254
274
  }
255
275
  }
276
+ function createInertRunner() {
277
+ return {
278
+ engine: {},
279
+ model: "inert",
280
+ async runAgent() {
281
+ throw new Error("Eval unexpectedly requested the agent runner");
282
+ },
283
+ analyzeContext() {
284
+ throw new Error("Eval unexpectedly requested analyze context");
285
+ },
286
+ };
287
+ }
256
288
  //# sourceMappingURL=runner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/eval/runner.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The evals runner: discover `*.eval.ts` / `evals/*.ts` files, run each eval\n * through its scorer pipeline against the *real* agent loop, score, and report.\n *\n * It is the engine behind `agent-native eval` — when used as a CI deploy gate\n * the CLI exits non-zero if any eval scores below its threshold.\n *\n * Two layers:\n * - `scoreEval` / `runEvals` — pure orchestration over an `AgentRunner` and\n * a list of evals. Fully unit-testable with an injected runner (no model).\n * - `discoverEvalFiles` / `loadEvals` — filesystem discovery + dynamic import\n * of author-written eval modules.\n *\n * Results are also (best-effort) written to the observability eval store so a\n * dashboard can surface CI eval history next to production run evals.\n */\n\nimport nodePath from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport { insertEvalResult } from \"../observability/store.js\";\nimport type { EvalResult as ObservabilityEvalResult } from \"../observability/types.js\";\nimport type { AgentRunner } from \"./agent-runner.js\";\nimport { createAgentRunner } from \"./agent-runner.js\";\nimport { DEFAULT_EVAL_THRESHOLD } from \"./define-eval.js\";\nimport { clamp01 } from \"./scorer.js\";\nimport type {\n AgentRunOutput,\n Eval,\n EvalResultRow,\n EvalRunReport,\n ScorerResult,\n} from \"./types.js\";\n\n// ─── Scoring orchestration ────────────────────────────────────────────\n\n/** Run one scorer's pipeline (preprocess → analyze → score → reason). */\nasync function runScorer(\n scorer: Eval[\"scorers\"][number],\n run: AgentRunOutput,\n runner: AgentRunner,\n threshold: number,\n): Promise<ScorerResult> {\n try {\n const pre = scorer.preprocess ? await scorer.preprocess(run) : run;\n const analysis = scorer.analyze\n ? await scorer.analyze(pre as never, runner.analyzeContext())\n : pre;\n const rawScore = await scorer.generateScore(analysis as never);\n const score = clamp01(rawScore);\n const reason = scorer.generateReason\n ? await scorer.generateReason({\n run,\n analysis: analysis as never,\n score,\n })\n : undefined;\n return { scorer: scorer.name, score, reason, passed: score >= threshold };\n } catch (err) {\n // A scorer that throws is a failed scorer, not a crashed run — degrade\n // gracefully so one bad scorer can't take down the whole CI gate.\n return {\n scorer: scorer.name,\n score: 0,\n reason: `Scorer errored: ${err instanceof Error ? err.message : String(err)}`,\n passed: false,\n };\n }\n}\n\n/** Run a single eval: invoke the agent, then score with each scorer. */\nexport async function scoreEval(\n evalCase: Eval,\n runner: AgentRunner,\n opts: { thresholdOverride?: number } = {},\n): Promise<EvalResultRow> {\n const threshold =\n opts.thresholdOverride ?? evalCase.threshold ?? DEFAULT_EVAL_THRESHOLD;\n\n let run: AgentRunOutput;\n if (evalCase.run) {\n run = await evalCase.run({\n input: evalCase.input,\n runAgent: (input) => runner.runAgent(input),\n });\n } else {\n run = await runner.runAgent(evalCase.input);\n }\n\n const scores: ScorerResult[] = [];\n for (const scorer of evalCase.scorers) {\n scores.push(await runScorer(scorer, run, runner, threshold));\n }\n\n const avgScore =\n scores.length > 0\n ? scores.reduce((s, r) => s + r.score, 0) / scores.length\n : 0;\n\n return {\n eval: evalCase.name,\n threshold,\n scores,\n // A run that errored, or any sub-threshold scorer, fails the case.\n passed: run.ok && scores.every((s) => s.passed),\n avgScore,\n durationMs: run.durationMs,\n error: run.ok ? undefined : run.error,\n };\n}\n\n/** Run a batch of evals against one runner and aggregate a report. */\nexport async function runEvals(\n evals: Eval[],\n runner: AgentRunner,\n opts: { thresholdOverride?: number; persist?: boolean } = {},\n): Promise<EvalRunReport> {\n const results: EvalResultRow[] = [];\n for (const evalCase of evals) {\n const row = await scoreEval(evalCase, runner, opts);\n results.push(row);\n if (opts.persist) await persistEvalRow(row).catch(() => {});\n }\n\n const passed = results.filter((r) => r.passed).length;\n return {\n total: results.length,\n passed,\n failed: results.length - passed,\n results,\n };\n}\n\n/**\n * Best-effort write of one eval result to the observability eval store so a\n * dashboard can show CI eval history alongside production run evals. We write\n * one row per (eval × scorer), tagged `evalType: \"automated\"` with a synthetic\n * `eval:` run id.\n *\n * TODO(live-sampling): the same scorer list should also run on a sampled\n * fraction of *real* production runs. That hook belongs in the agent loop's\n * (not-yet-added) post-run processor seam: when a run finishes, roll the\n * configured sample rate and, if it hits, replay the run output through these\n * scorers and write the rows here. Wiring it now would require the in-loop\n * processor seam another wave is adding — so this is the single intended\n * attachment point, intentionally left as a note.\n */\nasync function persistEvalRow(row: EvalResultRow): Promise<void> {\n const runId = `eval:${row.eval}:${Date.now()}`;\n for (const s of row.scores) {\n const result: ObservabilityEvalResult = {\n id: crypto.randomUUID(),\n runId,\n threadId: null,\n userId: null,\n evalType: \"automated\",\n criteria: `eval:${row.eval}:${s.scorer}`,\n score: s.score,\n reasoning: s.reason ?? null,\n metadata: {\n source: \"cli-eval\",\n threshold: row.threshold,\n passed: s.passed,\n },\n createdAt: Date.now(),\n };\n await insertEvalResult(result);\n }\n}\n\n// ─── Discovery + loading ──────────────────────────────────────────────\n\nconst EVAL_FILE_RE = /\\.eval\\.(ts|js|mjs)$/;\nconst SKIP_DIRS = new Set([\"node_modules\", \"dist\", \".git\", \".output\", \"build\"]);\n\n/**\n * Walk `root` for eval files. Matches two conventions:\n * - any `**\\/*.eval.ts` (co-located with code), and\n * - any `*.ts` directly inside an `evals/` directory.\n * `pattern` further filters by substring of the relative path.\n */\nexport async function discoverEvalFiles(\n root: string,\n pattern?: string,\n): Promise<string[]> {\n const fs = await import(\"node:fs\");\n const out: string[] = [];\n\n function isEvalFile(full: string, parentName: string): boolean {\n const base = nodePath.basename(full);\n if (EVAL_FILE_RE.test(base)) return true;\n if (parentName === \"evals\" && /\\.(ts|js|mjs)$/.test(base)) {\n // Skip obvious support files inside evals/.\n return !/\\.(spec|test|d)\\.(ts|js|mjs)$/.test(base);\n }\n return false;\n }\n\n function walk(dir: string, parentName: string): void {\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = nodePath.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(\".\")) continue;\n walk(full, entry.name);\n } else if (entry.isFile() && isEvalFile(full, parentName)) {\n out.push(full);\n }\n }\n }\n\n walk(root, nodePath.basename(root));\n out.sort();\n\n if (!pattern) return out;\n return out.filter((f) => nodePath.relative(root, f).includes(pattern));\n}\n\n/** Pull `Eval` definitions out of a dynamically-imported eval module. */\nfunction extractEvals(mod: Record<string, unknown>): Eval[] {\n const candidates: unknown[] = [];\n if (mod.default !== undefined) candidates.push(mod.default);\n for (const [key, value] of Object.entries(mod)) {\n if (key === \"default\") continue;\n candidates.push(value);\n }\n\n const evals: Eval[] = [];\n for (const c of candidates.flat()) {\n if (\n c &&\n typeof c === \"object\" &&\n typeof (c as Eval).name === \"string\" &&\n Array.isArray((c as Eval).scorers) &&\n (c as Eval).input\n ) {\n evals.push(c as Eval);\n }\n }\n return evals;\n}\n\n/** Discover and import all eval files under `root`, returning their evals. */\nexport async function loadEvals(\n root: string,\n pattern?: string,\n): Promise<{ files: string[]; evals: Eval[] }> {\n const files = await discoverEvalFiles(root, pattern);\n const evals: Eval[] = [];\n for (const file of files) {\n const mod = (await import(pathToFileURL(file).href)) as Record<\n string,\n unknown\n >;\n evals.push(...extractEvals(mod));\n }\n return { files, evals };\n}\n\n// ─── High-level entry used by the CLI ─────────────────────────────────\n\nexport interface RunEvalSuiteOptions {\n /** App root to discover eval files + actions under. Defaults to cwd. */\n cwd?: string;\n /** Substring filter on the eval file path. */\n pattern?: string;\n /** Global threshold override (wins over per-eval thresholds). */\n thresholdOverride?: number;\n /** App actions to expose to the agent. Auto-discovered when omitted. */\n actions?: Record<string, ActionEntry>;\n /** System prompt for runs. */\n systemPrompt?: string;\n /** Write results to the observability eval store (default true). */\n persist?: boolean;\n /** Pre-built runner (tests inject this to avoid touching engine/loop). */\n runner?: AgentRunner;\n /** Pre-loaded evals (tests inject this to skip filesystem discovery). */\n evals?: Eval[];\n}\n\n/**\n * End-to-end: load evals, build a runner, score, report. The CLI wraps this\n * and maps `report.failed > 0` to a non-zero exit code (the CI gate).\n */\nexport async function runEvalSuite(\n opts: RunEvalSuiteOptions = {},\n): Promise<{ report: EvalRunReport; files: string[] }> {\n const cwd = opts.cwd ?? process.cwd();\n\n let files: string[] = [];\n let evals = opts.evals;\n if (!evals) {\n const loaded = await loadEvals(cwd, opts.pattern);\n files = loaded.files;\n evals = loaded.evals;\n }\n\n const runner =\n opts.runner ??\n (await createAgentRunner({\n actions: opts.actions ?? (await discoverActions(cwd)),\n systemPrompt: opts.systemPrompt,\n }));\n\n const report = await runEvals(evals, runner, {\n thresholdOverride: opts.thresholdOverride,\n persist: opts.persist ?? true,\n });\n return { report, files };\n}\n\n/**\n * Discover the app's actions so the agent under test has the real tool\n * surface. Lazy-imports `autoDiscoverActions` to keep server-only deps out of\n * any browser bundle that might touch this module's types.\n */\nasync function discoverActions(\n cwd: string,\n): Promise<Record<string, ActionEntry>> {\n try {\n const { autoDiscoverActions } =\n await import(\"../server/action-discovery.js\");\n const actionsDir = nodePath.join(cwd, \"actions\");\n return await autoDiscoverActions(pathToFileURL(actionsDir + \"/\").href);\n } catch {\n return {};\n }\n}\n"]}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/eval/runner.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The evals runner: discover `*.eval.ts` / `evals/*.ts` files, run each eval\n * through its scorer pipeline against the *real* agent loop, score, and report.\n *\n * It is the engine behind `agent-native eval` — when used as a CI deploy gate\n * the CLI exits non-zero if any eval scores below its threshold.\n *\n * Two layers:\n * - `scoreEval` / `runEvals` — pure orchestration over an `AgentRunner` and\n * a list of evals. Fully unit-testable with an injected runner (no model).\n * - `discoverEvalFiles` / `loadEvals` — filesystem discovery + dynamic import\n * of author-written eval modules.\n *\n * Results are also (best-effort) written to the observability eval store so a\n * dashboard can surface CI eval history next to production run evals.\n */\n\nimport nodePath from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport { insertEvalResult } from \"../observability/store.js\";\nimport type { EvalResult as ObservabilityEvalResult } from \"../observability/types.js\";\nimport type { AgentRunner } from \"./agent-runner.js\";\nimport { createAgentRunner } from \"./agent-runner.js\";\nimport { DEFAULT_EVAL_THRESHOLD } from \"./define-eval.js\";\nimport { clamp01 } from \"./scorer.js\";\nimport type {\n AgentRunOutput,\n Eval,\n EvalResultRow,\n EvalRunReport,\n ScorerResult,\n} from \"./types.js\";\n\n// ─── Scoring orchestration ────────────────────────────────────────────\n\n/** Run one scorer's pipeline (preprocess → analyze → score → reason). */\nasync function runScorer(\n scorer: Eval[\"scorers\"][number],\n run: AgentRunOutput,\n runner: AgentRunner,\n threshold: number,\n): Promise<ScorerResult> {\n try {\n const pre = scorer.preprocess ? await scorer.preprocess(run) : run;\n const analysis = scorer.analyze\n ? await scorer.analyze(pre as never, runner.analyzeContext())\n : pre;\n const rawScore = await scorer.generateScore(analysis as never);\n const score = clamp01(rawScore);\n const reason = scorer.generateReason\n ? await scorer.generateReason({\n run,\n analysis: analysis as never,\n score,\n })\n : undefined;\n return { scorer: scorer.name, score, reason, passed: score >= threshold };\n } catch (err) {\n // A scorer that throws is a failed scorer, not a crashed run — degrade\n // gracefully so one bad scorer can't take down the whole CI gate.\n return {\n scorer: scorer.name,\n score: 0,\n reason: `Scorer errored: ${err instanceof Error ? err.message : String(err)}`,\n passed: false,\n };\n }\n}\n\n/** Run a single eval: invoke the agent, then score with each scorer. */\nexport async function scoreEval(\n evalCase: Eval,\n runner: AgentRunner,\n opts: { thresholdOverride?: number } = {},\n): Promise<EvalResultRow> {\n const threshold =\n opts.thresholdOverride ?? evalCase.threshold ?? DEFAULT_EVAL_THRESHOLD;\n\n if (evalCase.skipReason) {\n return {\n eval: evalCase.name,\n threshold,\n scores: [],\n status: \"skipped\",\n skipReason: evalCase.skipReason,\n // Keep the legacy boolean gate friendly: skipped rows do not fail CI.\n passed: true,\n avgScore: 0,\n durationMs: 0,\n };\n }\n\n let run: AgentRunOutput;\n if (evalCase.run) {\n run = await evalCase.run({\n input: evalCase.input,\n runAgent: (input) => runner.runAgent(input),\n });\n } else {\n run = await runner.runAgent(evalCase.input);\n }\n\n const scores: ScorerResult[] = [];\n for (const scorer of evalCase.scorers) {\n scores.push(await runScorer(scorer, run, runner, threshold));\n }\n\n const avgScore =\n scores.length > 0\n ? scores.reduce((s, r) => s + r.score, 0) / scores.length\n : 0;\n\n return {\n eval: evalCase.name,\n threshold,\n scores,\n // A run that errored, or any sub-threshold scorer, fails the case.\n passed: run.ok && scores.every((s) => s.passed),\n status: run.ok && scores.every((s) => s.passed) ? \"passed\" : \"failed\",\n avgScore,\n durationMs: run.durationMs,\n error: run.ok ? undefined : run.error,\n };\n}\n\n/** Run a batch of evals against one runner and aggregate a report. */\nexport async function runEvals(\n evals: Eval[],\n runner: AgentRunner,\n opts: { thresholdOverride?: number; persist?: boolean } = {},\n): Promise<EvalRunReport> {\n const results: EvalResultRow[] = [];\n for (const evalCase of evals) {\n const row = await scoreEval(evalCase, runner, opts);\n results.push(row);\n if (opts.persist && row.status !== \"skipped\") {\n await persistEvalRow(row).catch(() => {});\n }\n }\n\n const passed = results.filter((r) => r.passed).length;\n const skipped = results.filter((r) => r.status === \"skipped\").length;\n return {\n total: results.length,\n passed,\n failed: results.filter((r) => r.status !== \"skipped\" && !r.passed).length,\n skipped,\n results,\n };\n}\n\n/**\n * Best-effort write of one eval result to the observability eval store so a\n * dashboard can show CI eval history alongside production run evals. We write\n * one row per (eval × scorer), tagged `evalType: \"automated\"` with a synthetic\n * `eval:` run id.\n *\n * TODO(live-sampling): the same scorer list should also run on a sampled\n * fraction of *real* production runs. That hook belongs in the agent loop's\n * (not-yet-added) post-run processor seam: when a run finishes, roll the\n * configured sample rate and, if it hits, replay the run output through these\n * scorers and write the rows here. Wiring it now would require the in-loop\n * processor seam another wave is adding — so this is the single intended\n * attachment point, intentionally left as a note.\n */\nasync function persistEvalRow(row: EvalResultRow): Promise<void> {\n const runId = `eval:${row.eval}:${Date.now()}`;\n for (const s of row.scores) {\n const result: ObservabilityEvalResult = {\n id: crypto.randomUUID(),\n runId,\n threadId: null,\n userId: null,\n evalType: \"automated\",\n criteria: `eval:${row.eval}:${s.scorer}`,\n score: s.score,\n reasoning: s.reason ?? null,\n metadata: {\n source: \"cli-eval\",\n threshold: row.threshold,\n passed: s.passed,\n },\n createdAt: Date.now(),\n };\n await insertEvalResult(result);\n }\n}\n\n// ─── Discovery + loading ──────────────────────────────────────────────\n\nconst EVAL_FILE_RE = /\\.eval\\.(ts|js|mjs)$/;\nconst SKIP_DIRS = new Set([\"node_modules\", \"dist\", \".git\", \".output\", \"build\"]);\n\n/**\n * Walk `root` for eval files. Matches two conventions:\n * - any `**\\/*.eval.ts` (co-located with code), and\n * - any `*.ts` directly inside an `evals/` directory.\n * `pattern` further filters by substring of the relative path.\n */\nexport async function discoverEvalFiles(\n root: string,\n pattern?: string,\n): Promise<string[]> {\n const fs = await import(\"node:fs\");\n const out: string[] = [];\n\n function isEvalFile(full: string, parentName: string): boolean {\n const base = nodePath.basename(full);\n if (EVAL_FILE_RE.test(base)) return true;\n if (parentName === \"evals\" && /\\.(ts|js|mjs)$/.test(base)) {\n // Skip obvious support files inside evals/.\n return !/\\.(spec|test|d)\\.(ts|js|mjs)$/.test(base);\n }\n return false;\n }\n\n function walk(dir: string, parentName: string): void {\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = nodePath.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(\".\")) continue;\n walk(full, entry.name);\n } else if (entry.isFile() && isEvalFile(full, parentName)) {\n out.push(full);\n }\n }\n }\n\n walk(root, nodePath.basename(root));\n out.sort();\n\n if (!pattern) return out;\n return out.filter((f) => nodePath.relative(root, f).includes(pattern));\n}\n\n/** Pull `Eval` definitions out of a dynamically-imported eval module. */\nfunction extractEvals(mod: Record<string, unknown>): Eval[] {\n const candidates: unknown[] = [];\n if (mod.default !== undefined) candidates.push(mod.default);\n for (const [key, value] of Object.entries(mod)) {\n if (key === \"default\") continue;\n candidates.push(value);\n }\n\n const evals: Eval[] = [];\n for (const c of candidates.flat()) {\n if (\n c &&\n typeof c === \"object\" &&\n typeof (c as Eval).name === \"string\" &&\n Array.isArray((c as Eval).scorers) &&\n (c as Eval).input\n ) {\n evals.push(c as Eval);\n }\n }\n return evals;\n}\n\n/** Discover and import all eval files under `root`, returning their evals. */\nexport async function loadEvals(\n root: string,\n pattern?: string,\n): Promise<{ files: string[]; evals: Eval[] }> {\n const files = await discoverEvalFiles(root, pattern);\n const evals: Eval[] = [];\n for (const file of files) {\n const mod = (await import(pathToFileURL(file).href)) as Record<\n string,\n unknown\n >;\n evals.push(...extractEvals(mod));\n }\n return { files, evals };\n}\n\n// ─── High-level entry used by the CLI ─────────────────────────────────\n\nexport interface RunEvalSuiteOptions {\n /** App root to discover eval files + actions under. Defaults to cwd. */\n cwd?: string;\n /** Substring filter on the eval file path. */\n pattern?: string;\n /** Global threshold override (wins over per-eval thresholds). */\n thresholdOverride?: number;\n /** App actions to expose to the agent. Auto-discovered when omitted. */\n actions?: Record<string, ActionEntry>;\n /** System prompt for runs. */\n systemPrompt?: string;\n /** Write results to the observability eval store (default true). */\n persist?: boolean;\n /** Pre-built runner (tests inject this to avoid touching engine/loop). */\n runner?: AgentRunner;\n /** Pre-loaded evals (tests inject this to skip filesystem discovery). */\n evals?: Eval[];\n}\n\n/**\n * End-to-end: load evals, build a runner, score, report. The CLI wraps this\n * and maps `report.failed > 0` to a non-zero exit code (the CI gate).\n */\nexport async function runEvalSuite(\n opts: RunEvalSuiteOptions = {},\n): Promise<{ report: EvalRunReport; files: string[] }> {\n const cwd = opts.cwd ?? process.cwd();\n\n let files: string[] = [];\n let evals = opts.evals;\n if (!evals) {\n const loaded = await loadEvals(cwd, opts.pattern);\n files = loaded.files;\n evals = loaded.evals;\n }\n\n const needsRunner = evals.some((evalCase) => !evalCase.skipReason);\n const runner =\n opts.runner ??\n (needsRunner\n ? await createAgentRunner({\n actions: opts.actions ?? (await discoverActions(cwd)),\n systemPrompt: opts.systemPrompt,\n })\n : createInertRunner());\n\n const report = await runEvals(evals, runner, {\n thresholdOverride: opts.thresholdOverride,\n persist: opts.persist ?? true,\n });\n return { report, files };\n}\n\n/**\n * Discover the app's actions so the agent under test has the real tool\n * surface. Lazy-imports `autoDiscoverActions` to keep server-only deps out of\n * any browser bundle that might touch this module's types.\n */\nasync function discoverActions(\n cwd: string,\n): Promise<Record<string, ActionEntry>> {\n try {\n const { autoDiscoverActions } =\n await import(\"../server/action-discovery.js\");\n const actionsDir = nodePath.join(cwd, \"actions\");\n return await autoDiscoverActions(pathToFileURL(actionsDir + \"/\").href);\n } catch {\n return {};\n }\n}\n\nfunction createInertRunner(): AgentRunner {\n return {\n engine: {} as AgentRunner[\"engine\"],\n model: \"inert\",\n async runAgent() {\n throw new Error(\"Eval unexpectedly requested the agent runner\");\n },\n analyzeContext() {\n throw new Error(\"Eval unexpectedly requested analyze context\");\n },\n };\n}\n"]}
@@ -122,6 +122,12 @@ export interface EvalRunContext {
122
122
  export interface Eval {
123
123
  name: string;
124
124
  input: EvalInput;
125
+ /**
126
+ * Skip this case without running the agent or scorers. Use for opt-in
127
+ * suites that need secrets, live provider credentials, or manual/nightly
128
+ * gates. Skipped rows are reported distinctly and do not fail the suite.
129
+ */
130
+ skipReason?: string;
125
131
  /**
126
132
  * Optional override for how the agent is run for this case. Defaults to the
127
133
  * runner's headless `runAgent`. Use this to do custom setup (seed data,
@@ -144,6 +150,10 @@ export interface EvalResultRow {
144
150
  eval: string;
145
151
  threshold: number;
146
152
  scores: ScorerResult[];
153
+ /** Explicit row status for reports. Older consumers can still read `passed`. */
154
+ status?: "passed" | "failed" | "skipped";
155
+ /** Human-readable reason when `status` is `skipped`. */
156
+ skipReason?: string;
147
157
  /** True only when every scorer passed. */
148
158
  passed: boolean;
149
159
  /** Mean of the scorer scores, for at-a-glance ranking. */
@@ -157,6 +167,7 @@ export interface EvalRunReport {
157
167
  total: number;
158
168
  passed: number;
159
169
  failed: number;
170
+ skipped?: number;
160
171
  results: EvalResultRow[];
161
172
  }
162
173
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/eval/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/eval/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/eval/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG","sourcesContent":["/**\n * Types for the first-class evals primitive.\n *\n * This is a *test-case* eval system (define a prompt + expected behavior,\n * actually run the agent, score the output) — distinct from the post-hoc\n * run-scoring engine in `../observability/evals.ts`, which scores already-\n * completed production runs. The two are complementary:\n *\n * - `observability/evals.ts` — \"how did this real run do?\" (passive,\n * sampled, lives next to traces).\n * - `eval/*` (this module) — \"does the agent do the right thing on this\n * fixed input?\" (active, deterministic CI gate, run via the CLI).\n *\n * The pipeline shape (preprocess → analyze → generateScore → generateReason)\n * is borrowed from Mastra's scorer design: each scorer is a small, composable\n * 4-step pipeline so a single scorer can mix plain-JS checks with an LLM\n * judge while still producing one normalized 0..1 number plus a reason.\n */\n\nimport type { AgentEngine } from \"../agent/engine/types.js\";\n\n// ─── Agent run output ─────────────────────────────────────────────────\n\n/**\n * The result of actually running the agent loop for one eval input. Scorers\n * receive this as the thing under test. It is intentionally small and\n * transport-agnostic so a scorer never reaches into framework internals.\n */\nexport interface AgentRunOutput {\n /** Concatenated assistant text emitted across the run. */\n readonly text: string;\n /** Names of tools/actions the agent invoked, in call order. */\n readonly toolCalls: readonly string[];\n /** Whether the run completed without a terminal error event. */\n readonly ok: boolean;\n /** Terminal error message, if the run errored. */\n readonly error?: string;\n /** Synthetic run id, useful for writing eval rows to the observability store. */\n readonly runId: string;\n /** Wall-clock duration of the run in milliseconds. */\n readonly durationMs: number;\n}\n\n// ─── Scorer pipeline ──────────────────────────────────────────────────\n\n/**\n * Context handed to a scorer's analyze step when it needs an LLM judge. The\n * engine/model are resolved by the runner from the existing engine registry —\n * a scorer NEVER hardcodes a provider or model, keeping evals provider-\n * agnostic. `judge()` is a convenience that streams a single judging turn and\n * returns the raw model text.\n */\nexport interface ScorerAnalyzeContext {\n /** The resolved, provider-agnostic engine for LLM-judge scorers. */\n readonly engine: AgentEngine;\n /** The resolved model string for the engine. */\n readonly model: string;\n /**\n * Run a single LLM judging turn. Returns the model's raw text output. Used\n * by `llmJudge` and any custom LLM-backed analyze step. Provider-agnostic —\n * the engine is whatever the app/CLI resolved.\n */\n judge(opts: {\n systemPrompt?: string;\n prompt: string;\n maxOutputTokens?: number;\n signal?: AbortSignal;\n }): Promise<string>;\n}\n\n/**\n * A 4-step scoring pipeline (Mastra-style):\n *\n * preprocess(run) → x (transform the run/output; optional)\n * analyze(x, ctx) → analysis (plain JS OR an LLM judge; optional)\n * generateScore(a) → 0..1 (REQUIRED, normalized)\n * generateReason(...) → string (human-readable why; optional)\n *\n * Generics flow `Pre` (preprocess output) → `Ana` (analyze output) so a\n * single scorer is fully typed end-to-end.\n */\nexport interface Scorer<Pre = AgentRunOutput, Ana = Pre> {\n readonly name: string;\n preprocess?(run: AgentRunOutput): Pre | Promise<Pre>;\n analyze?(input: Pre, ctx: ScorerAnalyzeContext): Ana | Promise<Ana>;\n /** REQUIRED. Returns a normalized score in [0, 1]. */\n generateScore(analysis: Ana): number | Promise<number>;\n generateReason?(args: {\n run: AgentRunOutput;\n analysis: Ana;\n score: number;\n }): string | Promise<string>;\n}\n\n/** Definition object passed to `createScorer`. */\nexport interface ScorerDefinition<Pre = AgentRunOutput, Ana = Pre> {\n name: string;\n preprocess?(run: AgentRunOutput): Pre | Promise<Pre>;\n analyze?(input: Pre, ctx: ScorerAnalyzeContext): Ana | Promise<Ana>;\n generateScore(analysis: Ana): number | Promise<number>;\n generateReason?(args: {\n run: AgentRunOutput;\n analysis: Ana;\n score: number;\n }): string | Promise<string>;\n}\n\n// ─── Eval definition ──────────────────────────────────────────────────\n\n/** The prompt + optional setup that drives one eval case. */\nexport interface EvalInput {\n /** The user prompt / message sent to the agent. */\n prompt: string;\n /**\n * Optional prior conversation turns to seed before `prompt`. Each is a\n * plain { role, text } pair; the runner converts them to engine messages.\n */\n history?: Array<{ role: \"user\" | \"assistant\"; text: string }>;\n}\n\n/** Context passed to an eval's optional `run` override. */\nexport interface EvalRunContext {\n readonly input: EvalInput;\n /** The default agent runner — invoke it to run the agent loop as a caller. */\n runAgent(input: EvalInput): Promise<AgentRunOutput>;\n}\n\n/**\n * A named eval = one test case. `scorers` produce per-scorer rows; the case\n * passes when EVERY scorer meets `threshold` (default 0.5, overridable per\n * eval and globally from the CLI).\n */\nexport interface Eval {\n name: string;\n input: EvalInput;\n /**\n * Optional override for how the agent is run for this case. Defaults to the\n * runner's headless `runAgent`. Use this to do custom setup (seed data,\n * multi-turn) before/after the agent call.\n */\n run?(ctx: EvalRunContext): AgentRunOutput | Promise<AgentRunOutput>;\n scorers: Scorer<any, any>[];\n /** Minimum acceptable score (per scorer) in [0, 1]. Default 0.5. */\n threshold?: number;\n}\n\n// ─── Results ──────────────────────────────────────────────────────────\n\n/** One result row per (eval × scorer). Stores both the number AND the reason. */\nexport interface ScorerResult {\n scorer: string;\n score: number;\n reason?: string;\n passed: boolean;\n}\n\n/** Aggregated result for a single eval (all of its scorers). */\nexport interface EvalResultRow {\n eval: string;\n threshold: number;\n scores: ScorerResult[];\n /** True only when every scorer passed. */\n passed: boolean;\n /** Mean of the scorer scores, for at-a-glance ranking. */\n avgScore: number;\n durationMs: number;\n /** Terminal error if the agent run itself failed. */\n error?: string;\n}\n\n/** The full runner report. */\nexport interface EvalRunReport {\n total: number;\n passed: number;\n failed: number;\n results: EvalResultRow[];\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/eval/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG","sourcesContent":["/**\n * Types for the first-class evals primitive.\n *\n * This is a *test-case* eval system (define a prompt + expected behavior,\n * actually run the agent, score the output) — distinct from the post-hoc\n * run-scoring engine in `../observability/evals.ts`, which scores already-\n * completed production runs. The two are complementary:\n *\n * - `observability/evals.ts` — \"how did this real run do?\" (passive,\n * sampled, lives next to traces).\n * - `eval/*` (this module) — \"does the agent do the right thing on this\n * fixed input?\" (active, deterministic CI gate, run via the CLI).\n *\n * The pipeline shape (preprocess → analyze → generateScore → generateReason)\n * is borrowed from Mastra's scorer design: each scorer is a small, composable\n * 4-step pipeline so a single scorer can mix plain-JS checks with an LLM\n * judge while still producing one normalized 0..1 number plus a reason.\n */\n\nimport type { AgentEngine } from \"../agent/engine/types.js\";\n\n// ─── Agent run output ─────────────────────────────────────────────────\n\n/**\n * The result of actually running the agent loop for one eval input. Scorers\n * receive this as the thing under test. It is intentionally small and\n * transport-agnostic so a scorer never reaches into framework internals.\n */\nexport interface AgentRunOutput {\n /** Concatenated assistant text emitted across the run. */\n readonly text: string;\n /** Names of tools/actions the agent invoked, in call order. */\n readonly toolCalls: readonly string[];\n /** Whether the run completed without a terminal error event. */\n readonly ok: boolean;\n /** Terminal error message, if the run errored. */\n readonly error?: string;\n /** Synthetic run id, useful for writing eval rows to the observability store. */\n readonly runId: string;\n /** Wall-clock duration of the run in milliseconds. */\n readonly durationMs: number;\n}\n\n// ─── Scorer pipeline ──────────────────────────────────────────────────\n\n/**\n * Context handed to a scorer's analyze step when it needs an LLM judge. The\n * engine/model are resolved by the runner from the existing engine registry —\n * a scorer NEVER hardcodes a provider or model, keeping evals provider-\n * agnostic. `judge()` is a convenience that streams a single judging turn and\n * returns the raw model text.\n */\nexport interface ScorerAnalyzeContext {\n /** The resolved, provider-agnostic engine for LLM-judge scorers. */\n readonly engine: AgentEngine;\n /** The resolved model string for the engine. */\n readonly model: string;\n /**\n * Run a single LLM judging turn. Returns the model's raw text output. Used\n * by `llmJudge` and any custom LLM-backed analyze step. Provider-agnostic —\n * the engine is whatever the app/CLI resolved.\n */\n judge(opts: {\n systemPrompt?: string;\n prompt: string;\n maxOutputTokens?: number;\n signal?: AbortSignal;\n }): Promise<string>;\n}\n\n/**\n * A 4-step scoring pipeline (Mastra-style):\n *\n * preprocess(run) → x (transform the run/output; optional)\n * analyze(x, ctx) → analysis (plain JS OR an LLM judge; optional)\n * generateScore(a) → 0..1 (REQUIRED, normalized)\n * generateReason(...) → string (human-readable why; optional)\n *\n * Generics flow `Pre` (preprocess output) → `Ana` (analyze output) so a\n * single scorer is fully typed end-to-end.\n */\nexport interface Scorer<Pre = AgentRunOutput, Ana = Pre> {\n readonly name: string;\n preprocess?(run: AgentRunOutput): Pre | Promise<Pre>;\n analyze?(input: Pre, ctx: ScorerAnalyzeContext): Ana | Promise<Ana>;\n /** REQUIRED. Returns a normalized score in [0, 1]. */\n generateScore(analysis: Ana): number | Promise<number>;\n generateReason?(args: {\n run: AgentRunOutput;\n analysis: Ana;\n score: number;\n }): string | Promise<string>;\n}\n\n/** Definition object passed to `createScorer`. */\nexport interface ScorerDefinition<Pre = AgentRunOutput, Ana = Pre> {\n name: string;\n preprocess?(run: AgentRunOutput): Pre | Promise<Pre>;\n analyze?(input: Pre, ctx: ScorerAnalyzeContext): Ana | Promise<Ana>;\n generateScore(analysis: Ana): number | Promise<number>;\n generateReason?(args: {\n run: AgentRunOutput;\n analysis: Ana;\n score: number;\n }): string | Promise<string>;\n}\n\n// ─── Eval definition ──────────────────────────────────────────────────\n\n/** The prompt + optional setup that drives one eval case. */\nexport interface EvalInput {\n /** The user prompt / message sent to the agent. */\n prompt: string;\n /**\n * Optional prior conversation turns to seed before `prompt`. Each is a\n * plain { role, text } pair; the runner converts them to engine messages.\n */\n history?: Array<{ role: \"user\" | \"assistant\"; text: string }>;\n}\n\n/** Context passed to an eval's optional `run` override. */\nexport interface EvalRunContext {\n readonly input: EvalInput;\n /** The default agent runner — invoke it to run the agent loop as a caller. */\n runAgent(input: EvalInput): Promise<AgentRunOutput>;\n}\n\n/**\n * A named eval = one test case. `scorers` produce per-scorer rows; the case\n * passes when EVERY scorer meets `threshold` (default 0.5, overridable per\n * eval and globally from the CLI).\n */\nexport interface Eval {\n name: string;\n input: EvalInput;\n /**\n * Skip this case without running the agent or scorers. Use for opt-in\n * suites that need secrets, live provider credentials, or manual/nightly\n * gates. Skipped rows are reported distinctly and do not fail the suite.\n */\n skipReason?: string;\n /**\n * Optional override for how the agent is run for this case. Defaults to the\n * runner's headless `runAgent`. Use this to do custom setup (seed data,\n * multi-turn) before/after the agent call.\n */\n run?(ctx: EvalRunContext): AgentRunOutput | Promise<AgentRunOutput>;\n scorers: Scorer<any, any>[];\n /** Minimum acceptable score (per scorer) in [0, 1]. Default 0.5. */\n threshold?: number;\n}\n\n// ─── Results ──────────────────────────────────────────────────────────\n\n/** One result row per (eval × scorer). Stores both the number AND the reason. */\nexport interface ScorerResult {\n scorer: string;\n score: number;\n reason?: string;\n passed: boolean;\n}\n\n/** Aggregated result for a single eval (all of its scorers). */\nexport interface EvalResultRow {\n eval: string;\n threshold: number;\n scores: ScorerResult[];\n /** Explicit row status for reports. Older consumers can still read `passed`. */\n status?: \"passed\" | \"failed\" | \"skipped\";\n /** Human-readable reason when `status` is `skipped`. */\n skipReason?: string;\n /** True only when every scorer passed. */\n passed: boolean;\n /** Mean of the scorer scores, for at-a-glance ranking. */\n avgScore: number;\n durationMs: number;\n /** Terminal error if the agent run itself failed. */\n error?: string;\n}\n\n/** The full runner report. */\nexport interface EvalRunReport {\n total: number;\n passed: number;\n failed: number;\n skipped?: number;\n results: EvalResultRow[];\n}\n"]}
@@ -3,18 +3,18 @@ declare const _default: import("../../action.js").ActionDefinition<{
3
3
  url?: string;
4
4
  filename?: string;
5
5
  }, {
6
+ id?: undefined;
6
7
  error: string;
7
8
  configured?: undefined;
8
9
  connectPath?: undefined;
9
10
  url?: undefined;
10
- id?: undefined;
11
11
  provider?: undefined;
12
12
  } | {
13
+ id?: undefined;
13
14
  error: string;
14
15
  configured: boolean;
15
16
  connectPath: string;
16
17
  url?: undefined;
17
- id?: undefined;
18
18
  provider?: undefined;
19
19
  } | {
20
20
  error?: undefined;
@@ -56,13 +56,13 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
56
56
  ok?: undefined;
57
57
  summary?: undefined;
58
58
  spans?: undefined;
59
- error: any;
60
59
  id?: undefined;
60
+ error: any;
61
61
  } | {
62
62
  error?: undefined;
63
63
  summary?: undefined;
64
64
  spans?: undefined;
65
- ok: boolean;
66
65
  id?: undefined;
66
+ ok: boolean;
67
67
  }>>;
68
68
  //# sourceMappingURL=routes.d.ts.map
@@ -15,7 +15,7 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
15
15
  error: string;
16
16
  ok?: undefined;
17
17
  } | {
18
- error?: undefined;
19
18
  ok: boolean;
19
+ error?: undefined;
20
20
  }>>;
21
21
  //# sourceMappingURL=routes.d.ts.map
@@ -49,11 +49,11 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
49
49
  }>;
50
50
  /** DELETE /_agent-native/resources/:id — delete a resource */
51
51
  export declare function handleDeleteResource(event: any): Promise<{
52
- ok?: undefined;
53
52
  error: string;
53
+ ok?: undefined;
54
54
  } | {
55
- error?: undefined;
56
55
  ok: boolean;
56
+ error?: undefined;
57
57
  }>;
58
58
  /** POST /_agent-native/resources/upload — upload a file as a resource */
59
59
  export declare function handleUploadResource(event: any): Promise<import("./store.js").Resource | {
@@ -73,9 +73,9 @@ export declare function handleUploadResource(event: any): Promise<import("./stor
73
73
  runId: string | null;
74
74
  expiresAt: number | null;
75
75
  metadata: string | null;
76
- error?: undefined;
77
76
  url: string;
78
77
  provider: string;
78
+ error?: undefined;
79
79
  }>;
80
80
  export {};
81
81
  //# sourceMappingURL=handlers.d.ts.map
@@ -20,7 +20,7 @@ export declare function createTranscribeVoiceHandler(): import("h3").EventHandle
20
20
  error: string;
21
21
  text?: undefined;
22
22
  } | {
23
- error?: undefined;
24
23
  text: string;
24
+ error?: undefined;
25
25
  }>>;
26
26
  //# sourceMappingURL=transcribe-voice.d.ts.map
@@ -2,9 +2,9 @@
2
2
  name: reliable-mutations
3
3
  description: >-
4
4
  How the agent must perform writes so they actually persist under the hosted
5
- ~40s run budget. Use whenever you create, update, delete, or batch-write app
6
- data — especially "do this for many items" loops, or any task where the user
7
- expects N things to end up saved.
5
+ foreground run budget and long-running background handoffs. Use whenever you
6
+ create, update, delete, or batch-write app data — especially "do this for many
7
+ items" loops, or any task where the user expects N things to end up saved.
8
8
  ---
9
9
 
10
10
  # Reliable Mutations
@@ -18,15 +18,12 @@ tool ✓ alone.
18
18
 
19
19
  ## Why
20
20
 
21
- Hosted agent runs have a ~40s soft budget (it exists to hand off cleanly under
22
- the upstream gateway/function walls it is correct and is not raisable; see the
23
- durable-agent-runs design doc). When you loop many sequential writes inside one
24
- turn, the budget can cut you off mid-loop. The run resumes in a new chunk, but
25
- the resume often re-does earlier steps instead of advancing, so the loop churns
26
- and the *saved* result ends up partial — or empty — even though each individual
27
- tool call appeared to succeed. The user gets told "done" while the data says
28
- otherwise. One atomic call commits or fails as a unit; verification turns a
29
- hopeful ✓ into a fact.
21
+ Hosted foreground agent runs have a short soft budget so they can hand off
22
+ cleanly under synchronous serverless walls. Durable background runs get a much
23
+ longer budget, but they still should not rely on loops of many small writes:
24
+ continuations can retry the same intent and leave partial state if each item is
25
+ committed separately. One atomic call commits or fails as a unit; verification
26
+ turns a hopeful into a fact.
30
27
 
31
28
  ## How
32
29
 
@@ -34,11 +31,12 @@ hopeful ✓ into a fact.
34
31
  many, set all, bulk update), pass the full batch in one call so it commits
35
32
  atomically. Check the action surface for a batch/plural form before reaching
36
33
  for a loop.
37
- 2. **Do not loop many small writes under the run budget.** A sequence of N
38
- per-item writes in one turn will race the ~40s cutoff and can leave partial
39
- or no state. If no batch action exists, that is a gap in the action layer —
40
- add or extend an action that accepts the batch (see the `actions` skill)
41
- rather than papering over it with a loop.
34
+ 2. **Do not loop many small writes under any run budget.** A sequence of N
35
+ per-item writes can still leave partial or no state when a foreground run
36
+ hands off, a background run continues, or an upstream provider fails. If no
37
+ batch action exists, that is a gap in the action layer add or extend an
38
+ action that accepts the batch (see the `actions` skill) rather than papering
39
+ over it with a loop.
42
40
  3. **Verify the end state after writing.** Re-read the data (a list/read action,
43
41
  a count query) and confirm the result matches intent — the right number of
44
42
  rows, the expected ids/fields. Do this before you tell the user it worked.
@@ -90,13 +90,14 @@ export default defineEval({
90
90
 
91
91
  An eval passes only when **every** scorer meets the threshold. Key `defineEval` fields:
92
92
 
93
- | Field | Type | Notes |
94
- | ----------- | --------------------- | ------------------------------------------------------------- |
95
- | `name` | string | Required. Shown in the report. |
96
- | `input` | `{ prompt, history }` | Required `prompt`; optional prior `{ role, text }` turns. |
97
- | `scorers` | `Scorer[]` | Required, at least one. |
98
- | `threshold` | number `0..1` | Per-scorer pass bar. Default `0.5`; overridable from the CLI. |
99
- | `run` | function | Optional override for custom setup (seed data, multi-turn). |
93
+ | Field | Type | Notes |
94
+ | ------------ | --------------------- | --------------------------------------------------------------------------------------------------------------- |
95
+ | `name` | string | Required. Shown in the report. |
96
+ | `input` | `{ prompt, history }` | Required `prompt`; optional prior `{ role, text }` turns. |
97
+ | `scorers` | `Scorer[]` | Required, at least one, unless `skipReason` is set. |
98
+ | `threshold` | number `0..1` | Per-scorer pass bar. Default `0.5`; overridable from the CLI. |
99
+ | `run` | function | Optional override for custom setup (seed data, multi-turn). |
100
+ | `skipReason` | string | Optional reason to skip this eval without running the agent; useful for manual/nightly gates that need secrets. |
100
101
 
101
102
  The agent run handed to scorers is small and transport-agnostic:
102
103
 
@@ -225,11 +226,32 @@ The command discovers `**/*.eval.ts` and `evals/*.ts` under the current app, run
225
226
 
226
227
  Exit codes:
227
228
 
228
- | Code | Meaning |
229
- | ---- | --------------------------------------------------------------- |
230
- | `0` | All evals passed _or_ no eval files were found (CI-friendly). |
231
- | `1` | At least one eval scored below threshold, or the suite errored. |
232
- | `2` | Bad arguments (e.g. `--threshold` outside `[0, 1]`). |
229
+ | Code | Meaning |
230
+ | ---- | -------------------------------------------------------------------------------- |
231
+ | `0` | All evals passed, evals were skipped, or no eval files were found (CI-friendly). |
232
+ | `1` | At least one eval scored below threshold, or the suite errored. |
233
+ | `2` | Bad arguments (e.g. `--threshold` outside `[0, 1]`). |
234
+
235
+ ### Skipping gated evals {#skipping}
236
+
237
+ Use `skipReason` when an eval suite is intentionally gated behind manual,
238
+ nightly, or secret-backed execution:
239
+
240
+ ```ts
241
+ export default defineEval({
242
+ name: "provider-backed source sync",
243
+ input: { prompt: "Refresh the source and summarize the changes." },
244
+ skipReason: process.env.SOURCE_SYNC_EVALS
245
+ ? undefined
246
+ : "Skipped because SOURCE_SYNC_EVALS is unset",
247
+ scorers: process.env.SOURCE_SYNC_EVALS ? [contains("updated")] : [],
248
+ });
249
+ ```
250
+
251
+ Skipped evals do not run the agent or scorers, do not fail the suite, and are
252
+ reported distinctly with `status: "skipped"` and `skipReason` in JSON output.
253
+ Use this for expensive or credential-dependent evals; keep cheap deterministic
254
+ coverage in normal PR CI.
233
255
 
234
256
  ### As a CI deploy gate {#ci}
235
257
 
@@ -231,6 +231,13 @@ agent-native eval --threshold 0.8 # override every eval's pass threshold (0..
231
231
  | `1` | تم تسجيل تقييم واحد على الأقل أقل من الحد الأدنى، أو حدث خطأ في المجموعة. |
232
232
  | `2` | وسيطات غير صالحة (على سبيل المثال، `--threshold` خارج `[0, 1]`). |
233
233
 
234
+ ### تخطي التقييمات المحكومة {#skipping}
235
+
236
+ استخدم `skipReason` عندما تكون مجموعة التقييمات مخصصة عمدا للتشغيل اليدوي أو
237
+ الليلي أو المعتمد على الأسرار. لا تشغل التقييمات المتخطاة الوكيل أو أدوات
238
+ التسجيل، ولا تفشل المجموعة، وتظهر في JSON مع `status: "skipped"` و
239
+ `skipReason`. أبق التغطية الحتمية الرخيصة في CI العادي لطلبات السحب.
240
+
234
241
  ### كبوابة نشر CI {#ci}
235
242
 
236
243
  قم بإضافته إلى المسار الذي يتم تشغيله قبل النشر:
@@ -231,6 +231,14 @@ Exit-Codes:
231
231
  | `1` | Mindestens eine Bewertung lag unter dem Schwellenwert oder die Suite ist fehlerhaft. |
232
232
  | `2` | Ungültige Argumente (z. B. `--threshold` außerhalb von `[0, 1]`). |
233
233
 
234
+ ### Gated Evals überspringen {#skipping}
235
+
236
+ Verwenden Sie `skipReason`, wenn eine Eval-Suite absichtlich nur manuell,
237
+ nachts oder mit Secrets ausgeführt werden soll. Übersprungene Evals führen
238
+ weder Agent noch Scorer aus, lassen die Suite nicht fehlschlagen und erscheinen
239
+ in der JSON-Ausgabe mit `status: "skipped"` und `skipReason`. Günstige
240
+ deterministische Abdeckung bleibt im normalen PR-CI.
241
+
234
242
  ### Als CI-Deploy-Gate {#ci}
235
243
 
236
244
  Fügen Sie es der Pipeline hinzu, die vor einer Bereitstellung ausgeführt wird:
@@ -231,6 +231,14 @@ Códigos de salida:
231
231
  | `1` | Al menos una evaluación obtuvo una puntuación inferior al umbral o la suite tuvo un error. |
232
232
  | `2` | Malos argumentos (por ejemplo, `--threshold` fuera de `[0, 1]`). |
233
233
 
234
+ ### Omitir evaluaciones gated {#skipping}
235
+
236
+ Use `skipReason` cuando una suite de evaluaciones esté reservada
237
+ intencionalmente para ejecución manual, nocturna o con secretos. Las
238
+ evaluaciones omitidas no ejecutan el agente ni los scorers, no hacen fallar la
239
+ suite y aparecen en JSON con `status: "skipped"` y `skipReason`. Mantenga la
240
+ cobertura determinista barata en el CI normal de PR.
241
+
234
242
  ### Como puerta de implementación de CI {#ci}
235
243
 
236
244
  Agréguelo al proceso que se ejecuta antes de una implementación:
@@ -231,6 +231,14 @@ Codes de sortie :
231
231
  | `1` | Au moins une évaluation a obtenu un score inférieur au seuil, ou la suite a commis une erreur. |
232
232
  | `2` | Mauvais arguments (par exemple `--threshold` en dehors de `[0, 1]`). |
233
233
 
234
+ ### Ignorer les évaluations gated {#skipping}
235
+
236
+ Utilisez `skipReason` lorsqu'une suite d'évaluations est volontairement réservée
237
+ à une exécution manuelle, nocturne ou dépendante de secrets. Les évaluations
238
+ ignorées n'exécutent ni l'agent ni les scorers, ne font pas échouer la suite, et
239
+ apparaissent dans la sortie JSON avec `status: "skipped"` et `skipReason`.
240
+ Gardez la couverture déterministe peu coûteuse dans le CI normal des PR.
241
+
234
242
  ### En tant que porte de déploiement CI {#ci}
235
243
 
236
244
  Ajoutez-le au pipeline qui s'exécute avant un déploiement :
@@ -229,6 +229,14 @@ agent-native eval --threshold 0.8 # override every eval's pass threshold (0..
229
229
  | `1` | कम से कम एक ईवल ने सीमा से नीचे स्कोर किया, या सुइट में त्रुटि हुई। |
230
230
  | `2` | खराब तर्क (उदाहरण के लिए `[0, 1]` के बाहर `--threshold`)। |
231
231
 
232
+ ### gated evals छोड़ना {#skipping}
233
+
234
+ जब कोई eval suite केवल manual, nightly, या secret-backed execution के लिए हो,
235
+ तो `skipReason` का उपयोग करें। छोड़े गए evals agent या scorers नहीं चलाते,
236
+ suite को fail नहीं करते, और JSON output में `status: "skipped"` और
237
+ `skipReason` के साथ दिखते हैं। सस्ती deterministic coverage को सामान्य PR CI
238
+ में रखें।
239
+
232
240
  ### सीआई परिनियोजन गेट के रूप में {#ci}
233
241
 
234
242
  इसे उस पाइपलाइन में जोड़ें जो परिनियोजन से पहले चलती है:
@@ -231,6 +231,13 @@ agent-native eval --threshold 0.8 # override every eval's pass threshold (0..
231
231
  | `1` | 少なくとも 1 つの評価スコアがしきい値を下回ったか、スイートでエラーが発生しました。 |
232
232
  | `2` | 不正な引数 (例: `[0, 1]` の外の `--threshold`)。 |
233
233
 
234
+ ### gated eval をスキップする {#skipping}
235
+
236
+ 手動、夜間、または secret が必要な eval スイートには `skipReason` を使い
237
+ ます。スキップされた eval はエージェントや scorer を実行せず、スイート
238
+ を失敗させず、JSON 出力では `status: "skipped"` と `skipReason` とし
239
+ て表示されます。安価で決定的なカバレッジは通常の PR CI に残します。
240
+
234
241
  ### CI デプロイゲートとして {#ci}
235
242
 
236
243
  デプロイ前に実行されるパイプラインに追加します。
@@ -231,6 +231,13 @@ agent-native eval --threshold 0.8 # override every eval's pass threshold (0..
231
231
  | `1` | 최소 하나의 평가가 임계값 미만의 점수를 얻었거나 제품군에 오류가 발생했습니다. |
232
232
  | `2` | 잘못된 인수(예: `[0, 1]` 외부의 `--threshold`). |
233
233
 
234
+ ### 게이트된 평가 건너뛰기 {#skipping}
235
+
236
+ 수동, 야간 또는 시크릿이 필요한 평가 스위트에는 `skipReason`를 사용하세요.
237
+ 건너뛴 평가는 에이전트나 scorer를 실행하지 않고, 스위트를 실패시키지
238
+ 않으며, JSON 출력에 `status: "skipped"` 및 `skipReason`로 표시됩니다.
239
+ 저렴한 결정적 커버리지는 일반 PR CI에 유지하세요.
240
+
234
241
  ### CI 배포 게이트로 {#ci}
235
242
 
236
243
  배포 전에 실행되는 파이프라인에 추가하세요:
@@ -231,6 +231,14 @@ Códigos de saída:
231
231
  | `1` | Pelo menos uma avaliação com pontuação abaixo do limite ou o conjunto apresentou erro. |
232
232
  | `2` | Argumentos incorretos (por exemplo, `--threshold` fora de `[0, 1]`). |
233
233
 
234
+ ### Ignorar evals gated {#skipping}
235
+
236
+ Use `skipReason` quando uma suíte de evals for intencionalmente reservada para
237
+ execução manual, noturna ou dependente de secrets. Evals ignorados não executam
238
+ o agente nem os scorers, não fazem a suíte falhar e aparecem no JSON com
239
+ `status: "skipped"` e `skipReason`. Mantenha cobertura determinística barata no
240
+ CI normal de PR.
241
+
234
242
  ### Como porta de implantação de CI {#ci}
235
243
 
236
244
  Adicione-o ao pipeline executado antes da implantação:
@@ -229,6 +229,13 @@ agent-native eval --threshold 0.8 # override every eval's pass threshold (0..
229
229
  | `1` | 至少有一项评估得分低于阈值,或者套件出错。 |
230
230
  | `2` | 错误的参数(例如 `--threshold` 位于 `[0, 1]` 之外)。 |
231
231
 
232
+ ### 跳过受控评估 {#skipping}
233
+
234
+ 当某个评估套件只应在手动、夜间或具备密钥的环境中运行时,请使用
235
+ `skipReason`。被跳过的评估不会运行代理或 scorer,不会让套件失败,并会
236
+ 在 JSON 输出中显示 `status: "skipped"` 和 `skipReason`。廉价的确定性覆
237
+ 盖应保留在普通 PR CI 中。
238
+
232
239
  ### 作为 CI 部署门 {#ci}
233
240
 
234
241
  将其添加到部署之前运行的管道: