claude_agent 0.7.15 → 0.7.16
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/.claude/rules/conventions.md +66 -16
- data/CHANGELOG.md +2 -0
- data/CLAUDE.md +24 -4
- data/README.md +52 -1529
- data/docs/architecture.md +339 -0
- data/docs/client.md +526 -0
- data/docs/configuration.md +571 -0
- data/docs/conversations.md +461 -0
- data/docs/errors.md +127 -0
- data/docs/events.md +225 -0
- data/docs/getting-started.md +310 -0
- data/docs/hooks.md +380 -0
- data/docs/logging.md +96 -0
- data/docs/mcp.md +308 -0
- data/docs/messages.md +871 -0
- data/docs/permissions.md +611 -0
- data/docs/queries.md +227 -0
- data/docs/sessions.md +335 -0
- data/lib/claude_agent/configuration.rb +129 -0
- data/lib/claude_agent/conversation.rb +28 -3
- data/lib/claude_agent/errors.rb +3 -0
- data/lib/claude_agent/event_handler.rb +14 -0
- data/lib/claude_agent/hook_registry.rb +110 -0
- data/lib/claude_agent/mcp/server.rb +22 -0
- data/lib/claude_agent/mcp/tool.rb +24 -3
- data/lib/claude_agent/message.rb +93 -0
- data/lib/claude_agent/options.rb +10 -0
- data/lib/claude_agent/permission_policy.rb +174 -0
- data/lib/claude_agent/session.rb +100 -11
- data/lib/claude_agent/session_paths.rb +5 -2
- data/lib/claude_agent/version.rb +1 -1
- data/lib/claude_agent.rb +175 -0
- metadata +19 -1
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
Internal architecture of the ClaudeAgent Ruby SDK.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Layer Diagram
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
ClaudeAgent.ask / .chat / .query
|
|
11
|
+
|
|
|
12
|
+
Configuration (Stripe-style global defaults, Forwardable delegators)
|
|
13
|
+
|
|
|
14
|
+
Options (validation, CLI arg serialization, env vars)
|
|
15
|
+
|
|
|
16
|
+
Conversation / Client (lifecycle, turns, event dispatch)
|
|
17
|
+
|
|
|
18
|
+
EventHandler / TurnResult / CumulativeUsage
|
|
19
|
+
|
|
|
20
|
+
ControlProtocol (request/response routing, hooks, MCP, permissions)
|
|
21
|
+
Primitives | Lifecycle | Messaging | Commands | RequestHandling
|
|
22
|
+
|
|
|
23
|
+
Transport::Subprocess (JSON Lines framing, stdin/stdout, process mgmt)
|
|
24
|
+
|
|
|
25
|
+
Claude Code CLI (spawned as subprocess)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Module Responsibilities
|
|
31
|
+
|
|
32
|
+
### Entry Points
|
|
33
|
+
|
|
34
|
+
| Module | Role |
|
|
35
|
+
|--------------------------|-------------------------------------------------------------------------------------------------------|
|
|
36
|
+
| `ClaudeAgent.ask` | One-shot query, returns `TurnResult`. Merges global config, builds `EventHandler` from `on_*` kwargs. |
|
|
37
|
+
| `ClaudeAgent.chat` | Multi-turn conversation. Block form auto-cleans; no block returns `Conversation`. |
|
|
38
|
+
| `ClaudeAgent.query` | Low-level streaming enumerator. Returns `Enumerator<Message>`. |
|
|
39
|
+
| `ClaudeAgent.query_turn` | Like `query` but accumulates into `TurnResult` with optional `EventHandler`. |
|
|
40
|
+
|
|
41
|
+
### Configuration Layer
|
|
42
|
+
|
|
43
|
+
| Module | Role |
|
|
44
|
+
|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
45
|
+
| `Configuration` | Stripe-style global defaults. Holds all configurable fields (Tier 1/2/3), global `PermissionPolicy`, `HookRegistry`, and MCP server registrations. `to_options(**overrides)` merges config + per-request kwargs into an `Options` instance. |
|
|
46
|
+
| `Options` | All configurable attributes with validation and CLI arg serialization. Includes `Serializer` mixin for `to_cli_args` and `to_env`. Auto-compiles `PermissionPolicy` to lambda, `HookRegistry` to hash. Auto-sets `permission_prompt_tool_name = "stdio"` when `can_use_tool` or `permission_queue` is present. |
|
|
47
|
+
|
|
48
|
+
### Conversation Layer
|
|
49
|
+
|
|
50
|
+
| Module | Role |
|
|
51
|
+
|----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
52
|
+
| `Conversation` | High-level lifecycle manager. Wraps `Client` with auto-connect on first `say`, multi-turn history, tool activity timeline with timestamps, and cumulative cost tracking. Partitions kwargs into callbacks / conversation keys / options keys. Supports `open` (block), `resume` (session ID), and permission mode mapping (`:queue`, `:accept_edits`, policy, callable). |
|
|
53
|
+
| `Client` | Bidirectional connection to CLI. Composes `Transport`, `ControlProtocol`, `EventHandler`, `CumulativeUsage`, and `PermissionQueue`. Provides `send_message`, `receive_turn`, `send_and_receive`, `stream_input`, `interrupt`, and `abort!`. Includes `Commands` mixin for control operations (permission mode, model changes, file rewind, MCP server management). |
|
|
54
|
+
|
|
55
|
+
### Event & Accumulation Layer
|
|
56
|
+
|
|
57
|
+
| Module | Role |
|
|
58
|
+
|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
59
|
+
| `EventHandler` | Three-layer event dispatch: (1) `:message` catch-all, (2) type-based (`:assistant`, `:stream_event`, `:status`, etc.), (3) decomposed (`:text`, `:thinking`, `:tool_use`, `:tool_result`). Pairs tool results with their originating tool use blocks. Supports `EventHandler.define` DSL and method chaining. |
|
|
60
|
+
| `TurnResult` | Message accumulator for a single agent turn. Convenience accessors: `text`, `thinking`, `tool_uses`, `tool_results`, `tool_executions`, `cost`, `session_id`, `usage`, `model`, `structured_output`, `permission_denials`. Accumulates streaming text deltas as fallback for aborted turns. |
|
|
61
|
+
| `CumulativeUsage` | Thread-safe (Mutex) token and cost tracker across turns. Sums `input_tokens`, `output_tokens`, cache tokens. Takes session-cumulative `total_cost_usd` and `num_turns` from the most recent `ResultMessage`. |
|
|
62
|
+
|
|
63
|
+
### Protocol Layer
|
|
64
|
+
|
|
65
|
+
| Module | Role |
|
|
66
|
+
|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
67
|
+
| `ControlProtocol` | Core protocol handler. Composed of five submodules (below). Manages shared state: transport, parser, request counter, pending requests/results, threading primitives (Mutex, ConditionVariable, Queue), abort signal. |
|
|
68
|
+
| `Primitives` | Low-level read/write helpers. `write_message` serializes and sends JSON. Request/response ID generation. Stateless except for shared counters and pending-request maps. |
|
|
69
|
+
| `Lifecycle` | Connection lifecycle: `start` (connect transport, spawn reader thread, send initialize), `stop` (end input, join reader, close transport), `abort!` (cancel pending requests, drain permission queue, terminate transport). Background `reader_loop` routes `control_request`, `control_response`, and SDK messages to appropriate handlers or the message queue. |
|
|
70
|
+
| `Messaging` | Consumer-facing message delivery: `each_message`, `receive_response`, `send_user_message`, `stream_input`, `stream_conversation`. Reads from the internal `Queue`, parses via `MessageParser`, checks abort signal. |
|
|
71
|
+
| `Commands` | Control commands sent to CLI: `change_permission_mode`, `change_model`, `rewind_files`, `mcp_server_status`, `set_mcp_servers`, `interrupt`. Each sends a `control_request` and waits for the response. |
|
|
72
|
+
| `RequestHandling` | Handles incoming control requests from CLI: `can_use_tool` (three modes: synchronous callback, queue-based, default allow), `hook_callback`, `mcp_message` (routes to SDK MCP server instances), `elicitation`. Normalizes Ruby field names to CLI camelCase keys. |
|
|
73
|
+
|
|
74
|
+
### Transport Layer
|
|
75
|
+
|
|
76
|
+
| Module | Role |
|
|
77
|
+
|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
78
|
+
| `Transport::Base` | Abstract base class defining the transport interface. |
|
|
79
|
+
| `Transport::Subprocess` | Spawns Claude Code CLI via `Open3.popen3` or custom spawn function. Manages stdin/stdout/stderr streams. JSON Lines framing with partial-JSON buffering. Version checking against minimum CLI version. Supports graceful termination (SIGTERM) and force kill (SIGKILL). Custom spawn support via `SpawnOptions` / `SpawnedProcess` for non-standard process management. |
|
|
80
|
+
|
|
81
|
+
### Parsing Layer
|
|
82
|
+
|
|
83
|
+
| Module | Role |
|
|
84
|
+
|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
85
|
+
| `MessageParser` | Registry-based router. Maps raw JSON hashes (string keys, camelCase) to typed message objects. `deep_transform_keys` normalizes to snake_case symbols. Dispatches by `type` (top-level) or `type:subtype` (system messages). Unknown types wrapped in `GenericMessage`. |
|
|
86
|
+
|
|
87
|
+
### Permission System
|
|
88
|
+
|
|
89
|
+
| Module | Role |
|
|
90
|
+
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
91
|
+
| `PermissionPolicy` | Declarative DSL for permission rules: `allow`, `deny`, `allow_matching`, `deny_matching`, `allow_all`, `deny_all`, `ask` (custom fallback). Compiles to a `can_use_tool` lambda. Rules evaluated in order; first match wins. |
|
|
92
|
+
| `PermissionQueue` | Thread-safe `Queue` wrapper for deferred permission requests. Non-blocking `poll`, blocking `pop(timeout:)`, and `drain!` for abort cleanup. |
|
|
93
|
+
| `PermissionRequest` | Deferred permission request resolved from any thread. `allow!` / `deny!` unblock the reader thread via Mutex + ConditionVariable. Supports hybrid mode: callback can call `context.request.defer!` to enqueue instead of returning synchronously. |
|
|
94
|
+
|
|
95
|
+
### Hook System
|
|
96
|
+
|
|
97
|
+
| Module | Role |
|
|
98
|
+
|----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
99
|
+
| `HookRegistry` | Ruby-friendly DSL mapping idiomatic method names (`before_tool_use`, `after_tool_use`, `on_session_start`, etc.) to CLI event names (`PreToolUse`, `PostToolUse`, `SessionStart`, etc.). Compiles to the `Hash{String => Array<HookMatcher>}` format consumed by `Options#hooks`. Supports regex/string tool matchers and additive merge. |
|
|
100
|
+
|
|
101
|
+
### MCP Layer
|
|
102
|
+
|
|
103
|
+
| Module | Role |
|
|
104
|
+
|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
105
|
+
| `MCP::Server` | In-process MCP server. Handles JSON-RPC messages: `initialize`, `tools/list`, `tools/call`. Registered via `Options#mcp_servers` with `type: "sdk"`. Block DSL for inline tool definition. |
|
|
106
|
+
| `MCP::Tool` | Single tool definition with name, description, JSON Schema (auto-normalized from Ruby types/symbols), optional annotations, and handler block. Formats results as MCP content blocks. |
|
|
107
|
+
|
|
108
|
+
### Session Layer
|
|
109
|
+
|
|
110
|
+
| Module | Role |
|
|
111
|
+
|--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
112
|
+
| `Session` | Rails-like finder with Stripe-style resource methods. `find` / `retrieve` / `all` / `where` class methods. Instance methods: `messages` (returns `SessionMessageRelation`), `rename`, `tag_session`, `fork`, `reload`, `resume`. |
|
|
113
|
+
| `SessionMessageRelation` | Chainable Enumerable query object. Lazy evaluation with `where(limit:, offset:)`. Wraps `GetSessionMessages`. |
|
|
114
|
+
| `ListSessions` | Reads session metadata from disk without spawning CLI. Returns `SessionInfo` sorted by last modified. Supports directory scoping and git worktree inclusion. |
|
|
115
|
+
| `GetSessionMessages` | Reads JSONL session transcript, reconstructs main conversation thread, returns `SessionMessage` array with pagination. |
|
|
116
|
+
| `GetSessionInfo` | Targeted single-session lookup by UUID. |
|
|
117
|
+
| `ForkSession` | Creates a new session file with remapped UUIDs, optional truncation point. |
|
|
118
|
+
| `SessionMutations` | Appends `custom-title` and `tag` entries to session files. |
|
|
119
|
+
| `SessionPaths` | Shared infrastructure for resolving session file paths across projects and worktrees. |
|
|
120
|
+
|
|
121
|
+
### Abort & Signal
|
|
122
|
+
|
|
123
|
+
| Module | Role |
|
|
124
|
+
|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
125
|
+
| `AbortController` | JavaScript-style abort controller. Owns an `AbortSignal`. `abort(reason)` triggers the signal; `reset!` clears it for reuse. |
|
|
126
|
+
| `AbortSignal` | Thread-safe (Mutex + ConditionVariable) signal. `aborted?`, `reason`, `on_abort` callbacks, `wait(timeout:)`, `check!` (raises `AbortError`). Used by `ControlProtocol` (reader loop check, queue push), `Conversation` (auto-reset per turn). |
|
|
127
|
+
|
|
128
|
+
### Tool Activity Tracking
|
|
129
|
+
|
|
130
|
+
| Module | Role |
|
|
131
|
+
|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
132
|
+
| `ToolActivity` | Immutable (`Data.define`) record of a completed tool execution. Pairs `ToolUseBlock` + `ToolResultBlock` with turn index and wall-clock timestamps. |
|
|
133
|
+
| `LiveToolActivity` | Mutable wrapper for real-time status tracking. States: `:running`, `:done`, `:error`. Updated by progress messages. Suitable for live UIs. |
|
|
134
|
+
| `ToolActivityTracker` | Enumerable collection with auto-wiring. Attaches to `EventHandler` or `Client`. Callbacks: `on_start`, `on_complete`, `on_progress`, `on_change`. Query methods: `running`, `done`, `errored`, `find_by_id`. |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Data Flow
|
|
139
|
+
|
|
140
|
+
### One-Shot Query (`ask`)
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
User calls ClaudeAgent.ask(prompt, **kwargs)
|
|
144
|
+
|
|
|
145
|
+
+-- extract_callbacks separates on_* from config overrides
|
|
146
|
+
+-- Configuration.to_options merges global defaults + overrides --> Options
|
|
147
|
+
+-- build_events creates EventHandler from callbacks
|
|
148
|
+
|
|
|
149
|
+
+-- query_turn(prompt, options, events)
|
|
150
|
+
|
|
|
151
|
+
+-- ClaudeAgent.query(prompt, options) returns Enumerator
|
|
152
|
+
| |
|
|
153
|
+
| +-- Transport::Subprocess.new(options)
|
|
154
|
+
| +-- ControlProtocol.new(transport, options)
|
|
155
|
+
| +-- protocol.start(streaming: true)
|
|
156
|
+
| | +-- transport.connect --> spawn CLI subprocess
|
|
157
|
+
| | +-- reader_loop starts in background Thread
|
|
158
|
+
| | +-- send_initialize --> handshake with CLI
|
|
159
|
+
| +-- protocol.send_user_message(prompt)
|
|
160
|
+
| | +-- write JSON to stdin
|
|
161
|
+
| +-- protocol.each_message yields parsed messages
|
|
162
|
+
| +-- reader_loop reads JSON Lines from stdout
|
|
163
|
+
| +-- routes control_request to RequestHandling
|
|
164
|
+
| +-- routes control_response to pending request
|
|
165
|
+
| +-- queues SDK messages for consumer
|
|
166
|
+
| +-- consumer pops from Queue
|
|
167
|
+
| +-- MessageParser.parse(raw) --> typed message
|
|
168
|
+
| +-- yield message to Enumerator
|
|
169
|
+
|
|
|
170
|
+
+-- TurnResult << message (accumulates)
|
|
171
|
+
+-- EventHandler.handle(message) (dispatches events)
|
|
172
|
+
+-- yield message to caller block (if given)
|
|
173
|
+
+-- return TurnResult
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Multi-Turn Conversation (`chat`)
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
User calls ClaudeAgent.chat(**kwargs)
|
|
180
|
+
|
|
|
181
|
+
+-- merge_config_into_kwargs applies global defaults
|
|
182
|
+
+-- Conversation.new(**merged)
|
|
183
|
+
|
|
|
184
|
+
+-- partition_kwargs --> callbacks / conversation_kwargs / options_kwargs
|
|
185
|
+
+-- build_options (compiles PermissionPolicy, HookRegistry, permission mode)
|
|
186
|
+
+-- Client.new(options)
|
|
187
|
+
+-- register_callbacks on Client's EventHandler
|
|
188
|
+
+-- register_timing_hooks for tool activity timestamps
|
|
189
|
+
|
|
|
190
|
+
+-- conversation.say(prompt)
|
|
191
|
+
|
|
|
192
|
+
+-- ensure_connected! (auto-connects on first call)
|
|
193
|
+
| +-- Client.connect
|
|
194
|
+
| +-- ControlProtocol.start(streaming: true)
|
|
195
|
+
+-- Client.send_and_receive(prompt)
|
|
196
|
+
| +-- send_message --> protocol.send_user_message
|
|
197
|
+
| +-- receive_turn
|
|
198
|
+
| +-- TurnResult.new
|
|
199
|
+
| +-- receive_response yields messages
|
|
200
|
+
| +-- TurnResult << message
|
|
201
|
+
| +-- EventHandler.handle(message)
|
|
202
|
+
| +-- CumulativeUsage.track(message)
|
|
203
|
+
| +-- stops on ResultMessage
|
|
204
|
+
+-- build_tool_activities (timestamps from hooks)
|
|
205
|
+
+-- return TurnResult
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Permission Request Flow
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
CLI sends control_request { subtype: "can_use_tool" }
|
|
212
|
+
|
|
|
213
|
+
+-- reader_loop receives raw message
|
|
214
|
+
+-- handle_control_request dispatches to handle_can_use_tool
|
|
215
|
+
|
|
|
216
|
+
+-- Mode 1: Synchronous callback
|
|
217
|
+
| +-- options.can_use_tool.call(name, input, context)
|
|
218
|
+
| +-- callback returns PermissionResultAllow or PermissionResultDeny
|
|
219
|
+
| +-- (or callback calls context.request.defer! to switch to queue mode)
|
|
220
|
+
|
|
|
221
|
+
+-- Mode 2: Queue-based
|
|
222
|
+
| +-- PermissionRequest created with Mutex + ConditionVariable
|
|
223
|
+
| +-- pushed to PermissionQueue
|
|
224
|
+
| +-- reader thread blocks on perm_request.wait(timeout:)
|
|
225
|
+
| +-- main thread polls client.pending_permission
|
|
226
|
+
| +-- main thread calls request.allow! or request.deny!
|
|
227
|
+
| +-- ConditionVariable.broadcast unblocks reader thread
|
|
228
|
+
|
|
|
229
|
+
+-- Mode 3: Default allow (no callback, no queue)
|
|
230
|
+
|
|
|
231
|
+
+-- normalize_permission_result --> Hash
|
|
232
|
+
+-- send_control_response back to CLI
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Immutable Types
|
|
238
|
+
|
|
239
|
+
All message types and content blocks use `Data.define`, frozen at construction:
|
|
240
|
+
|
|
241
|
+
**Messages**: `UserMessage`, `UserMessageReplay`, `AssistantMessage`, `SystemMessage`, `ResultMessage`, `StreamEvent`, `CompactBoundaryMessage`, `StatusMessage`, `ToolProgressMessage`, `HookResponseMessage`, `AuthStatusMessage`, `TaskNotificationMessage`, `HookStartedMessage`, `HookProgressMessage`, `ToolUseSummaryMessage`, `FilesPersistedEvent`, `TaskStartedMessage`, `TaskProgressMessage`, `RateLimitEvent`, `PromptSuggestionMessage`, `ElicitationCompleteMessage`, `LocalCommandOutputMessage`, `GenericMessage`
|
|
242
|
+
|
|
243
|
+
**Content Blocks**: `TextBlock`, `ThinkingBlock`, `ToolUseBlock`, `ToolResultBlock`, `ServerToolUseBlock`, `ServerToolResultBlock`, `ImageContentBlock`, `GenericBlock`
|
|
244
|
+
|
|
245
|
+
**Data Types**: `SessionInfo`, `SessionMessage`, `ForkSessionResult`, `ToolActivity`, `TaskUsage`, `SDKPermissionDenial`, `RewindFilesResult`, `ToolsPreset`, `SlashCommand`, `McpServerStatus`, `McpSetServersResult`, `PermissionResultAllow`, `PermissionResultDeny`
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Thread Safety
|
|
250
|
+
|
|
251
|
+
| Component | Mechanism | Purpose |
|
|
252
|
+
|---------------------------------------------|-------------------------------|----------------------------------------------------------------------------------------------------|
|
|
253
|
+
| `PermissionRequest` | `Mutex` + `ConditionVariable` | Reader thread blocks on `wait`; main thread resolves via `allow!` / `deny!` |
|
|
254
|
+
| `PermissionQueue` | `Queue` (thread-safe stdlib) | Bridges reader thread and consumer thread for permission requests |
|
|
255
|
+
| `AbortSignal` | `Mutex` + `ConditionVariable` | Multiple consumers check `aborted?`; `on_abort` callbacks fire once; `wait` blocks until triggered |
|
|
256
|
+
| `CumulativeUsage` | `Mutex` | All reads and writes synchronized |
|
|
257
|
+
| `ControlProtocol` | `Mutex` + `ConditionVariable` | Shared state for pending requests/results; reader thread signals consumer |
|
|
258
|
+
| `Transport::Subprocess` | `Mutex` | Protects stdin writes and stream close operations |
|
|
259
|
+
| `ControlProtocol.reader_loop` | Background `Thread` | Reads transport, routes control messages, queues SDK messages |
|
|
260
|
+
| `Transport::Subprocess.start_stderr_reader` | Background `Thread` | Drains stderr to prevent pipe buffer fill; forwards to `stderr_callback` |
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Types Reference
|
|
265
|
+
|
|
266
|
+
### Core Return Types
|
|
267
|
+
|
|
268
|
+
| Type | Description |
|
|
269
|
+
|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
270
|
+
| `TurnResult` | Accumulator for a single turn. Accessors: `text`, `thinking`, `tool_uses`, `tool_results`, `tool_executions`, `cost`, `session_id`, `usage`, `model`, `stop_reason`, `structured_output`, `permission_denials` |
|
|
271
|
+
| `CumulativeUsage` | Cross-turn token/cost tracker. Fields: `input_tokens`, `output_tokens`, `cache_read_input_tokens`, `cache_creation_input_tokens`, `total_cost_usd`, `num_turns`, `duration_ms`, `duration_api_ms` |
|
|
272
|
+
| `EventHandler` | Event dispatcher. Events: `message`, `user`, `assistant`, `system`, `result`, `stream_event`, `status`, `tool_progress`, `text`, `thinking`, `tool_use`, `tool_result`, and more |
|
|
273
|
+
|
|
274
|
+
### Tool Activity
|
|
275
|
+
|
|
276
|
+
| Type | Description |
|
|
277
|
+
|-----------------------|-----------------------------------------------------------------------------------------------|
|
|
278
|
+
| `ToolActivity` | Immutable. Post-turn record of a tool execution with timestamps and turn index |
|
|
279
|
+
| `LiveToolActivity` | Mutable. Real-time status (`:running`, `:done`, `:error`) with elapsed time |
|
|
280
|
+
| `ToolActivityTracker` | Enumerable collection with `on_start` / `on_complete` / `on_progress` / `on_change` callbacks |
|
|
281
|
+
|
|
282
|
+
### Permissions
|
|
283
|
+
|
|
284
|
+
| Type | Description |
|
|
285
|
+
|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
286
|
+
| `PermissionRequest` | Deferred request with `allow!` / `deny!` / `defer!`. Thread-safe resolution |
|
|
287
|
+
| `PermissionQueue` | Thread-safe queue with `poll` (non-blocking) and `pop` (blocking) |
|
|
288
|
+
| `PermissionPolicy` | Declarative DSL. Compiles to `can_use_tool` lambda |
|
|
289
|
+
| `PermissionResultAllow` | Allow response with optional `updated_input` and `updated_permissions` |
|
|
290
|
+
| `PermissionResultDeny` | Deny response with `message` and `interrupt` flag |
|
|
291
|
+
| `ToolPermissionContext` | Context passed to `can_use_tool`: `permission_suggestions`, `blocked_path`, `decision_reason`, `tool_use_id`, `agent_id`, `description`, `signal`, `request` |
|
|
292
|
+
|
|
293
|
+
### Sessions
|
|
294
|
+
|
|
295
|
+
| Type | Description |
|
|
296
|
+
|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
297
|
+
| `Session` | Rich finder object. Class methods: `find`, `retrieve`, `all`, `where`. Instance: `messages`, `rename`, `fork`, `resume`, `reload` |
|
|
298
|
+
| `SessionInfo` | Immutable metadata: `session_id`, `summary`, `last_modified`, `file_size`, `custom_title`, `first_prompt`, `git_branch`, `cwd`, `tag`, `created_at` |
|
|
299
|
+
| `SessionMessage` | Immutable transcript entry: `type`, `uuid`, `session_id`, `message`, `parent_tool_use_id` |
|
|
300
|
+
| `SessionMessageRelation` | Chainable Enumerable with `where(limit:, offset:)` |
|
|
301
|
+
| `ForkSessionResult` | Fork result with new `session_id` |
|
|
302
|
+
|
|
303
|
+
### MCP
|
|
304
|
+
|
|
305
|
+
| Type | Description |
|
|
306
|
+
|-----------------------|-----------------------------------------------------------------------------------------------|
|
|
307
|
+
| `MCP::Server` | In-process MCP server hosting `MCP::Tool` instances |
|
|
308
|
+
| `MCP::Tool` | Tool definition with schema normalization and handler block |
|
|
309
|
+
| `McpServerStatus` | Status of an MCP server: `name`, `status`, `server_info`, `error`, `config`, `scope`, `tools` |
|
|
310
|
+
| `McpSetServersResult` | Result of dynamic server management: `added`, `removed`, `errors` |
|
|
311
|
+
|
|
312
|
+
### Abort
|
|
313
|
+
|
|
314
|
+
| Type | Description |
|
|
315
|
+
|-------------------|-------------------------------------------------------------------------------------------|
|
|
316
|
+
| `AbortController` | Owns an `AbortSignal`. Methods: `abort(reason)`, `reset!` |
|
|
317
|
+
| `AbortSignal` | Thread-safe signal. Methods: `aborted?`, `reason`, `on_abort`, `wait`, `check!`, `reset!` |
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Development
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
bin/setup # Install dependencies
|
|
325
|
+
bundle exec rake # Unit tests + RBS + RuboCop (default task)
|
|
326
|
+
bundle exec rake test # Unit tests only
|
|
327
|
+
bundle exec rake test_integration # Integration tests (requires CLI v2.0.0+)
|
|
328
|
+
bundle exec rake test_smoke # Smoke tests against local LLM (e.g. Ollama)
|
|
329
|
+
bundle exec rake test_all # All tests
|
|
330
|
+
bundle exec rake rbs # Validate RBS type signatures
|
|
331
|
+
bundle exec rubocop # Lint
|
|
332
|
+
bin/console # IRB with gem loaded
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Binstubs**: `bin/test`, `bin/test-integration`, `bin/test-all`, `bin/test-smoke`, `bin/rbs-validate`
|
|
336
|
+
|
|
337
|
+
**Test structure**: Unit tests in `test/claude_agent/` (no CLI required), integration tests in `test/integration/` (require `INTEGRATION=true`), smoke tests in `test/smoke/` (require Ollama + `SMOKE=true`). Support files and mocks in `test/support/`.
|
|
338
|
+
|
|
339
|
+
**Single file**: `bundle exec ruby -Itest test/claude_agent/test_foo.rb`
|