Module: LittleGhost::Content
- Defined in:
- lib/little_ghost/content.rb
Overview
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.
Defined Under Namespace
Classes: Document, Image, Reasoning, Text, ToolResult, ToolUse
Constant Summary collapse
- Serializable =
:nodoc:
Module.new do # :nodoc: def to_h = Content.serialize(self) def to_json(*arguments) = JSON.generate(to_h, *arguments) end
Class Method Summary collapse
-
.binary(type, data, **attributes) ⇒ Object
:nodoc:.
-
.from_hash(value) ⇒ Object
Reconstructs a content block from its serialized hash.
-
.normalize(value) ⇒ Object
Accepts an existing block, a String, or a serialized Hash.
-
.serialize(block) ⇒ Object
Produces the JSON-safe representation of
block. -
.serialize_tool_result_content(content) ⇒ Object
:nodoc:.
Class Method Details
.binary(type, data, **attributes) ⇒ Object
:nodoc:
313 314 315 316 |
# File 'lib/little_ghost/content.rb', line 313 def binary(type, data, **attributes) # :nodoc: {"type" => type, "data" => Base64.strict_encode64(data), "encoding" => "base64"} .merge(attributes.transform_keys(&:to_s)) end |
.from_hash(value) ⇒ Object
Reconstructs a content block from its serialized hash.
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# 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.}" end |
.normalize(value) ⇒ Object
Accepts an existing block, a String, or a serialized Hash.
230 231 232 233 234 235 236 237 238 239 240 241 |
# 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 |
.serialize(block) ⇒ Object
Produces the JSON-safe representation of block.
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# 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 |
.serialize_tool_result_content(content) ⇒ Object
:nodoc:
318 319 320 321 322 |
# File 'lib/little_ghost/content.rb', line 318 def serialize_tool_result_content(content) # :nodoc: return content unless content.is_a?(Array) content.map { |block| block.respond_to?(:to_h) ? block.to_h : block } end |