Skip to content

Size the judge's response budget for reasoning models and keep the CLI prompt off argv - #106

Merged
dacharyc merged 4 commits into
mainfrom
fix/issue-103-response-budget
Oct 18, 2026
Merged

dacharyc merged 4 commits into
mainfrom
fix/issue-103-response-budget

Conversation

@dacharyc

@dacharyc dacharyc commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

Fixes #103.

What was wrong

  • judge.NewClient fixed the response budget at 500 tokens with no flag to change it. The judge's JSON answer fits in that, but reasoning models (OpenAI o-series and gpt-5, GLM, Kimi, DeepSeek) think inside the same budget before answering, so they returned empty content and the user saw no valid JSON object found in response: with nothing after the colon.
  • The claude-cli provider passed the system prompt and the content as command-line arguments. The judge prompt alone is about 24 KB, so with the default 8 KB of content the command line sat at the Windows limit of 32 KB, and far over the 8 KB limit that applies when claude is launched through a .cmd shim. Not only --full-content failed; the default did.

What changed

  • Budget: judge.DefaultMaxResponseTokens is 8192, used when ClientOptions.MaxResponseTokens is zero. score evaluate exposes it as --max-response-tokens, validated before an API key is looked up. The HTTP timeout goes from 30 seconds to 3 minutes, since a reasoning model can take that long on a large budget.
  • Diagnosis: both clients return judge.ErrEmptyResponse when a successful call carries no answer text. When the finish reason, the presence of reasoning_content, reasoning, or Anthropic thinking blocks, or a nonzero usage.completion_tokens_details.reasoning_tokens (OpenAI's own reasoning models keep the text private) shows the budget was used up thinking, the message names the budget and the flag, with the reasoning token count when it is reported. Empty output from the claude CLI is also reported as an empty response rather than failing later in the JSON parser. The Anthropic client now takes the first text block rather than the first block, so a gateway with extended thinking on no longer hands back a thinking block's empty text.
  • claude-cli: content goes to the CLI on stdin, and the system prompt through a temporary --system-prompt-file (Claude Code 1.0.55 and later), removed after the call. buildArgs no longer carries prompt text at all. The CLI is invoked through a package variable so tests can capture the invocation.
  • README: documents the budget and flag, adds the empty-response error to troubleshooting, and notes the stdin and prompt-file behavior for claude-cli.

Verification

  • Unit tests: default and explicit budgets reach the Anthropic and OpenAI request bodies; four empty-content shapes from OpenAI-compatible endpoints and two thinking-block shapes from Anthropic produce the right error; the CLI client sends 40 KB of flag-like content on stdin with none of it in argv, the prompt file holds the system prompt during the call and is gone afterwards; CLI failures include stderr.
  • Integration: score evaluate --help lists the flag; --max-response-tokens 0 is rejected with a clear message before any key is needed.
  • End to end against the installed claude CLI (2.1.292) on a scratch copy of the valid-skill fixture: a full six-dimension score came back in about five seconds and no prompt file was left in the temp directory.

go test -race ./..., go vet for darwin and windows, and golangci-lint run are clean.

No CHANGELOG entry, following the release-commit pattern.

…I prompt off argv

The response budget was fixed at 500 tokens with no way to change it.
That fits the judge's JSON answer, but reasoning models (OpenAI o-series
and gpt-5, GLM, Kimi, DeepSeek) think inside the same budget first, so
they returned empty content and the user saw "no valid JSON object found
in response:" with nothing after the colon. Fixes #103.

Default the budget to 8192 tokens, expose it as --max-response-tokens
and judge.DefaultMaxResponseTokens, and raise the HTTP timeout from 30
seconds to 3 minutes to match. When a response carries no answer text,
say why: both clients now return ErrEmptyResponse, and when the finish
reason or the presence of reasoning_content, reasoning, or thinking
blocks shows the budget was used up thinking, the message names the
budget and the flag. The Anthropic client picks the first text block
rather than the first block, so a gateway with extended thinking on no
longer returns the thinking block's empty text.

The claude-cli provider passed the system prompt and the content as
arguments. The judge prompt alone is about 24 KB, so with the content
the command line exceeded the Windows limit of 32 KB, or 8 KB through a
.cmd shim. The content now goes to the CLI on stdin and the system
prompt through a temporary --system-prompt-file, available since Claude
Code 1.0.55; the file is removed after the call. Verified against the
installed CLI, which returned the full six-dimension score.
The paragraph was inserted at the top of the README instead of after
the --max-tokens-style table it refers to.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Empty Anthropic text blocks still bypass the new empty-response and budget diagnostics.

1 open issue
What changed in this PR

Addresses #103 by increasing the judge’s reasoning budget and keeping large Claude CLI prompts off command-line arguments.

Changes:

  • Adds an 8,192-token default, configurable response budget, and longer HTTP timeout.
  • Improves empty-response diagnostics and Anthropic text-block selection.
  • Moves CLI prompts to stdin and temporary files, with tests and documentation.
File Description
README.md Documents budgets, diagnostics, and CLI prompt transport.
judge/​client.go Updates budgets, response handling, and CLI invocation.
judge/​client_test.go Tests response handling, budgets, and prompt transport.
cmd/​score_evaluate.go Adds and validates the response-budget flag.
cmd/​score_evaluate_integration_test.go Checks flag visibility and zero-value rejection.

Review effort: Balanced

Comment thread judge/client.go Outdated
The Anthropic client returned the first text block even when it was
empty, so a thinking block followed by an empty text block at
stop_reason max_tokens came back as "" with no error, skipping the
budget diagnostic, and an empty text block hid any later text block.
An empty content array also exited before the diagnostics. Flagged in
review.

Return the first text block that has text; otherwise route every
no-answer shape through the same check, naming the budget when the
stop reason is max_tokens and ErrEmptyResponse otherwise.
@dacharyc
dacharyc force-pushed the fix/issue-103-response-budget branch from b4436b4 to 195e179 Compare October 18, 2026 16:04
@dacharyc
dacharyc requested a balanced review from Copilot October 18, 2026 16:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No blocking issues were identified in budget propagation, response handling, or CLI prompt transport and cleanup.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

OpenAI's own reasoning models do not return their thinking in the
response, only its size in usage.completion_tokens_details. Read it, so
an empty answer from them names the budget and says how many tokens
went to reasoning, rather than relying on the finish reason alone.

The claude-cli provider returned empty output as a successful empty
string, which failed later in the JSON parser with nothing to show.
Return ErrEmptyResponse instead; the CLI manages its own token budget,
so no budget hint applies.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused changes include regression coverage, and no unresolved blocking issues were identified.

No open issues 🎉

Review effort: Balanced

@dacharyc
dacharyc merged commit c4f116f into main Oct 18, 2026
4 checks passed
@dacharyc
dacharyc deleted the fix/issue-103-response-budget branch October 18, 2026 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

score evaluate: 500-token default returns empty content on reasoning models (GLM/Kimi); claude-cli hits Windows argv limit

2 participants