@bastani/atomic 0.9.16-alpha.7 → 0.9.16-alpha.8

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 (207) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  3. package/dist/builtin/intercom/README.md +4 -4
  4. package/dist/builtin/intercom/broker/broker.ts +617 -22
  5. package/dist/builtin/intercom/broker/client-message-validation.ts +9 -0
  6. package/dist/builtin/intercom/broker/client.ts +200 -10
  7. package/dist/builtin/intercom/broker/pending-send-registry.ts +4 -0
  8. package/dist/builtin/intercom/broker/send-handler.ts +90 -36
  9. package/dist/builtin/intercom/broker/send-signature.ts +20 -8
  10. package/dist/builtin/intercom/group.ts +85 -0
  11. package/dist/builtin/intercom/index.bundle.mjs +680 -53
  12. package/dist/builtin/intercom/package.json +1 -1
  13. package/dist/builtin/intercom/session-target.ts +54 -0
  14. package/dist/builtin/intercom/skills/intercom/SKILL.md +18 -3
  15. package/dist/builtin/intercom/source-ownership.ts +31 -0
  16. package/dist/builtin/intercom/types.ts +115 -0
  17. package/dist/builtin/mcp/index.bundle.mjs +109 -35
  18. package/dist/builtin/mcp/package.json +1 -1
  19. package/dist/builtin/subagents/package.json +1 -1
  20. package/dist/builtin/subagents/src/extension/index.bundle.mjs +173 -51
  21. package/dist/builtin/web-access/index.bundle.mjs +109 -35
  22. package/dist/builtin/web-access/package.json +1 -1
  23. package/dist/builtin/workflows/CHANGELOG.md +15 -0
  24. package/dist/builtin/workflows/README.md +40 -37
  25. package/dist/builtin/workflows/builtin/adversarial-verification.js +13 -0
  26. package/dist/builtin/workflows/builtin/{shared-prompts.ts → chunk-0x6e303p.js} +133 -154
  27. package/dist/builtin/workflows/builtin/chunk-29wrp38a.js +199 -0
  28. package/dist/builtin/workflows/builtin/chunk-2dqb5s2q.js +602 -0
  29. package/dist/builtin/workflows/builtin/chunk-4febxsv4.js +264 -0
  30. package/dist/builtin/workflows/builtin/chunk-5n10x7j2.js +69730 -0
  31. package/dist/builtin/workflows/builtin/chunk-5wgwscd0.js +4 -0
  32. package/dist/builtin/workflows/builtin/chunk-6fqs7c01.js +155 -0
  33. package/dist/builtin/workflows/builtin/chunk-7430zyas.js +126 -0
  34. package/dist/builtin/workflows/builtin/chunk-7at6dnkr.js +33 -0
  35. package/dist/builtin/workflows/builtin/chunk-82ha8p41.js +175 -0
  36. package/dist/builtin/workflows/builtin/chunk-bfkmzv9h.js +156 -0
  37. package/dist/builtin/workflows/builtin/chunk-c53y8bdh.js +345 -0
  38. package/dist/builtin/workflows/builtin/chunk-cdtd3m3w.js +529 -0
  39. package/dist/builtin/workflows/builtin/chunk-cg9tmks0.js +206 -0
  40. package/dist/builtin/workflows/builtin/chunk-hdpj1dkw.js +2447 -0
  41. package/dist/builtin/workflows/builtin/chunk-hzzn6adg.js +221 -0
  42. package/dist/builtin/workflows/builtin/chunk-nqr34qp3.js +1061 -0
  43. package/dist/builtin/workflows/builtin/chunk-qwzvgxnq.js +404 -0
  44. package/dist/builtin/workflows/builtin/chunk-qx2ptjs3.js +215 -0
  45. package/dist/builtin/workflows/builtin/chunk-v04c5qmd.js +1207 -0
  46. package/dist/builtin/workflows/builtin/chunk-wpckd35c.js +12 -0
  47. package/dist/builtin/workflows/builtin/chunk-x2ghn0je.js +4110 -0
  48. package/dist/builtin/workflows/builtin/chunk-zf28603f.js +1080 -0
  49. package/dist/builtin/workflows/builtin/classify-and-act.js +12 -0
  50. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +10 -0
  51. package/dist/builtin/workflows/builtin/generate-and-filter.js +12 -0
  52. package/dist/builtin/workflows/builtin/goal.js +16 -0
  53. package/dist/builtin/workflows/builtin/index.js +49 -0
  54. package/dist/builtin/workflows/builtin/loop-until-done.js +12 -0
  55. package/dist/builtin/workflows/builtin/open-claude-design.js +11 -0
  56. package/dist/builtin/workflows/builtin/ralph.js +16 -0
  57. package/dist/builtin/workflows/builtin/steering-context.d.ts +6 -0
  58. package/dist/builtin/workflows/builtin/steering-context.js +7 -0
  59. package/dist/builtin/workflows/builtin/tournament.js +13 -0
  60. package/dist/builtin/workflows/package.json +10 -7
  61. package/dist/builtin/workflows/src/authoring/typebox-defaults.d.ts +41 -0
  62. package/dist/builtin/workflows/src/extension/index.bundle.mjs +1228 -428
  63. package/dist/builtin/workflows/src/{index.bundle.mjs → index.js} +956 -427
  64. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +403 -0
  65. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +327 -0
  66. package/dist/builtin/workflows/src/shared/budget.d.ts +67 -0
  67. package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +60 -0
  68. package/dist/builtin/workflows/src/shared/workflow-heartbeat-contract.d.ts +21 -0
  69. package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
  70. package/dist/core/agent-session-custom-message-commit.js +12 -5
  71. package/dist/core/agent-session-custom-message-commit.js.map +1 -1
  72. package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
  73. package/dist/core/agent-session-persistent-custom-messages.js +2 -0
  74. package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
  75. package/dist/core/agent-session.d.ts.map +1 -1
  76. package/dist/core/agent-session.js +2 -1
  77. package/dist/core/agent-session.js.map +1 -1
  78. package/dist/core/auth-storage.d.ts +2 -0
  79. package/dist/core/auth-storage.d.ts.map +1 -1
  80. package/dist/core/auth-storage.js +4 -0
  81. package/dist/core/auth-storage.js.map +1 -1
  82. package/dist/core/builtin-install-layout.d.ts +1 -1
  83. package/dist/core/builtin-install-layout.d.ts.map +1 -1
  84. package/dist/core/builtin-install-layout.js +1 -1
  85. package/dist/core/builtin-install-layout.js.map +1 -1
  86. package/dist/core/codex-fast-mode.d.ts +10 -7
  87. package/dist/core/codex-fast-mode.d.ts.map +1 -1
  88. package/dist/core/codex-fast-mode.js +31 -13
  89. package/dist/core/codex-fast-mode.js.map +1 -1
  90. package/dist/core/extensions/context-types.d.ts +35 -0
  91. package/dist/core/extensions/context-types.d.ts.map +1 -1
  92. package/dist/core/extensions/context-types.js.map +1 -1
  93. package/dist/core/extensions/index.d.ts +1 -1
  94. package/dist/core/extensions/index.d.ts.map +1 -1
  95. package/dist/core/extensions/index.js.map +1 -1
  96. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  97. package/dist/core/extensions/loader-virtual-modules.js +6 -1
  98. package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
  99. package/dist/core/model-runtime.d.ts +2 -0
  100. package/dist/core/model-runtime.d.ts.map +1 -1
  101. package/dist/core/model-runtime.js +4 -0
  102. package/dist/core/model-runtime.js.map +1 -1
  103. package/dist/core/runtime-credentials.d.ts +1 -0
  104. package/dist/core/runtime-credentials.d.ts.map +1 -1
  105. package/dist/core/runtime-credentials.js +8 -0
  106. package/dist/core/runtime-credentials.js.map +1 -1
  107. package/dist/core/sdk.d.ts.map +1 -1
  108. package/dist/core/sdk.js +5 -5
  109. package/dist/core/sdk.js.map +1 -1
  110. package/dist/core/session-manager-storage.d.ts +2 -0
  111. package/dist/core/session-manager-storage.d.ts.map +1 -1
  112. package/dist/core/session-manager-storage.js +4 -2
  113. package/dist/core/session-manager-storage.js.map +1 -1
  114. package/dist/core/slash-commands.js +1 -1
  115. package/dist/core/slash-commands.js.map +1 -1
  116. package/dist/core/workflow-stage-admission.d.ts +6 -1
  117. package/dist/core/workflow-stage-admission.d.ts.map +1 -1
  118. package/dist/core/workflow-stage-admission.js +8 -9
  119. package/dist/core/workflow-stage-admission.js.map +1 -1
  120. package/dist/index.d.ts +0 -1
  121. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  122. package/dist/modes/interactive/components/footer.js +1 -1
  123. package/dist/modes/interactive/components/footer.js.map +1 -1
  124. package/dist/modes/interactive/interactive-autocomplete.js +1 -1
  125. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  126. package/dist/modes/interactive/interactive-startup.js +1 -1
  127. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  128. package/dist/modes/interactive-engine/isolated-runtime.d.ts +4 -0
  129. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  130. package/dist/modes/interactive-engine/isolated-runtime.js +69 -10
  131. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  132. package/dist/modes/rpc/rpc-client-api.d.ts +18 -2
  133. package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
  134. package/dist/modes/rpc/rpc-client-api.js +33 -5
  135. package/dist/modes/rpc/rpc-client-api.js.map +1 -1
  136. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  137. package/dist/modes/rpc/rpc-command-handler.js +8 -4
  138. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  139. package/dist/modes/rpc/rpc-types.d.ts +13 -0
  140. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  141. package/dist/modes/rpc/rpc-types.js.map +1 -1
  142. package/docs/intercom.md +15 -6
  143. package/docs/packages.md +2 -2
  144. package/docs/providers.md +8 -3
  145. package/docs/quickstart.md +2 -2
  146. package/docs/rpc.md +21 -4
  147. package/docs/settings.md +6 -4
  148. package/docs/subagents.md +1 -1
  149. package/docs/usage.md +1 -1
  150. package/docs/workflows.md +108 -239
  151. package/npm-shrinkwrap.json +32 -32
  152. package/package.json +9 -13
  153. package/dist/builtin/workflows/ambient.d.ts +0 -61
  154. package/dist/builtin/workflows/builtin/adversarial-verification-prompts.ts +0 -26
  155. package/dist/builtin/workflows/builtin/adversarial-verification-runner.ts +0 -391
  156. package/dist/builtin/workflows/builtin/adversarial-verification.ts +0 -34
  157. package/dist/builtin/workflows/builtin/classify-and-act-prompts.ts +0 -14
  158. package/dist/builtin/workflows/builtin/classify-and-act-runner.ts +0 -108
  159. package/dist/builtin/workflows/builtin/classify-and-act.ts +0 -40
  160. package/dist/builtin/workflows/builtin/fan-out-and-synthesize-prompts.ts +0 -14
  161. package/dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts +0 -96
  162. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.ts +0 -37
  163. package/dist/builtin/workflows/builtin/generate-and-filter-prompts.ts +0 -41
  164. package/dist/builtin/workflows/builtin/generate-and-filter-runner.ts +0 -90
  165. package/dist/builtin/workflows/builtin/generate-and-filter.ts +0 -31
  166. package/dist/builtin/workflows/builtin/goal-artifacts.ts +0 -64
  167. package/dist/builtin/workflows/builtin/goal-convergence.ts +0 -87
  168. package/dist/builtin/workflows/builtin/goal-ledger.ts +0 -139
  169. package/dist/builtin/workflows/builtin/goal-models.ts +0 -72
  170. package/dist/builtin/workflows/builtin/goal-orchestrator-prompts.ts +0 -94
  171. package/dist/builtin/workflows/builtin/goal-prompts.ts +0 -217
  172. package/dist/builtin/workflows/builtin/goal-reducer.ts +0 -176
  173. package/dist/builtin/workflows/builtin/goal-reports.ts +0 -76
  174. package/dist/builtin/workflows/builtin/goal-reverify.ts +0 -305
  175. package/dist/builtin/workflows/builtin/goal-review.ts +0 -139
  176. package/dist/builtin/workflows/builtin/goal-runner.ts +0 -504
  177. package/dist/builtin/workflows/builtin/goal-schemas.ts +0 -89
  178. package/dist/builtin/workflows/builtin/goal-types.ts +0 -164
  179. package/dist/builtin/workflows/builtin/goal.ts +0 -78
  180. package/dist/builtin/workflows/builtin/index.ts +0 -16
  181. package/dist/builtin/workflows/builtin/loop-until-done-prompts.ts +0 -87
  182. package/dist/builtin/workflows/builtin/loop-until-done-runner.ts +0 -282
  183. package/dist/builtin/workflows/builtin/loop-until-done.ts +0 -51
  184. package/dist/builtin/workflows/builtin/open-claude-design-live-protocol.ts +0 -305
  185. package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +0 -337
  186. package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +0 -347
  187. package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +0 -313
  188. package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +0 -311
  189. package/dist/builtin/workflows/builtin/open-claude-design.ts +0 -57
  190. package/dist/builtin/workflows/builtin/pattern-artifact-root.ts +0 -28
  191. package/dist/builtin/workflows/builtin/progress-scoring.ts +0 -230
  192. package/dist/builtin/workflows/builtin/ralph-core.ts +0 -449
  193. package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +0 -100
  194. package/dist/builtin/workflows/builtin/ralph-models.ts +0 -183
  195. package/dist/builtin/workflows/builtin/ralph-review-gate.ts +0 -103
  196. package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +0 -104
  197. package/dist/builtin/workflows/builtin/ralph-runner.ts +0 -459
  198. package/dist/builtin/workflows/builtin/ralph.ts +0 -82
  199. package/dist/builtin/workflows/builtin/review-convergence.ts +0 -229
  200. package/dist/builtin/workflows/builtin/selection-math.ts +0 -156
  201. package/dist/builtin/workflows/builtin/steering-context.ts +0 -51
  202. package/dist/builtin/workflows/builtin/tournament-prompts.ts +0 -70
  203. package/dist/builtin/workflows/builtin/tournament-runner.ts +0 -400
  204. package/dist/builtin/workflows/builtin/tournament.ts +0 -73
  205. package/dist/builtin/workflows/builtin/verification-criteria.ts +0 -330
  206. package/dist/builtin/workflows/builtin/verification-prompts.ts +0 -206
  207. package/dist/builtin/workflows/builtin/verification-usage.ts +0 -44
