claude-agent-sdk 0.37.0 → 1.1.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 +4 -4
- data/CHANGELOG.md +37 -0
- data/README.md +6 -2
- data/UPGRADING-1.0.md +151 -0
- data/docs/client.md +11 -0
- data/docs/configuration.md +42 -0
- data/docs/errors.md +6 -0
- data/docs/sessions.md +20 -1
- data/docs/types.md +17 -14
- data/lib/claude_agent_sdk/cli_installer.rb +1 -1
- data/lib/claude_agent_sdk/deprecation.rb +1 -40
- data/lib/claude_agent_sdk/errors.rb +10 -0
- data/lib/claude_agent_sdk/query.rb +320 -56
- data/lib/claude_agent_sdk/session_resume.rb +11 -5
- data/lib/claude_agent_sdk/subprocess_cli_transport.rb +25 -0
- data/lib/claude_agent_sdk/types/attributes.rb +14 -49
- data/lib/claude_agent_sdk/types/base.rb +2 -0
- data/lib/claude_agent_sdk/types/messages.rb +7 -1
- data/lib/claude_agent_sdk/types/options.rb +69 -12
- data/lib/claude_agent_sdk/version.rb +1 -1
- data/lib/claude_agent_sdk.rb +28 -18
- data/sig/claude_agent_sdk/cancellation_signal.rbs +14 -0
- data/sig/claude_agent_sdk/configuration.rbs +14 -0
- data/sig/claude_agent_sdk/errors.rbs +86 -0
- data/sig/claude_agent_sdk/observer.rbs +42 -0
- data/sig/claude_agent_sdk/railtie.rbs +10 -0
- data/sig/claude_agent_sdk/sdk_mcp_server.rbs +76 -0
- data/sig/claude_agent_sdk/session_store.rbs +105 -0
- data/sig/claude_agent_sdk/streaming.rbs +15 -0
- data/sig/claude_agent_sdk/transport.rbs +98 -0
- data/sig/claude_agent_sdk/types/base.rbs +39 -0
- data/sig/claude_agent_sdk/types/content_blocks.rbs +79 -0
- data/sig/claude_agent_sdk/types/hooks.rbs +528 -0
- data/sig/claude_agent_sdk/types/mcp.rbs +216 -0
- data/sig/claude_agent_sdk/types/messages.rbs +586 -0
- data/sig/claude_agent_sdk/types/option_values.rbs +245 -0
- data/sig/claude_agent_sdk/types/options.rbs +297 -0
- data/sig/claude_agent_sdk/types/permissions.rbs +108 -0
- data/sig/claude_agent_sdk/types/sessions.rbs +66 -0
- data/sig/claude_agent_sdk.rbs +231 -0
- data/sig/manifest.yaml +5 -0
- metadata +23 -2
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../deprecation'
|
|
4
|
-
|
|
5
3
|
module ClaudeAgentSDK
|
|
6
4
|
# Attribute declarations and the rules #[], #[]=, .new and the camelCase
|
|
7
5
|
# readers follow (issue #126). Loaded by base.rb right after Type itself,
|
|
8
6
|
# before any subclass declares an attribute.
|
|
9
7
|
class Type
|
|
10
|
-
# The 1.0 switch for attribute access, false through 0.x. When true:
|
|
11
|
-
# an unknown key on a strict type (see .strict_attributes) raises
|
|
12
|
-
# ArgumentError, and #[], #[]= and the camelCase readers reach declared
|
|
13
|
-
# attributes only. While false, both cases warn once per class and name.
|
|
14
|
-
ENFORCE_ATTRIBUTES = false
|
|
15
|
-
|
|
16
8
|
LENIENT_KEY = :__claude_agent_sdk_lenient_attributes
|
|
17
|
-
private_constant :
|
|
9
|
+
private_constant :LENIENT_KEY
|
|
18
10
|
|
|
19
11
|
class << self
|
|
20
12
|
# attr_accessor / attr_reader / attr_writer also declare the names as
|
|
@@ -108,9 +100,9 @@ module ClaudeAgentSDK
|
|
|
108
100
|
|
|
109
101
|
# Declares a type the user constructs and passes IN (option values, hook
|
|
110
102
|
# matchers and outputs, permission results and updates). Constructing
|
|
111
|
-
# one directly (.new or #[]=) with a key that is not an attribute
|
|
112
|
-
#
|
|
113
|
-
#
|
|
103
|
+
# one directly (.new or #[]=) with a key that is not an attribute raises
|
|
104
|
+
# ArgumentError — a typo would otherwise be dropped silently (0.37 warned
|
|
105
|
+
# here; 1.0 raises). A read-only attribute (the +type+,
|
|
114
106
|
# +hook_event_name+ or +behavior+ discriminator a type sets itself, which
|
|
115
107
|
# its own #to_h emits) is accepted and ignored. Types the SDK parses from
|
|
116
108
|
# CLI output stay lenient so a newer CLI's extra fields never break an
|
|
@@ -151,15 +143,14 @@ module ClaudeAgentSDK
|
|
|
151
143
|
self.class.cache_attribute_reader(method_name, normalized.to_sym)
|
|
152
144
|
return public_send(normalized, ...)
|
|
153
145
|
end
|
|
154
|
-
return public_send(normalized, ...) if
|
|
146
|
+
return public_send(normalized, ...) if user_defined_method?(normalized)
|
|
155
147
|
end
|
|
156
148
|
super
|
|
157
149
|
end
|
|
158
150
|
|
|
159
151
|
def respond_to_missing?(method_name, include_private = false)
|
|
160
152
|
normalized = normalize_name(method_name)
|
|
161
|
-
(normalized != method_name.to_s && respond_to?(normalized) &&
|
|
162
|
-
(!ENFORCE_ATTRIBUTES || attribute_method?(normalized))) || super
|
|
153
|
+
(normalized != method_name.to_s && respond_to?(normalized) && attribute_method?(normalized)) || super
|
|
163
154
|
end
|
|
164
155
|
|
|
165
156
|
def assign_attributes(attributes)
|
|
@@ -184,12 +175,12 @@ module ClaudeAgentSDK
|
|
|
184
175
|
self.class.cache_attribute_writer(name, setter)
|
|
185
176
|
return public_send(setter, value)
|
|
186
177
|
end
|
|
187
|
-
return public_send(setter, value) if
|
|
178
|
+
return public_send(setter, value) if user_defined_method?(setter.to_s)
|
|
188
179
|
end
|
|
189
180
|
return unless self.class.strict_attributes? && !Thread.current[LENIENT_KEY] && !self.class.attribute?(normalized)
|
|
190
181
|
return if respond_to?(normalized) && user_defined_method?(normalized)
|
|
191
182
|
|
|
192
|
-
unknown_attribute(name
|
|
183
|
+
unknown_attribute(name)
|
|
193
184
|
end
|
|
194
185
|
|
|
195
186
|
def read_attribute(name)
|
|
@@ -202,7 +193,7 @@ module ClaudeAgentSDK
|
|
|
202
193
|
if self.class.attribute_method?(getter)
|
|
203
194
|
self.class.cache_attribute_reader(name, getter.to_sym)
|
|
204
195
|
public_send(getter)
|
|
205
|
-
elsif
|
|
196
|
+
elsif user_defined_method?(getter)
|
|
206
197
|
public_send(getter)
|
|
207
198
|
end
|
|
208
199
|
end
|
|
@@ -234,38 +225,12 @@ module ClaudeAgentSDK
|
|
|
234
225
|
!name.nil? && (name == 'ClaudeAgentSDK' || name.start_with?('ClaudeAgentSDK::'))
|
|
235
226
|
end
|
|
236
227
|
|
|
237
|
-
#
|
|
238
|
-
#
|
|
239
|
-
|
|
240
|
-
# treated as undefined from 1.0.
|
|
241
|
-
def reachable?(method_name, name, access)
|
|
242
|
-
return true if attribute_method?(method_name)
|
|
243
|
-
return false if ENFORCE_ATTRIBUTES
|
|
244
|
-
|
|
245
|
-
class_name = self.class.name || self.class.inspect
|
|
246
|
-
message = case access
|
|
247
|
-
when :read then "#{class_name}#[]: #{name.inspect} is not an attribute; " \
|
|
248
|
-
'Type#[] will only read attributes in 1.0'
|
|
249
|
-
when :write then "#{class_name}#[]=: #{name.inspect} is not an attribute; " \
|
|
250
|
-
'Type#[]= and .new will only write attributes in 1.0'
|
|
251
|
-
else "#{class_name}##{name}: #{method_name} is not an attribute; " \
|
|
252
|
-
'camelCase methods will only reach attributes in 1.0'
|
|
253
|
-
end
|
|
254
|
-
Deprecation.warn_once_at_caller([:non_attribute, self.class, method_name], message)
|
|
255
|
-
true
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
def unknown_attribute(name, normalized)
|
|
228
|
+
# A key that is not an attribute, on a strict type: a typo the user
|
|
229
|
+
# would otherwise never see.
|
|
230
|
+
def unknown_attribute(name)
|
|
259
231
|
klass = self.class
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
raise ArgumentError, "#{class_name}: unknown attribute #{name.inspect} (known: #{known})" if ENFORCE_ATTRIBUTES
|
|
263
|
-
|
|
264
|
-
Deprecation.warn_once_at_caller(
|
|
265
|
-
[:unknown_attribute, klass, normalized],
|
|
266
|
-
"#{class_name}: unknown attribute #{name.inspect} ignored; " \
|
|
267
|
-
"this will raise ArgumentError in 1.0 (known: #{known})"
|
|
268
|
-
)
|
|
232
|
+
raise ArgumentError, "#{klass.name || klass.inspect}: unknown attribute #{name.inspect} " \
|
|
233
|
+
"(known: #{klass.attribute_names.join(', ')})"
|
|
269
234
|
end
|
|
270
235
|
end
|
|
271
236
|
end
|
|
@@ -158,6 +158,8 @@ module ClaudeAgentSDK
|
|
|
158
158
|
# `seen` holds the Types/containers on the current rendering path (not
|
|
159
159
|
# every one rendered so far), so a shared-but-acyclic value still renders
|
|
160
160
|
# in full wherever it appears.
|
|
161
|
+
#
|
|
162
|
+
# @api private
|
|
161
163
|
def inspect_with(depth, seen)
|
|
162
164
|
return "#<#{inspect_class_name} …>" if depth > INSPECT_MAX_DEPTH || seen.key?(self)
|
|
163
165
|
|
|
@@ -192,7 +192,13 @@ module ClaudeAgentSDK
|
|
|
192
192
|
:outcome # "success", "error", or "cancelled"
|
|
193
193
|
end
|
|
194
194
|
|
|
195
|
-
# Session state changed system message
|
|
195
|
+
# Session state changed system message.
|
|
196
|
+
#
|
|
197
|
+
# Reaches your code only when you opt in with
|
|
198
|
+
# `CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS=1` in ClaudeAgentOptions#env. The
|
|
199
|
+
# SDK also asks the CLI for these frames on its own behalf (to tell when a
|
|
200
|
+
# query() run is over), but those arrive marked `sdk_host_only` and are
|
|
201
|
+
# dropped before the message stream.
|
|
196
202
|
class SessionStateChangedMessage < SystemMessage
|
|
197
203
|
attr_accessor :uuid, :session_id,
|
|
198
204
|
:state # "idle", "running", or "requires_action"
|
|
@@ -81,21 +81,11 @@ module ClaudeAgentSDK
|
|
|
81
81
|
self.include_hook_events = false
|
|
82
82
|
self.strict_mcp_config = false
|
|
83
83
|
self.forward_subagent_text = false
|
|
84
|
+
self.verbatim_prompts = false
|
|
84
85
|
|
|
85
86
|
super(merge_with_defaults(attributes || {}))
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
self.env ||= {}
|
|
89
|
-
self.extra_args ||= {}
|
|
90
|
-
self.mcp_servers ||= {}
|
|
91
|
-
self.add_dirs ||= []
|
|
92
|
-
self.observers ||= []
|
|
93
|
-
self.allowed_tools ||= []
|
|
94
|
-
self.disallowed_tools ||= []
|
|
95
|
-
self.session_store_flush ||= 'batched'
|
|
96
|
-
# 0 is a valid (immediate) timeout, so only fill in the default for nil.
|
|
97
|
-
self.load_timeout_ms = 60_000 if load_timeout_ms.nil?
|
|
98
|
-
self.callback_scheduling = :thread if callback_scheduling.nil?
|
|
88
|
+
fill_nil_defaults
|
|
99
89
|
end
|
|
100
90
|
|
|
101
91
|
def dup_with(**changes)
|
|
@@ -203,6 +193,58 @@ module ClaudeAgentSDK
|
|
|
203
193
|
@forward_subagent_text = coerce_boolean(value)
|
|
204
194
|
end
|
|
205
195
|
|
|
196
|
+
# Deliver every prompt to Claude as written.
|
|
197
|
+
#
|
|
198
|
+
# When true, every user message the SDK sends is marked `client_composed`:
|
|
199
|
+
# a String prompt to {ClaudeAgentSDK.query}, {Client#connect} or
|
|
200
|
+
# {Client#query}, and every message of a streamed (Enumerable) prompt to
|
|
201
|
+
# any of them. Claude Code then delivers the text exactly as given: no
|
|
202
|
+
# `@path` file-mention expansion and no slash-command dispatch. Use it when
|
|
203
|
+
# the prompt is assembled from content your end user did not type (earlier
|
|
204
|
+
# turns, tool output, third-party text), so an `@/absolute/path` inside it
|
|
205
|
+
# cannot make Claude Code read a local file. `tools: []`, `allowed_tools`
|
|
206
|
+
# and `disallowed_tools` do not stop that expansion: it happens before the
|
|
207
|
+
# model runs, without a tool call.
|
|
208
|
+
#
|
|
209
|
+
# While the option is on there is no per-message opt-out: a
|
|
210
|
+
# `client_composed` key on a streamed message Hash (either spelling) is
|
|
211
|
+
# overwritten. For per-turn control, leave the option off and set
|
|
212
|
+
# `client_composed: true` on individual streamed messages. The caller's
|
|
213
|
+
# Hashes are never mutated. A streamed JSONL String is parsed, marked and
|
|
214
|
+
# re-serialized; one that is not a single JSON object raises
|
|
215
|
+
# `ArgumentError` rather than being sent unmarked (on the background
|
|
216
|
+
# streaming paths that ends the stream with a warning, like any other
|
|
217
|
+
# stream error).
|
|
218
|
+
#
|
|
219
|
+
# On current Claude Code versions a turn delivered this way also skips the
|
|
220
|
+
# turn-start attachment pass as a whole: `@server:resource` MCP mentions
|
|
221
|
+
# are not expanded either, and the prompt goes without the context Claude
|
|
222
|
+
# Code normally attaches (nested `CLAUDE.md` and rules files, skill and
|
|
223
|
+
# tool listings, other per-turn reminders). The pass between tool calls is
|
|
224
|
+
# unaffected, so most of that context arrives after the turn's first tool
|
|
225
|
+
# call instead.
|
|
226
|
+
#
|
|
227
|
+
# Requires Claude Code 2.1.248 or later; older versions ignore the field,
|
|
228
|
+
# so prompts are still expanded there, and the SDK warns when it connects
|
|
229
|
+
# to one with this option on. Read once when the session starts. Not a
|
|
230
|
+
# CLI flag. Matches the Python SDK's `verbatim_prompts`.
|
|
231
|
+
#
|
|
232
|
+
# Assigning coerces to a Boolean; {#verbatim_prompts?} is the predicate
|
|
233
|
+
# form.
|
|
234
|
+
#
|
|
235
|
+
# @return [Boolean]
|
|
236
|
+
attr_reader :verbatim_prompts
|
|
237
|
+
|
|
238
|
+
# @return [Boolean] {#verbatim_prompts}, as a strict Boolean.
|
|
239
|
+
def verbatim_prompts?
|
|
240
|
+
!!verbatim_prompts
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# @see #verbatim_prompts
|
|
244
|
+
def verbatim_prompts=(value)
|
|
245
|
+
@verbatim_prompts = coerce_boolean(value)
|
|
246
|
+
end
|
|
247
|
+
|
|
206
248
|
# Request model-generated progress summaries for subagent (`local_agent`)
|
|
207
249
|
# tasks. `true` *requests* generation: while the CLI has it enabled, a
|
|
208
250
|
# subagent's {TaskProgressMessage#summary} **may** carry a one-line status.
|
|
@@ -288,6 +330,21 @@ module ClaudeAgentSDK
|
|
|
288
330
|
|
|
289
331
|
private
|
|
290
332
|
|
|
333
|
+
# Non-nil defaults for options that need them.
|
|
334
|
+
def fill_nil_defaults
|
|
335
|
+
self.env ||= {}
|
|
336
|
+
self.extra_args ||= {}
|
|
337
|
+
self.mcp_servers ||= {}
|
|
338
|
+
self.add_dirs ||= []
|
|
339
|
+
self.observers ||= []
|
|
340
|
+
self.allowed_tools ||= []
|
|
341
|
+
self.disallowed_tools ||= []
|
|
342
|
+
self.session_store_flush ||= 'batched'
|
|
343
|
+
# 0 is a valid (immediate) timeout, so only fill in the default for nil.
|
|
344
|
+
self.load_timeout_ms = 60_000 if load_timeout_ms.nil?
|
|
345
|
+
self.callback_scheduling = :thread if callback_scheduling.nil?
|
|
346
|
+
end
|
|
347
|
+
|
|
291
348
|
# Strict key validation: unlike other Type subclasses (which silently drop
|
|
292
349
|
# unknown keys for forward-compat with newer CLI output), ClaudeAgentOptions
|
|
293
350
|
# is a developer-facing config object — typos should fail loudly.
|
data/lib/claude_agent_sdk.rb
CHANGED
|
@@ -541,27 +541,27 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
541
541
|
SessionSummary.fold_session_summary(prev, key, entries)
|
|
542
542
|
end
|
|
543
543
|
|
|
544
|
-
# ---- Deprecated store twins (removed in
|
|
544
|
+
# ---- Deprecated store twins (removed in 2.0) ----
|
|
545
545
|
#
|
|
546
546
|
# Each forwards to the same implementation as before — not to the merged
|
|
547
547
|
# function, so a nil session_store keeps failing as it always did instead
|
|
548
548
|
# of silently reading local disk — after one warning per method per process.
|
|
549
549
|
|
|
550
|
-
# @deprecated Use {.list_sessions} with +session_store:+. Removed in
|
|
550
|
+
# @deprecated Use {.list_sessions} with +session_store:+. Removed in 2.0.
|
|
551
551
|
# @return [Array<SDKSessionInfo>] sorted by last_modified descending
|
|
552
552
|
def self.list_sessions_from_store(session_store:, directory: nil, limit: nil, offset: 0)
|
|
553
553
|
Deprecation.warn_once(:list_sessions_from_store, 'list_sessions(session_store: store)')
|
|
554
554
|
Sessions.list_sessions_from_store(session_store: session_store, directory: directory, limit: limit, offset: offset)
|
|
555
555
|
end
|
|
556
556
|
|
|
557
|
-
# @deprecated Use {.get_session_info} with +session_store:+. Removed in
|
|
557
|
+
# @deprecated Use {.get_session_info} with +session_store:+. Removed in 2.0.
|
|
558
558
|
# @return [SDKSessionInfo, nil]
|
|
559
559
|
def self.get_session_info_from_store(session_store:, session_id:, directory: nil)
|
|
560
560
|
Deprecation.warn_once(:get_session_info_from_store, 'get_session_info(session_store: store, ...)')
|
|
561
561
|
Sessions.get_session_info_from_store(session_store: session_store, session_id: session_id, directory: directory)
|
|
562
562
|
end
|
|
563
563
|
|
|
564
|
-
# @deprecated Use {.get_session_messages} with +session_store:+. Removed in
|
|
564
|
+
# @deprecated Use {.get_session_messages} with +session_store:+. Removed in 2.0.
|
|
565
565
|
# @return [Array<SessionMessage>]
|
|
566
566
|
def self.get_session_messages_from_store(session_store:, session_id:, directory: nil, limit: nil, offset: 0)
|
|
567
567
|
Deprecation.warn_once(:get_session_messages_from_store, 'get_session_messages(session_store: store, ...)')
|
|
@@ -569,14 +569,14 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
569
569
|
directory: directory, limit: limit, offset: offset)
|
|
570
570
|
end
|
|
571
571
|
|
|
572
|
-
# @deprecated Use {.list_subagents} with +session_store:+. Removed in
|
|
572
|
+
# @deprecated Use {.list_subagents} with +session_store:+. Removed in 2.0.
|
|
573
573
|
# @return [Array<String>]
|
|
574
574
|
def self.list_subagents_from_store(session_store:, session_id:, directory: nil)
|
|
575
575
|
Deprecation.warn_once(:list_subagents_from_store, 'list_subagents(session_store: store, ...)')
|
|
576
576
|
Sessions.list_subagents_from_store(session_store: session_store, session_id: session_id, directory: directory)
|
|
577
577
|
end
|
|
578
578
|
|
|
579
|
-
# @deprecated Use {.get_subagent_metadata} with +session_store:+. Removed in
|
|
579
|
+
# @deprecated Use {.get_subagent_metadata} with +session_store:+. Removed in 2.0.
|
|
580
580
|
# @return [Hash{String => Object}, nil]
|
|
581
581
|
def self.get_subagent_metadata_from_store(session_store:, session_id:, agent_id:, directory: nil)
|
|
582
582
|
Deprecation.warn_once(:get_subagent_metadata_from_store, 'get_subagent_metadata(session_store: store, ...)')
|
|
@@ -584,7 +584,7 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
584
584
|
agent_id: agent_id, directory: directory)
|
|
585
585
|
end
|
|
586
586
|
|
|
587
|
-
# @deprecated Use {.get_subagent_messages} with +session_store:+. Removed in
|
|
587
|
+
# @deprecated Use {.get_subagent_messages} with +session_store:+. Removed in 2.0.
|
|
588
588
|
# @return [Array<SessionMessage>]
|
|
589
589
|
def self.get_subagent_messages_from_store(session_store:, session_id:, agent_id:, directory: nil, limit: nil,
|
|
590
590
|
offset: 0)
|
|
@@ -593,28 +593,28 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
593
593
|
agent_id: agent_id, directory: directory, limit: limit, offset: offset)
|
|
594
594
|
end
|
|
595
595
|
|
|
596
|
-
# @deprecated Use {.rename_session} with +session_store:+. Removed in
|
|
596
|
+
# @deprecated Use {.rename_session} with +session_store:+. Removed in 2.0.
|
|
597
597
|
def self.rename_session_via_store(session_store:, session_id:, title:, directory: nil)
|
|
598
598
|
Deprecation.warn_once(:rename_session_via_store, 'rename_session(session_store: store, ...)')
|
|
599
599
|
SessionMutations.rename_session_via_store(session_store: session_store, session_id: session_id,
|
|
600
600
|
title: title, directory: directory)
|
|
601
601
|
end
|
|
602
602
|
|
|
603
|
-
# @deprecated Use {.tag_session} with +session_store:+. Removed in
|
|
603
|
+
# @deprecated Use {.tag_session} with +session_store:+. Removed in 2.0.
|
|
604
604
|
def self.tag_session_via_store(session_store:, session_id:, tag:, directory: nil)
|
|
605
605
|
Deprecation.warn_once(:tag_session_via_store, 'tag_session(session_store: store, ...)')
|
|
606
606
|
SessionMutations.tag_session_via_store(session_store: session_store, session_id: session_id,
|
|
607
607
|
tag: tag, directory: directory)
|
|
608
608
|
end
|
|
609
609
|
|
|
610
|
-
# @deprecated Use {.delete_session} with +session_store:+. Removed in
|
|
610
|
+
# @deprecated Use {.delete_session} with +session_store:+. Removed in 2.0.
|
|
611
611
|
def self.delete_session_via_store(session_store:, session_id:, directory: nil)
|
|
612
612
|
Deprecation.warn_once(:delete_session_via_store, 'delete_session(session_store: store, ...)')
|
|
613
613
|
SessionMutations.delete_session_via_store(session_store: session_store, session_id: session_id,
|
|
614
614
|
directory: directory)
|
|
615
615
|
end
|
|
616
616
|
|
|
617
|
-
# @deprecated Use {.fork_session} with +session_store:+. Removed in
|
|
617
|
+
# @deprecated Use {.fork_session} with +session_store:+. Removed in 2.0.
|
|
618
618
|
# @return [ForkSessionResult]
|
|
619
619
|
def self.fork_session_via_store(session_store:, session_id:, directory: nil, up_to_message_id: nil, title: nil)
|
|
620
620
|
Deprecation.warn_once(:fork_session_via_store, 'fork_session(session_store: store, ...)')
|
|
@@ -749,7 +749,9 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
749
749
|
forward_subagent_text: configured_options.forward_subagent_text?,
|
|
750
750
|
agent_progress_summaries: configured_options.agent_progress_summaries,
|
|
751
751
|
callback_scheduling: callback_scheduling,
|
|
752
|
-
callback_wrapper: callback_wrapper
|
|
752
|
+
callback_wrapper: callback_wrapper,
|
|
753
|
+
verbatim_prompts: configured_options.verbatim_prompts?,
|
|
754
|
+
run_end_ceiling_ms: Query.run_end_ceiling_ms(configured_options.env)
|
|
753
755
|
)
|
|
754
756
|
|
|
755
757
|
# Mirror transcripts to the session_store, if configured. Installed
|
|
@@ -782,7 +784,7 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
782
784
|
parent_tool_use_id: nil,
|
|
783
785
|
session_id: ''
|
|
784
786
|
}
|
|
785
|
-
transport.write("#{
|
|
787
|
+
transport.write("#{Query.serialize_user_message(message, configured_options.verbatim_prompts?)}\n")
|
|
786
788
|
# Background-spawn so messages stream to the user block while stdin
|
|
787
789
|
# close waits (without timeout) for the first result; a synchronous
|
|
788
790
|
# call would defer all delivery until the turn completes (mirrors
|
|
@@ -1084,7 +1086,7 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
1084
1086
|
parent_tool_use_id: nil,
|
|
1085
1087
|
session_id: session_id
|
|
1086
1088
|
}
|
|
1087
|
-
writeln(
|
|
1089
|
+
writeln(Query.serialize_user_message(message, @verbatim_prompts))
|
|
1088
1090
|
elsif prompt.respond_to?(:each)
|
|
1089
1091
|
# Inline iteration on the caller, Python client.py parity — NOT
|
|
1090
1092
|
# Query#stream_input, whose ensure always ends input after
|
|
@@ -1394,6 +1396,10 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
1394
1396
|
exclude_dynamic_sections = ClaudeAgentSDK.extract_exclude_dynamic_sections(configured_options.system_prompt)
|
|
1395
1397
|
system_prompt_snapshot = ClaudeAgentSDK.extract_system_prompt_snapshot(configured_options.system_prompt)
|
|
1396
1398
|
|
|
1399
|
+
# Captured once, so String and streamed prompts in one session are
|
|
1400
|
+
# stamped alike (the Query stamps the streamed ones with this value).
|
|
1401
|
+
@verbatim_prompts = configured_options.verbatim_prompts?
|
|
1402
|
+
|
|
1397
1403
|
# Create Query handler
|
|
1398
1404
|
@query_handler = Query.new(
|
|
1399
1405
|
transport: @transport,
|
|
@@ -1408,7 +1414,9 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
1408
1414
|
forward_subagent_text: configured_options.forward_subagent_text?,
|
|
1409
1415
|
agent_progress_summaries: configured_options.agent_progress_summaries,
|
|
1410
1416
|
callback_scheduling: @callback_scheduling,
|
|
1411
|
-
callback_wrapper: @callback_wrapper
|
|
1417
|
+
callback_wrapper: @callback_wrapper,
|
|
1418
|
+
verbatim_prompts: @verbatim_prompts,
|
|
1419
|
+
run_end_ceiling_ms: Query.run_end_ceiling_ms(configured_options.env)
|
|
1412
1420
|
)
|
|
1413
1421
|
|
|
1414
1422
|
# Mirror transcripts to the session_store, if configured.
|
|
@@ -1450,7 +1458,9 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
1450
1458
|
# key styles — an explicit nil is preserved, mirroring Python's
|
|
1451
1459
|
# `"session_id" not in msg`). Strings pass through verbatim (Ruby
|
|
1452
1460
|
# superset: Streaming.user_message emits pre-serialized JSONL; no
|
|
1453
|
-
# parse-stamp-regenerate, which would block the reactor on huge frames)
|
|
1461
|
+
# parse-stamp-regenerate, which would block the reactor on huge frames),
|
|
1462
|
+
# except that verbatim_prompts must mark them `client_composed`, so with
|
|
1463
|
+
# that option on they are parsed and re-serialized (Query.stamp_user_message).
|
|
1454
1464
|
def stream_query_messages(prompt, session_id)
|
|
1455
1465
|
prompt.each do |msg|
|
|
1456
1466
|
case msg
|
|
@@ -1460,13 +1470,13 @@ module ClaudeAgentSDK # rubocop:disable Metrics/ModuleLength -- the public entry
|
|
|
1460
1470
|
ClaudeAgentSDK.notify_observers(@resolved_observers, :on_user_prompt, text,
|
|
1461
1471
|
scheduling: @callback_scheduling, wrapper: @callback_wrapper)
|
|
1462
1472
|
end
|
|
1463
|
-
writeln(
|
|
1473
|
+
writeln(Query.serialize_user_message(msg, @verbatim_prompts))
|
|
1464
1474
|
when String
|
|
1465
1475
|
if (text = ClaudeAgentSDK.extract_user_prompt_text(msg))
|
|
1466
1476
|
ClaudeAgentSDK.notify_observers(@resolved_observers, :on_user_prompt, text,
|
|
1467
1477
|
scheduling: @callback_scheduling, wrapper: @callback_wrapper)
|
|
1468
1478
|
end
|
|
1469
|
-
writeln(msg)
|
|
1479
|
+
writeln(Query.serialize_user_message(msg, @verbatim_prompts))
|
|
1470
1480
|
else
|
|
1471
1481
|
# No to_s fallback — silently serializing arbitrary objects is the
|
|
1472
1482
|
# exact inspect-garbage bug class this method exists to prevent.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module ClaudeAgentSDK
|
|
2
|
+
# Delivered as ToolPermissionContext#signal and HookContext#signal. It is
|
|
3
|
+
# cancelled when the CLI cancels the request (or the session closes), so a
|
|
4
|
+
# long-running callback can stop early.
|
|
5
|
+
class CancellationSignal
|
|
6
|
+
def initialize: () -> void
|
|
7
|
+
|
|
8
|
+
def cancelled?: () -> bool
|
|
9
|
+
|
|
10
|
+
# Blocks until cancelled or until timeout seconds pass; returns
|
|
11
|
+
# #cancelled?.
|
|
12
|
+
def wait: (?timeout: (Integer | Float)?) -> bool
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module ClaudeAgentSDK
|
|
2
|
+
# Global defaults set via ClaudeAgentSDK.configure, merged under every
|
|
3
|
+
# ClaudeAgentOptions (per-call options win).
|
|
4
|
+
class Configuration
|
|
5
|
+
# A frozen snapshot of the configured defaults ({} when unset). Keys are
|
|
6
|
+
# ClaudeAgentOptions option names.
|
|
7
|
+
attr_reader default_options: Hash[Symbol | String, untyped]
|
|
8
|
+
|
|
9
|
+
def initialize: () -> void
|
|
10
|
+
|
|
11
|
+
# Stores a deep-frozen copy; nil resets to {}.
|
|
12
|
+
def default_options=: (Hash[Symbol | String, untyped]? value) -> Hash[Symbol | String, untyped]?
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
module ClaudeAgentSDK
|
|
2
|
+
# Base exception for all Claude SDK errors.
|
|
3
|
+
class ClaudeSDKError < StandardError
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
# Raised when unable to connect to Claude Code (also: "Not connected").
|
|
7
|
+
class CLIConnectionError < ClaudeSDKError
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Raised when the control protocol does not respond in time.
|
|
11
|
+
class ControlRequestTimeoutError < CLIConnectionError
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Raised when Claude Code is not found or not installed.
|
|
15
|
+
class CLINotFoundError < CLIConnectionError
|
|
16
|
+
def initialize: (?String message, ?cli_path: (String | Pathname)?) -> void
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Raised when CLIInstaller cannot install the CLI binary.
|
|
20
|
+
class CLIInstallError < ClaudeSDKError
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Raised by the local-disk session APIs when the Claude config directory
|
|
24
|
+
# cannot be located.
|
|
25
|
+
class ConfigDirError < ClaudeSDKError
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Raised by Client#connect, ClaudeAgentSDK.query and .ask when resuming
|
|
29
|
+
# from ClaudeAgentOptions#session_store fails (a store call raised or
|
|
30
|
+
# exceeded load_timeout_ms). #cause holds the adapter's own exception.
|
|
31
|
+
class SessionStoreError < ClaudeSDKError
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Raised when the CLI process fails.
|
|
35
|
+
class ProcessError < ClaudeSDKError
|
|
36
|
+
attr_reader exit_code: Integer?
|
|
37
|
+
|
|
38
|
+
attr_reader stderr: String?
|
|
39
|
+
|
|
40
|
+
def initialize: (String message, ?exit_code: Integer?, ?stderr: String?) -> void
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Raised when the CLI exits non-zero after an error result. Every
|
|
44
|
+
# structured field is type-narrowed (nil unless the payload held the
|
|
45
|
+
# documented type); #data holds the payload as the CLI sent it.
|
|
46
|
+
class ResultError < ProcessError
|
|
47
|
+
attr_reader subtype: String?
|
|
48
|
+
|
|
49
|
+
attr_reader errors: Array[String]
|
|
50
|
+
|
|
51
|
+
attr_reader result: String?
|
|
52
|
+
|
|
53
|
+
attr_reader api_error_status: Integer?
|
|
54
|
+
|
|
55
|
+
attr_reader terminal_reason: String?
|
|
56
|
+
|
|
57
|
+
attr_reader session_id: String?
|
|
58
|
+
|
|
59
|
+
attr_reader data: Hash[Symbol | String, untyped]
|
|
60
|
+
|
|
61
|
+
attr_reader original_error: ProcessError?
|
|
62
|
+
|
|
63
|
+
# The exception text a `result` payload produces (any payload is
|
|
64
|
+
# accepted; a non-Hash reads as empty).
|
|
65
|
+
def self.error_text: (untyped data) -> String
|
|
66
|
+
|
|
67
|
+
def initialize: (String message, ?data: untyped, ?exit_code: Integer?, ?stderr: String?, ?original_error: ProcessError?) -> void
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Raised when a stdout line from the CLI is not valid JSON.
|
|
71
|
+
class CLIJSONDecodeError < ClaudeSDKError
|
|
72
|
+
attr_reader line: String
|
|
73
|
+
|
|
74
|
+
attr_reader original_error: Exception
|
|
75
|
+
|
|
76
|
+
def initialize: (String line, Exception original_error) -> void
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Raised when a CLI message cannot be parsed into a typed message.
|
|
80
|
+
class MessageParseError < ClaudeSDKError
|
|
81
|
+
# The offending payload, as received.
|
|
82
|
+
attr_reader data: untyped
|
|
83
|
+
|
|
84
|
+
def initialize: (String message, ?data: untyped) -> void
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module ClaudeAgentSDK
|
|
2
|
+
# Base module for message observers (ClaudeAgentOptions#observers): include
|
|
3
|
+
# it and override the callbacks you need; each defaults to a no-op.
|
|
4
|
+
# Observer errors are rescued and never reach the pipeline.
|
|
5
|
+
module Observer
|
|
6
|
+
def on_user_prompt: (String prompt) -> void
|
|
7
|
+
|
|
8
|
+
def on_message: (message message) -> void
|
|
9
|
+
|
|
10
|
+
def on_error: (StandardError error) -> void
|
|
11
|
+
|
|
12
|
+
def on_close: () -> void
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Loaded by `require 'claude_agent_sdk/instrumentation'` (needs the
|
|
16
|
+
# opentelemetry-api gem).
|
|
17
|
+
module Instrumentation
|
|
18
|
+
# Emits OpenTelemetry spans (gen_ai.* + OpenInference conventions) for a
|
|
19
|
+
# session.
|
|
20
|
+
class OTelObserver
|
|
21
|
+
include Observer
|
|
22
|
+
|
|
23
|
+
TRACER_NAME: String
|
|
24
|
+
|
|
25
|
+
MAX_ATTRIBUTE_LENGTH: Integer
|
|
26
|
+
|
|
27
|
+
# default_attributes are added to every span. Attribute names usually
|
|
28
|
+
# contain dots, so they are commonly given as String keys
|
|
29
|
+
# (`new('user.id' => 'u1')`).
|
|
30
|
+
def initialize: (?tracer_name: String, **untyped default_attributes) -> void
|
|
31
|
+
| (Hash[String | Symbol, untyped] default_attributes) -> void
|
|
32
|
+
|
|
33
|
+
def on_user_prompt: (String prompt) -> void
|
|
34
|
+
|
|
35
|
+
def on_message: (message message) -> void
|
|
36
|
+
|
|
37
|
+
def on_error: (StandardError error) -> void
|
|
38
|
+
|
|
39
|
+
def on_close: () -> void
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module ClaudeAgentSDK
|
|
2
|
+
# Rails integration (lib/claude_agent_sdk/railtie.rb), loaded only when
|
|
3
|
+
# Rails::Railtie is defined. Declared without its Rails::Railtie superclass
|
|
4
|
+
# so these signatures validate without Rails' own.
|
|
5
|
+
class Railtie
|
|
6
|
+
# A callback_wrapper that runs SDK callbacks in the Rails executor,
|
|
7
|
+
# deadlock-free under development code reloading.
|
|
8
|
+
def self.callback_wrapper: () -> _CallbackWrapper
|
|
9
|
+
end
|
|
10
|
+
end
|