claude-agent-sdk 0.1.1 → 0.1.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 +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +92 -5
- data/lib/claude_agent_sdk/query.rb +66 -1
- data/lib/claude_agent_sdk/sdk_mcp_server.rb +210 -4
- data/lib/claude_agent_sdk/streaming.rb +73 -0
- data/lib/claude_agent_sdk/subprocess_cli_transport.rb +22 -21
- data/lib/claude_agent_sdk/types.rb +25 -0
- data/lib/claude_agent_sdk/version.rb +1 -1
- data/lib/claude_agent_sdk.rb +23 -1
- metadata +3 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d1b1a2ec74f15062544d42a0df92058e256bab2ed29754e19133bfc1340cddcf
         | 
| 4 | 
            +
              data.tar.gz: f01aea04b3f32e51b5d98e6994d52c8e2864259fa86d1c5bdc64104486b63687
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: ef15b15c77ceb22fc0b40884ecc1e79a884b9b7d043b21420ef0faa34d638206eec6284ab6afeb015097d721c75c0e00ce0f3db4c63e7f8e90305bda2e468b16
         | 
| 7 | 
            +
              data.tar.gz: 74ee1d9b848c2e84336fb3a12e8147b35243f64ad6c1d352fe451a39c16a92cdaa92303acb20cf053495c580171bfe36d60f5a53bee98d2781da0b1b261870d3
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -5,6 +5,22 @@ 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.1.3] - 2025-10-15
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ### Added
         | 
| 11 | 
            +
            - **MCP resource support:** Full support for MCP resources (list, read, subscribe operations)
         | 
| 12 | 
            +
            - **MCP prompt support:** Support for MCP prompts (list, get operations)
         | 
| 13 | 
            +
            - **Streaming input support:** Added streaming capabilities for input handling
         | 
| 14 | 
            +
            - Feature complete MCP implementation matching Python SDK functionality
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            ## [0.1.2] - 2025-10-14
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            ### Fixed
         | 
| 19 | 
            +
            - **Critical:** Replaced `Async::Process` with Ruby's built-in `Open3` for subprocess management
         | 
| 20 | 
            +
            - Fixed "uninitialized constant Async::Process" error that prevented the gem from working
         | 
| 21 | 
            +
            - Process management now uses standard Ruby threads instead of async tasks
         | 
| 22 | 
            +
            - All 86 tests passing
         | 
| 23 | 
            +
             | 
| 8 24 | 
             
            ## [0.1.1] - 2025-10-14
         | 
| 9 25 |  | 
| 10 26 | 
             
            ### Fixed
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,11 +1,13 @@ | |
| 1 1 | 
             
            # Claude Agent SDK for Ruby
         | 
