claude-agent-sdk 0.7.2 → 0.7.3

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: 1bb953f4036b0f107f4afe0bfb8d89281bb3d496cf15f89a6c5607e7b3b5e210
4
- data.tar.gz: 84081e6b7aa1ebbe580b0e900f4142829278c3a458dc706807e4d141a0af70ff
3
+ metadata.gz: d17d03fa867e2779de155d6fba8a86fbc9edbc5662157ca3e21606016c81fb17
4
+ data.tar.gz: 949787994cd58eb5be72b8834a519a704697c61ecbfff9ca1d6f4e1fe921b18f
5
5
  SHA512:
6
- metadata.gz: eda57b17c43f2efa673e31cba432db7022af999e8c8de82065bc4e21c13325a07480cc632004226847d383881916605218332b129f0524d2b3a1c0b291dee3d1
7
- data.tar.gz: e5e9f25bb361ecaaf84a9972e55d94ed1eb18e5ae50c7abc8831f9a3a01c36e510835a8d253f71c0ba0df7f88de04ca024125ac4627a4274c84629e56ba3f57c
6
+ metadata.gz: a99fdb7b2dcab7e0286763abfb1f6d0277423a7ef2198a040ef8c76a8959907009ebc21f6523c35ecff1409a66fd8c636648d1f594aaa481119ed3598eb1b06e
7
+ data.tar.gz: 8e3e7e26487dcfe993534d3d1b7f695ba5009ad18e9d173c9e1e0f1353ec54565905f3e74e81a39eb5789aa2df008536a2a5a191095e7d8604f36abd27bb6583
data/CHANGELOG.md CHANGED
@@ -5,11 +5,30 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.7.3] - 2026-02-26
9
+
10
+ ### Fixed
11
+ - **String-keyed JSON schema crash:** Libraries like [RubyLLM](https://github.com/crmne/ruby_llm) that deep-stringify schema keys (e.g., `{ 'type' => 'object', 'properties' => { ... } }`) were misidentified as simple type-mapping schemas, causing each top-level key to be treated as a parameter name instead of passing the schema through. Now both symbol-keyed and string-keyed schemas are detected and normalized correctly. (PR #9 by [@iuhoay](https://github.com/iuhoay))
12
+ - **Shallow key symbolization:** `convert_schema` used `transform_keys` (shallow) which left nested property keys as strings, breaking downstream `MCP::Tool::InputSchema` construction. Now uses deep symbolization recursively.
13
+ - **Guard ordering crash:** `convert_schema` and `convert_input_schema` accessed `schema[:type]` before the `schema.is_a?(Hash)` guard, which would raise `NoMethodError` on `nil` input.
14
+ - **Schema detection tightened:** Pre-built schema detection now requires `type == 'object'` and `properties.is_a?(Hash)`, preventing false positives when a simple schema happens to have parameters named `type` and `properties`.
15
+
16
+ ### Added
17
+ - `ClaudeAgentSDK.deep_symbolize_keys` utility method for recursive hash key symbolization
18
+
8
19
  ## [0.7.2] - 2026-02-21
9
20
 
10
21
  ### Fixed
22
+ - **Unknown content block crash:** Unrecognized content block types (e.g., `document` blocks from PDF reading) now return `UnknownBlock` instead of raising `MessageParseError`, aligning with the Python SDK's forward-compatible design
23
+ - **Unknown message type crash:** Unrecognized message types now return `nil` (skipped by callers) instead of raising
11
24
  - **Empty input schema crash:** Tools with no parameters (`input_schema: {}`) caused `MCP::Tool::InputSchema` validation failure (`required` array must have at least 1 item per JSON Schema draft-04). Now omits `required` when empty.
12
- - **RuboCop offense:** Removed redundant `else` clause in `MessageParser.parse`
25
+
26
+ ### Added
27
+ - `UnknownBlock` type that preserves raw data for unrecognized content block types
28
+
29
+ ### Changed
30
+ - **Breaking (minor):** `MessageParser.parse` no longer raises `MessageParseError` for unknown message types — returns `nil` instead. If you were rescuing `MessageParseError` to handle unknown types, check for `nil` return values instead.
31
+ - **Breaking (minor):** `MessageParser.parse_content_block` no longer raises `MessageParseError` for unknown content block types — returns `UnknownBlock` instead. Content block iteration using `is_a?` filtering (e.g., `block.is_a?(TextBlock)`) is unaffected.
13
32
 
14
33
  ## [0.7.1] - 2026-02-21
15
34
 
data/README.md CHANGED
@@ -39,7 +39,7 @@ Add this line to your application's Gemfile:
39
39
  gem 'claude-agent-sdk', github: 'ya-luotao/claude-agent-sdk-ruby'
40
40
 
41
41
  # Or use a stable version from RubyGems
42
- gem 'claude-agent-sdk', '~> 0.7.2'
42
+ gem 'claude-agent-sdk', '~> 0.7.3'
43
43
  ```
44
44
 
45
45
  And then execute:
@@ -282,6 +282,26 @@ Async do
282
282
  end.wait
283
283
  ```
284
284
 
285
+ ### Pre-built JSON Schemas
286
+
287
+ If your schemas come from another library (e.g., [RubyLLM](https://github.com/crmne/ruby_llm)) that deep-stringifies keys, the SDK handles them transparently — both symbol-keyed and string-keyed schemas are accepted and normalized:
288
+
289
+ ```ruby
290
+ # Symbol keys (standard Ruby)
291
+ tool = ClaudeAgentSDK.create_tool('save', 'Save a fact', {
292
+ type: 'object',
293
+ properties: { fact: { type: 'string' } },
294
+ required: ['fact']
295
+ }) { |args| { content: [{ type: 'text', text: "Saved: #{args[:fact]}" }] } }
296
+
297
+ # String keys (e.g., from RubyLLM or JSON.parse)
298
+ tool = ClaudeAgentSDK.create_tool('save', 'Save a fact', {
299
+ 'type' => 'object',
300
+ 'properties' => { 'fact' => { 'type' => 'string' } },
301
+ 'required' => ['fact']
302
+ }) { |args| { content: [{ type: 'text', text: "Saved: #{args[:fact]}" }] } }
303
+ ```
304
+
285
305
  ### Benefits Over External MCP Servers
286
306
 
287
307
  - **No subprocess management** - Runs in the same process as your application
@@ -978,7 +998,7 @@ end
978
998
 
979
999
  ```ruby
980
1000
  # Union type of all content blocks
981
- ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock
1001
+ ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock | UnknownBlock
982
1002
  ```
983
1003
 
984
1004
  #### TextBlock
@@ -1026,6 +1046,17 @@ class ToolResultBlock
1026
1046
  end
1027
1047
  ```
1028
1048
 
1049
+ #### UnknownBlock
1050
+
1051
+ Generic content block for types the SDK doesn't explicitly handle (e.g., `document` for PDFs, `image` for inline images). Preserves the raw data for forward compatibility with newer CLI versions.
1052
+
1053
+ ```ruby
1054
+ class UnknownBlock
1055
+ attr_accessor :type, # String — the original block type (e.g., "document")
1056
+ :data # Hash — the full raw block hash
1057
+ end
1058
+ ```
1059
+
1029
1060
  ### Error Types
1030
1061
 
1031
1062
  ```ruby
@@ -3,6 +3,15 @@
3
3
  require 'mcp'
4
4
 
5
5
  module ClaudeAgentSDK
6
+ # Recursively convert all hash keys to symbols
7
+ def self.deep_symbolize_keys(obj)
8
+ case obj
9
+ when Hash then obj.transform_keys(&:to_sym).transform_values { |v| deep_symbolize_keys(v) }
10
+ when Array then obj.map { |v| deep_symbolize_keys(v) }
11
+ else obj
12
+ end
13
+ end
14
+
6
15
  # SDK MCP Server - wraps official MCP::Server with block-based API
7
16
  #
8
17
  # Unlike external MCP servers that run as separate processes, SDK MCP servers
@@ -191,9 +200,12 @@ module ClaudeAgentSDK
191
200
  private
192
201
 
193
202
  def convert_schema(schema)
194
- # If it's already a proper JSON schema, return it
195
- if schema.is_a?(Hash) && schema[:type] && schema[:properties]
196
- return schema
203
+ # If it's already a proper JSON schema (symbol or string keys), normalize
204
+ # to symbol keys so downstream code (schema[:properties]) works uniformly.
205
+ if schema.is_a?(Hash)
206
+ type_val = schema[:type] || schema['type']
207
+ props_val = schema[:properties] || schema['properties']
208
+ return ClaudeAgentSDK.deep_symbolize_keys(schema) if type_val == 'object' && props_val.is_a?(Hash)
197
209
  end
198
210
 
199
211
  # Simple schema: hash mapping parameter names to types
@@ -318,9 +330,12 @@ module ClaudeAgentSDK
318
330
  end
319
331
 
320
332
  def convert_input_schema(schema)
321
- # If it's already a proper JSON schema, return it
322
- if schema.is_a?(Hash) && schema[:type] && schema[:properties]
323
- return schema
333
+ # If it's already a proper JSON schema (symbol or string keys), normalize
334
+ # to symbol keys for consistent output.
335
+ if schema.is_a?(Hash)
336
+ type_val = schema[:type] || schema['type']
337
+ props_val = schema[:properties] || schema['properties']
338
+ return ClaudeAgentSDK.deep_symbolize_keys(schema) if type_val == 'object' && props_val.is_a?(Hash)
324
339
  end
325
340
 
326
341
  # Simple schema: hash mapping parameter names to types
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeAgentSDK
4
- VERSION = '0.7.2'
4
+ VERSION = '0.7.3'
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: claude-agent-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Community Contributors
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-02-21 00:00:00.000000000 Z
10
+ date: 2026-02-25 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: async