fix(tools): accept integer OR string for browser_task max_steps - #136
Merged
Conversation
Sentry #1084: Groq rejected the tool call with `invalid_request_error … parameters for tool browser_task did not match schema: /max_steps: expected number, but got string` — the model emitted "10" instead of 10. Providers validate the model's call against our ADVERTISED schema server-side, so the call never reaches us and we cannot coerce it. Widen the advertised type to ["integer","string"] on all three browser_task declarations (disabled/inert, sidecar, browser-use Cloud) and normalise to int at the seam. RawSchema keeps it a plain JSON Schema type union rather than anyOf, which strict function-calling modes tend to reject. #937 (BuildArtifactJob: Failed to build artifact) was the downstream failure of the same run.
escapeboy
added a commit
that referenced
this pull request
Aug 4, 2026
failed_jobs had never been pruned and had grown to 1916 rows on production, the oldest from 2026-04. Every row is a resolved incident, and the volume drowns the handful that still matter — `queue:failed` shows only the tail, so the table reads as "3 old entries" when it is nearly two thousand. `queue:prune-failed --hours=720` keeps 30 days, which is long enough to investigate a failure after the fact. Verified the schedule entry registers (`15 4 * * *`, next due 19h). Found while validating the current failures rather than assuming they were stale: of the 17 since 2026-07-24, all but one are DistillTeamEventsJob at 01:31 nightly, which stopped after 2026-07-29 (fix #131, 2026-08-01 — six clean nights since, with `memory:distill-events` confirmed still scheduled and due, so the silence is a fix and not a job that quietly stopped running). The remaining one is the browser_task max_steps 400, fixed in #136.
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.
Fixes Sentry #1084; #937 was the downstream failure of the same run.
Problem
The model emitted
"10"instead of10. Providers validate the model's tool call against our advertised schema, server-side — the call is rejected before it ever reaches the app, so there is nothing for us to coerce at runtime. Our schema was not wrong; it was simply stricter than what the model reliably produces.Change
Widen the advertised type to
["integer","string"]on all threebrowser_taskdeclarations (the inert/disabled one, the sidecar one, and the browser-use Cloud one — the inert one still advertises its schema to the LLM, so it needs it too), and normalise tointat the seam vianormaliseMaxSteps().RawSchemais used rather thanAnyOfSchemaso this stays a plain JSON Schema type union instead ofanyOf, which strict function-calling modes tend to reject.Tests
browser+browser_use_cloud)max_steps: '7'reaches the sidecar as integer7Unit/Domain/Tool+Feature/Domain/Tool; pint + phpstan clean on the touched filesNote on scope
This is a tolerance change, not a claim that the model bug is ours. It stops one malformed generation from failing an entire agent run.