Skip to content

feat(ruby): M3 — inbound dispatcher + client-side LLMs (77/77) - #2855

Draft
filip-michalsky wants to merge 1 commit into
filipmichalsky/ruby-sdk-m1-m2from
filipmichalsky/ruby-sdk-m3
Draft

feat(ruby): M3 — inbound dispatcher + client-side LLMs (77/77)#2855
filip-michalsky wants to merge 1 commit into
filipmichalsky/ruby-sdk-m1-m2from
filipmichalsky/ruby-sdk-m3

Conversation

@filip-michalsky

Copy link
Copy Markdown
Collaborator

Part of the AP-2857 parity stack:

Stack: #2820 (spike) ← #2854 (M1–M2) ← this PR (M3) ← M4 (#2851)

The 77th and final protocol method — inbound llm.generate:

  • RPCClient gains a dedicated dispatcher thread for inbound work and an on_request API: params decoded and results validated via the generated wire registry, JSON-RPC error mapping matching Python (-32601/-32602/-32603 with the error class name as data)
  • Notification listeners (including page.on blocks) now run on the dispatcher and may issue RPC calls (the reader-thread restriction is gone)
  • Stagehand.create(model: ->(params) { … }) registers an llm.generate handler and announces ClientModelReference(source: "client") in stagehand.init
  • Wire unions follow nested union references, so LLM message content decodes to typed blocks
  • examples/custom_llm.rb: port of custom_llm.py over an OpenAI-compatible chat completions endpoint (OPENAI_API_KEY or Vercel AI Gateway)

Verification

  • 108 unit tests / 711 assertions
  • Live on local Chrome and Browserbase: custom_llm.rb runs extract/observe/act with every model call served by the Ruby callback (4 llm.generate round trips)

🤖 Generated with Claude Code

- rpc_client: dedicated dispatcher thread for inbound work; on_request API
  (params decoded / results validated via Models::METHODS, JSON-RPC error
  mapping matching Python: -32601/-32602/-32603 with error name data);
  notification listeners now run on the dispatcher and may issue RPC calls
- client: model: accepts a callable -> registers an llm.generate handler and
  announces ClientModelReference(source: "client") in stagehand.init
- wire: unions follow nested union references (LLMMessageContentBlock blocks
  decode to LLMTextContent etc. instead of raw hashes)
- examples/custom_llm.rb: port of custom_llm.py over an OpenAI-compatible
  chat completions endpoint (OPENAI_API_KEY or Vercel AI Gateway); verified
  live on local Chrome and Browserbase (extract/observe/act all served by
  the Ruby callback)
- tests: on_request round trip, handler-issued RPC calls, error mapping,
  removal semantics, client wiring (108 runs, 711 assertions)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Aug 29, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 7c9f052

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant