fix: surgically relocate only OpenCode-fingerprinted system entries#156
fix: surgically relocate only OpenCode-fingerprinted system entries#156griffinmartin wants to merge 1 commit intomainfrom
Conversation
v1.4.8 (#148) worked around Anthropic's OAuth content validation by bulk-relocating all non-core system entries to the first user message. This caused a regression in long conversations (#154) because AGENTS.md, environment metadata, and skills blocks lost system-level attention priority and prompt-cache efficiency. Replace bulk relocation with a feature-based detector that only moves entries containing OpenCode fingerprints (\bopencode\b, anomalyco, 'Workspace root folder', <directories>), keeping all other system content in system[] where it belongs. Empirical probing against api.anthropic.com confirmed the classifier is multi-feature rather than substring-based — AGENTS.md, skills, and Claude Code-format env blocks all pass validation cleanly when kept in system[]. Fixes #154
|
I traced this end-to-end against the actual OpenCode runtime path and there is one important gap in the current approach.
Runtime path:
That means the current I verified this locally before patching by feeding a runtime-shaped combined system blob through the current code path. What worked locallyI added a small follow-up fix in
With that in place, the runtime-shaped flow behaved the way this PR intends:
I also added runtime-shaped tests locally for:
So I think the missing piece here is not in Happy to share the exact shape/tests if helpful, but the key point is: the current tests prove the surgical relocation works on synthetic separated |
Summary
Fixes #154 — v1.4.8 (#148) worked around Anthropic's OAuth content validation by bulk-relocating all non-core
system[]entries to the first user message. While this fixed the 400 error from #147, it caused a real regression in long conversations: AGENTS.md instructions, environment metadata, skills blocks, and per-message system prompts lost the privileged attention priority thatsystem[]provides, and prompt-cache efficiency dropped because static instructions were interleaved with per-turn user content.This PR replaces the bulk relocation with a surgical relocation that only moves entries containing OpenCode fingerprints. AGENTS.md, CLAUDE.md, skills blocks, and Claude Code-format env blocks all stay in
system[]where they belong.What changed
src/transforms.ts— Added an exportedisOpenCodeBrandedEntry(text)helper backed by a 4-pattern regex array, and refactored the relocation loop to call it per entry:Entries matching any pattern → relocated to the first user message (same as v1.4.8). Entries that don't match → kept in
system[].src/transforms.test.ts— Added 10 new unit tests forisOpenCodeBrandedEntry, 6 new behavioral tests for surgical relocation (keeps AGENTS.md insystem[], keeps CC-format env insystem[], keeps skills insystem[], relocatesanomalycoURLs, relocates OpenCode env blocks, mixed branded/non-branded input). Updated 4 existing tests whose assertions reflected the old bulk-relocation behavior.How I found the detector features
I built a temporary probe script (
scripts/probe-system-validation.ts, not committed) that sent real minimal requests toapi.anthropic.com/v1/messageswith varyingsystem[]contents, using the existing OAuth credential path and billing header construction. 16 probes againstclaude-opus-4-6:"Workspace root folder"alone<directories>alone"Here is some"wording"OpenCode"brand onlyKey findings:
system[]as long as they don't mention OpenCode themselves.Workspace root folder,<directories>, and other OpenCode-specific features. This is a finding the v1.4.8 PR didn't surface.Rather than try to track the exact classifier threshold (which can change), the detector relocates any entry containing any known fingerprint feature. This over-relocates in rare false-positive cases (e.g. an AGENTS.md that explicitly mentions
opencode) but is robust against classifier tuning.Why this matters for long conversations
system[]system[]system[]<directories>)\bopencode\b)Instructions that were being buried in the first user message — and drifting further from the active context with every turn — now live in
system[]again with full attention priority and cache stability.Test plan
pnpm run buildcompiles cleanlypnpm run lint— 0 warnings, 0 errors, formatting cleanKnown limitations / follow-ups
Workspace root folder,<directories>, and align to Claude Code's exact format) to keep it insystem[]too. I kept that out of this PR to keep scope focused.opencodementions in user AGENTS.md. If a user's AGENTS.md contains the wordopencode, that entry gets relocated. This is an acceptable over-match — the content still reaches the model, just with reduced attention priority. Users can rephrase if they want it to stay insystem[].OPENCODE_FEATURE_PATTERNS.Fixes #154