From 2925a3afa1c2da9fd05f492bd76ab58d778cb87b Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 30 Oct 2026 16:25:00 -0700 Subject: [PATCH 1/2] test(ai): expect Gemini skip thought signature on rich tool failure call (v2.2.5 #60498) --- packages/ai/test/provider/gemini.test.ts | 45 ++++++++++++++++++------ 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/packages/ai/test/provider/gemini.test.ts b/packages/ai/test/provider/gemini.test.ts index 967d28fa8790..92fd8217ec68 100644 --- a/packages/ai/test/provider/gemini.test.ts +++ b/packages/ai/test/provider/gemini.test.ts @@ -1,7 +1,18 @@ import { describe, expect } from "bun:test" import { Deferred, Effect, Fiber } from "effect" import * as TestClock from "effect/testing/TestClock" -import { ai, AIError, isRetryable, LLMEvent, LLMRequest, Media, Message, ToolCallPart, ToolDefinition, Usage } from "../../src/effect.js" +import { + ai, + AIError, + isRetryable, + LLMEvent, + LLMRequest, + Media, + Message, + ToolCallPart, + ToolDefinition, + Usage, +} from "../../src/effect.js" import { Auth, LLMClient } from "../../src/route.js" import { compileRequest } from "../../src/route/client.js" import * as Gemini from "../../src/protocols/gemini.js" @@ -568,7 +579,12 @@ describe("Gemini route", () => { const errorText = `${JSON.stringify(value)}\ncould not capture` expect(legacy.body.contents).toEqual([ - { role: "model", parts: [{ functionCall: { name: "snapshot", args: {} } }] }, + { + role: "model", + parts: [ + { functionCall: { name: "snapshot", args: {} }, thoughtSignature: "skip_thought_signature_validator" }, + ], + }, { role: "user", parts: [ @@ -582,7 +598,10 @@ describe("Gemini route", () => { }, { role: "user", - parts: [{ text: "Attached media from tool result:" }, { inlineData: { mimeType: "image/png", data: "AAECAw==" } }], + parts: [ + { text: "Attached media from tool result:" }, + { inlineData: { mimeType: "image/png", data: "AAECAw==" } }, + ], }, ]) expect(current.body.contents[1]).toMatchObject({ @@ -686,9 +705,7 @@ describe("Gemini route", () => { }, { role: "user", - parts: [ - { functionResponse: { id: "call_video", name: "read", response: { name: "read", content: "" } } }, - ], + parts: [{ functionResponse: { id: "call_video", name: "read", response: { name: "read", content: "" } } }], }, { role: "user", @@ -2168,7 +2185,9 @@ describe("Gemini response continuation", () => { it.effect("forgets a block once the resumed request finishes", () => Effect.gen(function* () { const server = scripted([ - sseEvents(text("THIRTEEN", { continuationToken: "checkpoint-1" }), { promptFeedback: { blockReason: "OTHER" } }), + sseEvents(text("THIRTEEN", { continuationToken: "checkpoint-1" }), { + promptFeedback: { blockReason: "OTHER" }, + }), sseEvents(text(" THOUSAND", { finishReason: "STOP" })), ]) const response = yield* LLMClient.generate(continuedRequest).pipe(Effect.provide(server.layer)) @@ -2263,13 +2282,17 @@ describe("Gemini response continuation", () => { pull(controller) { if (sent) return new Promise(() => Deferred.doneUnsafe(stalled, Effect.void)) sent = true - controller.enqueue(new TextEncoder().encode(chunks(text("THIRTEEN", { continuationToken: "checkpoint-1" })))) + controller.enqueue( + new TextEncoder().encode(chunks(text("THIRTEEN", { continuationToken: "checkpoint-1" }))), + ) }, }), ]) - const fiber = yield* LLMClient.generate( - LLMRequest.update(continuedRequest, { http: { timeout: 1_000 } }), - ).pipe(Effect.provide(server.layer), Effect.flip, Effect.forkChild({ startImmediately: true })) + const fiber = yield* LLMClient.generate(LLMRequest.update(continuedRequest, { http: { timeout: 1_000 } })).pipe( + Effect.provide(server.layer), + Effect.flip, + Effect.forkChild({ startImmediately: true }), + ) yield* Deferred.await(stalled) yield* TestClock.adjust("1 second") const error = yield* Fiber.join(fiber) From ddaeab053aaedd5817c0cf2507c256dbc0239a28 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 30 Oct 2026 16:25:46 -0700 Subject: [PATCH 2/2] test(ai): keep fix minimal, drop unrelated formatting --- packages/ai/test/provider/gemini.test.ts | 42 +++++++----------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/packages/ai/test/provider/gemini.test.ts b/packages/ai/test/provider/gemini.test.ts index 92fd8217ec68..4042a764b676 100644 --- a/packages/ai/test/provider/gemini.test.ts +++ b/packages/ai/test/provider/gemini.test.ts @@ -1,18 +1,7 @@ import { describe, expect } from "bun:test" import { Deferred, Effect, Fiber } from "effect" import * as TestClock from "effect/testing/TestClock" -import { - ai, - AIError, - isRetryable, - LLMEvent, - LLMRequest, - Media, - Message, - ToolCallPart, - ToolDefinition, - Usage, -} from "../../src/effect.js" +import { ai, AIError, isRetryable, LLMEvent, LLMRequest, Media, Message, ToolCallPart, ToolDefinition, Usage } from "../../src/effect.js" import { Auth, LLMClient } from "../../src/route.js" import { compileRequest } from "../../src/route/client.js" import * as Gemini from "../../src/protocols/gemini.js" @@ -581,9 +570,7 @@ describe("Gemini route", () => { expect(legacy.body.contents).toEqual([ { role: "model", - parts: [ - { functionCall: { name: "snapshot", args: {} }, thoughtSignature: "skip_thought_signature_validator" }, - ], + parts: [{ functionCall: { name: "snapshot", args: {} }, thoughtSignature: "skip_thought_signature_validator" }], }, { role: "user", @@ -598,10 +585,7 @@ describe("Gemini route", () => { }, { role: "user", - parts: [ - { text: "Attached media from tool result:" }, - { inlineData: { mimeType: "image/png", data: "AAECAw==" } }, - ], + parts: [{ text: "Attached media from tool result:" }, { inlineData: { mimeType: "image/png", data: "AAECAw==" } }], }, ]) expect(current.body.contents[1]).toMatchObject({ @@ -705,7 +689,9 @@ describe("Gemini route", () => { }, { role: "user", - parts: [{ functionResponse: { id: "call_video", name: "read", response: { name: "read", content: "" } } }], + parts: [ + { functionResponse: { id: "call_video", name: "read", response: { name: "read", content: "" } } }, + ], }, { role: "user", @@ -2185,9 +2171,7 @@ describe("Gemini response continuation", () => { it.effect("forgets a block once the resumed request finishes", () => Effect.gen(function* () { const server = scripted([ - sseEvents(text("THIRTEEN", { continuationToken: "checkpoint-1" }), { - promptFeedback: { blockReason: "OTHER" }, - }), + sseEvents(text("THIRTEEN", { continuationToken: "checkpoint-1" }), { promptFeedback: { blockReason: "OTHER" } }), sseEvents(text(" THOUSAND", { finishReason: "STOP" })), ]) const response = yield* LLMClient.generate(continuedRequest).pipe(Effect.provide(server.layer)) @@ -2282,17 +2266,13 @@ describe("Gemini response continuation", () => { pull(controller) { if (sent) return new Promise(() => Deferred.doneUnsafe(stalled, Effect.void)) sent = true - controller.enqueue( - new TextEncoder().encode(chunks(text("THIRTEEN", { continuationToken: "checkpoint-1" }))), - ) + controller.enqueue(new TextEncoder().encode(chunks(text("THIRTEEN", { continuationToken: "checkpoint-1" })))) }, }), ]) - const fiber = yield* LLMClient.generate(LLMRequest.update(continuedRequest, { http: { timeout: 1_000 } })).pipe( - Effect.provide(server.layer), - Effect.flip, - Effect.forkChild({ startImmediately: true }), - ) + const fiber = yield* LLMClient.generate( + LLMRequest.update(continuedRequest, { http: { timeout: 1_000 } }), + ).pipe(Effect.provide(server.layer), Effect.flip, Effect.forkChild({ startImmediately: true })) yield* Deferred.await(stalled) yield* TestClock.adjust("1 second") const error = yield* Fiber.join(fiber)