Repository navigation
v0.16.8
Patch release: README restructure into docs/ topic subpages, plus a sweep of P0/P1 production-hardening fixes across transport, query, sessions, types, and SDK MCP (PR #34). All fixes target accidental behavior — no documented API contracts changed.
Added
ServerToolUseBlock+ServerToolResultBlockcontent blocks for the CLI's built-in server-side tools (web_search,advisor,code_execution). Parser now recognisesserver_tool_use/server_tool_result.DeferredToolUseclass andResultMessage#deferred_tool_usefield — populated when a PreToolUse hook returnspermissionDecision: "defer".ResultMessage#api_error_status— integer HTTP status (429, 500, 529) on theapi_errorsubtype (CLI 2.1.110+).ToolPermissionContextgainstitle,display_name,description,blocked_path,decision_reasonsocan_use_toolcallbacks can render the same prompt UI the CLI would.PostToolUseHookSpecificOutput#updated_tool_output— unified tool-output replacement that works for any tool (MCP or built-in).
Changed
- README slimmed from 1857 lines to ~285; detail moved into nine topic subpages under
docs/(client.md,mcp-servers.md,hooks-and-permissions.md,configuration.md,sessions.md,observability.md,rails.md,types.md,errors.md). The gemspec now shipsdocs/**/*sobundle show claude-agent-sdkexposes the full reference offline. Query#startraisesCLIConnectionErrorif invoked outsideAsync{}. The previous implementation appeared to support synchronous callers but silently hung forever. All documented usage already wraps inAsync{}, so this only surfaces a previously hidden failure mode.CommandBuilderraisesArgumentErrorsynchronously when bothcontinue_conversationandresumeare set, instead of producing an opaque non-zero CLI exit.sdk_mcp_server'sread_resource,get_prompt, dynamicResource#read, and dynamicPrompt#getnow hop throughFiberBoundary.invoke(matchingcall_tool). User reader/generator blocks that touchThread.current-keyed libraries (ActiveRecord, pg) no longer see the async-gem fiber scheduler.
Fixed
- Transport
@stdinrace:write/closeare now serialised by a mutex. User callbacks onFiberBoundarythreads can no longer raceclose()and hitNoMethodErroron a nilled@stdin. The mutex only guards the reference snapshot — blocking IO happens outside the lock so disconnect is never blocked by a full pipe buffer. - Transport stdout poisoning: stdout lines that do not start with
{are skipped when the JSON buffer is empty. Previously CLI debug prefixes like[SandboxDebug]accumulated until the 1 MB cap raisedCLIJSONDecodeErrorand killed the session. - Transport stderr resilience: each
stderrcallback invocation is wrapped inrescue StandardError. A transiently failing user logger no longer terminates the read loop and silently stops stderr capture (matches Python SDK v0.2.82 PR #932). - Transport process reaping:
@process.valueis&.-safe and rescuesErrno::ECHILD, so a concurrentclose()that already reaped the subprocess cannot crash the message loop. - Query read-loop cancellation:
@tasknow holds the actualread_messageschild task. The previous outer-Async-wrapper finished immediately, soclose's@task.stopnever reached the read fiber. - Query control-request leak:
send_control_requestcleans@pending_control_*in anensureblock and usesAsync::Task.current.with_timeout. AnAsync::Stoppropagating through.wait, or a latecontrol_responseafter timeout, can no longer leak pending state. - Session forks dropped metadata:
parse_fork_transcriptfilters transcript body byTRANSCRIPT_TYPES(user/assistant/attachment/system/progress).custom-title,tag,aiTitleno longer bleed into the forked transcript with the old sessionId. - Session forks lost content-replacement history:
content-replacemententries accumulate across compaction rounds (concatenated, not overwritten), gated on matchingsessionId. Forks emitcontent-replacementandcustom-titleentries withuuid+timestampso a fork-of-a-fork can re-ingest them. delete_sessionorphans: nowFileUtils.rm_rfs the sibling<session-id>/subagent transcript directory.detect_worktreeshang: 5-second hard cap withSIGKILLfallback. StdlibTimeout.timeoutis unsafe under the Async fiber scheduler (raises across threads viaThread#raise), so the new implementation drains stdout/stderr on side threads and kills the child on deadline. A pipe-buffer-overrun edge case that previously silently lost every worktree path is also fixed.
What's changed
- #34 Harden production paths: fix P0/P1 bugs across transport, query, sessions, and types — @ya-luotao
Full Changelog: v0.16.7...v0.16.8
gem install claude-agent-sdk -v 0.16.8