claude-agent-sdk 0.2.1 → 0.4.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.
@@ -1,6 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeAgentSDK
4
+ # Type constants for permission modes
5
+ PERMISSION_MODES = %w[default acceptEdits plan bypassPermissions].freeze
6
+
7
+ # Type constants for setting sources
8
+ SETTING_SOURCES = %w[user project local].freeze
9
+
10
+ # Type constants for permission update destinations
11
+ PERMISSION_UPDATE_DESTINATIONS = %w[userSettings projectSettings localSettings session].freeze
12
+
13
+ # Type constants for permission behaviors
14
+ PERMISSION_BEHAVIORS = %w[allow deny ask].freeze
15
+
16
+ # Type constants for hook events
17
+ HOOK_EVENTS = %w[PreToolUse PostToolUse UserPromptSubmit Stop SubagentStop PreCompact].freeze
18
+
19
+ # Type constants for assistant message errors
20
+ ASSISTANT_MESSAGE_ERRORS = %w[authentication_failed billing_error rate_limit invalid_request server_error unknown].freeze
21
+
22
+ # Type constants for SDK beta features
23
+ # Available beta features that can be enabled via the betas option
24
+ SDK_BETAS = %w[context-1m-2025-08-07].freeze
25
+
4
26
  # Content Blocks
5
27
 
6
28
  # Text content block
@@ -48,22 +70,24 @@ module ClaudeAgentSDK
48
70
 
49
71
  # User message
50
72
  class UserMessage
51
- attr_accessor :content, :parent_tool_use_id
73
+ attr_accessor :content, :uuid, :parent_tool_use_id
52
74
 
53
- def initialize(content:, parent_tool_use_id: nil)
75
+ def initialize(content:, uuid: nil, parent_tool_use_id: nil)
54
76
  @content = content
77
+ @uuid = uuid # Unique identifier for rewind support
55
78
  @parent_tool_use_id = parent_tool_use_id
56
79
  end
57
80
  end
58
81
 
59
82
  # Assistant message with content blocks
60
83
  class AssistantMessage
61
- attr_accessor :content, :model, :parent_tool_use_id
84
+ attr_accessor :content, :model, :parent_tool_use_id, :error
62
85
 
63
- def initialize(content:, model:, parent_tool_use_id: nil)
86
+ def initialize(content:, model:, parent_tool_use_id: nil, error: nil)
64
87
  @content = content
65
88
  @model = model
66
89
  @parent_tool_use_id = parent_tool_use_id
90
+ @error = error # One of: authentication_failed, billing_error, rate_limit, invalid_request, server_error, unknown
67
91
  end
68
92
  end
69
93
 
@@ -80,10 +104,10 @@ module ClaudeAgentSDK
80
104
  # Result message with cost and usage information
81
105
  class ResultMessage
82
106
  attr_accessor :subtype, :duration_ms, :duration_api_ms, :is_error,
83
- :num_turns, :session_id, :total_cost_usd, :usage, :result
107
+ :num_turns, :session_id, :total_cost_usd, :usage, :result, :structured_output
84
108
 
85
109
  def initialize(subtype:, duration_ms:, duration_api_ms:, is_error:,
86
- num_turns:, session_id:, total_cost_usd: nil, usage: nil, result: nil)
110
+ num_turns:, session_id:, total_cost_usd: nil, usage: nil, result: nil, structured_output: nil)
87
111
  @subtype = subtype
88
112
  @duration_ms = duration_ms
89
113
  @duration_api_ms = duration_api_ms
@@ -93,6 +117,7 @@ module ClaudeAgentSDK
93
117
  @total_cost_usd = total_cost_usd
94
118
  @usage = usage
95
119
  @result = result
120
+ @structured_output = structured_output # Structured output when output_format is specified
96
121
  end
97
122
  end
98
123
 
@@ -201,11 +226,215 @@ module ClaudeAgentSDK
201
226
 
202
227
  # Hook matcher configuration
203
228
  class HookMatcher
204
- attr_accessor :matcher, :hooks
229
+ attr_accessor :matcher, :hooks, :timeout
205
230
 
206
- def initialize(matcher: nil, hooks: [])
231
+ def initialize(matcher: nil, hooks: [], timeout: nil)
207
232
  @matcher = matcher
208
233
  @hooks = hooks
