feat(open_ai): image content parts, response_format and token limits - #623
Merged
Conversation
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.
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.
Changes
Message.contentis nowString | Array(Content)— either plain text, or a list of typedTextContent/ImageContentparts.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"} ]}ImageContentalso 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 barehttps://URL) raisesJSON::ParseException.CreateChatCompletiongains optionalresponse_formatandmax_completion_tokens, both exposed as arguments onchat.Encoded blobs are kept out of the logs —
redact_blobsstrips any 256+ character run of base64 / hex from the request body before it is logged. The real payload still goes out on the wire: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.[{"role": "user", "content": "a string"}]) still deserialize;voice_control'scustom_promptsis unaffected.execcallers ofchatsee the same shape.One caveat for Crystal callers: code treating
Message#contentas aStringno longer compiles against the union. Nothing in this repo does;Message#textis 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