@aigne/core 1.43.1 → 1.45.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 CHANGED
@@ -12,6 +12,38 @@
12
12
  * dependencies
13
13
  * @aigne/observability bumped to 0.1.0
14
14
 
15
+ ## [1.45.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.44.0...core-v1.45.0) (2025-08-06)
16
+
17
+
18
+ ### Features
19
+
20
+ * **core:** add concurrency support for team agent ([#323](https://github.com/AIGNE-io/aigne-framework/issues/323)) ([5743260](https://github.com/AIGNE-io/aigne-framework/commit/57432603a45208ad3503b9fc4c64f07c8151f9ee))
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * **core:** remove lodash dependency ensure core support both esm and cjs ([#324](https://github.com/AIGNE-io/aigne-framework/issues/324)) ([d6c2452](https://github.com/AIGNE-io/aigne-framework/commit/d6c2452b660a163c73f2c628ffdc2a12949360b0))
26
+ * **models:** aigne-hub adapter not working in node.js v21 ([#320](https://github.com/AIGNE-io/aigne-framework/issues/320)) ([2884d00](https://github.com/AIGNE-io/aigne-framework/commit/2884d00b83e153ae7465ef1369fcd22d7c6d43e0))
27
+
28
+
29
+ ### Dependencies
30
+
31
+ * The following workspace dependencies were updated
32
+ * dependencies
33
+ * @aigne/platform-helpers bumped to 0.5.1
34
+
35
+ ## [1.44.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.43.1...core-v1.44.0) (2025-08-05)
36
+
37
+
38
+ ### Features
39
+
40
+ * allow inserting agent-hub credits manually ([#315](https://github.com/AIGNE-io/aigne-framework/issues/315)) ([e3e4d1f](https://github.com/AIGNE-io/aigne-framework/commit/e3e4d1ff0d9d3fef33bb41d85e99735d4dd76cb7))
41
+
42
+
43
+ ### Bug Fixes
44
+
45
+ * **cli:** improve CLI prompts and output handling ([#318](https://github.com/AIGNE-io/aigne-framework/issues/318)) ([681ee79](https://github.com/AIGNE-io/aigne-framework/commit/681ee79e9b18aed5a977a0a418c2d9df20a7297c))
46
+
15
47
  ## [1.43.1](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.43.0...core-v1.43.1) (2025-08-05)
16
48
 
17
49
 
@@ -450,14 +450,14 @@ class Agent {
450
450
  let finalOutput = this.includeInputInOutput ? { ...input, ...parsedOutput } : parsedOutput;
451
451
  await this.postprocess(input, finalOutput, options);
452
452
  logger_js_1.logger.debug("Invoke agent %s succeed with output: %O", this.name, finalOutput);
453
- if (!this.disableEvents)
454
- context.emit("agentSucceed", { agent: this, output: finalOutput });
455
453
  let o = await this.callHooks("onSuccess", { input, output: finalOutput }, options);
456
454
  if (o?.output)
457
455
  finalOutput = o.output;
458
456
  o = await this.callHooks("onEnd", { input, output: finalOutput }, options);
459
457
  if (o?.output)
460
458
  finalOutput = o.output;
459
+ if (!this.disableEvents)
460
+ context.emit("agentSucceed", { agent: this, output: finalOutput });
461
461
  return finalOutput;
462
462
  }
463
463
  /**
@@ -381,4 +381,8 @@ export interface ChatModelOutputUsage {
381
381
  * Number of output tokens
382
382
  */
383
383
  outputTokens: number;
384
+ /**
385
+ * AIGNE Hub credit usage
386
+ */
387
+ aigneHubCredits?: number;
384
388
  }
@@ -214,6 +214,7 @@ const chatModelOutputToolCallSchema = zod_1.z.object({
214
214
  const chatModelOutputUsageSchema = zod_1.z.object({
215
215
  inputTokens: zod_1.z.number(),
216
216
  outputTokens: zod_1.z.number(),
217
+ aigneHubCredits: zod_1.z.number().optional(),
217
218
  });
218
219
  const chatModelOutputSchema = zod_1.z.object({
219
220
  text: zod_1.z.string().optional(),
@@ -1,7 +1,37 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
5
35
  Object.defineProperty(exports, "__esModule", { value: true });
6
36
  exports.MCPResource = exports.MCPPrompt = exports.MCPTool = exports.MCPBase = exports.MCPAgent = void 0;
7
37
  const stdio_client_transport_js_1 = require("@aigne/platform-helpers/mcp/stdio-client-transport.js");
@@ -10,7 +40,6 @@ const index_js_2 = require("@modelcontextprotocol/sdk/client/index.js");
10
40
  const sse_js_1 = require("@modelcontextprotocol/sdk/client/sse.js");
11
41
  const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
12
42
  const uriTemplate_js_1 = require("@modelcontextprotocol/sdk/shared/uriTemplate.js");
13
- const p_retry_1 = __importDefault(require("p-retry"));
14
43
  const zod_1 = require("zod");
15
44
  const logger_js_1 = require("../utils/logger.js");
16
45
  const mcp_utils_js_1 = require("../utils/mcp-utils.js");
@@ -222,7 +251,8 @@ class ClientWithReconnect extends index_js_2.Client {
222
251
  const transportCreator = this.reconnectOptions?.transportCreator;
223
252
  if (!transportCreator)
224
253
  throw new Error("reconnect requires a transportCreator");
225
- await (0, p_retry_1.default)(async () => {
254
+ const retry = await Promise.resolve().then(() => __importStar(require("p-retry")));
255
+ await retry.default(async () => {
226
256
  await this.close();
227
257
  await this.connect(await transportCreator(), {
228
258
  timeout: this.reconnectOptions?.timeout ?? DEFAULT_TIMEOUT(),
@@ -137,6 +137,22 @@ export interface TeamAgentOptions<I extends Message, O extends Message> extends
137
137
  * - The processing results are streamed incrementally as each iteration completes
138
138
  */
139
139
  iterateOn?: keyof I;
140
+ /**
141
+ * The maximum number of concurrent operations when processing array items with `iterateOn`.
142
+ *
143
+ * This property controls how many array elements are processed simultaneously when
144
+ * iterating over an array field. A higher concurrency value allows for faster
145
+ * parallel processing but may consume more resources.
146
+ *
147
+ * @remarks
148
+ * - Only applies when `iterateOn` is specified
149
+ * - Cannot be used together with `iterateWithPreviousOutput` (concurrency > 1)
150
+ * - Uses a queue-based approach to limit concurrent operations
151
+ * - Each concurrent operation processes one array element through the entire agent workflow
152
+ *
153
+ * @default 1
154
+ */
155
+ concurrency?: number;
140
156
  /**
141
157
  * Controls whether to merge the output from each iteration back into the array items
142
158
  * for subsequent iterations when using `iterateOn`.
@@ -228,6 +244,16 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
228
244
  * @see TeamAgentOptions.iterateOn for detailed documentation
229
245
  */
230
246
  iterateOn?: keyof I;
247
+ /**
248
+ * The maximum number of concurrent operations when processing array items.
249
+ *
250
+ * This property controls the concurrency level for iterative processing when `iterateOn`
251
+ * is used. It determines how many array elements are processed simultaneously.
252
+ *
253
+ * @see TeamAgentOptions.concurrency for detailed documentation
254
+ * @default 1
255
+ */
256
+ concurrency: number;
231
257
  /**
232
258
  * Controls whether to merge the output from each iteration back into the array items
233
259
  * for subsequent iterations when using `iterateOn`.
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.TeamAgent = exports.DEFAULT_REFLECTION_MAX_ITERATIONS = exports.ProcessMode = void 0;
7
7
  const node_assert_1 = __importDefault(require("node:assert"));
8
+ const fastq_1 = __importDefault(require("fastq"));
8
9
  const immer_1 = require("immer");
9
10
  const stream_utils_js_1 = require("../utils/stream-utils.js");
10
11
  const type_utils_js_1 = require("../utils/type-utils.js");
@@ -82,8 +83,12 @@ class TeamAgent extends agent_js_1.Agent {
82
83
  maxIterations: options.reflection.maxIterations ?? exports.DEFAULT_REFLECTION_MAX_ITERATIONS,
83
84
  };
84
85
  this.iterateOn = options.iterateOn;
86
+ this.concurrency = options.concurrency ?? 1;
85
87
  this.iterateWithPreviousOutput = options.iterateWithPreviousOutput;
86
88
  this.includeAllStepsOutput = options.includeAllStepsOutput;
89
+ if (this.concurrency !== 1 && this.iterateWithPreviousOutput) {
90
+ throw new Error(`iterateWithPreviousOutput cannot be used with concurrency > 1, concurrency: ${this.concurrency}`);
91
+ }
87
92
  }
88
93
  /**
89
94
  * The processing mode that determines how agents in the team are executed.
@@ -109,6 +114,16 @@ class TeamAgent extends agent_js_1.Agent {
109
114
  * @see TeamAgentOptions.iterateOn for detailed documentation
110
115
  */
111
116
  iterateOn;
117
+ /**
118
+ * The maximum number of concurrent operations when processing array items.
119
+ *
120
+ * This property controls the concurrency level for iterative processing when `iterateOn`
121
+ * is used. It determines how many array elements are processed simultaneously.
122
+ *
123
+ * @see TeamAgentOptions.concurrency for detailed documentation
124
+ * @default 1
125
+ */
126
+ concurrency;
112
127
  /**
113
128
  * Controls whether to merge the output from each iteration back into the array items
114
129
  * for subsequent iterations when using `iterateOn`.
@@ -180,23 +195,27 @@ class TeamAgent extends agent_js_1.Agent {
180
195
  (0, node_assert_1.default)(this.iterateOn, "iterateInputKey must be defined for iterator processing");
181
196
  let arr = input[this.iterateOn];
182
197
  arr = Array.isArray(arr) ? [...arr] : (0, type_utils_js_1.isNil)(arr) ? [arr] : [];
183
- const result = [];
184
- for (let i = 0; i < arr.length; i++) {
185
- const item = arr[i];
198
+ const results = new Array(arr.length);
199
+ const queue = fastq_1.default.promise(async ({ item, index }) => {
186
200
  if (!(0, type_utils_js_1.isRecord)(item))
187
201
  throw new TypeError(`Expected ${String(key)} to be an object, got ${typeof item}`);
188
- const res = await (0, agent_js_1.agentProcessResultToObject)(await this._processNonIterator({ ...input, [key]: arr, ...item }, { ...options, streaming: false }));
202
+ const o = await (0, agent_js_1.agentProcessResultToObject)(await this._processNonIterator({ ...input, [key]: arr, ...item }, { ...options, streaming: false }));
203
+ const res = (0, type_utils_js_1.omit)(o, key);
189
204
  // Merge the item result with the original item used for next iteration
190
205
  if (this.iterateWithPreviousOutput) {
191
206
  arr = (0, immer_1.produce)(arr, (draft) => {
192
- const item = draft[i];
207
+ const item = draft[index];
193
208
  (0, node_assert_1.default)(item);
194
209
  Object.assign(item, res);
195
210
  });
196
211
  }
197
- result.push((0, type_utils_js_1.omit)(res, key));
198
- yield { delta: { json: { [key]: result } } };
212
+ results[index] = res;
213
+ }, this.concurrency);
214
+ for (let index = 0; index < arr.length; index++) {
215
+ queue.push({ index, item: arr[index] });
199
216
  }
217
+ await queue.drained();
218
+ yield { delta: { json: { [key]: results } } };
200
219
  }
201
220
  _processNonIterator(input, options) {
202
221
  switch (this.mode) {
@@ -46,6 +46,9 @@ export interface TeamAgentSchema extends BaseAgentSchema {
46
46
  type: "team";
47
47
  mode?: ProcessMode;
48
48
  iterateOn?: string;
49
+ concurrency?: number;
50
+ iterateWithPreviousOutput?: boolean;
51
+ includeAllStepsOutput?: boolean;
49
52
  reflection?: Omit<ReflectionMode, "reviewer"> & {
50
53
  reviewer: NestAgentSchema;
51
54
  };
@@ -78,6 +78,9 @@ async function parseAgentFile(path, data) {
78
78
  type: zod_1.z.literal("team"),
79
79
  mode: (0, schema_js_1.optionalize)(zod_1.z.nativeEnum(team_agent_js_1.ProcessMode)),
80
80
  iterateOn: (0, schema_js_1.optionalize)(zod_1.z.string()),
81
+ concurrency: (0, schema_js_1.optionalize)(zod_1.z.number().int().min(1)),
82
+ iterateWithPreviousOutput: (0, schema_js_1.optionalize)(zod_1.z.boolean()),
83
+ includeAllStepsOutput: (0, schema_js_1.optionalize)(zod_1.z.boolean()),
81
84
  reflection: (0, schema_js_1.camelizeSchema)((0, schema_js_1.optionalize)(zod_1.z.object({
82
85
  reviewer: nestAgentSchema,
83
86
  isApproved: zod_1.z.string(),
@@ -1,16 +1,13 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.defaultInputSchema = exports.inputOutputSchema = void 0;
7
4
  exports.optionalize = optionalize;
8
5
  exports.camelizeSchema = camelizeSchema;
9
6
  const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
10
- const camelize_ts_1 = __importDefault(require("camelize-ts"));
11
7
  const yaml_1 = require("yaml");
12
8
  const zod_1 = require("zod");
13
9
  const agent_js_1 = require("../agents/agent.js");
10
+ const camelize_js_1 = require("../utils/camelize.js");
14
11
  const type_utils_js_1 = require("../utils/type-utils.js");
15
12
  const inputOutputSchema = ({ path }) => {
16
13
  const includeExternalSchema = async (schema) => {
@@ -67,5 +64,5 @@ function optionalize(schema) {
67
64
  return schema.nullish().transform((v) => v ?? undefined);
68
65
  }
69
66
  function camelizeSchema(schema, { shallow = true } = {}) {
70
- return zod_1.z.preprocess((v) => ((0, type_utils_js_1.isRecord)(v) ? (0, camelize_ts_1.default)(v, shallow) : v), schema);
67
+ return zod_1.z.preprocess((v) => ((0, type_utils_js_1.isRecord)(v) ? (0, camelize_js_1.camelize)(v, shallow) : v), schema);
71
68
  }
@@ -0,0 +1 @@
1
+ export declare function camelize<T>(obj: T, shallow?: boolean): any;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.camelize = camelize;
4
+ const type_utils_js_1 = require("./type-utils.js");
5
+ function camelize(obj, shallow = false) {
6
+ if (Array.isArray(obj)) {
7
+ return shallow ? obj : obj.map((item) => camelize(item, false));
8
+ }
9
+ if ((0, type_utils_js_1.isRecord)(obj)) {
10
+ return Object.fromEntries(Object.entries(obj).map(([key, value]) => [
11
+ camelCase(key),
12
+ shallow ? value : camelize(value, false),
13
+ ]));
14
+ }
15
+ return obj;
16
+ }
17
+ function camelCase(key) {
18
+ key = key.replace(/[-_#@$\s]+(.)?/g, (_, char) => char.toUpperCase());
19
+ key = key.charAt(0).toLowerCase() + key.slice(1);
20
+ return key;
21
+ }
@@ -1,4 +1,5 @@
1
1
  export declare enum LogLevel {
2
+ SILENT = "silent",
2
3
  ERROR = "error",
3
4
  WARN = "warn",
4
5
  INFO = "info",
@@ -9,6 +9,7 @@ const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
9
9
  const debug_1 = __importDefault(require("debug"));
10
10
  var LogLevel;
11
11
  (function (LogLevel) {
12
+ LogLevel["SILENT"] = "silent";
12
13
  LogLevel["ERROR"] = "error";
13
14
  LogLevel["WARN"] = "warn";
14
15
  LogLevel["INFO"] = "info";
@@ -76,5 +77,5 @@ class Logger {
76
77
  exports.Logger = Logger;
77
78
  exports.logger = new Logger({
78
79
  ns: "aigne:core",
79
- level: LogLevel.INFO,
80
+ level: LogLevel.SILENT,
80
81
  });
@@ -381,4 +381,8 @@ export interface ChatModelOutputUsage {
381
381
  * Number of output tokens
382
382
  */
383
383
  outputTokens: number;
384
+ /**
385
+ * AIGNE Hub credit usage
386
+ */
387
+ aigneHubCredits?: number;
384
388
  }
@@ -137,6 +137,22 @@ export interface TeamAgentOptions<I extends Message, O extends Message> extends
137
137
  * - The processing results are streamed incrementally as each iteration completes
138
138
  */
139
139
  iterateOn?: keyof I;
140
+ /**
141
+ * The maximum number of concurrent operations when processing array items with `iterateOn`.
142
+ *
143
+ * This property controls how many array elements are processed simultaneously when
144
+ * iterating over an array field. A higher concurrency value allows for faster
145
+ * parallel processing but may consume more resources.
146
+ *
147
+ * @remarks
148
+ * - Only applies when `iterateOn` is specified
149
+ * - Cannot be used together with `iterateWithPreviousOutput` (concurrency > 1)
150
+ * - Uses a queue-based approach to limit concurrent operations
151
+ * - Each concurrent operation processes one array element through the entire agent workflow
152
+ *
153
+ * @default 1
154
+ */
155
+ concurrency?: number;
140
156
  /**
141
157
  * Controls whether to merge the output from each iteration back into the array items
142
158
  * for subsequent iterations when using `iterateOn`.
@@ -228,6 +244,16 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
228
244
  * @see TeamAgentOptions.iterateOn for detailed documentation
229
245
  */
230
246
  iterateOn?: keyof I;
247
+ /**
248
+ * The maximum number of concurrent operations when processing array items.
249
+ *
250
+ * This property controls the concurrency level for iterative processing when `iterateOn`
251
+ * is used. It determines how many array elements are processed simultaneously.
252
+ *
253
+ * @see TeamAgentOptions.concurrency for detailed documentation
254
+ * @default 1
255
+ */
256
+ concurrency: number;
231
257
  /**
232
258
  * Controls whether to merge the output from each iteration back into the array items
233
259
  * for subsequent iterations when using `iterateOn`.
@@ -46,6 +46,9 @@ export interface TeamAgentSchema extends BaseAgentSchema {
46
46
  type: "team";
47
47
  mode?: ProcessMode;
48
48
  iterateOn?: string;
49
+ concurrency?: number;
50
+ iterateWithPreviousOutput?: boolean;
51
+ includeAllStepsOutput?: boolean;
49
52
  reflection?: Omit<ReflectionMode, "reviewer"> & {
50
53
  reviewer: NestAgentSchema;
51
54
  };
@@ -0,0 +1 @@
1
+ export declare function camelize<T>(obj: T, shallow?: boolean): any;
@@ -1,4 +1,5 @@
1
1
  export declare enum LogLevel {
2
+ SILENT = "silent",
2
3
  ERROR = "error",
3
4
  WARN = "warn",
4
5
  INFO = "info",
@@ -405,14 +405,14 @@ export class Agent {
405
405
  let finalOutput = this.includeInputInOutput ? { ...input, ...parsedOutput } : parsedOutput;
406
406
  await this.postprocess(input, finalOutput, options);
407
407
  logger.debug("Invoke agent %s succeed with output: %O", this.name, finalOutput);
408
- if (!this.disableEvents)
409
- context.emit("agentSucceed", { agent: this, output: finalOutput });
410
408
  let o = await this.callHooks("onSuccess", { input, output: finalOutput }, options);
411
409
  if (o?.output)
412
410
  finalOutput = o.output;
413
411
  o = await this.callHooks("onEnd", { input, output: finalOutput }, options);
414
412
  if (o?.output)
415
413
  finalOutput = o.output;
414
+ if (!this.disableEvents)
415
+ context.emit("agentSucceed", { agent: this, output: finalOutput });
416
416
  return finalOutput;
417
417
  }
418
418
  /**
@@ -381,4 +381,8 @@ export interface ChatModelOutputUsage {
381
381
  * Number of output tokens
382
382
  */
383
383
  outputTokens: number;
384
+ /**
385
+ * AIGNE Hub credit usage
386
+ */
387
+ aigneHubCredits?: number;
384
388
  }
@@ -210,6 +210,7 @@ const chatModelOutputToolCallSchema = z.object({
210
210
  const chatModelOutputUsageSchema = z.object({
211
211
  inputTokens: z.number(),
212
212
  outputTokens: z.number(),
213
+ aigneHubCredits: z.number().optional(),
213
214
  });
214
215
  const chatModelOutputSchema = z.object({
215
216
  text: z.string().optional(),
@@ -4,7 +4,6 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
4
  import { SSEClientTransport, } from "@modelcontextprotocol/sdk/client/sse.js";
5
5
  import { StreamableHTTPClientTransport, } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
6
6
  import { UriTemplate } from "@modelcontextprotocol/sdk/shared/uriTemplate.js";
7
- import pRetry from "p-retry";
8
7
  import { z } from "zod";
9
8
  import { logger } from "../utils/logger.js";
10
9
  import { promptFromMCPPrompt, resourceFromMCPResource, toolFromMCPTool, } from "../utils/mcp-utils.js";
@@ -215,7 +214,8 @@ class ClientWithReconnect extends Client {
215
214
  const transportCreator = this.reconnectOptions?.transportCreator;
216
215
  if (!transportCreator)
217
216
  throw new Error("reconnect requires a transportCreator");
218
- await pRetry(async () => {
217
+ const retry = await import("p-retry");
218
+ await retry.default(async () => {
219
219
  await this.close();
220
220
  await this.connect(await transportCreator(), {
221
221
  timeout: this.reconnectOptions?.timeout ?? DEFAULT_TIMEOUT(),
@@ -137,6 +137,22 @@ export interface TeamAgentOptions<I extends Message, O extends Message> extends
137
137
  * - The processing results are streamed incrementally as each iteration completes
138
138
  */
139
139
  iterateOn?: keyof I;
140
+ /**
141
+ * The maximum number of concurrent operations when processing array items with `iterateOn`.
142
+ *
143
+ * This property controls how many array elements are processed simultaneously when
144
+ * iterating over an array field. A higher concurrency value allows for faster
145
+ * parallel processing but may consume more resources.
146
+ *
147
+ * @remarks
148
+ * - Only applies when `iterateOn` is specified
149
+ * - Cannot be used together with `iterateWithPreviousOutput` (concurrency > 1)
150
+ * - Uses a queue-based approach to limit concurrent operations
151
+ * - Each concurrent operation processes one array element through the entire agent workflow
152
+ *
153
+ * @default 1
154
+ */
155
+ concurrency?: number;
140
156
  /**
141
157
  * Controls whether to merge the output from each iteration back into the array items
142
158
  * for subsequent iterations when using `iterateOn`.
@@ -228,6 +244,16 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
228
244
  * @see TeamAgentOptions.iterateOn for detailed documentation
229
245
  */
230
246
  iterateOn?: keyof I;
247
+ /**
248
+ * The maximum number of concurrent operations when processing array items.
249
+ *
250
+ * This property controls the concurrency level for iterative processing when `iterateOn`
251
+ * is used. It determines how many array elements are processed simultaneously.
252
+ *
253
+ * @see TeamAgentOptions.concurrency for detailed documentation
254
+ * @default 1
255
+ */
256
+ concurrency: number;
231
257
  /**
232
258
  * Controls whether to merge the output from each iteration back into the array items
233
259
  * for subsequent iterations when using `iterateOn`.
@@ -1,4 +1,5 @@
1
1
  import assert from "node:assert";
2
+ import fastq from "fastq";
2
3
  import { produce } from "immer";
3
4
  import { mergeAgentResponseChunk } from "../utils/stream-utils.js";
4
5
  import { isEmpty, isNil, isRecord, omit } from "../utils/type-utils.js";
@@ -76,8 +77,12 @@ export class TeamAgent extends Agent {
76
77
  maxIterations: options.reflection.maxIterations ?? DEFAULT_REFLECTION_MAX_ITERATIONS,
77
78
  };
78
79
  this.iterateOn = options.iterateOn;
80
+ this.concurrency = options.concurrency ?? 1;
79
81
  this.iterateWithPreviousOutput = options.iterateWithPreviousOutput;
80
82
  this.includeAllStepsOutput = options.includeAllStepsOutput;
83
+ if (this.concurrency !== 1 && this.iterateWithPreviousOutput) {
84
+ throw new Error(`iterateWithPreviousOutput cannot be used with concurrency > 1, concurrency: ${this.concurrency}`);
85
+ }
81
86
  }
82
87
  /**
83
88
  * The processing mode that determines how agents in the team are executed.
@@ -103,6 +108,16 @@ export class TeamAgent extends Agent {
103
108
  * @see TeamAgentOptions.iterateOn for detailed documentation
104
109
  */
105
110
  iterateOn;
111
+ /**
112
+ * The maximum number of concurrent operations when processing array items.
113
+ *
114
+ * This property controls the concurrency level for iterative processing when `iterateOn`
115
+ * is used. It determines how many array elements are processed simultaneously.
116
+ *
117
+ * @see TeamAgentOptions.concurrency for detailed documentation
118
+ * @default 1
119
+ */
120
+ concurrency;
106
121
  /**
107
122
  * Controls whether to merge the output from each iteration back into the array items
108
123
  * for subsequent iterations when using `iterateOn`.
@@ -174,23 +189,27 @@ export class TeamAgent extends Agent {
174
189
  assert(this.iterateOn, "iterateInputKey must be defined for iterator processing");
175
190
  let arr = input[this.iterateOn];
176
191
  arr = Array.isArray(arr) ? [...arr] : isNil(arr) ? [arr] : [];
177
- const result = [];
178
- for (let i = 0; i < arr.length; i++) {
179
- const item = arr[i];
192
+ const results = new Array(arr.length);
193
+ const queue = fastq.promise(async ({ item, index }) => {
180
194
  if (!isRecord(item))
181
195
  throw new TypeError(`Expected ${String(key)} to be an object, got ${typeof item}`);
182
- const res = await agentProcessResultToObject(await this._processNonIterator({ ...input, [key]: arr, ...item }, { ...options, streaming: false }));
196
+ const o = await agentProcessResultToObject(await this._processNonIterator({ ...input, [key]: arr, ...item }, { ...options, streaming: false }));
197
+ const res = omit(o, key);
183
198
  // Merge the item result with the original item used for next iteration
184
199
  if (this.iterateWithPreviousOutput) {
185
200
  arr = produce(arr, (draft) => {
186
- const item = draft[i];
201
+ const item = draft[index];
187
202
  assert(item);
188
203
  Object.assign(item, res);
189
204
  });
190
205
  }
191
- result.push(omit(res, key));
192
- yield { delta: { json: { [key]: result } } };
206
+ results[index] = res;
207
+ }, this.concurrency);
208
+ for (let index = 0; index < arr.length; index++) {
209
+ queue.push({ index, item: arr[index] });
193
210
  }
211
+ await queue.drained();
212
+ yield { delta: { json: { [key]: results } } };
194
213
  }
195
214
  _processNonIterator(input, options) {
196
215
  switch (this.mode) {
@@ -46,6 +46,9 @@ export interface TeamAgentSchema extends BaseAgentSchema {
46
46
  type: "team";
47
47
  mode?: ProcessMode;
48
48
  iterateOn?: string;
49
+ concurrency?: number;
50
+ iterateWithPreviousOutput?: boolean;
51
+ includeAllStepsOutput?: boolean;
49
52
  reflection?: Omit<ReflectionMode, "reviewer"> & {
50
53
  reviewer: NestAgentSchema;
51
54
  };
@@ -74,6 +74,9 @@ export async function parseAgentFile(path, data) {
74
74
  type: z.literal("team"),
75
75
  mode: optionalize(z.nativeEnum(ProcessMode)),
76
76
  iterateOn: optionalize(z.string()),
77
+ concurrency: optionalize(z.number().int().min(1)),
78
+ iterateWithPreviousOutput: optionalize(z.boolean()),
79
+ includeAllStepsOutput: optionalize(z.boolean()),
77
80
  reflection: camelizeSchema(optionalize(z.object({
78
81
  reviewer: nestAgentSchema,
79
82
  isApproved: z.string(),
@@ -1,8 +1,8 @@
1
1
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
2
- import camelize from "camelize-ts";
3
2
  import { parse } from "yaml";
4
3
  import { z } from "zod";
5
4
  import { DEFAULT_INPUT_ACTION_GET } from "../agents/agent.js";
5
+ import { camelize } from "../utils/camelize.js";
6
6
  import { isRecord } from "../utils/type-utils.js";
7
7
  export const inputOutputSchema = ({ path }) => {
8
8
  const includeExternalSchema = async (schema) => {
@@ -0,0 +1 @@
1
+ export declare function camelize<T>(obj: T, shallow?: boolean): any;
@@ -0,0 +1,18 @@
1
+ import { isRecord } from "./type-utils.js";
2
+ export function camelize(obj, shallow = false) {
3
+ if (Array.isArray(obj)) {
4
+ return shallow ? obj : obj.map((item) => camelize(item, false));
5
+ }
6
+ if (isRecord(obj)) {
7
+ return Object.fromEntries(Object.entries(obj).map(([key, value]) => [
8
+ camelCase(key),
9
+ shallow ? value : camelize(value, false),
10
+ ]));
11
+ }
12
+ return obj;
13
+ }
14
+ function camelCase(key) {
15
+ key = key.replace(/[-_#@$\s]+(.)?/g, (_, char) => char.toUpperCase());
16
+ key = key.charAt(0).toLowerCase() + key.slice(1);
17
+ return key;
18
+ }
@@ -1,4 +1,5 @@
1
1
  export declare enum LogLevel {
2
+ SILENT = "silent",
2
3
  ERROR = "error",
3
4
  WARN = "warn",
4
5
  INFO = "info",
@@ -2,6 +2,7 @@ import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
2
2
  import debug from "debug";
3
3
  export var LogLevel;
4
4
  (function (LogLevel) {
5
+ LogLevel["SILENT"] = "silent";
5
6
  LogLevel["ERROR"] = "error";
6
7
  LogLevel["WARN"] = "warn";
7
8
  LogLevel["INFO"] = "info";
@@ -68,5 +69,5 @@ export class Logger {
68
69
  }
69
70
  export const logger = new Logger({
70
71
  ns: "aigne:core",
71
- level: LogLevel.INFO,
72
+ level: LogLevel.SILENT,
72
73
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.43.1",
3
+ "version": "1.45.0",
4
4
  "description": "AIGNE core library for building AI-powered applications",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -76,11 +76,11 @@
76
76
  "debug": "^4.4.1",
77
77
  "eventsource-parser": "^3.0.3",
78
78
  "fast-deep-equal": "^3.1.3",
79
+ "fastq": "^1.19.1",
79
80
  "immer": "^10.1.1",
80
81
  "jaison": "^2.0.2",
81
82
  "jsonata": "^2.0.6",
82
83
  "mustache": "^4.2.0",
83
- "nanoid": "^5.1.5",
84
84
  "nunjucks": "^3.2.4",
85
85
  "p-retry": "^6.2.1",
86
86
  "raw-body": "^3.0.0",
@@ -91,7 +91,7 @@
91
91
  "zod": "^3.25.67",
92
92
  "zod-to-json-schema": "^3.24.6",
93
93
  "@aigne/observability-api": "^0.9.0",
94
- "@aigne/platform-helpers": "^0.5.0"
94
+ "@aigne/platform-helpers": "^0.5.1"
95
95
  },
96
96
  "devDependencies": {
97
97
  "@types/bun": "^1.2.18",