Serialization
Copy MarkdownSycophant provides JSON round-trip serialization for all core structs via the
Sycophant.Serializable protocol. This enables persisting conversation state
to a database and restoring it later.
Round-trip Example
alias Sycophant.{Context, Serializable.Decoder}
# After a conversation
{:ok, response} = Sycophant.generate_text("openai:gpt-4o-mini", messages)
# Serialize to JSON
json = Decoder.encode(response)
# Store in database, cache, etc.
MyRepo.insert(%Conversation{state: json})
# Later, restore and continue
json = MyRepo.get(Conversation, id).state
restored = Decoder.decode(json)
ctx = restored.context |> Context.add(Message.user("Continue our chat"))
{:ok, continued} = Sycophant.generate_text("openai:gpt-4o-mini", ctx)Supported Structs
All core structs implement the Sycophant.Serializable protocol:
ResponseContextMessageMessage.Content.TextMessage.Content.ImageToolToolCallUsagePricingPricing.ComponentReasoningEmbeddingRequestEmbeddingResponseEmbeddingParams
Type Discriminators
Each serialized map includes a "__type__" key that identifies the struct
type for deserialization:
Sycophant.Serializable.to_map(%Sycophant.Usage{input_tokens: 10, output_tokens: 25})
#=> %{"__type__" => "Usage", "input_tokens" => 10, "output_tokens" => 25}Tool Registry
Function references cannot be serialized to JSON. When decoding Tool
structs, pass a :tool_registry option to restore function references:
registry = %{
"get_weather" => &MyApp.Weather.get/1,
"search" => &MyApp.Search.query/1
}
restored = Decoder.decode(json, tool_registry: registry)Tools decoded without a registry will have function: nil and behave as
manual tools.
Working with Maps
Use from_map/2 when you already have parsed maps (e.g., from a JSON column
in your database):
map = %{"__type__" => "Usage", "input_tokens" => 10, "output_tokens" => 25}
usage = Decoder.from_map(map)
#=> %Sycophant.Usage{input_tokens: 10, output_tokens: 25}