fix(pipeline): stop the agent files telling the model it has tools - #451
Open
shirgoldbird wants to merge 1 commit into
Open
shirgoldbird wants to merge 1 commit into
shirgoldbird wants to merge 1 commit into
Conversation
The generation step returned a transcript of itself using tools instead of a
page:
I'll research the GitHub repo and peer pages before writing.
<tool_call>{"name": "Glob", "arguments": {"pattern": "docs/.../*.mdx"}}</tool_call>
<tool_response>docs/learning-how-tos/cookbook/context-aware.mdx ...</tool_response>
build_authoring_system_prompt pastes .claude/agents/docs-writer.md verbatim into
a plain Messages API call. That file is an agent definition: its frontmatter
declares `tools: Read, Write, Edit, Grep, Glob, Bash, Agent`, its body says to
search with Grep and Glob and to delegate to the diataxis agent, and it ends
with "Return the complete draft as file content (using Write or Edit)". The call
passes no tools, so the model did the only thing those instructions allow and
faked them. diataxis.md and editorial-reviewer.md declare tools too, so rework
and review shared the exposure.
- load_agent() strips the YAML frontmatter from every agent file.
- NO_TOOLS, appended after the guidelines so it wins, cancels what the bodies
still assume: no file reading, no Grep/Glob, no delegation, no tool calls, and
"using Write or Edit" means put the content in the reply.
- generate.py and rework.py check the reply's shape and spend one corrective
turn when it's wrong, rather than writing an unusable draft. rework validates
the `--- SPLIT:` markers for multi-target runs and frontmatter otherwise.
Salvaging a page out of a transcript is deliberately not attempted: a faked tool
result can quote another page's frontmatter, so cutting at the first `---` risks
promoting spliced content.
Assistant prefill would have been stronger, but claude-sonnet-4-6 rejects it:
"This model does not support assistant message prefill."
Verified by running the pipeline end to end on the one live gap
(thin_page for the google-sheets cookbook page, which reproduced the transcript
before this change): generate -> evaluate (0 errors, 0 warnings) -> review
(clean, 5 fixes applied) -> promote wrote the canonical .mdx. The promoted page
was reverted; it was a verification run, not content to ship.
Tests: pipeline/test_prompts.py (14), including the real transcript as a case.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Running the pipeline end to end (which I should have done before opening #450) turned up a third bug. The generation step didn't return a page — it returned a transcript of itself using tools:
build_authoring_system_promptpastes.claude/agents/docs-writer.mdverbatim into a plain Messages API call. That file is an agent definition:tools: Read, Write, Edit, Grep, Glob, Bash, AgentThe call passes no tools, so the model did the only thing those instructions allow and faked them.
diataxis.mdandeditorial-reviewer.mddeclare tools too, sorework.pyandreview.pyshared the exposure.This is pre-existing and intermittent — #447's pages came out as valid
.mdxthrough the same assembly. #450 surfaced it here because the prompt now carries the page's real content, which mentions a GitHub repo, and that nudged the model toward "research first".What changed
load_agent()strips the YAML frontmatter from every agent file.NO_TOOLSis appended after the guidelines, so it wins: no file reading, no Grep/Glob, no delegation, no tool calls, and "using Write or Edit" means put the content in the reply.generate.pyandrework.pycheck the reply's shape and spend one corrective turn when it's wrong, instead of writing an unusable draft.reworkvalidates the--- SPLIT:markers on multi-target runs and frontmatter otherwise.Two decisions worth reviewing:
---is tempting and wrong: a faked tool result can quote another page's frontmatter, so salvage risks promoting spliced content. A corrective turn costs one call and can't mangle anything.---makes a preamble structurally impossible, but the API rejects it:This model does not support assistant message prefill.I found that by running it.Verification
Full run on the one live gap — the
thin_pageforcookbook/google-sheets, the same gap that produced the transcript:.mdxdraftdocs/learning-how-tos/cookbook/google-sheets.mdxrun.pyexited 0. The promoted page was reverted — this was a verification run, not content to ship.New
pipeline/test_prompts.py— 14 tests, including the real transcript as alooks_like_mdxcase and a check thatNO_TOOLSis positioned after the guidelines it overrides. 55 tests total inpipeline/.Two things this run exposed that I did not fix
promote.pyrunsmint broken-linksand prints the result, but doesn't fail on it. The generated page linked to/api-reference/translate/translate-text, which doesn't exist, and that sailed through both gates.Code.gs,Sidebar.html,appsscript.json) — plausible, unverified, and exactly what a reviewer has to check by hand. The docs-writer instruction to research peers exists for a reason; suppressing it doesn't give the model the knowledge, it just stops it pretending. Worth deciding whether the pipeline should get real read tools for generation.🤖 Generated with Claude Code