claude-agent-sdk 0.37.0 → 1.0.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 +17 -0
- data/README.md +6 -2
- data/UPGRADING-1.0.md +151 -0
- data/docs/errors.md +6 -0
- data/docs/sessions.md +20 -1
- data/docs/types.md +17 -14
- data/lib/claude_agent_sdk/deprecation.rb +1 -40
- data/lib/claude_agent_sdk/errors.rb +10 -0
- data/lib/claude_agent_sdk/session_resume.rb +11 -5
- 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/version.rb +1 -1
- data/lib/claude_agent_sdk.rb +11 -11
- 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 +288 -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 +22 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a678100ed5fdb6ba11e9895e534b4a87df8a2b8a57d0a0a459900d81d88bf593
|
|
4
|
+
data.tar.gz: 8bc65b4056f315abe23a3f1f9089402819137b2abb38cbd1d57afdcfe5366e42
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b7ec8544374217a99458cc3557504777d5ac4e2a66cab706f9322f326f43220b312fc877388983961a688a1e3c55b3493bae1458c4a7ed71a7614bfe2e6bc0aa
|
|
7
|
+
data.tar.gz: b119e67d145088a4adbf832f611eaf5d7047c255a2037e5a76372f6ac319d8d6d7addaf4af062b58acbb12ba9acf17799027b89175c02498f65471320683533a
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.0] - 2026-09-23
|
|
11
|
+
|
|
12
|
+
**1.0 is a stability commitment.** From here on the public API — everything documented in `docs/` plus the YARD docs without `@api private`, now also described by the RBS signatures in `sig/` — follows Semantic Versioning: no breaking changes within 1.x. Upgrading from 0.x? Read [UPGRADING-1.0.md](UPGRADING-1.0.md) and run your suite on 0.37 first.
|
|
13
|
+
|
|
14
|
+
1.0 ([#126](https://github.com/ya-luotao/claude-agent-sdk-ruby/issues/126)): three breaking changes, the first two of which 0.37 warns about at the call site. **Read [UPGRADING-1.0.md](UPGRADING-1.0.md) before upgrading** and run your suite on 0.37 with warnings visible first: an app that runs on 0.37 without SDK warnings is unaffected by those two, except that `respond_to?` on a camelCase non-attribute (`msg.respond_to?(:toH)`) silently answered `true` on 0.37 and answers `false` now.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- **`ClaudeAgentSDK::SessionStoreError`** (a `ClaudeSDKError`), raised by `query`, `ask` and `Client#connect` when resuming from `session_store:` fails: a store call (`#load`, `#list_sessions`, `#list_subkeys`) raised or exceeded `load_timeout_ms` while the SDK materialized the transcript. The message names the store call, and `#cause` holds the adapter's exception (or the timeout). Documented in `docs/errors.md` and `docs/sessions.md`.
|
|
18
|
+
- **RBS signatures for the public API** ([#126](https://github.com/ya-luotao/claude-agent-sdk-ruby/issues/126)). The gem now ships `sig/`, so Steep and other RBS tools type-check code that uses it (through `rbs collection`; `sig/manifest.yaml` declares the one stdlib dependency, `pathname`). The signatures cover the whole public surface (the objects documented in `docs/` and YARD without `@api private`): `ClaudeAgentSDK.query` / `.ask` / `.configure` / `.offload`, the SDK MCP helpers, every session function (including `session_store:` and the deprecated twins), `Client` with its Ruby-style aliases, `ClaudeAgentOptions` (every option as a typed keyword), the message, content-block, hook, permission and MCP types, the error hierarchy, `CLIInstaller`, `Streaming`, `Railtie.callback_wrapper` and the observers. Duck types are interfaces, so any object with the right methods fits: `_Transport`, `_SessionStore` (only `#append` and `#load` are required), and one interface per user callback (`_CanUseTool`, `_HookCallback`, `_ToolHandler`, `_CallbackWrapper`, ...). Hashes follow the documented key rule: `wire_hash` (`Hash[Symbol, untyped]`) for data from the CLI stream, `transcript_hash` (`Hash[String, untyped]`) for transcripts and store data. Internals tagged `@api private` have no signatures. CI validates the signatures (`rake rbs:validate`) and runs the suite under RBS's runtime type checker (`rake rbs:test`), so a signature that disagrees with the code fails the build. `CONTRIBUTING.md` explains how to keep `sig/` in step with API changes.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- **Breaking: unknown keys on user-constructed types raise `ArgumentError`.** `.new` and `#[]=` on the value types you build and pass in (option values such as `AgentDefinition`, `SandboxSettings`, the thinking and MCP server configs; `HookMatcher`; hook outputs; `PermissionResultAllow` / `PermissionResultDeny`; `PermissionUpdate`; `PermissionRuleValue`) raise instead of warning, with a message naming the class, the key and the known keys: `ClaudeAgentSDK::HookMatcher: unknown attribute :matchr (known: hooks, matcher, timeout)`. camelCase and String keys and a type's own discriminator are still accepted; `.from_hash`, `.wrap` and every type parsed from CLI output stay lenient.
|
|
22
|
+
- **Breaking: `Type#[]`, `#[]=` and camelCase methods reach attributes only.** A name that is not an attribute behaves like an undefined one: `msg[:to_h]` is `nil`, `#[]=` ignores it (raises on the strict types above), `msg.toH` raises `NoMethodError` and `respond_to?(:toH)` is `false`. Methods your own code adds to a subclass, mixin or instance still count as attributes.
|
|
23
|
+
- **Breaking: store-backed resume failures raise `SessionStoreError` instead of `RuntimeError`.** The two SDK-raised `RuntimeError`s (store call failed, store call timed out) become `SessionStoreError`, and a `RuntimeError` raised by the adapter itself, which 0.37 let through unwrapped, is now wrapped too, so `rescue ClaudeSDKError` catches every resume-materialization failure. Code that rescued `RuntimeError` there must rescue `SessionStoreError`. The failure message now includes the adapter exception's class (`... failed during resume materialization: IOError: connection reset`).
|
|
24
|
+
- `UPGRADING-1.0.md` ships in the gem and the YARD docs, linked from the README.
|
|
25
|
+
- The deprecation warning printed by the ten `*_from_store` / `*_via_store` session functions, and their YARD and docs, now say they will be removed in **2.0**. 0.36 and 0.37 said 1.0, but they stay, deprecated, for all of 1.x ([#126](https://github.com/ya-luotao/claude-agent-sdk-ruby/issues/126)). Nothing else about them changes: each still works and still warns once per process.
|
|
26
|
+
|
|
10
27
|
## [0.37.0] - 2026-09-23
|
|
11
28
|
|
|
12
29
|
The last 0.x release before 1.0 ([roadmap](https://github.com/ya-luotao/claude-agent-sdk-ruby/issues/126)). No runtime behaviour changes — only new warnings for things 1.0 will reject. **Run your suite on 0.37 with warnings visible before moving to 1.0:**
|
data/README.md
CHANGED
|
@@ -12,6 +12,8 @@ A Ruby SDK for the [Claude Code](https://docs.claude.com/en/docs/claude-code-ove
|
|
|
12
12
|
|
|
13
13
|
> **Unofficial and community-maintained.** This project is not affiliated with or supported by Anthropic. It tracks the official SDKs release by release; see the [CHANGELOG](CHANGELOG.md) for the currently synced version.
|
|
14
14
|
|
|
15
|
+
> **Upgrading from 0.x?** 1.0 raises on unknown keys, limits `#[]` to attributes and adds `SessionStoreError`. [UPGRADING-1.0.md](UPGRADING-1.0.md) has the checklist.
|
|
16
|
+
|
|
15
17
|
## Highlights
|
|
16
18
|
|
|
17
19
|
- **Rails integration.** `bin/rails generate claude_agent_sdk:install` writes the initializer and `bin/rails claude_agent_sdk:install_cli` vendors the CLI; [docs/rails.md](docs/rails.md) covers jobs, ActionCable streaming, session resumption, and solid_queue fiber workers (`callback_scheduling: :inline`).
|
|
@@ -29,7 +31,7 @@ A Ruby SDK for the [Claude Code](https://docs.claude.com/en/docs/claude-code-ove
|
|
|
29
31
|
|
|
30
32
|
```ruby
|
|
31
33
|
# Gemfile
|
|
32
|
-
gem 'claude-agent-sdk', '~>
|
|
34
|
+
gem 'claude-agent-sdk', '~> 1.0'
|
|
33
35
|
```
|
|
34
36
|
|
|
35
37
|
Then `bundle install`, or install directly with `gem install claude-agent-sdk`. To track unreleased changes, point the Gemfile at GitHub: `gem 'claude-agent-sdk', github: 'ya-luotao/claude-agent-sdk-ruby'`.
|
|
@@ -252,11 +254,13 @@ This repository is also a Claude Code plugin marketplace. The bundled skill teac
|
|
|
252
254
|
bundle install
|
|
253
255
|
bundle exec rspec # unit suite
|
|
254
256
|
bundle exec rubocop # lint
|
|
257
|
+
bundle exec rake rbs:validate # validate the RBS signatures in sig/
|
|
258
|
+
bundle exec rake rbs:test # the suite under RBS runtime type checking
|
|
255
259
|
RUN_INTEGRATION=1 bundle exec rspec # also run the real-CLI integration suite (needs `claude` and ANTHROPIC_API_KEY)
|
|
256
260
|
BUNDLE_GEMFILE=gemfiles/rails_8.gemfile bundle exec rspec --options spec/rails/.rspec # Rails integration specs
|
|
257
261
|
```
|
|
258
262
|
|
|
259
|
-
CI runs the suite and RuboCop on Ruby 3.2, 3.3, and 3.4 on Linux, the suite on macOS, and the Rails specs against Rails 7.1 and 8; a weekly job runs the integration suite against the pinned CLI. See [CONTRIBUTING.md](https://github.com/ya-luotao/claude-agent-sdk-ruby/blob/main/CONTRIBUTING.md) for the development setup and [spec/README.md](https://github.com/ya-luotao/claude-agent-sdk-ruby/blob/main/spec/README.md) for the test layout.
|
|
263
|
+
CI runs the suite and RuboCop on Ruby 3.2, 3.3, and 3.4 on Linux, the suite on macOS, and the Rails specs against Rails 7.1 and 8, validates the RBS signatures and runs the suite under RBS runtime type checking; a weekly job runs the integration suite against the pinned CLI. The gem ships RBS signatures for its public API in `sig/`, which Steep and other RBS tools pick up through `rbs collection`. See [CONTRIBUTING.md](https://github.com/ya-luotao/claude-agent-sdk-ruby/blob/main/CONTRIBUTING.md) for the development setup and [spec/README.md](https://github.com/ya-luotao/claude-agent-sdk-ruby/blob/main/spec/README.md) for the test layout.
|
|
260
264
|
|
|
261
265
|
## Contributing
|
|
262
266
|
|
data/UPGRADING-1.0.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Upgrading from 0.37 to 1.0
|
|
2
|
+
|
|
3
|
+
1.0 is 0.37 plus three breaking changes. 0.37 already warns about each of the
|
|
4
|
+
first two at the exact call site, so **if your app runs on 0.37 without SDK
|
|
5
|
+
warnings, the first two changes will not affect it on 1.0**, with one silent
|
|
6
|
+
exception: `respond_to?` on a camelCase name that is not an attribute
|
|
7
|
+
(`msg.respond_to?(:toH)`) answered `true` on 0.37 without a warning and answers
|
|
8
|
+
`false` on 1.0. The third change is to which exception class you rescue.
|
|
9
|
+
|
|
10
|
+
| Area | 0.37 | 1.0 |
|
|
11
|
+
|------|------|-----|
|
|
12
|
+
| Unknown key on a type you build (`HookMatcher.new(matchr: ...)`) | warns once, key ignored | raises `ArgumentError` |
|
|
13
|
+
| `#[]` / `#[]=` / camelCase reaching a non-attribute (`msg[:to_h]`, `msg.toH`) | works, warns once | treated as undefined |
|
|
14
|
+
| Store-backed resume failure | bare `RuntimeError` | `ClaudeAgentSDK::SessionStoreError` |
|
|
15
|
+
|
|
16
|
+
## Checklist
|
|
17
|
+
|
|
18
|
+
1. Upgrade to 0.37 first: `gem 'claude-agent-sdk', '~> 0.37.0'`, then `bundle update claude-agent-sdk`.
|
|
19
|
+
2. Run your test suite, and exercise a staging boot, with warnings visible and
|
|
20
|
+
stderr kept: no `-W0`, no `$VERBOSE = nil`, and no stderr filtering.
|
|
21
|
+
For example, `bundle exec rspec 2> sdk-warnings.log`.
|
|
22
|
+
3. Find the SDK's warnings:
|
|
23
|
+
```sh
|
|
24
|
+
grep -E 'unknown attribute|is not an attribute|is deprecated' sdk-warnings.log
|
|
25
|
+
```
|
|
26
|
+
Each line starts with the `file:line` of your call. Every warning is
|
|
27
|
+
printed once per process per class and key (or per method), so fix what
|
|
28
|
+
you find and run again until the output is empty.
|
|
29
|
+
4. Fix each hit as described below.
|
|
30
|
+
5. Around code that resumes from a `session_store:` (`query`, `ask`,
|
|
31
|
+
`Client#connect`, `Client.open`), search for `rescue RuntimeError` and for
|
|
32
|
+
rescues of your adapter's own exception classes that inherit from
|
|
33
|
+
`RuntimeError` (for example `Net::ReadTimeout`, a `Timeout::Error`, which is
|
|
34
|
+
a `RuntimeError`). In 1.0 these arrive wrapped: rescue
|
|
35
|
+
`ClaudeAgentSDK::SessionStoreError` and inspect `#cause` for the original.
|
|
36
|
+
6. Upgrade: `gem 'claude-agent-sdk', '~> 1.0'`.
|
|
37
|
+
|
|
38
|
+
## Unknown keys raise `ArgumentError`
|
|
39
|
+
|
|
40
|
+
The value types you build and pass *in* now reject a key they do not define,
|
|
41
|
+
as `ClaudeAgentOptions` always has. Before 0.37 the key was silently dropped,
|
|
42
|
+
so a typo such as `matchr:` built a matcher that matched every tool:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
ClaudeAgentSDK::HookMatcher.new(matchr: 'Bash', hooks: [check])
|
|
46
|
+
# 0.37: warning: ClaudeAgentSDK::HookMatcher: unknown attribute :matchr ignored; this will raise ArgumentError in 1.0 (known: hooks, matcher, timeout)
|
|
47
|
+
# 1.0: ArgumentError: ClaudeAgentSDK::HookMatcher: unknown attribute :matchr (known: hooks, matcher, timeout)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This covers `.new` and `#[]=` on the option values (`AgentDefinition`,
|
|
51
|
+
`SandboxSettings` and its network and filesystem configs, the three thinking
|
|
52
|
+
configs, `TaskBudget`, the three system prompt types, `ToolsPreset`,
|
|
53
|
+
`SdkPluginConfig`, the four MCP server configs), `HookMatcher`, the hook
|
|
54
|
+
outputs (`SyncHookJSONOutput`, `AsyncHookJSONOutput`, every
|
|
55
|
+
`*HookSpecificOutput`), `PermissionResultAllow`, `PermissionResultDeny`,
|
|
56
|
+
`PermissionUpdate` and `PermissionRuleValue`. The full list is in
|
|
57
|
+
[docs/types.md](docs/types.md#unknown-keys).
|
|
58
|
+
|
|
59
|
+
**Fix:** correct the key, or remove it if the type never had it. Symbol and
|
|
60
|
+
String keys, snake_case and camelCase all still work, and so does a type's own
|
|
61
|
+
discriminator (`type`, `hook_event_name`, `behavior`), so on types that define
|
|
62
|
+
their own `#to_h` (the MCP server configs, `SandboxSettings`, the system prompt
|
|
63
|
+
types, the hook outputs, ...) `klass.new(value.to_h)` round-trips. For a Hash you did not write yourself (deserialized from the CLI,
|
|
64
|
+
a queue or a database), use `.from_hash` or `.wrap`: both stay lenient and
|
|
65
|
+
ignore unknown keys. Types the SDK parses from CLI output (messages, content
|
|
66
|
+
blocks, hook inputs) are not affected.
|
|
67
|
+
|
|
68
|
+
## `#[]`, `#[]=` and camelCase reach attributes only
|
|
69
|
+
|
|
70
|
+
These accessors are public API for a type's attributes: the fields it declares,
|
|
71
|
+
predicates such as `options.forkSession?`, and any method your own code adds to
|
|
72
|
+
a subclass, a mixin or an instance. Through 0.37 they reached *any* public
|
|
73
|
+
method. In 1.0 a name that is not an attribute behaves like an undefined one:
|
|
74
|
+
|
|
75
|
+
| Call | 0.37 | 1.0 |
|
|
76
|
+
|------|------|-----|
|
|
77
|
+
| `msg[:to_h]`, `msg['freeze']` | calls the method, warns | `nil` (method not called) |
|
|
78
|
+
| `msg[:some_method] = x` | calls `some_method=`, warns | ignored; `ArgumentError` on the strict types above |
|
|
79
|
+
| `msg.toH` | calls `to_h`, warns | `NoMethodError`; `respond_to?(:toH)` is `false` |
|
|
80
|
+
|
|
81
|
+
**Fix:** call the method directly (`msg.to_h`). `UserMessage#text` and
|
|
82
|
+
`AssistantMessage#text` are convenience methods, not attributes, so
|
|
83
|
+
`msg[:text]` is `nil`; use `msg.text`.
|
|
84
|
+
|
|
85
|
+
## `SessionStoreError` replaces `RuntimeError` on store-backed resume
|
|
86
|
+
|
|
87
|
+
When `query`, `ask` or `Client#connect` resume a session from
|
|
88
|
+
`session_store:` and a store call raises or exceeds `load_timeout_ms`, they now
|
|
89
|
+
raise `ClaudeAgentSDK::SessionStoreError < ClaudeSDKError`. In 0.37 this was a
|
|
90
|
+
bare `RuntimeError`, and a `RuntimeError` raised by your adapter escaped
|
|
91
|
+
unwrapped, so `rescue ClaudeAgentSDK::ClaudeSDKError` missed both. The message
|
|
92
|
+
names the store call and `#cause` holds your adapter's exception (or the
|
|
93
|
+
timeout):
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
begin
|
|
97
|
+
ClaudeAgentSDK.ask('Continue', options: options)
|
|
98
|
+
rescue ClaudeAgentSDK::SessionStoreError => e
|
|
99
|
+
e.message # "SessionStore#load for session 3f2c… failed during resume materialization: IOError: …"
|
|
100
|
+
e.cause # the IOError your adapter raised
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Fix:** replace `rescue RuntimeError` on these paths with
|
|
105
|
+
`rescue ClaudeAgentSDK::SessionStoreError` (or `ClaudeSDKError`). Other store
|
|
106
|
+
paths are unchanged: the session functions called with `session_store:` behave
|
|
107
|
+
exactly as in 0.37, and mirroring failures still arrive as
|
|
108
|
+
`MirrorErrorMessage`, never as exceptions.
|
|
109
|
+
|
|
110
|
+
## What SemVer covers from 1.0
|
|
111
|
+
|
|
112
|
+
No breaking changes within 1.x to the public API: everything documented in
|
|
113
|
+
`docs/` and the README, and every class, module, method and constant in the
|
|
114
|
+
YARD docs that is not tagged `@api private`. `@api private` objects (`Query`,
|
|
115
|
+
`MessageParser`, `FiberBoundary`, the `Sessions*` modules, ...) stay callable
|
|
116
|
+
but can change in any release. See
|
|
117
|
+
[CONTRIBUTING.md](https://github.com/ya-luotao/claude-agent-sdk-ruby/blob/main/CONTRIBUTING.md#what-is-public-api).
|
|
118
|
+
|
|
119
|
+
A removal is first deprecated in a minor release with a one-time warning that
|
|
120
|
+
names the replacement, and happens in the next major.
|
|
121
|
+
|
|
122
|
+
## The Hash-key rule
|
|
123
|
+
|
|
124
|
+
Unchanged in 1.0, and now part of the SemVer contract: a plain Hash passed
|
|
125
|
+
through from the CLI's live stream (`usage`, `origin`, hook `tool_input`, the
|
|
126
|
+
`can_use_tool` input, SDK MCP tool `args`, `Client#mcp_status`) has **Symbol**
|
|
127
|
+
keys spelled as on the wire; a Hash read from a transcript or a `SessionStore`
|
|
128
|
+
(`SessionMessage#message`, `get_subagent_metadata`, store keys and entries) has
|
|
129
|
+
**String** keys. The wrong form reads `nil` rather than raising. See
|
|
130
|
+
[docs/types.md](docs/types.md#hash-keys).
|
|
131
|
+
|
|
132
|
+
## Deprecated, kept through 1.x
|
|
133
|
+
|
|
134
|
+
The ten store-specific session functions still work in 1.x and still print a
|
|
135
|
+
one-time warning. They will be removed in 2.0. Each is the same call as its
|
|
136
|
+
replacement:
|
|
137
|
+
|
|
138
|
+
| Deprecated | Replacement |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `list_sessions_from_store(session_store: s, ...)` | `list_sessions(session_store: s, ...)` |
|
|
141
|
+
| `get_session_info_from_store(session_store: s, ...)` | `get_session_info(session_store: s, ...)` |
|
|
142
|
+
| `get_session_messages_from_store(session_store: s, ...)` | `get_session_messages(session_store: s, ...)` |
|
|
143
|
+
| `list_subagents_from_store(session_store: s, ...)` | `list_subagents(session_store: s, ...)` |
|
|
144
|
+
| `get_subagent_metadata_from_store(session_store: s, ...)` | `get_subagent_metadata(session_store: s, ...)` |
|
|
145
|
+
| `get_subagent_messages_from_store(session_store: s, ...)` | `get_subagent_messages(session_store: s, ...)` |
|
|
146
|
+
| `rename_session_via_store(session_store: s, ...)` | `rename_session(session_store: s, ...)` |
|
|
147
|
+
| `tag_session_via_store(session_store: s, ...)` | `tag_session(session_store: s, ...)` |
|
|
148
|
+
| `delete_session_via_store(session_store: s, ...)` | `delete_session(session_store: s, ...)` |
|
|
149
|
+
| `fork_session_via_store(session_store: s, ...)` | `fork_session(session_store: s, ...)` |
|
|
150
|
+
|
|
151
|
+
`import_session_to_store` is not deprecated.
|
data/docs/errors.md
CHANGED
|
@@ -117,6 +117,11 @@ end
|
|
|
117
117
|
# no usable home directory exists for the default ~/.claude
|
|
118
118
|
class ConfigDirError < ClaudeSDKError; end
|
|
119
119
|
|
|
120
|
+
# Raised when resuming from a SessionStore fails: a store call raised or
|
|
121
|
+
# exceeded load_timeout_ms during resume materialization. #cause holds the
|
|
122
|
+
# adapter's exception (or the timeout)
|
|
123
|
+
class SessionStoreError < ClaudeSDKError; end
|
|
124
|
+
|
|
120
125
|
# Raised when the Claude Code process fails
|
|
121
126
|
class ProcessError < ClaudeSDKError
|
|
122
127
|
attr_reader :exit_code, # Integer | nil
|
|
@@ -155,6 +160,7 @@ end
|
|
|
155
160
|
| `ControlRequestTimeoutError` | Control protocol timeout (configurable via env var) |
|
|
156
161
|
| `CLINotFoundError` | Claude Code not installed |
|
|
157
162
|
| `ConfigDirError` | A local-disk session API (`list_sessions`, `get_session_*`, `rename_session`, ...) could not locate the Claude config directory: `CLAUDE_CONFIG_DIR` is unset and there is no usable home directory (`HOME` unset with no passwd entry, as under `docker --user` in a minimal image, or an empty/relative `HOME`). Set `CLAUDE_CONFIG_DIR` |
|
|
163
|
+
| `SessionStoreError` | Resuming from `session_store:` failed: a store call (`#load`, `#list_sessions`, `#list_subkeys`) raised or exceeded `load_timeout_ms` while the SDK materialized the transcript, before the CLI started. The message names the call; `#cause` is the adapter's exception. Before 1.0 this was a bare `RuntimeError` — see [Sessions](sessions.md#mirroring-to-a-sessionstore) |
|
|
158
164
|
| `ProcessError` | Process failed (includes `exit_code` and `stderr`) — also raised when the CLI is still running 5s after closing stdout and the SDK had to terminate it |
|
|
159
165
|
| `ResultError` | Run ended on a terminal error result (subclasses `ProcessError`; adds `subtype`, `errors`, `api_error_status`, `terminal_reason`, ...) — rescue it first |
|
|
160
166
|
| `CLIJSONDecodeError` | JSON parsing issues — including stdout ending mid-frame (a truncated final message; `line` holds the partial frame) |
|
data/docs/sessions.md
CHANGED
|
@@ -227,6 +227,25 @@ while an append is in flight are coalesced into the next append, so a slow
|
|
|
227
227
|
store never accumulates one background task per frame), and `load_timeout_ms`
|
|
228
228
|
(per store call during resume materialization, default `60_000`).
|
|
229
229
|
|
|
230
|
+
If a store call raises or exceeds `load_timeout_ms` during resume
|
|
231
|
+
materialization, `ClaudeAgentSDK.query`, `.ask` and `Client#connect` raise
|
|
232
|
+
`ClaudeAgentSDK::SessionStoreError` (a `ClaudeSDKError`) before the CLI
|
|
233
|
+
starts. The message names the call (`SessionStore#load for session <id> failed
|
|
234
|
+
during resume materialization: IOError: ...`) and `#cause` holds the adapter's
|
|
235
|
+
own exception, or the internal timeout:
|
|
236
|
+
|
|
237
|
+
```ruby
|
|
238
|
+
begin
|
|
239
|
+
ClaudeAgentSDK.ask('Continue', options: options.dup_with(resume: session_id))
|
|
240
|
+
rescue ClaudeAgentSDK::SessionStoreError => e
|
|
241
|
+
logger.warn("resume from store failed: #{e.message} (#{e.cause&.class})")
|
|
242
|
+
raise
|
|
243
|
+
end
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Before 1.0 this surfaced as a bare `RuntimeError` (and a `RuntimeError` your
|
|
247
|
+
adapter raised escaped unwrapped), which `rescue ClaudeSDKError` missed.
|
|
248
|
+
|
|
230
249
|
Resume materialization re-serializes each loaded entry to JSONL. An entry that
|
|
231
250
|
cannot be serialized (NaN/Infinity, invalid UTF-8, circular nesting), an
|
|
232
251
|
unserializable subagent metadata sidecar, or a subkey that is not a safe
|
|
@@ -478,7 +497,7 @@ skipped with a warning.
|
|
|
478
497
|
> `get_subagent_messages_from_store`, `rename_session_via_store`,
|
|
479
498
|
> `tag_session_via_store`, `delete_session_via_store`,
|
|
480
499
|
> `fork_session_via_store`) still work unchanged but print a one-time
|
|
481
|
-
> deprecation warning and will be removed in
|
|
500
|
+
> deprecation warning; they stay through 1.x and will be removed in 2.0. Replace
|
|
482
501
|
> `ClaudeAgentSDK.x_from_store(session_store: store, ...)` or
|
|
483
502
|
> `x_via_store(session_store: store, ...)` with
|
|
484
503
|
> `ClaudeAgentSDK.x(..., session_store: store)`.
|
data/docs/types.md
CHANGED
|
@@ -47,8 +47,8 @@ msg.sessionId # camelCase reader (also answers respond_to?)
|
|
|
47
47
|
|
|
48
48
|
`#[]` returns `nil` for a name the type does not define, while a misspelled
|
|
49
49
|
method call such as `msg.nope` raises `NoMethodError`. These accessors reach a type's
|
|
50
|
-
**attributes** only; any other method
|
|
51
|
-
|
|
50
|
+
**attributes** only; any other method (`to_h`, `freeze`, ...) counts as undefined —
|
|
51
|
+
see [Attributes Only](#attributes-only).
|
|
52
52
|
|
|
53
53
|
`#[]=` assigns through the attribute's setter, with the same name
|
|
54
54
|
normalization, and returns the assigned value:
|
|
@@ -63,8 +63,8 @@ msg[:result] = 'edited' # same as msg.result = 'edited'
|
|
|
63
63
|
Copy first if you need the original.
|
|
64
64
|
- A name the type does not define is ignored on the types the SDK parses from
|
|
65
65
|
CLI output. `ClaudeAgentOptions` raises `ArgumentError` for an unknown key (as
|
|
66
|
-
its constructor and `dup_with` do), and the value types you build and
|
|
67
|
-
|
|
66
|
+
its constructor and `dup_with` do), and so do the value types you build and
|
|
67
|
+
pass in — see [Unknown Keys](#unknown-keys).
|
|
68
68
|
- Discriminator fields (`type` on the MCP server and system-prompt configs,
|
|
69
69
|
`behavior` on `PermissionResultAllow` / `PermissionResultDeny`,
|
|
70
70
|
`hook_event_name` on hook inputs and outputs) are read-only, so
|
|
@@ -380,29 +380,32 @@ end
|
|
|
380
380
|
|
|
381
381
|
### Unknown Keys
|
|
382
382
|
|
|
383
|
-
`ClaudeAgentOptions`
|
|
383
|
+
`ClaudeAgentOptions` and the value types you build and pass *in* raise `ArgumentError` on a key they do not define, naming the class, the key and the keys it accepts:
|
|
384
384
|
|
|
385
|
-
```
|
|
386
|
-
|
|
385
|
+
```ruby
|
|
386
|
+
ClaudeAgentSDK::HookMatcher.new(matchr: 'Bash', hooks: [check])
|
|
387
|
+
# ArgumentError: ClaudeAgentSDK::HookMatcher: unknown attribute :matchr (known: hooks, matcher, timeout)
|
|
387
388
|
```
|
|
388
389
|
|
|
389
|
-
|
|
390
|
+
This covers `.new` and `#[]=` on:
|
|
390
391
|
|
|
391
392
|
- option values: `AgentDefinition`, `SandboxSettings`, `SandboxNetworkConfig`, `SandboxFilesystemConfig`, `ThinkingConfigAdaptive` / `Enabled` / `Disabled`, `TaskBudget`, `SystemPromptPreset` / `Custom` / `File`, `ToolsPreset`, `SdkPluginConfig`, `McpStdioServerConfig`, `McpSSEServerConfig`, `McpHttpServerConfig`, `McpSdkServerConfig`
|
|
392
393
|
- `HookMatcher` and hook outputs: `SyncHookJSONOutput`, `AsyncHookJSONOutput`, every `*HookSpecificOutput`
|
|
393
394
|
- `PermissionResultAllow`, `PermissionResultDeny`, `PermissionUpdate`, `PermissionRuleValue`
|
|
394
395
|
|
|
395
|
-
|
|
396
|
+
A nested value is checked as its own type: `PermissionUpdate.new(rules: [{ rule_contnt: 'x' }])` raises naming `PermissionRuleValue`.
|
|
397
|
+
|
|
398
|
+
Accepted: Symbol or String keys, snake_case or camelCase spellings, and the fixed discriminator a type sets itself (`type`, `hook_event_name`, `behavior`), so on a type that defines its own `#to_h` (the MCP server configs, `SandboxSettings`, the system prompt types, the hook outputs, ...) `klass.new(value.to_h)` round-trips. Types the SDK parses from CLI output (messages, content blocks, hook inputs, `ToolPermissionContext`, the MCP status types) stay lenient, so a field added by a newer CLI is ignored rather than raising, and so does every construction through `.from_hash` or `.wrap`. Use those two for data you did not write yourself, such as a Hash deserialized from the CLI or from storage.
|
|
399
|
+
|
|
400
|
+
(0.37 printed a one-time warning here and ignored the key; 1.0 raises. See [UPGRADING-1.0.md](../UPGRADING-1.0.md).)
|
|
396
401
|
|
|
397
402
|
### Attributes Only
|
|
398
403
|
|
|
399
|
-
`#[]`, `#[]=` and the camelCase readers (`msg[:session_id]`, `msg['sessionId']`, `msg.sessionId`) are public API for a type's **attributes**: the fields it declares, plus predicates such as `options.forkSession?`. Methods your own code adds to a subclass (an `attr_accessor`, a hand-written reader or setter, a mixin's accessors, a singleton method) count as attributes too.
|
|
404
|
+
`#[]`, `#[]=` and the camelCase readers (`msg[:session_id]`, `msg['sessionId']`, `msg.sessionId`) are public API for a type's **attributes**: the fields it declares, plus predicates such as `options.forkSession?`. Methods your own code adds to a subclass (an `attr_accessor`, a hand-written reader or setter, a mixin's accessors, a singleton method) count as attributes too.
|
|
400
405
|
|
|
401
|
-
|
|
402
|
-
app/jobs/sync.rb:8: warning: ClaudeAgentSDK::ResultMessage#[]: :to_h is not an attribute; Type#[] will only read attributes in 1.0
|
|
403
|
-
```
|
|
406
|
+
A name that is not an attribute behaves like an undefined one: `#[]` returns `nil`, `#[]=` ignores it (on the strict types above it raises `ArgumentError`), a camelCase call raises `NoMethodError`, and `respond_to?` answers `false`. So `msg[:to_h]` is `nil`, `msg['freeze']` does not freeze the message, and `msg.toH` raises; call the method directly instead (`msg.to_h`). `UserMessage#text` and `AssistantMessage#text` are convenience methods, not attributes.
|
|
404
407
|
|
|
405
|
-
|
|
408
|
+
(Through 0.37 these accessors reached any public method, with a one-time warning in 0.37.)
|
|
406
409
|
|
|
407
410
|
## Constants
|
|
408
411
|
|
|
@@ -35,56 +35,17 @@ module ClaudeAgentSDK
|
|
|
35
35
|
return unless first
|
|
36
36
|
|
|
37
37
|
begin
|
|
38
|
-
warn("ClaudeAgentSDK.#{name} is deprecated and will be removed in
|
|
38
|
+
warn("ClaudeAgentSDK.#{name} is deprecated and will be removed in 2.0; " \
|
|
39
39
|
"use ClaudeAgentSDK.#{replacement}", uplevel: 2)
|
|
40
40
|
rescue StandardError
|
|
41
41
|
nil
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
# Warn +message+ once per process per +key+, attributed to the first
|
|
46
|
-
# caller frame outside the SDK's lib/ directory: the user's call site,
|
|
47
|
-
# however deep inside the SDK the deprecated behaviour is detected
|
|
48
|
-
# (e.g. an unknown attribute found by Type#assign_attribute during
|
|
49
|
-
# HookMatcher.new). Best-effort like #warn_once.
|
|
50
|
-
#
|
|
51
|
-
# @param key [Object] once-guard key; any value usable in a Set
|
|
52
|
-
# @param message [String]
|
|
53
|
-
# @return [void]
|
|
54
|
-
def warn_once_at_caller(key, message)
|
|
55
|
-
first = @mutex.synchronize { @warned.add?(key) }
|
|
56
|
-
return unless first
|
|
57
|
-
|
|
58
|
-
begin
|
|
59
|
-
locations = caller_locations(1)
|
|
60
|
-
index = locations.index { |location| !sdk_frame?(location) }
|
|
61
|
-
index ? warn(message, uplevel: index + 1) : warn(message)
|
|
62
|
-
rescue StandardError
|
|
63
|
-
nil
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
45
|
# Test hook: forget which deprecations were already reported.
|
|
68
46
|
def reset!
|
|
69
47
|
@mutex.synchronize { @warned.clear }
|
|
70
48
|
end
|
|
71
|
-
|
|
72
|
-
private
|
|
73
|
-
|
|
74
|
-
# A frame inside the gem's lib/ (both the loaded and the real path, in
|
|
75
|
-
# case lib/ is reached through a symlink), or a Ruby-internal one
|
|
76
|
-
# (<internal:...>, e.g. Array#each on 3.4). A C frame such as Class#new
|
|
77
|
-
# reports its caller's path, so it counts as the caller's.
|
|
78
|
-
def sdk_frame?(location)
|
|
79
|
-
path = location.absolute_path || location.path
|
|
80
|
-
return true if path.nil? || path.start_with?('<internal:')
|
|
81
|
-
|
|
82
|
-
SDK_LIB_DIRS.any? { |dir| path.start_with?(dir) }
|
|
83
|
-
end
|
|
84
49
|
end
|
|
85
|
-
|
|
86
|
-
SDK_LIB_DIRS = [File.expand_path('..', File.dirname(__FILE__)), File.expand_path('..', __dir__)]
|
|
87
|
-
.uniq.map { |dir| "#{dir}/" }.freeze
|
|
88
|
-
private_constant :SDK_LIB_DIRS
|
|
89
50
|
end
|
|
90
51
|
end
|
|
@@ -31,6 +31,14 @@ module ClaudeAgentSDK
|
|
|
31
31
|
# relative HOME). Set CLAUDE_CONFIG_DIR to fix it.
|
|
32
32
|
class ConfigDirError < ClaudeSDKError; end
|
|
33
33
|
|
|
34
|
+
# Raised when resuming a session from ClaudeAgentOptions#session_store
|
|
35
|
+
# fails: a store call (#load, #list_sessions, #list_subkeys, ...) raised or
|
|
36
|
+
# exceeded load_timeout_ms while the SDK was materializing the transcript
|
|
37
|
+
# for the CLI. Raised by Client#connect, ClaudeAgentSDK.query and .ask,
|
|
38
|
+
# before the CLI starts. The message names the store call; #cause holds the
|
|
39
|
+
# adapter's own exception (or the internal timeout).
|
|
40
|
+
class SessionStoreError < ClaudeSDKError; end
|
|
41
|
+
|
|
34
42
|
# Raised when the CLI process fails
|
|
35
43
|
class ProcessError < ClaudeSDKError
|
|
36
44
|
attr_reader :exit_code, :stderr
|
|
@@ -112,6 +120,8 @@ module ClaudeAgentSDK
|
|
|
112
120
|
# never disagree. Private to ResultError (Python keeps the equivalent
|
|
113
121
|
# helpers module-private as _normalize_result_errors); callers outside
|
|
114
122
|
# go through .error_text.
|
|
123
|
+
#
|
|
124
|
+
# @api private
|
|
115
125
|
module Payload
|
|
116
126
|
module_function
|
|
117
127
|
|
|
@@ -119,7 +119,8 @@ module ClaudeAgentSDK
|
|
|
119
119
|
# Returns a MaterializedResume, or nil when no materialization is needed
|
|
120
120
|
# (no store, no resume/continue, store has no entries, or the resolved
|
|
121
121
|
# session id is not a valid UUID) — the caller then falls through to the
|
|
122
|
-
# normal spawn path. Raises
|
|
122
|
+
# normal spawn path. Raises SessionStoreError (#cause: the adapter's own
|
|
123
|
+
# exception or the timeout) if a store call fails or times out.
|
|
123
124
|
def materialize_resume_session(options) # rubocop:disable Metrics/AbcSize -- materialization sequence kept in order
|
|
124
125
|
store = options.session_store
|
|
125
126
|
return nil if store.nil?
|
|
@@ -290,7 +291,12 @@ module ClaudeAgentSDK
|
|
|
290
291
|
end
|
|
291
292
|
|
|
292
293
|
# Run a store call (user code) on a plain thread bounded by timeout_s,
|
|
293
|
-
# re-raising failures/timeouts as
|
|
294
|
+
# re-raising failures/timeouts as SessionStoreError with context, the
|
|
295
|
+
# original as #cause (Ruby sets it: the raise is inside the rescue). Every
|
|
296
|
+
# StandardError is wrapped, the adapter's own RuntimeError included, so
|
|
297
|
+
# `rescue ClaudeSDKError` catches every materialization failure (0.x let
|
|
298
|
+
# a RuntimeError through unwrapped and raised the rest as bare
|
|
299
|
+
# RuntimeErrors, mirroring Python). The thread hop
|
|
294
300
|
# (the default for FiberBoundary with a timeout) both keeps the async
|
|
295
301
|
# scheduler out of the user's store code AND enforces load_timeout_ms
|
|
296
302
|
# unconditionally — including when materialization runs outside an Async
|
|
@@ -305,11 +311,11 @@ module ClaudeAgentSDK
|
|
|
305
311
|
def with_timeout(timeout_s, what, scheduling = :thread, wrapper = nil, &)
|
|
306
312
|
FiberBoundary.invoke(timeout: timeout_s, scheduling: scheduling, wrapper: wrapper, &)
|
|
307
313
|
rescue FiberBoundary::JoinTimeout
|
|
308
|
-
raise "#{what} timed out after #{(timeout_s * 1000).to_i}ms during resume materialization"
|
|
309
|
-
rescue
|
|
314
|
+
raise SessionStoreError, "#{what} timed out after #{(timeout_s * 1000).to_i}ms during resume materialization"
|
|
315
|
+
rescue SessionStoreError
|
|
310
316
|
raise
|
|
311
317
|
rescue StandardError => e
|
|
312
|
-
raise "#{what} failed during resume materialization: #{e}"
|
|
318
|
+
raise SessionStoreError, "#{what} failed during resume materialization: #{e.class}: #{e.message}"
|
|
313
319
|
end
|
|
314
320
|
|
|
315
321
|
# Write pre-encoded JSON lines (see encode_jsonl_lines), one per line,
|
|
@@ -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
|
|