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:
324 325 326 327 |
# File 'lib/little_ghost/content.rb', line 324 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.
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 283 284 285 286 287 288 289 290 291 |
# File 'lib/little_ghost/content.rb', line 253 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.
239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/little_ghost/content.rb', line 239 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.
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/little_ghost/content.rb', line 294 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.map(&:to_h) if block.details end when Image binary("image", block.data, media_type: block.media_type).tap do |value| value["name"] = block.name if block.name end 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.to_h} 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:
329 330 331 332 333 |
# File 'lib/little_ghost/content.rb', line 329 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 |