Class: ClaudeAgentSDK::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/claude_agent_sdk.rb

Overview

Client for bidirectional, interactive conversations with Claude Code

This client provides full control over the conversation flow with support for streaming, hooks, permission callbacks, and dynamic message sending. The Client class always uses streaming mode for bidirectional communication.

Examples:

Basic usage

Async do
  client = ClaudeAgentSDK::Client.new
  client.connect  # No arguments needed - automatically uses streaming mode

  client.query("What is the capital of France?")
  client.receive_response do |msg|
    puts msg if msg.is_a?(ClaudeAgentSDK::AssistantMessage)
  end

  client.disconnect
end

With hooks

options = ClaudeAgentOptions.new(
  hooks: {
    'PreToolUse' => [
      HookMatcher.new(
        matcher: 'Bash',
        hooks: [
          ->(input, tool_use_id, context) {
            # Return hook output
            {}
          }
        ]
      )
    ]
  }
)
client = ClaudeAgentSDK::Client.new(options: options)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options: nil) ⇒ Client

Returns a new instance of Client.



135
136
137
138
139
140
# File 'lib/claude_agent_sdk.rb', line 135

def initialize(options: nil)
  @options = options || ClaudeAgentOptions.new
  @transport = nil
  @query_handler = nil
  @connected = false
end

Instance Attribute Details

#query_handlerObject (readonly)

Returns the value of attribute query_handler.



133
134
135
# File 'lib/claude_agent_sdk.rb', line 133

def query_handler
  @query_handler
end

Instance Method Details

#connect(prompt = nil) ⇒ Object

Connect to Claude with optional initial prompt.

Client always uses streaming mode for bidirectional communication. If you pass a String, it will be sent as an initial user message after the connection is established. If you pass an Enumerator, it should yield JSONL messages (e.g., from ClaudeAgentSDK::Streaming.user_message).

Parameters:

  • prompt (String, Enumerator, nil) (defaults to: nil)

    Initial prompt or message stream

Raises:

  • (ArgumentError)


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/claude_agent_sdk.rb', line 150

def connect(prompt = nil)
  return if @connected

  raise ArgumentError, "prompt must be a String, an Enumerator, or nil (got #{prompt.class})" unless prompt.nil? || prompt.is_a?(String) || prompt.respond_to?(:each)

  # Validate and configure permission settings
  configured_options = @options
  if @options.can_use_tool
    # can_use_tool and permission_prompt_tool_name are mutually exclusive
    raise ArgumentError, 'can_use_tool callback cannot be used with permission_prompt_tool_name' if @options.permission_prompt_tool_name

    # Set permission_prompt_tool_name to stdio for control protocol
    configured_options = @options.dup_with(permission_prompt_tool_name: 'stdio')
  end

  configured_options = configured_options.dup_with(
    env: (configured_options.env || {}).merge('CLAUDE_CODE_ENTRYPOINT' => 'sdk-rb-client')
  )

  # Client always uses streaming mode; keep stdin open for bidirectional communication.
  @transport = SubprocessCLITransport.new([].to_enum, configured_options)
  @transport.connect

  # Extract SDK MCP servers
  sdk_mcp_servers = {}
  if configured_options.mcp_servers.is_a?(Hash)
    configured_options.mcp_servers.each do |name, config|
      sdk_mcp_servers[name] = config[:instance] if config.is_a?(Hash) && config[:type] == 'sdk'
    end
  end

  # Convert hooks to internal format
  hooks = convert_hooks_to_internal_format(configured_options.hooks) if configured_options.hooks

  # Create Query handler
  @query_handler = Query.new(
    transport: @transport,
    is_streaming_mode: true,
    can_use_tool: configured_options.can_use_tool,
    hooks: hooks,
    sdk_mcp_servers: sdk_mcp_servers
  )

  # Start query handler and initialize
  @query_handler.start
  @query_handler.initialize_protocol

  @connected = true

  # Optionally send initial prompt/messages after connection is ready.
  case prompt
  when nil
    nil
  when String
    query(prompt)
  else
    prompt.each do |message_json|
      message_json = message_json.to_s
      message_json += "\n" unless message_json.end_with?("\n")
      @transport.write(message_json)
    end
  end
