claude_agent 0.1.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 962eff5c1e28589e347c1096e8c9683714b58bc95d56f281256580311bf0b87f
4
- data.tar.gz: e482f60ed6579f9b364e2947b970fca1eaf35c6eec02e5669d557b9c5caf15bc
3
+ metadata.gz: c630af2842675c8aa126588105617fa1af823c437ef1095029b3f7e9efbc982c
4
+ data.tar.gz: 16199aa31e03d542bf9128356594a0ea6659a16ecfba7fa2b3e1a97429662ef2
5
5
  SHA512:
6
- metadata.gz: 03fc463581c3dc92b0f3d121e7f59f252b746e0a049f4eb505ef14938799de397f4cb64cd01fca09946c8be38b767205792a06f51cfa968abd880eebc2b7d79c
7
- data.tar.gz: a3407945fe4b87957c898ca2872f869b62cd520db7afbf76602aa5105febcb2a95dc5a66131b68ad0254b8b7f922ecc387394f96bd78ac9da2227443f3cb2a33
6
+ metadata.gz: 8f555706af9480e572d8f310a73ab0d1294b9eaf6b162146364032450bbad86f0a2e962649f12e74e48dae4155fd1929221efd46a349253d1bf96ad09249db54
7
+ data.tar.gz: fbf3a236589cad360dbfff15dfa8164a353a973e211e5f4ab4802d8b383d803359a137a9a312478bbd0175f7b866c4f40795f55c6d8b2eb8f028992f403b5182
data/CHANGELOG.md CHANGED
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.0] - 2026-01-16
11
+
12
+ ### Added
13
+ - `agent` option for specifying main thread agent name (TypeScript SDK v0.2.9 parity)
14
+ - `model` field in `SessionStartInput` hook input
15
+
16
+ ## [0.2.0] - 2026-01-11
17
+
18
+ ### Added
19
+ - V2 Session API for multi-turn conversations (`unstable_v2_create_session`, `unstable_v2_resume_session`, `unstable_v2_prompt`)
20
+ - `Session` class for stateful conversation management
21
+ - `SessionOptions` data type for V2 API configuration
22
+
23
+ ### Fixed
24
+ - `Options#initialize` now correctly handles nil values without overriding defaults
25
+
10
26
  ## [0.1.0] - 2026-01-10
11
27
 
12
28
  ### Added
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ClaudeAgent
2
2
 