234
+ @timeout = timeout # Timeout in seconds for hook execution
235
+ end
236
+ end
237
+
238
+ # Hook context passed to hook callbacks
239
+ class HookContext
240
+ attr_accessor :signal
241
+
242
+ def initialize(signal: nil)
243
+ @signal = signal
244
+ end
245
+ end
246
+
247
+ # Base hook input with common fields
248
+ class BaseHookInput
249
+ attr_accessor :session_id, :transcript_path, :cwd, :permission_mode
250
+
251
+ def initialize(session_id: nil, transcript_path: nil, cwd: nil, permission_mode: nil)
252
+ @session_id = session_id
253
+ @transcript_path = transcript_path
254
+ @cwd = cwd
255
+ @permission_mode = permission_mode
256
+ end
257
+ end
258
+
259
+ # PreToolUse hook input
260
+ class PreToolUseHookInput < BaseHookInput
261
+ attr_accessor :hook_event_name, :tool_name, :tool_input
262
+
263
+ def initialize(hook_event_name: 'PreToolUse', tool_name: nil, tool_input: nil, **base_args)
264
+ super(**base_args)
265
+ @hook_event_name = hook_event_name
266
+ @tool_name = tool_name
267
+ @tool_input = tool_input
268
+ end
269
+ end
270
+
271
+ # PostToolUse hook input
272
+ class PostToolUseHookInput < BaseHookInput
273
+ attr_accessor :hook_event_name, :tool_name, :tool_input, :tool_response
274
+
275
+ def initialize(hook_event_name: 'PostToolUse', tool_name: nil, tool_input: nil, tool_response: nil, **base_args)
276
+ super(**base_args)
277
+ @hook_event_name = hook_event_name
278
+ @tool_name = tool_name
279
+ @tool_input = tool_input
280
+ @tool_response = tool_response
281
+ end
282
+ end
283
+
284
+ # UserPromptSubmit hook input
285
+ class UserPromptSubmitHookInput < BaseHookInput
286
+ attr_accessor :hook_event_name, :prompt
287
+
288
+ def initialize(hook_event_name: 'UserPromptSubmit', prompt: nil, **base_args)
289
+ super(**base_args)
290
+ @hook_event_name = hook_event_name
291
+ @prompt = prompt
292
+ end
293
+ end
294
+
295
+ # Stop hook input
296
+ class StopHookInput < BaseHookInput
297
+ attr_accessor :hook_event_name, :stop_hook_active
298
+
299
+ def initialize(hook_event_name: 'Stop', stop_hook_active: false, **base_args)
300
+ super(**base_args)
301
+ @hook_event_name = hook_event_name
302
+ @stop_hook_active = stop_hook_active
303
+ end
304
+ end
305
+
306
+ # SubagentStop hook input
307
+ class SubagentStopHookInput < BaseHookInput
308
+ attr_accessor :hook_event_name, :stop_hook_active
309
+
310
+ def initialize(hook_event_name: 'SubagentStop', stop_hook_active: false, **base_args)
311
+ super(**base_args)
312
+ @hook_event_name = hook_event_name
313
+ @stop_hook_active = stop_hook_active
314
+ end
315
+ end
316
+
317
+ # PreCompact hook input
318
+ class PreCompactHookInput < BaseHookInput
319
+ attr_accessor :hook_event_name, :trigger, :custom_instructions
320
+
321
+ def initialize(hook_event_name: 'PreCompact', trigger: nil, custom_instructions: nil, **base_args)
322
+ super(**base_args)
323
+ @hook_event_name = hook_event_name
324
+ @trigger = trigger
325
+ @custom_instructions = custom_instructions
326
+ end
327
+ end
328
+
329
+ # PreToolUse hook specific output
330
+ class PreToolUseHookSpecificOutput
331
+ attr_accessor :hook_event_name, :permission_decision, :permission_decision_reason, :updated_input
332
+
333
+ def initialize(permission_decision: nil, permission_decision_reason: nil, updated_input: nil)
334
+ @hook_event_name = 'PreToolUse'
335
+ @permission_decision = permission_decision # 'allow', 'deny', or 'ask'
336
+ @permission_decision_reason = permission_decision_reason
337
+ @updated_input = updated_input
338
+ end
339
+
340
+ def to_h
341
+ result = { hookEventName: @hook_event_name }
342
+ result[:permissionDecision] = @permission_decision if @permission_decision
343
+ result[:permissionDecisionReason] = @permission_decision_reason if @permission_decision_reason
344
+ result[:updatedInput] = @updated_input if @updated_input
345
+ result
346
+ end
347
+ end
348
+
349
+ # PostToolUse hook specific output
350
+ class PostToolUseHookSpecificOutput
351
+ attr_accessor :hook_event_name, :additional_context
352
+
353
+ def initialize(additional_context: nil)
354
+ @hook_event_name = 'PostToolUse'
355
+ @additional_context = additional_context
356
+ end
357
+
358
+ def to_h
359
+ result = { hookEventName: @hook_event_name }
360
+ result[:additionalContext] = @additional_context if @additional_context
361
+ result
362
+ end
363
+ end
364
+
365
+ # UserPromptSubmit hook specific output
366
+ class UserPromptSubmitHookSpecificOutput
367
+ attr_accessor :hook_event_name, :additional_context
368
+
369
+ def initialize(additional_context: nil)
370
+ @hook_event_name = 'UserPromptSubmit'
371
+ @additional_context = additional_context
372
+ end
373
+
374
+ def to_h
375
+ result = { hookEventName: @hook_event_name }
376
+ result[:additionalContext] = @additional_context if @additional_context
377
+ result
378
+ end
379
+ end
380
+
381
+ # SessionStart hook specific output
382
+ class SessionStartHookSpecificOutput
383
+ attr_accessor :hook_event_name, :additional_context
384
+
385
+ def initialize(additional_context: nil)
386
+ @hook_event_name = 'SessionStart'
387
+ @additional_context = additional_context
388
+ end
389
+
390
+ def to_h
391
+ result = { hookEventName: @hook_event_name }
392
+ result[:additionalContext] = @additional_context if @additional_context
393
+ result
394
+ end
395
+ end
396
+
397
+ # Async hook JSON output
398
+ class AsyncHookJSONOutput
399
+ attr_accessor :async, :async_timeout
400
+
401
+ def initialize(async: true, async_timeout: nil)
402
+ @async = async
403
+ @async_timeout = async_timeout
404
+ end
405
+
406
+ def to_h
407
+ result = { async: @async }
408
+ result[:asyncTimeout] = @async_timeout if @async_timeout
409
+ result
410
+ end
411
+ end
412
+
413
+ # Sync hook JSON output
414
+ class SyncHookJSONOutput
415
+ attr_accessor :continue, :suppress_output, :stop_reason, :decision,
416
+ :system_message, :reason, :hook_specific_output
417
+
418
+ def initialize(continue: true, suppress_output: false, stop_reason: nil, decision: nil,
419
+ system_message: nil, reason: nil, hook_specific_output: nil)
420
+ @continue = continue
421
+ @suppress_output = suppress_output
422
+ @stop_reason = stop_reason
423
+ @decision = decision
424
+ @system_message = system_message
425
+ @reason = reason
426
+ @hook_specific_output = hook_specific_output
427
+ end
428
+
429
+ def to_h
430
+ result = { continue: @continue }
431
+ result[:suppressOutput] = @suppress_output if @suppress_output
432
+ result[:stopReason] = @stop_reason if @stop_reason
433
+ result[:decision] = @decision if @decision
434
+ result[:systemMessage] = @system_message if @system_message
435
+ result[:reason] = @reason if @reason
436
+ result[:hookSpecificOutput] = @hook_specific_output.to_h if @hook_specific_output
437
+ result
209
438
  end
