Skip to content

Commit 39fb2c6

Browse files
committed
fix(api): dedupe Responses API streamed tool calls
1 parent b94a422 commit 39fb2c6

5 files changed

Lines changed: 329 additions & 79 deletions

File tree

apps/vscode-e2e/AGENTS.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,39 @@ ZAI_API_KEY=<key> TEST_FILE=zai.test pnpm --filter @roo-code/vscode-e2e test:ci
153153
154154
When adding a new test to this suite, add a matching fixture to the `installZAiFetchInterceptor` call in `suiteSetup`. Use a short unique prefix (e.g. `"zai-glm-e2e-mytest:"`) that won't appear in `<environment_details>`.
155155
156+
### xAI Grok (`suite/providers/xai.test.ts`)
157+
158+
xAI uses the **Responses API** (`POST https://api.x.ai/v1/responses`), which is not OpenAI-compatible. aimock can't intercept it. The suite instead patches `globalThis.fetch` to intercept requests to that endpoint. By default it replays hand-crafted SSE events; when a local `fixtures/xai.json` recording exists, it can replay recorded real-API SSE events for reference.
159+
160+
The local `fixtures/xai.json` file is gitignored. It keeps an empty top-level `fixtures` array so aimock can scan the directory without warnings. xAI recordings live under `xaiResponses`, which maps each model ID to `{ readCallId, turn1, turn2 }`:
161+
162+
- **`turn1`** — raw SSE events from the real API for the first API call (should contain a `read_file` function call)
163+
- **`readCallId`** — the `call_id` extracted from turn 1's `response.output_item.done` event; used to match the turn 2 request
164+
- **`turn2`** — raw SSE events for the second API call (should contain an `attempt_completion` call with the correct result text)
165+
166+
Having real-API events in the fixture guarantees:
167+
168+
1. The SSE format expected by the stream processor is correct.
169+
2. The `attempt_completion.result` field contains the actual marker value (not an empty string).
170+
171+
**Recording** (populate or refresh the fixture from the real xAI API):
172+
173+
```sh
174+
XAI_API_KEY=<key> XAI_RECORD=true TEST_FILE=providers/xai.test.js pnpm --filter @roo-code/vscode-e2e test:run
175+
```
176+
177+
This routes all xAI requests through the real API, captures the SSE events per turn, and writes the local gitignored `fixtures/xai.json` on teardown.
178+
179+
**Verifying the recorded fixture in mock mode** (no API key needed):
180+
181+
```sh
182+
TEST_FILE=xai.test pnpm --filter @roo-code/vscode-e2e test:ci:mock
183+
```
184+
185+
When no local recording exists for a model, the interceptor falls back to hand-crafted SSE events (using a hardcoded `readCallId`). CI should use this fallback so the suite remains deterministic and does not depend on large raw provider recordings.
186+
187+
When adding a new test to this suite, update the hand-crafted interceptor response unless the behavior specifically needs a real xAI SSE recording for local debugging. Use a short unique probe tag (e.g. `"xai-e2e:grok-4.20"`) that won't appear in `<environment_details>`.
188+
156189
### DeepSeek V4 (`suite/providers/deepseek-v4.test.ts`)
157190
158191
DeepSeek exposes `deepSeekBaseUrl`, so the suite redirects the OpenAI-compatible DeepSeek client through aimock with `deepSeekBaseUrl: ${AIMOCK_URL}/v1`. The test still installs a lightweight fetch capture for request-shape assertions, but responses should come from aimock fixtures or aimock record mode.

apps/vscode-e2e/fixtures/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
# Contributors should extract stable fixtures manually from these files, then delete them.
33
openai-*.json
44
anthropic-*.json
5+
xai.json

0 commit comments

Comments
 (0)