Skip to content

W.1: OpenAI chat encode as one pure function returning plain data (on #38) - #39

Open
cunninghamcard-bit wants to merge 3 commits into
exp/w0-wire-docsfrom
exp/w1-openai-chat-encode
Open

cunninghamcard-bit wants to merge 3 commits into
exp/w0-wire-docsfrom
exp/w1-openai-chat-encode

Conversation

@cunninghamcard-bit

Copy link
Copy Markdown
Owner

Unit W.1 (PHASES 1W; A9 W2). Stacked on #38 (W.0, exp/w0-wire-docs @ f9e40b0, which sits on #37 and E.6). The PR base is that branch.

Change (aimux-providers/src/openai/model.rs)

  • New EncodedChatRequest { url, headers, body, warnings }. It holds only plain data: no closures and no transport. It is re-exported as aimux_providers::openai::EncodedChatRequest.
  • New pure, synchronous encode_chat(url, headers, model_id, &CallOptions, stream, parser). It reuses convert.rs:1094 build_request_body_with_chat_options, and is now its only call site in model.rs. rg -n 'build_request_body_with_chat_options' aimux-providers/src/openai/model.rs finds one line, :211, inside encode_chat.
  • New OpenAIModel::encode_request(&CallOptions, stream) (#[doc(hidden)] pub). It resolves the configured URL and headers (the credential included), then calls encode_chat.
  • do_generate / do_stream now call encode_request and build the HttpRequest from the encoded url and headers. execute_generate / execute_stream receive the EncodedChatRequest and no longer build the body themselves.
  • Behaviour is unchanged:
    • Warnings are carried through (M9).
    • Content-type and the provider-utils suffix of the user-agent are still added by the helper when the request is sent.
    • Every existing test passes unchanged.

Acceptance

New test openai_factory_test::chat_encode_matches_recorded_requests_without_fetch:

  • It runs on all 7 recorded chat fixtures, with the settings each recording was made with. That includes chat-custom-name and chat-headers-merge.
  • It compares the encoded output directly with the fixture's request, and asserts the mock transport saw zero requests:
    • url must be equal.
    • body must be equal.
    • The headers must be equal to the recorded ones, apart from three differences:
      • The redacted key is replaced with the test key.
      • content-type is added later by the helper.
      • The user-agent is exactly ai-sdk-openai/4.0.80; the helper appends ai-sdk-provider-utils/5.0.51 when sending.

Fixture and cassette diff: zero.

Results (local linux x64)

E.4 (#31) / E.6 W.1
cargo test --workspace 2895 / 0 / 7 2896 / 0 / 7 (+1)
fmt / clippy -D warnings ok ok
boundary script 0 0
gen_ts_types --check ok ok, no .ts diff
Node ava (node 22) 87 / 1 baseline fail 87 passed / same 1 failure

Python was not run (no venv).

encode_chat(url, headers, model_id, &CallOptions, stream, parser) ->
EncodedChatRequest { url, headers, body, warnings } is the only place the
chat body is built; do_generate/do_stream resolve URL+headers
(OpenAIModel::encode_request), encode, then hand the result to the
execute_* helpers. New openai_factory_test compares encode output with all 7
recorded chat requests without a transport.
…at directly

openai/mod.rs: with_user_agent("openai", "4.0.83") (fixtures/aisdk/VERSIONS.json).
chat_encode_matches_recorded_requests_without_fetch derives the expected UA from
VERSIONS.json and asserts a provider-layer recorded UA starts with the encoded
one instead of comparing a literal. New unit test calls the pure encode_chat.
cunninghamcard-bit added a commit that referenced this pull request Oct 11, 2026
cunninghamcard-bit added a commit that referenced this pull request Oct 11, 2026
…-agent

Instead of overwriting the expected user-agent with the pinned value, each
factory test checks what aimux sent against the recording: every recording
contains the sent ai-sdk-provider-utils/<v> part, and a provider-layer
recording (messages-stream-basic, generate-stream-basic, chat-stream-basic)
starts with the sent ai-sdk-<pkg>/<v> part, like #39 does for openai.
Mutation: setting the constant and VERSIONS.json together to a fake version
(9.9.91/9.9.92/9.9.93) turns the three stream tests red.
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