@aigne/gemini 0.14.16-beta.11 → 0.14.16-beta.12
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,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.14.16-beta.12](https://github.com/AIGNE-io/aigne-framework/compare/gemini-v0.14.16-beta.11...gemini-v0.14.16-beta.12) (2026-01-06)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **core:** preserve Agent Skill in session compact and support complex tool result content ([#876](https://github.com/AIGNE-io/aigne-framework/issues/876)) ([edb86ae](https://github.com/AIGNE-io/aigne-framework/commit/edb86ae2b9cfe56a8f08b276f843606e310566cf))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @aigne/core bumped to 1.72.0-beta.11
|
|
16
|
+
* devDependencies
|
|
17
|
+
* @aigne/test-utils bumped to 0.5.69-beta.11
|
|
18
|
+
|
|
3
19
|
## [0.14.16-beta.11](https://github.com/AIGNE-io/aigne-framework/compare/gemini-v0.14.16-beta.10...gemini-v0.14.16-beta.11) (2026-01-06)
|
|
4
20
|
|
|
5
21
|
|
|
@@ -438,55 +438,46 @@ class GeminiChatModel extends core_1.ChatModel {
|
|
|
438
438
|
.find((c) => c?.id === msg.toolCallId);
|
|
439
439
|
if (!call)
|
|
440
440
|
throw new Error(`Tool call not found: ${msg.toolCallId}`);
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
441
|
+
if (!msg.content)
|
|
442
|
+
throw new Error("Tool call must have content");
|
|
443
|
+
// parse tool result as a record
|
|
444
|
+
let toolResult;
|
|
445
|
+
{
|
|
446
|
+
let text;
|
|
447
|
+
if (typeof msg.content === "string")
|
|
448
|
+
text = msg.content;
|
|
449
|
+
else if (msg.content?.length === 1) {
|
|
450
|
+
const first = msg.content[0];
|
|
451
|
+
if (first?.type === "text")
|
|
452
|
+
text = first.text;
|
|
453
|
+
}
|
|
454
|
+
if (text) {
|
|
455
|
+
try {
|
|
456
|
+
const obj = (0, yaml_1.parse)(text);
|
|
457
|
+
if ((0, type_utils_js_1.isRecord)(obj))
|
|
458
|
+
toolResult = obj;
|
|
459
|
+
}
|
|
460
|
+
catch {
|
|
461
|
+
// ignore
|
|
462
|
+
}
|
|
463
|
+
if (!toolResult)
|
|
464
|
+
toolResult = { result: text };
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
const functionResponse = {
|
|
468
|
+
id: msg.toolCallId,
|
|
469
|
+
name: call.function.name,
|
|
445
470
|
};
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
if (isError) {
|
|
449
|
-
Object.assign(response, { status: "error" }, output);
|
|
471
|
+
if (toolResult) {
|
|
472
|
+
functionResponse.response = toolResult;
|
|
450
473
|
}
|
|
451
474
|
else {
|
|
452
|
-
|
|
453
|
-
if ("output" in output) {
|
|
454
|
-
Object.assign(response, output);
|
|
455
|
-
}
|
|
456
|
-
else {
|
|
457
|
-
Object.assign(response, { output });
|
|
458
|
-
}
|
|
475
|
+
functionResponse.parts = await this.contentToParts(msg.content, options);
|
|
459
476
|
}
|
|
460
|
-
content.parts = [
|
|
461
|
-
{
|
|
462
|
-
functionResponse: {
|
|
463
|
-
id: msg.toolCallId,
|
|
464
|
-
name: call.function.name,
|
|
465
|
-
response,
|
|
466
|
-
},
|
|
467
|
-
},
|
|
468
|
-
];
|
|
469
|
-
}
|
|
470
|
-
else if (typeof msg.content === "string") {
|
|
471
|
-
content.parts = [{ text: msg.content }];
|
|
477
|
+
content.parts = [{ functionResponse }];
|
|
472
478
|
}
|
|
473
|
-
else if (
|
|
474
|
-
content.parts = await
|
|
475
|
-
switch (item.type) {
|
|
476
|
-
case "text":
|
|
477
|
-
return { text: item.text };
|
|
478
|
-
case "url":
|
|
479
|
-
return { fileData: { fileUri: item.url, mimeType: item.mimeType } };
|
|
480
|
-
case "file": {
|
|
481
|
-
const part = await this.buildVideoContentParts(item, options);
|
|
482
|
-
if (part)
|
|
483
|
-
return part;
|
|
484
|
-
return { inlineData: { data: item.data, mimeType: item.mimeType } };
|
|
485
|
-
}
|
|
486
|
-
case "local":
|
|
487
|
-
throw new Error(`Unsupported local file: ${item.path}, it should be converted to base64 at ChatModel`);
|
|
488
|
-
}
|
|
489
|
-
}));
|
|
479
|
+
else if (msg.content) {
|
|
480
|
+
content.parts = await this.contentToParts(msg.content, options);
|
|
490
481
|
}
|
|
491
482
|
return content;
|
|
492
483
|
}))).filter(type_utils_js_1.isNonNullable);
|
|
@@ -497,6 +488,26 @@ class GeminiChatModel extends core_1.ChatModel {
|
|
|
497
488
|
}
|
|
498
489
|
return result;
|
|
499
490
|
}
|
|
491
|
+
async contentToParts(content, options) {
|
|
492
|
+
if (typeof content === "string")
|
|
493
|
+
return [{ text: content }];
|
|
494
|
+
return Promise.all(content.map(async (item) => {
|
|
495
|
+
switch (item.type) {
|
|
496
|
+
case "text":
|
|
497
|
+
return { text: item.text };
|
|
498
|
+
case "url":
|
|
499
|
+
return { fileData: { fileUri: item.url, mimeType: item.mimeType } };
|
|
500
|
+
case "file": {
|
|
501
|
+
const part = await this.buildVideoContentParts(item, options);
|
|
502
|
+
if (part)
|
|
503
|
+
return part;
|
|
504
|
+
return { inlineData: { data: item.data, mimeType: item.mimeType } };
|
|
505
|
+
}
|
|
506
|
+
case "local":
|
|
507
|
+
throw new Error(`Unsupported local file: ${item.path}, it should be converted to base64 at ChatModel`);
|
|
508
|
+
}
|
|
509
|
+
}));
|
|
510
|
+
}
|
|
500
511
|
ensureMessagesHasUserMessage(systems, contents) {
|
|
501
512
|
// no messages but system messages
|
|
502
513
|
if (!contents.length && systems.length) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { agentProcessResultToObject, ChatModel, StructuredOutputError, safeParseJSON, } from "@aigne/core";
|
|
2
2
|
import { logger } from "@aigne/core/utils/logger.js";
|
|
3
3
|
import { mergeUsage } from "@aigne/core/utils/model-utils.js";
|
|
4
|
-
import { isNonNullable } from "@aigne/core/utils/type-utils.js";
|
|
4
|
+
import { isNonNullable, isRecord } from "@aigne/core/utils/type-utils.js";
|
|
5
5
|
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
6
6
|
import { v7 } from "@aigne/uuid";
|
|
7
7
|
import { createPartFromUri, createUserContent, FunctionCallingConfigMode, GoogleGenAI, ThinkingLevel, } from "@google/genai";
|
|
@@ -435,55 +435,46 @@ export class GeminiChatModel extends ChatModel {
|
|
|
435
435
|
.find((c) => c?.id === msg.toolCallId);
|
|
436
436
|
if (!call)
|
|
437
437
|
throw new Error(`Tool call not found: ${msg.toolCallId}`);
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
438
|
+
if (!msg.content)
|
|
439
|
+
throw new Error("Tool call must have content");
|
|
440
|
+
// parse tool result as a record
|
|
441
|
+
let toolResult;
|
|
442
|
+
{
|
|
443
|
+
let text;
|
|
444
|
+
if (typeof msg.content === "string")
|
|
445
|
+
text = msg.content;
|
|
446
|
+
else if (msg.content?.length === 1) {
|
|
447
|
+
const first = msg.content[0];
|
|
448
|
+
if (first?.type === "text")
|
|
449
|
+
text = first.text;
|
|
450
|
+
}
|
|
451
|
+
if (text) {
|
|
452
|
+
try {
|
|
453
|
+
const obj = parse(text);
|
|
454
|
+
if (isRecord(obj))
|
|
455
|
+
toolResult = obj;
|
|
456
|
+
}
|
|
457
|
+
catch {
|
|
458
|
+
// ignore
|
|
459
|
+
}
|
|
460
|
+
if (!toolResult)
|
|
461
|
+
toolResult = { result: text };
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
const functionResponse = {
|
|
465
|
+
id: msg.toolCallId,
|
|
466
|
+
name: call.function.name,
|
|
442
467
|
};
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
if (isError) {
|
|
446
|
-
Object.assign(response, { status: "error" }, output);
|
|
468
|
+
if (toolResult) {
|
|
469
|
+
functionResponse.response = toolResult;
|
|
447
470
|
}
|
|
448
471
|
else {
|
|
449
|
-
|
|
450
|
-
if ("output" in output) {
|
|
451
|
-
Object.assign(response, output);
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
Object.assign(response, { output });
|
|
455
|
-
}
|
|
472
|
+
functionResponse.parts = await this.contentToParts(msg.content, options);
|
|
456
473
|
}
|
|
457
|
-
content.parts = [
|
|
458
|
-
{
|
|
459
|
-
functionResponse: {
|
|
460
|
-
id: msg.toolCallId,
|
|
461
|
-
name: call.function.name,
|
|
462
|
-
response,
|
|
463
|
-
},
|
|
464
|
-
},
|
|
465
|
-
];
|
|
466
|
-
}
|
|
467
|
-
else if (typeof msg.content === "string") {
|
|
468
|
-
content.parts = [{ text: msg.content }];
|
|
474
|
+
content.parts = [{ functionResponse }];
|
|
469
475
|
}
|
|
470
|
-
else if (
|
|
471
|
-
content.parts = await
|
|
472
|
-
switch (item.type) {
|
|
473
|
-
case "text":
|
|
474
|
-
return { text: item.text };
|
|
475
|
-
case "url":
|
|
476
|
-
return { fileData: { fileUri: item.url, mimeType: item.mimeType } };
|
|
477
|
-
case "file": {
|
|
478
|
-
const part = await this.buildVideoContentParts(item, options);
|
|
479
|
-
if (part)
|
|
480
|
-
return part;
|
|
481
|
-
return { inlineData: { data: item.data, mimeType: item.mimeType } };
|
|
482
|
-
}
|
|
483
|
-
case "local":
|
|
484
|
-
throw new Error(`Unsupported local file: ${item.path}, it should be converted to base64 at ChatModel`);
|
|
485
|
-
}
|
|
486
|
-
}));
|
|
476
|
+
else if (msg.content) {
|
|
477
|
+
content.parts = await this.contentToParts(msg.content, options);
|
|
487
478
|
}
|
|
488
479
|
return content;
|
|
489
480
|
}))).filter(isNonNullable);
|
|
@@ -494,6 +485,26 @@ export class GeminiChatModel extends ChatModel {
|
|
|
494
485
|
}
|
|
495
486
|
return result;
|
|
496
487
|
}
|
|
488
|
+
async contentToParts(content, options) {
|
|
489
|
+
if (typeof content === "string")
|
|
490
|
+
return [{ text: content }];
|
|
491
|
+
return Promise.all(content.map(async (item) => {
|
|
492
|
+
switch (item.type) {
|
|
493
|
+
case "text":
|
|
494
|
+
return { text: item.text };
|
|
495
|
+
case "url":
|
|
496
|
+
return { fileData: { fileUri: item.url, mimeType: item.mimeType } };
|
|
497
|
+
case "file": {
|
|
498
|
+
const part = await this.buildVideoContentParts(item, options);
|
|
499
|
+
if (part)
|
|
500
|
+
return part;
|
|
501
|
+
return { inlineData: { data: item.data, mimeType: item.mimeType } };
|
|
502
|
+
}
|
|
503
|
+
case "local":
|
|
504
|
+
throw new Error(`Unsupported local file: ${item.path}, it should be converted to base64 at ChatModel`);
|
|
505
|
+
}
|
|
506
|
+
}));
|
|
507
|
+
}
|
|
497
508
|
ensureMessagesHasUserMessage(systems, contents) {
|
|
498
509
|
// no messages but system messages
|
|
499
510
|
if (!contents.length && systems.length) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/gemini",
|
|
3
|
-
"version": "0.14.16-beta.
|
|
3
|
+
"version": "0.14.16-beta.12",
|
|
4
4
|
"description": "AIGNE Gemini SDK for integrating with Google's Gemini AI models",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"yaml": "^2.8.1",
|
|
41
41
|
"zod": "^3.25.67",
|
|
42
42
|
"zod-to-json-schema": "^3.24.6",
|
|
43
|
-
"@aigne/core": "^1.72.0-beta.
|
|
43
|
+
"@aigne/core": "^1.72.0-beta.11",
|
|
44
44
|
"@aigne/platform-helpers": "^0.6.7-beta"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"npm-run-all": "^4.1.5",
|
|
50
50
|
"rimraf": "^6.0.1",
|
|
51
51
|
"typescript": "^5.9.2",
|
|
52
|
-
"@aigne/test-utils": "^0.5.69-beta.
|
|
52
|
+
"@aigne/test-utils": "^0.5.69-beta.11"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"lint": "tsc --noEmit",
|