@@ -1,400 +0,0 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
2
- import { join, isAbsolute, relative, resolve } from "node:path";
3
- import { Type } from "typebox";
4
- import type { WorkflowInputValues, WorkflowRunContext, WorkflowSerializableObject, WorkflowSerializableValue, WorkflowTaskResult, WorkflowTaskStep } from "../src/shared/types.js";
5
- import { accumulate, plan_comparisons, rank_candidates, select_pivots, soft_win, type Preference, type ScoringJob } from "./selection-math.js";
6
- import { build_scoring_prompt, scoring_prompt_reads, warm_first_fan_out, type ScoringCandidate, type SharedHead } from "./verification-prompts.js";
7
- import { normalize_criteria, parse_rubric, VERIFICATION_SCALE, type Criterion, type CriterionInput } from "./verification-criteria.js";
8
- import { DEFAULT_TOURNAMENT_CRITERIA, renderComparisonsReducerPrompt, renderTournamentAttemptPrompt } from "./tournament-prompts.js";
9
- import { stableArtifactRoot } from "./pattern-artifact-root.js";
10
- import { fold_usage, type UsageTotals } from "./verification-usage.js";
11
-
12
- const judgeScoreSchema = Type.Object({
13
- criterion_id: Type.String(),
14
- score_a: Type.Integer({ minimum: VERIFICATION_SCALE.min, maximum: VERIFICATION_SCALE.max }),
15
- score_b: Type.Integer({ minimum: VERIFICATION_SCALE.min, maximum: VERIFICATION_SCALE.max }),
16
- evidence: Type.Array(Type.String()),
17
- }, { additionalProperties: false });
18
-
19
- const JUDGE_GROUND_TRUTH_NOTE = "No external ground truth is supplied; score each presented solution against the task and criterion.";
20
- const JUDGE_OUTPUT_FORMAT =
21
- "Return only JSON with criterion_id (string), score_a (integer 1–20 for presented slot 1), score_b (integer 1–20 for presented slot 2), and evidence (array of strings).";
22
-
23
- type TournamentCriteriaInput = string | Record<string, string> | readonly string[] | readonly CriterionInput[];
24
- type TournamentInputs = WorkflowInputValues & { readonly prompt: string; readonly num_attempts: number; readonly max_concurrency: number; readonly n_evaluations: number; readonly pivots: number; readonly seed: number; readonly criteria?: TournamentCriteriaInput; readonly models?: readonly string[] };
25
-
26
- type Entrant = { readonly label: string; readonly path: string; readonly body: string };
27
- type JudgeReport = { readonly criterion_id: string; readonly score_a: number; readonly score_b: number; readonly evidence: readonly string[] };
28
- type ComparisonRecord = { a: number; b: number; phase: "ring" | "pivot"; criterion_id: string; rep: number; swapped: boolean; score_a?: number; score_b?: number; p_ab?: number; invalid?: true; judge_artifact_path: string };
29
- type ScoredComparisonRecord = ComparisonRecord & { score_a: number; score_b: number };
30
- type PairRecord = { a: number; b: number; phase: "ring" | "pivot"; valid_reports: number; mean_score_a?: number; mean_score_b?: number; p_ab: number; invalid?: true };
31
- type JudgeStage = { readonly job: ScoringJob; readonly name: string; readonly path: string; readonly slot1: number; readonly slot2: number; readonly step: WorkflowTaskStep };
32
-
33
- function serializableObject(
34
- value: WorkflowSerializableValue | undefined,
35
- ): WorkflowSerializableObject | undefined {
36
- if (value === null || Array.isArray(value) || typeof value !== "object") return undefined;
37
- return value as WorkflowSerializableObject;
38
- }
39
-
40
- function stringArray(value: WorkflowSerializableValue | undefined): value is readonly string[] {
41
- return Array.isArray(value) && value.every((item) => typeof item === "string");
42
- }
43
-
44
- function judgeReport(value: WorkflowSerializableValue | undefined): JudgeReport | undefined {
45
- const object = serializableObject(value);
46
- if (object === undefined) return undefined;
47
- const criterionId = object.criterion_id;
48
- const scoreA = object.score_a;
49
- const scoreB = object.score_b;
50
- const evidence = object.evidence;
51
- if (
52
- typeof criterionId !== "string" ||
53
- typeof scoreA !== "number" ||
54
- !Number.isInteger(scoreA) ||
55
- scoreA < VERIFICATION_SCALE.min ||
56
- scoreA > VERIFICATION_SCALE.max ||
57
- typeof scoreB !== "number" ||
58
- !Number.isInteger(scoreB) ||
59
- scoreB < VERIFICATION_SCALE.min ||
60
- scoreB > VERIFICATION_SCALE.max ||
61
- !stringArray(evidence)
62
- ) return undefined;
63
- return { criterion_id: criterionId, score_a: scoreA, score_b: scoreB, evidence };
64
- }
65
-
66
- function resultFor(
67
- results: readonly WorkflowTaskResult[],
68
- stageName: string,
69
- ): WorkflowTaskResult | undefined {
70
- return results.find((result) => result.stageName === stageName || result.name === stageName);
71
- }
72
-
73
- function scoredComparison(record: ComparisonRecord): record is ScoredComparisonRecord {
74
- return typeof record.score_a === "number" && typeof record.score_b === "number" && record.invalid !== true;
75
- }
76
-
77
- function stageName(job: ScoringJob): string {
78
- return `judge-${job.a}-${job.b}-${job.criterionId}-r${job.rep}`;
79
- }
80
-
81
- function criterionSlug(id: string): string {
82
- const slug = id
83
- .toLowerCase()
84
- .replace(/[^a-z0-9]+/g, "_")
85
- .replace(/^_+|_+$/g, "")
86
- .slice(0, 40)
87
- .replace(/_+$/g, "");
88
- return slug || "criterion";
89
- }
90
-
91
- function judgeArtifactPath(judgesDir: string, job: ScoringJob, criterionIndex: number): string {
92
- const filename = `judge-${job.a}-${job.b}-c${criterionIndex}-${criterionSlug(job.criterionId)}-r${job.rep}.json`;
93
- const root = resolve(judgesDir);
94
- const path = resolve(judgesDir, filename);
95
- const fromRoot = relative(root, path);
96
- if (fromRoot.startsWith("..") || isAbsolute(fromRoot)) {
97
- throw new Error(`tournament: judge artifact escaped its directory: ${path}`);
98
- }
99
- return path;
100
- }
101
-
102
- function tournamentCriteria(input: TournamentCriteriaInput | undefined): readonly Criterion[] {
103
- if (input === undefined) return normalize_criteria(DEFAULT_TOURNAMENT_CRITERIA);
104
- if (typeof input === "string") return parse_rubric(input).criteria;
105
- return normalize_criteria(input);
106
- }
107
-
108
- function modelAssignment(
109
- entrants: readonly Entrant[],
110
- models: readonly string[] | undefined,
111
- ): Record<string, string> | undefined {
112
- if (models === undefined) return undefined;
113
- const assignment: Record<string, string> = {};
114
- if (models.length === 0) return assignment;
115
- for (const [index, entrant] of entrants.entries()) assignment[entrant.label] = models[index % models.length]!;
116
- return assignment;
117
- }
118
-
119
- function combineUsage(totals: readonly UsageTotals[]): UsageTotals {
120
- const combined = {
121
- calls: 0,
122
- input: 0,
123
- output: 0,
124
- cacheRead: 0,
125
- cacheWrite: 0,
126
- cost: 0,
127
- turns: 0,
128
- };
129
- for (const total of totals) {
130
- combined.calls += total.calls;
131
- combined.input += total.input;
132
- combined.output += total.output;
133
- combined.cacheRead += total.cacheRead;
134
- combined.cacheWrite += total.cacheWrite;
135
- combined.cost += total.cost;
136
- combined.turns += total.turns;
137
- }
138
- const cacheDenominator = combined.input + combined.cacheRead;
139
- return {
140
- ...combined,
141
- cacheHitRate: cacheDenominator === 0 ? 0 : combined.cacheRead / cacheDenominator,
142
- };
143
- }
144
-
145
- export async function runTournament(ctx: WorkflowRunContext<TournamentInputs>) {
146
- const artifactDir = await stableArtifactRoot(ctx, "tournament");
147
- const attemptsDir = join(artifactDir, "attempts");
148
- const numAttempts = ctx.inputs.num_attempts ?? 4;
149
- const maxConcurrency = ctx.inputs.max_concurrency ?? 4;
150
- const nEvaluations = ctx.inputs.n_evaluations ?? 2;
151
- const pivotCount = ctx.inputs.pivots ?? 1;
152
- const seed = ctx.inputs.seed ?? 0;
153
- const judgesDir = join(artifactDir, "judges");
154
- await mkdir(attemptsDir, { recursive: true });
155
- await mkdir(judgesDir, { recursive: true });
156
-
157
- const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) =>
158
- join(attemptsDir, `attempt-${index + 1}.md`));
159
- const models = ctx.inputs.models;
160
- const attemptResults = await ctx.parallel(
161
- attemptArtifactPaths.map((path, index) => ({
162
- name: `attempt-${index + 1}`,
163
- prompt: renderTournamentAttemptPrompt(ctx.inputs.prompt, index + 1),
164
- context: "fresh" as const,
165
- output: path,
166
- outputMode: "file-only" as const,
167
- ...(models !== undefined && models.length > 0 ? { model: models[index % models.length] } : {}),
168
- })),
169
- { concurrency: maxConcurrency, failFast: true },
170
- );
171
-
172
- const entrants: Entrant[] = await Promise.all(attemptArtifactPaths.map(async (path, index) => ({
173
- label: `attempt-${index + 1}`,
174
- path,
175
- body: await readFile(path, "utf8"),
176
- })));
177
- const criteria = tournamentCriteria(ctx.inputs.criteria);
178
- const criterionIds = criteria.map((criterion) => criterion.id);
179
- const plan = plan_comparisons({
180
- n: entrants.length,
181
- pivots: pivotCount,
182
- repeats: nEvaluations,
183
- seed,
184
- });
185
- const weights = Array.from({ length: entrants.length }, () => 0);
186
- const counts = Array.from({ length: entrants.length }, () => 0);
187
- const comparisons: ComparisonRecord[] = [];
188
- const pairs: PairRecord[] = [];
189
- const judgeArtifactPaths: string[] = [];
190
- let executed = 0;
191
-
192
- const runPhase = async (
193
- phase: "ring" | "pivot",
194
- jobs: readonly ScoringJob[],
195
- ): Promise<{ readonly preferences: readonly Preference[]; readonly results: readonly WorkflowTaskResult[] }> => {
196
- const stages: JudgeStage[] = jobs.map((job) => {
197
- const slot1 = job.swapped ? job.b : job.a;
198
- const slot2 = job.swapped ? job.a : job.b;
199
- const first = entrants[slot1]!;
200
- const second = entrants[slot2]!;
201
- const head: SharedHead = {
202
- task: ctx.inputs.prompt,
203
- groundTruthNote: JUDGE_GROUND_TRUTH_NOTE,
204
- candidates: [
205
- { path: first.path, body: first.body },
206
- { path: second.path, body: second.body },
207
- ] satisfies readonly ScoringCandidate[],
208
- scaleAnchors: VERIFICATION_SCALE.anchors,
209
- outputFormat: JUDGE_OUTPUT_FORMAT,
210
- };
211
- const name = stageName(job);
212
- const criterionIndex = criterionIds.indexOf(job.criterionId);
213
- const path = judgeArtifactPath(judgesDir, job, criterionIndex);
214
- judgeArtifactPaths.push(path);
215
- return {
216
- job,
217
- name,
218
- path,
219
- slot1,
220
- slot2,
221
- step: {
222
- name,
223
- prompt: build_scoring_prompt(head, criteria.find((criterion) => criterion.id === job.criterionId)!),
224
- context: "fresh" as const,
225
- reads: scoring_prompt_reads(head),
226
- schema: judgeScoreSchema,
227
- },
228
- };
229
- });
230
- if (stages.length === 0) return { preferences: [], results: [] };
231
- executed += stages.length;
232
- const results = await warm_first_fan_out(
233
- ctx,
234
- stages.map((stage) => stage.step),
235
- (_step, index) => `${stages[index]!.slot1}:${stages[index]!.slot2}`,
236
- { concurrency: maxConcurrency, failFast: false },
237
- );
238
- const phaseResults = [...results];
239
- for (const stage of stages) {
240
- let report = judgeReport(resultFor(results, stage.name)?.structured);
241
- if (report === undefined) {
242
- executed += 1;
243
- const retried = await ctx.task(`${stage.name}-reask`, {
244
- prompt: `${stage.step.prompt}\nThe previous report was invalid. Return the required JSON schema exactly once.`,
245
- context: "fresh",
246
- reads: stage.step.reads,
247
- schema: judgeScoreSchema,
248
- });
249
- phaseResults.push(retried);
250
- report = judgeReport(retried.structured);
251
- }
252
- if (report === undefined) {
253
- await writeFile(stage.path, `${JSON.stringify({ invalid: true }, null, 2)}\n`);
254
- comparisons.push({
255
- a: stage.job.a,
256
- b: stage.job.b,
257
- phase,
258
- criterion_id: stage.job.criterionId,
259
- rep: stage.job.rep,
260
- swapped: stage.job.swapped,
261
- invalid: true,
262
- judge_artifact_path: stage.path,
263
- });
264
- continue;
265
- }
266
- await writeFile(stage.path, `${JSON.stringify(report, null, 2)}\n`);
267
- const scoreA = stage.job.swapped ? report.score_b : report.score_a;
268
- const scoreB = stage.job.swapped ? report.score_a : report.score_b;
269
- comparisons.push({
270
- a: stage.job.a,
271
- b: stage.job.b,
272
- phase,
273
- criterion_id: stage.job.criterionId,
274
- rep: stage.job.rep,
275
- swapped: stage.job.swapped,
276
- score_a: scoreA,
277
- score_b: scoreB,
278
- p_ab: soft_win(scoreA, scoreB),
279
- judge_artifact_path: stage.path,
280
- });
281
- }
282
-
283
- const phaseRecords = comparisons.filter((record) => record.phase === phase);
284
- const grouped = new Map<string, ComparisonRecord[]>();
285
- for (const record of phaseRecords) {
286
- const key = `${record.a}:${record.b}`;
287
- const group = grouped.get(key);
288
- if (group === undefined) grouped.set(key, [record]);
289
- else group.push(record);
290
- }
291
- const preferences: Preference[] = [];
292
- for (const records of grouped.values()) {
293
- const first = records[0]!;
294
- const valid = records.filter(scoredComparison);
295
- if (valid.length === 0) {
296
- pairs.push({ a: first.a, b: first.b, phase, valid_reports: 0, p_ab: 0.5, invalid: true });
297
- preferences.push({ a: first.a, b: first.b, p: 0.5 });
298
- continue;
299
- }
300
- const meanScoreA = valid.reduce((sum, record) => sum + record.score_a, 0) / valid.length;
301
- const meanScoreB = valid.reduce((sum, record) => sum + record.score_b, 0) / valid.length;
302
- const p = soft_win(meanScoreA, meanScoreB);
303
- pairs.push({
304
- a: first.a,
305
- b: first.b,
306
- phase,
307
- valid_reports: valid.length,
308
- mean_score_a: meanScoreA,
309
- mean_score_b: meanScoreB,
310
- p_ab: p,
311
- });
312
- preferences.push({ a: first.a, b: first.b, p });
313
- }
314
- return { preferences, results: phaseResults };
315
- };
316
-
317
- const ringJobs = plan.jobs(plan.ring, criterionIds);
318
- const ringPhase = await runPhase("ring", ringJobs);
319
- accumulate(ringPhase.preferences, weights, counts);
320
- const pivotIndices = select_pivots(weights, counts, pivotCount);
321
- const pivotJobs = plan.jobs(plan.pivotRounds(pivotIndices), criterionIds);
322
- const pivotPhase = await runPhase("pivot", pivotJobs);
323
- accumulate(pivotPhase.preferences, weights, counts);
324
- const ranking = rank_candidates(weights, counts).map((entry) => ({
325
- label: entrants[entry.index]!.label,
326
- index: entry.index,
327
- meanPreference: entry.meanPreference,
328
- }));
329
- const outputRanking = ranking.map(({ label, meanPreference }) => ({ label, meanPreference }));
330
- const budgetPivots = Math.min(pivotCount, entrants.length);
331
- // Planned units are judge jobs: scheduled directed pairs × criteria × evaluations.
332
- const comparisonBudget =
333
- (entrants.length + budgetPivots * (entrants.length - budgetPivots) + (budgetPivots * (budgetPivots - 1)) / 2) *
334
- criteria.length * nEvaluations;
335
- const comparisonPath = join(artifactDir, "comparisons.json");
336
- const assignment = modelAssignment(entrants, models);
337
- const phaseUsage = {
338
- attempts: fold_usage(attemptResults),
339
- ring: fold_usage(ringPhase.results),
340
- pivots: fold_usage(pivotPhase.results),
341
- };
342
- const baseLedger = {
343
- task: ctx.inputs.prompt,
344
- seed,
345
- params: {
346
- n: entrants.length,
347
- pivots: pivotCount,
348
- n_evaluations: nEvaluations,
349
- criteria,
350
- },
351
- comparisons,
352
- pairs,
353
- w: weights,
354
- c: counts,
355
- ranking,
356
- // Budget units are judge stages: planned jobs versus dispatched jobs, including re-asks in executed.
357
- budget: { planned: comparisonBudget, executed },
358
- ...(assignment === undefined ? {} : { model_assignment: assignment }),
359
- };
360
- const writeLedger = async (reducerUsage: UsageTotals): Promise<void> => {
361
- const usage = {
362
- ...phaseUsage,
363
- reducer: reducerUsage,
364
- total: combineUsage([phaseUsage.attempts, phaseUsage.ring, phaseUsage.pivots, reducerUsage]),
365
- };
366
- await writeFile(comparisonPath, `${JSON.stringify({ ...baseLedger, usage }, null, 2)}\n`);
367
- };
368
- await writeLedger(fold_usage([]));
369
-
370
- const winner = ranking[0]!;
371
- const winnerEntrant = entrants[winner.index]!;
372
- const resultPath = join(artifactDir, "winner.md");
373
- const reducer = await ctx.task("comparisons-reducer", {
374
- prompt: renderComparisonsReducerPrompt({
375
- task: ctx.inputs.prompt,
376
- comparisonsPath: comparisonPath,
377
- ranking: outputRanking,
378
- winnerLabel: winner.label,
379
- winnerPath: winnerEntrant.path,
380
- }),
381
- context: "fresh",
382
- reads: [comparisonPath, winnerEntrant.path, ...judgeArtifactPaths],
383
- output: resultPath,
384
- outputMode: "file-only",
385
- });
386
- await writeLedger(fold_usage([reducer]));
387
-
388
- return {
389
- result: reducer.text,
390
- winner: winner.label,
391
- winner_artifact_path: winnerEntrant.path,
392
- result_path: resultPath,
393
- attempt_artifact_paths: attemptArtifactPaths,
394
- judge_artifact_paths: judgeArtifactPaths,
395
- comparisons_path: comparisonPath,
396
- ranking: outputRanking,
397
- seed,
398
- artifact_dir: artifactDir,
399
- };
400
- }
@@ -1,73 +0,0 @@
1
- import { Type } from "typebox";
2
- import { workflow } from "../src/authoring/workflow.js";
3
- import { withSteeringPropagationContext } from "./steering-context.js";
4
- import { runTournament } from "./tournament-runner.js";
5
-
6
- export default workflow({
7
- name: "tournament",
8
- description: "Run independent whole-task attempts through a soft-scored pivot-pairing schedule and return an auditable ranking.",
9
- // The 15-minute default, stated rather than inherited: this is a per-workflow
10
- // product decision, so a future change to the global default must not silently
11
- // re-cadence a long autonomous run.
12
- heartbeatIntervalMinutes: 15,
13
- inputs: {
14
- prompt: Type.String({ description: "Task every competing agent must attempt independently." }),
15
- num_attempts: Type.Integer({
16
- minimum: 2,
17
- maximum: 8,
18
- default: 4,
19
- description: "Number of independent whole-task attempts (2-8).",
20
- }),
21
- max_concurrency: Type.Integer({
22
- minimum: 1,
23
- maximum: 8,
24
- default: 4,
25
- description: "Maximum simultaneously active attempts or pairwise judges (1-8).",
26
- }),
27
- n_evaluations: Type.Integer({
28
- minimum: 1,
29
- default: 2,
30
- description: "Number of repeated evaluations per criterion and directed pair.",
31
- }),
32
- pivots: Type.Integer({
33
- minimum: 1,
34
- default: 1,
35
- description: "Number of pivot candidates used for the second comparison phase.",
36
- }),
37
- seed: Type.Integer({
38
- default: 0,
39
- description: "Seed for the deterministic comparison schedule.",
40
- }),
41
- criteria: Type.Optional(Type.Union([
42
- Type.String(),
43
- Type.Record(Type.String(), Type.String()),
44
- Type.Array(Type.String()),
45
- Type.Array(Type.Object({
46
- id: Type.Optional(Type.String()),
47
- name: Type.Optional(Type.String()),
48
- description: Type.String(),
49
- }, { additionalProperties: true })),
50
- ], {
51
- description: "Optional V1 judge criteria; accepts a markdown rubric, record, string list, or CriterionInput list; omitted uses the default three-criterion rubric.",
52
- })),
53
- models: Type.Optional(Type.Array(Type.String(), {
54
- description: "Optional ordered model ids assigned round-robin to attempt slots.",
55
- })),
56
- },
57
- outputs: {
58
- result: Type.String({ description: "Compact reference to the final reducer report; read `result_path` for the full report." }),
59
- winner: Type.String({ description: "Stable attempt label selected as the top-ranked tournament winner." }),
60
- winner_artifact_path: Type.String({ description: "Path to the original winning attempt artifact." }),
61
- result_path: Type.String({ description: "Path to the final reducer report artifact." }),
62
- attempt_artifact_paths: Type.Array(Type.String(), { description: "Paths to every independent attempt artifact." }),
63
- judge_artifact_paths: Type.Array(Type.String(), { description: "Paths to all per-job structured judge artifacts." }),
64
- comparisons_path: Type.String({ description: "Path to the durable JSON soft-scored comparisons ledger." }),
65
- ranking: Type.Array(Type.Object({
66
- label: Type.String(),
67
- meanPreference: Type.Number(),
68
- }, { additionalProperties: false }), { description: "All attempts ordered by mean preference." }),
69
- seed: Type.Integer({ description: "Seed used for the deterministic comparison schedule." }),
70
- artifact_dir: Type.String({ description: "Run-specific directory containing tournament artifacts." }),
71
- },
72
- run: async (ctx) => await runTournament(withSteeringPropagationContext(ctx)),
73
- });