module LittleGhost::Content
Content gives messages a shared vocabulary for text, attachments, tool calls, tool results, and model reasoning. The same blocks move between agents, providers, tools, and sessions without leaking a provider’s wire format.
block = LittleGhost::Content::Text.new(text: "Hello") LittleGhost::Content.normalize("Hello") == block # => true
Every block serializes through Content.serialize. Binary data uses strict base64 encoding in the serialized form.
Public Instance Methods
Source
# File lib/little_ghost/content.rb, line 244 def from_hash(value) hash = value.transform_keys(&:to_sym) type = hash.delete(:type)&.to_sym encoding = hash.delete(:encoding) if encoding.to_s == "base64" encoded = hash.delete(:data) raise ArgumentError, "base64 data is required" unless encoded.is_a?(String) decoded = Base64.strict_decode64(encoded) if type == :reasoning hash[:redacted_content] = decoded else hash[:data] = decoded end end if type == :tool_result hash[:status] = hash[:status].to_sym if hash[:status] if hash[:content].is_a?(Array) hash[:content] = hash[:content].map do |block| if block.is_a?(Hash) && (block.key?(:type) || block.key?("type")) normalize(block) else block end end end end klass = { text: Text, image: Image, document: Document, tool_use: ToolUse, tool_result: ToolResult, reasoning: Reasoning }.fetch(type) { raise ArgumentError, "Unsupported content type: #{type.inspect}" } klass.new(**hash) rescue ArgumentError, KeyError => error raise ArgumentError, "Invalid #{type || "content"} block: #{error.message}" end
Reconstructs a content block from its serialized hash.
Source
# File lib/little_ghost/content.rb, line 230 def normalize(value) case value when Text, Image, Document, ToolUse, ToolResult, Reasoning value when String Text.new(text: value) when Hash from_hash(value) else raise ArgumentError, "Unsupported content block: #{value.class}" end end
Accepts an existing block, a String, or a serialized Hash.
Source
# File lib/little_ghost/content.rb, line 285 def serialize(block) case block when Text then {"type" => "text", "text" => block.text} when Reasoning {"type" => "reasoning", "text" => block.text}.tap do |value| value["signature"] = block.signature if block.signature if block.redacted_content value["data"] = Base64.strict_encode64(block.redacted_content) value["encoding"] = "base64" end value["details"] = block.details if block.details end when Image binary("image", block.data, media_type: block.media_type) when Document binary("document", block.data, media_type: block.media_type, name: block.name) when ToolUse {"type" => "tool_use", "id" => block.id, "name" => block.name, "input" => block.input} when ToolResult { "type" => "tool_result", "tool_use_id" => block.tool_use_id, "content" => serialize_tool_result_content(block.content), "status" => block.status.to_s } else raise ArgumentError, "Unsupported content block: #{block.class}" end end
Produces the JSON-safe representation of block.