@aigne/core 1.63.0-beta → 1.63.0-beta.2

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,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.63.0-beta.2](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.63.0-beta.1...core-v1.63.0-beta.2) (2025-10-09)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * input schema of AI agent should includes input key and input file key ([#600](https://github.com/AIGNE-io/aigne-framework/issues/600)) ([b4ca076](https://github.com/AIGNE-io/aigne-framework/commit/b4ca076d6b4a1a1ecb8d4ebb008abd0d7561aadd))
9
+
10
+ ## [1.63.0-beta.1](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.63.0-beta...core-v1.63.0-beta.1) (2025-10-09)
11
+
12
+
13
+ ### Features
14
+
15
+ * **core:** add `toolCallsConcurrency` support for AI agent ([#598](https://github.com/AIGNE-io/aigne-framework/issues/598)) ([84df406](https://github.com/AIGNE-io/aigne-framework/commit/84df406bfa9e3bdf159509f4b9cf2301ec80b155))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **core:** add input_file_key support for agent yaml ([#597](https://github.com/AIGNE-io/aigne-framework/issues/597)) ([63414a3](https://github.com/AIGNE-io/aigne-framework/commit/63414a3d46c74c686e7f033c224ca6175bea8c3f))
21
+
3
22
  ## [1.63.0-beta](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.62.0...core-v1.63.0-beta) (2025-10-07)
4
23
 
5
24
 
@@ -3,7 +3,7 @@ import { PromptBuilder } from "../prompt/prompt-builder.js";
3
3
  import { Agent, type AgentInvokeOptions, type AgentOptions, type AgentProcessAsyncGenerator, type AgentProcessResult, type Message } from "./agent.js";
4
4
  import type { ChatModel, ChatModelInput } from "./chat-model.js";
5
5
  import type { GuideRailAgentOutput } from "./guide-rail-agent.js";
6
- import type { FileType } from "./model.js";
6
+ import { type FileType } from "./model.js";
7
7
  export declare const DEFAULT_OUTPUT_KEY = "message";
8
8
  export declare const DEFAULT_OUTPUT_FILE_KEY = "files";
9
9
  /**
@@ -42,6 +42,12 @@ export interface AIAgentOptions<I extends Message = Message, O extends Message =
42
42
  * @default AIAgentToolChoice.auto
43
43
  */
44
44
  toolChoice?: AIAgentToolChoice | Agent;
45
+ /**
46
+ * Maximum number of tool calls to execute concurrently
47
+ *
48
+ * @default 1
49
+ */
50
+ toolCallsConcurrency?: number;
45
51
  /**
46
52
  * Whether to preserve text generated during tool usage in the final output
47
53
  */
@@ -237,6 +243,12 @@ export declare class AIAgent<I extends Message = any, O extends Message = any> e
237
243
  * {@includeCode ../../test/agents/ai-agent.test.ts#example-ai-agent-router}
238
244
  */
239
245
  toolChoice?: AIAgentToolChoice | Agent;
246
+ /**
247
+ * Maximum number of tool calls to execute concurrently
248
+ *
249
+ * @default 1
250
+ */
251
+ toolCallsConcurrency?: number;
240
252
  /**
241
253
  * Whether to preserve text generated during tool usage in the final output
242
254
  */
@@ -299,6 +311,7 @@ export declare class AIAgent<I extends Message = any, O extends Message = any> e
299
311
  metadataEnd: string;
300
312
  parse: (raw: string) => object;
301
313
  };
314
+ get inputSchema(): ZodType<I>;
302
315
  /**
303
316
  * Process an input message and generate a response
304
317
  *
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.AIAgent = exports.aiAgentOptionsSchema = exports.aiAgentToolChoiceSchema = exports.AIAgentToolChoice = exports.DEFAULT_OUTPUT_FILE_KEY = exports.DEFAULT_OUTPUT_KEY = void 0;
7
+ const fastq_1 = __importDefault(require("fastq"));
4
8
  const zod_1 = require("zod");
5
9
  const prompt_builder_js_1 = require("../prompt/prompt-builder.js");
6
10
  const structured_stream_instructions_js_1 = require("../prompt/prompts/structured-stream-instructions.js");
@@ -8,6 +12,7 @@ const template_js_1 = require("../prompt/template.js");
8
12
  const structured_stream_extractor_js_1 = require("../utils/structured-stream-extractor.js");
9
13
  const type_utils_js_1 = require("../utils/type-utils.js");
10
14
  const agent_js_1 = require("./agent.js");
15
+ const model_js_1 = require("./model.js");
11
16
  const types_js_1 = require("./types.js");
12
17
  exports.DEFAULT_OUTPUT_KEY = "message";
13
18
  exports.DEFAULT_OUTPUT_FILE_KEY = "files";
@@ -58,6 +63,7 @@ exports.aiAgentOptionsSchema = agent_js_1.agentOptionsSchema.extend({
58
63
  inputKey: zod_1.z.string().optional(),
59
64
  outputKey: zod_1.z.string().optional(),
60
65
  toolChoice: exports.aiAgentToolChoiceSchema.optional(),
66
+ toolCallsConcurrency: zod_1.z.number().int().min(0).optional(),
61
67
  keepTextInToolUses: zod_1.z.boolean().optional(),
62
68
  memoryAgentsAsTools: zod_1.z.boolean().optional(),
63
69
  memoryPromptTemplate: zod_1.z.string().optional(),
@@ -117,6 +123,7 @@ class AIAgent extends agent_js_1.Agent {
117
123
  this.outputFileKey = options.outputFileKey || exports.DEFAULT_OUTPUT_FILE_KEY;
118
124
  this.outputFileType = options.outputFileType;
119
125
  this.toolChoice = options.toolChoice;
126
+ this.toolCallsConcurrency = options.toolCallsConcurrency || 1;
120
127
  this.keepTextInToolUses = options.keepTextInToolUses;
121
128
  this.memoryAgentsAsTools = options.memoryAgentsAsTools;
122
129
  this.memoryPromptTemplate = options.memoryPromptTemplate;
@@ -173,6 +180,12 @@ class AIAgent extends agent_js_1.Agent {
173
180
  * {@includeCode ../../test/agents/ai-agent.test.ts#example-ai-agent-router}
174
181
  */
175
182
  toolChoice;
183
+ /**
184
+ * Maximum number of tool calls to execute concurrently
185
+ *
186
+ * @default 1
187
+ */
188
+ toolCallsConcurrency;
176
189
  /**
177
190
  * Whether to preserve text generated during tool usage in the final output
178
191
  */
@@ -230,6 +243,20 @@ class AIAgent extends agent_js_1.Agent {
230
243
  * which outputs structured data in YAML format within <metadata> tags.
231
244
  */
232
245
  customStructuredStreamInstructions;
246
+ get inputSchema() {
247
+ let schema = super.inputSchema;
248
+ if (this.inputKey) {
249
+ schema = schema.extend({
250
+ [this.inputKey]: zod_1.z.string().nullish(),
251
+ });
252
+ }
253
+ if (this.inputFileKey) {
254
+ schema = schema.extend({
255
+ [this.inputFileKey]: model_js_1.fileUnionContentsSchema.nullish(),
256
+ });
257
+ }
258
+ return schema;
259
+ }
233
260
  /**
234
261
  * Process an input message and generate a response
235
262
  *
@@ -287,31 +314,43 @@ class AIAgent extends agent_js_1.Agent {
287
314
  yield { delta: { text: { [outputKey]: "\n" } } };
288
315
  }
289
316
  const executedToolCalls = [];
317
+ let error;
318
+ const queue = fastq_1.default.promise(async ({ tool, call }) => {
319
+ try {
320
+ // NOTE: should pass both arguments (model generated) and input (user provided) to the tool
321
+ const output = await this.invokeSkill(tool, { ...input, ...call.function.arguments }, options).catch((error) => {
322
+ if (!this.catchToolsError) {
323
+ return Promise.reject(error);
324
+ }
325
+ return {
326
+ isError: true,
327
+ error: {
328
+ message: error.message,
329
+ },
330
+ };
331
+ });
332
+ executedToolCalls.push({ call, output });
333
+ }
334
+ catch (e) {
335
+ error = e;
336
+ queue.killAndDrain();
337
+ }
338
+ }, this.toolCallsConcurrency || 1);
290
339
  // Execute tools
291
340
  for (const call of toolCalls) {
292
341
  const tool = toolsMap.get(call.function.name);
293
342
  if (!tool)
294
343
  throw new Error(`Tool not found: ${call.function.name}`);
295
- // NOTE: should pass both arguments (model generated) and input (user provided) to the tool
296
- const output = await this.invokeSkill(tool, { ...input, ...call.function.arguments }, options).catch((error) => {
297
- if (!this.catchToolsError) {
298
- return Promise.reject(error);
299
- }
300
- return {
301
- isError: true,
302
- error: {
303
- message: error.message,
304
- },
305
- };
306
- });
307
- // NOTE: Return transfer output immediately
308
- if ((0, types_js_1.isTransferAgentOutput)(output)) {
309
- return output;
310
- }
311
- executedToolCalls.push({ call, output });
344
+ queue.push({ tool, call });
312
345
  }
346
+ await queue.drained();
347
+ if (error)
348
+ throw error;
313
349
  // Continue LLM function calling loop if any tools were executed
314
350
  if (executedToolCalls.length) {
351
+ const transferOutput = executedToolCalls.find((i) => (0, types_js_1.isTransferAgentOutput)(i.output))?.output;
352
+ if (transferOutput)
353
+ return transferOutput;
315
354
  toolCallMessages.push(await template_js_1.AgentMessageTemplate.from(undefined, executedToolCalls.map(({ call }) => call)).format(), ...(await Promise.all(executedToolCalls.map(({ call, output }) => template_js_1.ToolMessageTemplate.from(output, call.id).format()))));
316
355
  continue;
317
356
  }
@@ -46,8 +46,10 @@ export interface AIAgentSchema extends BaseAgentSchema {
46
46
  type: "ai";
47
47
  instructions?: Instructions;
48
48
  inputKey?: string;
49
+ inputFileKey?: string;
49
50
  outputKey?: string;
50
51
  toolChoice?: AIAgentToolChoice;
52
+ toolCallsConcurrency?: number;
51
53
  keepTextInToolUses?: boolean;
52
54
  }
53
55
  export interface ImageAgentSchema extends BaseAgentSchema {
@@ -95,7 +95,10 @@ async function parseAgentFile(path, data) {
95
95
  instructions: (0, schema_js_1.optionalize)(instructionsSchema),
96
96
  inputKey: (0, schema_js_1.optionalize)(zod_1.z.string()),
97
97
  outputKey: (0, schema_js_1.optionalize)(zod_1.z.string()),
98
+ inputFileKey: (0, schema_js_1.optionalize)(zod_1.z.string()),
99
+ outputFileKey: (0, schema_js_1.optionalize)(zod_1.z.string()),
98
100
  toolChoice: (0, schema_js_1.optionalize)(zod_1.z.nativeEnum(ai_agent_js_1.AIAgentToolChoice)),
101
+ toolCallsConcurrency: (0, schema_js_1.optionalize)(zod_1.z.number().int().min(0)),
99
102
  keepTextInToolUses: (0, schema_js_1.optionalize)(zod_1.z.boolean()),
100
103
  structuredStreamMode: (0, schema_js_1.optionalize)(zod_1.z.boolean()),
101
104
  })
@@ -3,7 +3,7 @@ import { PromptBuilder } from "../prompt/prompt-builder.js";
3
3
  import { Agent, type AgentInvokeOptions, type AgentOptions, type AgentProcessAsyncGenerator, type AgentProcessResult, type Message } from "./agent.js";
4
4
  import type { ChatModel, ChatModelInput } from "./chat-model.js";
5
5
  import type { GuideRailAgentOutput } from "./guide-rail-agent.js";
6
- import type { FileType } from "./model.js";
6
+ import { type FileType } from "./model.js";
7
7
  export declare const DEFAULT_OUTPUT_KEY = "message";
8
8
  export declare const DEFAULT_OUTPUT_FILE_KEY = "files";
9
9
  /**
@@ -42,6 +42,12 @@ export interface AIAgentOptions<I extends Message = Message, O extends Message =
42
42
  * @default AIAgentToolChoice.auto
43
43
  */
44
44
  toolChoice?: AIAgentToolChoice | Agent;
45
+ /**
46
+ * Maximum number of tool calls to execute concurrently
47
+ *
48
+ * @default 1
49
+ */
50
+ toolCallsConcurrency?: number;
45
51
  /**
46
52
  * Whether to preserve text generated during tool usage in the final output
47
53
  */
@@ -237,6 +243,12 @@ export declare class AIAgent<I extends Message = any, O extends Message = any> e
237
243
  * {@includeCode ../../test/agents/ai-agent.test.ts#example-ai-agent-router}
238
244
  */
239
245
  toolChoice?: AIAgentToolChoice | Agent;
246
+ /**
247
+ * Maximum number of tool calls to execute concurrently
248
+ *
249
+ * @default 1
250
+ */
251
+ toolCallsConcurrency?: number;
240
252
  /**
241
253
  * Whether to preserve text generated during tool usage in the final output
242
254
  */
@@ -299,6 +311,7 @@ export declare class AIAgent<I extends Message = any, O extends Message = any> e
299
311
  metadataEnd: string;
300
312
  parse: (raw: string) => object;
301
313
  };
314
+ get inputSchema(): ZodType<I>;
302
315
  /**
303
316
  * Process an input message and generate a response
304
317
  *
@@ -46,8 +46,10 @@ export interface AIAgentSchema extends BaseAgentSchema {
46
46
  type: "ai";
47
47
  instructions?: Instructions;
48
48
  inputKey?: string;
49
+ inputFileKey?: string;
49
50
  outputKey?: string;
50
51
  toolChoice?: AIAgentToolChoice;
52
+ toolCallsConcurrency?: number;
51
53
  keepTextInToolUses?: boolean;
52
54
  }
53
55
  export interface ImageAgentSchema extends BaseAgentSchema {
@@ -3,7 +3,7 @@ import { PromptBuilder } from "../prompt/prompt-builder.js";
3
3
  import { Agent, type AgentInvokeOptions, type AgentOptions, type AgentProcessAsyncGenerator, type AgentProcessResult, type Message } from "./agent.js";
4
4
  import type { ChatModel, ChatModelInput } from "./chat-model.js";
5
5
  import type { GuideRailAgentOutput } from "./guide-rail-agent.js";
6
- import type { FileType } from "./model.js";
6
+ import { type FileType } from "./model.js";
7
7
  export declare const DEFAULT_OUTPUT_KEY = "message";
8
8
  export declare const DEFAULT_OUTPUT_FILE_KEY = "files";
9
9
  /**
@@ -42,6 +42,12 @@ export interface AIAgentOptions<I extends Message = Message, O extends Message =
42
42
  * @default AIAgentToolChoice.auto
43
43
  */
44
44
  toolChoice?: AIAgentToolChoice | Agent;
45
+ /**
46
+ * Maximum number of tool calls to execute concurrently
47
+ *
48
+ * @default 1
49
+ */
50
+ toolCallsConcurrency?: number;
45
51
  /**
46
52
  * Whether to preserve text generated during tool usage in the final output
47
53
  */
@@ -237,6 +243,12 @@ export declare class AIAgent<I extends Message = any, O extends Message = any> e
237
243
  * {@includeCode ../../test/agents/ai-agent.test.ts#example-ai-agent-router}
238
244
  */
239
245
  toolChoice?: AIAgentToolChoice | Agent;
246
+ /**
247
+ * Maximum number of tool calls to execute concurrently
248
+ *
249
+ * @default 1
250
+ */
251
+ toolCallsConcurrency?: number;
240
252
  /**
241
253
  * Whether to preserve text generated during tool usage in the final output
242
254
  */
@@ -299,6 +311,7 @@ export declare class AIAgent<I extends Message = any, O extends Message = any> e
299
311
  metadataEnd: string;
300
312
  parse: (raw: string) => object;
301
313
  };
314
+ get inputSchema(): ZodType<I>;
302
315
  /**
303
316
  * Process an input message and generate a response
304
317
  *
@@ -1,3 +1,4 @@
1
+ import fastq from "fastq";
1
2
  import { z } from "zod";
2
3
  import { PromptBuilder } from "../prompt/prompt-builder.js";
3
4
  import { STRUCTURED_STREAM_INSTRUCTIONS } from "../prompt/prompts/structured-stream-instructions.js";
@@ -5,6 +6,7 @@ import { AgentMessageTemplate, ToolMessageTemplate } from "../prompt/template.js
5
6
  import { ExtractMetadataTransform } from "../utils/structured-stream-extractor.js";
6
7
  import { checkArguments, isEmpty } from "../utils/type-utils.js";
7
8
  import { Agent, agentOptionsSchema, isAgentResponseDelta, } from "./agent.js";
9
+ import { fileUnionContentsSchema } from "./model.js";
8
10
  import { isTransferAgentOutput } from "./types.js";
9
11
  export const DEFAULT_OUTPUT_KEY = "message";
10
12
  export const DEFAULT_OUTPUT_FILE_KEY = "files";
@@ -55,6 +57,7 @@ export const aiAgentOptionsSchema = agentOptionsSchema.extend({
55
57
  inputKey: z.string().optional(),
56
58
  outputKey: z.string().optional(),
57
59
  toolChoice: aiAgentToolChoiceSchema.optional(),
60
+ toolCallsConcurrency: z.number().int().min(0).optional(),
58
61
  keepTextInToolUses: z.boolean().optional(),
59
62
  memoryAgentsAsTools: z.boolean().optional(),
60
63
  memoryPromptTemplate: z.string().optional(),
@@ -114,6 +117,7 @@ export class AIAgent extends Agent {
114
117
  this.outputFileKey = options.outputFileKey || DEFAULT_OUTPUT_FILE_KEY;
115
118
  this.outputFileType = options.outputFileType;
116
119
  this.toolChoice = options.toolChoice;
120
+ this.toolCallsConcurrency = options.toolCallsConcurrency || 1;
117
121
  this.keepTextInToolUses = options.keepTextInToolUses;
118
122
  this.memoryAgentsAsTools = options.memoryAgentsAsTools;
119
123
  this.memoryPromptTemplate = options.memoryPromptTemplate;
@@ -170,6 +174,12 @@ export class AIAgent extends Agent {
170
174
  * {@includeCode ../../test/agents/ai-agent.test.ts#example-ai-agent-router}
171
175
  */
172
176
  toolChoice;
177
+ /**
178
+ * Maximum number of tool calls to execute concurrently
179
+ *
180
+ * @default 1
181
+ */
182
+ toolCallsConcurrency;
173
183
  /**
174
184
  * Whether to preserve text generated during tool usage in the final output
175
185
  */
@@ -227,6 +237,20 @@ export class AIAgent extends Agent {
227
237
  * which outputs structured data in YAML format within <metadata> tags.
228
238
  */
229
239
  customStructuredStreamInstructions;
240
+ get inputSchema() {
241
+ let schema = super.inputSchema;
242
+ if (this.inputKey) {
243
+ schema = schema.extend({
244
+ [this.inputKey]: z.string().nullish(),
245
+ });
246
+ }
247
+ if (this.inputFileKey) {
248
+ schema = schema.extend({
249
+ [this.inputFileKey]: fileUnionContentsSchema.nullish(),
250
+ });
251
+ }
252
+ return schema;
253
+ }
230
254
  /**
231
255
  * Process an input message and generate a response
232
256
  *
@@ -284,31 +308,43 @@ export class AIAgent extends Agent {
284
308
  yield { delta: { text: { [outputKey]: "\n" } } };
285
309
  }
286
310
  const executedToolCalls = [];
311
+ let error;
312
+ const queue = fastq.promise(async ({ tool, call }) => {
313
+ try {
314
+ // NOTE: should pass both arguments (model generated) and input (user provided) to the tool
315
+ const output = await this.invokeSkill(tool, { ...input, ...call.function.arguments }, options).catch((error) => {
316
+ if (!this.catchToolsError) {
317
+ return Promise.reject(error);
318
+ }
319
+ return {
320
+ isError: true,
321
+ error: {
322
+ message: error.message,
323
+ },
324
+ };
325
+ });
326
+ executedToolCalls.push({ call, output });
327
+ }
328
+ catch (e) {
329
+ error = e;
330
+ queue.killAndDrain();
331
+ }
332
+ }, this.toolCallsConcurrency || 1);
287
333
  // Execute tools
288
334
  for (const call of toolCalls) {
289
335
  const tool = toolsMap.get(call.function.name);
290
336
  if (!tool)
291
337
  throw new Error(`Tool not found: ${call.function.name}`);
292
- // NOTE: should pass both arguments (model generated) and input (user provided) to the tool
293
- const output = await this.invokeSkill(tool, { ...input, ...call.function.arguments }, options).catch((error) => {
294
- if (!this.catchToolsError) {
295
- return Promise.reject(error);
296
- }
297
- return {
298
- isError: true,
299
- error: {
300
- message: error.message,
301
- },
302
- };
303
- });
304
- // NOTE: Return transfer output immediately
305
- if (isTransferAgentOutput(output)) {
306
- return output;
307
- }
308
- executedToolCalls.push({ call, output });
338
+ queue.push({ tool, call });
309
339
  }
340
+ await queue.drained();
341
+ if (error)
342
+ throw error;
310
343
  // Continue LLM function calling loop if any tools were executed
311
344
  if (executedToolCalls.length) {
345
+ const transferOutput = executedToolCalls.find((i) => isTransferAgentOutput(i.output))?.output;
346
+ if (transferOutput)
347
+ return transferOutput;
312
348
  toolCallMessages.push(await AgentMessageTemplate.from(undefined, executedToolCalls.map(({ call }) => call)).format(), ...(await Promise.all(executedToolCalls.map(({ call, output }) => ToolMessageTemplate.from(output, call.id).format()))));
313
349
  continue;
314
350
  }
@@ -46,8 +46,10 @@ export interface AIAgentSchema extends BaseAgentSchema {
46
46
  type: "ai";
47
47
  instructions?: Instructions;
48
48
  inputKey?: string;
49
+ inputFileKey?: string;
49
50
  outputKey?: string;
50
51
  toolChoice?: AIAgentToolChoice;
52
+ toolCallsConcurrency?: number;
51
53
  keepTextInToolUses?: boolean;
52
54
  }
53
55
  export interface ImageAgentSchema extends BaseAgentSchema {
@@ -91,7 +91,10 @@ export async function parseAgentFile(path, data) {
91
91
  instructions: optionalize(instructionsSchema),
92
92
  inputKey: optionalize(z.string()),
93
93
  outputKey: optionalize(z.string()),
94
+ inputFileKey: optionalize(z.string()),
95
+ outputFileKey: optionalize(z.string()),
94
96
  toolChoice: optionalize(z.nativeEnum(AIAgentToolChoice)),
97
+ toolCallsConcurrency: optionalize(z.number().int().min(0)),
95
98
  keepTextInToolUses: optionalize(z.boolean()),
96
99
  structuredStreamMode: optionalize(z.boolean()),
97
100
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.63.0-beta",
3
+ "version": "1.63.0-beta.2",
4
4
  "description": "The functional core of agentic AI",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -92,9 +92,9 @@
92
92
  "zod": "^3.25.67",
93
93
  "zod-from-json-schema": "^0.0.5",
94
94
  "zod-to-json-schema": "^3.24.6",
95
- "@aigne/observability-api": "^0.11.2-beta",
95
+ "@aigne/afs": "^1.0.0",
96
96
  "@aigne/platform-helpers": "^0.6.3",
97
- "@aigne/afs": "^1.0.0"
97
+ "@aigne/observability-api": "^0.11.2-beta"
98
98
  },
99
99
  "devDependencies": {
100
100
  "@types/bun": "^1.2.22",