Enable Opus 5 support, native thinking fixes, proper mapping for effort#117
Open
guidan-nick wants to merge 4 commits into
Open
Enable Opus 5 support, native thinking fixes, proper mapping for effort#117guidan-nick wants to merge 4 commits into
guidan-nick wants to merge 4 commits into
Conversation
Thinking blocks never rendered in OpenCode, and xhigh effort was unreachable. Two independent causes. OpenCode drops reasoning deltas unless the model declares both `reasoning: true` and `interleaved.field`. The plugin emits reasoning as `reasoning_content` (streaming/openai-converter.ts) but never declared either field, so every reasoning chunk was discarded before rendering. Every model in OpenCode's own registry that carries reasoning in a non-standard field declares both; this brings the plugin in line. budgetToEffort had no branch returning xhigh, so the level could only be reached by setting `effort` explicitly in kiro.json. With auto_effort_mapping on by default, xhigh was dead configuration and adding models to XHIGH_CAPABLE_MODELS had no effect on the auto path. Move the model list into plugin/model-registry.ts and derive the thinking entries from effort capability, so a model's advertised variants and the budget mapping cannot drift apart. Adds the missing claude-opus-5, claude-opus-5-thinking and claude-opus-4-7-thinking entries. Kiro's GPT-5.6 tiers stay unadvertised: they configure reasoning through `reasoning.effort` / `reasoning.mode` rather than `output_config.effort`, so they need their own request path. BREAKING: budget bands are rescaled to Kiro's real thinking range (1024-128000) instead of OpenCode's conventional 32768 cap, so xhigh and max are reachable from a budget. A budget of 32768 now maps to medium rather than max. Users depending on the old bands should set an explicit `effort` in kiro.json. Verified: effort=xhigh confirmed on the wire against opus-5 (HTTP 200).
The install example told users to hand-write the whole model registry, which is what left thinking models without reasoning flags in the first place. The plugin advertises every model itself, so the example is now just the plugin entry. Document that reasoning + interleaved.field are both required, and warn that overriding provider.kiro.models replaces the plugin registry wholesale, so anyone doing that has to carry the flags themselves.
CodeWhisperer sends reasoning on thinking models as reasoningContentEvent, a member of the ChatResponseStream union. transformSdkStream handled assistantResponseEvent, toolUseEvent, metadataEvent and contextUsageEvent and fell through on everything else, so every reasoning event was dropped. Measured against opus-5 before this change: 17 reasoning events received, 0 reasoning deltas emitted. After: 20 events in, 19 reasoning_content chunks out; 36 in, 35 out. The one-event gap per response is the trailing event carrying signature/redactedContent rather than text, which is skipped deliberately — redactedContent is encrypted by the provider and has no renderable form. Until now the only thinking that ever surfaced came from injecting <thinking_mode> into the system prompt and scraping <thinking> tags out of the assistant text. Opus 5 does not emit those tags at all, so on that model thinking was invisible regardless of configuration. The scraper stays as a fallback for models that do inline reasoning in their text; when native reasoning arrives, the scraper is bypassed and its block closed so literal tag mentions in the answer are not re-parsed. logSdkRequest now records the resolved additionalModelRequestFields, since effort was previously invisible in the logs and could not be confirmed without patching the plugin.
guidan-nick
force-pushed
the
feat/reasoning-flags-and-effort-ladder
branch
from
July 25, 2026 11:10
142b54f to
1cd6f08
Compare
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.
Thinking never rendered in OpenCode on Kiro models, and
xhigheffort could not be reached. Three independent causes.Fixes
reasoningContentEvent, whichtransformSdkStreamdid not handle, so every event was dropped. Now forwarded asreasoning_contentdeltas. Measured on opus-5: 17 events in / 0 deltas out before, 20 in / 19 out after. The one-event gap is the trailingsignature/redactedContentevent, skipped deliberately since it has no renderable text.reasoning: trueandinterleaved.field. The plugin emittedreasoning_contentbut declared neither. Both are now set on every-thinkingentry, matching how OpenCode's own registry declares non-standard reasoning fields.xhighwas unreachable.budgetToEfforthad no branch returning it, so withauto_effort_mappingon by default it was dead configuration — adding models toXHIGH_CAPABLE_MODELShad no effect. Confirmed on the wire after the fix:{"output_config":{"effort":"xhigh"}}, HTTP 200.The old mechanism was prompt injection plus scraping
<thinking>tags out of the answer. Opus 5 never emits those tags, so thinking was invisible there regardless of config. The scraper stays as a fallback for models that do inline reasoning.Also
plugin/model-registry.ts; thinking entries derive from effort capability so variants and budget bands cannot drift apart.xhighonly offered on opus-4.7/4.8/5 and sonnet-5.claude-opus-5,claude-opus-5-thinking,claude-opus-4-7-thinkingentries.reasoning.effort/reasoning.mode, notoutput_config.effort, so they need their own request path.logSdkRequestrecords the resolvedadditionalModelRequestFields; effort was previously invisible in logs and unconfirmable without patching the plugin.Breaking
Budget bands rescaled to Kiro's real range (1024–128000) instead of OpenCode's 32768 convention, so
xhighandmaxare reachable from a budget:<= 16384low<= 32768medium<= 65536high<= 98304xhigh> 98304maxA budget of 32768 now maps to
mediumrather thanmax. Anyone relying on the old bands should set an expliciteffortinkiro.json.Testing
173 tests pass,
tsc --noEmitand Prettier clean. New coverage for registry flags, xhigh gating, variant/band agreement, and the reasoning stream including the live event shape. Verified end to end against a live account withprovider.kiro.modelsremoved, so the plugin's registry supplied everything.Every behavioural claim here is wire-verified. Nothing speculative: an earlier revision of this branch added a
send_thinking_configoption to send Kiro'sthinkingblock explicitly, and it was dropped because the API's acceptance of those fields was never tested and reasoning works without them.