claude_agent 0.7.7 → 0.7.9
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 +65 -0
- data/README.md +551 -37
- data/SPEC.md +70 -30
- data/lib/claude_agent/client.rb +197 -7
- data/lib/claude_agent/content_blocks.rb +193 -5
- data/lib/claude_agent/control_protocol.rb +111 -11
- data/lib/claude_agent/conversation.rb +248 -0
- data/lib/claude_agent/cumulative_usage.rb +106 -0
- data/lib/claude_agent/event_handler.rb +152 -0
- data/lib/claude_agent/hooks.rb +106 -225
- data/lib/claude_agent/list_sessions.rb +508 -0
- data/lib/claude_agent/mcp/server.rb +3 -3
- data/lib/claude_agent/mcp/tool.rb +4 -4
- data/lib/claude_agent/message_parser.rb +201 -185
- data/lib/claude_agent/messages.rb +86 -13
- data/lib/claude_agent/options.rb +5 -4
- data/lib/claude_agent/permission_queue.rb +87 -0
- data/lib/claude_agent/permission_request.rb +151 -0
- data/lib/claude_agent/permissions.rb +4 -2
- data/lib/claude_agent/query.rb +34 -0
- data/lib/claude_agent/tool_activity.rb +78 -0
- data/lib/claude_agent/turn_result.rb +239 -0
- data/lib/claude_agent/types.rb +29 -0
- data/lib/claude_agent/version.rb +1 -1
- data/lib/claude_agent.rb +39 -1
- data/sig/claude_agent.rbs +285 -4
- metadata +9 -1
data/SPEC.md
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
This document provides a comprehensive specification of the Claude Agent SDK, comparing feature parity across the official TypeScript and Python SDKs with this Ruby implementation.
|
|
4
4
|
|
|
5
5
|
**Reference Versions:**
|
|
6
|
-
- TypeScript SDK: v0.2.
|
|
7
|
-
- Python SDK: v0.1.
|
|
6
|
+
- TypeScript SDK: v0.2.56 (npm package)
|
|
7
|
+
- Python SDK: v0.1.43 from GitHub (commit 9d758dd)
|
|
8
8
|
- Ruby SDK: This repository
|
|
9
9
|
|
|
10
|
-
**Last Updated:** 2026-02-
|
|
10
|
+
**Last Updated:** 2026-02-25
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -111,6 +111,7 @@ Messages exchanged between SDK and CLI.
|
|
|
111
111
|
| `TaskNotificationMessage` | ✅ | ❌ | ✅ | Background task completion |
|
|
112
112
|
| `ToolUseSummaryMessage` | ✅ | ❌ | ✅ | Summary of tool use (collapsed) |
|
|
113
113
|
| `TaskStartedMessage` | ✅ | ❌ | ✅ | Subagent task registered (v0.2.45) |
|
|
114
|
+
| `TaskProgressMessage` | ✅ | ❌ | ✅ | Background task progress (v0.2.51) |
|
|
114
115
|
| `RateLimitEvent` | ✅ | ❌ | ✅ | Rate limit status changes |
|
|
115
116
|
| `PromptSuggestionMessage` | ✅ | ❌ | ✅ | Suggested next prompt (v0.2.47) |
|
|
116
117
|
| `FilesPersistedEvent` | ✅ | ❌ | ✅ | File persistence confirmation |
|
|
@@ -232,9 +233,12 @@ Bidirectional control protocol for SDK-CLI communication.
|
|
|
232
233
|
| `mcp_reconnect` | ✅ | ❌ | ✅ | Reconnect to MCP server |
|
|
233
234
|
| `mcp_toggle` | ✅ | ❌ | ✅ | Enable/disable MCP server |
|
|
234
235
|
| `stop_task` | ✅ | ❌ | ✅ | Stop a running background task |
|
|
236
|
+
| `mcp_authenticate` | ✅ | ❌ | ✅ | Authenticate MCP server (v0.2.52) |
|
|
237
|
+
| `mcp_clear_auth` | ✅ | ❌ | ✅ | Clear MCP server auth (v0.2.52) |
|
|
235
238
|
| `supported_commands` | ✅ | ❌ | ✅ | Get available slash commands |
|
|
236
239
|
| `supported_models` | ✅ | ❌ | ✅ | Get available models |
|
|
237
240
|
| `account_info` | ✅ | ❌ | ✅ | Get account information |
|
|
241
|
+
| `apply_flag_settings` | ✅ | ❌ | ✅ | Merge settings into flag layer |
|
|
238
242
|
|
|
239
243
|
### Return Types
|
|
240
244
|
|
|
@@ -274,6 +278,8 @@ Event hooks for intercepting and modifying SDK behavior.
|
|
|
274
278
|
| `TeammateIdle` | ✅ | ❌ | ✅ | Teammate idle (v0.2.33) |
|
|
275
279
|
| `TaskCompleted` | ✅ | ❌ | ✅ | Task completed (v0.2.33) |
|
|
276
280
|
| `ConfigChange` | ✅ | ❌ | ✅ | Config file changed (v0.2.49) |
|
|
281
|
+
| `WorktreeCreate` | ✅ | ❌ | ✅ | Worktree creation (v0.2.50) |
|
|
282
|
+
| `WorktreeRemove` | ✅ | ❌ | ✅ | Worktree removal (v0.2.50) |
|
|
277
283
|
|
|
278
284
|
### Hook Input Types
|
|
279
285
|
|
|
@@ -295,6 +301,8 @@ Event hooks for intercepting and modifying SDK behavior.
|
|
|
295
301
|
| `TeammateIdleHookInput` | ✅ | ❌ | ✅ |
|
|
296
302
|
| `TaskCompletedHookInput` | ✅ | ❌ | ✅ |
|
|
297
303
|
| `ConfigChangeHookInput` | ✅ | ❌ | ✅ |
|
|
304
|
+
| `WorktreeCreateHookInput` | ✅ | ❌ | ✅ |
|
|
305
|
+
| `WorktreeRemoveHookInput` | ✅ | ❌ | ✅ |
|
|
298
306
|
|
|
299
307
|
### Hook Output Types
|
|
300
308
|
|
|
@@ -514,6 +522,25 @@ Session management and resumption.
|
|
|
514
522
|
| Persist session | ✅ | ❌ | ✅ | `persistSession` option |
|
|
515
523
|
| Continue most recent | ✅ | ✅ | ✅ | `continue` option |
|
|
516
524
|
|
|
525
|
+
### Session Discovery
|
|
526
|
+
|
|
527
|
+
| Feature | TypeScript | Python | Ruby | Notes |
|
|
528
|
+
|------------------|:----------:|:------:|:----:|--------------------------------------------|
|
|
529
|
+
| `listSessions()` | ✅ | ❌ | ✅ | List past sessions with metadata (v0.2.53) |
|
|
530
|
+
|
|
531
|
+
#### SDKSessionInfo Fields
|
|
532
|
+
|
|
533
|
+
| Field | TypeScript | Python | Ruby | Notes |
|
|
534
|
+
|----------------|:----------:|:------:|:----:|-------------------------------------|
|
|
535
|
+
| `sessionId` | ✅ | ❌ | ✅ | Session UUID |
|
|
536
|
+
| `summary` | ✅ | ❌ | ✅ | Display title/summary |
|
|
537
|
+
| `lastModified` | ✅ | ❌ | ✅ | Last modified time (ms since epoch) |
|
|
538
|
+
| `fileSize` | ✅ | ❌ | ✅ | Session file size in bytes |
|
|
539
|
+
| `customTitle` | ✅ | ❌ | ✅ | User-set title via /rename |
|
|
540
|
+
| `firstPrompt` | ✅ | ❌ | ✅ | First meaningful user prompt |
|
|
541
|
+
| `gitBranch` | ✅ | ❌ | ✅ | Git branch at end of session |
|
|
542
|
+
| `cwd` | ✅ | ❌ | ✅ | Working directory for session |
|
|
543
|
+
|
|
517
544
|
### V2 Session API (Unstable)
|
|
518
545
|
|
|
519
546
|
| Feature | TypeScript | Python | Ruby | Notes |
|
|
@@ -593,11 +620,11 @@ Error types and hierarchy.
|
|
|
593
620
|
|----------------------|:----------:|:------:|:----:|--------------------------------|
|
|
594
621
|
| Base Error | ✅ | ✅ | ✅ | `Error` / `ClaudeAgent::Error` |
|
|
595
622
|
| `AbortError` | ✅ | ❌ | ✅ | Operation cancelled |
|
|
596
|
-
| `CLINotFoundError` | ❌ |
|
|
623
|
+
| `CLINotFoundError` | ❌ | ✅ | ✅ | CLI not found |
|
|
597
624
|
| `CLIVersionError` | ❌ | ❌ | ✅ | CLI version too old |
|
|
598
|
-
| `CLIConnectionError` | ❌ |
|
|
599
|
-
| `ProcessError` | ❌ |
|
|
600
|
-
| `JSONDecodeError` | ❌ |
|
|
625
|
+
| `CLIConnectionError` | ❌ | ✅ | ✅ | Connection failed |
|
|
626
|
+
| `ProcessError` | ❌ | ✅ | ✅ | CLI process failed |
|
|
627
|
+
| `JSONDecodeError` | ❌ | ✅ | ✅ | JSON parsing failed |
|
|
601
628
|
| `MessageParseError` | ❌ | ❌ | ✅ | Message parsing failed |
|
|
602
629
|
| `TimeoutError` | ❌ | ❌ | ✅ | Control request timeout |
|
|
603
630
|
| `ConfigurationError` | ❌ | ❌ | ✅ | Invalid configuration |
|
|
@@ -620,6 +647,12 @@ Error types and hierarchy.
|
|
|
620
647
|
|
|
621
648
|
Public API surface for SDK clients.
|
|
622
649
|
|
|
650
|
+
### Standalone Functions
|
|
651
|
+
|
|
652
|
+
| Feature | TypeScript | Python | Ruby | Notes |
|
|
653
|
+
|------------------|:----------------:|:------:|:----:|--------------------------------------------|
|
|
654
|
+
| `listSessions()` | ✅ `listSessions` | ❌ | ✅ | List past sessions with metadata (v0.2.53) |
|
|
655
|
+
|
|
623
656
|
### Query Interface
|
|
624
657
|
|
|
625
658
|
| Feature | TypeScript | Python | Ruby | Notes |
|
|
@@ -629,24 +662,24 @@ Public API surface for SDK clients.
|
|
|
629
662
|
|
|
630
663
|
### Query Control Methods
|
|
631
664
|
|
|
632
|
-
| Method | TypeScript | Python | Ruby | Notes
|
|
633
|
-
|
|
634
|
-
| `interrupt()` | ✅ | ✅ | ✅ | Interrupt execution
|
|
635
|
-
| `setPermissionMode()` | ✅ | ✅ | ✅ | Change permission mode
|
|
636
|
-
| `setModel()` | ✅ | ✅ | ✅ | Change model
|
|
637
|
-
| `setMaxThinkingTokens()` | ✅ | ❌ | ✅ | Set thinking limit
|
|
638
|
-
| `supportedCommands()` | ✅ | ❌ | ✅ | Get slash commands
|
|
639
|
-
| `supportedModels()` | ✅ | ❌ | ✅ | Get available models
|
|
640
|
-
| `mcpServerStatus()` | ✅ | ✅ | ✅ | Get MCP status
|
|
641
|
-
| `accountInfo()` | ✅ | ❌ | ✅ | Get account info
|
|
642
|
-
| `rewindFiles()` | ✅ | ✅ | ✅ | Rewind file changes
|
|
643
|
-
| `setMcpServers()` | ✅ | ❌ | ✅ | Dynamic MCP servers
|
|
644
|
-
| `reconnectMcpServer()` | ✅ | ❌ | ✅ | Reconnect MCP server
|
|
645
|
-
| `toggleMcpServer()` | ✅ | ❌ | ✅ | Enable/disable MCP
|
|
646
|
-
| `stopTask()` | ✅ | ❌ | ✅ | Stop running task
|
|
647
|
-
| `streamInput()` | ✅ | ✅ | ✅ | Stream user input
|
|
648
|
-
| `initializationResult()` | ✅ |
|
|
649
|
-
| `close()` | ✅ | ✅ | ✅ | Close query/session
|
|
665
|
+
| Method | TypeScript | Python | Ruby | Notes |
|
|
666
|
+
|--------------------------|:----------:|:------:|:----:|----------------------------------------------|
|
|
667
|
+
| `interrupt()` | ✅ | ✅ | ✅ | Interrupt execution |
|
|
668
|
+
| `setPermissionMode()` | ✅ | ✅ | ✅ | Change permission mode |
|
|
669
|
+
| `setModel()` | ✅ | ✅ | ✅ | Change model |
|
|
670
|
+
| `setMaxThinkingTokens()` | ✅ | ❌ | ✅ | Set thinking limit |
|
|
671
|
+
| `supportedCommands()` | ✅ | ❌ | ✅ | Get slash commands |
|
|
672
|
+
| `supportedModels()` | ✅ | ❌ | ✅ | Get available models |
|
|
673
|
+
| `mcpServerStatus()` | ✅ | ✅ | ✅ | Get MCP status |
|
|
674
|
+
| `accountInfo()` | ✅ | ❌ | ✅ | Get account info |
|
|
675
|
+
| `rewindFiles()` | ✅ | ✅ | ✅ | Rewind file changes |
|
|
676
|
+
| `setMcpServers()` | ✅ | ❌ | ✅ | Dynamic MCP servers |
|
|
677
|
+
| `reconnectMcpServer()` | ✅ | ❌ | ✅ | Reconnect MCP server |
|
|
678
|
+
| `toggleMcpServer()` | ✅ | ❌ | ✅ | Enable/disable MCP |
|
|
679
|
+
| `stopTask()` | ✅ | ❌ | ✅ | Stop running task |
|
|
680
|
+
| `streamInput()` | ✅ | ✅ | ✅ | Stream user input |
|
|
681
|
+
| `initializationResult()` | ✅ | ✅ | ✅ | Full init response (Py: `get_server_info()`) |
|
|
682
|
+
| `close()` | ✅ | ✅ | ✅ | Close query/session |
|
|
650
683
|
|
|
651
684
|
### Client Class
|
|
652
685
|
|
|
@@ -689,23 +722,30 @@ Public API surface for SDK clients.
|
|
|
689
722
|
- `executable`/`executableArgs` are JS-specific (`node`/`bun`/`deno`)
|
|
690
723
|
- v0.2.45: Added `TaskStartedMessage`, `RateLimitEvent` message types
|
|
691
724
|
- v0.2.47: Added `promptSuggestions` option and `PromptSuggestionMessage`
|
|
692
|
-
- v0.2.49: Added `ConfigChange` hook event, `SandboxFilesystemConfig
|
|
725
|
+
- v0.2.49: Added `ConfigChange` hook event, `SandboxFilesystemConfig`, ModelInfo capability fields
|
|
726
|
+
- v0.2.50: Added `WorktreeCreate`/`WorktreeRemove` hook events, `apply_flag_settings` control request
|
|
727
|
+
- v0.2.51: Added `TaskProgressMessage` for real-time background agent progress reporting
|
|
728
|
+
- v0.2.52: Added `mcp_authenticate`/`mcp_clear_auth` control requests for MCP server authentication
|
|
729
|
+
- v0.2.53: Added `listSessions()` for discovering and listing past sessions with `SDKSessionInfo` metadata
|
|
730
|
+
- v0.2.54 – v0.2.56: CLI parity updates (no new SDK-facing features)
|
|
693
731
|
|
|
694
732
|
### Python SDK
|
|
695
733
|
- Full source available with `Transport` abstract class
|
|
696
734
|
- Partial control protocol: query and client support interrupt, setPermissionMode, setModel, rewindFiles, mcpStatus
|
|
697
|
-
-
|
|
735
|
+
- Has `CLINotFoundError`, `CLIConnectionError`, `ProcessError`, `CLIJSONDecodeError` error types
|
|
736
|
+
- Missing hooks: SessionStart, SessionEnd, Setup, TeammateIdle, TaskCompleted, ConfigChange, WorktreeCreate, WorktreeRemove
|
|
698
737
|
- Missing permission modes: `dontAsk`
|
|
699
738
|
- Missing options: `allowDangerouslySkipPermissions`, `persistSession`, `resumeSessionAt`, `sessionId`, `strictMcpConfig`, `init`/`initOnly`/`maintenance`, `debug`/`debugFile`, `promptSuggestions`
|
|
700
739
|
- `ToolPermissionContext` missing `blockedPath`, `decisionReason`, `toolUseID`, `agentID`, `description`
|
|
701
740
|
- Has SDK MCP server support with `tool()` helper and annotations
|
|
702
741
|
- Added `thinking` config and `effort` option in v0.1.36
|
|
703
|
-
- Handles `rate_limit_event` and unknown message types gracefully (v0.1.
|
|
742
|
+
- Handles `rate_limit_event` and unknown message types gracefully (v0.1.40)
|
|
743
|
+
- Client has `get_server_info()` for accessing the initialization result (v0.1.31+)
|
|
744
|
+
- v0.1.42 – v0.1.43: CLI parity updates (no new SDK-facing features)
|
|
704
745
|
|
|
705
746
|
### Ruby SDK (This Repository)
|
|
706
|
-
- Feature parity with TypeScript SDK v0.2.
|
|
747
|
+
- Feature parity with TypeScript SDK v0.2.56
|
|
707
748
|
- Ruby-idiomatic patterns (Data.define, snake_case)
|
|
708
749
|
- Complete control protocol, hook, and V2 Session API support
|
|
709
750
|
- Dedicated Client class for multi-turn conversations
|
|
710
751
|
- `executable`/`executableArgs` marked N/A (JS runtime options)
|
|
711
|
-
- Gaps from TS v0.2.43-v0.2.49: `promptSuggestions`, `TaskStartedMessage`, `RateLimitEvent`, `PromptSuggestionMessage`, `ConfigChange` hook, `SandboxFilesystemConfig`
|
data/lib/claude_agent/client.rb
CHANGED
|
@@ -32,7 +32,7 @@ module ClaudeAgent
|
|
|
32
32
|
# end
|
|
33
33
|
#
|
|
34
34
|
class Client
|
|
35
|
-
attr_reader :options, :transport, :server_info
|
|
35
|
+
attr_reader :options, :transport, :server_info, :cumulative_usage, :event_handler, :permission_queue
|
|
36
36
|
|
|
37
37
|
# Open a client with automatic cleanup
|
|
38
38
|
#
|
|
@@ -61,6 +61,9 @@ module ClaudeAgent
|
|
|
61
61
|
@protocol = nil
|
|
62
62
|
@server_info = nil
|
|
63
63
|
@connected = false
|
|
64
|
+
@cumulative_usage = CumulativeUsage.new
|
|
65
|
+
@event_handler = EventHandler.new
|
|
66
|
+
@permission_queue = PermissionQueue.new
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
# Connect to the CLI
|
|
@@ -74,6 +77,7 @@ module ClaudeAgent
|
|
|
74
77
|
|
|
75
78
|
logger.info("client") { "Connecting" }
|
|
76
79
|
@protocol = ControlProtocol.new(transport: @transport, options: @options)
|
|
80
|
+
@protocol.permission_queue = @permission_queue
|
|
77
81
|
@server_info = @protocol.start(streaming: true)
|
|
78
82
|
@connected = true
|
|
79
83
|
logger.info("client") { "Connected" }
|
|
@@ -88,6 +92,7 @@ module ClaudeAgent
|
|
|
88
92
|
return unless @connected
|
|
89
93
|
|
|
90
94
|
logger.info("client") { "Disconnecting" }
|
|
95
|
+
@permission_queue.drain!(reason: "Client disconnected")
|
|
91
96
|
@protocol&.stop
|
|
92
97
|
@protocol = nil
|
|
93
98
|
@connected = false
|
|
@@ -119,20 +124,133 @@ module ClaudeAgent
|
|
|
119
124
|
#
|
|
120
125
|
# @yield [Message] Received messages
|
|
121
126
|
# @return [Enumerator<Message>] If no block given
|
|
122
|
-
def receive_messages
|
|
127
|
+
def receive_messages
|
|
123
128
|
require_connection!
|
|
124
129
|
|
|
125
|
-
|
|
130
|
+
if block_given?
|
|
131
|
+
@protocol.each_message do |message|
|
|
132
|
+
@cumulative_usage.track(message)
|
|
133
|
+
yield message
|
|
134
|
+
end
|
|
135
|
+
else
|
|
136
|
+
enum_for(:receive_messages)
|
|
137
|
+
end
|
|
126
138
|
end
|
|
127
139
|
|
|
128
140
|
# Receive messages until a ResultMessage is received
|
|
129
141
|
#
|
|
130
142
|
# @yield [Message] Received messages
|
|
131
143
|
# @return [Enumerator<Message>] If no block given
|
|
132
|
-
def receive_response
|
|
144
|
+
def receive_response
|
|
133
145
|
require_connection!
|
|
134
146
|
|
|
135
|
-
|
|
147
|
+
if block_given?
|
|
148
|
+
@protocol.receive_response do |message|
|
|
149
|
+
@cumulative_usage.track(message)
|
|
150
|
+
yield message
|
|
151
|
+
end
|
|
152
|
+
else
|
|
153
|
+
enum_for(:receive_response)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Register an event handler
|
|
158
|
+
#
|
|
159
|
+
# Handlers persist across turns and fire automatically during
|
|
160
|
+
# {#receive_turn} and {#send_and_receive}.
|
|
161
|
+
#
|
|
162
|
+
# @param event [Symbol] Event name (:message, :text, :thinking, :tool_use, :tool_result, :result)
|
|
163
|
+
# @yield Event-specific arguments
|
|
164
|
+
# @return [self]
|
|
165
|
+
#
|
|
166
|
+
# @example
|
|
167
|
+
# client.on(:text) { |text| print text }
|
|
168
|
+
# client.on(:tool_use) { |tool| show_spinner(tool) }
|
|
169
|
+
#
|
|
170
|
+
def on(event, &block)
|
|
171
|
+
@event_handler.on(event, &block)
|
|
172
|
+
self
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# @!method on_text(&block)
|
|
176
|
+
# Register a handler for assistant text content
|
|
177
|
+
# @yield [String] Text from the AssistantMessage
|
|
178
|
+
# @return [self]
|
|
179
|
+
|
|
180
|
+
# @!method on_thinking(&block)
|
|
181
|
+
# Register a handler for assistant thinking content
|
|
182
|
+
# @yield [String] Thinking from the AssistantMessage
|
|
183
|
+
# @return [self]
|
|
184
|
+
|
|
185
|
+
# @!method on_tool_use(&block)
|
|
186
|
+
# Register a handler for tool use requests
|
|
187
|
+
# @yield [ToolUseBlock, ServerToolUseBlock] The tool use block
|
|
188
|
+
# @return [self]
|
|
189
|
+
|
|
190
|
+
# @!method on_tool_result(&block)
|
|
191
|
+
# Register a handler for tool results, paired with the original request
|
|
192
|
+
# @yield [ToolResultBlock, ToolUseBlock|nil] Result block and matched tool use
|
|
193
|
+
# @return [self]
|
|
194
|
+
|
|
195
|
+
# @!method on_result(&block)
|
|
196
|
+
# Register a handler for the final ResultMessage
|
|
197
|
+
# @yield [ResultMessage] The result
|
|
198
|
+
# @return [self]
|
|
199
|
+
|
|
200
|
+
# @!method on_message(&block)
|
|
201
|
+
# Register a handler for every message (catch-all)
|
|
202
|
+
# @yield [message] Any message object
|
|
203
|
+
# @return [self]
|
|
204
|
+
|
|
205
|
+
%i[message text thinking tool_use tool_result result].each do |event|
|
|
206
|
+
define_method(:"on_#{event}") { |&block| on(event, &block) }
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Receive messages until a ResultMessage, accumulating into a TurnResult
|
|
210
|
+
#
|
|
211
|
+
# Dispatches events to registered handlers (see {#on}).
|
|
212
|
+
#
|
|
213
|
+
# @yield [Message] Each message as it arrives (optional)
|
|
214
|
+
# @return [TurnResult] The completed turn
|
|
215
|
+
def receive_turn
|
|
216
|
+
require_connection!
|
|
217
|
+
|
|
218
|
+
turn = TurnResult.new
|
|
219
|
+
receive_response do |message|
|
|
220
|
+
turn << message
|
|
221
|
+
@event_handler.handle(message)
|
|
222
|
+
yield message if block_given?
|
|
223
|
+
end
|
|
224
|
+
@event_handler.reset!
|
|
225
|
+
turn
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Send a message and receive the complete turn result
|
|
229
|
+
#
|
|
230
|
+
# Combines {#send_message} and {#receive_turn} into a single call.
|
|
231
|
+
#
|
|
232
|
+
# @param content [String, Array] Message content
|
|
233
|
+
# @param session_id [String] Session ID
|
|
234
|
+
# @param uuid [String, nil] Message UUID for file checkpointing
|
|
235
|
+
# @yield [Message] Each message as it arrives (optional)
|
|
236
|
+
# @return [TurnResult] The completed turn
|
|
237
|
+
#
|
|
238
|
+
# @example Simple
|
|
239
|
+
# turn = client.send_and_receive("Fix the bug")
|
|
240
|
+
# puts turn.text
|
|
241
|
+
# puts "Cost: $#{turn.cost}"
|
|
242
|
+
#
|
|
243
|
+
# @example With streaming
|
|
244
|
+
# turn = client.send_and_receive("Fix the bug") do |msg|
|
|
245
|
+
# case msg
|
|
246
|
+
# when ClaudeAgent::AssistantMessage
|
|
247
|
+
# print msg.text
|
|
248
|
+
# end
|
|
249
|
+
# end
|
|
250
|
+
#
|
|
251
|
+
def send_and_receive(content, session_id: "default", uuid: nil, &block)
|
|
252
|
+
send_message(content, session_id: session_id, uuid: uuid)
|
|
253
|
+
receive_turn(&block)
|
|
136
254
|
end
|
|
137
255
|
|
|
138
256
|
# Stream user input from an enumerable (TypeScript SDK parity)
|
|
@@ -161,11 +279,14 @@ module ClaudeAgent
|
|
|
161
279
|
# end
|
|
162
280
|
# end
|
|
163
281
|
#
|
|
164
|
-
def stream_input(stream, session_id: "default"
|
|
282
|
+
def stream_input(stream, session_id: "default")
|
|
165
283
|
require_connection!
|
|
166
284
|
|
|
167
285
|
if block_given?
|
|
168
|
-
@protocol.stream_conversation(stream, session_id: session_id
|
|
286
|
+
@protocol.stream_conversation(stream, session_id: session_id) do |message|
|
|
287
|
+
@cumulative_usage.track(message)
|
|
288
|
+
yield message
|
|
289
|
+
end
|
|
169
290
|
else
|
|
170
291
|
@protocol.stream_input(stream, session_id: session_id)
|
|
171
292
|
end
|
|
@@ -191,6 +312,7 @@ module ClaudeAgent
|
|
|
191
312
|
def abort!(reason = nil)
|
|
192
313
|
return unless @connected
|
|
193
314
|
|
|
315
|
+
@permission_queue.drain!(reason: reason || "Operation aborted")
|
|
194
316
|
@options.abort_controller&.abort(reason)
|
|
195
317
|
@protocol&.abort!
|
|
196
318
|
end
|
|
@@ -298,6 +420,22 @@ module ClaudeAgent
|
|
|
298
420
|
@protocol.stop_task(task_id)
|
|
299
421
|
end
|
|
300
422
|
|
|
423
|
+
# Apply flag settings (TypeScript SDK v0.2.50 parity)
|
|
424
|
+
#
|
|
425
|
+
# Merges the provided settings into the flag settings layer.
|
|
426
|
+
#
|
|
427
|
+
# @param settings [Hash] Settings to merge into the flag layer
|
|
428
|
+
# @return [Hash] Response from the CLI
|
|
429
|
+
#
|
|
430
|
+
# @example
|
|
431
|
+
# client.apply_flag_settings({ "model" => "claude-sonnet-4-5-20250514" })
|
|
432
|
+
#
|
|
433
|
+
def apply_flag_settings(settings)
|
|
434
|
+
require_connection!
|
|
435
|
+
|
|
436
|
+
@protocol.apply_flag_settings(settings)
|
|
437
|
+
end
|
|
438
|
+
|
|
301
439
|
# Dynamically set MCP servers for this session (TypeScript SDK parity)
|
|
302
440
|
#
|
|
303
441
|
# This replaces the current set of dynamically-added MCP servers.
|
|
@@ -355,6 +493,58 @@ module ClaudeAgent
|
|
|
355
493
|
@protocol.mcp_toggle(server_name, enabled: enabled)
|
|
356
494
|
end
|
|
357
495
|
|
|
496
|
+
# Initiate OAuth authentication for an MCP server (TypeScript SDK v0.2.52 parity)
|
|
497
|
+
#
|
|
498
|
+
# @param server_name [String] Name of the MCP server to authenticate
|
|
499
|
+
# @return [Hash] Response from the CLI
|
|
500
|
+
#
|
|
501
|
+
# @example
|
|
502
|
+
# client.mcp_authenticate("my-remote-server")
|
|
503
|
+
#
|
|
504
|
+
def mcp_authenticate(server_name)
|
|
505
|
+
require_connection!
|
|
506
|
+
|
|
507
|
+
@protocol.mcp_authenticate(server_name)
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# Clear stored auth credentials for an MCP server (TypeScript SDK v0.2.52 parity)
|
|
511
|
+
#
|
|
512
|
+
# @param server_name [String] Name of the MCP server to clear auth for
|
|
513
|
+
# @return [Hash] Response from the CLI
|
|
514
|
+
#
|
|
515
|
+
# @example
|
|
516
|
+
# client.mcp_clear_auth("my-remote-server")
|
|
517
|
+
#
|
|
518
|
+
def mcp_clear_auth(server_name)
|
|
519
|
+
require_connection!
|
|
520
|
+
|
|
521
|
+
@protocol.mcp_clear_auth(server_name)
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
# Non-blocking poll for the next pending permission request.
|
|
525
|
+
#
|
|
526
|
+
# Returns the next {PermissionRequest} from the queue, or nil if
|
|
527
|
+
# no requests are pending. Call {PermissionRequest#allow!} or
|
|
528
|
+
# {PermissionRequest#deny!} to resolve it.
|
|
529
|
+
#
|
|
530
|
+
# @return [PermissionRequest, nil] The next pending request, or nil
|
|
531
|
+
#
|
|
532
|
+
# @example UI poll loop
|
|
533
|
+
# if request = client.pending_permission
|
|
534
|
+
# show_permission_dialog(request)
|
|
535
|
+
# end
|
|
536
|
+
#
|
|
537
|
+
def pending_permission
|
|
538
|
+
@permission_queue.poll
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
# Check if there are any pending permission requests.
|
|
542
|
+
#
|
|
543
|
+
# @return [Boolean]
|
|
544
|
+
def pending_permissions?
|
|
545
|
+
!@permission_queue.empty?
|
|
546
|
+
end
|
|
547
|
+
|
|
358
548
|
private
|
|
359
549
|
|
|
360
550
|
def logger
|