end

#disconnectObject

Disconnect from Claude



303
304
305
306
307
308
309
310
# File 'lib/claude_agent_sdk.rb', line 303

def disconnect
  return unless @connected

  @query_handler&.close
  @query_handler = nil
  @transport = nil
  @connected = false
end

#get_mcp_statusHash

Get current MCP server connection status (only works with streaming mode)

Returns:

  • (Hash)

    MCP status information, including mcpServers list

Raises:



290
291
292
293
# File 'lib/claude_agent_sdk.rb', line 290

def get_mcp_status
  raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected
  @query_handler.get_mcp_status
end

#get_server_infoHash

Get server initialization info including available commands and output styles

Returns:

  • (Hash)

    Server info

Raises:



297
298
299
300
# File 'lib/claude_agent_sdk.rb', line 297

def get_server_info
  raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected
  server_info
end

#interruptObject

Send interrupt signal

Raises:



254
255
256
257
# File 'lib/claude_agent_sdk.rb', line 254

def interrupt
  raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected
  @query_handler.interrupt
end

#query(prompt, session_id: 'default') ⇒ Object

Send a query to Claude

Parameters:

  • prompt (String)

    The prompt to send

  • session_id (String) (defaults to: 'default')

    Session identifier

Raises:



217
218
219
220
221
222
223
224
225
226
227
# File 'lib/claude_agent_sdk.rb', line 217

def query(prompt, session_id: 'default')
  raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected

  message = {
    type: 'user',
    message: { role: 'user', content: prompt },
    parent_tool_use_id: nil,
    session_id: session_id
  }
  @transport.write(JSON.generate(message) + "\n")
end

#receive_messages {|Message| ... } ⇒ Object

Receive all messages from Claude

Yields:

  • (Message)

    Each message received

Raises:



231
232
233
234
235
236
237
238
239
240
# File 'lib/claude_agent_sdk.rb', line 231

def receive_messages(&block)
  return enum_for(:receive_messages) unless block

  raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected

  @query_handler.receive_messages do |data|
    message = MessageParser.parse(data)
    block.call(message)
  end
end

#receive_response {|Message| ... } ⇒ Object

Receive messages until a ResultMessage is received

Yields:

  • (Message)

    Each message received



244
245
246
247
248
249
250
251
# File 'lib/claude_agent_sdk.rb', line 244

def receive_response(&block)
  return enum_for(:receive_response) unless block

  receive_messages do |message|
    block.call(message)
    break if message.is_a?(ResultMessage)
  end
end

#rewind_files(user_message_uuid) ⇒ Object

Rewind files to a previous checkpoint (v0.1.15+) Restores file state to what it was at the given user message Requires enable_file_checkpointing to be true in options

Parameters:

  • user_message_uuid (String)

    The UUID of the UserMessage to rewind to

Raises:



277
278
279
280
# File 'lib/claude_agent_sdk.rb', line 277

def rewind_files(user_message_uuid)
  raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected
  @query_handler.rewind_files(user_message_uuid)
end

#server_infoHash?

Get server initialization info

Returns:

  • (Hash, nil)

    Server info or nil



284
285
286
# File 'lib/claude_agent_sdk.rb', line 284

def server_info
  @query_handler&.instance_variable_get(:@initialization_result)
end

#set_model(model) ⇒ Object

Change the AI model during conversation

Parameters:

  • model (String, nil)

    Model name or nil for default

Raises:



268
269
270
271
# File 'lib/claude_agent_sdk.rb', line 268

def set_model(model)
  raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected
  @query_handler.set_model(model)
end

#set_permission_mode(mode) ⇒ Object

Change permission mode during conversation

Parameters:

  • mode (String)

    Permission mode (‘default’, ‘acceptEdits’, ‘bypassPermissions’)

Raises:



261
262
263
264
# File 'lib/claude_agent_sdk.rb', line 261

def set_permission_mode(mode)
  raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected
  @query_handler.set_permission_mode(mode)
end