@aigne/core 1.58.2 → 1.59.0
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 +15 -0
- package/lib/cjs/agents/agent.d.ts +1 -1
- package/lib/cjs/agents/agent.js +2 -1
- package/lib/cjs/agents/chat-model.d.ts +9 -3
- package/lib/cjs/agents/chat-model.js +31 -11
- package/lib/cjs/agents/image-model.d.ts +2 -2
- package/lib/cjs/loader/agent-yaml.js +4 -1
- package/lib/cjs/utils/json-schema.d.ts +1 -0
- package/lib/cjs/utils/json-schema.js +6 -0
- package/lib/cjs/utils/type-utils.d.ts +1 -0
- package/lib/cjs/utils/type-utils.js +19 -0
- package/lib/dts/agents/agent.d.ts +1 -1
- package/lib/dts/agents/chat-model.d.ts +9 -3
- package/lib/dts/agents/image-model.d.ts +2 -2
- package/lib/dts/utils/json-schema.d.ts +1 -0
- package/lib/dts/utils/type-utils.d.ts +1 -0
- package/lib/esm/agents/agent.d.ts +1 -1
- package/lib/esm/agents/agent.js +3 -2
- package/lib/esm/agents/chat-model.d.ts +9 -3
- package/lib/esm/agents/chat-model.js +32 -12
- package/lib/esm/agents/image-model.d.ts +2 -2
- package/lib/esm/loader/agent-yaml.js +4 -1
- package/lib/esm/utils/json-schema.d.ts +1 -0
- package/lib/esm/utils/json-schema.js +5 -0
- package/lib/esm/utils/type-utils.d.ts +1 -0
- package/lib/esm/utils/type-utils.js +18 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.59.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.58.3...core-v1.59.0) (2025-09-09)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* 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))
|
|
9
|
+
|
|
10
|
+
## [1.58.3](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.58.2...core-v1.58.3) (2025-09-08)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* handle absolute paths in agent YAML prompt URLs ([#466](https://github.com/AIGNE-io/aigne-framework/issues/466)) ([a07a088](https://github.com/AIGNE-io/aigne-framework/commit/a07a0880728f65fc831578763b62ce5144d1aed8))
|
|
16
|
+
* 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))
|
|
17
|
+
|
|
3
18
|
## [1.58.2](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.58.1...core-v1.58.2) (2025-09-05)
|
|
4
19
|
|
|
5
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
2
2
|
import type * as prompts from "@inquirer/prompts";
|
|
3
|
-
import { ZodObject, type ZodType } from "zod";
|
|
3
|
+
import { type ZodObject, type ZodType } from "zod";
|
|
4
4
|
import type { AgentEvent, Context, UserContext } from "../aigne/context.js";
|
|
5
5
|
import type { MessagePayload } from "../aigne/message-queue.js";
|
|
6
6
|
import type { ContextUsage } from "../aigne/usage.js";
|
package/lib/cjs/agents/agent.js
CHANGED
|
@@ -51,6 +51,7 @@ const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
|
|
|
51
51
|
const nunjucks_1 = __importDefault(require("nunjucks"));
|
|
52
52
|
const zod_1 = require("zod");
|
|
53
53
|
const agent_utils_js_1 = require("../utils/agent-utils.js");
|
|
54
|
+
const json_schema_js_1 = require("../utils/json-schema.js");
|
|
54
55
|
const logger_js_1 = require("../utils/logger.js");
|
|
55
56
|
const stream_utils_js_1 = require("../utils/stream-utils.js");
|
|
56
57
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
@@ -748,7 +749,7 @@ async function agentProcessResultToObject(response) {
|
|
|
748
749
|
: response;
|
|
749
750
|
}
|
|
750
751
|
function checkAgentInputOutputSchema(schema) {
|
|
751
|
-
if (
|
|
752
|
+
if (typeof schema !== "function" && !(0, json_schema_js_1.isZodSchema)(schema)) {
|
|
752
753
|
throw new Error(`schema must be a zod object or function return a zod object, got: ${typeof schema}`);
|
|
753
754
|
}
|
|
754
755
|
}
|
|
@@ -3,6 +3,10 @@ import { type PromiseOrValue } from "../utils/type-utils.js";
|
|
|
3
3
|
import { Agent, type AgentInvokeOptions, type AgentOptions, type AgentProcessResult, type AgentResponse, type AgentResponseStream, type Message } from "./agent.js";
|
|
4
4
|
export declare class StructuredOutputError extends Error {
|
|
5
5
|
}
|
|
6
|
+
export interface ChatModelOptions extends Omit<AgentOptions<ChatModelInput, ChatModelOutput>, "inputSchema" | "outputSchema"> {
|
|
7
|
+
model?: string;
|
|
8
|
+
modelOptions?: Omit<ModelOptions, "model">;
|
|
9
|
+
}
|
|
6
10
|
/**
|
|
7
11
|
* ChatModel is an abstract base class for interacting with Large Language Models (LLMs).
|
|
8
12
|
*
|
|
@@ -27,8 +31,9 @@ export declare class StructuredOutputError extends Error {
|
|
|
27
31
|
* {@includeCode ../../test/agents/chat-model.test.ts#example-chat-model-tools}
|
|
28
32
|
*/
|
|
29
33
|
export declare abstract class ChatModel extends Agent<ChatModelInput, ChatModelOutput> {
|
|
34
|
+
options?: ChatModelOptions | undefined;
|
|
30
35
|
tag: string;
|
|
31
|
-
constructor(options?:
|
|
36
|
+
constructor(options?: ChatModelOptions | undefined);
|
|
32
37
|
get credential(): PromiseOrValue<{
|
|
33
38
|
url?: string;
|
|
34
39
|
apiKey?: string;
|
|
@@ -145,7 +150,7 @@ export interface ChatModelInput extends Message {
|
|
|
145
150
|
/**
|
|
146
151
|
* Model-specific configuration options
|
|
147
152
|
*/
|
|
148
|
-
modelOptions?:
|
|
153
|
+
modelOptions?: ModelOptions;
|
|
149
154
|
}
|
|
150
155
|
/**
|
|
151
156
|
* Message role types
|
|
@@ -578,7 +583,7 @@ export type Modality = "text" | "image" | "audio";
|
|
|
578
583
|
*
|
|
579
584
|
* Contains various parameters for controlling model behavior, such as model name, temperature, etc.
|
|
580
585
|
*/
|
|
581
|
-
export interface
|
|
586
|
+
export interface ModelOptions {
|
|
582
587
|
/**
|
|
583
588
|
* Model name or version
|
|
584
589
|
*/
|
|
@@ -604,6 +609,7 @@ export interface ChatModelOptions {
|
|
|
604
609
|
*/
|
|
605
610
|
parallelToolCalls?: boolean;
|
|
606
611
|
modalities?: Modality[];
|
|
612
|
+
preferFileInputType?: "file" | "url";
|
|
607
613
|
}
|
|
608
614
|
/**
|
|
609
615
|
* Output message format for ChatModel
|
|
@@ -76,10 +76,11 @@ exports.StructuredOutputError = StructuredOutputError;
|
|
|
76
76
|
* {@includeCode ../../test/agents/chat-model.test.ts#example-chat-model-tools}
|
|
77
77
|
*/
|
|
78
78
|
class ChatModel extends agent_js_1.Agent {
|
|
79
|
+
options;
|
|
79
80
|
tag = "ChatModelAgent";
|
|
80
81
|
constructor(options) {
|
|
81
82
|
if (options)
|
|
82
|
-
(0, type_utils_js_1.checkArguments)("ChatModel",
|
|
83
|
+
(0, type_utils_js_1.checkArguments)("ChatModel", chatModelOptionsSchema, options);
|
|
83
84
|
const retryOnError = options?.retryOnError === false
|
|
84
85
|
? false
|
|
85
86
|
: options?.retryOnError === true
|
|
@@ -94,6 +95,7 @@ class ChatModel extends agent_js_1.Agent {
|
|
|
94
95
|
outputSchema: chatModelOutputSchema,
|
|
95
96
|
retryOnError,
|
|
96
97
|
});
|
|
98
|
+
this.options = options;
|
|
97
99
|
}
|
|
98
100
|
get credential() {
|
|
99
101
|
return {};
|
|
@@ -188,6 +190,18 @@ class ChatModel extends agent_js_1.Agent {
|
|
|
188
190
|
mimeType: item.mimeType || ChatModel.getMimeType(item.filename || item.path),
|
|
189
191
|
};
|
|
190
192
|
}
|
|
193
|
+
if ((input.modelOptions?.preferFileInputType ||
|
|
194
|
+
this.options?.modelOptions?.preferFileInputType) !== "url") {
|
|
195
|
+
if (item.type === "url") {
|
|
196
|
+
return {
|
|
197
|
+
...item,
|
|
198
|
+
type: "file",
|
|
199
|
+
data: Buffer.from(await (await this.downloadFile(item.url)).arrayBuffer()).toString("base64"),
|
|
200
|
+
url: undefined,
|
|
201
|
+
mimeType: item.mimeType || ChatModel.getMimeType(item.filename || item.url),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
191
205
|
return item;
|
|
192
206
|
})),
|
|
193
207
|
};
|
|
@@ -216,14 +230,6 @@ class ChatModel extends agent_js_1.Agent {
|
|
|
216
230
|
}
|
|
217
231
|
}
|
|
218
232
|
}
|
|
219
|
-
if (input.responseFormat?.type === "json_schema" &&
|
|
220
|
-
// NOTE: Should not validate if there are tool calls
|
|
221
|
-
!output.toolCalls?.length) {
|
|
222
|
-
const ajv = new ajv_1.Ajv();
|
|
223
|
-
if (!ajv.validate(input.responseFormat.jsonSchema.schema, output.json)) {
|
|
224
|
-
throw new StructuredOutputError(`Output JSON does not conform to the provided JSON schema: ${ajv.errorsText()}`);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
233
|
super.postprocess(input, output, options);
|
|
228
234
|
const { usage } = output;
|
|
229
235
|
if (usage) {
|
|
@@ -241,6 +247,16 @@ class ChatModel extends agent_js_1.Agent {
|
|
|
241
247
|
files: await Promise.all(files.map((file) => this.transformFileOutput(input, file, options))),
|
|
242
248
|
};
|
|
243
249
|
}
|
|
250
|
+
// Remove fields with `null` value for validation
|
|
251
|
+
output = (0, type_utils_js_1.omitByDeep)(output, (value) => (0, type_utils_js_1.isNil)(value));
|
|
252
|
+
if (input.responseFormat?.type === "json_schema" &&
|
|
253
|
+
// NOTE: Should not validate if there are tool calls
|
|
254
|
+
!output.toolCalls?.length) {
|
|
255
|
+
const ajv = new ajv_1.Ajv();
|
|
256
|
+
if (!ajv.validate(input.responseFormat.jsonSchema.schema, output.json)) {
|
|
257
|
+
throw new StructuredOutputError(`Output JSON does not conform to the provided JSON schema: ${ajv.errorsText()}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
244
260
|
return super.processAgentOutput(input, output, options);
|
|
245
261
|
}
|
|
246
262
|
async transformFileOutput(input, data, options) {
|
|
@@ -377,7 +393,7 @@ const chatModelInputToolChoiceSchema = zod_1.z.union([
|
|
|
377
393
|
zod_1.z.literal("required"),
|
|
378
394
|
chatModelInputToolSchema,
|
|
379
395
|
]);
|
|
380
|
-
const
|
|
396
|
+
const modelOptionsSchema = zod_1.z.object({
|
|
381
397
|
model: zod_1.z.string().optional(),
|
|
382
398
|
temperature: zod_1.z.number().optional(),
|
|
383
399
|
topP: zod_1.z.number().optional(),
|
|
@@ -386,12 +402,16 @@ const chatModelOptionsSchema = zod_1.z.object({
|
|
|
386
402
|
parallelToolCalls: zod_1.z.boolean().optional().default(true),
|
|
387
403
|
modalities: zod_1.z.array(zod_1.z.enum(["text", "image", "audio"])).optional(),
|
|
388
404
|
});
|
|
405
|
+
const chatModelOptionsSchema = agent_js_1.agentOptionsSchema.extend({
|
|
406
|
+
model: zod_1.z.string().optional(),
|
|
407
|
+
modelOptions: modelOptionsSchema.optional(),
|
|
408
|
+
});
|
|
389
409
|
const chatModelInputSchema = zod_1.z.object({
|
|
390
410
|
messages: zod_1.z.array(chatModelInputMessageSchema),
|
|
391
411
|
responseFormat: chatModelInputResponseFormatSchema.optional(),
|
|
392
412
|
tools: zod_1.z.array(chatModelInputToolSchema).optional(),
|
|
393
413
|
toolChoice: chatModelInputToolChoiceSchema.optional(),
|
|
394
|
-
modelOptions:
|
|
414
|
+
modelOptions: modelOptionsSchema.optional(),
|
|
395
415
|
});
|
|
396
416
|
var FileOutputType;
|
|
397
417
|
(function (FileOutputType) {
|
|
@@ -32,14 +32,14 @@ export declare const imageModelInputSchema: z.ZodObject<{
|
|
|
32
32
|
}, "strip", z.ZodTypeAny, {
|
|
33
33
|
prompt: string;
|
|
34
34
|
model?: string | undefined;
|
|
35
|
-
responseFormat?: "base64" | "url" | undefined;
|
|
36
35
|
image?: string | string[] | undefined;
|
|
36
|
+
responseFormat?: "base64" | "url" | undefined;
|
|
37
37
|
n?: number | undefined;
|
|
38
38
|
}, {
|
|
39
39
|
prompt: string;
|
|
40
40
|
model?: string | undefined;
|
|
41
|
-
responseFormat?: "base64" | "url" | undefined;
|
|
42
41
|
image?: string | string[] | undefined;
|
|
42
|
+
responseFormat?: "base64" | "url" | undefined;
|
|
43
43
|
n?: number | undefined;
|
|
44
44
|
}>;
|
|
45
45
|
export interface ImageModelOutput extends Message {
|
|
@@ -59,7 +59,9 @@ async function parseAgentFile(path, data) {
|
|
|
59
59
|
])
|
|
60
60
|
.transform((v) => typeof v === "string"
|
|
61
61
|
? { content: v, path }
|
|
62
|
-
: Promise.resolve(index_js_1.nodejs.path.
|
|
62
|
+
: Promise.resolve(index_js_1.nodejs.path.isAbsolute(v.url)
|
|
63
|
+
? v.url
|
|
64
|
+
: index_js_1.nodejs.path.join(index_js_1.nodejs.path.dirname(path), v.url)).then((path) => index_js_1.nodejs.fs.readFile(path, "utf8").then((content) => ({ content, path }))));
|
|
63
65
|
return (0, schema_js_1.camelizeSchema)(zod_1.z.discriminatedUnion("type", [
|
|
64
66
|
zod_1.z
|
|
65
67
|
.object({
|
|
@@ -68,6 +70,7 @@ async function parseAgentFile(path, data) {
|
|
|
68
70
|
inputKey: (0, schema_js_1.optionalize)(zod_1.z.string()),
|
|
69
71
|
outputKey: (0, schema_js_1.optionalize)(zod_1.z.string()),
|
|
70
72
|
toolChoice: (0, schema_js_1.optionalize)(zod_1.z.nativeEnum(ai_agent_js_1.AIAgentToolChoice)),
|
|
73
|
+
structuredStreamMode: (0, schema_js_1.optionalize)(zod_1.z.boolean()),
|
|
71
74
|
})
|
|
72
75
|
.extend(baseAgentSchema.shape),
|
|
73
76
|
zod_1.z
|
|
@@ -10,3 +10,4 @@ export declare function parseJSON(json: string): any;
|
|
|
10
10
|
* @returns The union array with at least 1 item (but the type is at least 2 items for z.union)
|
|
11
11
|
*/
|
|
12
12
|
export declare function ensureZodUnionArray<T extends z.ZodType>(union: T[]): [T, T, ...T[]];
|
|
13
|
+
export declare function isZodSchema(schema: ZodType): schema is ZodType;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.outputSchemaToResponseFormatSchema = outputSchemaToResponseFormatSchema;
|
|
4
4
|
exports.parseJSON = parseJSON;
|
|
5
5
|
exports.ensureZodUnionArray = ensureZodUnionArray;
|
|
6
|
+
exports.isZodSchema = isZodSchema;
|
|
6
7
|
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
7
8
|
const logger_js_1 = require("./logger.js");
|
|
8
9
|
function outputSchemaToResponseFormatSchema(agentOutput) {
|
|
@@ -45,3 +46,8 @@ function ensureZodUnionArray(union) {
|
|
|
45
46
|
}
|
|
46
47
|
return union;
|
|
47
48
|
}
|
|
49
|
+
function isZodSchema(schema) {
|
|
50
|
+
if (!schema || typeof schema !== "object")
|
|
51
|
+
return false;
|
|
52
|
+
return typeof schema.parse === "function" && typeof schema.safeParse === "function";
|
|
53
|
+
}
|
|
@@ -19,6 +19,7 @@ export declare function pick<T extends object, K extends keyof T>(obj: T, ...key
|
|
|
19
19
|
export declare function omit<T extends object, K extends keyof T>(obj: T, ...keys: (K | K[])[]): Omit<T, K>;
|
|
20
20
|
export declare function omitDeep<T, K>(obj: T, ...keys: (K | K[])[]): unknown;
|
|
21
21
|
export declare function omitBy<T extends object, K extends keyof T>(obj: T, predicate: (value: T[K], key: K) => boolean): Partial<T>;
|
|
22
|
+
export declare function omitByDeep(obj: any, predicate: (value: any, key: any) => boolean): any;
|
|
22
23
|
export declare function flat<T>(...value: (T | T[])[]): NonNullable<T>[];
|
|
23
24
|
export declare function createAccessorArray<T>(array: T[], accessor: (array: T[], name: string) => T | undefined): T[] & {
|
|
24
25
|
[key: string]: T;
|
|
@@ -12,6 +12,7 @@ exports.pick = pick;
|
|
|
12
12
|
exports.omit = omit;
|
|
13
13
|
exports.omitDeep = omitDeep;
|
|
14
14
|
exports.omitBy = omitBy;
|
|
15
|
+
exports.omitByDeep = omitByDeep;
|
|
15
16
|
exports.flat = flat;
|
|
16
17
|
exports.createAccessorArray = createAccessorArray;
|
|
17
18
|
exports.checkArguments = checkArguments;
|
|
@@ -102,6 +103,24 @@ function omitBy(obj, predicate) {
|
|
|
102
103
|
return !predicate(value, k);
|
|
103
104
|
}));
|
|
104
105
|
}
|
|
106
|
+
function omitByDeep(obj, predicate) {
|
|
107
|
+
if (obj === null || obj === undefined)
|
|
108
|
+
return obj;
|
|
109
|
+
if (Array.isArray(obj)) {
|
|
110
|
+
return obj.map((item) => omitByDeep(item, predicate));
|
|
111
|
+
}
|
|
112
|
+
if (typeof obj === "object") {
|
|
113
|
+
const result = {};
|
|
114
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
115
|
+
const newValue = omitByDeep(value, predicate);
|
|
116
|
+
if (!predicate(newValue, key)) {
|
|
117
|
+
result[key] = newValue;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
return obj;
|
|
123
|
+
}
|
|
105
124
|
function flat(...value) {
|
|
106
125
|
return value.flat().filter(isNonNullable);
|
|
107
126
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
2
2
|
import type * as prompts from "@inquirer/prompts";
|
|
3
|
-
import { ZodObject, type ZodType } from "zod";
|
|
3
|
+
import { type ZodObject, type ZodType } from "zod";
|
|
4
4
|
import type { AgentEvent, Context, UserContext } from "../aigne/context.js";
|
|
5
5
|
import type { MessagePayload } from "../aigne/message-queue.js";
|
|
6
6
|
import type { ContextUsage } from "../aigne/usage.js";
|
|
@@ -3,6 +3,10 @@ import { type PromiseOrValue } from "../utils/type-utils.js";
|
|
|
3
3
|
import { Agent, type AgentInvokeOptions, type AgentOptions, type AgentProcessResult, type AgentResponse, type AgentResponseStream, type Message } from "./agent.js";
|
|
4
4
|
export declare class StructuredOutputError extends Error {
|
|
5
5
|
}
|
|
6
|
+
export interface ChatModelOptions extends Omit<AgentOptions<ChatModelInput, ChatModelOutput>, "inputSchema" | "outputSchema"> {
|
|
7
|
+
model?: string;
|
|
8
|
+
modelOptions?: Omit<ModelOptions, "model">;
|
|
9
|
+
}
|
|
6
10
|
/**
|
|
7
11
|
* ChatModel is an abstract base class for interacting with Large Language Models (LLMs).
|
|
8
12
|
*
|
|
@@ -27,8 +31,9 @@ export declare class StructuredOutputError extends Error {
|
|
|
27
31
|
* {@includeCode ../../test/agents/chat-model.test.ts#example-chat-model-tools}
|
|
28
32
|
*/
|
|
29
33
|
export declare abstract class ChatModel extends Agent<ChatModelInput, ChatModelOutput> {
|
|
34
|
+
options?: ChatModelOptions | undefined;
|
|
30
35
|
tag: string;
|
|
31
|
-
constructor(options?:
|
|
36
|
+
constructor(options?: ChatModelOptions | undefined);
|
|
32
37
|
get credential(): PromiseOrValue<{
|
|
33
38
|
url?: string;
|
|
34
39
|
apiKey?: string;
|
|
@@ -145,7 +150,7 @@ export interface ChatModelInput extends Message {
|
|
|
145
150
|
/**
|
|
146
151
|
* Model-specific configuration options
|
|
147
152
|
*/
|
|
148
|
-
modelOptions?:
|
|
153
|
+
modelOptions?: ModelOptions;
|
|
149
154
|
}
|
|
150
155
|
/**
|
|
151
156
|
* Message role types
|
|
@@ -578,7 +583,7 @@ export type Modality = "text" | "image" | "audio";
|
|
|
578
583
|
*
|
|
579
584
|
* Contains various parameters for controlling model behavior, such as model name, temperature, etc.
|
|
580
585
|
*/
|
|
581
|
-
export interface
|
|
586
|
+
export interface ModelOptions {
|
|
582
587
|
/**
|
|
583
588
|
* Model name or version
|
|
584
589
|
*/
|
|
@@ -604,6 +609,7 @@ export interface ChatModelOptions {
|
|
|
604
609
|
*/
|
|
605
610
|
parallelToolCalls?: boolean;
|
|
606
611
|
modalities?: Modality[];
|
|
612
|
+
preferFileInputType?: "file" | "url";
|
|
607
613
|
}
|
|
608
614
|
/**
|
|
609
615
|
* Output message format for ChatModel
|
|
@@ -32,14 +32,14 @@ export declare const imageModelInputSchema: z.ZodObject<{
|
|
|
32
32
|
}, "strip", z.ZodTypeAny, {
|
|
33
33
|
prompt: string;
|
|
34
34
|
model?: string | undefined;
|
|
35
|
-
responseFormat?: "base64" | "url" | undefined;
|
|
36
35
|
image?: string | string[] | undefined;
|
|
36
|
+
responseFormat?: "base64" | "url" | undefined;
|
|
37
37
|
n?: number | undefined;
|
|
38
38
|
}, {
|
|
39
39
|
prompt: string;
|
|
40
40
|
model?: string | undefined;
|
|
41
|
-
responseFormat?: "base64" | "url" | undefined;
|
|
42
41
|
image?: string | string[] | undefined;
|
|
42
|
+
responseFormat?: "base64" | "url" | undefined;
|
|
43
43
|
n?: number | undefined;
|
|
44
44
|
}>;
|
|
45
45
|
export interface ImageModelOutput extends Message {
|
|
@@ -10,3 +10,4 @@ export declare function parseJSON(json: string): any;
|
|
|
10
10
|
* @returns The union array with at least 1 item (but the type is at least 2 items for z.union)
|
|
11
11
|
*/
|
|
12
12
|
export declare function ensureZodUnionArray<T extends z.ZodType>(union: T[]): [T, T, ...T[]];
|
|
13
|
+
export declare function isZodSchema(schema: ZodType): schema is ZodType;
|
|
@@ -19,6 +19,7 @@ export declare function pick<T extends object, K extends keyof T>(obj: T, ...key
|
|
|
19
19
|
export declare function omit<T extends object, K extends keyof T>(obj: T, ...keys: (K | K[])[]): Omit<T, K>;
|
|
20
20
|
export declare function omitDeep<T, K>(obj: T, ...keys: (K | K[])[]): unknown;
|
|
21
21
|
export declare function omitBy<T extends object, K extends keyof T>(obj: T, predicate: (value: T[K], key: K) => boolean): Partial<T>;
|
|
22
|
+
export declare function omitByDeep(obj: any, predicate: (value: any, key: any) => boolean): any;
|
|
22
23
|
export declare function flat<T>(...value: (T | T[])[]): NonNullable<T>[];
|
|
23
24
|
export declare function createAccessorArray<T>(array: T[], accessor: (array: T[], name: string) => T | undefined): T[] & {
|
|
24
25
|
[key: string]: T;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
2
2
|
import type * as prompts from "@inquirer/prompts";
|
|
3
|
-
import { ZodObject, type ZodType } from "zod";
|
|
3
|
+
import { type ZodObject, type ZodType } from "zod";
|
|
4
4
|
import type { AgentEvent, Context, UserContext } from "../aigne/context.js";
|
|
5
5
|
import type { MessagePayload } from "../aigne/message-queue.js";
|
|
6
6
|
import type { ContextUsage } from "../aigne/usage.js";
|
package/lib/esm/agents/agent.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
2
2
|
import equal from "fast-deep-equal";
|
|
3
3
|
import nunjucks from "nunjucks";
|
|
4
|
-
import {
|
|
4
|
+
import { z } from "zod";
|
|
5
5
|
import { sortHooks } from "../utils/agent-utils.js";
|
|
6
|
+
import { isZodSchema } from "../utils/json-schema.js";
|
|
6
7
|
import { logger } from "../utils/logger.js";
|
|
7
8
|
import { agentResponseStreamToObject, asyncGeneratorToReadableStream, isAsyncGenerator, mergeAgentResponseChunk, objectToAgentResponseStream, onAgentResponseStreamEnd, } from "../utils/stream-utils.js";
|
|
8
9
|
import { checkArguments, createAccessorArray, flat, isEmpty, isNil, isNonNullable, isRecord, } from "../utils/type-utils.js";
|
|
@@ -699,7 +700,7 @@ export async function agentProcessResultToObject(response) {
|
|
|
699
700
|
: response;
|
|
700
701
|
}
|
|
701
702
|
function checkAgentInputOutputSchema(schema) {
|
|
702
|
-
if (
|
|
703
|
+
if (typeof schema !== "function" && !isZodSchema(schema)) {
|
|
703
704
|
throw new Error(`schema must be a zod object or function return a zod object, got: ${typeof schema}`);
|
|
704
705
|
}
|
|
705
706
|
}
|
|
@@ -3,6 +3,10 @@ import { type PromiseOrValue } from "../utils/type-utils.js";
|
|
|
3
3
|
import { Agent, type AgentInvokeOptions, type AgentOptions, type AgentProcessResult, type AgentResponse, type AgentResponseStream, type Message } from "./agent.js";
|
|
4
4
|
export declare class StructuredOutputError extends Error {
|
|
5
5
|
}
|
|
6
|
+
export interface ChatModelOptions extends Omit<AgentOptions<ChatModelInput, ChatModelOutput>, "inputSchema" | "outputSchema"> {
|
|
7
|
+
model?: string;
|
|
8
|
+
modelOptions?: Omit<ModelOptions, "model">;
|
|
9
|
+
}
|
|
6
10
|
/**
|
|
7
11
|
* ChatModel is an abstract base class for interacting with Large Language Models (LLMs).
|
|
8
12
|
*
|
|
@@ -27,8 +31,9 @@ export declare class StructuredOutputError extends Error {
|
|
|
27
31
|
* {@includeCode ../../test/agents/chat-model.test.ts#example-chat-model-tools}
|
|
28
32
|
*/
|
|
29
33
|
export declare abstract class ChatModel extends Agent<ChatModelInput, ChatModelOutput> {
|
|
34
|
+
options?: ChatModelOptions | undefined;
|
|
30
35
|
tag: string;
|
|
31
|
-
constructor(options?:
|
|
36
|
+
constructor(options?: ChatModelOptions | undefined);
|
|
32
37
|
get credential(): PromiseOrValue<{
|
|
33
38
|
url?: string;
|
|
34
39
|
apiKey?: string;
|
|
@@ -145,7 +150,7 @@ export interface ChatModelInput extends Message {
|
|
|
145
150
|
/**
|
|
146
151
|
* Model-specific configuration options
|
|
147
152
|
*/
|
|
148
|
-
modelOptions?:
|
|
153
|
+
modelOptions?: ModelOptions;
|
|
149
154
|
}
|
|
150
155
|
/**
|
|
151
156
|
* Message role types
|
|
@@ -578,7 +583,7 @@ export type Modality = "text" | "image" | "audio";
|
|
|
578
583
|
*
|
|
579
584
|
* Contains various parameters for controlling model behavior, such as model name, temperature, etc.
|
|
580
585
|
*/
|
|
581
|
-
export interface
|
|
586
|
+
export interface ModelOptions {
|
|
582
587
|
/**
|
|
583
588
|
* Model name or version
|
|
584
589
|
*/
|
|
@@ -604,6 +609,7 @@ export interface ChatModelOptions {
|
|
|
604
609
|
*/
|
|
605
610
|
parallelToolCalls?: boolean;
|
|
606
611
|
modalities?: Modality[];
|
|
612
|
+
preferFileInputType?: "file" | "url";
|
|
607
613
|
}
|
|
608
614
|
/**
|
|
609
615
|
* Output message format for ChatModel
|
|
@@ -4,7 +4,7 @@ import mime from "mime";
|
|
|
4
4
|
import { v7 } from "uuid";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { optionalize } from "../loader/schema.js";
|
|
7
|
-
import { checkArguments, pick } from "../utils/type-utils.js";
|
|
7
|
+
import { checkArguments, isNil, omitByDeep, pick, } from "../utils/type-utils.js";
|
|
8
8
|
import { Agent, agentOptionsSchema, } from "./agent.js";
|
|
9
9
|
const CHAT_MODEL_DEFAULT_RETRY_OPTIONS = {
|
|
10
10
|
retries: 3,
|
|
@@ -36,10 +36,11 @@ export class StructuredOutputError extends Error {
|
|
|
36
36
|
* {@includeCode ../../test/agents/chat-model.test.ts#example-chat-model-tools}
|
|
37
37
|
*/
|
|
38
38
|
export class ChatModel extends Agent {
|
|
39
|
+
options;
|
|
39
40
|
tag = "ChatModelAgent";
|
|
40
41
|
constructor(options) {
|
|
41
42
|
if (options)
|
|
42
|
-
checkArguments("ChatModel",
|
|
43
|
+
checkArguments("ChatModel", chatModelOptionsSchema, options);
|
|
43
44
|
const retryOnError = options?.retryOnError === false
|
|
44
45
|
? false
|
|
45
46
|
: options?.retryOnError === true
|
|
@@ -54,6 +55,7 @@ export class ChatModel extends Agent {
|
|
|
54
55
|
outputSchema: chatModelOutputSchema,
|
|
55
56
|
retryOnError,
|
|
56
57
|
});
|
|
58
|
+
this.options = options;
|
|
57
59
|
}
|
|
58
60
|
get credential() {
|
|
59
61
|
return {};
|
|
@@ -148,6 +150,18 @@ export class ChatModel extends Agent {
|
|
|
148
150
|
mimeType: item.mimeType || ChatModel.getMimeType(item.filename || item.path),
|
|
149
151
|
};
|
|
150
152
|
}
|
|
153
|
+
if ((input.modelOptions?.preferFileInputType ||
|
|
154
|
+
this.options?.modelOptions?.preferFileInputType) !== "url") {
|
|
155
|
+
if (item.type === "url") {
|
|
156
|
+
return {
|
|
157
|
+
...item,
|
|
158
|
+
type: "file",
|
|
159
|
+
data: Buffer.from(await (await this.downloadFile(item.url)).arrayBuffer()).toString("base64"),
|
|
160
|
+
url: undefined,
|
|
161
|
+
mimeType: item.mimeType || ChatModel.getMimeType(item.filename || item.url),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
151
165
|
return item;
|
|
152
166
|
})),
|
|
153
167
|
};
|
|
@@ -176,14 +190,6 @@ export class ChatModel extends Agent {
|
|
|
176
190
|
}
|
|
177
191
|
}
|
|
178
192
|
}
|
|
179
|
-
if (input.responseFormat?.type === "json_schema" &&
|
|
180
|
-
// NOTE: Should not validate if there are tool calls
|
|
181
|
-
!output.toolCalls?.length) {
|
|
182
|
-
const ajv = new Ajv();
|
|
183
|
-
if (!ajv.validate(input.responseFormat.jsonSchema.schema, output.json)) {
|
|
184
|
-
throw new StructuredOutputError(`Output JSON does not conform to the provided JSON schema: ${ajv.errorsText()}`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
193
|
super.postprocess(input, output, options);
|
|
188
194
|
const { usage } = output;
|
|
189
195
|
if (usage) {
|
|
@@ -201,6 +207,16 @@ export class ChatModel extends Agent {
|
|
|
201
207
|
files: await Promise.all(files.map((file) => this.transformFileOutput(input, file, options))),
|
|
202
208
|
};
|
|
203
209
|
}
|
|
210
|
+
// Remove fields with `null` value for validation
|
|
211
|
+
output = omitByDeep(output, (value) => isNil(value));
|
|
212
|
+
if (input.responseFormat?.type === "json_schema" &&
|
|
213
|
+
// NOTE: Should not validate if there are tool calls
|
|
214
|
+
!output.toolCalls?.length) {
|
|
215
|
+
const ajv = new Ajv();
|
|
216
|
+
if (!ajv.validate(input.responseFormat.jsonSchema.schema, output.json)) {
|
|
217
|
+
throw new StructuredOutputError(`Output JSON does not conform to the provided JSON schema: ${ajv.errorsText()}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
204
220
|
return super.processAgentOutput(input, output, options);
|
|
205
221
|
}
|
|
206
222
|
async transformFileOutput(input, data, options) {
|
|
@@ -336,7 +352,7 @@ const chatModelInputToolChoiceSchema = z.union([
|
|
|
336
352
|
z.literal("required"),
|
|
337
353
|
chatModelInputToolSchema,
|
|
338
354
|
]);
|
|
339
|
-
const
|
|
355
|
+
const modelOptionsSchema = z.object({
|
|
340
356
|
model: z.string().optional(),
|
|
341
357
|
temperature: z.number().optional(),
|
|
342
358
|
topP: z.number().optional(),
|
|
@@ -345,12 +361,16 @@ const chatModelOptionsSchema = z.object({
|
|
|
345
361
|
parallelToolCalls: z.boolean().optional().default(true),
|
|
346
362
|
modalities: z.array(z.enum(["text", "image", "audio"])).optional(),
|
|
347
363
|
});
|
|
364
|
+
const chatModelOptionsSchema = agentOptionsSchema.extend({
|
|
365
|
+
model: z.string().optional(),
|
|
366
|
+
modelOptions: modelOptionsSchema.optional(),
|
|
367
|
+
});
|
|
348
368
|
const chatModelInputSchema = z.object({
|
|
349
369
|
messages: z.array(chatModelInputMessageSchema),
|
|
350
370
|
responseFormat: chatModelInputResponseFormatSchema.optional(),
|
|
351
371
|
tools: z.array(chatModelInputToolSchema).optional(),
|
|
352
372
|
toolChoice: chatModelInputToolChoiceSchema.optional(),
|
|
353
|
-
modelOptions:
|
|
373
|
+
modelOptions: modelOptionsSchema.optional(),
|
|
354
374
|
});
|
|
355
375
|
export var FileOutputType;
|
|
356
376
|
(function (FileOutputType) {
|
|
@@ -32,14 +32,14 @@ export declare const imageModelInputSchema: z.ZodObject<{
|
|
|
32
32
|
}, "strip", z.ZodTypeAny, {
|
|
33
33
|
prompt: string;
|
|
34
34
|
model?: string | undefined;
|
|
35
|
-
responseFormat?: "base64" | "url" | undefined;
|
|
36
35
|
image?: string | string[] | undefined;
|
|
36
|
+
responseFormat?: "base64" | "url" | undefined;
|
|
37
37
|
n?: number | undefined;
|
|
38
38
|
}, {
|
|
39
39
|
prompt: string;
|
|
40
40
|
model?: string | undefined;
|
|
41
|
-
responseFormat?: "base64" | "url" | undefined;
|
|
42
41
|
image?: string | string[] | undefined;
|
|
42
|
+
responseFormat?: "base64" | "url" | undefined;
|
|
43
43
|
n?: number | undefined;
|
|
44
44
|
}>;
|
|
45
45
|
export interface ImageModelOutput extends Message {
|
|
@@ -55,7 +55,9 @@ export async function parseAgentFile(path, data) {
|
|
|
55
55
|
])
|
|
56
56
|
.transform((v) => typeof v === "string"
|
|
57
57
|
? { content: v, path }
|
|
58
|
-
: Promise.resolve(nodejs.path.
|
|
58
|
+
: Promise.resolve(nodejs.path.isAbsolute(v.url)
|
|
59
|
+
? v.url
|
|
60
|
+
: nodejs.path.join(nodejs.path.dirname(path), v.url)).then((path) => nodejs.fs.readFile(path, "utf8").then((content) => ({ content, path }))));
|
|
59
61
|
return camelizeSchema(z.discriminatedUnion("type", [
|
|
60
62
|
z
|
|
61
63
|
.object({
|
|
@@ -64,6 +66,7 @@ export async function parseAgentFile(path, data) {
|
|
|
64
66
|
inputKey: optionalize(z.string()),
|
|
65
67
|
outputKey: optionalize(z.string()),
|
|
66
68
|
toolChoice: optionalize(z.nativeEnum(AIAgentToolChoice)),
|
|
69
|
+
structuredStreamMode: optionalize(z.boolean()),
|
|
67
70
|
})
|
|
68
71
|
.extend(baseAgentSchema.shape),
|
|
69
72
|
z
|
|
@@ -10,3 +10,4 @@ export declare function parseJSON(json: string): any;
|
|
|
10
10
|
* @returns The union array with at least 1 item (but the type is at least 2 items for z.union)
|
|
11
11
|
*/
|
|
12
12
|
export declare function ensureZodUnionArray<T extends z.ZodType>(union: T[]): [T, T, ...T[]];
|
|
13
|
+
export declare function isZodSchema(schema: ZodType): schema is ZodType;
|
|
@@ -40,3 +40,8 @@ export function ensureZodUnionArray(union) {
|
|
|
40
40
|
}
|
|
41
41
|
return union;
|
|
42
42
|
}
|
|
43
|
+
export function isZodSchema(schema) {
|
|
44
|
+
if (!schema || typeof schema !== "object")
|
|
45
|
+
return false;
|
|
46
|
+
return typeof schema.parse === "function" && typeof schema.safeParse === "function";
|
|
47
|
+
}
|
|
@@ -19,6 +19,7 @@ export declare function pick<T extends object, K extends keyof T>(obj: T, ...key
|
|
|
19
19
|
export declare function omit<T extends object, K extends keyof T>(obj: T, ...keys: (K | K[])[]): Omit<T, K>;
|
|
20
20
|
export declare function omitDeep<T, K>(obj: T, ...keys: (K | K[])[]): unknown;
|
|
21
21
|
export declare function omitBy<T extends object, K extends keyof T>(obj: T, predicate: (value: T[K], key: K) => boolean): Partial<T>;
|
|
22
|
+
export declare function omitByDeep(obj: any, predicate: (value: any, key: any) => boolean): any;
|
|
22
23
|
export declare function flat<T>(...value: (T | T[])[]): NonNullable<T>[];
|
|
23
24
|
export declare function createAccessorArray<T>(array: T[], accessor: (array: T[], name: string) => T | undefined): T[] & {
|
|
24
25
|
[key: string]: T;
|
|
@@ -84,6 +84,24 @@ export function omitBy(obj, predicate) {
|
|
|
84
84
|
return !predicate(value, k);
|
|
85
85
|
}));
|
|
86
86
|
}
|
|
87
|
+
export function omitByDeep(obj, predicate) {
|
|
88
|
+
if (obj === null || obj === undefined)
|
|
89
|
+
return obj;
|
|
90
|
+
if (Array.isArray(obj)) {
|
|
91
|
+
return obj.map((item) => omitByDeep(item, predicate));
|
|
92
|
+
}
|
|
93
|
+
if (typeof obj === "object") {
|
|
94
|
+
const result = {};
|
|
95
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
96
|
+
const newValue = omitByDeep(value, predicate);
|
|
97
|
+
if (!predicate(newValue, key)) {
|
|
98
|
+
result[key] = newValue;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
return obj;
|
|
104
|
+
}
|
|
87
105
|
export function flat(...value) {
|
|
88
106
|
return value.flat().filter(isNonNullable);
|
|
89
107
|
}
|