claude-agent-sdk 0.16.3 → 0.16.5
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 +16 -0
- data/README.md +1 -1
- data/lib/claude_agent_sdk/command_builder.rb +11 -0
- data/lib/claude_agent_sdk/fiber_boundary.rb +4 -0
- data/lib/claude_agent_sdk/query.rb +14 -11
- data/lib/claude_agent_sdk/types.rb +34 -4
- data/lib/claude_agent_sdk/version.rb +1 -1
- data/lib/claude_agent_sdk.rb +21 -12
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2fe7bf072c2a3b8448b23bf82c95e7f0a896b347bd43039145458b72e21f301
|
|
4
|
+
data.tar.gz: 1a58f5e31ef7a872aeaf75a3aada1c8e60a264d9ad5e93615b62c42d96179d99
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e76c6cfe62c7b01320edf7a3d659e44fce46921f764132da7ab0f8223bb1d5a4a2b4457f5406b7bc68a1dde91f7af29fd0d4ff565334ed2cae8ad120339bac83
|
|
7
|
+
data.tar.gz: 9e1920a7254f5e27dab4ae88cc5ba6d8ac7430a7ec32e8c9157d80c792a65bee8c258096f52ac20ce69d5bedfd1a629a2c8ef852341c9b03e4aaa631c491d912
|
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.16.5] - 2026-04-24
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `display:` option on `ThinkingConfigAdaptive` and `ThinkingConfigEnabled`, forwarded to the CLI as `--thinking-display <summarized|omitted>`. Opus 4.7 defaults thinking display to `"omitted"` (empty `thinking` field, signature only), so pass `ThinkingConfigAdaptive.new(display: "summarized")` to receive plaintext summarized thinking text. Invalid values raise `ArgumentError` at construction. See [adaptive thinking docs](https://docs.claude.com/en/docs/build-with-claude/adaptive-thinking).
|
|
14
|
+
|
|
15
|
+
### Internal
|
|
16
|
+
- Extracted private `writeln`/`write` helpers in `Client` and `Query` to consolidate the `@transport.write(json + "\n")` pattern across five call sites. Pure refactor; same bytes on the wire.
|
|
17
|
+
|
|
18
|
+
## [0.16.4] - 2026-04-23
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- `Client#receive_response` no longer hangs in interactive Client mode. The 0.16.1 flag-based fix relied on the loop draining via the transport's `:end` sentinel, which only arrives when the CLI subprocess exits — true for one-shot `query()` but never for a `Client` whose CLI stays alive between turns. `receive_response` now drives `QueryHandler#receive_messages` directly so its `break` runs on the same fiber as the underlying `Async::Queue#dequeue` loop and unwinds it. The 0.16.1 regression spec passed only because its stub iterated a finite array; replaced with a real `Async::Queue` driven from a sibling task so a hang now fails the test.
|
|
22
|
+
|
|
23
|
+
### Internal
|
|
24
|
+
- `FiberBoundary` doc-comment now warns that `break`/`return`/`next` cannot cross the thread hop, so SDK-internal loops yielding user callbacks must keep loop control on the outer side of the boundary.
|
|
25
|
+
|
|
10
26
|
## [0.16.3] - 2026-04-23
|
|
11
27
|
|
|
12
28
|
### Changed
|
data/README.md
CHANGED
|
@@ -108,7 +108,7 @@ Add this line to your application's Gemfile:
|
|
|
108
108
|
gem 'claude-agent-sdk', github: 'ya-luotao/claude-agent-sdk-ruby'
|
|
109
109
|
|
|
110
110
|
# Or use a stable version from RubyGems
|
|
111
|
-
gem 'claude-agent-sdk', '~> 0.16.
|
|
111
|
+
gem 'claude-agent-sdk', '~> 0.16.5'
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
And then execute:
|
|
@@ -158,8 +158,10 @@ module ClaudeAgentSDK
|
|
|
158
158
|
case @options.thinking
|
|
159
159
|
when ThinkingConfigAdaptive
|
|
160
160
|
cmd.push("--thinking", "adaptive")
|
|
161
|
+
append_thinking_display(cmd, @options.thinking.display)
|
|
161
162
|
when ThinkingConfigEnabled
|
|
162
163
|
cmd.push("--max-thinking-tokens", @options.thinking.budget_tokens.to_s)
|
|
164
|
+
append_thinking_display(cmd, @options.thinking.display)
|
|
163
165
|
when ThinkingConfigDisabled
|
|
164
166
|
cmd.push("--thinking", "disabled")
|
|
165
167
|
end
|
|
@@ -168,6 +170,15 @@ module ClaudeAgentSDK
|
|
|
168
170
|
end
|
|
169
171
|
end
|
|
170
172
|
|
|
173
|
+
# `--thinking-display` toggles between `"summarized"` (visible thinking
|
|
174
|
+
# text) and `"omitted"` (empty thinking, signature only). Opus 4.7 defaults
|
|
175
|
+
# to `"omitted"`, so pass `display: "summarized"` to see reasoning.
|
|
176
|
+
def append_thinking_display(cmd, display)
|
|
177
|
+
return if display.nil?
|
|
178
|
+
|
|
179
|
+
cmd.push("--thinking-display", display.to_s)
|
|
180
|
+
end
|
|
181
|
+
|
|
171
182
|
# The set of supported levels is model-dependent; the CLI falls back to
|
|
172
183
|
# the highest supported level at or below the one requested
|
|
173
184
|
# (e.g. `xhigh` → `high` on Opus 4.6).
|
|
@@ -23,6 +23,10 @@ module ClaudeAgentSDK
|
|
|
23
23
|
# user's app makes.
|
|
24
24
|
#
|
|
25
25
|
# No-op when no scheduler is active, so it's cheap to use unconditionally.
|
|
26
|
+
#
|
|
27
|
+
# The thread hop severs `break`/`return`/`next` from the surrounding method,
|
|
28
|
+
# so SDK loops yielding user callbacks must keep loop control outside the
|
|
29
|
+
# invoked block (see `Client#receive_response`).
|
|
26
30
|
module FiberBoundary
|
|
27
31
|
module_function
|
|
28
32
|
|
|
@@ -261,7 +261,7 @@ module ClaudeAgentSDK
|
|
|
261
261
|
response: response_data
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
|
-
|
|
264
|
+
writeln(JSON.generate(success_response))
|
|
265
265
|
rescue Async::Stop
|
|
266
266
|
# Cancellation requested; respond with an error so the CLI can unblock.
|
|
267
267
|
cancelled_response = {
|
|
@@ -273,7 +273,7 @@ module ClaudeAgentSDK
|
|
|
273
273
|
error: 'Cancelled'
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
|
-
|
|
276
|
+
writeln(JSON.generate(cancelled_response))
|
|
277
277
|
rescue StandardError => e
|
|
278
278
|
# Send error response
|
|
279
279
|
error_response = {
|
|
@@ -285,7 +285,7 @@ module ClaudeAgentSDK
|
|
|
285
285
|
error: e.message
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
|
-
|
|
288
|
+
writeln(JSON.generate(error_response))
|
|
289
289
|
end
|
|
290
290
|
|
|
291
291
|
def handle_permission_request(request_data)
|
|
@@ -642,7 +642,7 @@ module ClaudeAgentSDK
|
|
|
642
642
|
request: request
|
|
643
643
|
}
|
|
644
644
|
|
|
645
|
-
|
|
645
|
+
writeln(JSON.generate(control_request))
|
|
646
646
|
|
|
647
647
|
# Wait for response with timeout (default 1200s to handle slow CLI startup)
|
|
648
648
|
Async do |task|
|
|
@@ -913,13 +913,8 @@ module ClaudeAgentSDK
|
|
|
913
913
|
def stream_input(stream)
|
|
914
914
|
stream.each do |message|
|
|
915
915
|
break if @closed
|
|
916
|
-
serialized =
|
|
917
|
-
|
|
918
|
-
else
|
|
919
|
-
message.to_s
|
|
920
|
-
end
|
|
921
|
-
serialized += "\n" unless serialized.end_with?("\n")
|
|
922
|
-
@transport.write(serialized)
|
|
916
|
+
serialized = message.is_a?(Hash) ? JSON.generate(message) : message.to_s
|
|
917
|
+
writeln(serialized)
|
|
923
918
|
end
|
|
924
919
|
rescue StandardError => e
|
|
925
920
|
# Log error but don't raise
|
|
@@ -928,6 +923,14 @@ module ClaudeAgentSDK
|
|
|
928
923
|
wait_for_result_and_end_input
|
|
929
924
|
end
|
|
930
925
|
|
|
926
|
+
def writeln(string)
|
|
927
|
+
write string.end_with?("\n") ? string : "#{string}\n"
|
|
928
|
+
end
|
|
929
|
+
|
|
930
|
+
def write(string)
|
|
931
|
+
@transport.write(string)
|
|
932
|
+
end
|
|
933
|
+
|
|
931
934
|
# Receive SDK messages (not control messages)
|
|
932
935
|
def receive_messages(&block)
|
|
933
936
|
return enum_for(:receive_messages) unless block
|
|
@@ -599,23 +599,53 @@ module ClaudeAgentSDK
|
|
|
599
599
|
end
|
|
600
600
|
|
|
601
601
|
# Thinking configuration types
|
|
602
|
+
#
|
|
603
|
+
# `display` controls how thinking content appears in responses. Valid values
|
|
604
|
+
# are `"summarized"` (plaintext summary) and `"omitted"` (empty thinking
|
|
605
|
+
# field, signature only). Defaults are model-dependent: Opus 4.6/Sonnet 4.6
|
|
606
|
+
# default to `"summarized"`; Opus 4.7 and Mythos Preview default to
|
|
607
|
+
# `"omitted"`. Pass `display: "summarized"` explicitly on Opus 4.7 to get
|
|
608
|
+
# visible thinking text. Not supported with `ThinkingConfigDisabled`.
|
|
609
|
+
THINKING_DISPLAY_VALUES = %w[summarized omitted].freeze
|
|
602
610
|
|
|
603
611
|
# Adaptive thinking: uses a default budget of 32000 tokens
|
|
604
612
|
class ThinkingConfigAdaptive
|
|
605
|
-
attr_accessor :type
|
|
613
|
+
attr_accessor :type, :display
|
|
606
614
|
|
|
607
|
-
def initialize
|
|
615
|
+
def initialize(display: nil)
|
|
608
616
|
@type = 'adaptive'
|
|
617
|
+
@display = validate_display(display)
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
private
|
|
621
|
+
|
|
622
|
+
def validate_display(value)
|
|
623
|
+
return nil if value.nil?
|
|
624
|
+
return value if THINKING_DISPLAY_VALUES.include?(value.to_s)
|
|
625
|
+
|
|
626
|
+
raise ArgumentError,
|
|
627
|
+
"invalid thinking display #{value.inspect}; expected one of #{THINKING_DISPLAY_VALUES.inspect}"
|
|
609
628
|
end
|
|
610
629
|
end
|
|
611
630
|
|
|
612
631
|
# Enabled thinking: uses a user-specified budget
|
|
613
632
|
class ThinkingConfigEnabled
|
|
614
|
-
attr_accessor :type, :budget_tokens
|
|
633
|
+
attr_accessor :type, :budget_tokens, :display
|
|
615
634
|
|
|
616
|
-
def initialize(budget_tokens:)
|
|
635
|
+
def initialize(budget_tokens:, display: nil)
|
|
617
636
|
@type = 'enabled'
|
|
618
637
|
@budget_tokens = budget_tokens
|
|
638
|
+
@display = validate_display(display)
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
private
|
|
642
|
+
|
|
643
|
+
def validate_display(value)
|
|
644
|
+
return nil if value.nil?
|
|
645
|
+
return value if THINKING_DISPLAY_VALUES.include?(value.to_s)
|
|
646
|
+
|
|
647
|
+
raise ArgumentError,
|
|
648
|
+
"invalid thinking display #{value.inspect}; expected one of #{THINKING_DISPLAY_VALUES.inspect}"
|
|
619
649
|
end
|
|
620
650
|
end
|
|
621
651
|
|
data/lib/claude_agent_sdk.rb
CHANGED
|
@@ -374,9 +374,7 @@ module ClaudeAgentSDK
|
|
|
374
374
|
query(prompt)
|
|
375
375
|
else
|
|
376
376
|
prompt.each do |message_json|
|
|
377
|
-
message_json
|
|
378
|
-
message_json += "\n" unless message_json.end_with?("\n")
|
|
379
|
-
@transport.write(message_json)
|
|
377
|
+
writeln(message_json.to_s)
|
|
380
378
|
end
|
|
381
379
|
end
|
|
382
380
|
end
|
|
@@ -394,7 +392,7 @@ module ClaudeAgentSDK
|
|
|
394
392
|
parent_tool_use_id: nil,
|
|
395
393
|
session_id: session_id
|
|
396
394
|
}
|
|
397
|
-
|
|
395
|
+
writeln(JSON.generate(message))
|
|
398
396
|
end
|
|
399
397
|
|
|
400
398
|
# Receive all messages from Claude
|
|
@@ -418,15 +416,18 @@ module ClaudeAgentSDK
|
|
|
418
416
|
def receive_response(&block)
|
|
419
417
|
return enum_for(:receive_response) unless block
|
|
420
418
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
#
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
419
|
+
raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected
|
|
420
|
+
|
|
421
|
+
# Keep `break` on the same fiber as the underlying dequeue. Going through
|
|
422
|
+
# Client#receive_messages would put the FiberBoundary hop above the break
|
|
423
|
+
# and hang in Client mode — the CLI keeps stdin open and never emits `:end`.
|
|
424
|
+
@query_handler.receive_messages do |data|
|
|
425
|
+
message = MessageParser.parse(data)
|
|
426
|
+
next unless message
|
|
427
427
|
|
|
428
|
-
|
|
429
|
-
|
|
428
|
+
ClaudeAgentSDK.notify_observers(@resolved_observers, :on_message, message)
|
|
429
|
+
FiberBoundary.invoke { block.call(message) }
|
|
430
|
+
break if message.is_a?(ResultMessage)
|
|
430
431
|
end
|
|
431
432
|
end
|
|
432
433
|
|
|
@@ -554,5 +555,13 @@ module ClaudeAgentSDK
|
|
|
554
555
|
end
|
|
555
556
|
nil
|
|
556
557
|
end
|
|
558
|
+
|
|
559
|
+
def writeln(string)
|
|
560
|
+
write string.end_with?("\n") ? string : "#{string}\n"
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
def write(string)
|
|
564
|
+
@transport.write(string)
|
|
565
|
+
end
|
|
557
566
|
end
|
|
558
567
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: claude-agent-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.16.
|
|
4
|
+
version: 0.16.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Community Contributors
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-04-
|
|
10
|
+
date: 2026-04-24 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: async
|