feat: add schema-driven reasoning and improve agent reliability - #6
Conversation
Normalize Claude thinking.type=enabled to a model-supported adaptive type before schema validation. Keep strict validation for unsupported thinking types, effort levels, display values, and budget fields, and add regression coverage for Claude and OpenAI-compatible reasoning requests.
…top pre-dispatch 400s and unrequested thinking-block injection Addresses the three must-fix findings from the PR #6 (schema-driven reasoning) review, plus two cheap follow-ups from the same pass. F1 (BLOCKER): translator.go unconditionally appended agentToolExecutionPrompt to the system prompt and agentToolTurnReminder to the user's final turn on every tool-bearing Claude request routed to Kiro — undisclosed behavior for a proxy sold as a transparent Claude passthrough. Both injection sites are now gated behind a new config.AgentToolSteering flag (default false, persisted the same way as the existing AllowOverUsage flag, exposed via the existing /admin settings GET/PATCH endpoint). With the flag off, translator output is byte-identical to pre-PR behavior. Noted in a code comment that estimatedInputTokens is computed pre-injection, so the token estimate under-counts by ~150 tokens/request when the flag is on. F2 (HIGH): reasoningCapabilityForModel reads a schema built exclusively from Kiro accounts. In a mixed pool, BuildClaudeAdditionalModelRequestFields could hard-400 a request ahead of account dispatch even when the request would have gone to a Bedrock/custom_api account that needs no Kiro schema at all (Bedrock speaks native Anthropic Messages directly). handleCountTokens, handleClaudeMessagesInternal, handleOpenAIChat, and handleOpenAIResponses now call a new reasoningBuildErrorIsFatal() (reuses hasKiroCapableAccount) and degrade to warn-and-drop instead of a 400 when the pool has no Kiro-capable account for this request. F3 (HIGH): the `thinking` response-shape gate was broadened to `legacyOrClientThinking || nativeRequested`, but nativeRequested goes true from output_config.effort alone (no thinking object required), while thinkingResponseOpts stayed keyed off req.Thinking and fell back to the operator's configured ClaudeFormat. A client sending only output_config.effort could get reasoning content inlined as `<think>...</think>` in its plain text stream purely because of an operator default, despite never mentioning "thinking". Now requires req.Thinking != nil before nativeRequested can broaden the shape. F5/F8 (cheap): warmModelsCacheAsync was single-flighted but not rate-limited — on a total Kiro outage (or an all-Bedrock pool) cachedModels never gets written, so the CAS re-arms on literally every request, refiring a full account fan-out and accelerating auto-ban. Added a 30s lastWarmAttemptNanos gate. Also moved panic recovery to the first defer in the warm goroutine (a bare `go func()` is not covered by net/http's handler-goroutine panic recovery). Tightened TestWarmModelsCacheAsyncSingleFlights to assert exactly 1 call, not merely "at most 1". F11's stale comment was already fixed upstream of this branch. Every fix ships with a regression test verified to fail when the fix is reverted: TestAgentToolSteering* (4), TestReasoningBuildErrorDoesNotFail... (2), TestEffortOnlyRequestDoesNotInjectThinkingIntoTextStream, TestWarmModelsCacheAsyncIsRateLimited. 629 tests pass (was 621); go build/vet/gofmt clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Merged into Changes made while merging: Dropped: the Fixed on top:
Gated behind a new default-off config flag ( 629 tests pass; go build, go vet and gofmt clean. |
Summary
This PR adds runtime schema-driven native reasoning support and improves reliability for long-running agent workflows.
The main changes are:
1. Schema-driven native reasoning
Problem
Kiro exposes model-specific request capabilities through
additionalModelRequestFieldsSchema, but the proxy did not preserve or use that schema when building requests.As a result:
-thinkingsuffix relied mainly on prompt injection instead of model-native request fields.Solution
The proxy now preserves
additionalModelRequestFieldsSchemafromListAvailableModelsand parses it at runtime.The parsed capability includes:
budget_tokens;output_config.effort, orreasoning.effort;low,medium,high,xhigh, andmax.Requested values are validated against the selected model's schema before the upstream request is sent.
API coverage
Native reasoning is supported across:
The generated fields are forwarded through
additionalModelRequestFields.Backward compatibility
The configured thinking suffix, such as
-thinking, remains supported.When compatible native reasoning fields are available, they are forwarded directly and the legacy thinking prompt is not injected.
When native fields are unavailable, the existing legacy thinking prompt remains the fallback.
2. Environment-gated diagnostics
Problem
Investigating issues such as truncated payloads, incomplete streams, reasoning forwarding, and chunk normalization previously required adding temporary logs directly to the request path.
Solution
This PR adds opt-in diagnostic flags:
KIRO_DIAGNOSTICSfalseKIRO_DIAG_STREAMfalseKIRO_DIAG_PAYLOADfalseKIRO_DIAG_REASONINGfalseKIRO_DIAG_CHUNKSfalseAccepted enabled values are
1,true,yes,on, andenabled.KIRO_DIAGNOSTICSintentionally does not enableKIRO_DIAG_CHUNKS, because chunk logs may contain prompts, reasoning, source code, or tool output.All diagnostics remain disabled by default.
3. Agent tool-execution reliability
Problem
During coding-agent workflows, a model may describe or plan a tool action without actually invoking the required tool, causing the turn to end before the requested work is complete.
Solution
Tool-enabled agent requests now include execution guidance that instructs the model to:
A shorter reminder is also added on continued tool turns when pending work still requires tool execution.
The guidance is not added when tool use is explicitly disabled through
tool_choice.4. Stream and region reliability
Longer streaming timeout
The Kiro streaming HTTP timeout is increased from 5 minutes to 15 minutes to support long-running coding-agent operations.
The separate REST client keeps its existing 30-second timeout.
IDC and external IdP region probing
For
idcandexternal_idpaccounts, the authentication region may differ from the Kiro profile region.Profile discovery can now probe configured fallback regions for these account types when resolving the profile ARN.
Once a profile ARN is resolved, its region continues to determine the data-plane endpoint.
5. Payload and stream diagnostics
Payload diagnostics report:
The diagnostics wrap the existing byte-and-token-aware truncation logic without changing its preservation rules.
Stream diagnostics report aggregate information such as:
Raw chunk previews remain separately opt-in.
Changes
ListAvailableModels.README.md.Tests
Added and updated tests covering:
output_config.effort;reasoning.effort;Verification performed:
gofmtgo test ./...go vet ./...git diff --check zsec/main --Compatibility notes
-thinkingmodel suffixes remain supported.