| 2 2 |  | 
| 3 | 
            -
            > **⚠️ DISCLAIMER**: This is an **unofficial, community-maintained** Ruby SDK for Claude Agent. It is not officially supported or maintained by Anthropic. For official SDK support, please refer to the [Python SDK](https:// | 
| 3 | 
            +
            > **⚠️ DISCLAIMER**: This is an **unofficial, community-maintained** Ruby SDK for Claude Agent. It is not officially supported or maintained by Anthropic. For official SDK support, please refer to the [Python SDK](https://docs.claude.com/en/api/agent-sdk/python).
         | 
| 4 4 | 
             
            >
         | 
| 5 5 | 
             
            > This implementation is based on the official Python SDK and aims to provide feature parity for Ruby developers. Use at your own risk.
         | 
| 6 6 |  | 
| 7 7 | 
             
            Ruby SDK for Claude Agent. See the [Claude Agent SDK documentation](https://docs.anthropic.com/en/docs/claude-code/sdk) for more information.
         | 
| 8 8 |  | 
| 9 | 
            +
            [](https://badge.fury.io/rb/claude-agent-sdk)
         | 
| 10 | 
            +
             | 
| 9 11 | 
             
            ## Installation
         | 
| 10 12 |  | 
| 11 13 | 
             
            Add this line to your application's Gemfile:
         | 
| @@ -92,6 +94,41 @@ options = ClaudeAgentSDK::ClaudeAgentOptions.new( | |
| 92 94 | 
             
            )
         | 
| 93 95 | 
             
            ```
         | 
| 94 96 |  | 
| 97 | 
            +
            ### Streaming Input
         | 
| 98 | 
            +
             | 
| 99 | 
            +
            The `query()` function supports streaming input, allowing you to send multiple messages dynamically instead of a single prompt string.
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            ```ruby
         | 
| 102 | 
            +
            require 'claude_agent_sdk'
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            # Create a stream of messages
         | 
| 105 | 
            +
            messages = ['Hello!', 'What is 2+2?', 'Thanks!']
         | 
| 106 | 
            +
            stream = ClaudeAgentSDK::Streaming.from_array(messages)
         | 
| 107 | 
            +
             | 
| 108 | 
            +
            # Query with streaming input
         | 
| 109 | 
            +
            ClaudeAgentSDK.query(prompt: stream) do |message|
         | 
| 110 | 
            +
              puts message if message.is_a?(ClaudeAgentSDK::AssistantMessage)
         | 
| 111 | 
            +
            end
         | 
| 112 | 
            +
            ```
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            You can also create custom streaming enumerators:
         | 
| 115 | 
            +
             | 
| 116 | 
            +
            ```ruby
         | 
| 117 | 
            +
            # Dynamic message generation
         | 
| 118 | 
            +
            stream = Enumerator.new do |yielder|
         | 
| 119 | 
            +
              yielder << ClaudeAgentSDK::Streaming.user_message("First message")
         | 
| 120 | 
            +
              # Do some processing...
         | 
| 121 | 
            +
              yielder << ClaudeAgentSDK::Streaming.user_message("Second message")
         | 
| 122 | 
            +
              yielder << ClaudeAgentSDK::Streaming.user_message("Third message")
         | 
| 123 | 
            +
            end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
            ClaudeAgentSDK.query(prompt: stream) do |message|
         | 
| 126 | 
            +
              # Process responses
         | 
| 127 | 
            +
            end
         | 
| 128 | 
            +
            ```
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            For a complete example, see [examples/streaming_input_example.rb](examples/streaming_input_example.rb).
         | 
| 131 | 
            +
             | 
| 95 132 | 
             
            ## Client
         | 
| 96 133 |  | 
| 97 134 | 
             
            `ClaudeAgentSDK::Client` supports bidirectional, interactive conversations with Claude Code. Unlike `query()`, `Client` enables **custom tools**, **hooks**, and **permission callbacks**, all of which can be defined as Ruby procs/lambdas. See [lib/claude_agent_sdk.rb](lib/claude_agent_sdk.rb).
         | 
| @@ -193,6 +230,58 @@ options = ClaudeAgentSDK::ClaudeAgentOptions.new( | |
| 193 230 | 
             
            )
         | 
| 194 231 | 
             
            ```
         | 
| 195 232 |  | 
| 233 | 
            +
            #### MCP Resources and Prompts
         | 
| 234 | 
            +
             | 
| 235 | 
            +
            SDK MCP servers can also expose **resources** (data sources) and **prompts** (reusable templates):
         | 
| 236 | 
            +
             | 
| 237 | 
            +
            ```ruby
         | 
| 238 | 
            +
            # Create a resource (data source Claude can read)
         | 
| 239 | 
            +
            config_resource = ClaudeAgentSDK.create_resource(
         | 
| 240 | 
            +
              uri: 'config://app/settings',
         | 
| 241 | 
            +
              name: 'Application Settings',
         | 
| 242 | 
            +
              description: 'Current app configuration',
         | 
| 243 | 
            +
              mime_type: 'application/json'
         | 
| 244 | 
            +
            ) do
         | 
| 245 | 
            +
              config_data = { app_name: 'MyApp', version: '1.0.0' }
         | 
| 246 | 
            +
              {
         | 
| 247 | 
            +
                contents: [{
         | 
| 248 | 
            +
                  uri: 'config://app/settings',
         | 
| 249 | 
            +
                  mimeType: 'application/json',
         | 
| 250 | 
            +
                  text: JSON.pretty_generate(config_data)
         | 
| 251 | 
            +
                }]
         | 
| 252 | 
            +
              }
         | 
| 253 | 
            +
            end
         | 
| 254 | 
            +
             | 
| 255 | 
            +
            # Create a prompt template
         | 
| 256 | 
            +
            review_prompt = ClaudeAgentSDK.create_prompt(
         | 
| 257 | 
            +
              name: 'code_review',
         | 
| 258 | 
            +
              description: 'Review code for best practices',
         | 
| 259 | 
            +
              arguments: [
         | 
| 260 | 
            +
                { name: 'code', description: 'Code to review', required: true }
         | 
| 261 | 
            +
              ]
         | 
| 262 | 
            +
            ) do |args|
         | 
| 263 | 
            +
              {
         | 
| 264 | 
            +
                messages: [{
         | 
| 265 | 
            +
                  role: 'user',
         | 
| 266 | 
            +
                  content: {
         | 
| 267 | 
            +
                    type: 'text',
         | 
| 268 | 
            +
                    text: "Review this code: #{args[:code]}"
         | 
| 269 | 
            +
                  }
         | 
| 270 | 
            +
                }]
         | 
| 271 | 
            +
              }
         | 
| 272 | 
            +
            end
         | 
| 273 | 
            +
             | 
| 274 | 
            +
            # Create server with tools, resources, and prompts
         | 
| 275 | 
            +
            server = ClaudeAgentSDK.create_sdk_mcp_server(
         | 
| 276 | 
            +
              name: 'dev-tools',
         | 
| 277 | 
            +
              tools: [my_tool],
         | 
| 278 | 
            +
              resources: [config_resource],
         | 
| 279 | 
            +
              prompts: [review_prompt]
         | 
| 280 | 
            +
            )
         | 
| 281 | 
            +
            ```
         | 
| 282 | 
            +
             | 
| 283 | 
            +
            For complete examples, see [examples/mcp_resources_prompts_example.rb](examples/mcp_resources_prompts_example.rb).
         | 
| 284 | 
            +
             | 
| 196 285 | 
             
            ### Basic Client Usage
         | 
| 197 286 |  | 
| 198 287 | 
             
            ```ruby
         | 
| @@ -415,7 +504,9 @@ See the following examples for complete working code: | |
| 415 504 |  | 
| 416 505 | 
             
            - [examples/quick_start.rb](examples/quick_start.rb) - Basic `query()` usage with options
         | 
| 417 506 | 
             
            - [examples/client_example.rb](examples/client_example.rb) - Interactive Client usage
         | 
| 507 | 
            +
            - [examples/streaming_input_example.rb](examples/streaming_input_example.rb) - Streaming input for multi-turn conversations
         | 
| 418 508 | 
             
            - [examples/mcp_calculator.rb](examples/mcp_calculator.rb) - Custom tools with SDK MCP servers
         | 
| 509 | 
            +
            - [examples/mcp_resources_prompts_example.rb](examples/mcp_resources_prompts_example.rb) - MCP resources and prompts
         | 
| 419 510 | 
             
            - [examples/hooks_example.rb](examples/hooks_example.rb) - Using hooks to control tool execution
         | 
| 420 511 | 
             
            - [examples/permission_callback_example.rb](examples/permission_callback_example.rb) - Dynamic tool permission control
         | 
| 421 512 |  | 
| @@ -423,10 +514,6 @@ See the following examples for complete working code: | |
| 423 514 |  | 
| 424 515 | 
             
            After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rspec` to run the tests.
         | 
| 425 516 |  | 
| 426 | 
            -
            ## Contributing
         | 
| 427 | 
            -
             | 
| 428 | 
            -
            Bug reports and pull requests are welcome on GitHub at https://github.com/anthropics/claude-agent-sdk-ruby.
         | 
| 429 | 
            -
             | 
| 430 517 | 
             
            ## License
         | 
| 431 518 |  | 
| 432 519 | 
             
            The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
         | 
| @@ -314,6 +314,14 @@ module ClaudeAgentSDK | |
| 314 314 | 
             
                    handle_mcp_tools_list(server, message)
         | 
| 315 315 | 
             
                  when 'tools/call'
         | 
| 316 316 | 
             
                    handle_mcp_tools_call(server, message, params)
         | 
| 317 | 
            +
                  when 'resources/list'
         | 
| 318 | 
            +
                    handle_mcp_resources_list(server, message)
         | 
| 319 | 
            +
                  when 'resources/read'
         | 
| 320 | 
            +
                    handle_mcp_resources_read(server, message, params)
         | 
| 321 | 
            +
                  when 'prompts/list'
         | 
| 322 | 
            +
                    handle_mcp_prompts_list(server, message)
         | 
| 323 | 
            +
                  when 'prompts/get'
         | 
| 324 | 
            +
                    handle_mcp_prompts_get(server, message, params)
         | 
| 317 325 | 
             
                  when 'notifications/initialized'
         | 
| 318 326 | 
             
                    { jsonrpc: '2.0', result: {} }
         | 
| 319 327 | 
             
                  else
         | 
| @@ -332,12 +340,17 @@ module ClaudeAgentSDK | |
| 332 340 | 
             
                end
         | 
| 333 341 |  | 
| 334 342 | 
             
                def handle_mcp_initialize(server, message)
         | 
| 343 | 
            +
                  capabilities = {}
         | 
| 344 | 
            +
                  capabilities[:tools] = {} if server.tools && !server.tools.empty?
         | 
| 345 | 
            +
                  capabilities[:resources] = {} if server.resources && !server.resources.empty?
         | 
| 346 | 
            +
                  capabilities[:prompts] = {} if server.prompts && !server.prompts.empty?
         | 
| 347 | 
            +
             | 
| 335 348 | 
             
                  {
         | 
| 336 349 | 
             
                    jsonrpc: '2.0',
         | 
| 337 350 | 
             
                    id: message[:id],
         | 
| 338 351 | 
             
                    result: {
         | 
| 339 352 | 
             
                      protocolVersion: '2024-11-05',
         | 
| 340 | 
            -
                      capabilities:  | 
| 353 | 
            +
                      capabilities: capabilities,
         | 
| 341 354 | 
             
                      serverInfo: {
         | 
| 342 355 | 
             
                        name: server.name,
         | 
| 343 356 | 
             
                        version: server.version || '1.0.0'
         | 
| @@ -384,6 +397,58 @@ module ClaudeAgentSDK | |
| 384 397 | 
             
                  }
         | 
| 385 398 | 
             
                end
         | 
| 386 399 |  | 
| 400 | 
            +
                def handle_mcp_resources_list(server, message)
         | 
| 401 | 
            +
                  # List resources from the SDK MCP server
         | 
| 402 | 
            +
                  resources_data = server.list_resources
         | 
| 403 | 
            +
                  {
         | 
| 404 | 
            +
                    jsonrpc: '2.0',
         | 
| 405 | 
            +
                    id: message[:id],
         | 
| 406 | 
            +
                    result: { resources: resources_data }
         | 
| 407 | 
            +
                  }
         | 
| 408 | 
            +
                end
         | 
| 409 | 
            +
             | 
| 410 | 
            +
                def handle_mcp_resources_read(server, message, params)
         | 
| 411 | 
            +
                  # Read a resource from the SDK MCP server
         | 
| 412 | 
            +
                  uri = params[:uri]
         | 
| 413 | 
            +
                  raise 'Missing uri parameter for resources/read' unless uri
         | 
| 414 | 
            +
             | 
| 415 | 
            +
                  # Read the resource
         | 
| 416 | 
            +
                  result = server.read_resource(uri)
         | 
| 417 | 
            +
             | 
| 418 | 
            +
                  {
         | 
| 419 | 
            +
                    jsonrpc: '2.0',
         | 
| 420 | 
            +
                    id: message[:id],
         | 
| 421 | 
            +
                    result: result
         | 
| 422 | 
            +
                  }
         | 
| 423 | 
            +
                end
         | 
| 424 | 
            +
             | 
| 425 | 
            +
                def handle_mcp_prompts_list(server, message)
         | 
| 426 | 
            +
                  # List prompts from the SDK MCP server
         | 
| 427 | 
            +
                  prompts_data = server.list_prompts
         | 
| 428 | 
            +
                  {
         | 
| 429 | 
            +
                    jsonrpc: '2.0',
         | 
| 430 | 
            +
                    id: message[:id],
         | 
| 431 | 
            +
                    result: { prompts: prompts_data }
         | 
| 432 | 
            +
                  }
         | 
| 433 | 
            +
                end
         | 
| 434 | 
            +
             | 
| 435 | 
            +
                def handle_mcp_prompts_get(server, message, params)
         | 
| 436 | 
            +
                  # Get a prompt from the SDK MCP server
         | 
| 437 | 
            +
                  name = params[:name]
         | 
| 438 | 
            +
                  raise 'Missing name parameter for prompts/get' unless name
         | 
| 439 | 
            +
             | 
| 440 | 
            +
                  arguments = params[:arguments] || {}
         | 
| 441 | 
            +
             | 
| 442 | 
            +
                  # Get the prompt
         | 
| 443 | 
            +
                  result = server.get_prompt(name, arguments)
         | 
| 444 | 
            +
             | 
| 445 | 
            +
                  {
         | 
| 446 | 
            +
                    jsonrpc: '2.0',
         | 
| 447 | 
            +
                    id: message[:id],
         | 
| 448 | 
            +
                    result: result
         | 
| 449 | 
            +
                  }
         | 
| 450 | 
            +
                end
         | 
| 451 | 
            +
             | 
| 387 452 | 
             
                public
         | 
| 388 453 |  | 
| 389 454 | 
             
                # Send interrupt control request
         | 
| @@ -6,14 +6,23 @@ module ClaudeAgentSDK | |
| 6 6 | 
             
              # Unlike external MCP servers that run as separate processes, SDK MCP servers
         | 
| 7 7 | 
             
              # run directly in your application's process, providing better performance
         | 
| 8 8 | 
             
              # and simpler deployment.
         | 
| 9 | 
            +
              #
         | 
| 10 | 
            +
              # Supports:
         | 
| 11 | 
            +
              # - Tools: Executable functions that Claude can call
         | 
| 12 | 
            +
              # - Resources: Data sources that can be read (files, databases, APIs, etc.)
         | 
| 13 | 
            +
              # - Prompts: Reusable prompt templates with arguments
         | 
| 9 14 | 
             
              class SdkMcpServer
         | 
| 10 | 
            -
                attr_reader :name, :version, :tools
         | 
| 15 | 
            +
                attr_reader :name, :version, :tools, :resources, :prompts
         | 
| 11 16 |  | 
| 12 | 
            -
                def initialize(name:, version: '1.0.0', tools: [])
         | 
| 17 | 
            +
                def initialize(name:, version: '1.0.0', tools: [], resources: [], prompts: [])
         | 
| 13 18 | 
             
                  @name = name
         | 
| 14 19 | 
             
                  @version = version
         | 
| 15 20 | 
             
                  @tools = tools
         | 
| 21 | 
            +
                  @resources = resources
         | 
| 22 | 
            +
                  @prompts = prompts
         | 
| 16 23 | 
             
                  @tool_map = tools.each_with_object({}) { |tool, hash| hash[tool.name] = tool }
         | 
| 24 | 
            +
                  @resource_map = resources.each_with_object({}) { |res, hash| hash[res.uri] = res }
         | 
| 25 | 
            +
                  @prompt_map = prompts.each_with_object({}) { |prompt, hash| hash[prompt.name] = prompt }
         | 
| 17 26 | 
             
                end
         | 
| 18 27 |  | 
| 19 28 | 
             
                # List all available tools
         | 
| @@ -47,6 +56,68 @@ module ClaudeAgentSDK | |
| 47 56 | 
             
                  result
         | 
| 48 57 | 
             
                end
         | 
| 49 58 |  | 
| 59 | 
            +
                # List all available resources
         | 
| 60 | 
            +
                # @return [Array<Hash>] Array of resource definitions
         | 
| 61 | 
            +
                def list_resources
         | 
| 62 | 
            +
                  @resources.map do |resource|
         | 
| 63 | 
            +
                    {
         | 
| 64 | 
            +
                      uri: resource.uri,
         | 
| 65 | 
            +
                      name: resource.name,
         | 
| 66 | 
            +
                      description: resource.description,
         | 
| 67 | 
            +
                      mimeType: resource.mime_type
         | 
| 68 | 
            +
                    }.compact
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                # Read a resource by URI
         | 
| 73 | 
            +
                # @param uri [String] Resource URI
         | 
| 74 | 
            +
                # @return [Hash] Resource content
         | 
| 75 | 
            +
                def read_resource(uri)
         | 
| 76 | 
            +
                  resource = @resource_map[uri]
         | 
| 77 | 
            +
                  raise "Resource '#{uri}' not found" unless resource
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  # Call the resource's reader
         | 
| 80 | 
            +
                  content = resource.reader.call
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  # Ensure content has the expected format
         | 
| 83 | 
            +
                  unless content.is_a?(Hash) && content[:contents]
         | 
| 84 | 
            +
                    raise "Resource '#{uri}' must return a hash with :contents key"
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  content
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                # List all available prompts
         | 
| 91 | 
            +
                # @return [Array<Hash>] Array of prompt definitions
         | 
| 92 | 
            +
                def list_prompts
         | 
| 93 | 
            +
                  @prompts.map do |prompt|
         | 
| 94 | 
            +
                    {
         | 
| 95 | 
            +
                      name: prompt.name,
         | 
| 96 | 
            +
                      description: prompt.description,
         | 
| 97 | 
            +
                      arguments: prompt.arguments
         | 
| 98 | 
            +
                    }.compact
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                # Get a prompt by name
         | 
| 103 | 
            +
                # @param name [String] Prompt name
         | 
| 104 | 
            +
                # @param arguments [Hash] Arguments to fill in the prompt template
         | 
| 105 | 
            +
                # @return [Hash] Prompt with filled-in arguments
         | 
| 106 | 
            +
                def get_prompt(name, arguments = {})
         | 
| 107 | 
            +
                  prompt = @prompt_map[name]
         | 
| 108 | 
            +
                  raise "Prompt '#{name}' not found" unless prompt
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                  # Call the prompt's generator
         | 
| 111 | 
            +
                  result = prompt.generator.call(arguments)
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  # Ensure result has the expected format
         | 
| 114 | 
            +
                  unless result.is_a?(Hash) && result[:messages]
         | 
| 115 | 
            +
                    raise "Prompt '#{name}' must return a hash with :messages key"
         | 
| 116 | 
            +
                  end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  result
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 50 121 | 
             
                private
         | 
| 51 122 |  | 
| 52 123 | 
             
                def convert_input_schema(schema)
         | 
| @@ -130,11 +201,123 @@ module ClaudeAgentSDK | |
| 130 201 | 
             
                )
         | 
| 131 202 | 
             
              end
         | 
| 132 203 |  | 
| 204 | 
            +
              # Helper function to create a resource definition
         | 
| 205 | 
            +
              #
         | 
| 206 | 
            +
              # @param uri [String] Unique identifier for the resource (e.g., "file:///path/to/file")
         | 
| 207 | 
            +
              # @param name [String] Human-readable name
         | 
| 208 | 
            +
              # @param description [String, nil] Optional description
         | 
| 209 | 
            +
              # @param mime_type [String, nil] Optional MIME type (e.g., "text/plain", "application/json")
         | 
| 210 | 
            +
              # @param reader [Proc] Block that returns the resource content
         | 
| 211 | 
            +
              # @return [SdkMcpResource] Resource definition
         | 
| 212 | 
            +
              #
         | 
| 213 | 
            +
              # @example File resource
         | 
| 214 | 
            +
              #   resource = create_resource(
         | 
| 215 | 
            +
              #     uri: 'file:///config/settings.json',
         | 
| 216 | 
            +
              #     name: 'Application Settings',
         | 
| 217 | 
            +
              #     description: 'Current application configuration',
         | 
| 218 | 
            +
              #     mime_type: 'application/json'
         | 
| 219 | 
            +
              #   ) do
         | 
| 220 | 
            +
              #     content = File.read('/path/to/settings.json')
         | 
| 221 | 
            +
              #     {
         | 
| 222 | 
            +
              #       contents: [{
         | 
| 223 | 
            +
              #         uri: 'file:///config/settings.json',
         | 
| 224 | 
            +
              #         mimeType: 'application/json',
         | 
| 225 | 
            +
              #         text: content
         | 
| 226 | 
            +
              #       }]
         | 
| 227 | 
            +
              #     }
         | 
| 228 | 
            +
              #   end
         | 
| 229 | 
            +
              #
         | 
| 230 | 
            +
              # @example Database resource
         | 
| 231 | 
            +
              #   resource = create_resource(
         | 
| 232 | 
            +
              #     uri: 'db://users/count',
         | 
| 233 | 
            +
              #     name: 'User Count',
         | 
| 234 | 
            +
              #     description: 'Total number of registered users'
         | 
| 235 | 
            +
              #   ) do
         | 
| 236 | 
            +
              #     count = User.count
         | 
| 237 | 
            +
              #     {
         | 
| 238 | 
            +
              #       contents: [{
         | 
| 239 | 
            +
              #         uri: 'db://users/count',
         | 
| 240 | 
            +
              #         mimeType: 'text/plain',
         | 
| 241 | 
            +
              #         text: count.to_s
         | 
| 242 | 
            +
              #       }]
         | 
| 243 | 
            +
              #     }
         | 
| 244 | 
            +
              #   end
         | 
| 245 | 
            +
              def self.create_resource(uri:, name:, description: nil, mime_type: nil, &reader)
         | 
| 246 | 
            +
                raise ArgumentError, 'Block required for resource reader' unless reader
         | 
| 247 | 
            +
             | 
| 248 | 
            +
                SdkMcpResource.new(
         | 
| 249 | 
            +
                  uri: uri,
         | 
| 250 | 
            +
                  name: name,
         | 
| 251 | 
            +
                  description: description,
         | 
| 252 | 
            +
                  mime_type: mime_type,
         | 
| 253 | 
            +
                  reader: reader
         | 
| 254 | 
            +
                )
         | 
| 255 | 
            +
              end
         | 
| 256 | 
            +
             | 
| 257 | 
            +
              # Helper function to create a prompt definition
         | 
| 258 | 
            +
              #
         | 
| 259 | 
            +
              # @param name [String] Unique identifier for the prompt
         | 
| 260 | 
            +
              # @param description [String, nil] Optional description
         | 
| 261 | 
            +
              # @param arguments [Array<Hash>, nil] Optional argument definitions
         | 
| 262 | 
            +
              # @param generator [Proc] Block that generates prompt messages
         | 
| 263 | 
            +
              # @return [SdkMcpPrompt] Prompt definition
         | 
| 264 | 
            +
              #
         | 
| 265 | 
            +
              # @example Simple prompt
         | 
| 266 | 
            +
              #   prompt = create_prompt(
         | 
| 267 | 
            +
              #     name: 'code_review',
         | 
| 268 | 
            +
              #     description: 'Review code for best practices'
         | 
| 269 | 
            +
              #   ) do |args|
         | 
| 270 | 
            +
              #     {
         | 
| 271 | 
            +
              #       messages: [
         | 
| 272 | 
            +
              #         {
         | 
| 273 | 
            +
              #           role: 'user',
         | 
| 274 | 
            +
              #           content: {
         | 
| 275 | 
            +
              #             type: 'text',
         | 
| 276 | 
            +
              #             text: 'Please review this code for best practices and suggest improvements.'
         | 
| 277 | 
            +
              #           }
         | 
| 278 | 
            +
              #         }
         | 
| 279 | 
            +
              #       ]
         | 
| 280 | 
            +
              #     }
         | 
| 281 | 
            +
              #   end
         | 
| 282 | 
            +
              #
         | 
| 283 | 
            +
              # @example Prompt with arguments
         | 
| 284 | 
            +
              #   prompt = create_prompt(
         | 
| 285 | 
            +
              #     name: 'git_commit',
         | 
| 286 | 
            +
              #     description: 'Generate a git commit message',
         | 
| 287 | 
            +
              #     arguments: [
         | 
| 288 | 
            +
              #       { name: 'changes', description: 'Description of changes', required: true }
         | 
| 289 | 
            +
              #     ]
         | 
| 290 | 
            +
              #   ) do |args|
         | 
| 291 | 
            +
              #     {
         | 
| 292 | 
            +
              #       messages: [
         | 
| 293 | 
            +
              #         {
         | 
| 294 | 
            +
              #           role: 'user',
         | 
| 295 | 
            +
              #           content: {
         | 
| 296 | 
            +
              #             type: 'text',
         | 
| 297 | 
            +
              #             text: "Generate a concise git commit message for: #{args[:changes]}"
         | 
| 298 | 
            +
              #           }
         | 
| 299 | 
            +
              #         }
         | 
| 300 | 
            +
              #       ]
         | 
| 301 | 
            +
              #     }
         | 
| 302 | 
            +
              #   end
         | 
| 303 | 
            +
              def self.create_prompt(name:, description: nil, arguments: nil, &generator)
         | 
| 304 | 
            +
                raise ArgumentError, 'Block required for prompt generator' unless generator
         | 
| 305 | 
            +
             | 
| 306 | 
            +
                SdkMcpPrompt.new(
         | 
| 307 | 
            +
                  name: name,
         | 
| 308 | 
            +
                  description: description,
         | 
| 309 | 
            +
                  arguments: arguments,
         | 
| 310 | 
            +
                  generator: generator
         | 
| 311 | 
            +
                )
         | 
| 312 | 
            +
              end
         | 
| 313 | 
            +
             | 
| 133 314 | 
             
              # Create an SDK MCP server
         | 
| 134 315 | 
             
              #
         | 
| 135 316 | 
             
              # @param name [String] Unique identifier for the server
         | 
| 136 317 | 
             
              # @param version [String] Server version (default: '1.0.0')
         | 
| 137 318 | 
             
              # @param tools [Array<SdkMcpTool>] List of tool definitions
         | 
| 319 | 
            +
              # @param resources [Array<SdkMcpResource>] List of resource definitions
         | 
| 320 | 
            +
              # @param prompts [Array<SdkMcpPrompt>] List of prompt definitions
         | 
| 138 321 | 
             
              # @return [Hash] MCP server configuration for ClaudeAgentOptions
         | 
| 139 322 | 
             
              #
         | 
| 140 323 | 
             
              # @example Simple calculator server
         | 
| @@ -152,8 +335,31 @@ module ClaudeAgentSDK | |
| 152 335 | 
             
              #     mcp_servers: { calc: calculator },
         | 
| 153 336 | 
             
              #     allowed_tools: ['mcp__calc__add']
         | 
| 154 337 | 
             
              #   )
         | 
| 155 | 
            -
               | 
| 156 | 
            -
             | 
| 338 | 
            +
              #
         | 
| 339 | 
            +
              # @example Server with resources and prompts
         | 
| 340 | 
            +
              #   config_resource = ClaudeAgentSDK.create_resource(
         | 
| 341 | 
            +
              #     uri: 'config://app',
         | 
| 342 | 
            +
              #     name: 'App Config'
         | 
| 343 | 
            +
              #   ) { { contents: [{ uri: 'config://app', text: 'config data' }] } }
         | 
| 344 | 
            +
              #
         | 
| 345 | 
            +
              #   review_prompt = ClaudeAgentSDK.create_prompt(
         | 
| 346 | 
            +
              #     name: 'review',
         | 
| 347 | 
            +
              #     description: 'Code review'
         | 
| 348 | 
            +
              #   ) { { messages: [{ role: 'user', content: { type: 'text', text: 'Review this' } }] } }
         | 
| 349 | 
            +
              #
         | 
| 350 | 
            +
              #   server = ClaudeAgentSDK.create_sdk_mcp_server(
         | 
| 351 | 
            +
              #     name: 'dev-tools',
         | 
| 352 | 
            +
              #     resources: [config_resource],
         | 
| 353 | 
            +
              #     prompts: [review_prompt]
         | 
| 354 | 
            +
              #   )
         | 
| 355 | 
            +
              def self.create_sdk_mcp_server(name:, version: '1.0.0', tools: [], resources: [], prompts: [])
         | 
| 356 | 
            +
                server = SdkMcpServer.new(
         | 
| 357 | 
            +
                  name: name,
         | 
| 358 | 
            +
                  version: version,
         | 
| 359 | 
            +
                  tools: tools,
         | 
| 360 | 
            +
                  resources: resources,
         | 
| 361 | 
            +
                  prompts: prompts
         | 
| 362 | 
            +
                )
         | 
| 157 363 |  | 
| 158 364 | 
             
                # Return configuration for ClaudeAgentOptions
         | 
| 159 365 | 
             
                {
         | 
| @@ -0,0 +1,73 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'json'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module ClaudeAgentSDK
         | 
| 6 | 
            +
              # Streaming input helpers for Claude Agent SDK
         | 
| 7 | 
            +
              module Streaming
         | 
| 8 | 
            +
                # Create a user message for streaming input
         | 
| 9 | 
            +
                #
         | 
| 10 | 
            +
                # @param content [String] The message content
         | 
| 11 | 
            +
                # @param session_id [String] Session identifier
         | 
| 12 | 
            +
                # @param parent_tool_use_id [String, nil] Parent tool use ID if responding to a tool
         | 
| 13 | 
            +
                # @return [String] JSON-encoded message
         | 
| 14 | 
            +
                def self.user_message(content, session_id: 'default', parent_tool_use_id: nil)
         | 
| 15 | 
            +
                  message = {
         | 
| 16 | 
            +
                    type: 'user',
         | 
| 17 | 
            +
                    message: {
         | 
| 18 | 
            +
                      role: 'user',
         | 
| 19 | 
            +
                      content: content
         | 
| 20 | 
            +
                    },
         | 
| 21 | 
            +
                    parent_tool_use_id: parent_tool_use_id,
         | 
| 22 | 
            +
                    session_id: session_id
         | 
| 23 | 
            +
                  }
         | 
| 24 | 
            +
                  JSON.generate(message) + "\n"
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                # Create an Enumerator from an array of messages
         | 
| 28 | 
            +
                #
         | 
| 29 | 
            +
                # @param messages [Array<String>] Array of message strings
         | 
| 30 | 
            +
                # @param session_id [String] Session identifier
         | 
| 31 | 
            +
                # @return [Enumerator] Enumerator yielding JSON-encoded messages
         | 
| 32 | 
            +
                #
         | 
| 33 | 
            +
                # @example
         | 
| 34 | 
            +
                #   messages = ['Hello', 'What is 2+2?', 'Thanks!']
         | 
| 35 | 
            +
                #   stream = ClaudeAgentSDK::Streaming.from_array(messages)
         | 
| 36 | 
            +
                def self.from_array(messages, session_id: 'default')
         | 
| 37 | 
            +
                  Enumerator.new do |yielder|
         | 
| 38 | 
            +
                    messages.each do |content|
         | 
| 39 | 
            +
                      yielder << user_message(content, session_id: session_id)
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                # Create an Enumerator from a block
         | 
| 45 | 
            +
                #
         | 
| 46 | 
            +
                # @yield Block that yields message strings
         | 
| 47 | 
            +
                # @param session_id [String] Session identifier
         | 
| 48 | 
            +
                # @return [Enumerator] Enumerator yielding JSON-encoded messages
         | 
| 49 | 
            +
                #
         | 
| 50 | 
            +
                # @example
         | 
| 51 | 
            +
                #   stream = ClaudeAgentSDK::Streaming.from_block do |yielder|
         | 
| 52 | 
            +
                #     yielder.yield('First message')
         | 
| 53 | 
            +
                #     sleep 1
         | 
| 54 | 
            +
                #     yielder.yield('Second message')
         | 
| 55 | 
            +
                #   end
         | 
| 56 | 
            +
                def self.from_block(session_id: 'default', &block)
         | 
| 57 | 
            +
                  Enumerator.new do |yielder|
         | 
| 58 | 
            +
                    collector = Object.new
         | 
| 59 | 
            +
                    def collector.yield(content)
         | 
| 60 | 
            +
                      @content = content
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                    def collector.content
         | 
| 63 | 
            +
                      @content
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    inner_enum = Enumerator.new(&block)
         | 
| 67 | 
            +
                    inner_enum.each do |content|
         | 
| 68 | 
            +
                      yielder << user_message(content, session_id: session_id)
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
            end
         | 
| @@ -162,23 +162,14 @@ module ClaudeAgentSDK | |
| 162 162 | 
             
                  should_pipe_stderr = @options.stderr || @options.extra_args.key?('debug-to-stderr')
         | 
| 163 163 |  | 
| 164 164 | 
             
                  begin
         | 
| 165 | 
            -
                    # Start process
         | 
| 166 | 
            -
                     | 
| 167 | 
            -
                      *cmd,
         | 
| 168 | 
            -
                      stdin: :pipe,
         | 
| 169 | 
            -
                      stdout: :pipe,
         | 
| 170 | 
            -
                      stderr: should_pipe_stderr ? :pipe : nil,
         | 
| 171 | 
            -
                      chdir: @cwd&.to_s,
         | 
| 172 | 
            -
                      env: process_env
         | 
| 173 | 
            -
                    )
         | 
| 165 | 
            +
                    # Start process using Open3
         | 
| 166 | 
            +
                    opts = { chdir: @cwd&.to_s }.compact
         | 
| 174 167 |  | 
| 175 | 
            -
                    @stdout  | 
| 176 | 
            -
                    @stdin = @process.stdin if @is_streaming
         | 
| 168 | 
            +
                    @stdin, @stdout, @stderr, @process = Open3.popen3(process_env, *cmd, opts)
         | 
| 177 169 |  | 
| 178 170 | 
             
                    # Handle stderr if piped
         | 
| 179 | 
            -
                    if should_pipe_stderr && @ | 
| 180 | 
            -
                      @ | 
| 181 | 
            -
                      @stderr_task = Async do
         | 
| 171 | 
            +
                    if should_pipe_stderr && @stderr
         | 
| 172 | 
            +
                      @stderr_task = Thread.new do
         | 
| 182 173 | 
             
                        handle_stderr
         | 
| 183 174 | 
             
                      rescue StandardError
         | 
| 184 175 | 
             
                        # Ignore errors during stderr reading
         | 
| @@ -186,7 +177,8 @@ module ClaudeAgentSDK | |
| 186 177 | 
             
                    end
         | 
| 187 178 |  | 
| 188 179 | 
             
                    # Close stdin for non-streaming mode
         | 
| 189 | 
            -
                    @ | 
| 180 | 
            +
                    @stdin.close unless @is_streaming
         | 
| 181 | 
            +
                    @stdin = nil unless @is_streaming
         | 
| 190 182 |  | 
| 191 183 | 
             
                    @ready = true
         | 
| 192 184 | 
             
                  rescue Errno::ENOENT => e
         | 
| @@ -223,8 +215,11 @@ module ClaudeAgentSDK | |
| 223 215 | 
             
                  @ready = false
         | 
| 224 216 | 
             
                  return unless @process
         | 
| 225 217 |  | 
| 226 | 
            -
                  #  | 
| 227 | 
            -
                  @stderr_task&. | 
| 218 | 
            +
                  # Kill stderr thread
         | 
| 219 | 
            +
                  if @stderr_task&.alive?
         | 
| 220 | 
            +
                    @stderr_task.kill
         | 
| 221 | 
            +
                    @stderr_task.join(1) rescue nil
         | 
| 222 | 
            +
                  end
         | 
| 228 223 |  | 
| 229 224 | 
             
                  # Close streams
         | 
| 230 225 | 
             
                  begin
         | 
| @@ -232,6 +227,11 @@ module ClaudeAgentSDK | |
| 232 227 | 
             
                  rescue StandardError
         | 
| 233 228 | 
             
                    # Ignore
         | 
| 234 229 | 
             
                  end
         | 
| 230 | 
            +
                  begin
         | 
| 231 | 
            +
                    @stdout&.close
         | 
| 232 | 
            +
                  rescue StandardError
         | 
| 233 | 
            +
                    # Ignore
         | 
| 234 | 
            +
                  end
         | 
| 235 235 | 
             
                  begin
         | 
| 236 236 | 
             
                    @stderr&.close
         | 
| 237 237 | 
             
                  rescue StandardError
         | 
| @@ -240,8 +240,8 @@ module ClaudeAgentSDK | |
| 240 240 |  | 
| 241 241 | 
             
                  # Terminate process
         | 
| 242 242 | 
             
                  begin
         | 
| 243 | 
            -
                    @process. | 
| 244 | 
            -
                    @process. | 
| 243 | 
            +
                    Process.kill('TERM', @process.pid) if @process.alive?
         | 
| 244 | 
            +
                    @process.value
         | 
| 245 245 | 
             
                  rescue StandardError
         | 
| 246 246 | 
             
                    # Ignore
         | 
| 247 247 | 
             
                  end
         | 
| @@ -250,12 +250,13 @@ module ClaudeAgentSDK | |
| 250 250 | 
             
                  @stdout = nil
         | 
| 251 251 | 
             
                  @stdin = nil
         | 
| 252 252 | 
             
                  @stderr = nil
         | 
| 253 | 
            +
                  @stderr_task = nil
         | 
| 253 254 | 
             
                  @exit_error = nil
         | 
| 254 255 | 
             
                end
         | 
| 255 256 |  | 
| 256 257 | 
             
                def write(data)
         | 
| 257 258 | 
             
                  raise CLIConnectionError, 'ProcessTransport is not ready for writing' unless @ready && @stdin
         | 
| 258 | 
            -
                  raise CLIConnectionError, "Cannot write to terminated process" if @process &&  | 
| 259 | 
            +
                  raise CLIConnectionError, "Cannot write to terminated process" if @process && !@process.alive?
         | 
| 259 260 |  | 
| 260 261 | 
             
                  raise CLIConnectionError, "Cannot write to process that exited with error: #{@exit_error}" if @exit_error
         | 
| 261 262 |  | 
| @@ -326,7 +327,7 @@ module ClaudeAgentSDK | |
| 326 327 | 
             
                  end
         | 
| 327 328 |  | 
| 328 329 | 
             
                  # Check process completion
         | 
| 329 | 
            -
                  status = @process. | 
| 330 | 
            +
                  status = @process.value
         | 
| 330 331 | 
             
                  returncode = status.exitstatus
         | 
| 331 332 |  | 
| 332 333 | 
             
                  if returncode && returncode != 0
         | 
| @@ -355,4 +355,29 @@ module ClaudeAgentSDK | |
| 355 355 | 
             
                  @handler = handler
         | 
| 356 356 | 
             
                end
         | 
| 357 357 | 
             
              end
         | 
| 358 | 
            +
             | 
| 359 | 
            +
              # SDK MCP Resource definition
         | 
| 360 | 
            +
              class SdkMcpResource
         | 
| 361 | 
            +
                attr_accessor :uri, :name, :description, :mime_type, :reader
         | 
| 362 | 
            +
             | 
| 363 | 
            +
                def initialize(uri:, name:, description: nil, mime_type: nil, reader:)
         | 
| 364 | 
            +
                  @uri = uri
         | 
| 365 | 
            +
                  @name = name
         | 
| 366 | 
            +
                  @description = description
         | 
| 367 | 
            +
                  @mime_type = mime_type
         | 
| 368 | 
            +
                  @reader = reader
         | 
| 369 | 
            +
                end
         | 
| 370 | 
            +
              end
         | 
| 371 | 
            +
             | 
| 372 | 
            +
              # SDK MCP Prompt definition
         | 
| 373 | 
            +
              class SdkMcpPrompt
         | 
| 374 | 
            +
                attr_accessor :name, :description, :arguments, :generator
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                def initialize(name:, description: nil, arguments: nil, generator:)
         | 
| 377 | 
            +
                  @name = name
         | 
| 378 | 
            +
                  @description = description
         | 
| 379 | 
            +
                  @arguments = arguments
         | 
| 380 | 
            +
                  @generator = generator
         | 
| 381 | 
            +
                end
         | 
| 382 | 
            +
              end
         | 
| 358 383 | 
             
            end
         | 
    
        data/lib/claude_agent_sdk.rb
    CHANGED
    
    | @@ -8,6 +8,7 @@ require_relative 'claude_agent_sdk/subprocess_cli_transport' | |
| 8 8 | 
             
            require_relative 'claude_agent_sdk/message_parser'
         | 
| 9 9 | 
             
            require_relative 'claude_agent_sdk/query'
         | 
| 10 10 | 
             
            require_relative 'claude_agent_sdk/sdk_mcp_server'
         | 
| 11 | 
            +
            require_relative 'claude_agent_sdk/streaming'
         | 
| 11 12 | 
             
            require 'async'
         | 
| 12 13 | 
             
            require 'securerandom'
         | 
| 13 14 |  | 
| @@ -18,7 +19,7 @@ module ClaudeAgentSDK | |
| 18 19 | 
             
              # This function is ideal for simple, stateless queries where you don't need
         | 
| 19 20 | 
             
              # bidirectional communication or conversation management.
         | 
| 20 21 | 
             
              #
         | 
| 21 | 
            -
              # @param prompt [String] The prompt to send to Claude
         | 
| 22 | 
            +
              # @param prompt [String, Enumerator] The prompt to send to Claude, or an Enumerator for streaming input
         | 
| 22 23 | 
             
              # @param options [ClaudeAgentOptions] Optional configuration
         | 
| 23 24 | 
             
              # @yield [Message] Each message from the conversation
         | 
| 24 25 | 
             
              # @return [Enumerator] if no block given
         | 
| @@ -40,6 +41,12 @@ module ClaudeAgentSDK | |
| 40 41 | 
             
              #       end
         | 
| 41 42 | 
             
              #     end
         | 
| 42 43 | 
             
              #   end
         | 
| 44 | 
            +
              #
         | 
| 45 | 
            +
              # @example Streaming input
         | 
| 46 | 
            +
              #   messages = Streaming.from_array(['Hello', 'What is 2+2?', 'Thanks!'])
         | 
| 47 | 
            +
              #   ClaudeAgentSDK.query(prompt: messages) do |message|
         | 
| 48 | 
            +
              #     puts message
         | 
| 49 | 
            +
              #   end
         | 
| 43 50 | 
             
              def self.query(prompt:, options: nil, &block)
         | 
| 44 51 | 
             
                return enum_for(:query, prompt: prompt, options: options) unless block
         | 
| 45 52 |  | 
| @@ -50,6 +57,21 @@ module ClaudeAgentSDK | |
| 50 57 | 
             
                  transport = SubprocessCLITransport.new(prompt, options)
         | 
| 51 58 | 
             
                  begin
         | 
| 52 59 | 
             
                    transport.connect
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    # If prompt is an Enumerator, write each message to stdin
         | 
| 62 | 
            +
                    if prompt.is_a?(Enumerator) || prompt.respond_to?(:each)
         | 
| 63 | 
            +
                      Async do
         | 
| 64 | 
            +
                        begin
         | 
| 65 | 
            +
                          prompt.each do |message_json|
         | 
| 66 | 
            +
                            transport.write(message_json)
         | 
| 67 | 
            +
                          end
         | 
| 68 | 
            +
                        ensure
         | 
| 69 | 
            +
                          transport.end_input
         | 
| 70 | 
            +
                        end
         | 
| 71 | 
            +
                      end
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    # Read and yield messages
         | 
| 53 75 | 
             
                    transport.read_messages do |data|
         | 
| 54 76 | 
             
                      message = MessageParser.parse(data)
         | 
| 55 77 | 
             
                      block.call(message)
         | 
    
        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.1. | 
| 4 | 
            +
              version: 0.1.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Community Contributors
         | 
| 8 8 | 
             
            bindir: bin
         | 
| 9 9 | 
             
            cert_chain: []
         | 
| 10 | 
            -
            date: 2025-10- | 
| 10 | 
            +
            date: 2025-10-15 00:00:00.000000000 Z
         | 
| 11 11 | 
             
            dependencies:
         | 
| 12 12 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 13 13 | 
             
              name: async
         | 
| @@ -94,6 +94,7 @@ files: | |
| 94 94 | 
             
            - lib/claude_agent_sdk/message_parser.rb
         | 
| 95 95 | 
             
            - lib/claude_agent_sdk/query.rb
         | 
| 96 96 | 
             
            - lib/claude_agent_sdk/sdk_mcp_server.rb
         | 
| 97 | 
            +
            - lib/claude_agent_sdk/streaming.rb
         | 
| 97 98 | 
             
            - lib/claude_agent_sdk/subprocess_cli_transport.rb
         | 
| 98 99 | 
             
            - lib/claude_agent_sdk/transport.rb
         | 
| 99 100 | 
             
            - lib/claude_agent_sdk/types.rb
         |