@agent-native/core 0.84.0 → 0.84.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +6 -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/package.json +1 -1
  15. package/corpus/core/src/eval/define-eval.ts +4 -1
  16. package/corpus/core/src/eval/report.ts +23 -8
  17. package/corpus/core/src/eval/runner.ts +41 -6
  18. package/corpus/core/src/eval/types.ts +11 -0
  19. package/corpus/templates/content/AGENTS.md +9 -2
  20. package/corpus/templates/content/actions/_database-row-batch.ts +230 -0
  21. package/corpus/templates/content/actions/_database-utils.ts +17 -9
  22. package/corpus/templates/content/actions/_notion-action-utils.ts +26 -0
  23. package/corpus/templates/content/actions/connect-notion-status.ts +13 -4
  24. package/corpus/templates/content/actions/create-and-link-notion-page.ts +23 -0
  25. package/corpus/templates/content/actions/delete-database-items.ts +55 -0
  26. package/corpus/templates/content/actions/delete-document.ts +4 -4
  27. package/corpus/templates/content/actions/disconnect-notion.ts +16 -0
  28. package/corpus/templates/content/actions/duplicate-database-item.ts +1 -1
  29. package/corpus/templates/content/actions/duplicate-database-items.ts +191 -0
  30. package/corpus/templates/content/actions/link-notion-page.ts +10 -7
  31. package/corpus/templates/content/actions/list-notion-links.ts +3 -4
  32. package/corpus/templates/content/actions/pull-notion-page.ts +7 -9
  33. package/corpus/templates/content/actions/push-notion-page.ts +7 -9
  34. package/corpus/templates/content/actions/refresh-notion-sync-status.ts +24 -0
  35. package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +23 -0
  36. package/corpus/templates/content/actions/search-notion-pages.ts +67 -0
  37. package/corpus/templates/content/actions/unlink-notion-page.ts +23 -0
  38. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +27 -34
  39. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +16 -13
  40. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +10 -10
  41. package/corpus/templates/content/app/components/editor/NotionConflictBanner.tsx +1 -1
  42. package/corpus/templates/content/app/components/editor/NotionSyncBar.tsx +18 -9
  43. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +27 -34
  44. package/corpus/templates/content/app/components/editor/database/navigation-state.ts +10 -4
  45. package/corpus/templates/content/app/components/sidebar/NotionButton.tsx +32 -17
  46. package/corpus/templates/content/app/hooks/use-content-database.ts +35 -0
  47. package/corpus/templates/content/app/hooks/use-notion.ts +108 -99
  48. package/corpus/templates/content/package.json +3 -0
  49. package/corpus/templates/content/parity/README.md +69 -0
  50. package/corpus/templates/content/parity/eval-scenarios.ts +118 -0
  51. package/corpus/templates/content/parity/exceptions.allowlist.ts +17 -0
  52. package/corpus/templates/content/parity/matrix.md +28 -0
  53. package/corpus/templates/content/parity/matrix.ts +606 -0
  54. package/corpus/templates/content/parity/matrix.types.ts +42 -0
  55. package/corpus/templates/content/parity/parity-evals.eval.ts +4 -0
  56. package/corpus/templates/content/parity/render-matrix.ts +90 -0
  57. package/corpus/templates/content/parity/scenario-to-eval.ts +57 -0
  58. package/corpus/templates/content/shared/api.ts +11 -0
  59. package/dist/collab/awareness.d.ts +2 -2
  60. package/dist/collab/awareness.d.ts.map +1 -1
  61. package/dist/collab/routes.d.ts +1 -1
  62. package/dist/eval/define-eval.d.ts.map +1 -1
  63. package/dist/eval/define-eval.js +2 -1
  64. package/dist/eval/define-eval.js.map +1 -1
  65. package/dist/eval/report.d.ts.map +1 -1
  66. package/dist/eval/report.js +19 -4
  67. package/dist/eval/report.js.map +1 -1
  68. package/dist/eval/runner.d.ts.map +1 -1
  69. package/dist/eval/runner.js +38 -6
  70. package/dist/eval/runner.js.map +1 -1
  71. package/dist/eval/types.d.ts +11 -0
  72. package/dist/eval/types.d.ts.map +1 -1
  73. package/dist/eval/types.js.map +1 -1
  74. package/dist/notifications/routes.d.ts +3 -3
  75. package/dist/progress/routes.d.ts +1 -1
  76. package/dist/resources/handlers.d.ts +1 -1
  77. package/docs/content/evals.mdx +34 -12
  78. package/docs/content/locales/ar-SA/evals.mdx +7 -0
  79. package/docs/content/locales/de-DE/evals.mdx +8 -0
  80. package/docs/content/locales/es-ES/evals.mdx +8 -0
  81. package/docs/content/locales/fr-FR/evals.mdx +8 -0
  82. package/docs/content/locales/hi-IN/evals.mdx +8 -0
  83. package/docs/content/locales/ja-JP/evals.mdx +7 -0
  84. package/docs/content/locales/ko-KR/evals.mdx +7 -0
  85. package/docs/content/locales/pt-BR/evals.mdx +8 -0
  86. package/docs/content/locales/zh-CN/evals.mdx +7 -0
  87. package/docs/content/locales/zh-TW/evals.mdx +7 -0
  88. package/package.json +1 -1
  89. package/corpus/templates/content/server/routes/api/notion/disconnect.post.ts +0 -12
