Skip to content

test: add provider bridge conformance replay suite - #2261

Open
lsm wants to merge 1 commit into
devfrom
space/add-provider-bridge-conformance-replay-suite
Open

test: add provider bridge conformance replay suite#2261
lsm wants to merge 1 commit into
devfrom
space/add-provider-bridge-conformance-replay-suite

Conversation

@lsm

@lsm lsm commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Replays synthetic provider payloads through the OpenAI Chat, OpenAI Responses (Codex), and Anthropic-Messages pass-through bridges, asserting the exact ordered Anthropic event sequence the UI consumes. Fills the gap categories the per-bridge unit tests leave coarse: reasoning_content/thinking blocks, include arrays, OAuth-gated request variants (api_key vs chatgpt_oauth URL/headers), stop_reason + usage mapping, and malformed/partial-chunk resilience.

The replay drives the canonical stream transforms (streamChatToAnthropic / streamResponsesToAnthropic) directly with synthetic upstream Response bodies — no Bun.serve, no real network — so it is fully deterministic. The 1-core shard globs the directory, so CI picks the new file up automatically.

@lsm lsm left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🤖 Review by GLM-5.1[1m] (GLM / Zhipu)

Model: GLM-5.1[1m] | Client: NeoKai | Provider: GLM (Zhipu)

Recommendation: APPROVE

Reviewed the full 1205-line suite against all three bridge implementations (line-by-line), not just the diff. Every assertion traces to real computed behavior — no bugs locked in, and the tests exercise the SDK/UI-visible contract (ordered Anthropic event sequence, block indices, delta contents, stop_reasons, usage) rather than internal helpers.

What I verified

  • Gates: 51/51 tests pass (ran directly); tsc --noEmit exit 0; check:test-quality audit clean. Lint is N/A — oxlint ignores *.test.ts via .oxlintrc.json ignorePatterns. Knip unaffected (no new prod exports).
  • Section A — OpenAI Chat bridge: canonical event sequence; reasoning_content → thinking block (index 0) strictly before text (index 1); delta.reasoning correctly NOT translated; tool_call arg fragments collapse to one input_json_delta at flush; stop_reason map (stop→end_turn, length→max_tokens, content_filter→end_turn, absent→end_turn); malformed-JSON skip, choices-less usage harvest, split-frame reassembly, no-trailing-newline flush, non-SSE-200 error; ceil(len/4) usage heuristic floored at 1; buildChatRequest flag gating (reasoning_effort/tools/stream_options).
  • Section B — Responses (Codex) bridge: response.reasoning_summary_part.added opens thinking @0, summary_text.done closes, text @1; empty-block path; function_call_arguments.done → tool_use + dedup vs response.completed; monotonic block indices; response.incomplete→max_tokens; usage aliases (prompt_tokens/completion_tokens) + reasoning_tokens; onReasoningItems encrypted round-trip; resilience; response.failed→error with no message_delta; code:'429'rate_limit_error.
  • Section C — OAuth request variants: drives the real createOpenAIResponsesBridgeServer with a capturing upstream fetch (the only layer auth routing lives in). api_key → api.openai.com/v1/responses + Bearer + include admits reasoning.summary_text + keeps max_output_tokens; chatgpt_oauth → chatgpt.com/backend-api/codex/responses + ChatGPT-Account-ID (capital ID) + drops summary_text/max_output_tokens/parallel_tool_calls; FedRAMP header; effort bands incl. the model-cap (gpt-4o caps to high); 401 refresh-once + retried Bearer.
  • Section D — Anthropic pass-through: byte-for-byte verbatim forwarding (text/event-stream skips the JSON pre-buffer); anthropic-* header forwarding + dual x-api-key/Bearer; 200-with-JSON rate-limit body → retryable 429; count_tokens URL built once (suffix-strip handles a baseUrl already ending in /v1/messages).

The replay strategy is sound: response-side tests drive the canonical transforms directly with synthetic Response bodies (no network, fully deterministic), while the OAuth/pass-through tests go through the real server with a mocked upstream fetch. All seven task-named gap categories are covered.

Non-blocking observations (optional coverage refinements, not defects)

These are finite-suite edge sub-cases the task scope did not require; none affects correctness of what IS asserted:

  • response.incomplete + tool calls together (tool_use currently wins over max_tokens) isn't exercised — server.ts:1244.
  • The api_key path also emits parallel_tool_calls:false; only max_output_tokens is asserted on that path.
  • FedRAMP/ChatGPT-Account-ID headers are asserted only on the positive chatgpt_oauth path, not their absence on the api_key path.
  • content_block_stop index values aren't directly asserted (start indices + event sequence are).

Zero blocking findings. Self-PR so posting as COMMENT — recommendation is APPROVE.

@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: 5e5760501a

ℹ️ 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".

