claude-agent-sdk 0.17.0 → 0.19.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 +64 -0
- data/README.md +4 -2
- data/docs/configuration.md +13 -2
- data/docs/observability.md +28 -4
- data/docs/sessions.md +15 -2
- data/docs/types.md +13 -3
- data/lib/claude_agent_sdk/command_builder.rb +69 -22
- data/lib/claude_agent_sdk/fiber_boundary.rb +39 -1
- data/lib/claude_agent_sdk/instrumentation/otel.rb +97 -23
- data/lib/claude_agent_sdk/message_parser.rb +27 -4
- data/lib/claude_agent_sdk/observer.rb +23 -3
- data/lib/claude_agent_sdk/query.rb +223 -88
- data/lib/claude_agent_sdk/sdk_mcp_server.rb +232 -181
- data/lib/claude_agent_sdk/session_store.rb +4 -0
- data/lib/claude_agent_sdk/sessions.rb +144 -24
- data/lib/claude_agent_sdk/subprocess_cli_transport.rb +184 -50
- data/lib/claude_agent_sdk/testing/session_store_conformance.rb +15 -1
- data/lib/claude_agent_sdk/types.rb +90 -6
- data/lib/claude_agent_sdk/version.rb +1 -1
- data/lib/claude_agent_sdk.rb +359 -93
- metadata +12 -6
|
@@ -333,6 +333,19 @@ module ClaudeAgentSDK
|
|
|
333
333
|
# Task lifecycle notification statuses
|
|
334
334
|
TASK_NOTIFICATION_STATUSES = %w[completed failed stopped].freeze
|
|
335
335
|
|
|
336
|
+
# Possible status values reported inside a `task_updated` patch.
|
|
337
|
+
# pending/running/paused are non-terminal; completed/failed/killed are
|
|
338
|
+
# terminal. Note: task_updated reports the raw "killed"; the CLI maps that to
|
|
339
|
+
# "stopped" only when it emits a task_notification.
|
|
340
|
+
TASK_UPDATED_STATUSES = %w[pending running paused completed failed killed].freeze
|
|
341
|
+
|
|
342
|
+
# Task statuses that mean the task has finished and should be cleared from any
|
|
343
|
+
# "active task" tracking. Spans both lifecycle vocabularies: task_notification
|
|
344
|
+
# reports "stopped" (the CLI's mapped form of a killed task) while task_updated
|
|
345
|
+
# reports the raw "killed". Treat the status of a TaskNotificationMessage and a
|
|
346
|
+
# TaskUpdatedMessage the same way.
|
|
347
|
+
TERMINAL_TASK_STATUSES = %w[completed failed stopped killed].freeze
|
|
348
|
+
|
|
336
349
|
# Typed usage data for task progress and notifications
|
|
337
350
|
class TaskUsage < Type
|
|
338
351
|
attr_accessor :total_tokens, :tool_uses, :duration_ms
|
|
@@ -356,11 +369,44 @@ module ClaudeAgentSDK
|
|
|
356
369
|
attr_accessor :task_id, :description, :usage, :uuid, :session_id, :tool_use_id, :last_tool_name, :summary
|
|
357
370
|
end
|
|
358
371
|
|
|
359
|
-
# Task notification system message (task completed/failed/stopped)
|
|
372
|
+
# Task notification system message (task completed/failed/stopped).
|
|
373
|
+
#
|
|
374
|
+
# Note: not every terminal task emits this message. Background tasks may
|
|
375
|
+
# instead report completion only via a TaskUpdatedMessage whose patch["status"]
|
|
376
|
+
# is terminal (see TERMINAL_TASK_STATUSES). Consumers tracking active task IDs
|
|
377
|
+
# should clear them on a terminal status from *either* message.
|
|
360
378
|
class TaskNotificationMessage < SystemMessage
|
|
361
379
|
attr_accessor :task_id, :status, :output_file, :summary, :uuid, :session_id, :tool_use_id, :usage
|
|
362
380
|
end
|
|
363
381
|
|
|
382
|
+
# Task updated system message (background task lifecycle state change).
|
|
383
|
+
#
|
|
384
|
+
# The CLI emits system/task_updated events as a task moves through its
|
|
385
|
+
# lifecycle. `patch` carries the changed fields (e.g. status, end_time); when
|
|
386
|
+
# patch["status"] is terminal (see TERMINAL_TASK_STATUSES) the task has
|
|
387
|
+
# finished. A background task's terminal state can arrive *only* as a
|
|
388
|
+
# TaskUpdatedMessage with no accompanying TaskNotificationMessage — e.g. a task
|
|
389
|
+
# stopped via TaskStop reports status "killed" here and the matching
|
|
390
|
+
# notification is sometimes suppressed. Consumers tracking active task IDs
|
|
391
|
+
# should clear them on a terminal status from *either* message.
|
|
392
|
+
#
|
|
393
|
+
# Parsed defensively in the constructor — a lifecycle event must never raise:
|
|
394
|
+
# `status` is derived from patch["status"] (not a top-level field); a non-Hash
|
|
395
|
+
# or absent patch falls back to {}; and `task_id` defaults to "" (never nil,
|
|
396
|
+
# matching the Python SDK) so consumers can rely on it always being a String.
|
|
397
|
+
# The full patch is preserved on `#patch` for callers that need more than the
|
|
398
|
+
# status.
|
|
399
|
+
class TaskUpdatedMessage < SystemMessage
|
|
400
|
+
attr_accessor :task_id, :patch, :status, :uuid, :session_id
|
|
401
|
+
|
|
402
|
+
def initialize(attributes = {})
|
|
403
|
+
super
|
|
404
|
+
@task_id ||= ''
|
|
405
|
+
@patch = {} unless @patch.is_a?(Hash)
|
|
406
|
+
@status = @patch[:status]
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
364
410
|
# Result message with cost and usage information
|
|
365
411
|
class ResultMessage < Type
|
|
366
412
|
attr_accessor :subtype, :duration_ms, :duration_api_ms, :is_error,
|
|
@@ -525,7 +571,16 @@ module ClaudeAgentSDK
|
|
|
525
571
|
|
|
526
572
|
# Permission update configuration
|
|
527
573
|
class PermissionUpdate < Type
|
|
528
|
-
attr_accessor :type, :
|
|
574
|
+
attr_accessor :type, :behavior, :mode, :directories, :destination
|
|
575
|
+
attr_reader :rules
|
|
576
|
+
|
|
577
|
+
# Wire-format parity with Python PermissionUpdate.from_dict (#920): the CLI
|
|
578
|
+
# sends rules as camelCase hashes ({toolName:, ruleContent:}); hydrate them
|
|
579
|
+
# into PermissionRuleValue (Type#assign_attribute normalizes the camelCase
|
|
580
|
+
# keys). Already-typed PermissionRuleValue entries pass through unchanged.
|
|
581
|
+
def rules=(value)
|
|
582
|
+
@rules = value&.map { |rule| rule.is_a?(Hash) ? PermissionRuleValue.new(rule) : rule }
|
|
583
|
+
end
|
|
529
584
|
|
|
530
585
|
def to_h
|
|
531
586
|
result = { type: @type }
|
|
@@ -888,6 +943,22 @@ module ClaudeAgentSDK
|
|
|
888
943
|
end
|
|
889
944
|
end
|
|
890
945
|
|
|
946
|
+
# Fallback for hook events the SDK does not yet model. Carries the wire
|
|
947
|
+
# event name and the complete raw payload so no fields are lost (Python
|
|
948
|
+
# passes hook input through as a raw dict, so unknown events lose
|
|
949
|
+
# nothing there).
|
|
950
|
+
class UnknownHookInput < BaseHookInput
|
|
951
|
+
attr_accessor :raw_input
|
|
952
|
+
|
|
953
|
+
def initialize(attributes = {})
|
|
954
|
+
super
|
|
955
|
+
# Direct assignment: BaseHookInput exposes hook_event_name as
|
|
956
|
+
# attr_reader only, and Type#assign_attribute silently drops keys
|
|
957
|
+
# without public setters.
|
|
958
|
+
@hook_event_name = attributes[:hook_event_name] || attributes['hook_event_name']
|
|
959
|
+
end
|
|
960
|
+
end
|
|
961
|
+
|
|
891
962
|
# Setup hook specific output
|
|
892
963
|
class SetupHookSpecificOutput < Type
|
|
893
964
|
attr_accessor :additional_context
|
|
@@ -1480,10 +1551,10 @@ module ClaudeAgentSDK
|
|
|
1480
1551
|
:model, :permission_prompt_tool_name, :cwd, :cli_path, :settings,
|
|
1481
1552
|
:add_dirs, :env, :extra_args, :max_buffer_size, :stderr,
|
|
1482
1553
|
:can_use_tool, :hooks, :user,
|
|
1483
|
-
:agents, :setting_sources,
|
|
1554
|
+
:agents, :setting_sources, :skills,
|
|
1484
1555
|
:output_format, :max_budget_usd, :max_thinking_tokens,
|
|
1485
1556
|
:fallback_model, :plugins, :debug_stderr,
|
|
1486
|
-
:betas, :tools, :sandbox,
|
|
1557
|
+
:betas, :tools, :sandbox,
|
|
1487
1558
|
:thinking, :effort, :observers, :task_budget,
|
|
1488
1559
|
:session_store, :session_store_flush, :load_timeout_ms
|
|
1489
1560
|
attr_reader :bare, :fork_session, :enable_file_checkpointing,
|
|
@@ -1596,8 +1667,11 @@ module ClaudeAgentSDK
|
|
|
1596
1667
|
defaults = ClaudeAgentSDK.default_options
|
|
1597
1668
|
return attributes unless defaults.any?
|
|
1598
1669
|
|
|
1599
|
-
# Start from configured defaults
|
|
1600
|
-
|
|
1670
|
+
# Start from configured defaults. Container values are recursively
|
|
1671
|
+
# duped so per-instance mutation (options.allowed_tools << 'Bash')
|
|
1672
|
+
# can never corrupt the global defaults; non-container leaves
|
|
1673
|
+
# (Strings, Procs, SdkMcpServer instances) intentionally keep identity.
|
|
1674
|
+
result = deep_dup_containers(defaults)
|
|
1601
1675
|
attributes.each do |key, value|
|
|
1602
1676
|
default_val = result[key]
|
|
1603
1677
|
result[key] = if value.nil?
|
|
@@ -1610,6 +1684,16 @@ module ClaudeAgentSDK
|
|
|
1610
1684
|
end
|
|
1611
1685
|
result
|
|
1612
1686
|
end
|
|
1687
|
+
|
|
1688
|
+
# Recurse ONLY into Hash/Array; leaves keep object identity (observer
|
|
1689
|
+
# factories, callbacks, SDK MCP server instances must not be duped).
|
|
1690
|
+
def deep_dup_containers(value)
|
|
1691
|
+
case value
|
|
1692
|
+
when Hash then value.to_h { |k, v| [k, deep_dup_containers(v)] }
|
|
1693
|
+
when Array then value.map { |v| deep_dup_containers(v) }
|
|
1694
|
+
else value
|
|
1695
|
+
end
|
|
1696
|
+
end
|
|
1613
1697
|
end
|
|
1614
1698
|
|
|
1615
1699
|
# SDK MCP Tool definition
|