package/corpus/README.md CHANGED
@@ -28,4 +28,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
28
28
  ## Generated Counts
29
29
 
30
30
  - core files: 2043
31
- - template files: 4877
31
+ - template files: 4895
@@ -1,5 +1,11 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.84.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 87806ef: Report intentionally gated eval cases as skipped, keep skipped suites from setting up agent runners, and avoid action/engine setup for eval cases that fully short-circuit with custom run handlers.
8
+
3
9
  ## 0.84.0
4
10
 
5
11
  ### Minor Changes
@@ -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
  将其添加到部署之前运行的管道:
@@ -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
  將其新增到部署之前執行的管道:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.84.0",
3
+ "version": "0.84.1",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -35,7 +35,10 @@ export function defineEval(spec: Eval): Eval {
35
35
  if (!spec.input || typeof spec.input.prompt !== "string") {
36
36
  throw new Error(`defineEval("${spec.name}"): \`input.prompt\` is required`);
37
37
  }
38
- if (!Array.isArray(spec.scorers) || spec.scorers.length === 0) {
38
+ if (
39
+ (!Array.isArray(spec.scorers) || spec.scorers.length === 0) &&
40
+ !spec.skipReason
41
+ ) {
39
42
  throw new Error(
40
43
  `defineEval("${spec.name}"): at least one scorer is required`,
41
44
  );
@@ -27,13 +27,19 @@ export function formatReport(report: EvalRunReport): string {
27
27
  lines.push(" ─────");
28
28
 
29
29
  for (const row of report.results) {
30
- const mark = row.passed ? "✓" : "✗";
30
+ const mark = row.status === "skipped" ? "-" : row.passed ? "✓" : "✗";
31
31
  lines.push("");
32
- lines.push(
33
- ` ${mark} ${row.eval} (avg ${pct(row.avgScore)}, threshold ${pct(
34
- row.threshold,
35
- )})`,
36
- );
32
+ if (row.status === "skipped") {
33
+ lines.push(` ${mark} ${row.eval} (skipped)`);
34
+ lines.push(` reason: ${row.skipReason ?? "No reason provided"}`);
35
+ continue;
36
+ } else {
37
+ lines.push(
38
+ ` ${mark} ${row.eval} (avg ${pct(row.avgScore)}, threshold ${pct(
39
+ row.threshold,
40
+ )})`,
41
+ );
42
+ }
37
43
  if (row.error) {
38
44
  lines.push(` ⚠ run error: ${row.error}`);
39
45
  }
@@ -50,9 +56,18 @@ export function formatReport(report: EvalRunReport): string {
50
56
 
51
57
  lines.push("");
52
58
  lines.push(" ─────");
53
- const verdict = report.failed === 0 ? "PASS" : "FAIL";
59
+ const skipped = report.skipped ?? 0;
60
+ const executedTotal = report.total - skipped;
61
+ const executedPassed = report.passed - skipped;
62
+ const verdict =
63
+ executedTotal === 0 && skipped > 0
64
+ ? "SKIPPED"
65
+ : report.failed === 0
66
+ ? "PASS"
67
+ : "FAIL";
54
68
  lines.push(
55
- ` ${verdict}: ${report.passed}/${report.total} evals passed` +
69
+ ` ${verdict}: ${executedPassed}/${executedTotal} evals passed` +
70
+ (skipped > 0 ? `, ${skipped} skipped` : "") +
56
71
  (report.failed > 0 ? `, ${report.failed} below threshold` : ""),
57
72
  );
58
73
  lines.push("");
@@ -78,6 +78,20 @@ export async function scoreEval(
78
78
  const threshold =
79
79
  opts.thresholdOverride ?? evalCase.threshold ?? DEFAULT_EVAL_THRESHOLD;
80
80
 
81
+ if (evalCase.skipReason) {
82
+ return {
83
+ eval: evalCase.name,
84
+ threshold,
85
+ scores: [],
86
+ status: "skipped",
87
+ skipReason: evalCase.skipReason,
88
+ // Keep the legacy boolean gate friendly: skipped rows do not fail CI.
89
+ passed: true,
90
+ avgScore: 0,
91
+ durationMs: 0,
92
+ };
93
+ }
94
+
81
95
  let run: AgentRunOutput;
82
96
  if (evalCase.run) {
83
97
  run = await evalCase.run({
@@ -104,6 +118,7 @@ export async function scoreEval(
104
118
  scores,
105
119
  // A run that errored, or any sub-threshold scorer, fails the case.
106
120
  passed: run.ok && scores.every((s) => s.passed),
121
+ status: run.ok && scores.every((s) => s.passed) ? "passed" : "failed",
107
122
  avgScore,
108
123
  durationMs: run.durationMs,
109
124
  error: run.ok ? undefined : run.error,
@@ -120,14 +135,18 @@ export async function runEvals(
120
135
  for (const evalCase of evals) {
121
136
  const row = await scoreEval(evalCase, runner, opts);
122
137
  results.push(row);
123
- if (opts.persist) await persistEvalRow(row).catch(() => {});
138
+ if (opts.persist && row.status !== "skipped") {
139
+ await persistEvalRow(row).catch(() => {});
140
+ }
124
141
  }
125
142
 
126
143
  const passed = results.filter((r) => r.passed).length;
144
+ const skipped = results.filter((r) => r.status === "skipped").length;
127
145
  return {
128
146
  total: results.length,
129
147
  passed,
130
- failed: results.length - passed,
148
+ failed: results.filter((r) => r.status !== "skipped" && !r.passed).length,
149
+ skipped,
131
150
  results,
132
151
  };
133
152
  }
@@ -301,12 +320,15 @@ export async function runEvalSuite(
301
320
  evals = loaded.evals;
302
321
  }
303
322
 
323
+ const needsRunner = evals.some((evalCase) => !evalCase.skipReason);
304
324
  const runner =
305
325
  opts.runner ??
306
- (await createAgentRunner({
307
- actions: opts.actions ?? (await discoverActions(cwd)),
308
- systemPrompt: opts.systemPrompt,
309
- }));
326
+ (needsRunner
327
+ ? await createAgentRunner({
328
+ actions: opts.actions ?? (await discoverActions(cwd)),
329
+ systemPrompt: opts.systemPrompt,
330
+ })
331
+ : createInertRunner());
310
332
 
311
333
  const report = await runEvals(evals, runner, {
312
334
  thresholdOverride: opts.thresholdOverride,
@@ -332,3 +354,16 @@ async function discoverActions(
332
354
  return {};
333
355
  }
334
356
  }
357
+
358
+ function createInertRunner(): AgentRunner {
359
+ return {
360
+ engine: {} as AgentRunner["engine"],
361
+ model: "inert",
362
+ async runAgent() {
363
+ throw new Error("Eval unexpectedly requested the agent runner");
364
+ },
365
+ analyzeContext() {
366
+ throw new Error("Eval unexpectedly requested analyze context");
367
+ },
368
+ };
369
+ }
@@ -133,6 +133,12 @@ export interface EvalRunContext {
133
133
  export interface Eval {
134
134
  name: string;
135
135
  input: EvalInput;
136
+ /**
137
+ * Skip this case without running the agent or scorers. Use for opt-in
138
+ * suites that need secrets, live provider credentials, or manual/nightly
139
+ * gates. Skipped rows are reported distinctly and do not fail the suite.
140
+ */
141
+ skipReason?: string;
136
142
  /**
137
143
  * Optional override for how the agent is run for this case. Defaults to the
138
144
  * runner's headless `runAgent`. Use this to do custom setup (seed data,
@@ -159,6 +165,10 @@ export interface EvalResultRow {
159
165
  eval: string;
160
166
  threshold: number;
161
167
  scores: ScorerResult[];
168
+ /** Explicit row status for reports. Older consumers can still read `passed`. */
169
+ status?: "passed" | "failed" | "skipped";
170
+ /** Human-readable reason when `status` is `skipped`. */
171
+ skipReason?: string;
162
172
  /** True only when every scorer passed. */
163
173
  passed: boolean;
164
174
  /** Mean of the scorer scores, for at-a-glance ranking. */
@@ -173,5 +183,6 @@ export interface EvalRunReport {
173
183
  total: number;
174
184
  passed: number;
175
185
  failed: number;
186
+ skipped?: number;
176
187
  results: EvalResultRow[];
177
188
  }
@@ -121,7 +121,9 @@ cd templates/content && pnpm action <name> [args]
121
121
  | `validate-builder-source-execution` | `--databaseId <id>` or `--documentId <id> --changeSetId <id> [--idempotencyKey <key>]` | Validate/replay a prepared Builder execution gate locally as a dry run; never calls Builder |
122
122
  | `execute-builder-source-execution` | `--databaseId <id>` or `--documentId <id> --changeSetId <id> [--idempotencyKey <key>] [--pushModeConfirmation autosave\|draft\|publish]` | Execute a guarded live Builder write only when approved, validated, enabled, idempotent, and targeting `agent-native-blog-article-test` |
123
123
  | `add-database-item` | `--databaseId <id> [--title <text>] [--propertyValues <json>]` | Add a page row to a database, optionally seeding property values |
124
- | `duplicate-database-item` | `--itemId <id>` or `--documentId <id> [--title <text>]` | Duplicate a database row page and its stored property values |
124
+ | `duplicate-database-item` | `--itemId <id>` or `--documentId <id> [--title <text>]` | Duplicate exactly one database row page and its stored property values; for two or more rows, use `duplicate-database-items` once |
125
+ | `duplicate-database-items` | `--databaseId <id>` or `--documentId <databaseDocumentId> --itemIds <json-array>` or `--documentIds <json-array>` | Preferred multi-row duplicate action; duplicate multiple database row pages atomically and return ordered duplicate item/document IDs |
126
+ | `delete-database-items` | `--databaseId <id>` or `--documentId <databaseDocumentId> --itemIds <json-array>` or `--documentIds <json-array>` | Preferred multi-row delete action; delete multiple database row pages atomically while preserving `delete-document` admin semantics |
125
127
  | `move-database-item` | `--itemId <id>` or `--documentId <id> --position <number>` | Move a database row page to a new zero-based table position |
126
128
  | `update-content-database-view` | `--databaseId <id> --viewConfig <json>` | Persist database views, sorts, filters, hidden properties, and view settings |
127
129
  | `list-document-properties` | `--documentId <id> [--format json]` | List Notion-style property definitions and values for a document |
@@ -568,11 +570,16 @@ multi-select, users can add a new board group from the board itself; this
568
570
  appends a new option to the grouped property definition.
569
571
  Use
570
572
  `create-content-database`, `get-content-database`,
571
- `add-database-item`, `duplicate-database-item`, `move-database-item`,
573
+ `add-database-item`, `duplicate-database-item`, `duplicate-database-items`,
574
+ `delete-database-items`, `move-database-item`,
572
575
  `update-content-database-view`, `list-document-properties`,
573
576
  `configure-document-property`, `set-document-property`,
574
577
  `duplicate-document-property`, and `delete-document-property`; do not edit
575
578
  property rows or view config via raw SQL when an action can do it.
579
+ When targeting more than one database row, call `duplicate-database-items` or
580
+ `delete-database-items` once with a native JSON array of `itemIds` or
581
+ `documentIds`. Do not loop `duplicate-database-item` or `delete-document` for
582
+ multi-row duplicate/delete requests.
576
583
 
577
584
  ## UI Components
578
585