Skip to content

feat: add Responses WebSocket mode - #562

Open
jbeckwith-oai wants to merge 7 commits into
mainfrom
codex/responses-websocket-mode-ruby
Open

feat: add Responses WebSocket mode#562
jbeckwith-oai wants to merge 7 commits into
mainfrom
codex/responses-websocket-mode-ruby

Conversation

@jbeckwith-oai

@jbeckwith-oai jbeckwith-oai commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a Ruby-native block-scoped client.responses.connect WebSocket surface
  • extract product-neutral WebSocket transport, lifecycle, protocol, retry, and error helpers shared by Responses and Realtime
  • keep Realtime compatibility through thin facades while making Responses permissive: faithfully forward client fields, best-effort decode known events, and preserve unknown data
  • restore generated-union event typing and schema-shaped response.create keyword typing with consumer Sorbet coverage
  • add RBI/RBS declarations, README guidance, and focused regression coverage

Verification

  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/responses_websocket/connection_test.rb (39 runs, 170 assertions)
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/responses_websocket/errors_test.rb (1 run, 7 assertions)
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/responses_websocket/sorbet_test.rb (2 runs, 6 assertions)
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/realtime/connection_test.rb (32 runs, 227 assertions)
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/realtime/async_websocket_transport_test.rb (13 runs, 63 assertions)
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/realtime/network_invariants_test.rb (11 runs, 296 assertions)
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/realtime/auth_retry_test.rb (8 runs, 44 assertions)
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/realtime/sideband_connection_test.rb (13 runs, 47 assertions)
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/realtime/async_websocket_abort_test.rb (1 run, 7 assertions)
  • mise exec ruby@4.0.6 -- bundle exec rake typecheck:sorbet validate:rbs
  • focused RuboCop and git diff --check
  • two consecutive clean fresh-context adversarial-review rounds after the final code change
  • all GitHub checks green, including Ruby 3.3/3.4/4.0, bedrock, RBI/RBS, RuboCop, baseline consistency, and CodeQL

Notes

  • no generated model files were modified; the WebSocket behavior is layered in handwritten helpers around the existing generated Responses types
  • the separate generated-RBI soundness improvement is tracked in openai/openai#1425293 and openai/openai-ruby-internal#83
  • ambiguous writes remain terminal because delivery is unknowable; ordinary model-shape drift, error events, and payload-safe malformed JSON errors do not poison the connection

@jbeckwith-oai
jbeckwith-oai requested a review from a team as a code owner August 31, 2026 21:26
@openai-sdks

openai-sdks Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

OkTest Summary

237/237 SDK tests passed in 10.483s for Ruby SDK PR #562.

Test results — 42 files
Test Result Time
tests/chat-completions-complex-body.test.ts ✅ Passed 180ms
tests/chat-completions-create.test.ts ✅ Passed 240ms
tests/chat-completions-stream.test.ts ✅ Passed 143ms
tests/files-content-binary.test.ts ✅ Passed 216ms
tests/files-create-multipart.test.ts ✅ Passed 292ms
tests/files-list-pagination.test.ts ✅ Passed 171ms
tests/initialize-config.test.ts ✅ Passed 246ms
tests/instance-isolation.test.ts ✅ Passed 258ms
tests/models-list.test.ts ✅ Passed 224ms
tests/responses-background-lifecycle.test.ts ✅ Passed 207ms
tests/responses-body-method-errors.test.ts ✅ Passed 519ms
tests/responses-cancel-timeout.test.ts ✅ Passed 245ms
tests/responses-cancel.test.ts ✅ Passed 244ms
tests/responses-compact-retries.test.ts ✅ Passed 284ms
tests/responses-compact.test.ts ✅ Passed 261ms
tests/responses-create-advanced-stream.test.ts ✅ Passed 173ms
tests/responses-create-advanced.test.ts ✅ Passed 227ms
tests/responses-create-disconnect.test.ts ✅ Passed 1.077s
tests/responses-create-errors.test.ts ✅ Passed 280ms
tests/responses-create-malformed-api-responses.test.ts ✅ Passed 141ms
tests/responses-create-retries.test.ts ✅ Passed 334ms
tests/responses-create-stream-failures.test.ts ✅ Passed 194ms
tests/responses-create-stream-timeout.test.ts ✅ Passed 250ms
tests/responses-create-stream-wire.test.ts ✅ Passed 2.521s
tests/responses-create-stream.test.ts ✅ Passed 104ms
tests/responses-create-terminal-states.test.ts ✅ Passed 279ms
tests/responses-create-timeout.test.ts ✅ Passed 274ms
tests/responses-create.test.ts ✅ Passed 341ms
tests/responses-delete.test.ts ✅ Passed 300ms
tests/responses-input-items-errors.test.ts ✅ Passed 205ms
tests/responses-input-items-list.test.ts ✅ Passed 213ms
tests/responses-input-items-options.test.ts ✅ Passed 261ms
tests/responses-input-tokens-count-timeout.test.ts ✅ Passed 326ms
tests/responses-input-tokens-count.test.ts ✅ Passed 262ms
tests/responses-malformed-inputs.test.ts ✅ Passed 2.23s
tests/responses-not-found-errors.test.ts ✅ Passed 389ms
tests/responses-parse.test.ts ✅ Passed 195ms
tests/responses-retrieve-retries.test.ts ✅ Passed 317ms
tests/responses-retrieve.test.ts ✅ Passed 259ms
tests/responses-stored-method-errors.test.ts ✅ Passed 703ms
tests/retry-behavior.test.ts ✅ Passed 2.955s
tests/sdk-error-shape.test.ts ✅ Passed 382ms

