claude_agent 0.7.13 → 0.7.14

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: 6e5c5f3de29ca5a58accdb4c6dcc0937ed867fd87579c4909c42ae4d7c82e8d7
4
- data.tar.gz: 9209ef4868fc7d6267c8f215c6e46222d69cf672a8223c4277db35131510c466
3
+ metadata.gz: 6b6188550282e29001c6bf2996842b5c11cd013de37aeeded995c982cef67399
4
+ data.tar.gz: 33e7d2e6b000d5f085093f236fd531c136e3711be170c3af4c11715fbdedda77
5
5
  SHA512:
6
- metadata.gz: c78cf5cc5e99c4b97130950763ce04192cbe10dccc4def0f245d9dae298123a1a56e54a75ea079f23f1d9da1415ff9758f7b2a75943ba34027a602fff12cdf5d
7
- data.tar.gz: 7c3146bd079c24011f2bf95dbd1e12c6a0a81a0dad1634221827138516467df9f344e54813d2281f76bc1e6bd0ff97dd04b0ea81b854222b992f467e541d6c4d
6
+ metadata.gz: b5ec2de8caa5ef32681e671645dd6d6540d58f86221c3d99186cc7ab7e9a076b892fe41c16e2472b94399c296439b5ceba72f573eb0b218b8b2ff507661d162f
7
+ data.tar.gz: c00a1312f295f1f15949cac076155750b2259f5412cfb0cbe6acffa8bcb789927887bb58ebacdc94fd92fa492851f985b975a14bb31abe68b78e23ce4fda8c5d
data/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.14] - 2026-03-14
11
+
12
+ ### Fixed
13
+ - Replace busy-wait polling (`Queue#pop(true)` + `sleep 0.01`) in `ControlProtocol::Messaging#each_message` with blocking `Queue#pop` and `:done` sentinel, eliminating CPU waste and up-to-10ms per-message latency
14
+ - Fix `Conversation#partition_kwargs` misrouting `on_elicitation` (and any future `on_*` Options attributes) as event callbacks instead of forwarding to Options; now uses explicit allowlist derived from `EventHandler::EVENTS`
15
+ - Remove global `ENV["CLAUDE_CODE_ENTRYPOINT"]` mutation from `Client#connect` and `ClaudeAgent.query`; the subprocess already receives this via `Options#to_env`
16
+ - Log stderr callback errors instead of silently swallowing them in `Transport::Subprocess`
17
+
10
18
  ## [0.7.13] - 2026-03-14
11
19
 
12
20
  ### Added
@@ -77,8 +77,6 @@ module ClaudeAgent
77
77
  def connect(prompt: nil)
78
78
  raise CLIConnectionError, "Already connected" if @connected
79
79
 
80
- ENV["CLAUDE_CODE_ENTRYPOINT"] = "sdk-rb-client"
81
-
82
80
  logger.info("client") { "Connecting" }
83
81
  @protocol = ControlProtocol.new(transport: @transport, options: @options)
84
82
  @protocol.permission_queue = @permission_queue
@@ -72,7 +72,8 @@ module ClaudeAgent
72
72
  @condition.broadcast
73
73
  end
74
74
 
75
- # Terminate the transport
75
+ # Unblock the consumer and terminate the transport
76
+ @message_queue.push(:done)
76
77
  @transport.terminate if @transport.respond_to?(:terminate)
77
78
  end
78
79
 
@@ -107,6 +108,8 @@ module ClaudeAgent
107
108
  rescue AbortError
108
109
  logger.debug("protocol") { "Reader thread exiting: abort signal" }
109
110
  @running = false
111
+ ensure
112
+ @message_queue.push(:done)
110
113
  end
111
114
  end
112
115
  end
@@ -26,19 +26,16 @@ module ClaudeAgent
26
26
  def each_message
27
27
  return enum_for(:each_message) unless block_given?
28
28
 
29
- while @running || !@message_queue.empty?
30
- # Check abort signal
29
+ loop do
31
30
  @abort_signal&.check!
32
31
 
32
+ raw = @message_queue.pop # blocks until data available
33
+ break if raw == :done # sentinel from reader_loop
34
+
33
35
  begin
34
- raw = @message_queue.pop(true)
35
36
  message = @parser.parse(raw)
36
37
  yield message
37
- rescue ThreadError
38
- # Queue empty, wait a bit
39
- sleep 0.01
40
38
  rescue AbortError
41
- # Re-raise abort errors
42
39
  raise
43
40
  rescue => e
44
41
  logger.warn("protocol") { "Message parse error: #{e.message}" }
@@ -25,6 +25,28 @@ module ClaudeAgent
25
25
  # protocol.start
26
26
  # protocol.each_message { |msg| process(msg) }
27
27
  #
28
+ # State ownership across modules:
29
+ #
30
+ # Owned by Lifecycle:
31
+ # @running, @reader_thread
32
+ #
33
+ # Owned by RequestHandling:
34
+ # @hook_callbacks
35
+ #
36
+ # Owned by Primitives:
37
+ # write_message, read helpers (stateless)
38
+ #
39
+ # Owned by Commands:
40
+ # interrupt, rewind (stateless, uses @transport)
41
+ #
42
+ # Shared (initialized here, used by multiple modules):
43
+ # @transport, @options, @parser, @server_info
44
+ # @request_counter, @pending_requests, @pending_results (Primitives + RequestHandling)
45
+ # @mutex, @condition (Primitives + Lifecycle + RequestHandling)
46
+ # @message_queue (Lifecycle + Messaging)
47
+ # @abort_signal (Lifecycle + Messaging)
48
+ # @permission_queue (RequestHandling, set externally by Client)
49
+ #
28
50
  class ControlProtocol
29
51
  DEFAULT_TIMEOUT = 60
30
52
  REQUEST_ID_PREFIX = "req"
@@ -78,6 +100,7 @@ module ClaudeAgent
78
100
 
79
101
  # Abort signal from options
80
102
  @abort_signal = options&.abort_signal
103
+ @abort_signal&.on_abort { @message_queue.push(:done) }
81
104
  end
82
105
 
83
106
  private
@@ -193,6 +193,13 @@ module ClaudeAgent
193
193
 
194
194
  private
195
195
 
196
+ # Callback keys derived from EventHandler events + aliases + on_permission
197
+ CALLBACK_KEYS = (
198
+ EventHandler::EVENTS.map { |e| :"on_#{e}" } +
199
+ CALLBACK_ALIASES.keys +
200
+ [ :on_permission ]
201
+ ).freeze
202
+
196
203
  def partition_kwargs(kwargs)
197
204
  callbacks = {}
198
205
  conversation_kwargs = {}
@@ -201,7 +208,7 @@ module ClaudeAgent
201
208
  kwargs.each do |key, value|
202
209
  if CONVERSATION_KEYS.include?(key)
203
210
  conversation_kwargs[key] = value
204
- elsif key.to_s.start_with?("on_")
211
+ elsif CALLBACK_KEYS.include?(key)
205
212
  callbacks[key] = value
206
213
  else
207
214
  options_kwargs[key] = value
@@ -41,8 +41,6 @@ module ClaudeAgent
41
41
  transport ||= Transport::Subprocess.new(options: options)
42
42
 
43
43
  Enumerator.new do |yielder|
44
- # Set entrypoint environment variable
45
- ENV["CLAUDE_CODE_ENTRYPOINT"] = "sdk-rb"
46
44
  query_logger = options.effective_logger
47
45
  query_logger.info("query") { "Starting query" }
48
46
  query_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@@ -387,8 +387,8 @@ module ClaudeAgent
387
387
  @stderr.each_line do |line|
388
388
  # Call callback if provided, otherwise just drain
389
389
  @options.stderr_callback&.call(line.chomp)
390
- rescue
391
- # Ignore callback errors
390
+ rescue => e
391
+ logger.debug("transport") { "stderr callback error: #{e.message}" }
392
392
  end
393
393
  rescue IOError
394
394
  # Stream closed, exit thread
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeAgent
4
- VERSION = "0.7.13"
4
+ VERSION = "0.7.14"
5
5
  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.7.13
4
+ version: 0.7.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Carr