Skip to content

Fix structured output multi-turn conversation error#531

Merged
crmne merged 6 commits intocrmne:mainfrom
alexey-hunter-io:fix-structured-output-multi-turn
Mar 1, 2026
Merged

Fix structured output multi-turn conversation error#531
crmne merged 6 commits intocrmne:mainfrom
alexey-hunter-io:fix-structured-output-multi-turn

Conversation

@alexey-hunter-io
Copy link
Copy Markdown
Contributor

@alexey-hunter-io alexey-hunter-io commented Dec 9, 2025

What this does

Fixes multi-turn conversation error when using with_schema for structured output. The persisted Hash/Array response was being passed directly to OpenAI instead of being serialized as a JSON string.

OpenAI API expects message content to be a string, so structured output Hashes/Arrays stored in content_raw must be converted to JSON when replayed.

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Performance improvement

Scope check

  • I read the Contributing Guide
  • This aligns with RubyLLM's focus on LLM communication
  • This isn't application-specific logic that belongs in user code
  • This benefits most users, not just my specific use case

Quality check

  • I ran overcommit --install and all hooks pass
  • I tested my changes thoroughly
    • For provider changes: Re-recorded VCR cassettes with bundle exec rake vcr:record[provider_name]
    • All tests pass: bundle exec rspec
  • I updated documentation if needed
  • I didn't modify auto-generated files manually (models.json, aliases.json)

API changes

  • Breaking change
  • New public methods/classes
  • Changed method signatures
  • No API changes

Related issues

Fixes #497

When using with_schema for structured output and continuing a
conversation, the persisted Hash response was being passed directly
to OpenAI instead of being serialized as JSON string.

OpenAI API expects message content to be a string, so structured
output Hashes stored in content_raw must be converted to JSON when
replayed.

Fixes crmne#497
Copy link
Copy Markdown

@nerlichman nerlichman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

We faced the same issue on a project and applied locally the changes suggested in this PR, and this fixed our issue.

Comment thread lib/ruby_llm/providers/openai/media.rb Outdated
Comment on lines 12 to 15
return content.value.is_a?(Hash) ? content.value.to_json : content.value
end
return content.to_json if content.is_a?(Hash) || content.is_a?(Array)
return content unless content.is_a?(Content)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the same logic is done on Content::Raw for Hash/Array but using value instead of directly using content.

Maybe something like this could work too:

value = content.is_a?(RubyLLM::Content::Raw) ? content.value : content

return value.to_json if value.is_a?(Hash) || value.is_a?(Array)

return content unless content.is_a?(Content)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I've added an array check for consistency

@alexey-hunter-io
Copy link
Copy Markdown
Contributor Author

@crmne Is there anything I can do to help get this fix merged? Thanks!

@crmne crmne merged commit 8871844 into crmne:main Mar 1, 2026
19 checks passed
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.95%. Comparing base (31b7917) to head (9e7f3d9).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #531   +/-   ##
=======================================
  Coverage   80.95%   80.95%           
=======================================
  Files         114      114           
  Lines        5213     5215    +2     
  Branches     1351     1353    +2     
=======================================
+ Hits         4220     4222    +2     
  Misses        993      993           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Schema breaks multi-turn conversations after persistence

4 participants