Skip to content

Add Data and JSONValue paths for GeneratedContent JSON coding - #257

Merged
mattt merged 3 commits into
mainfrom
mattt/fix-issue-105
Sep 17, 2026
Merged

mattt merged 3 commits into
mainfrom
mattt/fix-issue-105

Conversation

@mattt

@mattt mattt commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

GeneratedContent could only be built from a JSON String and only serialized back to one, so callers holding response Data or a JSONValue had to go through a string and parse twice. Its Codable conformance also only accepted the internal id/kind representation, which made it unusable as a property on a Decodable provider response and was the root of the replay bug in #235. This adds init(json: Data) and jsonData, direct conversion to and from JSONValue (with ConvertibleToGeneratedContent and ConvertibleFromGeneratedContent conformances), and decoding of plain JSON of any shape alongside the canonical form; encoding is unchanged.

The Anthropic, Gemini, and Ollama providers now bridge tool-call arguments through JSONValue directly. This also fixes Anthropic tool-call replay, which still encoded arguments with the Codable wrapper and sent the internal kind structure as tool_use input.

Resolves #105

GeneratedContent could only be created from a JSON String and only
serialized to a String, so callers who already held Data or a JSONValue
had to convert through a String and parse twice. Its Codable conformance
also only accepted the internal id/kind representation, which made it
unusable as a property on a Decodable provider response.

Add init(json: Data) and jsonData, and make the String variants delegate
to them. Add direct conversion to and from JSONValue, and conform
JSONValue to ConvertibleToGeneratedContent and
ConvertibleFromGeneratedContent. Decoding now accepts plain JSON of any
shape in addition to the canonical representation; encoding is
unchanged.

Use the JSONValue bridge in the Anthropic, Gemini, and Ollama models.
This also fixes Anthropic tool-call replay, which encoded arguments with
the Codable wrapper and sent the internal kind structure as tool input.

Resolves #105
Decoding chose the canonical id/kind form whenever a kind member had
the canonical shape, which dropped sibling fields from plain JSON
objects. Require that the object hold only the id and kind keys,
enumerated with a string-backed CodingKey since a container keyed by
the CodingKeys enum hides unknown keys.

jsonValue walked properties while jsonString and jsonData walk
orderedKeys, so a structure with properties absent from orderedKeys
could send extra tool arguments during Anthropic or Gemini replay.
Walk orderedKeys in both.
Each helper had one caller and a single-expression body after the
switch to JSONValue bridging, so the shared names hid more than they
explained. Replace them with the direct conversions.
@mattt
mattt merged commit 688f50e into main Sep 17, 2026
12 checks passed
@mattt
mattt deleted the mattt/fix-issue-105 branch September 17, 2026 11:34
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.

Improve ergonomics / efficiency of GeneratedContent coding

1 participant