Add Data and JSONValue paths for GeneratedContent JSON coding - #257
Merged
Merged
Conversation
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.
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.
GeneratedContentcould only be built from a JSONStringand only serialized back to one, so callers holding responseDataor aJSONValuehad to go through a string and parse twice. ItsCodableconformance also only accepted the internalid/kindrepresentation, which made it unusable as a property on aDecodableprovider response and was the root of the replay bug in #235. This addsinit(json: Data)andjsonData, direct conversion to and fromJSONValue(withConvertibleToGeneratedContentandConvertibleFromGeneratedContentconformances), 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
JSONValuedirectly. This also fixes Anthropic tool-call replay, which still encoded arguments with theCodablewrapper and sent the internalkindstructure astool_useinput.Resolves #105