@bastani/atomic 0.9.4 → 0.9.5-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/agents/debugger.md +2 -2
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +19 -0
- package/dist/builtin/workflows/README.md +13 -11
- package/dist/builtin/workflows/builtin/deep-research-codebase-utils.ts +9 -8
- package/dist/builtin/workflows/builtin/goal-ledger.ts +3 -0
- package/dist/builtin/workflows/builtin/goal-prompts.ts +15 -4
- package/dist/builtin/workflows/builtin/goal-reports.ts +23 -0
- package/dist/builtin/workflows/builtin/goal-review.ts +29 -4
- package/dist/builtin/workflows/builtin/goal-runner.ts +7 -4
- package/dist/builtin/workflows/builtin/goal-schemas.ts +22 -0
- package/dist/builtin/workflows/builtin/goal-types.ts +17 -0
- package/dist/builtin/workflows/builtin/goal.d.ts +3 -0
- package/dist/builtin/workflows/builtin/goal.ts +4 -2
- package/dist/builtin/workflows/builtin/index.d.ts +6 -0
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +1 -0
- package/dist/builtin/workflows/builtin/ralph-core.ts +39 -2
- package/dist/builtin/workflows/builtin/ralph-models.ts +44 -47
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +29 -4
- package/dist/builtin/workflows/builtin/ralph-runner.ts +12 -5
- package/dist/builtin/workflows/builtin/ralph.d.ts +3 -0
- package/dist/builtin/workflows/builtin/ralph.ts +4 -1
- package/dist/builtin/workflows/builtin/shared-prompts.ts +15 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +1 -1
- package/docs/workflows.md +9 -4
- package/npm-shrinkwrap.json +23 -23
- package/package.json +2 -2
|
@@ -13,9 +13,10 @@ import { DEFAULT_MAX_TURNS } from "./goal-types.js";
|
|
|
13
13
|
|
|
14
14
|
export default workflow({
|
|
15
15
|
name: "goal",
|
|
16
|
-
description: "Goal Runner workflow with bounded LM turns, ledger artifacts, parallel reviewers, and reducer-gated completion.",
|
|
16
|
+
description: "Goal Runner workflow with bounded LM turns, immutable acceptance criteria, ledger artifacts, parallel reviewers, and reducer-gated completion. When launching follow-up goal runs from review findings, pass the ORIGINAL task text as acceptance_criteria so deltas cannot drift from the literal contract.",
|
|
17
17
|
inputs: {
|
|
18
|
-
objective: Type.String({ description: "The objective for
|
|
18
|
+
objective: Type.String({ description: "The objective or delta for this Goal Runner workflow run." }),
|
|
19
|
+
acceptance_criteria: Type.Optional(Type.String({ description: "Original immutable task contract this run must remain consistent with. Defaults to objective. Orchestrators launching follow-up runs from reviewer findings should pass the ORIGINAL task text here." })),
|
|
19
20
|
max_turns: Type.Number({
|
|
20
21
|
default: DEFAULT_MAX_TURNS,
|
|
21
22
|
description: "Maximum worker/review turns before Goal Runner stops as needs_human.",
|
|
@@ -39,6 +40,7 @@ export default workflow({
|
|
|
39
40
|
approved: Type.Optional(Type.Boolean({ description: "Whether the reducer reached complete." })),
|
|
40
41
|
goal_id: Type.Optional(Type.String({ description: "Per-run goal identifier stored in the ledger." })),
|
|
41
42
|
objective: Type.Optional(Type.String({ description: "Raw goal objective used by the run." })),
|
|
43
|
+
acceptance_criteria: Type.Optional(Type.String({ description: "Immutable acceptance criteria used by the run." })),
|
|
42
44
|
ledger_path: Type.Optional(Type.String({ description: "OS-temp path to goal-ledger.json with receipts, reviewer decisions, blockers, and lifecycle events." })),
|
|
43
45
|
turns_completed: Type.Optional(Type.Number({ description: "Worker/review turns completed." })),
|
|
44
46
|
iterations_completed: Type.Optional(Type.Number({ description: "Worker/review turns completed, retained for status summaries." })),
|
|
@@ -37,12 +37,14 @@ export type GoalWorkflowReceipt = {
|
|
|
37
37
|
};
|
|
38
38
|
export type GoalWorkflowInputs = WorkflowInputValues & {
|
|
39
39
|
readonly objective: string;
|
|
40
|
+
readonly acceptance_criteria?: string;
|
|
40
41
|
readonly max_turns: number;
|
|
41
42
|
readonly base_branch: string;
|
|
42
43
|
readonly create_pr: boolean;
|
|
43
44
|
};
|
|
44
45
|
export type GoalWorkflowRunInputs = WorkflowInputValues & {
|
|
45
46
|
readonly objective: string;
|
|
47
|
+
readonly acceptance_criteria?: string;
|
|
46
48
|
readonly max_turns?: number;
|
|
47
49
|
readonly base_branch?: string;
|
|
48
50
|
readonly create_pr?: boolean;
|
|
@@ -53,6 +55,7 @@ export type GoalWorkflowOutputs = WorkflowOutputValues & {
|
|
|
53
55
|
readonly approved?: boolean;
|
|
54
56
|
readonly goal_id?: string;
|
|
55
57
|
readonly objective?: string;
|
|
58
|
+
readonly acceptance_criteria?: string;
|
|
56
59
|
readonly ledger_path?: string;
|
|
57
60
|
readonly turns_completed?: number;
|
|
58
61
|
readonly iterations_completed?: number;
|
|
@@ -70,6 +73,7 @@ export type GoalWorkflowDefinition = WorkflowDefinition<
|
|
|
70
73
|
|
|
71
74
|
export type RalphWorkflowInputs = WorkflowInputValues & {
|
|
72
75
|
readonly prompt: string;
|
|
76
|
+
readonly acceptance_criteria?: string;
|
|
73
77
|
readonly max_loops: number;
|
|
74
78
|
readonly base_branch: string;
|
|
75
79
|
readonly git_worktree_dir: string;
|
|
@@ -77,6 +81,7 @@ export type RalphWorkflowInputs = WorkflowInputValues & {
|
|
|
77
81
|
};
|
|
78
82
|
export type RalphWorkflowRunInputs = WorkflowInputValues & {
|
|
79
83
|
readonly prompt: string;
|
|
84
|
+
readonly acceptance_criteria?: string;
|
|
80
85
|
readonly max_loops?: number;
|
|
81
86
|
readonly base_branch?: string;
|
|
82
87
|
readonly git_worktree_dir?: string;
|
|
@@ -89,6 +94,7 @@ export type RalphWorkflowOutputs = WorkflowOutputValues & {
|
|
|
89
94
|
readonly research?: string;
|
|
90
95
|
readonly research_path?: string;
|
|
91
96
|
readonly implementation_notes_path?: string;
|
|
97
|
+
readonly qa_video_path?: string;
|
|
92
98
|
readonly pr_report?: string;
|
|
93
99
|
readonly approved?: boolean;
|
|
94
100
|
readonly iterations_completed?: number;
|
|
@@ -86,6 +86,7 @@ export async function runOpenClaudeDesignWorkflow(ctx: OpenClaudeDesignContext):
|
|
|
86
86
|
"zai-coding-cn/glm-5.2:xhigh",
|
|
87
87
|
"openrouter/anthropic/claude-fable-5:xhigh",
|
|
88
88
|
"openrouter/anthropic/claude-opus-4-8:xhigh",
|
|
89
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
89
90
|
"openrouter/z-ai/glm-5.2:xhigh"
|
|
90
91
|
],
|
|
91
92
|
};
|
|
@@ -3,7 +3,7 @@ import { tmpdir } from "node:os";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { Type } from "typebox";
|
|
5
5
|
import type { WorkflowTaskResult } from "../src/shared/types.js";
|
|
6
|
-
import { E2E_VERIFICATION_GUIDANCE } from "./shared-prompts.js";
|
|
6
|
+
import { E2E_VERIFICATION_GUIDANCE, LITERAL_OBJECTIVE_CONTRACT } from "./shared-prompts.js";
|
|
7
7
|
import type { ReviewDecision } from "./ralph-review-gate.js";
|
|
8
8
|
|
|
9
9
|
export const DEFAULT_MAX_LOOPS = 10;
|
|
@@ -26,6 +26,12 @@ const reviewFindingSchema = Type.Object(
|
|
|
26
26
|
title: Type.String(),
|
|
27
27
|
body: Type.String(),
|
|
28
28
|
confidence_score: Type.Number({ minimum: 0, maximum: 1 }),
|
|
29
|
+
objective_alignment: Type.Union([
|
|
30
|
+
Type.Literal("required_by_objective"),
|
|
31
|
+
Type.Literal("consistent_with_objective"),
|
|
32
|
+
Type.Literal("beyond_objective"),
|
|
33
|
+
Type.Literal("contradicts_objective"),
|
|
34
|
+
]),
|
|
29
35
|
priority: Type.Optional(
|
|
30
36
|
Type.Union([Type.Integer({ minimum: 0, maximum: 3 }), Type.Null()]),
|
|
31
37
|
),
|
|
@@ -46,6 +52,20 @@ const reviewFindingSchema = Type.Object(
|
|
|
46
52
|
{ additionalProperties: false },
|
|
47
53
|
);
|
|
48
54
|
|
|
55
|
+
const requirementsTraceabilitySchema = Type.Object(
|
|
56
|
+
{
|
|
57
|
+
requirement: Type.String(),
|
|
58
|
+
status: Type.Union([
|
|
59
|
+
Type.Literal("proven"),
|
|
60
|
+
Type.Literal("contradicted"),
|
|
61
|
+
Type.Literal("missing"),
|
|
62
|
+
Type.Literal("unverified"),
|
|
63
|
+
]),
|
|
64
|
+
evidence: Type.String(),
|
|
65
|
+
},
|
|
66
|
+
{ additionalProperties: false },
|
|
67
|
+
);
|
|
68
|
+
|
|
49
69
|
const reviewerErrorSchema = Type.Object(
|
|
50
70
|
{
|
|
51
71
|
kind: Type.Union([
|
|
@@ -69,6 +89,7 @@ export const reviewDecisionSchema = Type.Object(
|
|
|
69
89
|
]),
|
|
70
90
|
overall_explanation: Type.String(),
|
|
71
91
|
overall_confidence_score: Type.Number({ minimum: 0, maximum: 1 }),
|
|
92
|
+
requirements_traceability: Type.Array(requirementsTraceabilitySchema),
|
|
72
93
|
stop_review_loop: Type.Boolean(),
|
|
73
94
|
reviewer_error: Type.Optional(
|
|
74
95
|
Type.Union([Type.Null(), reviewerErrorSchema]),
|
|
@@ -170,6 +191,7 @@ export function renderQaE2eVideoGuidance(qaVideoPath: string): string {
|
|
|
170
191
|
`Record that QA E2E pass as a reviewable video so the user can watch the feature working. After \`playwright-cli open\`, start recording with \`playwright-cli video-start ${qaVideoPath}\`, annotate the scenario with \`playwright-cli video-chapter\` / \`playwright-cli video-show-actions\`, exercise the full user scenario, then \`playwright-cli video-stop\`. Write the video to exactly this path and overwrite any prior recording so it always reflects the latest implemented state: ${qaVideoPath}`,
|
|
171
192
|
`After recording, add the video to the implementation notes as a reference: include a \`## QA E2E Video\` entry with the absolute path ${qaVideoPath} and a one-line description of the proven scenario, so the user can review the proof when this stage finishes.`,
|
|
172
193
|
"If the change has no user-visible UI scenario (pure refactor, docs, infra, or non-UI library code), do not fabricate a video; record in the implementation notes that no QA E2E video applies and why.",
|
|
194
|
+
"Assume credentials, auth, and browser environment access exist until a concrete attempt proves otherwise. Before declaring the QA E2E video impractical, check credential/auth state with non-destructive commands, attempt to launch the app/flow, and record the exact command(s) plus observed failure output.",
|
|
173
195
|
"If `playwright-cli` or a browser runtime is unavailable, install it once per the skill (`npm install -g @playwright/cli@latest`, then `npx playwright install chromium` for a missing browser executable). If it still cannot run, record the smallest validation actually performed and note that the QA E2E video could not be produced — never claim a video exists when it does not.",
|
|
174
196
|
].join("\n");
|
|
175
197
|
}
|
|
@@ -186,6 +208,7 @@ export function reviewerErrorDecision(error: string): ReviewDecision {
|
|
|
186
208
|
"Reviewer execution failed, so the review gate cannot safely approve the current repository state.",
|
|
187
209
|
overall_confidence_score: 0,
|
|
188
210
|
stop_review_loop: false,
|
|
211
|
+
requirements_traceability: [],
|
|
189
212
|
reviewer_error: {
|
|
190
213
|
kind: "reviewer_failure",
|
|
191
214
|
message: error,
|
|
@@ -258,6 +281,7 @@ export function forkContinuationOptions(
|
|
|
258
281
|
|
|
259
282
|
export function renderResearchPromptRefinementPrompt(args: {
|
|
260
283
|
readonly request: string;
|
|
284
|
+
readonly acceptanceCriteria: string;
|
|
261
285
|
readonly workflowCwdContext: PromptSection;
|
|
262
286
|
readonly latestReviewReportPath: string | undefined;
|
|
263
287
|
}): string {
|
|
@@ -265,6 +289,9 @@ export function renderResearchPromptRefinementPrompt(args: {
|
|
|
265
289
|
return [
|
|
266
290
|
basePrompt,
|
|
267
291
|
taggedPrompt([
|
|
292
|
+
["objective", `Research the full requested task: ${args.request}`],
|
|
293
|
+
["acceptance_criteria", args.acceptanceCriteria],
|
|
294
|
+
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
268
295
|
args.workflowCwdContext,
|
|
269
296
|
[
|
|
270
297
|
"review_findings",
|
|
@@ -272,7 +299,7 @@ export function renderResearchPromptRefinementPrompt(args: {
|
|
|
272
299
|
? "No prior review artifact is available."
|
|
273
300
|
: [
|
|
274
301
|
`Latest review round artifact: ${args.latestReviewReportPath}`,
|
|
275
|
-
"Read this JSON artifact and include unresolved reviewer findings in the transformed research question
|
|
302
|
+
"Read this JSON artifact and include unresolved reviewer findings in the transformed research question only when they are consistent with the literal objective and acceptance criteria.",
|
|
276
303
|
].join("\n"),
|
|
277
304
|
],
|
|
278
305
|
[
|
|
@@ -285,6 +312,8 @@ export function renderResearchPromptRefinementPrompt(args: {
|
|
|
285
312
|
|
|
286
313
|
export function renderResearchPrompt(args: {
|
|
287
314
|
readonly transformedResearchQuestion: string;
|
|
315
|
+
readonly prompt: string;
|
|
316
|
+
readonly acceptanceCriteria: string;
|
|
288
317
|
readonly workflowCwdContext: PromptSection;
|
|
289
318
|
readonly latestReviewReportPath: string | undefined;
|
|
290
319
|
readonly researchPath: string;
|
|
@@ -293,6 +322,9 @@ export function renderResearchPrompt(args: {
|
|
|
293
322
|
return [
|
|
294
323
|
basePrompt,
|
|
295
324
|
taggedPrompt([
|
|
325
|
+
["objective", `Research implementation requirements for: ${args.prompt}`],
|
|
326
|
+
["acceptance_criteria", args.acceptanceCriteria],
|
|
327
|
+
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
296
328
|
args.workflowCwdContext,
|
|
297
329
|
[
|
|
298
330
|
"review_findings",
|
|
@@ -318,6 +350,7 @@ export function renderResearchPrompt(args: {
|
|
|
318
350
|
|
|
319
351
|
export function renderForkedOrchestratorPrompt(args: {
|
|
320
352
|
readonly prompt: string;
|
|
353
|
+
readonly acceptanceCriteria: string;
|
|
321
354
|
readonly workflowCwdContext: PromptSection;
|
|
322
355
|
readonly researchPath: string;
|
|
323
356
|
readonly implementationNotesPath: string;
|
|
@@ -331,6 +364,8 @@ export function renderForkedOrchestratorPrompt(args: {
|
|
|
331
364
|
].join("\n"),
|
|
332
365
|
],
|
|
333
366
|
["objective", `Implement the full requested task: ${args.prompt}`],
|
|
367
|
+
["acceptance_criteria", args.acceptanceCriteria],
|
|
368
|
+
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
334
369
|
args.workflowCwdContext,
|
|
335
370
|
[
|
|
336
371
|
"research",
|
|
@@ -367,6 +402,7 @@ export function renderForkedOrchestratorPrompt(args: {
|
|
|
367
402
|
|
|
368
403
|
export type RalphInputs = {
|
|
369
404
|
readonly prompt?: string;
|
|
405
|
+
readonly acceptance_criteria?: string;
|
|
370
406
|
readonly max_loops?: number;
|
|
371
407
|
readonly base_branch?: string;
|
|
372
408
|
readonly git_worktree_dir?: string;
|
|
@@ -375,6 +411,7 @@ export type RalphInputs = {
|
|
|
375
411
|
|
|
376
412
|
export type RalphWorkflowOptions = {
|
|
377
413
|
readonly prompt: string;
|
|
414
|
+
readonly acceptanceCriteria: string;
|
|
378
415
|
readonly maxLoops: number;
|
|
379
416
|
readonly comparisonBaseBranch: string;
|
|
380
417
|
readonly workflowStartCwd: string;
|
|
@@ -1,41 +1,34 @@
|
|
|
1
1
|
import { reviewDecisionSchema } from "./ralph-core.js";
|
|
2
2
|
|
|
3
|
-
// Model chains are curated from Atomic's agentic-coding benchmark
|
|
4
|
-
//
|
|
5
|
-
// -
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// - Dropped as strictly dominated: claude-sonnet-5 (40-54% at $4-26, up to
|
|
15
|
-
// 268 steps), claude-sonnet-4.6 (30%/$5.52), gemini-3.1-pro (12%/$9.48),
|
|
16
|
-
// gemini-3.5-flash (37%/$7.34, 276k output tokens).
|
|
17
|
-
// - claude-opus-4.8 rides at :high — its value point (52%/$4.28); :xhigh
|
|
18
|
-
// doubles the cost for +2pts.
|
|
19
|
-
// - glm-5.2 is reviewer-C's diversity primary only (third model family
|
|
20
|
-
// decorrelates review errors); elsewhere it is a budget fallback. Note:
|
|
21
|
-
// GLM-5.2 has only two real reasoning tiers — its thinkingLevelMap collapses
|
|
3
|
+
// Model chains are curated from Atomic's agentic-coding benchmark and the
|
|
4
|
+
// July 2026 frontier refresh:
|
|
5
|
+
// - Critical synthesis/review stages prefer fable-5:xhigh, then gpt-5.5 xhigh
|
|
6
|
+
// variants, openrouter fugu-ultra, long-context opus, and GLM fallbacks.
|
|
7
|
+
// - Research remains on gpt-5.5:medium / fable-5:low for perf-per-dollar.
|
|
8
|
+
// - Reviewer B keeps gpt-5.5:xhigh as an independent frontier family;
|
|
9
|
+
// reviewer C leads with GLM-5.2 xhigh, with openrouter fugu-ultra retained
|
|
10
|
+
// mid-chain, to decorrelate review errors.
|
|
11
|
+
// - Dominated benchmark models stay out of the chains: claude-sonnet-5,
|
|
12
|
+
// claude-sonnet-4.6, gemini-3.1-pro, and gemini-3.5-flash.
|
|
13
|
+
// - GLM-5.2 has only two real reasoning tiers — its thinkingLevelMap collapses
|
|
22
14
|
// minimal/low/medium/high to "high" and xhigh to "max" — so chains only use
|
|
23
15
|
// :high (budget tier, 36%/$2.84) or :xhigh (best tier, 44%/$3.92); the
|
|
24
16
|
// openrouter/z-ai mirror maps :xhigh exclusively, so it is always :xhigh.
|
|
25
17
|
|
|
26
18
|
export const promptEngineerModelConfig = {
|
|
27
|
-
model: "
|
|
19
|
+
model: "anthropic/claude-fable-5:xhigh",
|
|
28
20
|
fallbackModels: [
|
|
21
|
+
"openai-codex/gpt-5.5:xhigh",
|
|
29
22
|
"github-copilot/gpt-5.5:xhigh",
|
|
30
23
|
"openai/gpt-5.5:xhigh",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"anthropic/claude-opus-4-8:high",
|
|
24
|
+
"github-copilot/claude-opus-4.8 (1m):xhigh",
|
|
25
|
+
"anthropic/claude-opus-4-8:xhigh",
|
|
34
26
|
"zai/glm-5.2:xhigh",
|
|
35
27
|
"zai-coding-cn/glm-5.2:xhigh",
|
|
36
|
-
"openrouter/openai/gpt-5.5:xhigh",
|
|
37
28
|
"openrouter/anthropic/claude-fable-5:xhigh",
|
|
38
|
-
"openrouter/
|
|
29
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
30
|
+
"openrouter/openai/gpt-5.5:xhigh",
|
|
31
|
+
"openrouter/anthropic/claude-opus-4-8:xhigh",
|
|
39
32
|
"openrouter/z-ai/glm-5.2:xhigh"
|
|
40
33
|
],
|
|
41
34
|
excludedTools: ["ask_user_question"],
|
|
@@ -60,19 +53,20 @@ export const researchModelConfig = {
|
|
|
60
53
|
};
|
|
61
54
|
|
|
62
55
|
export const orchestratorModelConfig = {
|
|
63
|
-
model: "
|
|
56
|
+
model: "anthropic/claude-fable-5:xhigh",
|
|
64
57
|
fallbackModels: [
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
58
|
+
"openai-codex/gpt-5.5:xhigh",
|
|
59
|
+
"github-copilot/gpt-5.5:xhigh",
|
|
60
|
+
"openai/gpt-5.5:xhigh",
|
|
61
|
+
"github-copilot/claude-opus-4.8 (1m):xhigh",
|
|
62
|
+
"anthropic/claude-opus-4-8:xhigh",
|
|
63
|
+
"zai/glm-5.2:xhigh",
|
|
64
|
+
"zai-coding-cn/glm-5.2:xhigh",
|
|
65
|
+
"openrouter/anthropic/claude-fable-5:xhigh",
|
|
66
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
67
|
+
"openrouter/openai/gpt-5.5:xhigh",
|
|
68
|
+
"openrouter/anthropic/claude-opus-4-8:xhigh",
|
|
69
|
+
"openrouter/z-ai/glm-5.2:xhigh"
|
|
76
70
|
],
|
|
77
71
|
excludedTools: ["ask_user_question"],
|
|
78
72
|
};
|
|
@@ -83,13 +77,14 @@ export const reviewerAModelConfig = {
|
|
|
83
77
|
"openai-codex/gpt-5.5:xhigh",
|
|
84
78
|
"github-copilot/gpt-5.5:xhigh",
|
|
85
79
|
"openai/gpt-5.5:xhigh",
|
|
86
|
-
"github-copilot/claude-opus-4.8 (1m):
|
|
87
|
-
"anthropic/claude-opus-4-8:
|
|
80
|
+
"github-copilot/claude-opus-4.8 (1m):xhigh",
|
|
81
|
+
"anthropic/claude-opus-4-8:xhigh",
|
|
88
82
|
"zai/glm-5.2:xhigh",
|
|
89
83
|
"zai-coding-cn/glm-5.2:xhigh",
|
|
90
84
|
"openrouter/anthropic/claude-fable-5:xhigh",
|
|
85
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
91
86
|
"openrouter/openai/gpt-5.5:xhigh",
|
|
92
|
-
"openrouter/anthropic/claude-opus-4-8:
|
|
87
|
+
"openrouter/anthropic/claude-opus-4-8:xhigh",
|
|
93
88
|
"openrouter/z-ai/glm-5.2:xhigh"
|
|
94
89
|
],
|
|
95
90
|
excludedTools: ["ask_user_question"],
|
|
@@ -102,13 +97,14 @@ export const reviewerBModelConfig = {
|
|
|
102
97
|
"github-copilot/gpt-5.5:xhigh",
|
|
103
98
|
"openai/gpt-5.5:xhigh",
|
|
104
99
|
"anthropic/claude-fable-5:xhigh",
|
|
105
|
-
"github-copilot/claude-opus-4.8 (1m):
|
|
106
|
-
"anthropic/claude-opus-4-8:
|
|
100
|
+
"github-copilot/claude-opus-4.8 (1m):xhigh",
|
|
101
|
+
"anthropic/claude-opus-4-8:xhigh",
|
|
107
102
|
"zai/glm-5.2:xhigh",
|
|
108
103
|
"zai-coding-cn/glm-5.2:xhigh",
|
|
109
104
|
"openrouter/openai/gpt-5.5:xhigh",
|
|
110
105
|
"openrouter/anthropic/claude-fable-5:xhigh",
|
|
111
|
-
"openrouter/
|
|
106
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
107
|
+
"openrouter/anthropic/claude-opus-4-8:xhigh",
|
|
112
108
|
"openrouter/z-ai/glm-5.2:xhigh"
|
|
113
109
|
],
|
|
114
110
|
excludedTools: ["ask_user_question"],
|
|
@@ -119,16 +115,17 @@ export const reviewerCModelConfig = {
|
|
|
119
115
|
model: "zai/glm-5.2:xhigh",
|
|
120
116
|
fallbackModels: [
|
|
121
117
|
"zai-coding-cn/glm-5.2:xhigh",
|
|
122
|
-
"openrouter/z-ai/glm-5.2:xhigh",
|
|
123
118
|
"openai-codex/gpt-5.5:xhigh",
|
|
124
119
|
"github-copilot/gpt-5.5:xhigh",
|
|
125
120
|
"openai/gpt-5.5:xhigh",
|
|
126
121
|
"anthropic/claude-fable-5:xhigh",
|
|
127
|
-
"github-copilot/claude-opus-4.8 (1m):
|
|
128
|
-
"anthropic/claude-opus-4-8:
|
|
122
|
+
"github-copilot/claude-opus-4.8 (1m):xhigh",
|
|
123
|
+
"anthropic/claude-opus-4-8:xhigh",
|
|
124
|
+
"openrouter/sakana/fugu-ultra:high",
|
|
125
|
+
"openrouter/z-ai/glm-5.2:xhigh",
|
|
129
126
|
"openrouter/openai/gpt-5.5:xhigh",
|
|
130
127
|
"openrouter/anthropic/claude-fable-5:xhigh",
|
|
131
|
-
"openrouter/anthropic/claude-opus-4-8:
|
|
128
|
+
"openrouter/anthropic/claude-opus-4-8:xhigh"
|
|
132
129
|
],
|
|
133
130
|
excludedTools: ["ask_user_question"],
|
|
134
131
|
schema: reviewDecisionSchema,
|
|
@@ -23,10 +23,17 @@
|
|
|
23
23
|
* depend on the model correctly deriving that flag.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
+
export type ObjectiveAlignment =
|
|
27
|
+
| "required_by_objective"
|
|
28
|
+
| "consistent_with_objective"
|
|
29
|
+
| "beyond_objective"
|
|
30
|
+
| "contradicts_objective";
|
|
31
|
+
|
|
26
32
|
export type ReviewFinding = {
|
|
27
33
|
readonly title: string;
|
|
28
34
|
readonly body: string;
|
|
29
35
|
readonly confidence_score: number;
|
|
36
|
+
readonly objective_alignment: ObjectiveAlignment;
|
|
30
37
|
readonly priority?: number | null;
|
|
31
38
|
readonly code_location: {
|
|
32
39
|
readonly absolute_file_path: string;
|
|
@@ -46,12 +53,19 @@ export type ReviewerError = {
|
|
|
46
53
|
readonly message: string;
|
|
47
54
|
readonly attempted_recovery: string;
|
|
48
55
|
};
|
|
56
|
+
export type RequirementTraceability = {
|
|
57
|
+
readonly requirement: string;
|
|
58
|
+
readonly status: "proven" | "contradicted" | "missing" | "unverified";
|
|
59
|
+
readonly evidence: string;
|
|
60
|
+
};
|
|
61
|
+
|
|
49
62
|
|
|
50
63
|
export type ReviewDecision = {
|
|
51
64
|
readonly findings: readonly ReviewFinding[];
|
|
52
65
|
readonly overall_correctness: "patch is correct" | "patch is incorrect";
|
|
53
66
|
readonly overall_explanation: string;
|
|
54
67
|
readonly overall_confidence_score: number;
|
|
68
|
+
readonly requirements_traceability: readonly RequirementTraceability[];
|
|
55
69
|
readonly stop_review_loop: boolean;
|
|
56
70
|
readonly reviewer_error?: ReviewerError | null;
|
|
57
71
|
};
|
|
@@ -69,6 +83,13 @@ export const MAX_BLOCKING_PRIORITY = 2;
|
|
|
69
83
|
* approves.
|
|
70
84
|
*/
|
|
71
85
|
export function isBlockingFinding(finding: ReviewFinding): boolean {
|
|
86
|
+
const alignment = finding.objective_alignment;
|
|
87
|
+
if (alignment === "beyond_objective" || alignment === "contradicts_objective") {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
if (alignment !== "required_by_objective" && alignment !== "consistent_with_objective") {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
72
93
|
const priority = finding.priority;
|
|
73
94
|
if (priority === undefined || priority === null) return true;
|
|
74
95
|
return priority <= MAX_BLOCKING_PRIORITY;
|
|
@@ -76,14 +97,18 @@ export function isBlockingFinding(finding: ReviewFinding): boolean {
|
|
|
76
97
|
|
|
77
98
|
/**
|
|
78
99
|
* A single reviewer approves (would stop the loop) when it judged the patch
|
|
79
|
-
* correct, surfaced no reviewer execution error,
|
|
80
|
-
*
|
|
81
|
-
*
|
|
100
|
+
* correct, surfaced no reviewer execution error, filed no blocking (P0/P1/P2)
|
|
101
|
+
* finding, and supplied a non-empty requirement traceability map where every
|
|
102
|
+
* explicit requirement is proven. P3 nice-to-haves and placeholder/dummy
|
|
103
|
+
* findings do not block approval.
|
|
82
104
|
*/
|
|
83
105
|
export function reviewDecisionApproved(decision: ReviewDecision): boolean {
|
|
106
|
+
const traceability = decision.requirements_traceability;
|
|
84
107
|
return (
|
|
85
108
|
decision.overall_correctness === "patch is correct" &&
|
|
86
109
|
decision.reviewer_error == null &&
|
|
87
|
-
!decision.findings.some(isBlockingFinding)
|
|
110
|
+
!decision.findings.some(isBlockingFinding) &&
|
|
111
|
+
traceability.length > 0 &&
|
|
112
|
+
traceability.every((entry) => entry.status === "proven")
|
|
88
113
|
);
|
|
89
114
|
}
|
|
@@ -5,6 +5,7 @@ import { join, resolve } from "node:path";
|
|
|
5
5
|
import type { WorkflowRunContext, WorkflowTaskResult } from "../src/shared/types.js";
|
|
6
6
|
import {
|
|
7
7
|
E2E_VERIFICATION_GUIDANCE,
|
|
8
|
+
LITERAL_OBJECTIVE_CONTRACT,
|
|
8
9
|
WORKER_PREFLIGHT_CONTRACT,
|
|
9
10
|
renderE2eQaVideoReviewGuidance,
|
|
10
11
|
} from "./shared-prompts.js";
|
|
@@ -43,7 +44,7 @@ export async function runRalphWorkflow(
|
|
|
43
44
|
ctx: WorkflowRunContext<RalphInputs>,
|
|
44
45
|
options: RalphWorkflowOptions,
|
|
45
46
|
): Promise<RalphWorkflowResult> {
|
|
46
|
-
const { prompt, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr } = options;
|
|
47
|
+
const { prompt, acceptanceCriteria, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr } = options;
|
|
47
48
|
let latestReviewReportPath: string | undefined;
|
|
48
49
|
let finalPlan = "";
|
|
49
50
|
let finalPlanPath = "";
|
|
@@ -68,6 +69,7 @@ export async function runRalphWorkflow(
|
|
|
68
69
|
const researchPromptRefinement = await ctx.task(`research-prompt-refinement-${iteration}`, {
|
|
69
70
|
prompt: renderResearchPromptRefinementPrompt({
|
|
70
71
|
request: workflowPrompt,
|
|
72
|
+
acceptanceCriteria,
|
|
71
73
|
workflowCwdContext,
|
|
72
74
|
latestReviewReportPath,
|
|
73
75
|
}),
|
|
@@ -81,6 +83,8 @@ export async function runRalphWorkflow(
|
|
|
81
83
|
const research = await ctx.task(`research-${iteration}`, {
|
|
82
84
|
prompt: renderResearchPrompt({
|
|
83
85
|
transformedResearchQuestion: researchPromptRefinement.text,
|
|
86
|
+
prompt: workflowPrompt,
|
|
87
|
+
acceptanceCriteria,
|
|
84
88
|
workflowCwdContext,
|
|
85
89
|
latestReviewReportPath,
|
|
86
90
|
researchPath: workflowResearchPath,
|
|
@@ -108,6 +112,8 @@ export async function runRalphWorkflow(
|
|
|
108
112
|
"objective",
|
|
109
113
|
`Implement the full requested task: ${workflowPrompt}`,
|
|
110
114
|
],
|
|
115
|
+
["acceptance_criteria", acceptanceCriteria],
|
|
116
|
+
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
111
117
|
workflowCwdContext,
|
|
112
118
|
[
|
|
113
119
|
"research",
|
|
@@ -195,6 +201,7 @@ export async function runRalphWorkflow(
|
|
|
195
201
|
])
|
|
196
202
|
: renderForkedOrchestratorPrompt({
|
|
197
203
|
prompt: workflowPrompt,
|
|
204
|
+
acceptanceCriteria,
|
|
198
205
|
workflowCwdContext,
|
|
199
206
|
researchPath,
|
|
200
207
|
implementationNotesPath,
|
|
@@ -220,6 +227,8 @@ export async function runRalphWorkflow(
|
|
|
220
227
|
].join("\n"),
|
|
221
228
|
],
|
|
222
229
|
["objective", `Review the current code delta for the task: ${workflowPrompt}`],
|
|
230
|
+
["acceptance_criteria", acceptanceCriteria],
|
|
231
|
+
["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
|
|
223
232
|
workflowCwdContext,
|
|
224
233
|
[
|
|
225
234
|
"comparison_baseline",
|
|
@@ -279,6 +288,7 @@ export async function runRalphWorkflow(
|
|
|
279
288
|
[
|
|
280
289
|
"Each finding title must start with a priority tag: [P0] drop-everything blocker, [P1] urgent next-cycle fix, [P2] normal fix, [P3] low-priority nice-to-have.",
|
|
281
290
|
"Also include numeric priority: 0 for P0, 1 for P1, 2 for P2, 3 for P3; use null only if priority genuinely cannot be determined. Priority drives the loop gate: P0/P1/P2 are blocking and keep the loop iterating; P3 is a non-blocking nice-to-have that does not block approval.",
|
|
291
|
+
"Classify every finding with objective_alignment: required_by_objective (the objective/acceptance criteria require fixing it), consistent_with_objective (valid defect within scope), beyond_objective (real issue but not required and must not block or be promoted without explicit reconciliation), or contradicts_objective (fixing it would violate literal objective wording and must never be implemented; escalate to the human). Missing/unknown classification is blocking.",
|
|
282
292
|
"The body must be one concise paragraph explaining why this is a bug and the exact scenario, environment, or inputs required for it to arise.",
|
|
283
293
|
"Use a matter-of-fact, non-accusatory tone. Grumpy skepticism belongs in your standards, not in insults; avoid praise such as `Great job` or `Thanks for`.",
|
|
284
294
|
"Keep code_location ranges as short as possible, ideally one line and never longer than 5-10 lines unless unavoidable.",
|
|
@@ -322,10 +332,7 @@ export async function runRalphWorkflow(
|
|
|
322
332
|
],
|
|
323
333
|
[
|
|
324
334
|
"decision_rules",
|
|
325
|
-
[
|
|
326
|
-
"Set stop_review_loop=true when the patch is correct, reviewer_error is null/omitted, and there are no blocking (P0/P1/P2) findings; remaining P3 nice-to-haves do not block approval. The loop gate is computed from finding priorities, so an unresolved P0/P1/P2 keeps the loop going regardless of this flag.",
|
|
327
|
-
"If you hit a reviewer/tool/validation error, set stop_review_loop=false and populate reviewer_error instead of pretending the patch is approved.",
|
|
328
|
-
].join("\n"),
|
|
335
|
+
["Set stop_review_loop=true only when the patch is correct, reviewer_error is null/omitted, there are no blocking objective-aligned P0/P1/P2 findings, requirements_traceability is non-empty and every entry is proven, and no objective-relevant verification remains; beyond_objective and contradicts_objective findings are non-blocking and must not be folded into follow-up objectives without checking the literal contract. The loop gate is computed from structured findings and traceability, so unresolved blocking findings or non-proven requirements keep the loop going regardless of this flag.", "Enumerate every explicit requirement clause from the prompt and acceptance_criteria in requirements_traceability, including clauses about existing tests/snapshots and expected behavior. Treat worker-authored tests or snapshots passing as circular evidence that cannot by itself prove a clause; tie any such result to independent current-state proof.", "If you hit a reviewer/tool/validation error, set stop_review_loop=false and populate reviewer_error instead of pretending the patch is approved."].join("\n"),
|
|
329
336
|
],
|
|
330
337
|
]);
|
|
331
338
|
let reviews: WorkflowTaskResult[];
|
|
@@ -2,6 +2,7 @@ import type { WorkflowDefinition, WorkflowInputValues, WorkflowOutputValues } fr
|
|
|
2
2
|
|
|
3
3
|
export type RalphWorkflowInputs = WorkflowInputValues & {
|
|
4
4
|
readonly prompt: string;
|
|
5
|
+
readonly acceptance_criteria?: string;
|
|
5
6
|
readonly max_loops: number;
|
|
6
7
|
readonly base_branch: string;
|
|
7
8
|
readonly git_worktree_dir: string;
|
|
@@ -10,6 +11,7 @@ export type RalphWorkflowInputs = WorkflowInputValues & {
|
|
|
10
11
|
|
|
11
12
|
export type RalphWorkflowRunInputs = WorkflowInputValues & {
|
|
12
13
|
readonly prompt: string;
|
|
14
|
+
readonly acceptance_criteria?: string;
|
|
13
15
|
readonly max_loops?: number;
|
|
14
16
|
readonly base_branch?: string;
|
|
15
17
|
readonly git_worktree_dir?: string;
|
|
@@ -23,6 +25,7 @@ export type RalphWorkflowOutputs = WorkflowOutputValues & {
|
|
|
23
25
|
readonly research?: string;
|
|
24
26
|
readonly research_path?: string;
|
|
25
27
|
readonly implementation_notes_path?: string;
|
|
28
|
+
readonly qa_video_path?: string;
|
|
26
29
|
readonly pr_report?: string;
|
|
27
30
|
readonly approved?: boolean;
|
|
28
31
|
readonly iterations_completed?: number;
|
|
@@ -11,9 +11,10 @@ import { runRalphWorkflow } from "./ralph-runner.js";
|
|
|
11
11
|
|
|
12
12
|
export default workflow({
|
|
13
13
|
name: "ralph",
|
|
14
|
-
description: "Raw prompt → research-prompt-refinement → research → orchestrate → multi-model parallel review loop with bounded iteration.",
|
|
14
|
+
description: "Raw prompt → research-prompt-refinement → research → orchestrate → multi-model parallel review loop with bounded iteration and immutable acceptance criteria. When launching follow-up ralph runs from review findings, pass the ORIGINAL task text as acceptance_criteria so deltas cannot drift from the literal contract.",
|
|
15
15
|
inputs: {
|
|
16
16
|
prompt: Type.String({ description: "The task or goal to research, execute, and refine." }),
|
|
17
|
+
acceptance_criteria: Type.Optional(Type.String({ description: "Original immutable task contract this run must remain consistent with. Defaults to prompt. Orchestrators launching follow-up runs from reviewer findings should pass the ORIGINAL task text here." })),
|
|
17
18
|
max_loops: Type.Number({
|
|
18
19
|
default: DEFAULT_MAX_LOOPS,
|
|
19
20
|
description: `Maximum research/orchestrate/review iterations (default ${DEFAULT_MAX_LOOPS}).`,
|
|
@@ -56,6 +57,7 @@ export default workflow({
|
|
|
56
57
|
const workflowStartCwd = workflowCtx.cwd ?? process.cwd();
|
|
57
58
|
const inputs = workflowCtx.inputs;
|
|
58
59
|
const prompt = inputs.prompt;
|
|
60
|
+
const acceptanceCriteria = inputs.acceptance_criteria?.trim() || prompt;
|
|
59
61
|
const maxLoops = positiveInteger(inputs.max_loops, DEFAULT_MAX_LOOPS);
|
|
60
62
|
const comparisonBaseBranch = normalizeBranchInput(
|
|
61
63
|
inputs.base_branch,
|
|
@@ -64,6 +66,7 @@ export default workflow({
|
|
|
64
66
|
const createPr = inputs.create_pr === true;
|
|
65
67
|
return await runRalphWorkflow(workflowCtx, {
|
|
66
68
|
prompt,
|
|
69
|
+
acceptanceCriteria,
|
|
67
70
|
maxLoops,
|
|
68
71
|
comparisonBaseBranch,
|
|
69
72
|
workflowStartCwd,
|
|
@@ -14,7 +14,9 @@ export const E2E_VERIFICATION_GUIDANCE = [
|
|
|
14
14
|
"Verify correctness end-to-end whenever practical for user-visible behavior; do not rely only on code inspection, unit tests, or stage summaries when an executable user scenario can prove the outcome.",
|
|
15
15
|
"For web or frontend flows — including frontend changes whose correctness depends on backend/API behavior — use the playwright-cli skill, or delegate to a subagent with `skill: \"playwright-cli\"`, to drive the application like a user and capture snapshot, screenshot, DOM, or network evidence when that proves the objective.",
|
|
16
16
|
"For TUI or terminal-app flows, use the tmux skill, or delegate to a subagent with `skill: \"tmux\"`, to launch the app in an isolated tmux session, send keys, capture pane output, and simulate the scenario end to end.",
|
|
17
|
-
"
|
|
17
|
+
"Assume credentials, auth, and environment access for playwright-cli/tmux E2E testing exist until a concrete attempt proves otherwise; never skip E2E based only on an assumed missing prerequisite.",
|
|
18
|
+
"Before declaring E2E impractical, do cheap non-destructive checks first (existing sessions, config files, env vars, CLI auth status), then actually attempt to launch the app or flow.",
|
|
19
|
+
"If end-to-end verification is not practical in this checkout, record the exact command(s) attempted, observed failure output, smallest missing prerequisite, and narrower validation run instead; an unattempted assumption is never valid grounds to skip.",
|
|
18
20
|
].join("\n");
|
|
19
21
|
|
|
20
22
|
export function renderE2eQaVideoReviewGuidance(
|
|
@@ -29,5 +31,17 @@ export function renderE2eQaVideoReviewGuidance(
|
|
|
29
31
|
"Use available video/file tooling such as `fetch_content` on the local video path with a prompt focused on whether the recording proves the required user scenario, or inspect representative frames/metadata when full video analysis is unavailable.",
|
|
30
32
|
"Check that the video reflects the current repository/application state, exercises the objective-relevant user path, shows the expected final behavior, and does not visibly hide errors, stale UI, broken loading states, or skipped steps.",
|
|
31
33
|
"For UI-applicable or full-stack changes, treat a missing, stale, unreadable, or inconclusive QA video as missing E2E evidence unless the receipt or implementation notes justify why no video applies and provide adequate alternate end-to-end proof.",
|
|
34
|
+
"Treat skipped E2E due to assumed-missing credentials, auth, or environment access as missing evidence unless the worker actually checked credential/auth state, attempted the launch/flow, and reported exact commands plus observed failure output.",
|
|
32
35
|
].join("\n");
|
|
33
36
|
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
export const LITERAL_OBJECTIVE_CONTRACT = [
|
|
40
|
+
"Literal objective contract:",
|
|
41
|
+
"- The objective and acceptance criteria are the sole and LITERAL source of truth for required behavior.",
|
|
42
|
+
"- Acceptance criteria are the immutable task contract; the run objective is a delta that must not contradict them.",
|
|
43
|
+
"- If the objective and acceptance criteria conflict, do not implement the contradiction. Surface it as a blocker or reviewer finding instead.",
|
|
44
|
+
"- When external knowledge (language specs, upstream issues, in-repo comments, general best practice, or prior reviewer speculation) conflicts with explicit objective wording, the objective/acceptance criteria win.",
|
|
45
|
+
"- Never silently resolve such a conflict in favor of external knowledge. Surface the conflict clearly.",
|
|
46
|
+
"- Do not add behaviors, restrictions, error conditions, or follow-up requirements beyond what the objective/acceptance criteria require.",
|
|
47
|
+
].join("\n");
|
|
@@ -49,7 +49,7 @@ const StageSessionOptionProperties = {
|
|
|
49
49
|
agentDir: Type.Optional(Type.String()),
|
|
50
50
|
authStorage: Type.Optional(SdkSessionOptionSchema("authStorage")),
|
|
51
51
|
modelRegistry: Type.Optional(SdkSessionOptionSchema("modelRegistry")),
|
|
52
|
-
model: Type.Optional(Type.Unsafe<WorkflowModelValue>({ description: "Primary model id or SDK model object. String ids may include a reasoning suffix, e.g. openai/gpt-5:high; valid levels: off|minimal|low|medium|high|xhigh. A parenthesized context-window token may precede or follow the suffix, e.g. github-copilot/claude-opus-4.8 (1m):
|
|
52
|
+
model: Type.Optional(Type.Unsafe<WorkflowModelValue>({ description: "Primary model id or SDK model object. String ids may include a reasoning suffix, e.g. openai/gpt-5:high; valid levels: off|minimal|low|medium|high|xhigh. A parenthesized context-window token may precede or follow the suffix, e.g. github-copilot/claude-opus-4.8 (1m):xhigh or github-copilot/claude-opus-4.8:xhigh (1m). Use (long) for a generic long-context marker, or a rounded size matching the model's long tier (e.g. (1m) or (1.1m)); both select the model's advertised long tier." })),
|
|
53
53
|
contextWindow: Type.Optional(Type.Number({ description: "Context-window token budget for the stage session (e.g. 1000000). Non-strict by default: an unsupported value keeps the model's default window. Prefer the per-model `(1m)` token in a model/fallbackModels entry when only specific models should use a larger window." })),
|
|
54
54
|
contextWindowStrict: Type.Optional(Type.Boolean({ description: "Treat an unsupported contextWindow as an error instead of falling back to the model's default window." })),
|
|
55
55
|
thinkingLevel: Type.Optional(SdkSessionOptionSchema("thinkingLevel")),
|