patcher: pin model='opus' on clawdforge sessions; CRAFTING_PATCHER_MODEL env override

Code-work prompts (read CVE/lint context, draft a unified diff that
verifies cleanly against the failing recipe) reward Opus's longer
context + careful reasoning. Cauldron-style high-frequency Sonnet calls
are unaffected — this only changes what crafting-table's patcher asks
clawdforge to use for its drafted-patch sessions.

Pairs with clawdforge dbbead2 which adds the optional `model` field on
POST /sessions and propagates ANTHROPIC_MODEL into the acpx subprocess
env on both create + turn.

Override knob: CRAFTING_PATCHER_MODEL env (e.g. "sonnet" if cost > quality).

Tests: 16/16 patcher tests still green.
This commit is contained in:
Kayos 2026-04-29 12:37:54 -07:00
parent a1b3c72c8f
commit 61a9814b67

View file

@ -98,6 +98,12 @@ class PatcherConfig:
# HTTP timeout margin — clawdforge adds an internal margin, but we cap
# transport-level too for hung connections.
http_timeout_secs: int = 600
# Model passed to clawdforge on session create. Pinned to "opus" by
# default — code-work prompts (read finding context, write a unified
# diff that doesn't break the verify recipe) reward Opus's longer
# context + deeper reasoning. Override via CRAFTING_PATCHER_MODEL env
# if you want sonnet for cost reasons.
model: str = "opus"
@classmethod
def from_env(cls, env: dict[str, str] | None = None) -> "PatcherConfig | None":
@ -127,6 +133,7 @@ class PatcherConfig:
auto_patch_branch_prefix=e.get(
"CRAFTING_PATCHER_BRANCH_PREFIX", "crafting-table/auto/"
),
model=e.get("CRAFTING_PATCHER_MODEL", "opus"),
)
@ -210,9 +217,12 @@ class ClawdforgeClient:
self,
*,
agent: str = "claude",
model: str | None = None,
meta: dict[str, Any] | None = None,
) -> dict[str, Any]:
body: dict[str, Any] = {"agent": agent}
if model is not None:
body["model"] = model
if meta is not None:
body["meta"] = meta
async with httpx.AsyncClient(timeout=self.timeout_secs) as ac:
@ -657,6 +667,7 @@ class Patcher:
try:
session_payload = await self.clawdforge.create_session(
agent="claude",
model=self.config.model,
meta={
"crafting_table_job_id": job["id"],
"finding_id": finding_id,