Skip to content

Commit 5d37729

Browse files
authored
Merge branch 'main' into snyk-upgrade-ea160fcc3b1079e3fb39a7b3e0f5d3e7
2 parents 4983200 + 78f904b commit 5d37729

File tree

26 files changed

+546
-208
lines changed

26 files changed

+546
-208
lines changed

core/llm/llms/CometAPI.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { LLMOptions } from "../../index.js";
21
import { allModelProviders } from "@continuedev/llm-info";
2+
import { LLMOptions } from "../../index.js";
33
import OpenAI from "./OpenAI.js";
44

55
/**
@@ -183,6 +183,7 @@ class CometAPI extends OpenAI {
183183
*/
184184
private static RECOMMENDED_MODELS = [
185185
// GPT series
186+
"gpt-5.1",
186187
"gpt-5-chat-latest",
187188
"chatgpt-4o-latest",
188189
"gpt-5-mini",

core/llm/llms/Gemini.ts

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ import {
2323
convertContinueToolToGeminiFunction,
2424
} from "./gemini-types";
2525

26+
interface GeminiToolCallDelta extends ToolCallDelta {
27+
extra_content?: {
28+
google?: {
29+
thought_signature?: string;
30+
};
31+
};
32+
}
33+
2634
class Gemini extends BaseLLM {
2735
static providerName = "gemini";
2836

@@ -266,18 +274,37 @@ class Gemini extends BaseLLM {
266274
? [{ text: msg.content }]
267275
: msg.content.map(this.continuePartToGeminiPart),
268276
};
269-
if (msg.toolCalls) {
270-
msg.toolCalls.forEach((toolCall) => {
271-
if (toolCall.function?.name) {
272-
assistantMsg.parts.push({
273-
functionCall: {
274-
name: toolCall.function.name,
275-
args: safeParseToolCallArgs(toolCall),
276-
},
277-
});
278-
}
279-
});
277+
278+
if (msg.toolCalls && msg.toolCalls.length) {
279+
(msg.toolCalls as GeminiToolCallDelta[]).forEach(
280+
(toolCall, index) => {
281+
if (toolCall.function?.name) {
282+
const signatureForCall =
283+
toolCall?.extra_content?.google?.thought_signature;
284+
285+
let thoughtSignature: string | undefined;
286+
if (index === 0) {
287+
if (typeof signatureForCall === "string") {
288+
thoughtSignature = signatureForCall;
289+
} else {
290+
// Fallback per https://ai.google.dev/gemini-api/docs/thought-signatures
291+
// for histories that were not generated by Gemini or are missing signatures.
292+
thoughtSignature = "skip_thought_signature_validator";
293+
}
294+
}
295+
296+
assistantMsg.parts.push({
297+
functionCall: {
298+
name: toolCall.function.name,
299+
args: safeParseToolCallArgs(toolCall),
300+
},
301+
...(thoughtSignature && { thoughtSignature }),
302+
});
303+
}
304+
},
305+
);
280306
}
307+
281308
return assistantMsg;
282309
}
283310
return {
@@ -370,6 +397,7 @@ class Gemini extends BaseLLM {
370397
if ("text" in part) {
371398
textParts.push({ type: "text", text: part.text });
372399
} else if ("functionCall" in part) {
400+
const thoughtSignature = part.thoughtSignature;
373401
toolCalls.push({
374402
type: "function",
375403
id: part.functionCall.id ?? uuidv4(),
@@ -380,6 +408,13 @@ class Gemini extends BaseLLM {
380408
? part.functionCall.args
381409
: JSON.stringify(part.functionCall.args),
382410
},
411+
...(thoughtSignature && {
412+
extra_content: {
413+
google: {
414+
thought_signature: thoughtSignature,
415+
},
416+
},
417+
}),
383418
});
384419
} else {
385420
// Note: function responses shouldn't be streamed, images not supported

core/llm/llms/gemini-types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ export type GeminiFunctionCallContentPart = {
192192
name: string;
193193
args: JSONSchema7Object;
194194
};
195+
thoughtSignature?: string;
195196
};
196197

197198
export type GeminiFunctionResponseContentPart = {

core/llm/toolSupport.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export const PROVIDER_TOOL_SUPPORT: Record<string, (model: string) => boolean> =
120120
},
121121
xAI: (model) => {
122122
const lowerCaseModel = model.toLowerCase();
123-
return ["grok-3", "grok-4", "grok-code"].some((val) =>
123+
return ["grok-3", "grok-4", "grok-4-1", "grok-code"].some((val) =>
124124
lowerCaseModel.includes(val),
125125
);
126126
},
@@ -392,10 +392,11 @@ export function isRecommendedAgentModel(modelName: string): boolean {
392392
[/o[134]/],
393393
[/deepseek/, /r1|reasoner/],
394394
[/gemini/, /2\.5/, /pro/],
395-
[/gpt-5/],
395+
[/gpt/, /-5|5\.1/],
396396
[/claude/, /sonnet/, /3\.7|3-7|-4/],
397397
[/claude/, /opus/, /-4/],
398398
[/grok-code/],
399+
[/grok-4-1|grok-4\.1/],
399400
[/claude/, /4-5/],
400401
];
401402
for (const combo of recs) {

0 commit comments

Comments
 (0)