You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[FEATURE]: Support for Structured Outputs in the OpenCode SDK #5639
I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
I would love to use opencode for some existing workflows we have which currently depend on the Claude Code SDK's structured output feature which allows generating JSON (generateObject-style) from an extant session:
I actually posted a review on #8161, but part of it is a discussion, so I'll bring it back up here.
Note
[Context] the PR implements a solution using the following pattern:
inject a system prompt that requests the model call a specific tool to terminate
provides a tool which enforces the schema called (the structured output tool)
this tool enforces schema compliance after the LLM is done iterating
retry with the LLM if failed (not sure this is actually implemented in the PR yet)
Relevant section of my review:
discussion: architecture
Is this the best path to take? I understand this is reverse-engineered from Claude Code, but let's be honest: I'm here because Claude Code was pissing me off. They couldn't even figure out how to remove MCP tools from their prompts when the tools are disabled for subagents.
That said, what do you think about an approach that utilizes the provider-level structured outputs? Almost all providers implement something for their models, and I think we could likely provide a clean abstraction that utilizes those features.
I personally built a system similar to this PR this inside my own plugin. Instead of a tool call, it simply injected the expected response format and requested the model reply in an object that matched. It does work, there's no doubt of that, but it does have it's limitations. In some scenarios, assuming the retry logic is implemented, you end up with a few extra round trips to correct the outputs. It's easy enough to enforce this at the tool layer, but different models have different levels of "willingness to cooperate".
Regarding my implementation, I injected the Zod schemas directly (in a format the LLM could understand) and asked it to just generate that output, instead of calling a tool. I found this method to be slightly more reliable than requesting a tool call, because many models see tool calls and "non-terminal" to their execution loops. Or at least, this is a working theory I have based off how many times I've seen OpenAI models get sassy when I request they end with tool calls.
Anyway, food for thought.
So I want to raise that question here: should we try to use provider-level support for structured outputs, should we use the tool/validate/retry method, a combo, or something else entirely?
I will say the tool/validate/retry method is more "universally supported" but you also do not get deterministic results. You are at the mercy of the model obeying the injected prompt and calling the tool. I have seen the tool/validate/retry not work so well, in my own attempts, but that's purely anecdotal and it only affected the "lower end" models. I wouldn't put much stock into that assessment. It does fine on most decent models.
The provider-level support is definitely more reliable; however, the implementation might be a little more complex. We would need some abstraction (shouldn't be too hard) along with implementations for each provider type...this might be hard? I don't honestly know.
Overall I feel like a provider-level solution (with a tool/validate/retry fallback) is the best approach long term, but would love to hear yalls thoughts on the matter.
Reacted by Alan Pogrebinschi, ItsVel0 and jbonatakis
Activity
github-actions commentedon Dec 16, 2025
This issue might be a duplicate of existing issues. Please check:
Feel free to ignore if none of these address your specific case.
seuros commentedon Dec 16, 2025
Possible once #5463 is merged.
The experimental client does no support structure.
AshwanthramKL commentedon Jan 12, 2026
@seuros Any update on this?
seuros commentedon Jan 12, 2026
It possible now, i can open a PR if thdxr 👍🏼 .
It looks like mcp is not top priority for now for them.
K-Mistele commentedon Jan 13, 2026
Will try to ship a PR for it this week
eXamadeus commentedon Jan 19, 2026
I actually posted a review on #8161, but part of it is a discussion, so I'll bring it back up here.
Note
[Context] the PR implements a solution using the following pattern:
Relevant section of my review:
So I want to raise that question here: should we try to use provider-level support for structured outputs, should we use the tool/validate/retry method, a combo, or something else entirely?
I will say the tool/validate/retry method is more "universally supported" but you also do not get deterministic results. You are at the mercy of the model obeying the injected prompt and calling the tool. I have seen the tool/validate/retry not work so well, in my own attempts, but that's purely anecdotal and it only affected the "lower end" models. I wouldn't put much stock into that assessment. It does fine on most decent models.
The provider-level support is definitely more reliable; however, the implementation might be a little more complex. We would need some abstraction (shouldn't be too hard) along with implementations for each provider type...this might be hard? I don't honestly know.
Overall I feel like a provider-level solution (with a tool/validate/retry fallback) is the best approach long term, but would love to hear yalls thoughts on the matter.
roadmap: #218 filed — MessageRequest has no response_format / output_…
roadmap: #218 filed — MessageRequest has no response_format / output_…
roadmap: #218 filed — MessageRequest has no response_format / output_…
roadmap: ultraworkers#218 filed — MessageRequest has no response_form…
roadmap: ultraworkers#218 filed — MessageRequest has no response_form…
roadmap: ultraworkers#218 filed — MessageRequest has no response_form…
roadmap: #218 filed — MessageRequest has no response_format / output_…
roadmap: ultraworkers#218 filed — MessageRequest has no response_form…