View OkTest run #33912498550

SDK merge (6604eb28b248) · head (80ee59546dcb) · base (32989f4b2d45) · OkTest (2b1bdfd25e98)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T19:48:06.746010Z 80ee595 New commits
🔒 Security Review Completed 2026-09-04T19:48:01.065280Z 80ee595 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Castiron custom code

✅ No new custom-code files detected.

47 mixed files remain; 1 existing customization changed.

Compared 41eb726b66fc180f75fb4f18. Generated baselines verified.

File Result Current custom patch
lib/openai.rb Existing customization changed +38 / −6
46 existing customizations unchanged
  • lib/openai/client.rb
  • lib/openai/models/chat/chat_completion_message.rb
  • lib/openai/models/chat/chat_completion_message_function_tool_call.rb
  • lib/openai/models/chat/completion_create_params.rb
  • lib/openai/models/response_format_json_schema.rb
  • lib/openai/models/responses/function_tool.rb
  • lib/openai/models/responses/response.rb
  • lib/openai/models/responses/response_create_params.rb
  • lib/openai/models/responses/response_format_text_config.rb
  • lib/openai/models/responses/response_format_text_json_schema_config.rb
  • lib/openai/models/responses/response_function_tool_call.rb
  • lib/openai/models/responses/response_function_web_search.rb
  • lib/openai/models/responses/response_output_text.rb
  • lib/openai/models/responses/tool.rb
  • lib/openai/resources/beta/threads.rb
  • lib/openai/resources/chat/completions.rb
  • lib/openai/resources/files.rb
  • lib/openai/resources/responses.rb
  • lib/openai/resources/vector_stores/file_batches.rb
  • lib/openai/resources/vector_stores/files.rb
  • lib/openai/resources/webhooks.rb
  • rbi/openai/client.rbi
  • rbi/openai/models/chat/chat_completion_message.rbi
  • rbi/openai/models/chat/chat_completion_message_function_tool_call.rbi
  • rbi/openai/models/chat/completion_create_params.rbi
  • rbi/openai/models/response_format_json_schema.rbi
  • rbi/openai/models/responses/response.rbi
  • rbi/openai/models/responses/response_create_params.rbi
  • rbi/openai/models/responses/response_function_tool_call.rbi
  • rbi/openai/models/responses/response_function_web_search.rbi
  • rbi/openai/models/responses/response_output_text.rbi
  • rbi/openai/resources/chat/completions.rbi
  • rbi/openai/resources/files.rbi
  • rbi/openai/resources/responses.rbi
  • rbi/openai/resources/vector_stores/file_batches.rbi
  • rbi/openai/resources/vector_stores/files.rbi
  • scripts/castiron/README.md
  • scripts/castiron/custom_code_report.py
  • scripts/castiron/test_custom_code_report.py
  • sig/openai/client.rbs

6 more in the full report.

A changed generated baseline means this report cannot reliably identify which handwritten lines changed.

Inspect the custom-code diff

Download the exact patch produced by this run (requires repository access):

gh run download 33861286491 --repo openai/openai-ruby \
  --name castiron-custom-code-33861286491-1 --dir /tmp/castiron-custom-code-33861286491-1
git apply --stat /tmp/castiron-custom-code-33861286491-1/custom-code.patch
cat /tmp/castiron-custom-code-33861286491-1/custom-code.patch

Or reproduce it from an SDK checkout containing the vendored reporter:

