@aigne/gemini 0.14.10-beta.1 → 0.14.10-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,86 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.14.10-beta.4](https://github.com/AIGNE-io/aigne-framework/compare/gemini-v0.14.10-beta.3...gemini-v0.14.10-beta.4) (2025-11-21)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **gemini:** properly handle thinking level for gemini 3.x models ([#763](https://github.com/AIGNE-io/aigne-framework/issues/763)) ([a5dc892](https://github.com/AIGNE-io/aigne-framework/commit/a5dc8921635811ed9ca2ff9e3e0699006f79cf22))
9
+ * **gemini:** return reasoningEffort in model options for gemini-3 ([#765](https://github.com/AIGNE-io/aigne-framework/issues/765)) ([682bfda](https://github.com/AIGNE-io/aigne-framework/commit/682bfda353b31fd432232baa57f8e0b0838eb76d))
10
+
11
+ ## [0.14.10-beta.3](https://github.com/AIGNE-io/aigne-framework/compare/gemini-v0.14.10-beta.2...gemini-v0.14.10-beta.3) (2025-11-19)
12
+
13
+
14
+ ### Features
15
+
16
+ * **models:** support gemini 3.x thinking level and thoughtSignature ([#760](https://github.com/AIGNE-io/aigne-framework/issues/760)) ([243f2d4](https://github.com/AIGNE-io/aigne-framework/commit/243f2d457792a20ba2b87378576092e6f88e319c))
17
+
18
+
19
+ ### Dependencies
20
+
21
+ * The following workspace dependencies were updated
22
+ * dependencies
23
+ * @aigne/core bumped to 1.69.0-beta.2
24
+ * devDependencies
25
+ * @aigne/test-utils bumped to 0.5.63-beta.3
26
+
27
+ ## [0.14.10-beta.2](https://github.com/AIGNE-io/aigne-framework/compare/gemini-v0.14.10-beta.1...gemini-v0.14.10-beta.2) (2025-11-18)
28
+
29
+
30
+ ### Features
31
+
32
+ * add dynamic model options resolution with getter pattern ([#708](https://github.com/AIGNE-io/aigne-framework/issues/708)) ([5ed5085](https://github.com/AIGNE-io/aigne-framework/commit/5ed5085203763c70194853c56edc13acf56d81c6))
33
+ * add modalities support for chat model ([#454](https://github.com/AIGNE-io/aigne-framework/issues/454)) ([70d1bf6](https://github.com/AIGNE-io/aigne-framework/commit/70d1bf631f4e711235d89c6df8ee210a19179b30))
34
+ * add reasoningEffort option for chat model ([#680](https://github.com/AIGNE-io/aigne-framework/issues/680)) ([f69d232](https://github.com/AIGNE-io/aigne-framework/commit/f69d232d714d4a3e4946bdc8c6598747c9bcbd57))
35
+ * add thinking support to Gemini chat models ([#650](https://github.com/AIGNE-io/aigne-framework/issues/650)) ([09b828b](https://github.com/AIGNE-io/aigne-framework/commit/09b828ba668d90cc6aac68a5e8190adb146b5e45))
36
+ * **cli:** add retry functionality and improve error handling for AIGNE Hub ([#348](https://github.com/AIGNE-io/aigne-framework/issues/348)) ([672c93a](https://github.com/AIGNE-io/aigne-framework/commit/672c93abbba8b4b234f6d810536ff4b603a97e1e))
37
+ * improve image model architecture and file handling ([#527](https://github.com/AIGNE-io/aigne-framework/issues/527)) ([4db50aa](https://github.com/AIGNE-io/aigne-framework/commit/4db50aa0387a1a0f045ca11aaa61613e36ca7597))
38
+ * **memory:** support did space memory adapter ([#229](https://github.com/AIGNE-io/aigne-framework/issues/229)) ([6f69b64](https://github.com/AIGNE-io/aigne-framework/commit/6f69b64e98b963db9d6ab5357306b445385eaa68))
39
+ * **models:** support aigne hub models ([#416](https://github.com/AIGNE-io/aigne-framework/issues/416)) ([b4f014c](https://github.com/AIGNE-io/aigne-framework/commit/b4f014cf5ed08ef930d3ddfc278d3610e64c6af3))
40
+ * **models:** support gemini and ideogram images models ([#412](https://github.com/AIGNE-io/aigne-framework/issues/412)) ([6534fec](https://github.com/AIGNE-io/aigne-framework/commit/6534fecb0bdfb4b0a4440d44c0e563b9a029a68f))
41
+ * **models:** support gemini and ideogram images models ([#412](https://github.com/AIGNE-io/aigne-framework/issues/412)) ([6534fec](https://github.com/AIGNE-io/aigne-framework/commit/6534fecb0bdfb4b0a4440d44c0e563b9a029a68f))
42
+ * **model:** support video model ([#647](https://github.com/AIGNE-io/aigne-framework/issues/647)) ([de81742](https://github.com/AIGNE-io/aigne-framework/commit/de817421ef1dd3246d0d8c51ff12f0a855658f9f))
43
+ * support custom prefer input file type ([#469](https://github.com/AIGNE-io/aigne-framework/issues/469)) ([db0161b](https://github.com/AIGNE-io/aigne-framework/commit/db0161bbac52542c771ee2f40f361636b0668075))
44
+
45
+
46
+ ### Bug Fixes
47
+
48
+ * add prefer input file type option for image model ([#536](https://github.com/AIGNE-io/aigne-framework/issues/536)) ([3cba8a5](https://github.com/AIGNE-io/aigne-framework/commit/3cba8a5562233a1567b49b6dd5c446c0760f5c4c))
49
+ * bump version ([93a1c10](https://github.com/AIGNE-io/aigne-framework/commit/93a1c10cf35f88eaafe91092481f5d087bd5b3a9))
50
+ * **core:** make getCredential async for aigne-hub mount point retrieval ([#372](https://github.com/AIGNE-io/aigne-framework/issues/372)) ([34ce7a6](https://github.com/AIGNE-io/aigne-framework/commit/34ce7a645fa83994d3dfe0f29ca70098cfecac9c))
51
+ * correct calculate token usage for gemini model ([7fd1328](https://github.com/AIGNE-io/aigne-framework/commit/7fd13289d3d0f8e062211f7c6dd5cb56e5318c1b))
52
+ * **docs:** update video mode docs ([#695](https://github.com/AIGNE-io/aigne-framework/issues/695)) ([d691001](https://github.com/AIGNE-io/aigne-framework/commit/d69100169457c16c14f2f3e2f7fcd6b2a99330f3))
53
+ * **gemini:** handle empty responses when files are present ([#648](https://github.com/AIGNE-io/aigne-framework/issues/648)) ([f4e259c](https://github.com/AIGNE-io/aigne-framework/commit/f4e259c5e5c687c347bb5cf29cbb0b5bf4d0d4a1))
54
+ * **gemini:** implement retry mechanism for empty responses with structured output fallback ([#638](https://github.com/AIGNE-io/aigne-framework/issues/638)) ([d33c8bb](https://github.com/AIGNE-io/aigne-framework/commit/d33c8bb9711aadddef9687d6cf472a179cd8ed9c))
55
+ * **gemini:** include thoughts token count in output token usage ([#669](https://github.com/AIGNE-io/aigne-framework/issues/669)) ([f6ff10c](https://github.com/AIGNE-io/aigne-framework/commit/f6ff10c33b0612a0bc416842c5a5bec3850a3fe6))
56
+ * **gemini:** should include at least one user message ([#521](https://github.com/AIGNE-io/aigne-framework/issues/521)) ([eb2752e](https://github.com/AIGNE-io/aigne-framework/commit/eb2752ed7d78f59c435ecc3ccb7227e804e3781e))
57
+ * **gemini:** use StructuredOutputError to trigger retry for missing JSON response ([#660](https://github.com/AIGNE-io/aigne-framework/issues/660)) ([e8826ed](https://github.com/AIGNE-io/aigne-framework/commit/e8826ed96db57bfcce0b577881bf0d2fd828c269))
58
+ * improve image model parameters ([#530](https://github.com/AIGNE-io/aigne-framework/issues/530)) ([d66b5ca](https://github.com/AIGNE-io/aigne-framework/commit/d66b5ca01e14baad2712cc1a84930cdb63703232))
59
+ * **models:** add image parameters support for video generation ([#684](https://github.com/AIGNE-io/aigne-framework/issues/684)) ([b048b7f](https://github.com/AIGNE-io/aigne-framework/commit/b048b7f92bd7a532dbdbeb6fb5fa5499bae6b953))
60
+ * **models:** add imageConfig to gemini image model ([#621](https://github.com/AIGNE-io/aigne-framework/issues/621)) ([252de7a](https://github.com/AIGNE-io/aigne-framework/commit/252de7a10701c4f5302c2fff977c88e5e833b7b1))
61
+ * **models:** add mineType for transform file ([#667](https://github.com/AIGNE-io/aigne-framework/issues/667)) ([155a173](https://github.com/AIGNE-io/aigne-framework/commit/155a173e75aff1dbe870a1305455a4300942e07a))
62
+ * **models:** aigne hub video params ([#665](https://github.com/AIGNE-io/aigne-framework/issues/665)) ([d00f836](https://github.com/AIGNE-io/aigne-framework/commit/d00f8368422d8e3707b974e1aff06714731ebb28))
63
+ * **models:** auto retry when got emtpy response from gemini ([#636](https://github.com/AIGNE-io/aigne-framework/issues/636)) ([9367cef](https://github.com/AIGNE-io/aigne-framework/commit/9367cef49ea4c0c87b8a36b454deb2efaee6886f))
64
+ * **models:** enhance gemini model tool use with status fields ([#634](https://github.com/AIGNE-io/aigne-framework/issues/634)) ([067b175](https://github.com/AIGNE-io/aigne-framework/commit/067b175c8e31bb5b1a6d0fc5a5cfb2d070d8d709))
65
+ * **models:** improve message structure handling and enable auto-message options ([#657](https://github.com/AIGNE-io/aigne-framework/issues/657)) ([233d70c](https://github.com/AIGNE-io/aigne-framework/commit/233d70cb292b937200fada8434f33d957d766ad6))
66
+ * **model:** transform local file to base64 before request llm ([#462](https://github.com/AIGNE-io/aigne-framework/issues/462)) ([58ef5d7](https://github.com/AIGNE-io/aigne-framework/commit/58ef5d77046c49f3c4eed15b7f0cc283cbbcd74a))
67
+ * **model:** updated default video duration settings for AI video models ([#663](https://github.com/AIGNE-io/aigne-framework/issues/663)) ([1203941](https://github.com/AIGNE-io/aigne-framework/commit/12039411aaef77ba665e8edfb0fe6f8097c43e39))
68
+ * should not return local path from aigne hub service ([#460](https://github.com/AIGNE-io/aigne-framework/issues/460)) ([c959717](https://github.com/AIGNE-io/aigne-framework/commit/c95971774f7e84dbeb3313f60b3e6464e2bb22e4))
69
+ * standardize file parameter naming across models ([#534](https://github.com/AIGNE-io/aigne-framework/issues/534)) ([f159a9d](https://github.com/AIGNE-io/aigne-framework/commit/f159a9d6af21ec0e99641996b150560929845845))
70
+ * support gemini-2.0-flash model for image model ([#429](https://github.com/AIGNE-io/aigne-framework/issues/429)) ([5a0bba1](https://github.com/AIGNE-io/aigne-framework/commit/5a0bba197cf8785384b70302f86cf702d04b7fc4))
71
+ * support optional field sturectured output for gemini ([#468](https://github.com/AIGNE-io/aigne-framework/issues/468)) ([70c6279](https://github.com/AIGNE-io/aigne-framework/commit/70c62795039a2862e3333f26707329489bf938de))
72
+ * **transport:** improve HTTP client option handling and error serialization ([#445](https://github.com/AIGNE-io/aigne-framework/issues/445)) ([d3bcdd2](https://github.com/AIGNE-io/aigne-framework/commit/d3bcdd23ab8011a7d40fc157fd61eb240494c7a5))
73
+ * update deps compatibility in CommonJS environment ([#580](https://github.com/AIGNE-io/aigne-framework/issues/580)) ([a1e35d0](https://github.com/AIGNE-io/aigne-framework/commit/a1e35d016405accb51c1aeb6a544503a1c78e912))
74
+
75
+
76
+ ### Dependencies
77
+
78
+ * The following workspace dependencies were updated
79
+ * dependencies
80
+ * @aigne/core bumped to 1.69.0-beta.1
81
+ * devDependencies
82
+ * @aigne/test-utils bumped to 0.5.63-beta.2
83
+
3
84
  ## [0.14.10-beta.1](https://github.com/AIGNE-io/aigne-framework/compare/gemini-v0.14.10-beta...gemini-v0.14.10-beta.1) (2025-11-18)
4
85
 
5
86
 
@@ -1,6 +1,6 @@
1
1
  import { type AgentInvokeOptions, type AgentProcessResult, ChatModel, type ChatModelInput, type ChatModelInputOptions, type ChatModelOptions, type ChatModelOutput } from "@aigne/core";
2
2
  import { type PromiseOrValue } from "@aigne/core/utils/type-utils.js";
3
- import { GoogleGenAI, type GoogleGenAIOptions } from "@google/genai";
3
+ import { GoogleGenAI, type GoogleGenAIOptions, ThinkingLevel } from "@google/genai";
4
4
  export interface GeminiChatModelOptions extends ChatModelOptions {
5
5
  /**
6
6
  * API key for Gemini API
@@ -57,7 +57,7 @@ export declare class GeminiChatModel extends ChatModel {
57
57
  modalities?: import("@aigne/core").Modality[] | {
58
58
  $get: string;
59
59
  } | undefined;
60
- preferInputFileType?: "file" | "url" | {
60
+ preferInputFileType?: "url" | "file" | {
61
61
  $get: string;
62
62
  } | undefined;
63
63
  reasoningEffort?: number | "minimal" | "low" | "medium" | "high" | {
@@ -66,13 +66,21 @@ export declare class GeminiChatModel extends ChatModel {
66
66
  }> | undefined;
67
67
  process(input: ChatModelInput, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<ChatModelOutput>>;
68
68
  protected thinkingBudgetModelMap: ({
69
+ pattern: RegExp;
70
+ support: boolean;
71
+ type: string;
72
+ min?: undefined;
73
+ max?: undefined;
74
+ } | {
69
75
  pattern: RegExp;
70
76
  support: boolean;
71
77
  min: number;
72
78
  max: number;
79
+ type?: undefined;
73
80
  } | {
74
81
  pattern: RegExp;
75
82
  support: boolean;
83
+ type?: undefined;
76
84
  min?: undefined;
77
85
  max?: undefined;
78
86
  })[];
@@ -82,9 +90,16 @@ export declare class GeminiChatModel extends ChatModel {
82
90
  low: number;
83
91
  minimal: number;
84
92
  };
93
+ protected thinkingLevelMap: {
94
+ high: ThinkingLevel;
95
+ medium: ThinkingLevel;
96
+ low: ThinkingLevel;
97
+ minimal: ThinkingLevel;
98
+ };
85
99
  protected getThinkingBudget(model: string, effort: ChatModelInputOptions["reasoningEffort"]): {
86
100
  support: boolean;
87
101
  budget?: number;
102
+ level?: ThinkingLevel;
88
103
  };
89
104
  private processInput;
90
105
  private buildConfig;
@@ -63,6 +63,11 @@ class GeminiChatModel extends core_1.ChatModel {
63
63
  }
64
64
  // References: https://ai.google.dev/gemini-api/docs/thinking#set-budget
65
65
  thinkingBudgetModelMap = [
66
+ {
67
+ pattern: /gemini-3/,
68
+ support: true,
69
+ type: "level",
70
+ },
66
71
  {
67
72
  pattern: /gemini-2.5-pro/,
68
73
  support: true,
@@ -92,10 +97,27 @@ class GeminiChatModel extends core_1.ChatModel {
92
97
  low: 5000,
93
98
  minimal: 200,
94
99
  };
100
+ thinkingLevelMap = {
101
+ high: genai_1.ThinkingLevel.HIGH,
102
+ medium: genai_1.ThinkingLevel.HIGH,
103
+ low: genai_1.ThinkingLevel.LOW,
104
+ minimal: genai_1.ThinkingLevel.LOW,
105
+ };
95
106
  getThinkingBudget(model, effort) {
96
107
  const m = this.thinkingBudgetModelMap.find((i) => i.pattern.test(model));
97
108
  if (!m?.support)
98
109
  return { support: false };
110
+ if (m.type === "level") {
111
+ let level = genai_1.ThinkingLevel.THINKING_LEVEL_UNSPECIFIED;
112
+ if (typeof effort === "string") {
113
+ level = this.thinkingLevelMap[effort];
114
+ }
115
+ else if (typeof effort === "number") {
116
+ level =
117
+ effort >= this.thinkingBudgetLevelMap["medium"] ? genai_1.ThinkingLevel.HIGH : genai_1.ThinkingLevel.LOW;
118
+ }
119
+ return { support: true, level };
120
+ }
99
121
  let budget = typeof effort === "string" ? this.thinkingBudgetLevelMap[effort] || undefined : effort;
100
122
  if (typeof budget === "undefined")
101
123
  return { support: true };
@@ -118,6 +140,7 @@ class GeminiChatModel extends core_1.ChatModel {
118
140
  ? {
119
141
  includeThoughts: true,
120
142
  thinkingBudget: thinkingBudget.budget,
143
+ thinkingLevel: thinkingBudget.level,
121
144
  }
122
145
  : undefined,
123
146
  responseModalities: modelOptions.modalities,
@@ -171,14 +194,21 @@ class GeminiChatModel extends core_1.ChatModel {
171
194
  json = part.functionCall.args;
172
195
  }
173
196
  else {
174
- toolCalls.push({
197
+ const toolCall = {
175
198
  id: part.functionCall.id || (0, uuid_1.v7)(),
176
199
  type: "function",
177
200
  function: {
178
201
  name: part.functionCall.name,
179
202
  arguments: part.functionCall.args || {},
180
203
  },
181
- });
204
+ };
205
+ // Preserve thought_signature for 3.x models
206
+ if (part.thoughtSignature && model.includes("gemini-3")) {
207
+ toolCall.metadata = {
208
+ thoughtSignature: part.thoughtSignature,
209
+ };
210
+ }
211
+ toolCalls.push(toolCall);
182
212
  yield { delta: { json: { toolCalls } } };
183
213
  }
184
214
  }
@@ -256,7 +286,8 @@ class GeminiChatModel extends core_1.ChatModel {
256
286
  usage,
257
287
  files: files.length ? files : undefined,
258
288
  modelOptions: {
259
- reasoningEffort: parameters.config?.thinkingConfig?.thinkingBudget,
289
+ reasoningEffort: parameters.config?.thinkingConfig?.thinkingLevel ||
290
+ parameters.config?.thinkingConfig?.thinkingBudget,
260
291
  },
261
292
  },
262
293
  },
@@ -340,13 +371,20 @@ class GeminiChatModel extends core_1.ChatModel {
340
371
  role: msg.role === "agent" ? "model" : msg.role === "user" ? "user" : undefined,
341
372
  };
342
373
  if (msg.toolCalls) {
343
- content.parts = msg.toolCalls.map((call) => ({
344
- functionCall: {
345
- id: call.id,
346
- name: call.function.name,
347
- args: call.function.arguments,
348
- },
349
- }));
374
+ content.parts = msg.toolCalls.map((call) => {
375
+ const part = {
376
+ functionCall: {
377
+ id: call.id,
378
+ name: call.function.name,
379
+ args: call.function.arguments,
380
+ },
381
+ };
382
+ // Restore thought_signature for 3.x models
383
+ if (call.metadata?.thoughtSignature) {
384
+ part.thoughtSignature = call.metadata.thoughtSignature;
385
+ }
386
+ return part;
387
+ });
350
388
  }
351
389
  else if (msg.toolCallId) {
352
390
  const call = input.messages
@@ -1,6 +1,6 @@
1
1
  import { type AgentInvokeOptions, type AgentProcessResult, ChatModel, type ChatModelInput, type ChatModelInputOptions, type ChatModelOptions, type ChatModelOutput } from "@aigne/core";
2
2
  import { type PromiseOrValue } from "@aigne/core/utils/type-utils.js";
3
- import { GoogleGenAI, type GoogleGenAIOptions } from "@google/genai";
3
+ import { GoogleGenAI, type GoogleGenAIOptions, ThinkingLevel } from "@google/genai";
4
4
  export interface GeminiChatModelOptions extends ChatModelOptions {
5
5
  /**
6
6
  * API key for Gemini API
@@ -57,7 +57,7 @@ export declare class GeminiChatModel extends ChatModel {
57
57
  modalities?: import("@aigne/core").Modality[] | {
58
58
  $get: string;
59
59
  } | undefined;
60
- preferInputFileType?: "file" | "url" | {
60
+ preferInputFileType?: "url" | "file" | {
61
61
  $get: string;
62
62
  } | undefined;
63
63
  reasoningEffort?: number | "minimal" | "low" | "medium" | "high" | {
@@ -66,13 +66,21 @@ export declare class GeminiChatModel extends ChatModel {
66
66
  }> | undefined;
67
67
  process(input: ChatModelInput, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<ChatModelOutput>>;
68
68
  protected thinkingBudgetModelMap: ({
69
+ pattern: RegExp;
70
+ support: boolean;
71
+ type: string;
72
+ min?: undefined;
73
+ max?: undefined;
74
+ } | {
69
75
  pattern: RegExp;
70
76
  support: boolean;
71
77
  min: number;
72
78
  max: number;
79
+ type?: undefined;
73
80
  } | {
74
81
  pattern: RegExp;
75
82
  support: boolean;
83
+ type?: undefined;
76
84
  min?: undefined;
77
85
  max?: undefined;
78
86
  })[];
@@ -82,9 +90,16 @@ export declare class GeminiChatModel extends ChatModel {
82
90
  low: number;
83
91
  minimal: number;
84
92
  };
93
+ protected thinkingLevelMap: {
94
+ high: ThinkingLevel;
95
+ medium: ThinkingLevel;
96
+ low: ThinkingLevel;
97
+ minimal: ThinkingLevel;
98
+ };
85
99
  protected getThinkingBudget(model: string, effort: ChatModelInputOptions["reasoningEffort"]): {
86
100
  support: boolean;
87
101
  budget?: number;
102
+ level?: ThinkingLevel;
88
103
  };
89
104
  private processInput;
90
105
  private buildConfig;
@@ -1,6 +1,6 @@
1
1
  import { type AgentInvokeOptions, type AgentProcessResult, ChatModel, type ChatModelInput, type ChatModelInputOptions, type ChatModelOptions, type ChatModelOutput } from "@aigne/core";
2
2
  import { type PromiseOrValue } from "@aigne/core/utils/type-utils.js";
3
- import { GoogleGenAI, type GoogleGenAIOptions } from "@google/genai";
3
+ import { GoogleGenAI, type GoogleGenAIOptions, ThinkingLevel } from "@google/genai";
4
4
  export interface GeminiChatModelOptions extends ChatModelOptions {
5
5
  /**
6
6
  * API key for Gemini API
@@ -57,7 +57,7 @@ export declare class GeminiChatModel extends ChatModel {
57
57
  modalities?: import("@aigne/core").Modality[] | {
58
58
  $get: string;
59
59
  } | undefined;
60
- preferInputFileType?: "file" | "url" | {
60
+ preferInputFileType?: "url" | "file" | {
61
61
  $get: string;
62
62
  } | undefined;
63
63
  reasoningEffort?: number | "minimal" | "low" | "medium" | "high" | {
@@ -66,13 +66,21 @@ export declare class GeminiChatModel extends ChatModel {
66
66
  }> | undefined;
67
67
  process(input: ChatModelInput, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<ChatModelOutput>>;
68
68
  protected thinkingBudgetModelMap: ({
69
+ pattern: RegExp;
70
+ support: boolean;
71
+ type: string;
72
+ min?: undefined;
73
+ max?: undefined;
74
+ } | {
69
75
  pattern: RegExp;
70
76
  support: boolean;
71
77
  min: number;
72
78
  max: number;
79
+ type?: undefined;
73
80
  } | {
74
81
  pattern: RegExp;
75
82
  support: boolean;
83
+ type?: undefined;
76
84
  min?: undefined;
77
85
  max?: undefined;
78
86
  })[];
@@ -82,9 +90,16 @@ export declare class GeminiChatModel extends ChatModel {
82
90
  low: number;
83
91
  minimal: number;
84
92
  };
93
+ protected thinkingLevelMap: {
94
+ high: ThinkingLevel;
95
+ medium: ThinkingLevel;
96
+ low: ThinkingLevel;
97
+ minimal: ThinkingLevel;
98
+ };
85
99
  protected getThinkingBudget(model: string, effort: ChatModelInputOptions["reasoningEffort"]): {
86
100
  support: boolean;
87
101
  budget?: number;
102
+ level?: ThinkingLevel;
88
103
  };
89
104
  private processInput;
90
105
  private buildConfig;
@@ -3,7 +3,7 @@ import { logger } from "@aigne/core/utils/logger.js";
3
3
  import { mergeUsage } from "@aigne/core/utils/model-utils.js";
4
4
  import { isNonNullable } from "@aigne/core/utils/type-utils.js";
5
5
  import { v7 } from "@aigne/uuid";
6
- import { FunctionCallingConfigMode, GoogleGenAI, } from "@google/genai";
6
+ import { FunctionCallingConfigMode, GoogleGenAI, ThinkingLevel, } from "@google/genai";
7
7
  import { z } from "zod";
8
8
  import { zodToJsonSchema } from "zod-to-json-schema";
9
9
  const GEMINI_DEFAULT_CHAT_MODEL = "gemini-2.0-flash";
@@ -60,6 +60,11 @@ export class GeminiChatModel extends ChatModel {
60
60
  }
61
61
  // References: https://ai.google.dev/gemini-api/docs/thinking#set-budget
62
62
  thinkingBudgetModelMap = [
63
+ {
64
+ pattern: /gemini-3/,
65
+ support: true,
66
+ type: "level",
67
+ },
63
68
  {
64
69
  pattern: /gemini-2.5-pro/,
65
70
  support: true,
@@ -89,10 +94,27 @@ export class GeminiChatModel extends ChatModel {
89
94
  low: 5000,
90
95
  minimal: 200,
91
96
  };
97
+ thinkingLevelMap = {
98
+ high: ThinkingLevel.HIGH,
99
+ medium: ThinkingLevel.HIGH,
100
+ low: ThinkingLevel.LOW,
101
+ minimal: ThinkingLevel.LOW,
102
+ };
92
103
  getThinkingBudget(model, effort) {
93
104
  const m = this.thinkingBudgetModelMap.find((i) => i.pattern.test(model));
94
105
  if (!m?.support)
95
106
  return { support: false };
107
+ if (m.type === "level") {
108
+ let level = ThinkingLevel.THINKING_LEVEL_UNSPECIFIED;
109
+ if (typeof effort === "string") {
110
+ level = this.thinkingLevelMap[effort];
111
+ }
112
+ else if (typeof effort === "number") {
113
+ level =
114
+ effort >= this.thinkingBudgetLevelMap["medium"] ? ThinkingLevel.HIGH : ThinkingLevel.LOW;
115
+ }
116
+ return { support: true, level };
117
+ }
96
118
  let budget = typeof effort === "string" ? this.thinkingBudgetLevelMap[effort] || undefined : effort;
97
119
  if (typeof budget === "undefined")
98
120
  return { support: true };
@@ -115,6 +137,7 @@ export class GeminiChatModel extends ChatModel {
115
137
  ? {
116
138
  includeThoughts: true,
117
139
  thinkingBudget: thinkingBudget.budget,
140
+ thinkingLevel: thinkingBudget.level,
118
141
  }
119
142
  : undefined,
120
143
  responseModalities: modelOptions.modalities,
@@ -168,14 +191,21 @@ export class GeminiChatModel extends ChatModel {
168
191
  json = part.functionCall.args;
169
192
  }
170
193
  else {
171
- toolCalls.push({
194
+ const toolCall = {
172
195
  id: part.functionCall.id || v7(),
173
196
  type: "function",
174
197
  function: {
175
198
  name: part.functionCall.name,
176
199
  arguments: part.functionCall.args || {},
177
200
  },
178
- });
201
+ };
202
+ // Preserve thought_signature for 3.x models
203
+ if (part.thoughtSignature && model.includes("gemini-3")) {
204
+ toolCall.metadata = {
205
+ thoughtSignature: part.thoughtSignature,
206
+ };
207
+ }
208
+ toolCalls.push(toolCall);
179
209
  yield { delta: { json: { toolCalls } } };
180
210
  }
181
211
  }
@@ -253,7 +283,8 @@ export class GeminiChatModel extends ChatModel {
253
283
  usage,
254
284
  files: files.length ? files : undefined,
255
285
  modelOptions: {
256
- reasoningEffort: parameters.config?.thinkingConfig?.thinkingBudget,
286
+ reasoningEffort: parameters.config?.thinkingConfig?.thinkingLevel ||
287
+ parameters.config?.thinkingConfig?.thinkingBudget,
257
288
  },
258
289
  },
259
290
  },
@@ -337,13 +368,20 @@ export class GeminiChatModel extends ChatModel {
337
368
  role: msg.role === "agent" ? "model" : msg.role === "user" ? "user" : undefined,
338
369
  };
339
370
  if (msg.toolCalls) {
340
- content.parts = msg.toolCalls.map((call) => ({
341
- functionCall: {
342
- id: call.id,
343
- name: call.function.name,
344
- args: call.function.arguments,
345
- },
346
- }));
371
+ content.parts = msg.toolCalls.map((call) => {
372
+ const part = {
373
+ functionCall: {
374
+ id: call.id,
375
+ name: call.function.name,
376
+ args: call.function.arguments,
377
+ },
378
+ };
379
+ // Restore thought_signature for 3.x models
380
+ if (call.metadata?.thoughtSignature) {
381
+ part.thoughtSignature = call.metadata.thoughtSignature;
382
+ }
383
+ return part;
384
+ });
347
385
  }
348
386
  else if (msg.toolCallId) {
349
387
  const call = input.messages
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/gemini",
3
- "version": "0.14.10-beta.1",
3
+ "version": "0.14.10-beta.4",
4
4
  "description": "AIGNE Gemini SDK for integrating with Google's Gemini AI models",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -36,10 +36,10 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@aigne/uuid": "^13.0.1",
39
- "@google/genai": "^1.24.0",
39
+ "@google/genai": "^1.30.0",
40
40
  "zod": "^3.25.67",
41
41
  "zod-to-json-schema": "^3.24.6",
42
- "@aigne/core": "^1.68.3-beta.1",
42
+ "@aigne/core": "^1.69.0-beta.2",
43
43
  "@aigne/platform-helpers": "^0.6.4"
44
44
  },
45
45
  "devDependencies": {
@@ -48,7 +48,7 @@
48
48
  "npm-run-all": "^4.1.5",
49
49
  "rimraf": "^6.0.1",
50
50
  "typescript": "^5.9.2",
51
- "@aigne/test-utils": "^0.5.63-beta.1"
51
+ "@aigne/test-utils": "^0.5.63-beta.3"
52
52
  },
53
53
  "scripts": {
54
54
  "lint": "tsc --noEmit",