Skip to content

feat(open_ai): image content parts, response_format and token limits - #623

Merged
stakach merged 1 commit into
masterfrom
feat/gpt-image-content
Aug 3, 2026
Merged

feat(open_ai): image content parts, response_format and token limits#623
stakach merged 1 commit into
masterfrom
feat/gpt-image-content

Conversation

@MrYuion

@MrYuion MrYuion commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Changes

Message.content is now String | Array(Content) — either plain text, or a list of typed TextContent / ImageContent parts.

Images are supplied as base64 and sent to OpenAI inline as a data URI, so the driver never hands the API a URL to fetch:

{"role": "user", "content": [
  {"type": "text", "text": "what is in this image?"},
  {"type": "image_url", "image": "iVBORw0...", "media_type": "image/png"}
]}

ImageContent also parses the data URI form it emits, so it round trips its own output across the exec boundary. A payload with no base64 data (a bare https:// URL) raises JSON::ParseException.

CreateChatCompletion gains optional response_format and max_completion_tokens, both exposed as arguments on chat.

Encoded blobs are kept out of the logsredact_blobs strips any 256+ character run of base64 / hex from the request body before it is logged. The real payload still goes out on the wire:

{"type":"image_url","image_url":{"url":"data:image/png;base64,<binary data redacted>"}}

Backwards compatibility

Wire format and settings are unchanged for existing callers:

  • CreateChatCompletion.new(model, messages) with string content serializes byte-identical to before — the new fields are nil and are skipped.
  • Old settings ([{"role": "user", "content": "a string"}]) still deserialize; voice_control's custom_prompts is unaffected.
  • Responses parse and re-serialize unchanged, so exec callers of chat see the same shape.

One caveat for Crystal callers: code treating Message#content as a String no longer compiles against the union. Nothing in this repo does; Message#text is the drop-in replacement.

Testing

./harness report drivers/open_ai/gpt.cr — 1 tested, 0 failures. Specs cover the image + text part request, response_format / max_completion_tokens, omission of both when unset, and the plain string path.

🤖 Generated with Claude Code

Message content is now either a plain string or a list of typed text /
image parts. Images are provided as base64 encoded data and sent to
OpenAI inline as a data URI, so drivers never hand the API a URL to
fetch. ImageContent parses both forms, allowing it to round trip its own
serialized output across the exec boundary.

Adds the optional response_format and max_completion_tokens fields to
CreateChatCompletion, exposed as arguments on chat.

Request bodies are also scrubbed of long base64 / hex runs before they
are logged, keeping encoded images out of the debug logs.
@MrYuion
MrYuion requested a review from stakach August 3, 2026 04:59

@stakach stakach left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@stakach
stakach merged commit 7336a08 into master Aug 3, 2026
3 of 6 checks passed
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.

2 participants