Skip to content

[EPIC-U][LOU-U19] Hitting maxSteps yields finishReason 'max-steps' - #83

Merged
LinuxDevil merged 1 commit into
mainfrom
lou-u19-max-steps-finish-reason
Oct 1, 2026
Merged

LinuxDevil merged 1 commit into
mainfrom
lou-u19-max-steps-finish-reason

Conversation

@LinuxDevil

Copy link
Copy Markdown
Owner

What

  • ExecutionFinishReason gains 'max-steps'. In AgentExecutor.runSteps(), leaving the step loop without the model having stopped (and without an abort) sets finishReason = 'max-steps' before finishRun(). The result, the finish event and run.done (which reads result.finishReason) all carry it; no edits to agentEvents.ts or agentRun.ts were needed.
  • Resumed runs go through the same loop, so initialSteps and approval resumes count toward the budget; resume.ts is untouched.
  • One-line consumer updates: eval completed() hint now keys on 'max-steps' (was 'tool_calls'), sub-agent task failure message recognises 'max-steps', and the MCP server's agent tool returns an error result instead of an empty success. Forge status mapping needed no change (non-approval results map to stopped).
  • Docs: new "Finish reasons" section in docs/api-overview.md, docs/streaming.md step.done/run.done rows, CHANGELOG entry, regenerated llms-full.txt.

Why

A run that exhausted maxSteps exited silently with the last step's finishReason (often tool_calls) and possibly empty text, so callers could not tell a completed run from an exhausted one.

Acceptance criteria

  • 'max-steps' added to ExecutionFinishReason; reported when the budget is exhausted while the model still wanted to continue; natural completion unchanged
  • run.done from agent.stream() / AgentExecutor.stream carries the reason, no agentEvents.ts edits
  • Resumed runs (initialSteps, approval resume) count correctly; a resume that immediately exhausts reports 'max-steps'; resume.ts untouched
  • ExecutionResult.steps kept; documented in docs/api-overview.md and docs/streaming.md; llms files regenerated
  • finishReason consumers checked (src, apps/agent-forge, examples, packages); three one-line updates, none broken
  • Tests with mockModel: always-tool model with maxSteps: 2 gives 'max-steps' and steps === 2; run.done carries it; text reply on exactly the last allowed step is 'stop'; resume paths (new src/execution/maxSteps.test.ts)
  • src/createAgent.ts, src/context/, src/providers/, src/react/* untouched

How verified

  • npx tsc --noEmit: no errors
  • npm run lint: 0 errors, 433 warnings (same as main)
  • npm run test:types: no type errors
  • npx vitest run (after build): 141 files passed, 2064 passed / 3 skipped
  • npm run build && npm run build --workspace=packages/create-loushy-agent: success
  • npm run docs:verify-snippets -- --skip-build: all 96 snippets type-check
  • npm run docs:llms:check: pass
  • npm run test:coverage: 141 files passed, 2064 tests passed
  • npm run fallow: exit 0, dead code none (one pre-existing duplicate group in src/providers)

🤖 Generated with Claude Code

https://claude.ai/code/session_016bY29ibQgv3MDdjAbUT4YR


Generated by Claude Code

When the agent loop spends its maxSteps budget while the model still wanted
to continue, the result, finish event and run.done now report 'max-steps'
instead of the stale last-turn reason. initialSteps / approval resumes count
toward the budget. Consumers that inferred a cut-off from 'tool_calls' (eval
completed() message, sub-agent task failure, MCP agent tool) use 'max-steps'.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bY29ibQgv3MDdjAbUT4YR
@LinuxDevil
LinuxDevil merged commit e98f864 into main Oct 1, 2026
1 check passed
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