@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.
- package/CHANGELOG.md +19 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/README.md +4 -4
- package/dist/builtin/intercom/broker/broker.ts +617 -22
- package/dist/builtin/intercom/broker/client-message-validation.ts +9 -0
- package/dist/builtin/intercom/broker/client.ts +200 -10
- package/dist/builtin/intercom/broker/pending-send-registry.ts +4 -0
- package/dist/builtin/intercom/broker/send-handler.ts +90 -36
- package/dist/builtin/intercom/broker/send-signature.ts +20 -8
- package/dist/builtin/intercom/group.ts +85 -0
- package/dist/builtin/intercom/index.bundle.mjs +680 -53
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/session-target.ts +54 -0
- package/dist/builtin/intercom/skills/intercom/SKILL.md +18 -3
- package/dist/builtin/intercom/source-ownership.ts +31 -0
- package/dist/builtin/intercom/types.ts +115 -0
- package/dist/builtin/mcp/index.bundle.mjs +109 -35
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +173 -51
- package/dist/builtin/web-access/index.bundle.mjs +109 -35
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +15 -0
- package/dist/builtin/workflows/README.md +40 -37
- package/dist/builtin/workflows/builtin/adversarial-verification.js +13 -0
- package/dist/builtin/workflows/builtin/{shared-prompts.ts → chunk-0x6e303p.js} +133 -154
- package/dist/builtin/workflows/builtin/chunk-29wrp38a.js +199 -0
- package/dist/builtin/workflows/builtin/chunk-2dqb5s2q.js +602 -0
- package/dist/builtin/workflows/builtin/chunk-4febxsv4.js +264 -0
- package/dist/builtin/workflows/builtin/chunk-5n10x7j2.js +69730 -0
- package/dist/builtin/workflows/builtin/chunk-5wgwscd0.js +4 -0
- package/dist/builtin/workflows/builtin/chunk-6fqs7c01.js +155 -0
- package/dist/builtin/workflows/builtin/chunk-7430zyas.js +126 -0
- package/dist/builtin/workflows/builtin/chunk-7at6dnkr.js +33 -0
- package/dist/builtin/workflows/builtin/chunk-82ha8p41.js +175 -0
- package/dist/builtin/workflows/builtin/chunk-bfkmzv9h.js +156 -0
- package/dist/builtin/workflows/builtin/chunk-c53y8bdh.js +345 -0
- package/dist/builtin/workflows/builtin/chunk-cdtd3m3w.js +529 -0
- package/dist/builtin/workflows/builtin/chunk-cg9tmks0.js +206 -0
- package/dist/builtin/workflows/builtin/chunk-hdpj1dkw.js +2447 -0
- package/dist/builtin/workflows/builtin/chunk-hzzn6adg.js +221 -0
- package/dist/builtin/workflows/builtin/chunk-nqr34qp3.js +1061 -0
- package/dist/builtin/workflows/builtin/chunk-qwzvgxnq.js +404 -0
- package/dist/builtin/workflows/builtin/chunk-qx2ptjs3.js +215 -0
- package/dist/builtin/workflows/builtin/chunk-v04c5qmd.js +1207 -0
- package/dist/builtin/workflows/builtin/chunk-wpckd35c.js +12 -0
- package/dist/builtin/workflows/builtin/chunk-x2ghn0je.js +4110 -0
- package/dist/builtin/workflows/builtin/chunk-zf28603f.js +1080 -0
- package/dist/builtin/workflows/builtin/classify-and-act.js +12 -0
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +10 -0
- package/dist/builtin/workflows/builtin/generate-and-filter.js +12 -0
- package/dist/builtin/workflows/builtin/goal.js +16 -0
- package/dist/builtin/workflows/builtin/index.js +49 -0
- package/dist/builtin/workflows/builtin/loop-until-done.js +12 -0
- package/dist/builtin/workflows/builtin/open-claude-design.js +11 -0
- package/dist/builtin/workflows/builtin/ralph.js +16 -0
- package/dist/builtin/workflows/builtin/steering-context.d.ts +6 -0
- package/dist/builtin/workflows/builtin/steering-context.js +7 -0
- package/dist/builtin/workflows/builtin/tournament.js +13 -0
- package/dist/builtin/workflows/package.json +10 -7
- package/dist/builtin/workflows/src/authoring/typebox-defaults.d.ts +41 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1228 -428
- package/dist/builtin/workflows/src/{index.bundle.mjs → index.js} +956 -427
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +403 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +327 -0
- package/dist/builtin/workflows/src/shared/budget.d.ts +67 -0
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +60 -0
- package/dist/builtin/workflows/src/shared/workflow-heartbeat-contract.d.ts +21 -0
- package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
- package/dist/core/agent-session-custom-message-commit.js +12 -5
- package/dist/core/agent-session-custom-message-commit.js.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +2 -0
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +2 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/builtin-install-layout.d.ts +1 -1
- package/dist/core/builtin-install-layout.d.ts.map +1 -1
- package/dist/core/builtin-install-layout.js +1 -1
- package/dist/core/builtin-install-layout.js.map +1 -1
- package/dist/core/codex-fast-mode.d.ts +10 -7
- package/dist/core/codex-fast-mode.d.ts.map +1 -1
- package/dist/core/codex-fast-mode.js +31 -13
- package/dist/core/codex-fast-mode.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +35 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +6 -1
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +4 -0
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +1 -0
- package/dist/core/runtime-credentials.d.ts.map +1 -1
- package/dist/core/runtime-credentials.js +8 -0
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -5
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-storage.d.ts +2 -0
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +4 -2
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/workflow-stage-admission.d.ts +6 -1
- package/dist/core/workflow-stage-admission.d.ts.map +1 -1
- package/dist/core/workflow-stage-admission.js +8 -9
- package/dist/core/workflow-stage-admission.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +1 -1
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts +4 -0
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +69 -10
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/rpc/rpc-client-api.d.ts +18 -2
- package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-api.js +33 -5
- package/dist/modes/rpc/rpc-client-api.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +8 -4
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/intercom.md +15 -6
- package/docs/packages.md +2 -2
- package/docs/providers.md +8 -3
- package/docs/quickstart.md +2 -2
- package/docs/rpc.md +21 -4
- package/docs/settings.md +6 -4
- package/docs/subagents.md +1 -1
- package/docs/usage.md +1 -1
- package/docs/workflows.md +108 -239
- package/npm-shrinkwrap.json +32 -32
- package/package.json +9 -13
- package/dist/builtin/workflows/ambient.d.ts +0 -61
- package/dist/builtin/workflows/builtin/adversarial-verification-prompts.ts +0 -26
- package/dist/builtin/workflows/builtin/adversarial-verification-runner.ts +0 -391
- package/dist/builtin/workflows/builtin/adversarial-verification.ts +0 -34
- package/dist/builtin/workflows/builtin/classify-and-act-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/classify-and-act-runner.ts +0 -108
- package/dist/builtin/workflows/builtin/classify-and-act.ts +0 -40
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts +0 -96
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.ts +0 -37
- package/dist/builtin/workflows/builtin/generate-and-filter-prompts.ts +0 -41
- package/dist/builtin/workflows/builtin/generate-and-filter-runner.ts +0 -90
- package/dist/builtin/workflows/builtin/generate-and-filter.ts +0 -31
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +0 -64
- package/dist/builtin/workflows/builtin/goal-convergence.ts +0 -87
- package/dist/builtin/workflows/builtin/goal-ledger.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-models.ts +0 -72
- package/dist/builtin/workflows/builtin/goal-orchestrator-prompts.ts +0 -94
- package/dist/builtin/workflows/builtin/goal-prompts.ts +0 -217
- package/dist/builtin/workflows/builtin/goal-reducer.ts +0 -176
- package/dist/builtin/workflows/builtin/goal-reports.ts +0 -76
- package/dist/builtin/workflows/builtin/goal-reverify.ts +0 -305
- package/dist/builtin/workflows/builtin/goal-review.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-runner.ts +0 -504
- package/dist/builtin/workflows/builtin/goal-schemas.ts +0 -89
- package/dist/builtin/workflows/builtin/goal-types.ts +0 -164
- package/dist/builtin/workflows/builtin/goal.ts +0 -78
- package/dist/builtin/workflows/builtin/index.ts +0 -16
- package/dist/builtin/workflows/builtin/loop-until-done-prompts.ts +0 -87
- package/dist/builtin/workflows/builtin/loop-until-done-runner.ts +0 -282
- package/dist/builtin/workflows/builtin/loop-until-done.ts +0 -51
- package/dist/builtin/workflows/builtin/open-claude-design-live-protocol.ts +0 -305
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +0 -337
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +0 -347
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +0 -313
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +0 -311
- package/dist/builtin/workflows/builtin/open-claude-design.ts +0 -57
- package/dist/builtin/workflows/builtin/pattern-artifact-root.ts +0 -28
- package/dist/builtin/workflows/builtin/progress-scoring.ts +0 -230
- package/dist/builtin/workflows/builtin/ralph-core.ts +0 -449
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +0 -100
- package/dist/builtin/workflows/builtin/ralph-models.ts +0 -183
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +0 -103
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +0 -104
- package/dist/builtin/workflows/builtin/ralph-runner.ts +0 -459
- package/dist/builtin/workflows/builtin/ralph.ts +0 -82
- package/dist/builtin/workflows/builtin/review-convergence.ts +0 -229
- package/dist/builtin/workflows/builtin/selection-math.ts +0 -156
- package/dist/builtin/workflows/builtin/steering-context.ts +0 -51
- package/dist/builtin/workflows/builtin/tournament-prompts.ts +0 -70
- package/dist/builtin/workflows/builtin/tournament-runner.ts +0 -400
- package/dist/builtin/workflows/builtin/tournament.ts +0 -73
- package/dist/builtin/workflows/builtin/verification-criteria.ts +0 -330
- package/dist/builtin/workflows/builtin/verification-prompts.ts +0 -206
- package/dist/builtin/workflows/builtin/verification-usage.ts +0 -44
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { writeFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { Type } from "typebox";
|
|
4
|
-
import type { WorkflowRunContext, WorkflowSerializableValue, WorkflowTaskStep } from "../src/shared/types.js";
|
|
5
|
-
import { branchPrompt, partitionPrompt, synthesisPrompt } from "./fan-out-and-synthesize-prompts.js";
|
|
6
|
-
import { stableArtifactRoot } from "./pattern-artifact-root.js";
|
|
7
|
-
|
|
8
|
-
const partitionSchema = Type.Object({
|
|
9
|
-
partitions: Type.Array(Type.Object({
|
|
10
|
-
label: Type.String({ minLength: 1 }),
|
|
11
|
-
objective: Type.String({ minLength: 1 }),
|
|
12
|
-
}, { additionalProperties: false }), { minItems: 1, maxItems: 12 }),
|
|
13
|
-
}, { additionalProperties: false });
|
|
14
|
-
|
|
15
|
-
type Inputs = {
|
|
16
|
-
readonly prompt: string;
|
|
17
|
-
readonly max_branches: number;
|
|
18
|
-
readonly max_concurrency: number;
|
|
19
|
-
} & Record<string, WorkflowSerializableValue>;
|
|
20
|
-
type Partition = { readonly label: string; readonly objective: string };
|
|
21
|
-
export type FanOutAndSynthesizeResult = {
|
|
22
|
-
readonly result: string;
|
|
23
|
-
readonly partitions: string[];
|
|
24
|
-
readonly branch_artifact_paths: string[];
|
|
25
|
-
readonly synthesis_path: string;
|
|
26
|
-
readonly artifact_dir: string;
|
|
27
|
-
readonly manifest_path: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
function safeName(value: string, index: number): string {
|
|
31
|
-
const normalized = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
32
|
-
return `${String(index + 1).padStart(2, "0")}-${normalized || "branch"}`;
|
|
33
|
-
}
|
|
34
|
-
function parsedPartitions(value: WorkflowSerializableValue | undefined, limit: number, prompt: string): Partition[] {
|
|
35
|
-
if (typeof value !== "object" || value === null || !("partitions" in value) || !Array.isArray(value.partitions)) {
|
|
36
|
-
return [{ label: "whole-task", objective: prompt }];
|
|
37
|
-
}
|
|
38
|
-
const result: Partition[] = [];
|
|
39
|
-
for (const candidate of value.partitions) {
|
|
40
|
-
if (typeof candidate !== "object" || candidate === null || !("label" in candidate) || !("objective" in candidate)) continue;
|
|
41
|
-
const label = String(candidate.label).trim();
|
|
42
|
-
const objective = String(candidate.objective).trim();
|
|
43
|
-
if (label !== "" && objective !== "") result.push({ label, objective });
|
|
44
|
-
if (result.length >= limit) break;
|
|
45
|
-
}
|
|
46
|
-
return result.length > 0 ? result : [{ label: "whole-task", objective: prompt }];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export async function runFanOutAndSynthesize(ctx: WorkflowRunContext<Inputs>): Promise<FanOutAndSynthesizeResult> {
|
|
50
|
-
const artifactDir = await stableArtifactRoot(ctx, "fan-out-and-synthesize");
|
|
51
|
-
const plan = await ctx.task("partition", {
|
|
52
|
-
prompt: partitionPrompt(ctx.inputs.prompt, ctx.inputs.max_branches),
|
|
53
|
-
schema: partitionSchema,
|
|
54
|
-
context: "fresh",
|
|
55
|
-
});
|
|
56
|
-
const partitions = parsedPartitions(plan.structured, ctx.inputs.max_branches, ctx.inputs.prompt);
|
|
57
|
-
const partitionPath = join(artifactDir, "partition-plan.json");
|
|
58
|
-
await writeFile(partitionPath, JSON.stringify({ task: ctx.inputs.prompt, partitions }, null, 2));
|
|
59
|
-
|
|
60
|
-
const branchPaths = partitions.map((partition, index) => join(artifactDir, `branch-${safeName(partition.label, index)}.md`));
|
|
61
|
-
const steps: WorkflowTaskStep[] = partitions.map((partition, index) => ({
|
|
62
|
-
name: `branch-${safeName(partition.label, index)}`,
|
|
63
|
-
prompt: branchPrompt({ prompt: ctx.inputs.prompt, ...partition }),
|
|
64
|
-
context: "fresh",
|
|
65
|
-
reads: [partitionPath],
|
|
66
|
-
output: branchPaths[index]!,
|
|
67
|
-
outputMode: "file-only",
|
|
68
|
-
}));
|
|
69
|
-
await ctx.parallel(steps, { concurrency: Math.min(ctx.inputs.max_concurrency, partitions.length), failFast: false });
|
|
70
|
-
|
|
71
|
-
const manifestPath = join(artifactDir, "manifest.json");
|
|
72
|
-
await writeFile(manifestPath, JSON.stringify({
|
|
73
|
-
task: ctx.inputs.prompt,
|
|
74
|
-
partition_plan: partitionPath,
|
|
75
|
-
branches: partitions.map((partition, index) => ({ ...partition, artifact_path: branchPaths[index] })),
|
|
76
|
-
}, null, 2));
|
|
77
|
-
const synthesisPath = join(artifactDir, "synthesis.md");
|
|
78
|
-
const synthesis = await ctx.task("synthesize", {
|
|
79
|
-
prompt: synthesisPrompt(ctx.inputs.prompt, manifestPath),
|
|
80
|
-
context: "fresh",
|
|
81
|
-
reads: [manifestPath, ...branchPaths],
|
|
82
|
-
output: synthesisPath,
|
|
83
|
-
outputMode: "file-only",
|
|
84
|
-
});
|
|
85
|
-
return {
|
|
86
|
-
// `file-only` already returns a compact artifact reference. Reading the file
|
|
87
|
-
// back here would defeat that and push the whole report into the caller's
|
|
88
|
-
// context; `synthesis_path` is returned for callers that want the contents.
|
|
89
|
-
result: synthesis.text,
|
|
90
|
-
partitions: partitions.map((partition) => partition.label),
|
|
91
|
-
branch_artifact_paths: branchPaths,
|
|
92
|
-
synthesis_path: synthesisPath,
|
|
93
|
-
artifact_dir: artifactDir,
|
|
94
|
-
manifest_path: manifestPath,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { Type } from "typebox";
|
|
2
|
-
import { workflow } from "../src/authoring/workflow.js";
|
|
3
|
-
import { withSteeringPropagationContext } from "./steering-context.js";
|
|
4
|
-
import { runFanOutAndSynthesize } from "./fan-out-and-synthesize-runner.js";
|
|
5
|
-
|
|
6
|
-
export default workflow({
|
|
7
|
-
name: "fan-out-and-synthesize",
|
|
8
|
-
description: "Partition a task, run bounded independent artifact branches, then synthesize all evidence at an explicit barrier.",
|
|
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 to partition, investigate, and synthesize." }),
|
|
15
|
-
max_branches: Type.Integer({
|
|
16
|
-
minimum: 1,
|
|
17
|
-
maximum: 12,
|
|
18
|
-
default: 4,
|
|
19
|
-
description: "Maximum number of independent partitions produced and executed.",
|
|
20
|
-
}),
|
|
21
|
-
max_concurrency: Type.Integer({
|
|
22
|
-
minimum: 1,
|
|
23
|
-
maximum: 12,
|
|
24
|
-
default: 4,
|
|
25
|
-
description: "Maximum number of branch agents running concurrently.",
|
|
26
|
-
}),
|
|
27
|
-
},
|
|
28
|
-
outputs: {
|
|
29
|
-
result: Type.String({ description: "Compact reference to the evidence-citing synthesis artifact; read `synthesis_path` for the full report." }),
|
|
30
|
-
partitions: Type.Array(Type.String(), { description: "Ordered labels for executed partitions." }),
|
|
31
|
-
branch_artifact_paths: Type.Array(Type.String(), { description: "Ordered branch artifact paths consumed by synthesis." }),
|
|
32
|
-
synthesis_path: Type.String({ description: "Final synthesis artifact path." }),
|
|
33
|
-
artifact_dir: Type.String({ description: "Per-run artifact directory." }),
|
|
34
|
-
manifest_path: Type.String({ description: "Barrier manifest linking partitions to branch artifacts." }),
|
|
35
|
-
},
|
|
36
|
-
run: async (ctx) => await runFanOutAndSynthesize(withSteeringPropagationContext(ctx)),
|
|
37
|
-
});
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { ScoringCandidate, SharedHead } from "./verification-prompts.js";
|
|
2
|
-
import { build_scoring_prompt, scoring_prompt_reads } from "./verification-prompts.js";
|
|
3
|
-
|
|
4
|
-
const GROUNDED_REPORTING = "Before reporting progress, audit each claim against a tool result from this session. Report only work you can point to evidence for; say so explicitly when something is unverified.";
|
|
5
|
-
const READABLE_REPORT = "Lead with the outcome. Keep facts, decisions, caveats, and next steps; drop background and repetition. Use complete, readable sentences rather than compressed fragments.";
|
|
6
|
-
|
|
7
|
-
export interface RenderedJudgePrompt {
|
|
8
|
-
readonly prompt: string;
|
|
9
|
-
readonly reads: readonly string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function renderGeneratorPrompt(task: string, ordinal: number): string {
|
|
13
|
-
return `<role>\nYou independently generate candidate ${ordinal}; do not imitate or assume other candidates.\n</role>\n\n<success_criteria>\nOne distinct, concrete candidate states its value, constraints, risks, and how it can be evaluated.\n</success_criteria>\n\n<stop_rules>\nStop after one self-contained, evaluable candidate; do not add alternatives.\n</stop_rules>\n\n<output_format>\nA candidate artifact with title, proposal, criteria-based rationale, risks, and evaluation evidence. ${READABLE_REPORT}\n${GROUNDED_REPORTING}\n</output_format>\n\n<objective>\n${task}\n</objective>`;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function renderFilterPrompt(task: string, candidatePaths: readonly string[], shortlistSize: number): string {
|
|
17
|
-
return `<artifacts>\nRead every candidate: ${candidatePaths.join(", ")}\n</artifacts>\n\n<role>\nYou deduplicate and filter independently generated candidates.\n</role>\n\n<rubric>\nFirst collapse substantively equivalent candidates. Then score fit to the task, feasibility, evidence, distinctiveness, and risk. Near-duplicates must not gain weight by repetition. Record every discarded candidate and a concrete reason.\n</rubric>\n\n<success_criteria>\nAt most ${shortlistSize} strongest distinct candidates remain, ranked by the rubric, and every discarded candidate has a concrete reason.\n</success_criteria>\n\n<stop_rules>\nStop after every candidate is shortlisted once or recorded as discarded.\n</stop_rules>\n\n<output_format>\nCall structured_output with shortlist (candidate artifact paths in ranked order) and discarded entries containing path and a concise, criteria-based reason.\n</output_format>\n\n<objective>\nSelect at most ${shortlistSize} strongest candidates for: ${task}\n</objective>`;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function renderJudgePrompt(
|
|
21
|
-
task: string,
|
|
22
|
-
filterPath: string,
|
|
23
|
-
shortlistSize: number,
|
|
24
|
-
candidates: readonly ScoringCandidate[] = [],
|
|
25
|
-
): RenderedJudgePrompt {
|
|
26
|
-
const head: SharedHead = {
|
|
27
|
-
task: `Rank at most ${shortlistSize} distinct candidate paths for: ${task}.`,
|
|
28
|
-
groundTruthNote: `Read the filter report at ${filterPath} and every candidate path it references before judging.`,
|
|
29
|
-
candidates,
|
|
30
|
-
outputFormat: "Call structured_output with shortlist (candidate paths in ranked order) and rationale (a concise, criteria-based explanation).",
|
|
31
|
-
};
|
|
32
|
-
const prompt = build_scoring_prompt(head, {
|
|
33
|
-
id: "filtered_shortlist",
|
|
34
|
-
name: "Filtered shortlist",
|
|
35
|
-
description: "Check task fit, feasibility, evidence, distinctiveness, and material risk; do not restore a duplicate merely because it is phrased differently.",
|
|
36
|
-
});
|
|
37
|
-
return { prompt, reads: [filterPath, ...scoring_prompt_reads(head)] };
|
|
38
|
-
}
|
|
39
|
-
export function renderFinalShortlistPrompt(task: string, decisionPath: string): string {
|
|
40
|
-
return `<artifact>\nRead the authoritative selection at ${decisionPath}; follow its order and do not add candidates.\n</artifact>\n\n<role>\nYou present a concise, actionable final shortlist so the reader can choose the next evaluation without reading the selection session.\n</role>\n\n<success_criteria>\nEvery selected candidate appears once in authoritative order with its differentiator, evidence, tradeoffs, and recommended next evaluation.\n</success_criteria>\n\n<stop_rules>\nStop after presenting every selected candidate once; do not add or reorder candidates.\n</stop_rules>\n\n<output_format>\nRanked markdown shortlist with candidate path, differentiator, evidence, tradeoffs, and recommended next evaluation. ${READABLE_REPORT}\n${GROUNDED_REPORTING}\n</output_format>\n\n<objective>\nSummarize the selected candidates for: ${task}\n</objective>`;
|
|
41
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { Type, type Static } from "typebox";
|
|
4
|
-
import type { WorkflowRunContext, WorkflowSerializableValue } from "../src/shared/types.js";
|
|
5
|
-
import { renderFilterPrompt, renderFinalShortlistPrompt, renderGeneratorPrompt, renderJudgePrompt } from "./generate-and-filter-prompts.js";
|
|
6
|
-
import { stableArtifactRoot } from "./pattern-artifact-root.js";
|
|
7
|
-
|
|
8
|
-
const filterSchema = Type.Object({
|
|
9
|
-
shortlist: Type.Array(Type.String()),
|
|
10
|
-
discarded: Type.Array(Type.Object({ path: Type.String(), reason: Type.String() }, { additionalProperties: false })),
|
|
11
|
-
}, { additionalProperties: false });
|
|
12
|
-
const judgeSchema = Type.Object({ shortlist: Type.Array(Type.String()), rationale: Type.String() }, { additionalProperties: false });
|
|
13
|
-
type FilterDecision = Static<typeof filterSchema>;
|
|
14
|
-
type JudgeDecision = Static<typeof judgeSchema>;
|
|
15
|
-
type Inputs = { readonly prompt: string; readonly num_candidates: number; readonly shortlist_size: number; readonly use_judge: boolean; readonly max_concurrency: number } & Record<string, WorkflowSerializableValue>;
|
|
16
|
-
export type GenerateAndFilterResult = {
|
|
17
|
-
readonly result: string;
|
|
18
|
-
readonly shortlist: string[];
|
|
19
|
-
readonly candidate_artifact_paths: string[];
|
|
20
|
-
readonly filter_path: string;
|
|
21
|
-
readonly judge_path: string | null;
|
|
22
|
-
readonly final_path: string;
|
|
23
|
-
readonly artifact_dir: string;
|
|
24
|
-
readonly manifest_path: string;
|
|
25
|
-
};
|
|
26
|
-
function isRecord(value: WorkflowSerializableValue): value is Record<string, WorkflowSerializableValue> { return typeof value === "object" && value !== null && !Array.isArray(value); }
|
|
27
|
-
function strings(value: WorkflowSerializableValue | undefined): value is string[] { return Array.isArray(value) && value.every((entry) => typeof entry === "string"); }
|
|
28
|
-
function filterDecision(value: WorkflowSerializableValue | undefined): FilterDecision | undefined {
|
|
29
|
-
if (value === undefined || !isRecord(value) || !strings(value.shortlist) || !Array.isArray(value.discarded)) return undefined;
|
|
30
|
-
const valid = value.discarded.every((entry) => isRecord(entry) && typeof entry.path === "string" && typeof entry.reason === "string");
|
|
31
|
-
return valid ? value as FilterDecision : undefined;
|
|
32
|
-
}
|
|
33
|
-
function judgeDecision(value: WorkflowSerializableValue | undefined): JudgeDecision | undefined {
|
|
34
|
-
return value !== undefined && isRecord(value) && strings(value.shortlist) && typeof value.rationale === "string" ? value as JudgeDecision : undefined;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export async function runGenerateAndFilter(ctx: WorkflowRunContext<Inputs>): Promise<GenerateAndFilterResult> {
|
|
38
|
-
const root = await stableArtifactRoot(ctx, "generate-and-filter");
|
|
39
|
-
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) => join(root, `candidate-${index + 1}.md`));
|
|
40
|
-
const shortlistLimit = Math.min(ctx.inputs.shortlist_size, ctx.inputs.num_candidates);
|
|
41
|
-
await ctx.parallel(candidatePaths.map((path, index) => ({
|
|
42
|
-
name: `generate-${index + 1}`, prompt: renderGeneratorPrompt(ctx.inputs.prompt, index + 1), context: "fresh" as const,
|
|
43
|
-
output: path, outputMode: "file-only" as const,
|
|
44
|
-
})), { concurrency: ctx.inputs.max_concurrency, failFast: false });
|
|
45
|
-
const manifestPath = join(root, "manifest.json");
|
|
46
|
-
await writeFile(manifestPath, JSON.stringify({ task: ctx.inputs.prompt, candidate_artifact_paths: candidatePaths }, null, 2));
|
|
47
|
-
|
|
48
|
-
const filterPath = join(root, "filter.json");
|
|
49
|
-
const filtered = await ctx.task("dedupe-and-filter", {
|
|
50
|
-
prompt: renderFilterPrompt(ctx.inputs.prompt, candidatePaths, shortlistLimit), context: "fresh",
|
|
51
|
-
reads: [manifestPath, ...candidatePaths], schema: filterSchema,
|
|
52
|
-
});
|
|
53
|
-
const filteredDecision = filterDecision(filtered.structured);
|
|
54
|
-
// The filter report is inter-stage data: the judge and final-shortlist
|
|
55
|
-
// stages read schema-shaped JSON from this path, so the runner persists the
|
|
56
|
-
// structured decision itself rather than routing it through the artifact.
|
|
57
|
-
await writeFile(filterPath, `${JSON.stringify(filteredDecision ?? { shortlist: [], discarded: [] }, null, 2)}\n`);
|
|
58
|
-
const selectCandidates = (paths: readonly string[]): string[] => [...new Set(paths.filter((path) => candidatePaths.includes(path)))].slice(0, shortlistLimit);
|
|
59
|
-
const fallbackShortlist = candidatePaths.slice(0, shortlistLimit);
|
|
60
|
-
const filteredShortlist = selectCandidates(filteredDecision?.shortlist ?? []);
|
|
61
|
-
let shortlist = filteredShortlist.length > 0 ? filteredShortlist : fallbackShortlist;
|
|
62
|
-
let judgePath: string | null = null;
|
|
63
|
-
let decisionPath = filterPath;
|
|
64
|
-
if (ctx.inputs.use_judge) {
|
|
65
|
-
judgePath = join(root, "judge.json");
|
|
66
|
-
const judgeCandidates = await Promise.all(
|
|
67
|
-
shortlist.map(async (path) => ({ path, body: await readFile(path, "utf8") })),
|
|
68
|
-
);
|
|
69
|
-
const judgePrompt = renderJudgePrompt(ctx.inputs.prompt, filterPath, shortlistLimit, judgeCandidates);
|
|
70
|
-
const judged = await ctx.task("judge", {
|
|
71
|
-
prompt: judgePrompt.prompt, context: "fresh",
|
|
72
|
-
reads: judgePrompt.reads, schema: judgeSchema,
|
|
73
|
-
});
|
|
74
|
-
const judgedDecision = judgeDecision(judged.structured);
|
|
75
|
-
// Same inter-stage contract as the filter report above.
|
|
76
|
-
await writeFile(judgePath, `${JSON.stringify(judgedDecision ?? { shortlist: [], rationale: "Judge stage produced no valid structured decision." }, null, 2)}\n`);
|
|
77
|
-
const judgedShortlist = selectCandidates(judgedDecision?.shortlist ?? []);
|
|
78
|
-
shortlist = judgedShortlist.length > 0 ? judgedShortlist : shortlist;
|
|
79
|
-
decisionPath = judgePath;
|
|
80
|
-
}
|
|
81
|
-
const finalPath = join(root, "shortlist.md");
|
|
82
|
-
const finalShortlist = await ctx.task("final-shortlist", {
|
|
83
|
-
prompt: renderFinalShortlistPrompt(ctx.inputs.prompt, decisionPath), context: "fresh",
|
|
84
|
-
reads: [decisionPath, ...shortlist], output: finalPath, outputMode: "file-only",
|
|
85
|
-
});
|
|
86
|
-
// `file-only` already returns a compact artifact reference. Reading the file
|
|
87
|
-
// back here would defeat that and push the whole report into the caller's
|
|
88
|
-
// context; `final_path` is returned for callers that want the contents.
|
|
89
|
-
return { result: finalShortlist.text, shortlist, candidate_artifact_paths: candidatePaths, filter_path: filterPath, judge_path: judgePath, final_path: finalPath, artifact_dir: root, manifest_path: manifestPath };
|
|
90
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { Type } from "typebox";
|
|
2
|
-
import { workflow } from "../src/authoring/workflow.js";
|
|
3
|
-
import { withSteeringPropagationContext } from "./steering-context.js";
|
|
4
|
-
import { runGenerateAndFilter } from "./generate-and-filter-runner.js";
|
|
5
|
-
|
|
6
|
-
export default workflow({
|
|
7
|
-
name: "generate-and-filter",
|
|
8
|
-
description: "Generate more independent candidates than needed, deduplicate and filter them by rubric, optionally judge them, and return a parent-consumable shortlist.",
|
|
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: "Prompt for candidate generation and selection." }),
|
|
15
|
-
num_candidates: Type.Integer({ minimum: 2, maximum: 20, default: 8, description: "Number of independent candidates to generate." }),
|
|
16
|
-
shortlist_size: Type.Integer({ minimum: 1, maximum: 10, default: 3, description: "Maximum number of candidates in the final shortlist." }),
|
|
17
|
-
use_judge: Type.Boolean({ default: true, description: "Whether an independent judge reviews the filtered shortlist." }),
|
|
18
|
-
max_concurrency: Type.Integer({ minimum: 1, maximum: 12, default: 4, description: "Maximum simultaneous generator stages." }),
|
|
19
|
-
},
|
|
20
|
-
outputs: {
|
|
21
|
-
result: Type.String({ description: "Compact reference to the final shortlist report artifact; read `final_path` for the full report." }),
|
|
22
|
-
shortlist: Type.Array(Type.String(), { description: "Ranked paths to selected candidate artifacts." }),
|
|
23
|
-
candidate_artifact_paths: Type.Array(Type.String(), { description: "Paths to every generated candidate artifact." }),
|
|
24
|
-
filter_path: Type.String({ description: "Path to the dedupe and filter decision." }),
|
|
25
|
-
judge_path: Type.Union([Type.String(), Type.Null()], { description: "Path to the optional judge decision, or null when disabled." }),
|
|
26
|
-
final_path: Type.String({ description: "Path to the final shortlist report." }),
|
|
27
|
-
artifact_dir: Type.String({ description: "Directory containing run artifacts." }),
|
|
28
|
-
manifest_path: Type.String({ description: "Path to the candidate artifact manifest." }),
|
|
29
|
-
},
|
|
30
|
-
run: async (ctx) => await runGenerateAndFilter(withSteeringPropagationContext(ctx)),
|
|
31
|
-
});
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { writeFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import type { ReviewDecision, ReviewRecord } from "./goal-types.js";
|
|
4
|
-
import {
|
|
5
|
-
consolidateFindingsBatch,
|
|
6
|
-
type ConsolidatedFinding,
|
|
7
|
-
type ReviewConvergenceSummary,
|
|
8
|
-
} from "./review-convergence.js";
|
|
9
|
-
import type { ReverifyAuditEntry, ReverifiableFinding } from "./goal-reverify.js";
|
|
10
|
-
|
|
11
|
-
export function artifactSafeName(value: string): string {
|
|
12
|
-
const safe = value
|
|
13
|
-
.toLowerCase()
|
|
14
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
15
|
-
.replace(/^-+|-+$/g, "");
|
|
16
|
-
return safe.length > 0 ? safe : "artifact";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function withoutTurn<T extends { readonly turn: number }>(value: T): Omit<T, "turn"> {
|
|
20
|
-
const copy = { ...value } as Omit<T, "turn"> & { turn?: number };
|
|
21
|
-
delete copy.turn;
|
|
22
|
-
return copy;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function writeReviewArtifact(
|
|
26
|
-
artifactDir: string,
|
|
27
|
-
reviewer: string,
|
|
28
|
-
decision: ReviewDecision,
|
|
29
|
-
rawText: string,
|
|
30
|
-
convergenceDecision: ReviewConvergenceSummary,
|
|
31
|
-
): Promise<string> {
|
|
32
|
-
const artifactPath = join(
|
|
33
|
-
artifactDir,
|
|
34
|
-
`review-${artifactSafeName(reviewer)}.json`,
|
|
35
|
-
);
|
|
36
|
-
await writeFile(
|
|
37
|
-
artifactPath,
|
|
38
|
-
`${JSON.stringify({ reviewer, decision, convergence_decision: convergenceDecision, raw_text: rawText }, null, 2)}\n`,
|
|
39
|
-
{ encoding: "utf8" },
|
|
40
|
-
);
|
|
41
|
-
return artifactPath;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export async function writeReviewRoundArtifact(
|
|
45
|
-
artifactDir: string,
|
|
46
|
-
reviews: readonly ReviewRecord[],
|
|
47
|
-
consolidatedFindings: readonly ConsolidatedFinding<ReverifiableFinding>[] = consolidateFindingsBatch(
|
|
48
|
-
reviews.map((review) => ({
|
|
49
|
-
reviewer: review.reviewer,
|
|
50
|
-
findings: review.findings,
|
|
51
|
-
})),
|
|
52
|
-
),
|
|
53
|
-
reverification: readonly ReverifyAuditEntry<ReverifiableFinding>[] = [],
|
|
54
|
-
): Promise<string> {
|
|
55
|
-
const artifactPath = join(artifactDir, "review-round-latest.json");
|
|
56
|
-
const visibleReviews = reviews.map(withoutTurn);
|
|
57
|
-
await writeFile(
|
|
58
|
-
artifactPath,
|
|
59
|
-
`${JSON.stringify({ reviews: visibleReviews, consolidated_findings: consolidatedFindings, reverification }, null, 2)}\n`,
|
|
60
|
-
{ encoding: "utf8" },
|
|
61
|
-
);
|
|
62
|
-
return artifactPath;
|
|
63
|
-
}
|
|
64
|
-
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Convergence evidence is observational only: it never approves, never
|
|
3
|
-
* terminates, never touches `stop_review_loop`, and feeds only
|
|
4
|
-
* `needs_human`-class escalation text.
|
|
5
|
-
*/
|
|
6
|
-
import type { UsageTotals } from "./verification-usage.js";
|
|
7
|
-
import {
|
|
8
|
-
classify_trend,
|
|
9
|
-
DEFAULT_FALL_DELTA,
|
|
10
|
-
DEFAULT_RISE_DELTA,
|
|
11
|
-
type TrendResult,
|
|
12
|
-
} from "./progress-scoring.js";
|
|
13
|
-
import { VERIFICATION_SCALE } from "./verification-criteria.js";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* `fractionProven` remains in its natural [0, 1] units. V7's hysteresis
|
|
17
|
-
* thresholds span a proportional part of `VERIFICATION_SCALE`, so applying
|
|
18
|
-
* that same proportion to the unit interval keeps the two series comparable
|
|
19
|
-
* without hard-coding a fraction-specific magic number.
|
|
20
|
-
*/
|
|
21
|
-
export const FRACTION_TREND_RISE_DELTA =
|
|
22
|
-
DEFAULT_RISE_DELTA / (VERIFICATION_SCALE.max - VERIFICATION_SCALE.min);
|
|
23
|
-
export const FRACTION_TREND_FALL_DELTA =
|
|
24
|
-
DEFAULT_FALL_DELTA / (VERIFICATION_SCALE.max - VERIFICATION_SCALE.min);
|
|
25
|
-
|
|
26
|
-
export type ConvergenceEntry = {
|
|
27
|
-
readonly unresolvedBlockingCount: number;
|
|
28
|
-
readonly meanFindingConfidence: number | null;
|
|
29
|
-
readonly fractionProven: number;
|
|
30
|
-
readonly demotions: number;
|
|
31
|
-
readonly usage: UsageTotals;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/** Purely shape one already-folded review round into a ledger entry. */
|
|
35
|
-
export function record_convergence(round: {
|
|
36
|
-
readonly unresolvedBlockingCount: number;
|
|
37
|
-
readonly meanFindingConfidence: number | null;
|
|
38
|
-
readonly fractionProven: number;
|
|
39
|
-
readonly demotions: number;
|
|
40
|
-
readonly usage: UsageTotals;
|
|
41
|
-
}): ConvergenceEntry {
|
|
42
|
-
return {
|
|
43
|
-
unresolvedBlockingCount: round.unresolvedBlockingCount,
|
|
44
|
-
meanFindingConfidence: round.meanFindingConfidence,
|
|
45
|
-
fractionProven: round.fractionProven,
|
|
46
|
-
demotions: round.demotions,
|
|
47
|
-
usage: round.usage,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function classify_convergence(entries: readonly ConvergenceEntry[]): {
|
|
52
|
-
blocking: TrendResult;
|
|
53
|
-
proven: TrendResult;
|
|
54
|
-
} {
|
|
55
|
-
return {
|
|
56
|
-
blocking: classify_trend(entries.map((entry) => entry.unresolvedBlockingCount)),
|
|
57
|
-
proven: classify_trend(entries.map((entry) => entry.fractionProven), {
|
|
58
|
-
riseDelta: FRACTION_TREND_RISE_DELTA,
|
|
59
|
-
fallDelta: FRACTION_TREND_FALL_DELTA,
|
|
60
|
-
}),
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* A FALLING `unresolvedBlockingCount` (classified "regressing" on the raw
|
|
66
|
-
* series) and a RISING `fractionProven` are the converging directions. A
|
|
67
|
-
* rising blocking count is never suppressed because it is the worsening
|
|
68
|
-
* direction on the axis the objective names first.
|
|
69
|
-
*/
|
|
70
|
-
export function convergence_escalation_evidence(
|
|
71
|
-
entries: readonly ConvergenceEntry[],
|
|
72
|
-
): readonly string[] {
|
|
73
|
-
if (entries.length === 0) return [];
|
|
74
|
-
const { blocking, proven } = classify_convergence(entries);
|
|
75
|
-
if (blocking.trend === "regressing" || (proven.trend === "rising" && blocking.trend !== "rising")) return [];
|
|
76
|
-
|
|
77
|
-
const latest = entries[entries.length - 1]?.meanFindingConfidence;
|
|
78
|
-
return [
|
|
79
|
-
`${entries.length} round${entries.length === 1 ? "" : "s"} recorded; no observed convergence: the blocking-count trend is ${blocking.trend}.`,
|
|
80
|
-
`Blocking-count trend: ${blocking.trend}; raw series: ${JSON.stringify(blocking.evidence.series)}.`,
|
|
81
|
-
`Fraction-proven trend: ${proven.trend}; raw series: ${JSON.stringify(proven.evidence.series)}.`,
|
|
82
|
-
latest === null
|
|
83
|
-
? "Latest mean finding confidence: no findings were filed."
|
|
84
|
-
: `Latest mean finding confidence: ${latest}.`,
|
|
85
|
-
"This is escalation EVIDENCE only; it never approves or terminates anything.",
|
|
86
|
-
];
|
|
87
|
-
}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
|
-
import { LEDGER_FILENAME, type GoalLedger, type GoalLifecycleEvent } from "./goal-types.js";
|
|
5
|
-
|
|
6
|
-
const LEDGER_STATE_FILENAME = "goal-ledger-state.json";
|
|
7
|
-
|
|
8
|
-
type ModelVisibleGoalLedger = Omit<
|
|
9
|
-
GoalLedger,
|
|
10
|
-
"turns" | "receipts" | "reviews" | "blockers" | "decisions" | "lifecycle"
|
|
11
|
-
> & {
|
|
12
|
-
readonly receipts: ReadonlyArray<Omit<GoalLedger["receipts"][number], "turn">>;
|
|
13
|
-
readonly reviews: ReadonlyArray<Omit<GoalLedger["reviews"][number], "turn">>;
|
|
14
|
-
readonly blockers: ReadonlyArray<Omit<GoalLedger["blockers"][number], "turn">>;
|
|
15
|
-
readonly decisions: ReadonlyArray<Omit<GoalLedger["decisions"][number], "turn">>;
|
|
16
|
-
readonly lifecycle: ReadonlyArray<Omit<GoalLedger["lifecycle"][number], "turn">>;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
function withoutTurn<T extends { readonly turn: number }>(value: T): Omit<T, "turn"> {
|
|
20
|
-
const copy = { ...value } as Omit<T, "turn"> & { turn?: number };
|
|
21
|
-
delete copy.turn;
|
|
22
|
-
return copy;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function modelVisibleLedger(ledger: GoalLedger): ModelVisibleGoalLedger {
|
|
26
|
-
return {
|
|
27
|
-
goal_id: ledger.goal_id,
|
|
28
|
-
objective: ledger.objective,
|
|
29
|
-
acceptance_criteria: ledger.acceptance_criteria,
|
|
30
|
-
status: ledger.status,
|
|
31
|
-
created_at: ledger.created_at,
|
|
32
|
-
updated_at: ledger.updated_at,
|
|
33
|
-
receipts: ledger.receipts.map(withoutTurn),
|
|
34
|
-
reviews: ledger.reviews.map(withoutTurn),
|
|
35
|
-
blockers: ledger.blockers.map(withoutTurn),
|
|
36
|
-
decisions: ledger.decisions.map(withoutTurn),
|
|
37
|
-
lifecycle: ledger.lifecycle.map(withoutTurn),
|
|
38
|
-
reverification: ledger.reverification ?? [],
|
|
39
|
-
convergence: ledger.convergence ?? [],
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function goalLedgerStatePath(ledgerPath: string): string {
|
|
44
|
-
return join(dirname(ledgerPath), LEDGER_STATE_FILENAME);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function appendLifecycleEvent(
|
|
48
|
-
ledger: GoalLedger,
|
|
49
|
-
event: GoalLifecycleEvent["event"],
|
|
50
|
-
summary: string,
|
|
51
|
-
turn = ledger.turns,
|
|
52
|
-
): void {
|
|
53
|
-
ledger.lifecycle.push({
|
|
54
|
-
turn,
|
|
55
|
-
event,
|
|
56
|
-
status: ledger.status,
|
|
57
|
-
at: new Date().toISOString(),
|
|
58
|
-
summary,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Restore only lossless authoritative state. A model-visible legacy ledger has
|
|
64
|
-
* no turn fields, so treating it as fresh is safer than fabricating reducer state.
|
|
65
|
-
*
|
|
66
|
-
* A sidecar that cannot be parsed is treated as absent for the same reason: the
|
|
67
|
-
* authoritative file is published by atomic rename below, so unparsable content
|
|
68
|
-
* means a torn write from before that guarantee (or a foreign file). Starting
|
|
69
|
-
* fresh loses recorded turns; throwing here would instead make the whole
|
|
70
|
-
* continuation unable to start.
|
|
71
|
-
*/
|
|
72
|
-
async function readExistingGoalLedger(ledgerPath: string): Promise<GoalLedger | undefined> {
|
|
73
|
-
let contents: string;
|
|
74
|
-
try {
|
|
75
|
-
contents = await readFile(goalLedgerStatePath(ledgerPath), "utf8");
|
|
76
|
-
} catch (error) {
|
|
77
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT") return undefined;
|
|
78
|
-
throw error;
|
|
79
|
-
}
|
|
80
|
-
try {
|
|
81
|
-
return JSON.parse(contents) as GoalLedger;
|
|
82
|
-
} catch {
|
|
83
|
-
return undefined;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
export async function createGoalLedger(
|
|
87
|
-
objective: string,
|
|
88
|
-
acceptanceCriteria: string,
|
|
89
|
-
artifactDir: string,
|
|
90
|
-
): Promise<{ ledger: GoalLedger; ledgerPath: string; artifactDir: string }> {
|
|
91
|
-
const ledgerPath = join(artifactDir, LEDGER_FILENAME);
|
|
92
|
-
const existing = await readExistingGoalLedger(ledgerPath);
|
|
93
|
-
if (existing !== undefined) return { ledger: existing, ledgerPath, artifactDir };
|
|
94
|
-
|
|
95
|
-
const goalId = randomUUID();
|
|
96
|
-
const now = new Date().toISOString();
|
|
97
|
-
const ledger: GoalLedger = {
|
|
98
|
-
goal_id: goalId,
|
|
99
|
-
objective,
|
|
100
|
-
acceptance_criteria: acceptanceCriteria,
|
|
101
|
-
status: "active",
|
|
102
|
-
turns: 0,
|
|
103
|
-
created_at: now,
|
|
104
|
-
updated_at: now,
|
|
105
|
-
receipts: [],
|
|
106
|
-
reviews: [],
|
|
107
|
-
blockers: [],
|
|
108
|
-
decisions: [],
|
|
109
|
-
lifecycle: [],
|
|
110
|
-
reverification: [],
|
|
111
|
-
convergence: [],
|
|
112
|
-
};
|
|
113
|
-
appendLifecycleEvent(ledger, "created", "Goal created.", 0);
|
|
114
|
-
await writeGoalLedger(ledgerPath, ledger);
|
|
115
|
-
return { ledger, ledgerPath, artifactDir };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export async function writeGoalLedger(
|
|
119
|
-
ledgerPath: string,
|
|
120
|
-
ledger: GoalLedger,
|
|
121
|
-
): Promise<void> {
|
|
122
|
-
ledger.updated_at = new Date().toISOString();
|
|
123
|
-
const visibleContents = `${JSON.stringify(modelVisibleLedger(ledger), null, 2)}\n`;
|
|
124
|
-
const stateContents = `${JSON.stringify(ledger, null, 2)}\n`;
|
|
125
|
-
const statePath = goalLedgerStatePath(ledgerPath);
|
|
126
|
-
// The sidecar is the authoritative resume state, so it is published by a
|
|
127
|
-
// complete same-directory write followed by an atomic rename. Overwriting it
|
|
128
|
-
// in place leaves a partial file readable when a write is interrupted, and
|
|
129
|
-
// the next continuation would then start from nothing.
|
|
130
|
-
const pendingStatePath = `${statePath}.${randomUUID()}.tmp`;
|
|
131
|
-
await writeFile(pendingStatePath, stateContents, { encoding: "utf8" });
|
|
132
|
-
try {
|
|
133
|
-
await rename(pendingStatePath, statePath);
|
|
134
|
-
} catch (error) {
|
|
135
|
-
await rm(pendingStatePath, { force: true });
|
|
136
|
-
throw error;
|
|
137
|
-
}
|
|
138
|
-
await writeFile(ledgerPath, visibleContents, { encoding: "utf8" });
|
|
139
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { reviewDecisionSchema } from "./goal-schemas.js";
|
|
2
|
-
|
|
3
|
-
// Keep this model list identical to Ralph's orchestrator while preserving a
|
|
4
|
-
// locally contained Goal configuration.
|
|
5
|
-
export const orchestratorModelConfig = {
|
|
6
|
-
model: "anthropic/claude-opus-5:high",
|
|
7
|
-
fallbackModels: [
|
|
8
|
-
"github-copilot/claude-opus-5:high",
|
|
9
|
-
"openai-codex/gpt-5.6-sol:xhigh",
|
|
10
|
-
"github-copilot/gpt-5.6-sol:xhigh",
|
|
11
|
-
"openai/gpt-5.6-sol:xhigh",
|
|
12
|
-
"anthropic/claude-fable-5:high",
|
|
13
|
-
"github-copilot/claude-fable-5:high",
|
|
14
|
-
"kimi-coding/k3:max",
|
|
15
|
-
"moonshotai/kimi-k3:max",
|
|
16
|
-
"moonshotai-cn/kimi-k3:max",
|
|
17
|
-
"openai-codex/gpt-5.5:xhigh",
|
|
18
|
-
"github-copilot/gpt-5.5:xhigh",
|
|
19
|
-
"openai/gpt-5.5:xhigh",
|
|
20
|
-
"anthropic/claude-opus-4-8:high",
|
|
21
|
-
"github-copilot/claude-opus-4.8:high",
|
|
22
|
-
"xai/grok-4.6:xhigh",
|
|
23
|
-
"github-copilot/grok-4.6:xhigh",
|
|
24
|
-
"zai/glm-5.3:high",
|
|
25
|
-
"zai-coding-cn/glm-5.3:high",
|
|
26
|
-
"openrouter/anthropic/claude-opus-5:high",
|
|
27
|
-
"openrouter/openai/gpt-5.6-sol:xhigh",
|
|
28
|
-
"openrouter/anthropic/claude-fable-5:high",
|
|
29
|
-
"openrouter/moonshotai/kimi-k3:max",
|
|
30
|
-
"openrouter/sakana/fugu-ultra:high",
|
|
31
|
-
"openrouter/openai/gpt-5.5:xhigh",
|
|
32
|
-
"openrouter/anthropic/claude-opus-4-8:high",
|
|
33
|
-
"openrouter/x-ai/grok-4.6",
|
|
34
|
-
],
|
|
35
|
-
excludedTools: ["ask_user_question"],
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// Keep Goal's reviewer configuration independent so GPT-5.6 precedes Kimi K3
|
|
39
|
-
// within both the leading direct-provider group and the OpenRouter group.
|
|
40
|
-
export const reviewerModelConfig = {
|
|
41
|
-
model: "anthropic/claude-opus-5:high",
|
|
42
|
-
fallbackModels: [
|
|
43
|
-
"github-copilot/claude-opus-5:high",
|
|
44
|
-
"anthropic/claude-fable-5:high",
|
|
45
|
-
"github-copilot/claude-fable-5:high",
|
|
46
|
-
"openai-codex/gpt-5.6-sol:xhigh",
|
|
47
|
-
"github-copilot/gpt-5.6-sol:xhigh",
|
|
48
|
-
"openai/gpt-5.6-sol:xhigh",
|
|
49
|
-
"kimi-coding/k3:max",
|
|
50
|
-
"moonshotai/kimi-k3:max",
|
|
51
|
-
"moonshotai-cn/kimi-k3:max",
|
|
52
|
-
"openai-codex/gpt-5.5:xhigh",
|
|
53
|
-
"github-copilot/gpt-5.5:xhigh",
|
|
54
|
-
"openai/gpt-5.5:xhigh",
|
|
55
|
-
"anthropic/claude-opus-4-8:high",
|
|
56
|
-
"github-copilot/claude-opus-4.8:high",
|
|
57
|
-
"xai/grok-4.6:xhigh",
|
|
58
|
-
"github-copilot/grok-4.6:xhigh",
|
|
59
|
-
"zai/glm-5.3:high",
|
|
60
|
-
"zai-coding-cn/glm-5.3:high",
|
|
61
|
-
"openrouter/anthropic/claude-opus-5:high",
|
|
62
|
-
"openrouter/anthropic/claude-fable-5:high",
|
|
63
|
-
"openrouter/openai/gpt-5.6-sol:xhigh",
|
|
64
|
-
"openrouter/moonshotai/kimi-k3:max",
|
|
65
|
-
"openrouter/sakana/fugu-ultra:high",
|
|
66
|
-
"openrouter/openai/gpt-5.5:xhigh",
|
|
67
|
-
"openrouter/anthropic/claude-opus-4-8:high",
|
|
68
|
-
"openrouter/x-ai/grok-4.6",
|
|
69
|
-
],
|
|
70
|
-
excludedTools: ["ask_user_question"],
|
|
71
|
-
schema: reviewDecisionSchema,
|
|
72
|
-
};
|