@aigne/gemini 0.14.11-beta → 0.14.12-beta
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,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.14.12-beta](https://github.com/AIGNE-io/aigne-framework/compare/gemini-v0.14.11...gemini-v0.14.12-beta) (2025-11-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* bump version ([ba7ad18](https://github.com/AIGNE-io/aigne-framework/commit/ba7ad184fcf32b49bf0507a3cb638d20fb00690d))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @aigne/core bumped to 1.69.2-beta
|
|
16
|
+
* @aigne/platform-helpers bumped to 0.6.5-beta
|
|
17
|
+
* devDependencies
|
|
18
|
+
* @aigne/test-utils bumped to 0.5.65-beta
|
|
19
|
+
|
|
20
|
+
## [0.14.11](https://github.com/AIGNE-io/aigne-framework/compare/gemini-v0.14.11-beta.1...gemini-v0.14.11) (2025-11-28)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Dependencies
|
|
24
|
+
|
|
25
|
+
* The following workspace dependencies were updated
|
|
26
|
+
* dependencies
|
|
27
|
+
* @aigne/core bumped to 1.69.1
|
|
28
|
+
* devDependencies
|
|
29
|
+
* @aigne/test-utils bumped to 0.5.64
|
|
30
|
+
|
|
31
|
+
## [0.14.11-beta.1](https://github.com/AIGNE-io/aigne-framework/compare/gemini-v0.14.11-beta...gemini-v0.14.11-beta.1) (2025-11-26)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Bug Fixes
|
|
35
|
+
|
|
36
|
+
* **model:** handle large video files by uploading to Files API ([#769](https://github.com/AIGNE-io/aigne-framework/issues/769)) ([5fd7661](https://github.com/AIGNE-io/aigne-framework/commit/5fd76613bd7301cc76bde933de2095a6d86f8c7e))
|
|
37
|
+
|
|
3
38
|
## [0.14.11-beta](https://github.com/AIGNE-io/aigne-framework/compare/gemini-v0.14.10...gemini-v0.14.11-beta) (2025-11-24)
|
|
4
39
|
|
|
5
40
|
|
|
@@ -5,12 +5,14 @@ const core_1 = require("@aigne/core");
|
|
|
5
5
|
const logger_js_1 = require("@aigne/core/utils/logger.js");
|
|
6
6
|
const model_utils_js_1 = require("@aigne/core/utils/model-utils.js");
|
|
7
7
|
const type_utils_js_1 = require("@aigne/core/utils/type-utils.js");
|
|
8
|
+
const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
|
|
8
9
|
const uuid_1 = require("@aigne/uuid");
|
|
9
10
|
const genai_1 = require("@google/genai");
|
|
10
11
|
const zod_1 = require("zod");
|
|
11
12
|
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
12
13
|
const GEMINI_DEFAULT_CHAT_MODEL = "gemini-2.0-flash";
|
|
13
14
|
const OUTPUT_FUNCTION_NAME = "output";
|
|
15
|
+
const NEED_UPLOAD_MAX_FILE_SIZE_MB = 20;
|
|
14
16
|
/**
|
|
15
17
|
* Implementation of the ChatModel interface for Google's Gemini API
|
|
16
18
|
*
|
|
@@ -64,7 +66,7 @@ class GeminiChatModel extends core_1.ChatModel {
|
|
|
64
66
|
// References: https://ai.google.dev/gemini-api/docs/thinking#set-budget
|
|
65
67
|
thinkingBudgetModelMap = [
|
|
66
68
|
{
|
|
67
|
-
pattern: /gemini-3/,
|
|
69
|
+
pattern: /gemini-3(?!.*-image-)/,
|
|
68
70
|
support: true,
|
|
69
71
|
type: "level",
|
|
70
72
|
},
|
|
@@ -130,7 +132,7 @@ class GeminiChatModel extends core_1.ChatModel {
|
|
|
130
132
|
async *processInput(input, options) {
|
|
131
133
|
const modelOptions = await this.getModelOptions(input, options);
|
|
132
134
|
const model = modelOptions.model || this.credential.model;
|
|
133
|
-
const { contents, config } = await this.buildContents(input);
|
|
135
|
+
const { contents, config } = await this.buildContents(input, options);
|
|
134
136
|
const thinkingBudget = this.getThinkingBudget(model, modelOptions.reasoningEffort);
|
|
135
137
|
const parameters = {
|
|
136
138
|
model,
|
|
@@ -348,7 +350,39 @@ class GeminiChatModel extends core_1.ChatModel {
|
|
|
348
350
|
};
|
|
349
351
|
return { tools, toolConfig: { functionCallingConfig } };
|
|
350
352
|
}
|
|
351
|
-
async
|
|
353
|
+
async buildVideoContentParts(media, options) {
|
|
354
|
+
const { path: filePath, mimeType: fileMimeType } = await this.transformFileType("local", media, options);
|
|
355
|
+
if (filePath) {
|
|
356
|
+
const stats = await index_js_1.nodejs.fs.stat(filePath);
|
|
357
|
+
const fileSizeInBytes = stats.size;
|
|
358
|
+
const fileSizeMB = fileSizeInBytes / (1024 * 1024);
|
|
359
|
+
if (fileSizeMB > NEED_UPLOAD_MAX_FILE_SIZE_MB) {
|
|
360
|
+
const uploadedFile = await this.googleClient.files.upload({
|
|
361
|
+
file: filePath,
|
|
362
|
+
config: { mimeType: fileMimeType },
|
|
363
|
+
});
|
|
364
|
+
let file = uploadedFile;
|
|
365
|
+
while (file.state === "PROCESSING") {
|
|
366
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
367
|
+
if (file.name) {
|
|
368
|
+
file = await this.googleClient.files.get({ name: file.name });
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (file.state !== "ACTIVE") {
|
|
372
|
+
throw new Error(`File ${file.name} failed to process: ${file.state}`);
|
|
373
|
+
}
|
|
374
|
+
if (file.uri && file.mimeType) {
|
|
375
|
+
const result = (0, genai_1.createUserContent)([(0, genai_1.createPartFromUri)(file.uri, file.mimeType), ""]);
|
|
376
|
+
const part = result.parts?.find((x) => x.fileData);
|
|
377
|
+
if (part) {
|
|
378
|
+
await index_js_1.nodejs.fs.rm(filePath);
|
|
379
|
+
return part;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
async buildContents(input, options) {
|
|
352
386
|
const result = {
|
|
353
387
|
contents: [],
|
|
354
388
|
};
|
|
@@ -431,8 +465,12 @@ class GeminiChatModel extends core_1.ChatModel {
|
|
|
431
465
|
return { text: item.text };
|
|
432
466
|
case "url":
|
|
433
467
|
return { fileData: { fileUri: item.url, mimeType: item.mimeType } };
|
|
434
|
-
case "file":
|
|
468
|
+
case "file": {
|
|
469
|
+
const part = await this.buildVideoContentParts(item, options);
|
|
470
|
+
if (part)
|
|
471
|
+
return part;
|
|
435
472
|
return { inlineData: { data: item.data, mimeType: item.mimeType } };
|
|
473
|
+
}
|
|
436
474
|
case "local":
|
|
437
475
|
throw new Error(`Unsupported local file: ${item.path}, it should be converted to base64 at ChatModel`);
|
|
438
476
|
}
|
|
@@ -2,12 +2,14 @@ import { agentProcessResultToObject, ChatModel, StructuredOutputError, safeParse
|
|
|
2
2
|
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
|
+
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
5
6
|
import { v7 } from "@aigne/uuid";
|
|
6
|
-
import { FunctionCallingConfigMode, GoogleGenAI, ThinkingLevel, } from "@google/genai";
|
|
7
|
+
import { createPartFromUri, createUserContent, FunctionCallingConfigMode, GoogleGenAI, ThinkingLevel, } from "@google/genai";
|
|
7
8
|
import { z } from "zod";
|
|
8
9
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
9
10
|
const GEMINI_DEFAULT_CHAT_MODEL = "gemini-2.0-flash";
|
|
10
11
|
const OUTPUT_FUNCTION_NAME = "output";
|
|
12
|
+
const NEED_UPLOAD_MAX_FILE_SIZE_MB = 20;
|
|
11
13
|
/**
|
|
12
14
|
* Implementation of the ChatModel interface for Google's Gemini API
|
|
13
15
|
*
|
|
@@ -61,7 +63,7 @@ export class GeminiChatModel extends ChatModel {
|
|
|
61
63
|
// References: https://ai.google.dev/gemini-api/docs/thinking#set-budget
|
|
62
64
|
thinkingBudgetModelMap = [
|
|
63
65
|
{
|
|
64
|
-
pattern: /gemini-3/,
|
|
66
|
+
pattern: /gemini-3(?!.*-image-)/,
|
|
65
67
|
support: true,
|
|
66
68
|
type: "level",
|
|
67
69
|
},
|
|
@@ -127,7 +129,7 @@ export class GeminiChatModel extends ChatModel {
|
|
|
127
129
|
async *processInput(input, options) {
|
|
128
130
|
const modelOptions = await this.getModelOptions(input, options);
|
|
129
131
|
const model = modelOptions.model || this.credential.model;
|
|
130
|
-
const { contents, config } = await this.buildContents(input);
|
|
132
|
+
const { contents, config } = await this.buildContents(input, options);
|
|
131
133
|
const thinkingBudget = this.getThinkingBudget(model, modelOptions.reasoningEffort);
|
|
132
134
|
const parameters = {
|
|
133
135
|
model,
|
|
@@ -345,7 +347,39 @@ export class GeminiChatModel extends ChatModel {
|
|
|
345
347
|
};
|
|
346
348
|
return { tools, toolConfig: { functionCallingConfig } };
|
|
347
349
|
}
|
|
348
|
-
async
|
|
350
|
+
async buildVideoContentParts(media, options) {
|
|
351
|
+
const { path: filePath, mimeType: fileMimeType } = await this.transformFileType("local", media, options);
|
|
352
|
+
if (filePath) {
|
|
353
|
+
const stats = await nodejs.fs.stat(filePath);
|
|
354
|
+
const fileSizeInBytes = stats.size;
|
|
355
|
+
const fileSizeMB = fileSizeInBytes / (1024 * 1024);
|
|
356
|
+
if (fileSizeMB > NEED_UPLOAD_MAX_FILE_SIZE_MB) {
|
|
357
|
+
const uploadedFile = await this.googleClient.files.upload({
|
|
358
|
+
file: filePath,
|
|
359
|
+
config: { mimeType: fileMimeType },
|
|
360
|
+
});
|
|
361
|
+
let file = uploadedFile;
|
|
362
|
+
while (file.state === "PROCESSING") {
|
|
363
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
364
|
+
if (file.name) {
|
|
365
|
+
file = await this.googleClient.files.get({ name: file.name });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (file.state !== "ACTIVE") {
|
|
369
|
+
throw new Error(`File ${file.name} failed to process: ${file.state}`);
|
|
370
|
+
}
|
|
371
|
+
if (file.uri && file.mimeType) {
|
|
372
|
+
const result = createUserContent([createPartFromUri(file.uri, file.mimeType), ""]);
|
|
373
|
+
const part = result.parts?.find((x) => x.fileData);
|
|
374
|
+
if (part) {
|
|
375
|
+
await nodejs.fs.rm(filePath);
|
|
376
|
+
return part;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
async buildContents(input, options) {
|
|
349
383
|
const result = {
|
|
350
384
|
contents: [],
|
|
351
385
|
};
|
|
@@ -428,8 +462,12 @@ export class GeminiChatModel extends ChatModel {
|
|
|
428
462
|
return { text: item.text };
|
|
429
463
|
case "url":
|
|
430
464
|
return { fileData: { fileUri: item.url, mimeType: item.mimeType } };
|
|
431
|
-
case "file":
|
|
465
|
+
case "file": {
|
|
466
|
+
const part = await this.buildVideoContentParts(item, options);
|
|
467
|
+
if (part)
|
|
468
|
+
return part;
|
|
432
469
|
return { inlineData: { data: item.data, mimeType: item.mimeType } };
|
|
470
|
+
}
|
|
433
471
|
case "local":
|
|
434
472
|
throw new Error(`Unsupported local file: ${item.path}, it should be converted to base64 at ChatModel`);
|
|
435
473
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/gemini",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.12-beta",
|
|
4
4
|
"description": "AIGNE Gemini SDK for integrating with Google's Gemini AI models",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -39,8 +39,8 @@
|
|
|
39
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.69.
|
|
43
|
-
"@aigne/platform-helpers": "^0.6.
|
|
42
|
+
"@aigne/core": "^1.69.2-beta",
|
|
43
|
+
"@aigne/platform-helpers": "^0.6.5-beta"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/bun": "^1.2.22",
|
|
@@ -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.
|
|
51
|
+
"@aigne/test-utils": "^0.5.65-beta"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"lint": "tsc --noEmit",
|