




























@@ -4610,6 +4610,105 @@ describe("openai transport stream", () => {
46104610);
46114611});
461246124613+it("falls back to skip_thought_signature_validator when a captured same-route Gemini 3 signature is truncated", () => {
4614+// Compaction-truncated sig: 109 chars, length mod 4 == 1.
4615+// Same-route assistant tool-call whose captured thoughtSignature is truncated.
4616+// The guard should fall back to the sentinel instead of dropping the field.
4617+const params = buildOpenAICompletionsParams(
4618+geminiModel,
4619+{
4620+messages: [
4621+{
4622+role: "assistant",
4623+api: geminiModel.api,
4624+provider: geminiModel.provider,
4625+model: geminiModel.id,
4626+usage: {
4627+input: 0,
4628+output: 0,
4629+cacheRead: 0,
4630+cacheWrite: 0,
4631+totalTokens: 0,
4632+cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
4633+},
4634+stopReason: "toolUse",
4635+timestamp: 1,
4636+content: [
4637+{
4638+type: "toolCall",
4639+id: "call_abc",
4640+name: "echo_value",
4641+arguments: { value: "repro" },
4642+thoughtSignature:
4643+"CmcBjz1rX55U6JcpC2oZVTk40Kx6nVK8LKzbl61rOFztcvSdL7pdIvBEDyJLRqWrPVpdD+rj3GsJ3f9PG6b2Ry2UnK38+dInfGIlJbXHt++EC",
4644+},
4645+],
4646+},
4647+],
4648+tools: [],
4649+} as never,
4650+undefined,
4651+) as { messages: Array<Record<string, unknown>> };
4652+4653+const assistant = params.messages.find((message) => message.role === "assistant") as
4654+| { tool_calls?: Array<{ extra_content?: { google?: { thought_signature?: string } } }> }
4655+| undefined;
4656+expect(assistant?.tool_calls?.[0]?.extra_content?.google?.thought_signature).toBe(
4657+"skip_thought_signature_validator",
4658+);
4659+});
4660+4661+it("drops the field when the model is not Gemini 3 and the captured same-route signature is truncated", () => {
4662+// gemini-2.5-pro: requiresGoogleCompatToolCallThoughtSignature returns false,
4663+// so fallbackSig is undefined and there is no sentinel to fall back to.
4664+// A truncated same-route sig should cause the field to be dropped entirely.
4665+const nonGemini3Model = {
4666+ ...geminiModel,
4667+id: "gemini-2.5-pro",
4668+name: "Gemini 2.5 Pro",
4669+};
4670+const params = buildOpenAICompletionsParams(
4671+nonGemini3Model,
4672+{
4673+messages: [
4674+{
4675+role: "assistant",
4676+api: nonGemini3Model.api,
4677+provider: nonGemini3Model.provider,
4678+model: nonGemini3Model.id,
4679+usage: {
4680+input: 0,
4681+output: 0,
4682+cacheRead: 0,
4683+cacheWrite: 0,
4684+totalTokens: 0,
4685+cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
4686+},
4687+stopReason: "toolUse",
4688+timestamp: 1,
4689+content: [
4690+{
4691+type: "toolCall",
4692+id: "call_abc",
4693+name: "echo_value",
4694+arguments: { value: "repro" },
4695+thoughtSignature:
4696+"CmcBjz1rX55U6JcpC2oZVTk40Kx6nVK8LKzbl61rOFztcvSdL7pdIvBEDyJLRqWrPVpdD+rj3GsJ3f9PG6b2Ry2UnK38+dInfGIlJbXHt++EC",
4697+},
4698+],
4699+},
4700+],
4701+tools: [],
4702+} as never,
4703+undefined,
4704+) as { messages: Array<Record<string, unknown>> };
4705+4706+const assistant = params.messages.find((message) => message.role === "assistant") as
4707+| { tool_calls?: Array<{ extra_content?: { google?: { thought_signature?: string } } }> }
4708+| undefined;
4709+expect(assistant?.tool_calls?.[0]?.extra_content?.google?.thought_signature).toBeUndefined();
4710+});
4711+46134712it("does not trust cross-route thought_signature for non-Gemini-3 Google compat models", () => {
46144713const nonGemini3Model = {
46154714 ...geminiModel,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。