git fetch --no-tags origin 32989f4b2d45edb4b2104a40f7561fb06c3341ee 180f75fb4f1843159668183b7cf349999e232bed
python3 scripts/castiron/custom_code_report.py report \
  --base 32989f4b2d45edb4b2104a40f7561fb06c3341ee \
  --head 180f75fb4f1843159668183b7cf349999e232bed --fetch --require-head-hash --public \
  --out /tmp/castiron-custom-code-180f75fb4f18
cat /tmp/castiron-custom-code-180f75fb4f18/custom-code.patch

This is the current full custom patch for mixed files, not an attribution of only the handwritten lines changed by this PR.

Full report and patch

@HAYDEN-OAI HAYDEN-OAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed d1bedef. Found two actionable correctness issues in nested-model serialization and application-exception propagation; details inline. Static source review only.

Comment thread lib/openai/helpers/responses_websocket/connection.rb Outdated
Comment thread lib/openai/helpers/responses_websocket/transports/async_websocket.rb Outdated

@HAYDEN-OAI HAYDEN-OAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 3e2a2a1. The previously reported nested-model serialization and callback-error issues are fixed. One high-priority correctness issue remains: valid function-call wire items are rejected because validation requires the SDK-computed parsed attribute. Details inline. Static source review only.

Comment thread lib/openai/helpers/responses_websocket/connection.rb Outdated

@apcha-oai apcha-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semantic notes
Blocking: this client is enforcing too much policy instead of acting as a permissive, faithful transport. It validates IDs, imposes arbitrary caps, rejects beta/newer fields, treats model coercion as wire validation, and permanently poisons the socket on ordinary shape mismatches.

We should match the SDK’s existing semantics here rather than inventing a stricter WebSocket-specific layer: faithfully pass requests through, parse responses flexibly, preserve unknown data, and avoid permanently poisoning the connection for model-shape mismatches. This should reuse the same established behavior as normal HTTP and streaming paths.

Design notes
I don’t think we should introduce another largely independent WebSocket stack. Responses is unlikely to be our last WebSocket API, and this causes some scaling issues for both consumers and maintainers.

At a high level, we should reuse and generalize the existing WebSocket machinery rather than fork it into another product-specific implementation.

Detailed design concerns:

  • blocking: OpenAI::Responses::Transports::AsyncWebSocket** delegates to OpenAI::Realtime::Transports::AsyncWebSocket and then translates RealtimeConnectionError into ResponsesConnectionError. I consider this blocking: generic WebSocket transport infrastructure should not be owned by one product API and adapted by every other product. The underlying transport and socket wrapper should move into a shared WebSocket namespace before we add another public WebSocket surface.
  • OpenAI::Realtime::ConnectionManager and OpenAI::Responses::ConnectionManager duplicate transport validation, opening, handshake completion, connection construction, yielding, closing, aborting, and cleanup behavior. That lifecycle machinery should be shared.
  • OpenAI::Helpers::Realtime::ClientExtension and OpenAI::Helpers::ResponsesWebSocket::ClientExtension duplicate WebSocket base-URL parsing, scheme conversion, request-option validation, header filtering, deadline handling, and workload-identity refresh behavior. That request/handshake construction should be shared.
  • OpenAI::Realtime::Connection and OpenAI::Responses::Connection both implement event iteration, reading, writing, closing, aborting, discriminator lookup, coercion validation, and unknown-event fallback. The common connection and protocol machinery should be shared, even if the public product connection classes remain thin separate facades.
  • OpenAI::Errors::RealtimeProtocolError, OpenAI::Errors::ResponsesProtocolError, OpenAI::Errors::ResponsesClientEventError, and OpenAI::Errors::ResponsesSendError: consider changing t part of a shared WebSocket error hierarchy rather than establishing another product-specific family.
  • Consumers shouldn’t need to rescue both OpenAI::Errors::RealtimeConnectionError and OpenAI::Errors::ResponsesConnectionError, plus additional equivalent errors for every future WebSocket API. These seem like protocol errors and not specific to the APIs

I feel less strongly about whether Realtime and Responses expose the exact same public connection class. Python and TypeScript retain product-specific connection surfaces, which may make sense given their different resource APIs. But those classes should ideally be thin product facades over one shared WebSocket core—not separate implementations or adapters that translate one product’s transport errors into another’s.

Realtime is new enough that we could either correct its public error surface in a breaking revision or preserve the existing names through compatibility inheritance. This is worth doing imo as we have several WS APIs already (e.g: responses beta)

Meta notes

