pi-crew 0.9.67 → 0.10.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 (222) hide show
  1. package/CHANGELOG.md +172 -0
  2. package/agents/analyst.md +1 -1
  3. package/agents/cold-verifier.md +3 -1
  4. package/agents/critic.md +1 -1
  5. package/agents/executor.md +1 -1
  6. package/agents/explorer.md +1 -1
  7. package/agents/planner.md +1 -1
  8. package/agents/reviewer.md +1 -1
  9. package/agents/security-reviewer.md +1 -1
  10. package/agents/test-engineer.md +1 -1
  11. package/agents/verifier.md +1 -1
  12. package/agents/writer.md +1 -1
  13. package/dist/index.mjs +65847 -60331
  14. package/docs/README.md +2 -0
  15. package/docs/actions-reference.md +31 -0
  16. package/docs/commands-reference.md +17 -6
  17. package/docs/resource-formats.md +13 -0
  18. package/package.json +9 -6
  19. package/schema.json +15 -1
  20. package/scripts/resource-sampler.mjs +36 -2
  21. package/skills/requirements-to-task-packet/SKILL.md +26 -0
  22. package/skills/widget-rendering/SKILL.md +7 -7
  23. package/src/agents/agent-config.ts +36 -14
  24. package/src/agents/discover-agents.ts +23 -14
  25. package/src/config/config-merge.ts +183 -0
  26. package/src/config/config-validation.ts +681 -0
  27. package/src/config/config.ts +22 -864
  28. package/src/config/defaults.ts +35 -1
  29. package/src/config/drift-detector.ts +1 -1
  30. package/src/config/env-vars.ts +691 -0
  31. package/src/config/role-tools.ts +8 -8
  32. package/src/config/sanitize-project-config.ts +172 -0
  33. package/src/config/types.ts +30 -0
  34. package/src/extension/async-notifier.ts +25 -2
  35. package/src/extension/crew-vibes/config.ts +2 -1
  36. package/src/extension/plan-orchestrate.ts +132 -0
  37. package/src/extension/registration/commands/dashboard.ts +158 -0
  38. package/src/extension/registration/commands/index.ts +35 -0
  39. package/src/extension/registration/commands/manage.ts +303 -0
  40. package/src/extension/registration/commands/run.ts +214 -0
  41. package/src/extension/registration/commands/shared.ts +631 -0
  42. package/src/extension/registration/commands/status.ts +60 -0
  43. package/src/extension/registration/commands.ts +13 -1224
  44. package/src/extension/registration/lifecycle-handlers.ts +126 -15
  45. package/src/extension/registration/subagent-tools.ts +218 -9
  46. package/src/extension/rpc-hmac.ts +5 -3
  47. package/src/extension/team-tool/api/heartbeat.ts +47 -10
  48. package/src/extension/team-tool/api/plan-approval.ts +9 -0
  49. package/src/extension/team-tool/api/task-claims.ts +109 -40
  50. package/src/extension/team-tool/cancel.ts +84 -50
  51. package/src/extension/team-tool/dispatch/index.ts +1 -0
  52. package/src/extension/team-tool/dispatch/run.ts +4 -1
  53. package/src/extension/team-tool/doctor.ts +103 -1
  54. package/src/extension/team-tool/orchestrate.ts +66 -1
  55. package/src/extension/team-tool/plans.ts +192 -0
  56. package/src/extension/team-tool/respond.ts +197 -65
  57. package/src/extension/team-tool/run-deadline.ts +16 -1
  58. package/src/extension/team-tool/run-intent.ts +63 -0
  59. package/src/extension/team-tool/run.ts +48 -18
  60. package/src/extension/team-tool/status.ts +84 -26
  61. package/src/extension/team-tool.ts +11 -2
  62. package/src/hooks/registry.ts +1 -6
  63. package/src/i18n.ts +9 -0
  64. package/src/prompt/prompt-runtime.ts +521 -2
  65. package/src/prompt/worker-events-channel.ts +173 -0
  66. package/src/runtime/README.md +8 -8
  67. package/src/runtime/async-runner.ts +7 -3
  68. package/src/runtime/background-runner.ts +42 -14
  69. package/src/runtime/broker/broker-issuer.ts +9 -2
  70. package/src/runtime/broker/crew-broker-tokens.ts +43 -6
  71. package/src/runtime/broker/crew-broker.ts +838 -10
  72. package/src/runtime/broker/wait-status-cache.ts +157 -0
  73. package/src/runtime/budget-enforcement.ts +281 -0
  74. package/src/runtime/child-pi/child-pi-spawn.ts +60 -14
  75. package/src/runtime/child-pi/child-pi-timers.ts +324 -0
  76. package/src/runtime/child-pi/child-pi.ts +97 -201
  77. package/src/runtime/child-pi/mock-fixtures.ts +16 -2
  78. package/src/runtime/crew-agent-records.ts +259 -14
  79. package/src/runtime/delegate-spawn.ts +148 -0
  80. package/src/runtime/deterministic-ast.ts +2 -1
  81. package/src/runtime/dispatch-batch.ts +945 -0
  82. package/src/runtime/finalize-run.ts +557 -0
  83. package/src/runtime/goal-workflow/adaptive-plan.ts +87 -13
  84. package/src/runtime/goal-workflow/dynamic-workflow-runner.ts +3 -2
  85. package/src/runtime/goal-workflow/goal-state-store.ts +1 -1
  86. package/src/runtime/group-join.ts +11 -125
  87. package/src/runtime/live-session/live-session-runtime.ts +26 -1
  88. package/src/runtime/merge-gate.ts +7 -1
  89. package/src/runtime/merge-loop.ts +130 -0
  90. package/src/runtime/model/model-budget-summary.ts +53 -0
  91. package/src/runtime/model/model-fallback.ts +32 -2
  92. package/src/runtime/model/pi-args.ts +10 -0
  93. package/src/runtime/model/provider-extensions.ts +10 -0
  94. package/src/runtime/orphan-worker-registry.ts +1 -1
  95. package/src/runtime/output/output-validator.ts +45 -0
  96. package/src/runtime/parent-guard.ts +3 -1
  97. package/src/runtime/peer-dep.ts +2 -1
  98. package/src/runtime/per-write-validator.ts +0 -5
  99. package/src/runtime/pi-spawn.ts +61 -15
  100. package/src/runtime/plan-approval.ts +125 -0
  101. package/src/runtime/plan-replan.ts +151 -0
  102. package/src/runtime/recovery/checkpoint.ts +0 -18
  103. package/src/runtime/recovery/crash-recovery.ts +95 -46
  104. package/src/runtime/scheduler-context.ts +98 -0
  105. package/src/runtime/scheduling/coalesce-tasks.ts +5 -0
  106. package/src/runtime/scheduling/global-worker-cap.ts +2 -1
  107. package/src/runtime/scheduling/nested-slots.ts +70 -0
  108. package/src/runtime/scheduling/run-coalesced-task-group.ts +64 -13
  109. package/src/runtime/scheduling/task-graph-scheduler.ts +0 -10
  110. package/src/runtime/scratchpad/README.md +10 -5
  111. package/src/runtime/scratchpad/guest.ts +103 -2
  112. package/src/runtime/scratchpad/protocol.ts +13 -1
  113. package/src/runtime/scratchpad/transform.ts +206 -12
  114. package/src/runtime/settings-store.ts +219 -0
  115. package/src/runtime/spawn-policy.ts +217 -0
  116. package/src/runtime/stale-reconciler.ts +87 -6
  117. package/src/runtime/subagent-manager.ts +25 -1
  118. package/src/runtime/task-output-context.ts +230 -9
  119. package/src/runtime/task-packet.ts +23 -1
  120. package/src/runtime/task-runner/child-executor.ts +106 -7
  121. package/src/runtime/task-runner/post-execution.ts +125 -1
  122. package/src/runtime/task-runner/pre-execution.ts +39 -1
  123. package/src/runtime/task-runner/prompt-builder.ts +51 -1
  124. package/src/runtime/task-runner/retrieval-orchestrator.ts +72 -18
  125. package/src/runtime/task-runner/spec-evidence.ts +403 -0
  126. package/src/runtime/task-runner/state-helpers.ts +26 -24
  127. package/src/runtime/task-runner.ts +11 -0
  128. package/src/runtime/team-runner.ts +129 -1671
  129. package/src/runtime/verification/spec-sandbox.ts +255 -0
  130. package/src/runtime/verification/verification-gates.ts +3 -2
  131. package/src/runtime/verification/verification-worktree.ts +2 -1
  132. package/src/runtime/workflow-phase-advance.ts +100 -0
  133. package/src/runtime/workspace-tree.ts +9 -0
  134. package/src/schema/config-schema.ts +65 -25
  135. package/src/schema/sensitive-config-paths.ts +64 -0
  136. package/src/schema/team-tool-schema.ts +13 -3
  137. package/src/state/README.md +4 -10
  138. package/src/state/atomic-write.ts +20 -3
  139. package/src/state/contracts.ts +38 -0
  140. package/src/state/coordination/mailbox.ts +12 -2
  141. package/src/state/event-log/cursor.ts +223 -0
  142. package/src/state/event-log/event-log-rotation.ts +12 -4
  143. package/src/state/event-log/event-log.ts +152 -369
  144. package/src/state/event-log/sequence-cache.ts +373 -0
  145. package/src/state/event-log/worker-atomic-writer.ts +2 -1
  146. package/src/state/stores/active-run-registry.ts +3 -2
  147. package/src/state/stores/manifest-io.ts +237 -0
  148. package/src/state/stores/ownership-map.ts +162 -0
  149. package/src/state/stores/plan-store.ts +241 -0
  150. package/src/state/stores/run-cache.ts +0 -90
  151. package/src/state/stores/spec-store.ts +189 -0
  152. package/src/state/stores/state-store.ts +66 -229
  153. package/src/state/types.ts +197 -0
  154. package/src/ui/dashboard-panes/plan-pane.ts +136 -0
  155. package/src/ui/dashboard-panes/progress-pane.ts +6 -0
  156. package/src/ui/dashboard-panes/transcript-pane.ts +31 -0
  157. package/src/ui/heartbeat-aggregator.ts +9 -1
  158. package/src/ui/keybinding-map.ts +54 -13
  159. package/src/ui/powerbar-publisher.ts +52 -1
  160. package/src/ui/run-dashboard.ts +31 -5
  161. package/src/ui/run-snapshot-cache.ts +57 -30
  162. package/src/ui/snapshot-types.ts +6 -1
  163. package/src/ui/widget/widget-renderer.ts +9 -1
  164. package/src/utils/file-coalescer.ts +0 -4
  165. package/src/utils/fs-errno.ts +66 -0
  166. package/src/utils/fs-watch.ts +1 -1
  167. package/src/utils/internal-error.ts +3 -1
  168. package/src/utils/paths.ts +11 -3
  169. package/src/utils/task-name-generator.ts +1 -8
  170. package/src/workflows/discover-workflows.ts +19 -2
  171. package/src/workflows/validate-workflow.ts +7 -1
  172. package/src/workflows/workflow-config.ts +10 -0
  173. package/src/workflows/workflow-serializer.ts +3 -0
  174. package/src/worktree/worktree-manager.ts +22 -0
  175. package/src/agents/agent-search.ts +0 -98
  176. package/src/benchmark/benchmark-runner.ts +0 -313
  177. package/src/benchmark/feedback-loop.ts +0 -73
  178. package/src/config/resilient-parser.ts +0 -117
  179. package/src/extension/crew-vibes/cat-frames.ts +0 -18
  180. package/src/extension/result-watcher.ts +0 -139
  181. package/src/observability/exporters/prometheus-exporter.ts +0 -54
  182. package/src/observability/metric-retention.ts +0 -64
  183. package/src/runtime/compaction/compaction-summary.ts +0 -278
  184. package/src/runtime/errors/crew-errors.ts +0 -162
  185. package/src/runtime/live-session/intercom-bridge.ts +0 -187
  186. package/src/runtime/loop-gates.ts +0 -128
  187. package/src/runtime/metric-parser.ts +0 -36
  188. package/src/runtime/output/stream-preview.ts +0 -184
  189. package/src/runtime/output/tool-progress.ts +0 -278
  190. package/src/runtime/phase-tracker.ts +0 -385
  191. package/src/runtime/pipeline-runner.ts +0 -523
  192. package/src/runtime/process/process-lifecycle.ts +0 -491
  193. package/src/runtime/recovery/retry-runner.ts +0 -330
  194. package/src/runtime/run-drift.ts +0 -219
  195. package/src/runtime/scratchpad/snapshot-hmac.ts +0 -167
  196. package/src/runtime/task-quality.ts +0 -199
  197. package/src/runtime/task-runner/run-projection.ts +0 -128
  198. package/src/runtime/verification/post-checks.ts +0 -142
  199. package/src/state/coordination/schedule.ts +0 -166
  200. package/src/state/event-log/jsonl-writer.ts +0 -115
  201. package/src/state/hook-instinct-bridge.ts +0 -94
  202. package/src/state/hook-integrations.ts +0 -51
  203. package/src/state/session-state-map.ts +0 -51
  204. package/src/state/stores/blob-store.ts +0 -308
  205. package/src/state/stores/instinct-store.ts +0 -275
  206. package/src/state/stores/observation-store.ts +0 -176
  207. package/src/state/tiered-eval.ts +0 -480
  208. package/src/state/types-eval.ts +0 -58
  209. package/src/tools/safe-bash-extension.ts +0 -54
  210. package/src/tools/safe-bash.ts +0 -505
  211. package/src/ui/agent-management-overlay.ts +0 -160
  212. package/src/ui/crew-footer.ts +0 -102
  213. package/src/ui/crew-select-list.ts +0 -114
  214. package/src/ui/dashboard-panes/capability-pane.ts +0 -77
  215. package/src/ui/transcript-entries.ts +0 -256
  216. package/src/utils/conflict-detect.ts +0 -721
  217. package/src/utils/fingerprint.ts +0 -180
  218. package/src/utils/gh-protocol.ts +0 -556
  219. package/src/utils/project-detector.ts +0 -160
  220. package/src/utils/sse-parser.ts +0 -131
  221. package/src/workflows/cost-estimator.ts +0 -34
  222. package/src/workflows/intermediate-store.ts +0 -166
@@ -1,176 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { logInternalError } from "../../utils/internal-error.ts";
3
- import { atomicWriteJson } from "../atomic-write.ts";
4
-
5
- // ── Types ────────────────────────────────────────────────────────────────
6
-
7
- export interface Observation {
8
- tool: string;
9
- input: string;
10
- output: string;
11
- filesRead: string[];
12
- filesModified: string[];
13
- timestamp: number;
14
- sessionId: string;
15
- taskId?: string;
16
- }
17
-
18
- export interface CompressedObservation {
19
- summary: string;
20
- patterns: string[];
21
- decisions: string[];
22
- filesAffected: string[];
23
- relevanceScore: number;
24
- timestamp: number;
25
- sessionId: string;
26
- }
27
-
28
- export interface ObservationStoreConfig {
29
- maxObservations: number;
30
- maxCompressed: number;
31
- privacyTags: string[]; // tags to strip before storage
32
- }
33
-
34
- const DEFAULT_CONFIG: ObservationStoreConfig = {
35
- maxObservations: 1000,
36
- maxCompressed: 200,
37
- privacyTags: ["<private>", "<secret>", "<credentials>"],
38
- };
39
-
40
- // ── Privacy ──────────────────────────────────────────────────────────────
41
-
42
- /**
43
- * Strip privacy-tagged content from a string.
44
- */
45
- export function stripPrivacyTags(content: string, config = DEFAULT_CONFIG): string {
46
- let result = content;
47
- for (const tag of config.privacyTags) {
48
- const openTag = tag;
49
- const closeTag = tag.replace("<", "</");
50
- // Remove everything between open and close tags
51
- const regex = new RegExp(`${escapeRegex(openTag)}[\\s\\S]*?${escapeRegex(closeTag)}`, "gi");
52
- result = result.replace(regex, "[REDACTED]");
53
- }
54
- return result;
55
- }
56
-
57
- function escapeRegex(str: string): string {
58
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
59
- }
60
-
61
- // ── Observation Store ────────────────────────────────────────────────────
62
-
63
- export class ObservationStore {
64
- private observations: Observation[] = [];
65
- private compressed: CompressedObservation[] = [];
66
- private config: ObservationStoreConfig;
67
- private storePath: string;
68
-
69
- constructor(storePath: string, config: Partial<ObservationStoreConfig> = {}) {
70
- this.config = { ...DEFAULT_CONFIG, ...config };
71
- this.storePath = storePath;
72
- if (existsSync(storePath)) {
73
- this.load();
74
- }
75
- }
76
-
77
- /**
78
- * Record a new observation.
79
- */
80
- record(observation: Observation): void {
81
- // Strip privacy
82
- const sanitized: Observation = {
83
- ...observation,
84
- input: stripPrivacyTags(observation.input, this.config),
85
- output: stripPrivacyTags(observation.output, this.config),
86
- };
87
-
88
- this.observations.push(sanitized);
89
-
90
- // Enforce capacity
91
- if (this.observations.length > this.config.maxObservations) {
92
- this.observations = this.observations.slice(-this.config.maxObservations);
93
- }
94
- }
95
-
96
- /**
97
- * Get recent observations.
98
- */
99
- getRecent(count = 10): Observation[] {
100
- return this.observations.slice(-count);
101
- }
102
-
103
- /**
104
- * Store a compressed observation.
105
- */
106
- addCompressed(compressed: CompressedObservation): void {
107
- this.compressed.push(compressed);
108
-
109
- if (this.compressed.length > this.config.maxCompressed) {
110
- this.compressed = this.compressed.slice(-this.config.maxCompressed);
111
- }
112
- }
113
-
114
- /**
115
- * Get compressed observations for injection.
116
- */
117
- getCompressed(limit = 5): CompressedObservation[] {
118
- return this.compressed.sort((a, b) => b.relevanceScore - a.relevanceScore).slice(0, limit);
119
- }
120
-
121
- /**
122
- * Format compressed observations for prompt injection.
123
- */
124
- injectCompressed(limit = 5): string {
125
- const items = this.getCompressed(limit);
126
- if (items.length === 0) return "";
127
-
128
- return (
129
- "## Observations from Previous Sessions\n\n" +
130
- items
131
- .map(
132
- (o) =>
133
- `### ${o.summary}\n` +
134
- `Patterns: ${o.patterns.join(", ")}\n` +
135
- `Decisions: ${o.decisions.join(", ")}\n` +
136
- `Files: ${o.filesAffected.join(", ")}`,
137
- )
138
- .join("\n\n") +
139
- "\n"
140
- );
141
- }
142
-
143
- /**
144
- * Persist to disk.
145
- */
146
- save(): void {
147
- try {
148
- // BUGFIX (Round 12 I4): use atomicWriteJson (temp-file + rename) instead
149
- // of raw writeFileSync, so a crash mid-write cannot leave a truncated /
150
- // empty file that breaks load() on restart.
151
- atomicWriteJson(this.storePath, {
152
- observations: this.observations,
153
- compressed: this.compressed,
154
- });
155
- } catch (error) {
156
- logInternalError("observation-store.save", error, `path=${this.storePath}`);
157
- }
158
- }
159
-
160
- get stats(): { observations: number; compressed: number } {
161
- return {
162
- observations: this.observations.length,
163
- compressed: this.compressed.length,
164
- };
165
- }
166
-
167
- private load(): void {
168
- try {
169
- const data = JSON.parse(readFileSync(this.storePath, "utf-8"));
170
- if (Array.isArray(data.observations)) this.observations = data.observations;
171
- if (Array.isArray(data.compressed)) this.compressed = data.compressed;
172
- } catch (error) {
173
- logInternalError("observation-store.load", error, `path=${this.storePath}`);
174
- }
175
- }
176
- }
@@ -1,480 +0,0 @@
1
- /**
2
- * Tiered Evaluation System
3
- *
4
- * Inspired by agent-eval's judge tiers, this module provides a hierarchical
5
- * evaluation system where checks are grouped by computational cost and reliability:
6
- *
7
- * - Tier 1 (deterministic): Fast checks (~1s timeout) - file exists, parse errors, etc.
8
- * - Tier 2 (pattern): Medium checks (~5s timeout) - grep, regex, structural checks
9
- * - Tier 3 (llm): Expensive checks (~60s timeout) - LLM-based evaluation
10
- */
11
-
12
- import type { EvalResult, EvalTier, TierConfig } from "./types-eval.ts";
13
-
14
- /**
15
- * Default tier configurations with increasing timeouts for more expensive evaluations.
16
- */
17
- export const TIER_CONFIGS: Record<EvalTier, TierConfig> = {
18
- 1: {
19
- tier: 1,
20
- name: "deterministic",
21
- description: "File exists, parse errors, fast checks",
22
- timeoutMs: 1000,
23
- },
24
- 2: {
25
- tier: 2,
26
- name: "pattern",
27
- description: "grep, regex, structural checks",
28
- timeoutMs: 5000,
29
- },
30
- 3: {
31
- tier: 3,
32
- name: "llm",
33
- description: "LLM-based evaluation",
34
- timeoutMs: 60000,
35
- },
36
- };
37
-
38
- /**
39
- * Default tier configurations (re-exported for convenience).
40
- */
41
- export const DEFAULT_TIER_CONFIGS = TIER_CONFIGS;
42
-
43
- export type { EvalResult, EvalTier, TierConfig };
44
-
45
- /**
46
- * Individual evaluation check with its assigned tier.
47
- */
48
- export interface EvalCheck<T = unknown> {
49
- /** The evaluation tier for this check */
50
- tier: EvalTier;
51
- /** The check function - returns true if passed */
52
- check: () => Promise<boolean> | boolean;
53
- /** Optional metadata about this check */
54
- metadata?: T;
55
- }
56
-
57
- /**
58
- * Configuration for the TieredEvalRunner.
59
- */
60
- export interface TieredEvalRunnerConfig {
61
- /** Override default tier configurations */
62
- tierConfigs?: Partial<Record<EvalTier, TierConfig>>;
63
- /** Default timeout multiplier for all tiers (default: 1.0) */
64
- timeoutMultiplier?: number;
65
- /** Whether to sort checks by tier before execution (default: true) */
66
- sortByTier?: boolean;
67
- /** Custom error message for timeouts */
68
- timeoutMessage?: string;
69
- }
70
-
71
- /**
72
- * Result of a single evaluation check.
73
- */
74
- export interface CheckResult extends EvalResult {
75
- /** The check function returned true */
76
- passed: boolean;
77
- /** Error message if check failed or timed out */
78
- error?: string;
79
- /** Check index in the original array */
80
- index: number;
81
- }
82
-
83
- /**
84
- * Extended result type for multi-check evaluations.
85
- */
86
- export interface TieredEvalResult {
87
- /** Overall success status - all checks passed */
88
- passed: boolean;
89
- /** Results for each individual check */
90
- results: CheckResult[];
91
- /** Total duration of all checks in milliseconds */
92
- totalDurationMs: number;
93
- /** Tier at which evaluation failed (if any) */
94
- failedAtTier?: EvalTier;
95
- /** Index of first failing check (if any) */
96
- failedAtIndex?: number;
97
- }
98
-
99
- /**
100
- * TieredEvalRunner executes evaluation checks in tiered order,
101
- * with appropriate timeouts for each tier level.
102
- *
103
- * Supports two execution modes:
104
- * - runTieredEval: Runs all checks regardless of failures
105
- * - runTieredEvalFailFast: Stops at first failure (like ECC promotion gates)
106
- *
107
- * @example
108
- * ```typescript
109
- * const runner = new TieredEvalRunner();
110
- *
111
- * // Run all checks
112
- * const allResults = await runner.runTieredEval('task-1', [
113
- * { tier: 1, check: () => fs.existsSync('output.json') },
114
- * { tier: 2, check: async () => (await run('grep', ['pattern', 'output.json'])).exitCode === 0 }
115
- * ]);
116
- *
117
- * // Fail-fast mode
118
- * const failFastResult = await runner.runTieredEvalFailFast('task-2', [
119
- * { tier: 1, check: () => fs.existsSync('output.json') },
120
- * { tier: 2, check: async () => (await run('grep', ['pattern', 'output.json'])).exitCode === 0 }
121
- * ]);
122
- * ```
123
- */
124
- export class TieredEvalRunner {
125
- private readonly tierConfigs: Record<EvalTier, TierConfig>;
126
- private readonly timeoutMultiplier: number;
127
- private readonly sortByTier: boolean;
128
- private readonly timeoutMessage: string;
129
-
130
- /**
131
- * Creates a new TieredEvalRunner instance.
132
- *
133
- * @param config - Optional configuration to override defaults
134
- */
135
- constructor(config?: TieredEvalRunnerConfig) {
136
- this.tierConfigs = { ...TIER_CONFIGS };
137
- this.timeoutMultiplier = config?.timeoutMultiplier ?? 1.0;
138
- this.sortByTier = config?.sortByTier ?? true;
139
- this.timeoutMessage = config?.timeoutMessage ?? "Evaluation timed out";
140
-
141
- // Apply tier config overrides
142
- if (config?.tierConfigs) {
143
- for (const [tierStr, tierConfig] of Object.entries(config.tierConfigs)) {
144
- const tier = Number(tierStr) as EvalTier;
145
- if (tierConfig && !Number.isNaN(tier)) {
146
- this.tierConfigs[tier] = {
147
- ...this.tierConfigs[tier],
148
- ...tierConfig,
149
- };
150
- }
151
- }
152
- }
153
- }
154
-
155
- /**
156
- * Gets the effective timeout for a given tier.
157
- *
158
- * @param tier - The evaluation tier
159
- * @returns The timeout in milliseconds (after multiplier is applied)
160
- */
161
- getTimeout(tier: EvalTier): number {
162
- return this.tierConfigs[tier].timeoutMs * this.timeoutMultiplier;
163
- }
164
-
165
- /**
166
- * Gets the configuration for a specific tier.
167
- *
168
- * @param tier - The evaluation tier
169
- * @returns The tier configuration
170
- */
171
- getTierConfig(tier: EvalTier): TierConfig {
172
- return this.tierConfigs[tier];
173
- }
174
-
175
- /**
176
- * Runs a check with the specified timeout.
177
- *
178
- * @param check - The check function to run
179
- * @param tier - The tier this check belongs to
180
- * @returns The result of the check
181
- */
182
- private async runCheckWithTimeout(check: () => Promise<boolean> | boolean, tier: EvalTier): Promise<CheckResult> {
183
- const timeout = this.getTimeout(tier);
184
- const startTime = Date.now();
185
-
186
- return new Promise<CheckResult>((resolve) => {
187
- const timeoutHandle = setTimeout(() => {
188
- resolve({
189
- tier,
190
- passed: false,
191
- durationMs: timeout,
192
- message: this.timeoutMessage,
193
- error: `Check timed out after ${timeout}ms`,
194
- index: -1,
195
- });
196
- }, timeout);
197
-
198
- // Execute the check
199
- Promise.resolve(check())
200
- .then((result) => {
201
- clearTimeout(timeoutHandle);
202
- const durationMs = Date.now() - startTime;
203
- resolve({
204
- tier,
205
- passed: result === true,
206
- durationMs,
207
- index: -1,
208
- error: result !== true ? "Check returned false" : undefined,
209
- });
210
- })
211
- .catch((error) => {
212
- clearTimeout(timeoutHandle);
213
- const durationMs = Date.now() - startTime;
214
- resolve({
215
- tier,
216
- passed: false,
217
- durationMs,
218
- message: error instanceof Error ? error.message : String(error),
219
- error: error instanceof Error ? error.message : String(error),
220
- index: -1,
221
- });
222
- });
223
- });
224
- }
225
-
226
- /**
227
- * Runs all evaluation checks and returns results for each.
228
- *
229
- * @param taskId - Identifier for the task being evaluated
230
- * @param checks - Array of checks to run, each with a tier assignment
231
- * @returns Array of evaluation results for each check
232
- *
233
- * @example
234
- * ```typescript
235
- * const results = await runner.runTieredEval('task-123', [
236
- * { tier: 1, check: () => fs.existsSync('output.json') },
237
- * { tier: 2, check: async () => (await grep('output.json', 'pattern')).found },
238
- * { tier: 3, check: async () => llmJudge.evaluate(output) }
239
- * ]);
240
- *
241
- * // Check if all passed
242
- * const allPassed = results.every(r => r.passed);
243
- * ```
244
- */
245
- async runTieredEval(
246
- taskId: string,
247
- checks: Array<{
248
- tier: EvalTier;
249
- check: () => Promise<boolean> | boolean;
250
- }>,
251
- ): Promise<EvalResult[]> {
252
- // Sort checks by tier if configured (lower tiers first)
253
- const sortedChecks = this.sortByTier ? [...checks].sort((a, b) => a.tier - b.tier) : checks;
254
-
255
- const results: EvalResult[] = [];
256
-
257
- for (let i = 0; i < sortedChecks.length; i++) {
258
- const { tier, check } = sortedChecks[i];
259
- const result = await this.runCheckWithTimeout(check, tier);
260
- results.push(result);
261
- }
262
-
263
- return results;
264
- }
265
-
266
- /**
267
- * Runs evaluation checks in fail-fast mode, stopping at the first failure.
268
- *
269
- * This is useful for promotion gates where cheaper checks should run first
270
- * and any failure should stop the evaluation immediately.
271
- *
272
- * @param taskId - Identifier for the task being evaluated
273
- * @param checks - Array of checks to run, each with a tier assignment
274
- * @returns Array of evaluation results (may be shorter than input if fail-fast triggered)
275
- *
276
- * @example
277
- * ```typescript
278
- * const results = await runner.runTieredEvalFailFast('task-123', [
279
- * { tier: 1, check: () => fs.existsSync('output.json') },
280
- * { tier: 2, check: async () => (await grep('output.json', 'pattern')).found },
281
- * { tier: 3, check: async () => llmJudge.evaluate(output) }
282
- * ]);
283
- *
284
- * if (results.length < checks.length) {
285
- * console.log(`Failed at tier ${results[results.length - 1].tier}`);
286
- * }
287
- * ```
288
- */
289
- async runTieredEvalFailFast(
290
- taskId: string,
291
- checks: Array<{
292
- tier: EvalTier;
293
- check: () => Promise<boolean> | boolean;
294
- }>,
295
- ): Promise<EvalResult[]> {
296
- // Sort checks by tier if configured (lower tiers first)
297
- const sortedChecks = this.sortByTier ? [...checks].sort((a, b) => a.tier - b.tier) : checks;
298
-
299
- const results: EvalResult[] = [];
300
-
301
- for (let i = 0; i < sortedChecks.length; i++) {
302
- const { tier, check } = sortedChecks[i];
303
- const result = await this.runCheckWithTimeout(check, tier);
304
- results.push(result);
305
-
306
- // Fail-fast: stop at first failure
307
- if (!result.passed) {
308
- break;
309
- }
310
- }
311
-
312
- return results;
313
- }
314
-
315
- /**
316
- * Runs evaluation checks and returns a structured result object.
317
- *
318
- * @param taskId - Identifier for the task being evaluated
319
- * @param checks - Array of checks to run, each with a tier assignment
320
- * @param failFast - Whether to stop at first failure (default: false)
321
- * @returns Structured evaluation result with metadata
322
- */
323
- async runEval(
324
- taskId: string,
325
- checks: Array<{
326
- tier: EvalTier;
327
- check: () => Promise<boolean> | boolean;
328
- }>,
329
- failFast = false,
330
- ): Promise<TieredEvalResult> {
331
- const sortedChecks = this.sortByTier ? [...checks].sort((a, b) => a.tier - b.tier) : checks;
332
-
333
- const results: CheckResult[] = [];
334
- let totalDurationMs = 0;
335
-
336
- for (let i = 0; i < sortedChecks.length; i++) {
337
- const { tier, check } = sortedChecks[i];
338
- const result = await this.runCheckWithTimeout(check, tier);
339
- result.index = i;
340
- results.push(result);
341
- totalDurationMs += result.durationMs;
342
-
343
- // Fail-fast: stop at first failure
344
- if (failFast && !result.passed) {
345
- return {
346
- passed: false,
347
- results,
348
- totalDurationMs,
349
- failedAtTier: tier,
350
- failedAtIndex: i,
351
- };
352
- }
353
- }
354
-
355
- return {
356
- passed: results.every((r) => r.passed),
357
- results,
358
- totalDurationMs,
359
- };
360
- }
361
-
362
- /**
363
- * Runs checks in parallel within each tier, but sequentially across tiers.
364
- *
365
- * This optimizes execution time when multiple checks exist at the same tier level.
366
- *
367
- * @param taskId - Identifier for the task being evaluated
368
- * @param checks - Array of checks to run
369
- * @param failFast - Whether to stop at first failure (default: false)
370
- * @returns Structured evaluation result
371
- */
372
- async runTieredEvalParallel(
373
- taskId: string,
374
- checks: Array<{
375
- tier: EvalTier;
376
- check: () => Promise<boolean> | boolean;
377
- }>,
378
- failFast = false,
379
- ): Promise<TieredEvalResult> {
380
- // Group checks by tier
381
- const checksByTier = new Map<
382
- EvalTier,
383
- Array<{
384
- check: () => Promise<boolean> | boolean;
385
- originalIndex: number;
386
- }>
387
- >();
388
-
389
- checks.forEach((c, originalIndex) => {
390
- const existing = checksByTier.get(c.tier) || [];
391
- existing.push({ check: c.check, originalIndex });
392
- checksByTier.set(c.tier, existing);
393
- });
394
-
395
- // Execute tiers in order
396
- const results: CheckResult[] = [];
397
- let totalDurationMs = 0;
398
-
399
- for (const tier of [1, 2, 3] as EvalTier[]) {
400
- const tierChecks = checksByTier.get(tier);
401
- if (!tierChecks || tierChecks.length === 0) continue;
402
-
403
- // Run all checks for this tier in parallel
404
- const tierResults = await Promise.all(
405
- tierChecks.map(async ({ check, originalIndex }) => {
406
- const result = await this.runCheckWithTimeout(check, tier);
407
- result.index = originalIndex;
408
- return result;
409
- }),
410
- );
411
-
412
- tierResults.forEach((result) => {
413
- results.push(result);
414
- totalDurationMs += result.durationMs;
415
- });
416
-
417
- // Check for any failures in this tier
418
- const tierFailed = tierResults.some((r) => !r.passed);
419
- if (failFast && tierFailed) {
420
- const failedIndex = tierResults.findIndex((r) => !r.passed);
421
- return {
422
- passed: false,
423
- results,
424
- totalDurationMs,
425
- failedAtTier: tier,
426
- failedAtIndex: tierResults[failedIndex].index,
427
- };
428
- }
429
- }
430
-
431
- // Sort results by original index
432
- results.sort((a, b) => a.index - b.index);
433
-
434
- return {
435
- passed: results.every((r) => r.passed),
436
- results,
437
- totalDurationMs,
438
- };
439
- }
440
-
441
- /**
442
- * Creates a new runner with overridden tier configurations.
443
- *
444
- * @param overrides - Tier configurations to override
445
- * @returns A new TieredEvalRunner instance
446
- */
447
- withConfig(overrides: Partial<Record<EvalTier, TierConfig>>): TieredEvalRunner {
448
- return new TieredEvalRunner({
449
- tierConfigs: overrides,
450
- timeoutMultiplier: this.timeoutMultiplier,
451
- sortByTier: this.sortByTier,
452
- timeoutMessage: this.timeoutMessage,
453
- });
454
- }
455
- }
456
-
457
- /**
458
- * Convenience function to create a TieredEvalRunner with default configuration.
459
- *
460
- * @param config - Optional configuration overrides
461
- * @returns A new TieredEvalRunner instance
462
- *
463
- * @example
464
- * ```typescript
465
- * const runner = createRunner({
466
- * timeoutMultiplier: 2.0, // Double all timeouts
467
- * tierConfigs: {
468
- * 3: { timeoutMs: 120000 } // 2 minutes for LLM tier
469
- * }
470
- * });
471
- * ```
472
- */
473
- export function createRunner(config?: TieredEvalRunnerConfig): TieredEvalRunner {
474
- return new TieredEvalRunner(config);
475
- }
476
-
477
- /**
478
- * Default runner instance with standard configuration.
479
- */
480
- export const defaultRunner = new TieredEvalRunner();
@@ -1,58 +0,0 @@
1
- /**
2
- * Types for the Tiered Evaluation System
3
- *
4
- * Inspired by agent-eval's judge tiers for hierarchical evaluation.
5
- */
6
-
7
- /**
8
- * Evaluation tiers with increasing computational cost.
9
- *
10
- * - Tier 1: Deterministic, fast checks (file existence, parse errors)
11
- * - Tier 2: Pattern matching, structural checks (grep, regex)
12
- * - Tier 3: LLM-based evaluation for natural language checks
13
- */
14
- export type EvalTier = 1 | 2 | 3;
15
-
16
- /**
17
- * Configuration for a specific evaluation tier.
18
- */
19
- export interface TierConfig {
20
- /** The tier level */
21
- tier: EvalTier;
22
- /** Human-readable name for the tier */
23
- name: string;
24
- /** Description of what this tier evaluates */
25
- description: string;
26
- /** Maximum time allowed for checks in this tier (milliseconds) */
27
- timeoutMs: number;
28
- }
29
-
30
- /**
31
- * Result of a single evaluation check.
32
- */
33
- export interface EvalResult {
34
- /** The tier this result came from */
35
- tier: EvalTier;
36
- /** Whether the check passed */
37
- passed: boolean;
38
- /** Optional message with additional context */
39
- message?: string;
40
- /** How long the check took in milliseconds */
41
- durationMs: number;
42
- }
43
-
44
- /**
45
- * Summary of a tiered evaluation run.
46
- */
47
- export interface TieredEvalSummary {
48
- /** Number of checks that passed */
49
- passed: number;
50
- /** Number of checks that failed */
51
- failed: number;
52
- /** Number of checks that timed out */
53
- timedOut: number;
54
- /** Total duration of all checks */
55
- totalDurationMs: number;
56
- /** Whether all checks passed */
57
- allPassed: boolean;
58
- }