headers: {
'Content-Type': 'application/json',
'anthropic-beta': 'interleaved-thinking-2025-05-14',
'anthropic-version': '2023-06-01',

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 Use a non-default version to test header forwarding

This request sends the bridge's default anthropic-version value and the test never asserts the captured version header. If forwarding of anthropic-version is removed, the bridge will still supply 2023-06-01 from its default and this claimed “every anthropic-* request header” conformance test will continue to pass. Send a distinguishable non-default value and assert that exact value upstream.

Useful? React with 👍 / 👎.

tools: [{ name: 't', description: '', input_schema: { type: 'object' } }],
tool_choice: { type: 'auto' as const },
};
const req = _openAIChatBridgeTesting.buildChatRequest(body, 'm', false, false, true);

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 Exercise reasoning forwarding with tool use disabled

Despite the test title, this request contains no thinking configuration and there is no assertion on req.reasoning_effort, so the field is undefined regardless of whether reasoning is correctly forwarded. A regression that accidentally couples reasoning translation to toolUseSupported would therefore pass this suite. Include a thinking budget in this case and assert the resulting effort while tool support is disabled.

Useful? React with 👍 / 👎.

Comment on lines +1183 to +1185
let capturedUrl = '';
const fetchImpl = async (url: string) => {
capturedUrl = url;

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 Count upstream calls in the count_tokens test

The test title promises that count_tokens is routed exactly once, but capturedUrl only records the most recent invocation. If the bridge begins issuing the same upstream request twice, both calls overwrite this variable with the expected URL and the test still passes, missing duplicated billing or side effects. Track the fetch call count and assert that it is one in addition to checking the URL.

Useful? React with 👍 / 👎.

Comment on lines +674 to +675
expect(blocksOfType(events, 'thinking')).toHaveLength(1);
expect(deltasOfType(events, 'thinking_delta')).toHaveLength(0);

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 Assert that the empty thinking block is closed

This test claims the empty thinking block is opened and closed, but it only checks for a content_block_start and the absence of deltas. If the bridge stops emitting content_block_stop for reasoning blocks, the resulting Anthropic stream is malformed while this test still passes. Assert the matching stop event and block index, ideally before the final message events.

Useful? React with 👍 / 👎.

Comment on lines +969 to +970
// Standard API path keeps max_output_tokens / parallel_tool_calls.
expect(caps.body.max_output_tokens).toBe(1024);

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 Assert the standard API parallel tool-call flag

The comment states that the standard API path retains both max_output_tokens and parallel_tool_calls, but this case only asserts the former. There is no other test for the standard-path value, so a regression that omits parallel_tool_calls: false—allowing an upstream default to enable parallel calls the bridge does not intend—would pass, even though the OAuth counterpart explicitly verifies omission. Assert that the captured standard request contains parallel_tool_calls: false.

Useful? React with 👍 / 👎.

@lsm

lsm commented Jul 26, 2026

Copy link
Copy Markdown
Owner Author

🤖 CI failure root-cause (follow-up) — GLM-5.1[1m]

Model: GLM-5.1[1m] | Client: NeoKai | Provider: GLM (Zhipu)

The red Daemon Unit Tests (1-core) check is a pre-existing dev-branch flake, not caused by this PR. My APPROVE verdict stands.

Evidence

  • dev failed identically before this PR existed. CI run 30215248587 on dev (18:41 UTC today) failed Daemon Unit Tests (1-core) on the exact same test: provider-service.test.ts:1379getProviderService > should return ProviderService instanceExpected: "function". This PR's commit was pushed at 19:30 UTC — ~49 min after dev was already red.
  • This PR is test-only. It adds provider-bridge-conformance-replay.test.ts (51 tests, all pass) and touches neither provider-service.ts nor provider-service.test.ts.
  • The failure is CI-only. The full 1-core shard passes locally on macOS (3650 pass / 0 fail), and provider-service.test.ts passes 78/78 in isolation. CI runs Bun 1.3.13 on Linux; the failing assertion's own comment admits it is fragile under Bun's duplicate-module-instance loading.

Likely mechanism (for whoever fixes the flake)

The 1-core shard runs as one bun test process with --jobs=1 (scripts/test-daemon.sh:230), so all files share module singletons. getProviderService() keys its singleton on a module-local Symbol in globalThis. tests/unit/1-core/session/session-lifecycle*.test.ts call mock.module on provider-service; a leaked/unrestored mock in that shared process can leave the singleton holding a stub without getDefaultProvider, which the later provider-service.test.ts then observes.

Recommendation

  • This PR is approvable and mergeable as-is — its own gates are green; the blocker is orthogonal.
  • The flake needs a separate fix on dev (e.g. robust singleton reset / module-restore in session-lifecycle*.test.ts, or de-flaking provider-service.test.ts:1379 to not depend on module-instance identity). Until that lands, every PR's 1-core check will be red regardless of its contents.

Replays synthetic/captured provider payloads through the OpenAI Chat,
OpenAI Responses (Codex), and Anthropic-Messages pass-through bridges,
asserting the exact ordered Anthropic event sequence + block structure
the UI consumes. Covers the gap categories the per-bridge unit tests leave
coarse: reasoning_content/thinking blocks, include arrays, OAuth-gated
request variants (api_key vs chatgpt_oauth), stop_reason + usage mapping,
and malformed/partial-chunk resilience.
@lsm
lsm force-pushed the space/add-provider-bridge-conformance-replay-suite branch from 5e57605 to 30fea2b Compare July 27, 2026 16:51
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

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