Stepping back, most of the concerns above fall out of two guiding principles that I think Codex missed:

  • SDKs should be thin, permissive clients. They should generally pass inputs through faithfully, return what the API sends, and avoid imposing additional validation or policy beyond what is minimally necessary
  • Generic protocol infrastructure should not be owned by a product API. For something like WebSockets, we should build a shared abstraction that specific API surfaces can use, rather than reusing one product’s implementation from another or rebuilding the same stack for every API.

Comment thread lib/openai/helpers/responses_websocket/connection.rb Outdated
Comment thread lib/openai/helpers/responses_websocket/connection.rb Outdated
Comment thread lib/openai/helpers/responses_websocket/connection.rb Outdated
Comment thread lib/openai/helpers/responses_websocket/connection.rb Outdated
Comment thread rbi/openai/helpers/responses_websocket/connection.rbi Outdated
Comment thread rbi/openai/helpers/responses_websocket/connection_resources.rbi Outdated
Comment thread lib/openai/helpers/responses_websocket/connection.rb
Comment thread lib/openai/helpers/responses_websocket/connection.rb

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8135e8fd82

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/openai/helpers/responses_websocket/connection.rb Outdated
Comment thread lib/openai/helpers/responses_websocket/connection_resources.rb Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9697b901c6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rbi/openai/helpers/responses_websocket/connection.rbi Outdated
@jbeckwith-oai
jbeckwith-oai force-pushed the codex/responses-websocket-mode-ruby branch from 9697b90 to 33bd3a3 Compare September 2, 2026 23:35

@markstuart-oai markstuart-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 33bd3a3d9e6f3a1c8f8adc3eb464016a80296062. The transport, connection lifecycle, protocol, and error extraction address most of the earlier structural duplication, and the prior correctness issues are resolved. One maintainability concern remains in handshake construction; details inline. Exact-head CI is green; local runtime tests were unavailable because this leased box has neither Ruby nor mise.

Comment thread lib/openai/helpers/websocket/client_request.rb
@jbeckwith-oai
jbeckwith-oai force-pushed the codex/responses-websocket-mode-ruby branch from 06ba854 to 180f75f Compare September 4, 2026 10:01

@apcha-oai apcha-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The runtime changes address much of my earlier feedback: permissive parsing and forwarding, plus shared WebSocket infrastructure, are the right direction. However, the public typing remains blocking. We cannot ship this API with T.anything replacing its request and event types. Providing consumers with useful, accurate types is a core purpose of this SDK, and Sorbet is a first-class typechecker we support.

P0 — Restore the public request/event typing contract.

ServerEvent and ClientEvent are currently T.anything, with corresponding RBS top aliases. This removes the typing contract from the new API. Decoding events into generated classes at runtime does not substitute for static typing.

This has concrete consequences: Sorbet accepts connection.send_event(123) and connection.send_event(Object.new), while a README-style event loop fails at event.type because the received value is T.anything.

We need a properly typed surface before shipping. Either generate it, which I would prefer, or handwrite complete declarations referencing the generated types and maintain them accordingly. Erasing the public types is not an acceptable workaround for incorrect generated declarations.

P1 — Accurately type the accepted request parameters and support normal Sorbet usage.

response.create needs to describe the parameters it accepts—model, input, reasoning, tools, stream_id, etc.—with their schema-defined types and optionality. The distinction is whether those parameters are accurately typed, not whether the language represents them as keywords or an object.

The existing Ruby Responses#create RBI demonstrates the intended pattern: individually typed keyword parameters referencing generated types. Python similarly exposes typed keywords; Node exposes an object with explicitly typed properties. Please apply that pattern using the WebSocket schema.

The current create(**params) RBI instead declares each keyword value as T::Hash[Symbol, T.anything]. Ordinary string-valued model and input fail Sorbet, while invalid hash-valued versions pass.

Replacing that declaration with T.anything would remove the immediate error without providing the required parameter contract. Please add consumer typechecks demonstrating that normal calls succeed, incorrect known parameter types fail, and generated nested inputs work correctly.

Clarification on stream_id — resolved, not blocking.

I am withdrawing the earlier P2 concern. This is the known Sorbet hash-shape limitation around omitted keys, not a Ruby runtime or WebSocket-specific model regression. The direct stream_id accessor is correctly typed as T.nilable(String), and the RBS declarations already mark the hash key optional. Sorbet cannot express that same optional-key contract precisely in an RBI heterogeneous hash shape; in the supported version, indexing the shape with to_hash[:stream_id] is inferred as T.untyped. The earlier passing hash-indexing example therefore did not demonstrate that Sorbet had established a non-null String.

