fix: stop sending every tool strict; surface provider error reasons (0.1.0-RC.5) #13

Merged
KofTwentyTwo merged 1 commits from feature/strict-tools-grammar-fix into develop 2026-10-13 18:29:57 +00:00
KofTwentyTwo commented 2026-10-13 18:25:47 +00:00 (Migrated from github.com)

Root cause of "the assistant still isn't working" (kof22, RC.3)

Every turn failed on its first model call. Anthropic returned 400 invalid_request_error: "The compiled grammar is too large, which would cause performance issues. Simplify your tool schemas or reduce the number of strict tools." (request id req_011CfzhY7Vnom2BcZXxYaBB9)

  • All ten read tools were sent with strict: true, and the API compiles every strict schema of a request into one grammar.
  • The request was within every documented limit (20 strict tools, 24 optional parameters, 16 unions). The real limit isn't published.
  • The adapter only logged INVALID_REQUEST httpStatus=400, so the reason was invisible.

Changes

  • No strict tools by default. Hosts opt in with AssistantQBitConfig.withStrictToolNames(...). The kernel already validates every tool input and returns INVALID_INPUT.
  • Fallback: when a provider refuses strict schemas (ModelProviderException.isStrictSchemaRejected), the turn retries once without strict tools and logs a WARN.
  • Diagnostics: provider errors carry the API error type, a sanitized message (one line, capped, key-like tokens redacted) and the request id.
    • They're logged at WARN on 4xx.
    • The request id goes on the assistant_usage row.
    • The reason is shown to assistant.admin holders in the panel error and in Test connection.
  • TurnEngine catches Error too, so a turn can't be swallowed by the executor and end as an empty COMPLETE.
  • AnthropicRequestContractTest builds the exact request for the fixture app and checks it:
    • the documented Messages API constraints: thinking/effort, no sampling parameters, no forced tool_choice, at most 4 cache breakpoints with the longer TTL first, message order, and strict-schema keywords;
    • a conservative strict budget (3 tools / 6 optional / 2 unions). The RC.3 shape is asserted to be over budget;
    • grammar-rejection recognition, and the end-to-end retry against the recorded Anthropic server.
  • There's no schema change and no new table or column, so kof22 needs only the version bump.

Tests

./mvnw verify is green against QQQ 4.1.0-RC.4 (the default) and against -Dqqq.snapshot.version=4.1.0-RC.5 (kof22's BOM). That includes checkstyle and the JaCoCo gate.

🤖 Generated with Claude Code

## Root cause of "the assistant still isn't working" (kof22, RC.3) Every turn failed on its first model call. Anthropic returned 400 `invalid_request_error`: "The compiled grammar is too large, which would cause performance issues. Simplify your tool schemas or reduce the number of strict tools." (request id `req_011CfzhY7Vnom2BcZXxYaBB9`) - All ten read tools were sent with `strict: true`, and the API compiles every strict schema of a request into one grammar. - The request was within every documented limit (20 strict tools, 24 optional parameters, 16 unions). The real limit isn't published. - The adapter only logged `INVALID_REQUEST httpStatus=400`, so the reason was invisible. ## Changes - **No strict tools by default.** Hosts opt in with `AssistantQBitConfig.withStrictToolNames(...)`. The kernel already validates every tool input and returns `INVALID_INPUT`. - **Fallback:** when a provider refuses strict schemas (`ModelProviderException.isStrictSchemaRejected`), the turn retries once without strict tools and logs a WARN. - **Diagnostics:** provider errors carry the API error type, a sanitized message (one line, capped, key-like tokens redacted) and the request id. - They're logged at WARN on 4xx. - The request id goes on the `assistant_usage` row. - The reason is shown to `assistant.admin` holders in the panel error and in Test connection. - `TurnEngine` catches `Error` too, so a turn can't be swallowed by the executor and end as an empty COMPLETE. - **`AnthropicRequestContractTest`** builds the exact request for the fixture app and checks it: - the documented Messages API constraints: thinking/effort, no sampling parameters, no forced `tool_choice`, at most 4 cache breakpoints with the longer TTL first, message order, and strict-schema keywords; - a conservative strict budget (3 tools / 6 optional / 2 unions). The RC.3 shape is asserted to be over budget; - grammar-rejection recognition, and the end-to-end retry against the recorded Anthropic server. - There's no schema change and no new table or column, so kof22 needs only the version bump. ## Tests `./mvnw verify` is green against QQQ 4.1.0-RC.4 (the default) and against `-Dqqq.snapshot.version=4.1.0-RC.5` (kof22's BOM). That includes checkstyle and the JaCoCo gate. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.