210
439
  end
211
440
 
@@ -274,6 +503,139 @@ module ClaudeAgentSDK
274
503
  end
275
504
  end
276
505
 
506
+ # SDK Plugin configuration
507
+ class SdkPluginConfig
508
+ attr_accessor :type, :path
509
+
510
+ def initialize(path:)
511
+ @type = 'plugin'
512
+ @path = path
513
+ end
514
+
515
+ def to_h
516
+ { type: @type, path: @path }
517
+ end
518
+ end
519
+
520
+ # Sandbox network configuration
521
+ class SandboxNetworkConfig
522
+ attr_accessor :allow_unix_sockets, :allow_all_unix_sockets, :allow_local_binding,
523
+ :http_proxy_port, :socks_proxy_port
524
+
525
+ def initialize(
526
+ allow_unix_sockets: nil,
527
+ allow_all_unix_sockets: nil,
528
+ allow_local_binding: nil,
529
+ http_proxy_port: nil,
530
+ socks_proxy_port: nil
531
+ )
532
+ @allow_unix_sockets = allow_unix_sockets
533
+ @allow_all_unix_sockets = allow_all_unix_sockets
534
+ @allow_local_binding = allow_local_binding
535
+ @http_proxy_port = http_proxy_port
536
+ @socks_proxy_port = socks_proxy_port
537
+ end
538
+
539
+ def to_h
540
+ result = {}
541
+ result[:allowUnixSockets] = @allow_unix_sockets unless @allow_unix_sockets.nil?
542
+ result[:allowAllUnixSockets] = @allow_all_unix_sockets unless @allow_all_unix_sockets.nil?
543
+ result[:allowLocalBinding] = @allow_local_binding unless @allow_local_binding.nil?
544
+ result[:httpProxyPort] = @http_proxy_port if @http_proxy_port
545
+ result[:socksProxyPort] = @socks_proxy_port if @socks_proxy_port
546
+ result
547
+ end
548
+ end
549
+
550
+ # Sandbox ignore violations configuration
551
+ class SandboxIgnoreViolations
552
+ attr_accessor :file, :network
553
+
554
+ def initialize(file: nil, network: nil)
555
+ @file = file # Array of file paths to ignore
556
+ @network = network # Array of network patterns to ignore
557
+ end
558
+
559
+ def to_h
560
+ result = {}
561
+ result[:file] = @file if @file
562
+ result[:network] = @network if @network
563
+ result
564
+ end
565
+ end
566
+
567
+ # Sandbox settings for isolated command execution
568
+ class SandboxSettings
569
+ attr_accessor :enabled, :auto_allow_bash_if_sandboxed, :excluded_commands,
570
+ :allow_unsandboxed_commands, :network, :ignore_violations,
571
+ :enable_weaker_nested_sandbox
572
+
573
+ def initialize(
574
+ enabled: nil,
575
+ auto_allow_bash_if_sandboxed: nil,
576
+ excluded_commands: nil,
577
+ allow_unsandboxed_commands: nil,
578
+ network: nil,
579
+ ignore_violations: nil,
580
+ enable_weaker_nested_sandbox: nil
581
+ )
582
+ @enabled = enabled
583
+ @auto_allow_bash_if_sandboxed = auto_allow_bash_if_sandboxed
584
+ @excluded_commands = excluded_commands # Array of commands to exclude
585
+ @allow_unsandboxed_commands = allow_unsandboxed_commands
586
+ @network = network # SandboxNetworkConfig instance
587
+ @ignore_violations = ignore_violations # SandboxIgnoreViolations instance
588
+ @enable_weaker_nested_sandbox = enable_weaker_nested_sandbox
589
+ end
590
+
591
+ def to_h
592
+ result = {}
593
+ result[:enabled] = @enabled unless @enabled.nil?
594
+ result[:autoAllowBashIfSandboxed] = @auto_allow_bash_if_sandboxed unless @auto_allow_bash_if_sandboxed.nil?
595
+ result[:excludedCommands] = @excluded_commands if @excluded_commands
596
+ result[:allowUnsandboxedCommands] = @allow_unsandboxed_commands unless @allow_unsandboxed_commands.nil?
597
+ if @network
598
+ result[:network] = @network.is_a?(SandboxNetworkConfig) ? @network.to_h : @network
599
+ end
600
+ if @ignore_violations
601
+ result[:ignoreViolations] = @ignore_violations.is_a?(SandboxIgnoreViolations) ? @ignore_violations.to_h : @ignore_violations
602
+ end
603
+ result[:enableWeakerNestedSandbox] = @enable_weaker_nested_sandbox unless @enable_weaker_nested_sandbox.nil?
604
+ result
605
+ end
606
+ end
607
+
608
+ # System prompt preset configuration
609
+ class SystemPromptPreset
610
+ attr_accessor :type, :preset, :append
611
+
612
+ def initialize(preset:, append: nil)
613
+ @type = 'preset'
614
+ @preset = preset
615
+ @append = append
616
+ end
617
+
618
+ def to_h
619
+ result = { type: @type, preset: @preset }
620
+ result[:append] = @append if @append
621
+ result
622
+ end
623
+ end
624
+
625
+ # Tools preset configuration
626
+ class ToolsPreset
627
+ attr_accessor :type, :preset
628
+
629
+ def initialize(preset:)
630
+ @type = 'preset'
631
+ @preset = preset
632
+ end
633
+
634
+ def to_h
635
+ { type: @type, preset: @preset }
636
+ end
637
+ end
638
+
277
639
  # Claude Agent Options for configuring queries
