ai-agents 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df386be7e27f87111901954d72e4caa3e26a1d789ec113fbf9e2da9d2f87587e
4
- data.tar.gz: f05b6827852966d0514abae61c7732a34ea92aeebe30855132ec8bee39c1e4c2
3
+ metadata.gz: 1e4285e8a584df94b230a5e9e65e4d7991bab421c48b02726e7a69882068ca9d
4
+ data.tar.gz: 5ebaacb25ed21e880c6393b70ff1a661216b2f7f4f2e946db8d298bb1fe8acc2
5
5
  SHA512:
6
- metadata.gz: 2180b6b495519d34ff4762cd027d6079fb39ad91117242f6f366779fd7360c7bbb55521761e151ad246eee3004363de9bf768ca953a8e69a1e39e2f2dfeb5345
7
- data.tar.gz: 41dadb09fd62a2ce47b063c6b85685f1efa8be73dbee467e83ad69cdb32793926aaadacbce7bfa820960c0d5f35e57325a7078733c19bef0e1121076bc6a9002
6
+ metadata.gz: 0c96c699fa544c44ca8200d70d8663adc2f82a39b9f58001d87b0a79f0c64ace068bbb5622d9708aaec7f5e48be0128c9e04dcbe918c899cc03c00ffaa710bd9
7
+ data.tar.gz: b103cd93cda31c7adfa874405587a6fdd5fc2c54049179e55651dd21585b4ea047d856596eceaf4108a631e30fc787f943d43247d3765c51950130f6e5126176
data/CHANGELOG.md CHANGED
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.1] - 2026-02-24
11
+
12
+ ### Fixed
13
+ - **Multimodal Conversation History**: Restored multimodal image content from conversation history, ensuring image URLs and base64 data are preserved across agent turns (#46)
14
+ - **Tracing Instrumentation**: Improved serialization of multimodal content in tracing callbacks, returning JSON for non-text content types
15
+
16
+ ### Changed
17
+ - **Test Infrastructure**: OpenTelemetry stubs in tests are now conditionally applied only when the `opentelemetry-api` gem is not installed (#45)
18
+
10
19
  ## [0.9.0] - 2026-02-09
11
20
 
12
21
  ### Added
@@ -48,7 +48,7 @@ module Agents
48
48
  tracing = tracing_state(context_wrapper)
49
49
  return unless tracing
50
50
 
51
- tracing[:pending_llm_input] = input.to_s
51
+ tracing[:pending_llm_input] = serialize_output(input)
52
52
 
53
53
  return if tracing[:current_agent_name] == agent_name
54
54
 
@@ -206,7 +206,7 @@ module Agents
206
206
  content = response.content
207
207
  return format_tool_calls(response) if content.nil?
208
208
 
209
- text = content.is_a?(Hash) || content.is_a?(Array) ? content.to_json : content.to_s
209
+ text = serialize_content(content)
210
210
  return format_tool_calls(response) if text.empty?
211
211
 
212
212
  text
@@ -229,6 +229,8 @@ module Agents
229
229
  end
230
230
 
231
231
  def serialize_content(content)
232
+ return serialize_multimodal_content(content) if multimodal_content?(content)
233
+
232
234
  content.is_a?(Hash) || content.is_a?(Array) ? content.to_json : content.to_s
233
235
  end
234
236
 
@@ -240,6 +242,8 @@ module Agents
240
242
  end
241
243
 
242
244
  def serialize_output(value)
245
+ return serialize_multimodal_content(value) if multimodal_content?(value)
246
+
243
247
  value.is_a?(Hash) || value.is_a?(Array) ? value.to_json : value.to_s
244
248
  end
245
249
 
@@ -334,6 +338,23 @@ module Agents
334
338
  def cleanup_tracing_state(context_wrapper)
335
339
  context_wrapper.context.delete(:__otel_tracing)
336
340
  end
341
+
342
+ def multimodal_content?(value)
343
+ value.respond_to?(:text) && value.respond_to?(:attachments)
344
+ end
345
+
346
+ def serialize_multimodal_content(content)
347
+ parts = []
348
+ text = content.text
349
+ parts << text if text && !text.empty?
350
+
351
+ if content.attachments&.any?
352
+ urls = content.attachments.map { |a| a.respond_to?(:source) ? a.source.to_s : a.to_s }
353
+ parts << "Attachments: #{urls.join(", ")}"
354
+ end
355
+
356
+ parts.join("\n")
357
+ end
337
358
  end
338
359
  end
339
360
  end
data/lib/agents/runner.rb CHANGED
@@ -334,7 +334,7 @@ module Agents
334
334
 
335
335
  params = {
336
336
  role: role,
337
- content: RubyLLM::Content.new(content_value)
337
+ content: build_content(content_value)
338
338
  }
339
339
 
340
340
  # Handle tool-specific parameters (Tool Results)
@@ -366,6 +366,24 @@ module Agents
366
366
  params
367
367
  end
368
368
 
369
+ # Build RubyLLM::Content from stored content, handling multimodal arrays with image attachments.
370
+ # Multimodal arrays follow the OpenAI content format: [{type: 'text', text: '...'}, {type: 'image_url', ...}]
371
+ def build_content(content_value)
372
+ return RubyLLM::Content.new(content_value) unless content_value.is_a?(Array)
373
+
374
+ text_parts = content_value.filter_map { |p| p[:text] || p["text"] if (p[:type] || p["type"]) == "text" }
375
+ image_urls = content_value.filter_map do |p|
376
+ next unless (p[:type] || p["type"]) == "image_url"
377
+
378
+ p.dig(:image_url, :url) || p.dig("image_url", "url")
379
+ end
380
+
381
+ return RubyLLM::Content.new(content_value.to_json) if text_parts.empty? && image_urls.empty?
382
+
383
+ text = text_parts.join(" ")
384
+ image_urls.any? ? RubyLLM::Content.new(text, image_urls) : RubyLLM::Content.new(text)
385
+ end
386
+
369
387
  # Validate tool message has required tool_call_id
370
388
  def valid_tool_message?(msg)
371
389
  if msg[:tool_call_id]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Agents
4
- VERSION = "0.9.0"
4
+ VERSION = "0.9.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ai-agents
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shivam Mishra