I consider this concern resolved within the SDK’s existing, documented Sorbet limitation. It is not an additional prerequisite for this PR, and it does not justify replacing the generated event types with T.anything; the P0 and P1 requirements above remain.

The live tests provide useful evidence that the runtime works—including function-call events, generated-model replay, and sequential requests—but green runtime tests and CI do not establish a correctly typed public API.

@jbeckwith-oai

jbeckwith-oai commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the remaining review feedback in 80ee595:

  • P0: Connection::ServerEvent and ClientEvent now expose the generated Responses WebSocket unions, with UnknownServerEvent / raw hash fallbacks instead of T.anything / top.
  • P1: response.create now has schema-shaped known keyword types in RBI and RBS while retaining **params at runtime for forward-compatible fields. Added consumer Sorbet coverage proving a normal generated nested input typechecks and a wrong known model type fails.
  • Breaking-change audit: restored the pre-existing Realtime AsyncWebSocket::Socket RBI/RBS callback contract and a real runtime compatibility wrapper, including its legacy constructor and yielded class identity.

The earlier optional stream_id concern remains non-blocking as clarified in the review; the separate generator fix is tracked in openai/openai#1425293 and openai/openai-ruby-internal#83.

Verification: Responses WebSocket runtime/errors/Sorbet tests, Realtime connection/transport/auth/sideband/abort/network-invariant tests, Sorbet examples, RBS validation (1,285 files), focused RuboCop, and two consecutive clean fresh-context adversarial-review rounds.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 80ee59546d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +50 to +51
def send_raw(data)
raise connection_error(closed_send_message) if closed?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce Responses state before raw writes

When a Responses connection is poisoned by an ambiguous send_event failure, it remains logically open until cleanup, but this inherited send_raw only checks closed?; calling the now-public internal helper can therefore issue another write, and calling it from another thread also bypasses assert_owner!. This defeats the terminal-write and single-owner guarantees and can duplicate response creation, so keep the helper public but override or wrap it for Responses to enforce ownership and poison state before delegating.

AGENTS.md reference: AGENTS.md:L20-L20

Useful? React with 👍 / 👎.

Comment on lines +9 to +13
ServerEvent = T.type_alias do
T.any(
OpenAI::Responses::ResponsesServerEvent::Variants,
OpenAI::Responses::UnknownServerEvent
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid promising valid fields for best-effort events

The fresh evidence is that this revision changes ServerEvent from T.anything back to the generated union while Connection#parse_event still intentionally ignores coercion errors and exactness. When a known event is partial—for example, a response.output_text.delta payload missing delta—the converter still returns ResponseTextWsDelta, so Sorbet accepts event.delta.upcase because delta is declared as String, but the accessor returns nil at runtime and the call fails; either reject/fallback for inexact known events or retain a type that reflects best-effort decoding.

Useful? React with 👍 / 👎.

@apcha-oai apcha-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is much closer and addresses the immediate typing issues. My remaining concern is that the pieces that evolve with the API are still handwritten.

For example, suppose we add a foo parameter to response.create, backed by a generated FooParam type. Codegen will update the request model, but nothing ensures foo: is added to these handwritten RBI/RBS signatures with the correct type and optionality. The runtime may forward it through **params, while the typed interface falls behind.

Similarly, adding a tool variant can update the generated tool union while leaving the manually enumerated tools: signature stale. The existing consumer tests can continue passing because they only exercise older parameters and tools.

We could adopt a “keep the signatures in sync” pattern, but I consider that an antipattern here. It creates a second copy of the API contract that a person, Codex, or a separate synchronization script must continually reconcile. A check that detects drift would help catch mistakes, but we should avoid introducing that duplication in the first place.

Please generate those schema-dependent pieces through the existing SDK generation pipeline, so adding a parameter or tool updates the WebSocket declarations in the same run.

The transport and connection lifecycle can remain handwritten. The parts that change when the API changes should be generated.

@sylvesterkaczmarek sylvesterkaczmarek left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The transport/lifecycle refactor is much cleaner now, but one API-evolution boundary still looks fragile on the current head: connection_resources.rbi hand-enumerates the response.create keyword set and tool union while the runtime accepts forward-compatible **params. A schema/codegen update can therefore make runtime accept a new field or tool while Sorbet/RBS remains stale with no automatic coupling. I would generate the schema-dependent WebSocket request/event declarations from the same API model pipeline and keep only the transport/lifecycle layer handwritten; otherwise this becomes a second API contract that has to be manually synchronized.

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.

5 participants