Skip to content

fix(agent): run the output contract check on a capped final answer - #192

Merged
samheutmaker merged 4 commits into
developmentfrom
fix/turn-cap-output-check
Oct 17, 2026
Merged

samheutmaker merged 4 commits into
developmentfrom
fix/turn-cap-output-check

Conversation

@samheutmaker

@samheutmaker samheutmaker commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Fix

A turn that hits the tool-call cap ends with a tools-disabled final answer from finalAnswer, which returned the model's reply without ev.CheckFinal. A definition with an output contract could therefore end a capped turn succeeded with no output: the daemon's correction round is what usually pushes an agent to the cap, and the answer it forced skipped the very check that asked for it. Loupe hit this on reviewers that spent their budget exploring (.ai-docs/plans/loupe-sdk-ergonomics/PLAN.md, follow-up 1).

  • finalAnswer runs the capped answer through the same final-message check the loop applies to a no-tools reply.
  • One correction round is allowed, as in the loop: the check's notice rides as an ephemeral system message ahead of the tools-disabled nudge.
  • A second miss fails the turn with the check's error, as it does in the loop.
  • No behavior change for turns without CheckFinal.

Validation

  • Two new tests in internal/agent/final_answer_test.go: a capped answer corrected on the second final call, and a second miss failing the turn.
  • go test ./internal/agent green; go vet clean.

🤖 Generated with Claude Code


Note

Medium Risk
Agent changes affect turn success/failure when definitions use output contracts at the tool cap; process env allowlisting slightly expands what managed children inherit but deliberately excludes proxy/auth Go variables.

Overview
Agent: When a turn hits the tool-call cap, the tools-disabled answer from finalAnswer now goes through ev.CheckFinal the same way a normal no-tools reply does. Logic is split into cappedAnswer (one forced final completion) and finalAnswer (check, optional one retry with ephemeral correction notice, fail on second miss). Turns without CheckFinal are unchanged.

Process / docs: Managed host children snapshot and inherit a fixed set of Go build vars (GOCACHE, GOMODCACHE, GOPATH, GOROOT, GOTOOLCHAIN, GOFLAGS) at process-manager startup so offline preloaded toolchains/caches work; credential-bearing GO* settings like GOPROXY stay out of the allowlist. docs/concurrency.md documents this; tests cover env snapshotting, ChildEnvironment overrides, and offline go list -m.

Reviewed by Cursor Bugbot for commit 92be932. Bugbot is set up for automated code reviews on this repo. Configure here.

When a turn hits the tool-call cap, finalAnswer returned the model's
tools-disabled reply without ev.CheckFinal, so a definition with an output
contract could end a capped turn "succeeded" with no output: the daemon's
correction round is what usually pushes a reviewer to the cap, and the
answer it forced skipped the very check that asked for it.

The capped answer now goes through the same check the loop runs on a
no-tools reply, with the one correction round the check may ask for. A
second miss fails the turn, as it does in the loop.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@samheutmaker
samheutmaker merged commit ceac917 into development Oct 17, 2026
22 checks passed
@samheutmaker
samheutmaker deleted the fix/turn-cap-output-check branch October 17, 2026 02:24
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.

2 participants