3
- A Ruby SDK for building AI-powered applications with [Claude Code](https://docs.anthropic.com/en/docs/claude-code). This library wraps the Claude Code CLI, providing both simple one-shot queries and interactive bidirectional sessions.
3
+ Ruby gem for building AI-powered applications with the [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview). This library essentially wraps the Claude Code CLI, providing both simple one-shot queries and interactive bidirectional sessions.
4
4
 
5
5
  ## Requirements
6
6
 
@@ -95,6 +95,9 @@ options = ClaudeAgent::Options.new(
95
95
  cwd: "/path/to/project",
96
96
  add_dirs: ["/additional/path"],
97
97
 
98
+ # Agent configuration
99
+ agent: "my-agent", # Agent name for main thread
100
+
98
101
  # Session management
99
102
  resume: "session-id",
100
103
  continue_conversation: true,
@@ -456,7 +459,7 @@ All available hook events:
456
459
  | PostToolUseFailure | `PostToolUseFailureInput` | tool_name, tool_input, error, tool_use_id, is_interrupt |
457
460
  | Notification | `NotificationInput` | message, title, notification_type |
458
461
  | UserPromptSubmit | `UserPromptSubmitInput` | prompt |
459
- | SessionStart | `SessionStartInput` | source, agent_type |
462
+ | SessionStart | `SessionStartInput` | source, agent_type, model |
460
463
  | SessionEnd | `SessionEndInput` | reason |
461
464
  | Stop | `StopInput` | stop_hook_active |
462
465
  | SubagentStart | `SubagentStartInput` | agent_id, agent_type |
@@ -591,6 +594,88 @@ puts client.account_info.email
591
594
  client.disconnect
592
595
  ```
593
596
 
597
+ ## V2 Session API (Unstable)
598
+
599
+ > **⚠️ Alpha API**: This API is unstable and may change without notice.
600
+
601
+ The V2 Session API provides a simpler interface for multi-turn conversations, matching the TypeScript SDK's `SDKSession` interface.
602
+
603
+ ### Create a Session
604
+
605
+ ```ruby
606
+ # Create a new session
607
+ session = ClaudeAgent.unstable_v2_create_session(
608
+ model: "claude-sonnet-4-5-20250514",
609
+ permission_mode: "acceptEdits"
610
+ )
611
+
612
+ # Send a message
613
+ session.send("Hello, Claude!")
614
+
615
+ # Stream responses
616
+ session.stream.each do |msg|
617
+ case msg
618
+ when ClaudeAgent::AssistantMessage
619
+ puts msg.text
620
+ when ClaudeAgent::ResultMessage
621
+ puts "Done! Cost: $#{msg.total_cost_usd}"
622
+ end
623
+ end
624
+
625
+ # Continue the conversation
626
+ session.send("Tell me more")
627
+ session.stream.each { |msg| puts msg.text if msg.is_a?(ClaudeAgent::AssistantMessage) }
628
+
629
+ # Close when done
630
+ session.close
631
+ ```
632
+
633
+ ### Resume a Session
634
+
635
+ ```ruby
636
+ # Resume an existing session by ID
637
+ session = ClaudeAgent.unstable_v2_resume_session(
638
+ "session-abc123",
639
+ model: "claude-sonnet-4-5-20250514"
640
+ )
641
+
642
+ session.send("What were we discussing?")
643
+ session.stream.each { |msg| puts msg.text if msg.is_a?(ClaudeAgent::AssistantMessage) }
644
+ session.close
645
+ ```
646
+
647
+ ### One-Shot Prompt
648
+
649
+ ```ruby
650
+ # Simple one-shot prompt (auto-closes session)
651
+ result = ClaudeAgent.unstable_v2_prompt(
652
+ "What is 2 + 2?",
653
+ model: "claude-sonnet-4-5-20250514"
654
+ )
655
+
656
+ puts "Success: #{result.success?}"
657
+ puts "Cost: $#{result.total_cost_usd}"
658
+ ```
659
+
660
+ ### SessionOptions
661
+
662
+ The V2 API uses a simplified options type:
663
+
664
+ ```ruby
665
+ options = ClaudeAgent::SessionOptions.new(
666
+ model: "claude-sonnet-4-5-20250514", # Required
667
+ permission_mode: "acceptEdits", # Optional
668
+ allowed_tools: ["Read", "Grep"], # Optional
669
+ disallowed_tools: ["Write"], # Optional
670
+ can_use_tool: ->(name, input, ctx) { ... }, # Optional
671
+ hooks: { "PreToolUse" => [...] }, # Optional
672
+ env: { "MY_VAR" => "value" }, # Optional
673
+ path_to_claude_code_executable: "/custom/path" # Optional
674
+ )
675
+
676
+ session = ClaudeAgent.unstable_v2_create_session(options)
677
+ ```
678
+
594
679
  ## Types Reference
595
680
 
596
681
  ### Return Types
data/SPEC.md CHANGED
@@ -3,8 +3,8 @@
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.3 (npm package)
7
- - Python SDK: Latest from GitHub (commit 55372da)
6
+ - TypeScript SDK: v0.2.9 (npm package)
7
+ - Python SDK: v0.1.20 from GitHub (commit 04da88d)
8
8
  - Ruby SDK: This repository
9
9
 
10
10
  ---
@@ -64,13 +64,14 @@ Configuration options for SDK queries and clients.
64
64
  | `sandbox` | ✅ | ✅ | ✅ | Sandbox settings |
65
65
  | `settingSources` | ✅ | ✅ | ✅ | Which settings to load |
66
66
  | `plugins` | ✅ | ✅ | ✅ | Plugin configurations |
67
- | `betas` | ✅ | ✅ | ✅ | Beta features (e.g., context-1m) |
67
+ | `betas` | ✅ | ✅ | ✅ | Beta features (e.g., context-1m-2025-08-07) |
68
+ | `agent` | ✅ | ❌ | ✅ | Agent name for main thread |
68
69
  | `abortController` | ✅ | ❌ | ✅ | Cancellation controller |
69
70
  | `stderr` | ✅ | ✅ | ✅ | Stderr callback |
70
71
  | `spawnClaudeCodeProcess` | ✅ | ❌ | ✅ | Custom spawn function |
71
72
  | `pathToClaudeCodeExecutable` | ✅ | ✅ | ✅ | Custom CLI path |
72
- | `executable` | ✅ | | | JS runtime (bun/deno/node) |
73
- | `executableArgs` | ✅ | | | JS runtime args |
73
+ | `executable` | ✅ | N/A | N/A | JS runtime (node/bun/deno) - JS-specific |
74
+ | `executableArgs` | ✅ | N/A | N/A | JS runtime args - JS-specific |
74
75
  | `extraArgs` | ✅ | ✅ | ✅ | Extra CLI arguments |
75
76
  | `user` | ❌ | ✅ | ✅ | User identifier |
76
77
 
@@ -289,7 +290,7 @@ Permission handling and updates.
289
290
  | `updatedPermissions` | ✅ | ✅ | ✅ |
290
291
  | `message` (deny) | ✅ | ✅ | ✅ |
291
292
  | `interrupt` (deny) | ✅ | ✅ | ✅ |
292
- | `toolUseID` | ✅ | ❌ | |
293
+ | `toolUseID` | ✅ | ❌ | |
293
294
 
294
295
  ### Permission Update Types
295
296
 
@@ -316,7 +317,7 @@ Permission handling and updates.
316
317
 
317
318
  | Field | TypeScript | Python | Ruby | Notes |
318
319
  |------------------|:----------:|:------:|:----:|---------------------------|
319
- | `signal` | ✅ | ✅ | | Abort signal |
320
+ | `signal` | ✅ | ✅ | | Abort signal |
320
321
  | `suggestions` | ✅ | ✅ | ✅ | Permission suggestions |
321
322
  | `blockedPath` | ✅ | ✅ | ✅ | Blocked file path |
322
323
  | `decisionReason` | ✅ | ❌ | ✅ | Why permission triggered |
@@ -392,10 +393,10 @@ Session management and resumption.
392
393
 
393
394
  | Feature | TypeScript | Python | Ruby | Notes |
394
395
  |-----------------------------|:----------:|:------:|:----:|---------------------------|
395
- | `SDKSession` interface | ✅ | ❌ | | Multi-turn session object |
396
- | `unstable_v2_createSession` | ✅ | ❌ | | Create new session |
397
- | `unstable_v2_resumeSession` | ✅ | ❌ | | Resume existing session |
398
- | `unstable_v2_prompt` | ✅ | ❌ | | One-shot prompt |
396
+ | `SDKSession` interface | ✅ | ❌ | | Multi-turn session object |
397
+ | `unstable_v2_createSession` | ✅ | ❌ | | Create new session |
398
+ | `unstable_v2_resumeSession` | ✅ | ❌ | | Resume existing session |
399
+ | `unstable_v2_prompt` | ✅ | ❌ | | One-shot prompt |
399
400
 
400
401
  ---
401
402
 
@@ -531,6 +532,7 @@ Public API surface for SDK clients.
531
532
 
532
533
  - ✅ = Fully implemented
533
534
  - ❌ = Not implemented
535
+ - N/A = Not applicable (language-specific feature)
534
536
  - Partial = Partially implemented
535
537
 
536
538
  ---
@@ -541,18 +543,24 @@ Public API surface for SDK clients.
541
543
  - Primary reference for API surface (most comprehensive)
542
544
  - Source is bundled/minified, but `sdk.d.ts` provides complete type definitions
543
545
  - Includes unstable V2 session API
544
- - Version 0.2.3 adds `maxOutputTokens` field to `ModelUsage`
546
+ - Version 0.2.9 adds `agent` option for specifying main thread agent
547
+ - Adds `deno` as supported executable option
548
+ - Includes experimental `criticalSystemReminder_EXPERIMENTAL` for agent definitions
549
+ - `SessionStartHookInput` includes `model` field
545
550
 
546
551
  ### Python SDK
547
- - Full source available
552
+ - Full source available (v0.1.20)
548
553
  - Fewer control protocol features than TypeScript
549
554
  - Does not support SessionStart/SessionEnd/Notification hooks due to setup limitations
550
555
  - Missing several permission modes (delegate, dontAsk)
551
556
  - `excludedCommands` in sandbox now supported
557
+ - `tool_use_id` now included in PreToolUseHookInput
552
558
 
553
559
  ### Ruby SDK (This Repository)
554
- - Aims for TypeScript SDK parity
560
+ - Full TypeScript SDK feature parity achieved
555
561
  - Ruby-idiomatic patterns (Data.define, snake_case)
556
562
  - Complete control protocol support
557
563
  - Dedicated Client class for multi-turn conversations
558
564
  - Full hook event support including all 12 events
565
+ - Full V2 Session API support (unstable)
566
+ - `executable`/`executableArgs` marked N/A (JS runtime options not applicable to Ruby)
@@ -141,14 +141,16 @@ module ClaudeAgent
141
141
  # Input for SessionStart hook (TypeScript SDK parity)
142
142
  #
143
143
  class SessionStartInput < BaseHookInput
144
- attr_reader :source, :agent_type
144
+ attr_reader :source, :agent_type, :model
145
145
 
146
146
  # @param source [String] One of: "startup", "resume", "clear", "compact"
147
147
  # @param agent_type [String, nil] Type of agent if running in subagent context
148
- def initialize(source:, agent_type: nil, **kwargs)
148
+ # @param model [String, nil] Model being used for this session
149
+ def initialize(source:, agent_type: nil, model: nil, **kwargs)
149
150
  super(hook_event_name: "SessionStart", **kwargs)
150
151
  @source = source
151
152
  @agent_type = agent_type
153
+ @model = model
152
154
  end
153
155
  end
154
156
 
@@ -50,7 +50,7 @@ module ClaudeAgent
50
50
  continue_conversation resume fork_session resume_session_at
51
51
  max_turns max_budget_usd max_thinking_tokens
52
52
  strict_mcp_config mcp_servers hooks
53
- settings sandbox cwd add_dirs env user
53
+ settings sandbox cwd add_dirs env user agent
54
54
  cli_path extra_args agents setting_sources plugins
55
55
  include_partial_messages output_format enable_file_checkpointing
56
56
  persist_session betas max_buffer_size stderr_callback
@@ -60,7 +60,9 @@ module ClaudeAgent
60
60
  attr_accessor(*ATTRIBUTES)
61
61
 
62
62
  def initialize(**kwargs)
63
- merged = DEFAULTS.merge(kwargs)
63
+ # Remove nil values so they don't override defaults
64
+ filtered = kwargs.compact
65
+ merged = DEFAULTS.merge(filtered)
64
66
  ATTRIBUTES.each do |attr|
65
67
  instance_variable_set(:"@#{attr}", merged[attr])
66
68
  end
@@ -204,6 +206,7 @@ module ClaudeAgent
204
206
  def environment_args
205
207
  [].tap do |args|
206
208
  args.push("--user", user) if user
209
+ args.push("--agent", agent) if agent
207
210
  add_dirs.each { |dir| args.push("--add-dir", dir.to_s) }
208
211
  args.push("--setting-sources", setting_sources.join(",")) if setting_sources&.any?
209
212
  plugins.each do |plugin|
@@ -5,11 +5,12 @@ module ClaudeAgent
5
5
  #
6
6
  # @example Allow with modified input
7
7
  # PermissionResultAllow.new(
8
- # updated_input: input.merge("safe" => true)
8
+ # updated_input: input.merge("safe" => true),
9
+ # tool_use_id: "tool_123"
9
10
  # )
10
11
  #
11
- PermissionResultAllow = Data.define(:updated_input, :updated_permissions) do
12
- def initialize(updated_input: nil, updated_permissions: nil)
12
+ PermissionResultAllow = Data.define(:updated_input, :updated_permissions, :tool_use_id) do
13
+ def initialize(updated_input: nil, updated_permissions: nil, tool_use_id: nil)
13
14
  super
14
15
  end
15
16
 
@@ -21,6 +22,7 @@ module ClaudeAgent
21
22
  h = { behavior: "allow" }
22
23
  h[:updatedInput] = updated_input if updated_input
23
24
  h[:updatedPermissions] = updated_permissions&.map { |p| p.respond_to?(:to_h) ? p.to_h : p } if updated_permissions
25
+ h[:toolUseID] = tool_use_id if tool_use_id
24
26
  h
25
27
  end
26
28
  end
@@ -30,11 +32,12 @@ module ClaudeAgent
30
32
  # @example Deny with message
31
33
  # PermissionResultDeny.new(
32
34
  # message: "Operation not allowed",
33
- # interrupt: true
35
+ # interrupt: true,
36
+ # tool_use_id: "tool_123"
34
37
  # )
35
38
  #
36
- PermissionResultDeny = Data.define(:message, :interrupt) do
37
- def initialize(message: "", interrupt: false)
39
+ PermissionResultDeny = Data.define(:message, :interrupt, :tool_use_id) do
40
+ def initialize(message: "", interrupt: false, tool_use_id: nil)
38
41
  super
39
42
  end
40
43
 
@@ -43,7 +46,9 @@ module ClaudeAgent
43
46
  end
44
47
 
45
48
  def to_h
46
- { behavior: "deny", message: message, interrupt: interrupt }
49
+ h = { behavior: "deny", message: message, interrupt: interrupt }
50
+ h[:toolUseID] = tool_use_id if tool_use_id
51
+ h
47
52
  end
48
53
  end
49
54
 
@@ -141,7 +146,8 @@ module ClaudeAgent
141
146
  # blocked_path: "/etc/passwd",
142
147
  # decision_reason: "Path outside allowed directories",
143
148
  # tool_use_id: "tool_123",
144
- # agent_id: "agent_456"
149
+ # agent_id: "agent_456",
150
+ # signal: abort_signal
145
151
  # )
146
152
  #
147
153
  ToolPermissionContext = Data.define(
@@ -149,14 +155,16 @@ module ClaudeAgent
149
155
  :blocked_path,
150
156
  :decision_reason,
151
157
  :tool_use_id,
152
- :agent_id
158
+ :agent_id,
159
+ :signal
153
160
  ) do
154
161
  def initialize(
155
162
  permission_suggestions: nil,
156
163
  blocked_path: nil,
157
164
  decision_reason: nil,
158
165
  tool_use_id: nil,
159
- agent_id: nil
166
+ agent_id: nil,
167
+ signal: nil
160
168
  )
161
169
  super
162
170
  end
@@ -0,0 +1,207 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClaudeAgent
4
+ # V2 Session options (subset of full Options)
5
+ # V2 API - UNSTABLE
6
+ # @alpha
7
+ #
8
+ # @example
9
+ # options = SessionOptions.new(
10
+ # model: "claude-sonnet-4-5-20250929",
11
+ # permission_mode: "acceptEdits"
12
+ # )
13
+ #
14
+ SessionOptions = Data.define(
15
+ :model,
16
+ :path_to_claude_code_executable,
17
+ :env,
18
+ :allowed_tools,
19
+ :disallowed_tools,
20
+ :can_use_tool,
21
+ :hooks,
22
+ :permission_mode
23
+ ) do
24
+ def initialize(
25
+ model:,
26
+ path_to_claude_code_executable: nil,
27
+ env: nil,
28
+ allowed_tools: nil,
29
+ disallowed_tools: nil,
30
+ can_use_tool: nil,
31
+ hooks: nil,
32
+ permission_mode: nil
33
+ )
34
+ super
35
+ end
36
+ end
37
+
38
+ # V2 API - UNSTABLE
39
+ # Multi-turn session interface for persistent conversations.
40
+ #
41
+ # This provides a simpler interface than the full Client class,
42
+ # matching the TypeScript SDK's SDKSession interface.
43
+ #
44
+ # @alpha
45
+ #
46
+ # @example Create a session and send messages
47
+ # session = ClaudeAgent.unstable_v2_create_session(model: "claude-sonnet-4-5-20250929")
48
+ # session.send("Hello!")
49
+ # session.stream.each { |msg| puts msg.inspect }
50
+ # session.close
51
+ #
52
+ class Session
53
+ attr_reader :session_id, :options
54
+
55
+ def initialize(options)
56
+ @options = options.is_a?(SessionOptions) ? options : SessionOptions.new(**options)
57
+ @client = nil
58
+ @session_id = nil
59
+ @closed = false
60
+ end
61
+
62
+ # Send a message to the agent
63
+ #
64
+ # @param message [String, UserMessage] The message to send
65
+ # @return [void]
66
+ def send(message)
67
+ ensure_connected!
68
+ content = message.is_a?(String) ? message : message
69
+ @client.send_message(content)
70
+ end
71
+
72
+ # Stream messages from the agent
73
+ #
74
+ # @return [Enumerator<message>] An enumerator of messages
75
+ # @yield [message] Each message received from the agent
76
+ def stream(&block)
77
+ ensure_connected!
78
+ if block_given?
79
+ @client.receive_response(&block)
80
+ else
81
+ @client.receive_response
82
+ end
83
+ end
84
+
85
+ # Close the session
86
+ #
87
+ # @return [void]
88
+ def close
89
+ return if @closed
90
+ @client&.disconnect
91
+ @closed = true
92
+ end
93
+
94
+ # Check if session is closed
95
+ #
96
+ # @return [Boolean]
97
+ def closed?
98
+ @closed
99
+ end
100
+
101
+ private
102
+
103
+ def ensure_connected!
104
+ raise AbortError, "Session is closed" if @closed
105
+ return if @client&.connected?
106
+
107
+ @client = Client.new(options: build_client_options)
108
+ @client.connect
109
+ update_session_id
110
+ end
111
+
112
+ def build_client_options
113
+ Options.new(
114
+ model: @options.model,
115
+ cli_path: @options.path_to_claude_code_executable,
116
+ env: @options.env,
117
+ allowed_tools: @options.allowed_tools,
118
+ disallowed_tools: @options.disallowed_tools,
119
+ can_use_tool: @options.can_use_tool,
120
+ hooks: @options.hooks,
121
+ permission_mode: @options.permission_mode
122
+ )
123
+ end
124
+
125
+ def update_session_id
126
+ # Session ID is typically extracted from the first system message
127
+ # but since we don't have it immediately, we leave it nil until available
128
+ @session_id = @client.server_info&.dig("session_id")
129
+ end
130
+ end
131
+
132
+ class << self
133
+ # V2 API - UNSTABLE
134
+ # Create a persistent session for multi-turn conversations.
135
+ #
136
+ # @param options [Hash, SessionOptions] Session configuration
137
+ # @return [Session] A new session instance
138
+ # @alpha
139
+ #
140
+ # @example
141
+ # session = ClaudeAgent.unstable_v2_create_session(model: "claude-sonnet-4-5-20250929")
142
+ #
143
+ def unstable_v2_create_session(options)
144
+ Session.new(options)
145
+ end
146
+
147
+ # V2 API - UNSTABLE
148
+ # Resume an existing session by ID.
149
+ #
150
+ # @param session_id [String] The session ID to resume
151
+ # @param options [Hash, SessionOptions] Session configuration
152
+ # @return [Session] A session configured to resume the specified session
153
+ # @alpha
154
+ #
155
+ # @example
156
+ # session = ClaudeAgent.unstable_v2_resume_session("session-abc123", model: "claude-sonnet-4-5-20250929")
157
+ #
158
+ def unstable_v2_resume_session(session_id, options)
159
+ # For resumption, we need to pass the resume option through
160
+ # Since SessionOptions doesn't have resume, we handle it in the Client options
161
+ session = Session.new(options)
162
+ session.instance_variable_set(:@resume_session_id, session_id)
163
+
164
+ # Override build_client_options to include resume
165
+ session.define_singleton_method(:build_client_options) do
166
+ Options.new(
167
+ model: @options.model,
168
+ cli_path: @options.path_to_claude_code_executable,
169
+ env: @options.env,
170
+ allowed_tools: @options.allowed_tools,
171
+ disallowed_tools: @options.disallowed_tools,
172
+ can_use_tool: @options.can_use_tool,
173
+ hooks: @options.hooks,
174
+ permission_mode: @options.permission_mode,
175
+ resume: @resume_session_id
176
+ )
177
+ end
178
+
179
+ session
180
+ end
181
+
182
+ # V2 API - UNSTABLE
183
+ # One-shot convenience function for single prompts.
184
+ #
185
+ # @param message [String] The prompt message
186
+ # @param options [Hash, SessionOptions] Session configuration
187
+ # @return [ResultMessage] The result of the query
188
+ # @alpha
189
+ #
190
+ # @example
191
+ # result = ClaudeAgent.unstable_v2_prompt("What files are here?", model: "claude-sonnet-4-5-20250929")
192
+ #
193
+ def unstable_v2_prompt(message, options)
194
+ session = unstable_v2_create_session(options)
195
+ begin
196
+ session.send(message)
197
+ result = nil
198
+ session.stream.each do |msg|
199
+ result = msg if msg.is_a?(ResultMessage)
200
+ end
201
+ result
202
+ ensure
203
+ session.close
204
+ end
205
+ end
206
+ end
207
+ end
@@ -83,7 +83,7 @@ module ClaudeAgent
83
83
  # Per-model usage statistics returned in result messages (TypeScript SDK parity)
84
84
  #
85
85
  # @example
86
- # usage = ModelUsage.new(input_tokens: 100, output_tokens: 50, cost_usd: 0.01)
86
+ # usage = ModelUsage.new(input_tokens: 100, output_tokens: 50, cost_usd: 0.01, max_output_tokens: 4096)
87
87
  #
88
88
  ModelUsage = Data.define(
89
89
  :input_tokens,
@@ -92,7 +92,8 @@ module ClaudeAgent
92
92
  :cache_creation_input_tokens,
93
93
  :web_search_requests,
94
94
  :cost_usd,
95
- :context_window
95
+ :context_window,
96
+ :max_output_tokens
96
97
  ) do
97
98
  def initialize(
98
99
  input_tokens: 0,
@@ -101,7 +102,8 @@ module ClaudeAgent
101
102
  cache_creation_input_tokens: 0,
102
103
  web_search_requests: 0,
103
104
  cost_usd: 0.0,
104
- context_window: nil
105
+ context_window: nil,
106
+ max_output_tokens: nil
105
107
  )
106
108
  super
107
109
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeAgent
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/claude_agent.rb CHANGED
@@ -22,6 +22,7 @@ require_relative "claude_agent/mcp/tool"
22
22
  require_relative "claude_agent/mcp/server"
23
23
  require_relative "claude_agent/query"
24
24
  require_relative "claude_agent/client"
25
+ require_relative "claude_agent/session" # V2 Session API (unstable)
25
26
 
26
27
  module ClaudeAgent
27
28
  # Re-export key classes at module level for convenience
data/sig/claude_agent.rbs CHANGED
@@ -122,8 +122,9 @@ module ClaudeAgent
122
122
  attr_reader web_search_requests: Integer
123
123
  attr_reader cost_usd: Float
124
124
  attr_reader context_window: Integer?
125
+ attr_reader max_output_tokens: Integer?
125
126
 
126
- def initialize: (?input_tokens: Integer, ?output_tokens: Integer, ?cache_read_input_tokens: Integer, ?cache_creation_input_tokens: Integer, ?web_search_requests: Integer, ?cost_usd: Float, ?context_window: Integer?) -> void
127
+ def initialize: (?input_tokens: Integer, ?output_tokens: Integer, ?cache_read_input_tokens: Integer, ?cache_creation_input_tokens: Integer, ?web_search_requests: Integer, ?cost_usd: Float, ?context_window: Integer?, ?max_output_tokens: Integer?) -> void
127
128
  end
128
129
 
129
130
  class SDKPermissionDenial
@@ -278,6 +279,7 @@ module ClaudeAgent
278
279
  attr_accessor add_dirs: Array[String]
279
280
  attr_accessor env: Hash[String, String]
280
281
  attr_accessor user: String?
282
+ attr_accessor agent: String?
281
283
 
282
284
  # CLI configuration
283
285
  attr_accessor cli_path: String?
@@ -632,8 +634,9 @@ module ClaudeAgent
632
634
  class SessionStartInput < BaseHookInput
633
635
  attr_reader source: String
634
636
  attr_reader agent_type: String?
637
+ attr_reader model: String?
635
638
 
636
- def initialize: (source: String, ?agent_type: String?, **untyped) -> void
639
+ def initialize: (source: String, ?agent_type: String?, ?model: String?, **untyped) -> void
637
640
  end
638
641
 
639
642
  class SessionEndInput < BaseHookInput
@@ -687,8 +690,9 @@ module ClaudeAgent
687
690
  class PermissionResultAllow
688
691
  attr_reader updated_input: Hash[String, untyped]?
689
692
  attr_reader updated_permissions: Array[PermissionUpdate]?
693
+ attr_reader tool_use_id: String?
690
694
 
691
- def initialize: (?updated_input: Hash[String, untyped]?, ?updated_permissions: Array[PermissionUpdate]?) -> void
695
+ def initialize: (?updated_input: Hash[String, untyped]?, ?updated_permissions: Array[PermissionUpdate]?, ?tool_use_id: String?) -> void
692
696
  def behavior: () -> "allow"
693
697
  def to_h: () -> Hash[Symbol, untyped]
694
698
  end
@@ -696,8 +700,9 @@ module ClaudeAgent
696
700
  class PermissionResultDeny
697
701
  attr_reader message: String
698
702
  attr_reader interrupt: bool
703
+ attr_reader tool_use_id: String?
699
704
 
700
- def initialize: (?message: String, ?interrupt: bool) -> void
705
+ def initialize: (?message: String, ?interrupt: bool, ?tool_use_id: String?) -> void
701
706
  def behavior: () -> "deny"
702
707
  def to_h: () -> Hash[Symbol, untyped]
703
708
  end
@@ -728,8 +733,9 @@ module ClaudeAgent
728
733
  attr_reader decision_reason: String?
729
734
  attr_reader tool_use_id: String?
730
735
  attr_reader agent_id: String?
736
+ attr_reader signal: AbortSignal?
731
737
 
732
- def initialize: (?permission_suggestions: untyped, ?blocked_path: String?, ?decision_reason: String?, ?tool_use_id: String?, ?agent_id: String?) -> void
738
+ def initialize: (?permission_suggestions: untyped, ?blocked_path: String?, ?decision_reason: String?, ?tool_use_id: String?, ?agent_id: String?, ?signal: AbortSignal?) -> void
733
739
  end
734
740
 
735
741
  # Client
@@ -909,4 +915,39 @@ module ClaudeAgent
909
915
  def to_config: () -> Hash[Symbol, untyped]
910
916
  end
911
917
  end
918
+
919
+ # V2 Session API - UNSTABLE
920
+ # @alpha
921
+
922
+ # V2 Session options (subset of full Options)
923
+ class SessionOptions
924
+ attr_reader model: String
925
+ attr_reader path_to_claude_code_executable: String?
926
+ attr_reader env: Hash[String, String]?
927
+ attr_reader allowed_tools: Array[String]?
928
+ attr_reader disallowed_tools: Array[String]?
929
+ attr_reader can_use_tool: (^(String, Hash[String, untyped], untyped) -> permission_result)?
930
+ attr_reader hooks: Hash[String, Array[HookMatcher]]?
931
+ attr_reader permission_mode: String?
932
+
933
+ def initialize: (model: String, ?path_to_claude_code_executable: String?, ?env: Hash[String, String]?, ?allowed_tools: Array[String]?, ?disallowed_tools: Array[String]?, ?can_use_tool: (^(String, Hash[String, untyped], untyped) -> permission_result)?, ?hooks: Hash[String, Array[HookMatcher]]?, ?permission_mode: String?) -> void
934
+ end
935
+
936
+ # V2 Session interface for multi-turn conversations
937
+ class Session
938
+ attr_reader session_id: String?
939
+ attr_reader options: SessionOptions
940
+
941
+ def initialize: (Hash[Symbol, untyped] | SessionOptions options) -> void
942
+ def send: (String | UserMessage message) -> void
943
+ def stream: () -> Enumerator[message, void]
944
+ | () { (message) -> void } -> void
945
+ def close: () -> void
946
+ def closed?: () -> bool
947
+ end
948
+
949
+ # V2 API module-level methods
950
+ def self.unstable_v2_create_session: (Hash[Symbol, untyped] | SessionOptions options) -> Session
951
+ def self.unstable_v2_resume_session: (String session_id, Hash[Symbol, untyped] | SessionOptions options) -> Session
952
+ def self.unstable_v2_prompt: (String message, Hash[Symbol, untyped] | SessionOptions options) -> ResultMessage
912
953
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: claude_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Carr
@@ -63,6 +63,7 @@ files:
63
63
  - lib/claude_agent/permissions.rb
64
64
  - lib/claude_agent/query.rb
65
65
  - lib/claude_agent/sandbox_settings.rb
66
+ - lib/claude_agent/session.rb
66
67
  - lib/claude_agent/spawn.rb
67
68
  - lib/claude_agent/transport/base.rb
68
69
  - lib/claude_agent/transport/subprocess.rb