Skip to content

v0.25.0

Choose a tag to compare

@ya-luotao ya-luotao released this 31 Jul 06:05
· 570 commits to main since this release

Added

  • Opt-in fiber-native callback execution: callback_scheduling: :inline (#47). By default the SDK hops every user callback (message blocks, hooks, permission callbacks, SDK MCP handlers, observers) to a plain thread so thread-keyed libraries (ActiveRecord, pg, …) never see the async gem's Fiber scheduler. Hosts that are fiber-isolated end to end — e.g. solid_queue fiber workers (fibers: N) with ActiveSupport::IsolatedExecutionState.isolation_level = :fiber — can now run callbacks in place on the reactor fiber: Fiber.scheduler is live inside callbacks, no per-call threads exist to strand AR connections, and the session can live directly on the job fiber. Matches the Python SDK's execution model. Default behavior is unchanged.
    • In :inline mode hook timeouts become cooperative cancellations (interrupted at the next suspension point, ensure blocks run) instead of hard thread abandonment — and a hook's rescue StandardError cannot swallow the cancellation.
    • SessionStore adapter calls intentionally stay on threads so a wedged adapter can never stall the reactor.
    • Warns once when :inline is enabled under isolation_level == :thread.
    • Sessions with different modes sharing one SDK MCP server stay fully isolated (mode travels via a scoped, invalidatable fiber-storage carrier — the server instance is never mutated).
  • ClaudeAgentSDK.offload { } — public escape hatch for :inline hosts: runs a heavy piece of a callback on a plain thread instead of the reactor fiber. Shields the reactor from scheduler-opaque blocking that releases the GVL; turns pure-Ruby CPU work into GVL time-slicing instead of a hard stall. (A C extension that holds the GVL still freezes the process — use a subprocess.) No-op outside a reactor.

Usage

# config/initializers/claude_agent_sdk.rb — solid_queue fiber-worker processes
ClaudeAgentSDK.configure do |config|
  config.default_options = { callback_scheduling: :inline }
end

# Heavy work inside an inline callback:
tool = ClaudeAgentSDK.create_tool('lookup', 'Query legacy DB', { id: String }) do |args|
  row = ClaudeAgentSDK.offload { legacy_client.fetch(args[:id]) }
  { content: [{ type: 'text', text: row.to_json }] }
end

See the new "Fiber workers (solid_queue) and callback_scheduling: :inline" section in docs/rails.md.

What's changed

  • #48 Fiber-native callback execution: opt-in callback_scheduling: :inline (#47 phase 1) — @ya-luotao

Full Changelog: v0.24.0...v0.25.0


gem install claude-agent-sdk -v 0.25.0