278
640
  class ClaudeAgentOptions
279
641
  attr_accessor :allowed_tools, :system_prompt, :mcp_servers, :permission_mode,
@@ -281,7 +643,10 @@ module ClaudeAgentSDK
281
643
  :model, :permission_prompt_tool_name, :cwd, :cli_path, :settings,
282
644
  :add_dirs, :env, :extra_args, :max_buffer_size, :stderr,
283
645
  :can_use_tool, :hooks, :user, :include_partial_messages,
284
- :fork_session, :agents, :setting_sources
646
+ :fork_session, :agents, :setting_sources,
647
+ :output_format, :max_budget_usd, :max_thinking_tokens,
648
+ :fallback_model, :plugins, :debug_stderr,
649
+ :betas, :tools, :sandbox, :enable_file_checkpointing, :append_allowed_tools
285
650
 
286
651
  def initialize(
287
652
  allowed_tools: [],
@@ -308,7 +673,18 @@ module ClaudeAgentSDK
308
673
  include_partial_messages: false,
309
674
  fork_session: false,
310
675
  agents: nil,
311
- setting_sources: nil
676
+ setting_sources: nil,
677
+ output_format: nil,
678
+ max_budget_usd: nil,
679
+ max_thinking_tokens: nil,
680
+ fallback_model: nil,
681
+ plugins: nil,
682
+ debug_stderr: nil,
683
+ betas: nil,
684
+ tools: nil,
685
+ sandbox: nil,
686
+ enable_file_checkpointing: false,
687
+ append_allowed_tools: nil
312
688
  )
