Class: ClaudeAgentSDK::Client
- Inherits:
-
Object
- Object
- ClaudeAgentSDK::Client
- 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.
Instance Attribute Summary collapse
-
#query_handler ⇒ Object
readonly
Returns the value of attribute query_handler.
Instance Method Summary collapse
-
#connect(prompt = nil) ⇒ Object
Connect to Claude with optional initial prompt.
-
#disconnect ⇒ Object
Disconnect from Claude.
-
#get_context_usage ⇒ Hash
Get a breakdown of current context window usage by category.
-
#get_mcp_status ⇒ Hash
Get current MCP server connection status (only works with streaming mode).
-
#get_server_info ⇒ Hash
Get server initialization info including available commands and output styles.
-
#initialize(options: nil, transport_class: SubprocessCLITransport, transport_args: {}) ⇒ Client
constructor
A new instance of Client.
-
#interrupt ⇒ Object
Send interrupt signal.
-
#query(prompt, session_id: 'default') ⇒ Object
Send a query to Claude.
-
#receive_messages {|Message| ... } ⇒ Object
Receive all messages from Claude.
-
#receive_response {|Message| ... } ⇒ Object
Receive messages until a ResultMessage is received.
-
#reconnect_mcp_server(server_name) ⇒ Object
Reconnect a failed MCP server.
-
#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.
-
#server_info ⇒ Hash?
Get server initialization info.
-
#set_model(model) ⇒ Object
Change the AI model during conversation.
-
#set_permission_mode(mode) ⇒ Object
Change permission mode during conversation.
-
#stop_task(task_id) ⇒ Object
Stop a running background task.
-
#toggle_mcp_server(server_name, enabled) ⇒ Object
Enable or disable an MCP server.
Constructor Details
#initialize(options: nil, transport_class: SubprocessCLITransport, transport_args: {}) ⇒ Client
Returns a new instance of Client.
439 440 441 442 443 444 445 446 447 |
# File 'lib/claude_agent_sdk.rb', line 439 def initialize(options: nil, transport_class: SubprocessCLITransport, transport_args: {}) @options = || ClaudeAgentOptions.new @transport_class = transport_class @transport_args = transport_args @transport = nil @query_handler = nil @connected = false @materialized = nil end |
Instance Attribute Details
#query_handler ⇒ Object (readonly)
Returns the value of attribute query_handler.
433 434 435 |
# File 'lib/claude_agent_sdk.rb', line 433 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).
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
# File 'lib/claude_agent_sdk.rb', line 457 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 = @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. # Set permission_prompt_tool_name to stdio for control protocol = @options.dup_with(permission_prompt_tool_name: 'stdio') end # Fail fast on invalid session_store combinations before spawning the CLI. SessionStores.() # Resume-from-store: materialize the session from the store into a temp # CLAUDE_CONFIG_DIR BEFORE spawn, then repoint options at it. Skipped for # custom transports (the materialized env/--resume only apply to the CLI # subprocess). On any later connect failure, disconnect cleans up the dir. = materialize_resume() # If anything after materialization fails, tear down (closes the # subprocess and removes the materialized temp config dir) before # surfacing the error, so a partial connect never leaks a temp dir # holding a credential copy. begin connect_inner(, prompt) rescue Exception # rubocop:disable Lint/RescueException # Tear down the partial connect, but never let a cleanup failure (e.g. a # custom transport whose #close raises) mask the original connect error. # Rescue Exception (not StandardError) so reactor cancellation # (Async::Stop < Exception) after materialize_resume set @materialized # still runs disconnect -> @materialized.cleanup, never leaking the temp # CLAUDE_CONFIG_DIR that holds the redacted .credentials.json copy. begin disconnect rescue StandardError => e warn "Claude SDK: cleanup after failed connect raised: #{e.}" end raise end end |
#disconnect ⇒ Object
Disconnect from Claude
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 |
# File 'lib/claude_agent_sdk.rb', line 636 def disconnect ClaudeAgentSDK.notify_observers(@resolved_observers || [], :on_close) if @connected # Tear down whatever exists — robust to a partial/failed connect, where # @connected is still false but a transport and/or materialized temp dir # were already created. #close on the query handler also closes the # transport (flushing the mirror batcher first); the extra @transport # close covers a failure before the query handler was built (idempotent). # # The nested ensures guarantee that even a raising close (e.g. a custom # transport whose #close raises) still runs the transport close, resets # state, and removes the materialized temp dir (which holds a redacted # .credentials.json copy) — so disconnect can never leave the client # half-open or leak the temp dir. The original error still propagates. begin @query_handler&.close ensure @query_handler = nil begin @transport&.close ensure @transport = nil @connected = false # Remove the materialized resume temp dir AFTER the subprocess exited. if @materialized @materialized.cleanup @materialized = nil end end end end |
#get_context_usage ⇒ Hash
Get a breakdown of current context window usage by category. Returns token counts per category (system prompt, tools, messages, etc.), total/max tokens, model info, MCP tools, memory files, and more.
616 617 618 619 |
# File 'lib/claude_agent_sdk.rb', line 616 def get_context_usage raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected @query_handler.get_context_usage end |
#get_mcp_status ⇒ Hash
Get current MCP server connection status (only works with streaming mode)
623 624 625 626 |
# File 'lib/claude_agent_sdk.rb', line 623 def get_mcp_status raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected @query_handler.get_mcp_status end |
#get_server_info ⇒ Hash
Get server initialization info including available commands and output styles
630 631 632 633 |
# File 'lib/claude_agent_sdk.rb', line 630 def get_server_info raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected server_info end |
#interrupt ⇒ Object
Send interrupt signal
556 557 558 559 |
# File 'lib/claude_agent_sdk.rb', line 556 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
506 507 508 509 510 511 512 513 514 515 516 517 |
# File 'lib/claude_agent_sdk.rb', line 506 def query(prompt, session_id: 'default') raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected ClaudeAgentSDK.notify_observers(@resolved_observers, :on_user_prompt, prompt) = { type: 'user', message: { role: 'user', content: prompt }, parent_tool_use_id: nil, session_id: session_id } writeln(JSON.generate()) end |
#receive_messages {|Message| ... } ⇒ Object
Receive all messages from Claude
521 522 523 524 525 526 527 528 529 530 531 532 533 |
# File 'lib/claude_agent_sdk.rb', line 521 def (&block) return enum_for(:receive_messages) unless block raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected @query_handler. do |data| = MessageParser.parse(data) if ClaudeAgentSDK.notify_observers(@resolved_observers, :on_message, ) FiberBoundary.invoke { block.call() } end end end |
#receive_response {|Message| ... } ⇒ Object
Receive messages until a ResultMessage is received
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
# File 'lib/claude_agent_sdk.rb', line 537 def receive_response(&block) return enum_for(:receive_response) unless block raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected # Keep `break` on the same fiber as the underlying dequeue. Going through # Client#receive_messages would put the FiberBoundary hop above the break # and hang in Client mode — the CLI keeps stdin open and never emits `:end`. @query_handler. do |data| = MessageParser.parse(data) next unless ClaudeAgentSDK.notify_observers(@resolved_observers, :on_message, ) FiberBoundary.invoke { block.call() } break if .is_a?(ResultMessage) end end |
#reconnect_mcp_server(server_name) ⇒ Object
Reconnect a failed MCP server
577 578 579 580 |
# File 'lib/claude_agent_sdk.rb', line 577 def reconnect_mcp_server(server_name) raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected @query_handler.reconnect_mcp_server(server_name) 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
601 602 603 604 |
# File 'lib/claude_agent_sdk.rb', line 601 def rewind_files() raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected @query_handler.rewind_files() end |
#server_info ⇒ Hash?
Get server initialization info
608 609 610 |
# File 'lib/claude_agent_sdk.rb', line 608 def server_info @query_handler&.instance_variable_get(:@initialization_result) end |
#set_model(model) ⇒ Object
Change the AI model during conversation
570 571 572 573 |
# File 'lib/claude_agent_sdk.rb', line 570 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
563 564 565 566 |
# File 'lib/claude_agent_sdk.rb', line 563 def (mode) raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected @query_handler.(mode) end |
#stop_task(task_id) ⇒ Object
Stop a running background task
592 593 594 595 |
# File 'lib/claude_agent_sdk.rb', line 592 def stop_task(task_id) raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected @query_handler.stop_task(task_id) end |
#toggle_mcp_server(server_name, enabled) ⇒ Object
Enable or disable an MCP server
585 586 587 588 |
# File 'lib/claude_agent_sdk.rb', line 585 def toggle_mcp_server(server_name, enabled) raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected @query_handler.toggle_mcp_server(server_name, enabled) end |