Skip to content

Commit 70ace03

Browse files
committed
fix: CR R2 fixes — tool call IDs, journal gaps, MIME fallback, reset parity
- ws-gemini-live: pre-compute tool call IDs so wire message and conversation history use the same values (was generating twice) - ws-gemini-live: push audio response to conversation history for multi-turn context continuity - ws-gemini-live: add journal entry for strict-mode WS rejection - recorder: change fallback MIME from "audio/mp3" to "audio/mpeg" - recorder: remove stale cast and comment (types already widened) - fal-audio: add journal entries for proxied requests - fal-audio: remove unnecessary RecordProviderKey casts - llmock: add falJobs.clear() to reset() for parity with HTTP reset
1 parent 70f203d commit 70ace03

4 files changed

Lines changed: 50 additions & 21 deletions

File tree

src/fal-audio.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
import type http from "node:http";
22
import crypto from "node:crypto";
3-
import type {
4-
AudioResponse,
5-
ChatCompletionRequest,
6-
Fixture,
7-
HandlerDefaults,
8-
RecordProviderKey,
9-
} from "./types.js";
3+
import type { AudioResponse, ChatCompletionRequest, Fixture, HandlerDefaults } from "./types.js";
104
import { isAudioResponse, isErrorResponse, FORMAT_TO_CONTENT_TYPE, getTestId } from "./helpers.js";
115
import { matchFixture } from "./router.js";
126
import { proxyAndRecord } from "./recorder.js";
@@ -257,13 +251,22 @@ async function handleQueueSubmit(
257251
req,
258252
res,
259253
syntheticReq,
260-
"fal" as RecordProviderKey,
254+
"fal",
261255
pathname,
262256
fixtures,
263257
defaults,
264258
body,
265259
);
266-
if (proxied) return;
260+
if (proxied) {
261+
journal.add({
262+
method: req.method ?? "POST",
263+
path: pathname,
264+
headers: {},
265+
body: syntheticReq,
266+
response: { status: res.statusCode ?? 200, fixture: null },
267+
});
268+
return;
269+
}
267270
}
268271

269272
const strictStatus = defaults.strict ? 503 : 404;
@@ -529,13 +532,22 @@ async function handleSyncRun(
529532
req,
530533
res,
531534
syntheticReq,
532-
"fal" as RecordProviderKey,
535+
"fal",
533536
pathname,
534537
fixtures,
535538
defaults,
536539
body,
537540
);
538-
if (proxied) return;
541+
if (proxied) {
542+
journal.add({
543+
method: req.method ?? "POST",
544+
path: pathname,
545+
headers: {},
546+
body: syntheticReq,
547+
response: { status: res.statusCode ?? 200, fixture: null },
548+
});
549+
return;
550+
}
539551
}
540552

541553
const strictStatus = defaults.strict ? 503 : 404;

src/llmock.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { Journal } from "./journal.js";
2727
import type { SearchFixture, SearchResult } from "./search.js";
2828
import type { RerankFixture, RerankResult } from "./rerank.js";
2929
import type { ModerationFixture, ModerationResult } from "./moderation.js";
30+
import { falJobs } from "./fal-audio.js";
3031

3132
export class LLMock {
3233
private fixtures: Fixture[] = [];
@@ -307,6 +308,7 @@ export class LLMock {
307308
this.searchFixtures.length = 0;
308309
this.rerankFixtures.length = 0;
309310
this.moderationFixtures.length = 0;
311+
falJobs.clear();
310312
if (this.serverInstance) {
311313
this.serverInstance.journal.clear();
312314
this.serverInstance.videoStates.clear();

src/recorder.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ export async function proxyAndRecord(
173173
fixtureResponse = {
174174
audio: {
175175
b64Json: collapsed.audioB64,
176-
contentType: collapsed.audioMimeType ?? "audio/mp3",
176+
contentType: collapsed.audioMimeType ?? "audio/mpeg",
177177
},
178178
};
179179
} else if (
@@ -235,11 +235,8 @@ export async function proxyAndRecord(
235235
const fixtureMatch = buildFixtureMatch(matchRequest);
236236

237237
// Build and save the fixture
238-
// Cast: EndpointType here is broader than FixtureMatch.endpoint to cover
239-
// audio-gen / fal-audio; the recorded JSON is correct, FixtureMatch will
240-
// be widened in a follow-up types.ts change.
241238
const fixture: Fixture = {
242-
match: fixtureMatch as Fixture["match"],
239+
match: fixtureMatch,
243240
response: fixtureResponse,
244241
};
245242

src/ws-gemini-live.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,13 @@ async function processMessage(
345345
if (!fixture) {
346346
if (defaults.strict) {
347347
defaults.logger.warn(`STRICT: No fixture matched for WebSocket message`);
348+
journal.add({
349+
method: "WS",
350+
path,
351+
headers: {},
352+
body: completionReq,
353+
response: { status: 404, fixture: null },
354+
});
348355
ws.close(1008, "Strict mode: no fixture matched");
349356
return;
350357
}
@@ -420,6 +427,11 @@ async function processMessage(
420427
},
421428
}),
422429
);
430+
431+
session.conversationHistory.push({
432+
role: "assistant",
433+
content: "[audio]",
434+
});
423435
return;
424436
}
425437

@@ -488,6 +500,12 @@ async function processMessage(
488500
return;
489501
}
490502

503+
// Pre-compute tool calls with stable IDs so wire message and history match
504+
const resolvedToolCalls = response.toolCalls.map((tc) => ({
505+
...tc,
506+
resolvedId: tc.id ?? generateToolCallId(),
507+
}));
508+
491509
// Send tool calls
492510
if (!ws.isClosed) {
493511
if (latency > 0) await delay(latency, interruption?.signal);
@@ -499,7 +517,7 @@ async function processMessage(
499517
return;
500518
}
501519

502-
const functionCalls = response.toolCalls.map((tc) => {
520+
const functionCalls = resolvedToolCalls.map((tc) => {
503521
let argsObj: Record<string, unknown>;
504522
try {
505523
argsObj = JSON.parse(tc.arguments || "{}") as Record<string, unknown>;
@@ -512,7 +530,7 @@ async function processMessage(
512530
return {
513531
name: tc.name,
514532
args: argsObj,
515-
id: tc.id ?? generateToolCallId(),
533+
id: tc.resolvedId,
516534
};
517535
});
518536

@@ -539,12 +557,12 @@ async function processMessage(
539557
);
540558
}
541559

542-
// Add to conversation history
560+
// Add to conversation history using the same resolved IDs from the wire message
543561
session.conversationHistory.push({
544562
role: "assistant",
545563
content: content || null,
546-
tool_calls: response.toolCalls.map((tc) => ({
547-
id: tc.id ?? generateToolCallId(),
564+
tool_calls: resolvedToolCalls.map((tc) => ({
565+
id: tc.resolvedId,
548566
type: "function" as const,
549567
function: {
550568
name: tc.name,

0 commit comments

Comments
 (0)