313
689
  @allowed_tools = allowed_tools
314
690
  @system_prompt = system_prompt
@@ -335,6 +711,17 @@ module ClaudeAgentSDK
335
711
  @fork_session = fork_session
336
712
  @agents = agents
337
713
  @setting_sources = setting_sources
714
+ @output_format = output_format # JSON schema for structured output
715
+ @max_budget_usd = max_budget_usd # Spending cap in dollars
716
+ @max_thinking_tokens = max_thinking_tokens # Extended thinking token budget
717
+ @fallback_model = fallback_model # Backup model if primary unavailable
718
+ @plugins = plugins # Array of SdkPluginConfig
719
+ @debug_stderr = debug_stderr # Debug output file object/path
720
+ @betas = betas # Array of beta feature strings (e.g., ["context-1m-2025-08-07"])
721
+ @tools = tools # Base tools selection: Array, empty array [], or ToolsPreset
722
+ @sandbox = sandbox # SandboxSettings instance for isolated command execution
723
+ @enable_file_checkpointing = enable_file_checkpointing # Enable file checkpointing for rewind support
724
+ @append_allowed_tools = append_allowed_tools # Array of tools to append to allowed_tools
338
725
  end
339
726
 
340
727
  def dup_with(**changes)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeAgentSDK
4
- VERSION = '0.2.1'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -244,6 +244,15 @@ module ClaudeAgentSDK
244
244
  @query_handler.set_model(model)
245
245
  end
246
246
 
247
+ # Rewind files to a previous checkpoint (v0.1.15+)
248
+ # Restores file state to what it was at the given user message
249
+ # Requires enable_file_checkpointing to be true in options
250
+ # @param user_message_uuid [String] The UUID of the UserMessage to rewind to
251
+ def rewind_files(user_message_uuid)
252
+ raise CLIConnectionError, 'Not connected. Call connect() first' unless @connected
253
+ @query_handler.rewind_files(user_message_uuid)
254
+ end
255
+
247
256
  # Get server initialization info
248
257
  # @return [Hash, nil] Server info or nil
249
258
  def server_info
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.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Community Contributors
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-10-17 00:00:00.000000000 Z
10
+ date: 2026-01-05 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: async