@aigne/core 1.58.2 → 1.58.3

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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.58.3](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.58.2...core-v1.58.3) (2025-09-08)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * 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))
9
+ * 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))
10
+
3
11
  ## [1.58.2](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.58.1...core-v1.58.2) (2025-09-05)
4
12
 
5
13
 
@@ -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";
@@ -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 (!(schema instanceof zod_1.ZodObject) && typeof schema !== "function") {
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
  }
@@ -216,14 +216,6 @@ class ChatModel extends agent_js_1.Agent {
216
216
  }
217
217
  }
218
218
  }
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
219
  super.postprocess(input, output, options);
228
220
  const { usage } = output;
229
221
  if (usage) {
@@ -241,6 +233,16 @@ class ChatModel extends agent_js_1.Agent {
241
233
  files: await Promise.all(files.map((file) => this.transformFileOutput(input, file, options))),
242
234
  };
243
235
  }
236
+ // Remove fields with `null` value for validation
237
+ output = (0, type_utils_js_1.omitByDeep)(output, (value) => (0, type_utils_js_1.isNil)(value));
238
+ if (input.responseFormat?.type === "json_schema" &&
239
+ // NOTE: Should not validate if there are tool calls
240
+ !output.toolCalls?.length) {
241
+ const ajv = new ajv_1.Ajv();
242
+ if (!ajv.validate(input.responseFormat.jsonSchema.schema, output.json)) {
243
+ throw new StructuredOutputError(`Output JSON does not conform to the provided JSON schema: ${ajv.errorsText()}`);
244
+ }
245
+ }
244
246
  return super.processAgentOutput(input, output, options);
245
247
  }
246
248
  async transformFileOutput(input, data, options) {
@@ -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.join(index_js_1.nodejs.path.dirname(path), v.url)).then((path) => index_js_1.nodejs.fs.readFile(path, "utf8").then((content) => ({ content, 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";
@@ -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";
@@ -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 { ZodObject, z } from "zod";
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 (!(schema instanceof ZodObject) && typeof schema !== "function") {
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
  }
@@ -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,
@@ -176,14 +176,6 @@ export class ChatModel extends Agent {
176
176
  }
177
177
  }
178
178
  }
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
179
  super.postprocess(input, output, options);
188
180
  const { usage } = output;
189
181
  if (usage) {
@@ -201,6 +193,16 @@ export class ChatModel extends Agent {
201
193
  files: await Promise.all(files.map((file) => this.transformFileOutput(input, file, options))),
202
194
  };
203
195
  }
196
+ // Remove fields with `null` value for validation
197
+ output = omitByDeep(output, (value) => isNil(value));
198
+ if (input.responseFormat?.type === "json_schema" &&
199
+ // NOTE: Should not validate if there are tool calls
200
+ !output.toolCalls?.length) {
201
+ const ajv = new Ajv();
202
+ if (!ajv.validate(input.responseFormat.jsonSchema.schema, output.json)) {
203
+ throw new StructuredOutputError(`Output JSON does not conform to the provided JSON schema: ${ajv.errorsText()}`);
204
+ }
205
+ }
204
206
  return super.processAgentOutput(input, output, options);
205
207
  }
206
208
  async transformFileOutput(input, data, options) {
@@ -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.join(nodejs.path.dirname(path), v.url)).then((path) => nodejs.fs.readFile(path, "utf8").then((content) => ({ content, 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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.58.2",
3
+ "version": "1.58.3",
4
4
  "description": "The functional core of agentic AI",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -92,8 +92,8 @@
92
92
  "yaml": "^2.8.0",
93
93
  "zod": "^3.25.67",
94
94
  "zod-to-json-schema": "^3.24.6",
95
- "@aigne/observability-api": "^0.10.2",
96
- "@aigne/platform-helpers": "^0.6.2"
95
+ "@aigne/platform-helpers": "^0.6.2",
96
+ "@aigne/observability-api": "^0.10.2"
97
97
  },
98
98
  "devDependencies": {
99
99
  "@types/bun": "^1.2.18",