@aigne/core 1.36.0 → 1.38.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,26 @@
12
12
  * dependencies
13
13
  * @aigne/observability bumped to 0.1.0
14
14
 
15
+ ## [1.38.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.37.0...core-v1.38.0) (2025-07-24)
16
+
17
+
18
+ ### Features
19
+
20
+ * **cli:** support aigne hub connect and model use ([#267](https://github.com/AIGNE-io/aigne-framework/issues/267)) ([8e5a32a](https://github.com/AIGNE-io/aigne-framework/commit/8e5a32afc64593137153d7407bde13837312ac70))
21
+ * **core:** support config reflection for TeamAgent in yaml file ([#276](https://github.com/AIGNE-io/aigne-framework/issues/276)) ([e6296a8](https://github.com/AIGNE-io/aigne-framework/commit/e6296a8aff313e8209c4fbb2878e7869cc672576))
22
+
23
+ ## [1.37.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.36.0...core-v1.37.0) (2025-07-22)
24
+
25
+
26
+ ### Features
27
+
28
+ * **core:** add reflection mode support to TeamAgent ([#273](https://github.com/AIGNE-io/aigne-framework/issues/273)) ([4e2dad6](https://github.com/AIGNE-io/aigne-framework/commit/4e2dad687c1caefa231c7a7620651d060f8c8b9d))
29
+
30
+
31
+ ### Bug Fixes
32
+
33
+ * **core:** function agent should use common schema from yaml definition ([#270](https://github.com/AIGNE-io/aigne-framework/issues/270)) ([076a489](https://github.com/AIGNE-io/aigne-framework/commit/076a4896948c397518e99df46c1a443ea43daa64))
34
+
15
35
  ## [1.36.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.35.0...core-v1.36.0) (2025-07-17)
16
36
 
17
37
 
@@ -22,6 +22,78 @@ export declare enum ProcessMode {
22
22
  */
23
23
  parallel = "parallel"
24
24
  }
25
+ export declare const DEFAULT_REFLECTION_MAX_ITERATIONS = 3;
26
+ /**
27
+ * Configuration for reflection mode processing in TeamAgent.
28
+ *
29
+ * Reflection mode enables iterative refinement of agent outputs through a review process.
30
+ * The team agent will repeatedly process the input and have a reviewer agent evaluate
31
+ * the output until it meets approval criteria or reaches the maximum iteration limit.
32
+ *
33
+ * This is particularly useful for:
34
+ * - Quality assurance workflows where outputs need validation
35
+ * - Iterative improvement processes where initial results can be refined
36
+ * - Self-correcting agent systems that learn from feedback
37
+ */
38
+ export interface ReflectionMode {
39
+ /**
40
+ * The agent responsible for reviewing and providing feedback on the team's output.
41
+ *
42
+ * The reviewer agent receives the combined output from the team's processing
43
+ * and should provide feedback or evaluation that can be used to determine
44
+ * whether the output meets the required standards.
45
+ */
46
+ reviewer: Agent;
47
+ /**
48
+ * Function or field name that determines whether the reviewer's output indicates approval.
49
+ *
50
+ * This can be either:
51
+ * - A function that receives the reviewer agent's output message and should return:
52
+ * - `true` or truthy value: The output is approved and processing should stop
53
+ * - `false` or falsy value: The output needs improvement and another iteration should run
54
+ * - A string representing a field name in the reviewer's output message to check for approval
55
+ *
56
+ * When using a function, it can be synchronous or asynchronous, allowing for complex approval logic
57
+ * including external validation, scoring systems, or human-in-the-loop approval.
58
+ *
59
+ * When using a string, the specified field in the reviewer's output will be evaluated for truthiness
60
+ * to determine approval status.
61
+ *
62
+ * @param output - The message output from the reviewer agent (when using function form)
63
+ * @returns A boolean or truthy/falsy value indicating approval status (when using function form)
64
+ */
65
+ isApproved: ((output: Message) => PromiseOrValue<boolean | unknown>) | string;
66
+ /**
67
+ * Maximum number of reflection iterations before giving up.
68
+ *
69
+ * This prevents infinite loops when the approval criteria cannot be met.
70
+ * If the maximum iterations are reached without approval, the process will
71
+ * throw an error indicating the reflection failed to converge.
72
+ *
73
+ * @default 3
74
+ */
75
+ maxIterations?: number;
76
+ /**
77
+ * Controls the behavior when maximum iterations are reached without approval.
78
+ *
79
+ * When set to `true`, the TeamAgent will return the last generated output
80
+ * instead of throwing an error when the maximum number of reflection iterations
81
+ * is reached without the reviewer's approval.
82
+ *
83
+ * When set to `false` or undefined, the TeamAgent will throw an error
84
+ * indicating that the reflection process failed to converge within the
85
+ * maximum iteration limit.
86
+ *
87
+ * This option is useful for scenarios where:
88
+ * - You want to get the best available result even if it's not perfect
89
+ * - The approval criteria might be too strict for the given context
90
+ * - You prefer graceful degradation over complete failure
91
+ * - You want to implement custom error handling based on the returned result
92
+ *
93
+ * @default false
94
+ */
95
+ returnLastOnMaxIterations?: boolean;
96
+ }
25
97
  /**
26
98
  * Configuration options for creating a TeamAgent.
27
99
  *
@@ -33,6 +105,21 @@ export interface TeamAgentOptions<I extends Message, O extends Message> extends
33
105
  * @default {ProcessMode.sequential}
34
106
  */
35
107
  mode?: ProcessMode;
108
+ /**
109
+ * Configuration for reflection mode processing.
110
+ *
111
+ * When enabled, the TeamAgent will use an iterative refinement process where:
112
+ * 1. The team processes the input normally
113
+ * 2. A reviewer agent evaluates the output
114
+ * 3. If not approved, the process repeats with the previous output as context
115
+ * 4. This continues until approval or maximum iterations are reached
116
+ *
117
+ * This enables self-improving agent workflows that can iteratively refine
118
+ * their outputs based on feedback from a specialized reviewer agent.
119
+ *
120
+ * @see ReflectionMode for detailed configuration options
121
+ */
122
+ reflection?: ReflectionMode;
36
123
  /**
37
124
  * Specifies which input field should be treated as an array for iterative processing.
38
125
  *
@@ -116,6 +203,14 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
116
203
  * This can be either sequential (one after another) or parallel (all at once).
117
204
  */
118
205
  mode: ProcessMode;
206
+ /**
207
+ * The reflection mode configuration with guaranteed maxIterations value.
208
+ *
209
+ * This is the internal representation after processing the user-provided
210
+ * reflection configuration, ensuring that maxIterations always has a value
211
+ * (defaulting to DEFAULT_REFLECTION_MAX_ITERATIONS if not specified).
212
+ */
213
+ reflection?: ReflectionMode & Required<Pick<ReflectionMode, "maxIterations">>;
119
214
  /**
120
215
  * The input field key to iterate over when processing array inputs.
121
216
  *
@@ -148,8 +243,10 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
148
243
  * @returns A stream of message chunks that collectively form the response
149
244
  */
150
245
  process(input: I, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<O>>;
246
+ private _processNonReflection;
247
+ private _processReflection;
151
248
  private _processIterator;
152
- private _process;
249
+ private _processNonIterator;
153
250
  /**
154
251
  * Process input sequentially through each agent in the team.
155
252
  *
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TeamAgent = exports.ProcessMode = void 0;
6
+ exports.TeamAgent = exports.DEFAULT_REFLECTION_MAX_ITERATIONS = exports.ProcessMode = void 0;
7
7
  const node_assert_1 = __importDefault(require("node:assert"));
8
8
  const immer_1 = require("immer");
9
9
  const stream_utils_js_1 = require("../utils/stream-utils.js");
@@ -32,6 +32,7 @@ var ProcessMode;
32
32
  */
33
33
  ProcessMode["parallel"] = "parallel";
34
34
  })(ProcessMode || (exports.ProcessMode = ProcessMode = {}));
35
+ exports.DEFAULT_REFLECTION_MAX_ITERATIONS = 3;
35
36
  /**
36
37
  * TeamAgent coordinates a group of agents working together to accomplish tasks.
37
38
  *
@@ -76,6 +77,10 @@ class TeamAgent extends agent_js_1.Agent {
76
77
  constructor(options) {
77
78
  super(options);
78
79
  this.mode = options.mode ?? ProcessMode.sequential;
80
+ this.reflection = options.reflection && {
81
+ ...options.reflection,
82
+ maxIterations: options.reflection.maxIterations ?? exports.DEFAULT_REFLECTION_MAX_ITERATIONS,
83
+ };
79
84
  this.iterateOn = options.iterateOn;
80
85
  this.iterateWithPreviousOutput = options.iterateWithPreviousOutput;
81
86
  }
@@ -85,6 +90,14 @@ class TeamAgent extends agent_js_1.Agent {
85
90
  * This can be either sequential (one after another) or parallel (all at once).
86
91
  */
87
92
  mode;
93
+ /**
94
+ * The reflection mode configuration with guaranteed maxIterations value.
95
+ *
96
+ * This is the internal representation after processing the user-provided
97
+ * reflection configuration, ensuring that maxIterations always has a value
98
+ * (defaulting to DEFAULT_REFLECTION_MAX_ITERATIONS if not specified).
99
+ */
100
+ reflection;
88
101
  /**
89
102
  * The input field key to iterate over when processing array inputs.
90
103
  *
@@ -119,10 +132,36 @@ class TeamAgent extends agent_js_1.Agent {
119
132
  process(input, options) {
120
133
  if (!this.skills.length)
121
134
  throw new Error("TeamAgent must have at least one skill defined.");
135
+ if (this.reflection)
136
+ return this._processReflection(input, options);
137
+ return this._processNonReflection(input, options);
138
+ }
139
+ _processNonReflection(input, options) {
122
140
  if (this.iterateOn) {
123
141
  return this._processIterator(this.iterateOn, input, options);
124
142
  }
125
- return this._process(input, options);
143
+ return this._processNonIterator(input, options);
144
+ }
145
+ async _processReflection(input, options) {
146
+ (0, node_assert_1.default)(this.reflection, "Reflection mode must be defined for reflection processing");
147
+ let iterations = 0;
148
+ const previousOutput = { ...input };
149
+ for (;;) {
150
+ const output = await (0, agent_js_1.agentProcessResultToObject)(await this._processNonReflection(previousOutput, options));
151
+ Object.assign(previousOutput, output);
152
+ const reviewOutput = await options.context.invoke(this.reflection.reviewer, previousOutput);
153
+ Object.assign(previousOutput, reviewOutput);
154
+ const { isApproved } = this.reflection;
155
+ const approved = typeof isApproved === "string" ? reviewOutput[isApproved] : await isApproved(reviewOutput);
156
+ if (approved)
157
+ return output;
158
+ if (++iterations >= this.reflection.maxIterations) {
159
+ if (this.reflection.returnLastOnMaxIterations)
160
+ return output;
161
+ break;
162
+ }
163
+ }
164
+ throw new Error(`Reflection mode exceeded max iterations ${this.reflection.maxIterations}. Please review the feedback and try again.`);
126
165
  }
127
166
  async *_processIterator(key, input, options) {
128
167
  (0, node_assert_1.default)(this.iterateOn, "iterateInputKey must be defined for iterator processing");
@@ -133,7 +172,7 @@ class TeamAgent extends agent_js_1.Agent {
133
172
  const item = arr[i];
134
173
  if (!(0, type_utils_js_1.isRecord)(item))
135
174
  throw new TypeError(`Expected ${String(key)} to be an object, got ${typeof item}`);
136
- const res = await (0, agent_js_1.agentProcessResultToObject)(await this._process({ ...input, [key]: arr, ...item }, { ...options, streaming: false }));
175
+ const res = await (0, agent_js_1.agentProcessResultToObject)(await this._processNonIterator({ ...input, [key]: arr, ...item }, { ...options, streaming: false }));
137
176
  // Merge the item result with the original item used for next iteration
138
177
  if (this.iterateWithPreviousOutput) {
139
178
  arr = (0, immer_1.produce)(arr, (draft) => {
@@ -146,7 +185,7 @@ class TeamAgent extends agent_js_1.Agent {
146
185
  yield { delta: { json: { [key]: result } } };
147
186
  }
148
187
  }
149
- _process(input, options) {
188
+ _processNonIterator(input, options) {
150
189
  switch (this.mode) {
151
190
  case ProcessMode.sequential:
152
191
  return this._processSequential(input, options);
@@ -1,8 +1,2 @@
1
- import { Agent, type FunctionAgentFn } from "../agents/agent.js";
2
- export declare function loadAgentFromJsFile(path: string): Promise<Agent<any, any> | {
3
- process: FunctionAgentFn;
4
- name: string;
5
- description?: string | undefined;
6
- inputSchema?: any;
7
- outputSchema?: any;
8
- }>;
1
+ import { Agent } from "../agents/agent.js";
2
+ export declare function loadAgentFromJsFile(path: string): Promise<Agent<any, any> | import("./agent-yaml.js").AgentSchema>;
@@ -34,27 +34,19 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.loadAgentFromJsFile = loadAgentFromJsFile;
37
- const json_schema_to_zod_1 = require("@aigne/json-schema-to-zod");
38
- const zod_1 = require("zod");
39
37
  const agent_js_1 = require("../agents/agent.js");
40
38
  const type_utils_js_1 = require("../utils/type-utils.js");
41
- const schema_js_1 = require("./schema.js");
39
+ const agent_yaml_js_1 = require("./agent-yaml.js");
42
40
  async function loadAgentFromJsFile(path) {
43
- const agentJsFileSchema = (0, schema_js_1.camelizeSchema)(zod_1.z.object({
44
- name: zod_1.z.string(),
45
- description: (0, schema_js_1.optionalize)(zod_1.z.string()),
46
- inputSchema: (0, schema_js_1.optionalize)((0, schema_js_1.inputOutputSchema)({ path })).transform((v) => v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined),
47
- outputSchema: (0, schema_js_1.optionalize)((0, schema_js_1.inputOutputSchema)({ path })).transform((v) => v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined),
48
- process: zod_1.z.custom(),
49
- }));
50
41
  const { default: agent } = await (0, type_utils_js_1.tryOrThrow)(() => Promise.resolve(`${path}`).then(s => __importStar(require(s))), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
51
42
  if (agent instanceof agent_js_1.Agent)
52
43
  return agent;
53
44
  if (typeof agent !== "function") {
54
45
  throw new Error(`Agent file ${path} must export a default function, but got ${typeof agent}`);
55
46
  }
56
- return (0, type_utils_js_1.tryOrThrow)(() => agentJsFileSchema.parseAsync({
47
+ return (0, type_utils_js_1.tryOrThrow)(() => (0, agent_yaml_js_1.parseAgentFile)(path, {
57
48
  ...agent,
49
+ type: "function",
58
50
  name: agent.agent_name || agent.agentName || agent.name,
59
51
  process: agent,
60
52
  }), (error) => new Error(`Failed to parse agent from ${path}: ${error.message}`));
@@ -1,6 +1,7 @@
1
1
  import { type ZodType } from "zod";
2
+ import type { FunctionAgentFn } from "../agents/agent.js";
2
3
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
3
- import { ProcessMode } from "../agents/team-agent.js";
4
+ import { ProcessMode, type ReflectionMode } from "../agents/team-agent.js";
4
5
  export interface HooksSchema {
5
6
  onStart?: NestAgentSchema;
6
7
  onSuccess?: NestAgentSchema;
@@ -15,7 +16,7 @@ export type NestAgentSchema = string | {
15
16
  defaultInput?: Record<string, any>;
16
17
  hooks?: HooksSchema | HooksSchema[];
17
18
  } | AgentSchema;
18
- interface BaseAgentSchema {
19
+ export interface BaseAgentSchema {
19
20
  name?: string;
20
21
  description?: string;
21
22
  inputSchema?: ZodType<Record<string, any>>;
@@ -28,28 +29,35 @@ interface BaseAgentSchema {
28
29
  subscribeTopic?: string[];
29
30
  };
30
31
  }
31
- interface AIAgentSchema extends BaseAgentSchema {
32
+ export interface AIAgentSchema extends BaseAgentSchema {
32
33
  type: "ai";
33
34
  instructions?: string;
34
35
  inputKey?: string;
35
36
  outputKey?: string;
36
37
  toolChoice?: AIAgentToolChoice;
37
38
  }
38
- interface MCPAgentSchema extends BaseAgentSchema {
39
+ export interface MCPAgentSchema extends BaseAgentSchema {
39
40
  type: "mcp";
40
41
  url?: string;
41
42
  command?: string;
42
43
  args?: string[];
43
44
  }
44
- interface TeamAgentSchema extends BaseAgentSchema {
45
+ export interface TeamAgentSchema extends BaseAgentSchema {
45
46
  type: "team";
46
47
  mode?: ProcessMode;
47
48
  iterateOn?: string;
49
+ reflection?: Omit<ReflectionMode, "reviewer"> & {
50
+ reviewer: NestAgentSchema;
51
+ };
48
52
  }
49
- interface TransformAgentSchema extends BaseAgentSchema {
53
+ export interface TransformAgentSchema extends BaseAgentSchema {
50
54
  type: "transform";
51
55
  jsonata: string;
52
56
  }
53
- type AgentSchema = AIAgentSchema | MCPAgentSchema | TeamAgentSchema | TransformAgentSchema;
57
+ export interface FunctionAgentSchema extends BaseAgentSchema {
58
+ type: "function";
59
+ process: FunctionAgentFn;
60
+ }
61
+ export type AgentSchema = AIAgentSchema | MCPAgentSchema | TeamAgentSchema | TransformAgentSchema | FunctionAgentSchema;
62
+ export declare function parseAgentFile(path: string, data: object): Promise<AgentSchema>;
54
63
  export declare function loadAgentFromYamlFile(path: string): Promise<AgentSchema>;
55
- export {};
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseAgentFile = parseAgentFile;
3
4
  exports.loadAgentFromYamlFile = loadAgentFromYamlFile;
4
5
  const json_schema_to_zod_1 = require("@aigne/json-schema-to-zod");
5
6
  const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
@@ -9,7 +10,7 @@ const ai_agent_js_1 = require("../agents/ai-agent.js");
9
10
  const team_agent_js_1 = require("../agents/team-agent.js");
10
11
  const type_utils_js_1 = require("../utils/type-utils.js");
11
12
  const schema_js_1 = require("./schema.js");
12
- async function loadAgentFromYamlFile(path) {
13
+ async function parseAgentFile(path, data) {
13
14
  const agentSchema = zod_1.z.lazy(() => {
14
15
  const nestAgentSchema = zod_1.z.lazy(() => zod_1.z.union([
15
16
  agentSchema,
@@ -76,6 +77,12 @@ async function loadAgentFromYamlFile(path) {
76
77
  type: zod_1.z.literal("team"),
77
78
  mode: (0, schema_js_1.optionalize)(zod_1.z.nativeEnum(team_agent_js_1.ProcessMode)),
78
79
  iterateOn: (0, schema_js_1.optionalize)(zod_1.z.string()),
80
+ reflection: (0, schema_js_1.camelizeSchema)((0, schema_js_1.optionalize)(zod_1.z.object({
81
+ reviewer: nestAgentSchema,
82
+ isApproved: zod_1.z.string(),
83
+ maxIterations: (0, schema_js_1.optionalize)(zod_1.z.number().int().min(1)),
84
+ returnLastOnMaxIterations: (0, schema_js_1.optionalize)(zod_1.z.boolean()),
85
+ }))),
79
86
  })
80
87
  .extend(baseAgentSchema.shape),
81
88
  zod_1.z
@@ -84,11 +91,20 @@ async function loadAgentFromYamlFile(path) {
84
91
  jsonata: zod_1.z.string(),
85
92
  })
86
93
  .extend(baseAgentSchema.shape),
94
+ zod_1.z
95
+ .object({
96
+ type: zod_1.z.literal("function"),
97
+ process: zod_1.z.custom(),
98
+ })
99
+ .extend(baseAgentSchema.shape),
87
100
  ]));
88
101
  });
102
+ return agentSchema.parseAsync(data);
103
+ }
104
+ async function loadAgentFromYamlFile(path) {
89
105
  const raw = await (0, type_utils_js_1.tryOrThrow)(() => index_js_1.nodejs.fs.readFile(path, "utf8"), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
90
106
  const json = (0, type_utils_js_1.tryOrThrow)(() => (0, yaml_1.parse)(raw), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
91
- const agent = await (0, type_utils_js_1.tryOrThrow)(async () => await agentSchema.parseAsync({
107
+ const agent = await (0, type_utils_js_1.tryOrThrow)(async () => await parseAgentFile(path, {
92
108
  ...json,
93
109
  type: json.type ?? "ai",
94
110
  skills: json.skills ?? json.tools,
@@ -12,9 +12,12 @@ interface LoadableModelClass {
12
12
  }
13
13
  export interface LoadableModel {
14
14
  name: string;
15
+ apiKeyEnvName?: string;
15
16
  create: (options: {
16
17
  model?: string;
17
18
  modelOptions?: ChatModelOptions;
19
+ accessKey?: string;
20
+ url?: string;
18
21
  }) => ChatModel;
19
22
  }
20
23
  export interface LoadOptions {
@@ -26,7 +29,10 @@ export interface LoadOptions {
26
29
  }
27
30
  export declare function load(options: LoadOptions): Promise<AIGNEOptions>;
28
31
  export declare function loadAgent(path: string, options?: LoadOptions, agentOptions?: AgentOptions): Promise<Agent>;
29
- export declare function loadModel(models: LoadableModel[], model?: Camelize<z.infer<typeof aigneFileSchema>["model"]>, modelOptions?: ChatModelOptions): Promise<ChatModel | undefined>;
32
+ export declare function loadModel(models: LoadableModel[], model?: Camelize<z.infer<typeof aigneFileSchema>["model"]>, modelOptions?: ChatModelOptions, accessKeyOptions?: {
33
+ accessKey?: string;
34
+ url?: string;
35
+ }): Promise<ChatModel | undefined>;
30
36
  declare const aigneFileSchema: z.ZodObject<{
31
37
  name: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
32
38
  description: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
@@ -44,7 +44,7 @@ async function loadAgent(path, options, agentOptions) {
44
44
  const agent = await (0, agent_js_js_1.loadAgentFromJsFile)(path);
45
45
  if (agent instanceof agent_js_1.Agent)
46
46
  return agent;
47
- return agent_js_1.FunctionAgent.from(agent);
47
+ return parseAgent(path, agent, options, agentOptions);
48
48
  }
49
49
  if ([".yml", ".yaml"].includes(index_js_1.nodejs.path.extname(path))) {
50
50
  const agent = await (0, agent_yaml_js_1.loadAgentFromYamlFile)(path);
@@ -125,6 +125,12 @@ async function parseAgent(path, agent, options, agentOptions) {
125
125
  case "team": {
126
126
  return team_agent_js_1.TeamAgent.from({
127
127
  ...baseOptions,
128
+ mode: agent.mode,
129
+ iterateOn: agent.iterateOn,
130
+ reflection: agent.reflection && {
131
+ ...agent.reflection,
132
+ reviewer: await loadNestAgent(path, agent.reflection.reviewer, options),
133
+ },
128
134
  });
129
135
  }
130
136
  case "transform": {
@@ -133,6 +139,12 @@ async function parseAgent(path, agent, options, agentOptions) {
133
139
  jsonata: agent.jsonata,
134
140
  });
135
141
  }
142
+ case "function": {
143
+ return agent_js_1.FunctionAgent.from({
144
+ ...baseOptions,
145
+ process: agent.process,
146
+ });
147
+ }
136
148
  }
137
149
  }
138
150
  async function loadMemory(memories, provider, options) {
@@ -145,7 +157,7 @@ async function loadMemory(memories, provider, options) {
145
157
  }
146
158
  const { MODEL_PROVIDER, MODEL_NAME } = index_js_1.nodejs.env;
147
159
  const DEFAULT_MODEL_PROVIDER = "openai";
148
- async function loadModel(models, model, modelOptions) {
160
+ async function loadModel(models, model, modelOptions, accessKeyOptions) {
149
161
  const params = {
150
162
  model: MODEL_NAME ?? model?.name ?? undefined,
151
163
  temperature: model?.temperature ?? undefined,
@@ -153,12 +165,13 @@ async function loadModel(models, model, modelOptions) {
153
165
  frequencyPenalty: model?.frequencyPenalty ?? undefined,
154
166
  presencePenalty: model?.presencePenalty ?? undefined,
155
167
  };
156
- const m = models.find((m) => m.name
157
- .toLowerCase()
158
- .includes((MODEL_PROVIDER ?? model?.provider ?? DEFAULT_MODEL_PROVIDER).toLowerCase()));
168
+ const providerName = MODEL_PROVIDER ?? model?.provider ?? DEFAULT_MODEL_PROVIDER;
169
+ const provider = providerName.replace(/-/g, "");
170
+ const m = models.find((m) => m.name.toLowerCase().includes(provider.toLowerCase()));
159
171
  if (!m)
160
172
  throw new Error(`Unsupported model: ${model?.provider} ${model?.name}`);
161
173
  return m.create({
174
+ ...(accessKeyOptions || {}),
162
175
  model: params.model,
163
176
  modelOptions: { ...params, ...modelOptions },
164
177
  });
@@ -22,6 +22,78 @@ export declare enum ProcessMode {
22
22
  */
23
23
  parallel = "parallel"
24
24
  }
25
+ export declare const DEFAULT_REFLECTION_MAX_ITERATIONS = 3;
26
+ /**
27
+ * Configuration for reflection mode processing in TeamAgent.
28
+ *
29
+ * Reflection mode enables iterative refinement of agent outputs through a review process.
30
+ * The team agent will repeatedly process the input and have a reviewer agent evaluate
31
+ * the output until it meets approval criteria or reaches the maximum iteration limit.
32
+ *
33
+ * This is particularly useful for:
34
+ * - Quality assurance workflows where outputs need validation
35
+ * - Iterative improvement processes where initial results can be refined
36
+ * - Self-correcting agent systems that learn from feedback
37
+ */
38
+ export interface ReflectionMode {
39
+ /**
40
+ * The agent responsible for reviewing and providing feedback on the team's output.
41
+ *
42
+ * The reviewer agent receives the combined output from the team's processing
43
+ * and should provide feedback or evaluation that can be used to determine
44
+ * whether the output meets the required standards.
45
+ */
46
+ reviewer: Agent;
47
+ /**
48
+ * Function or field name that determines whether the reviewer's output indicates approval.
49
+ *
50
+ * This can be either:
51
+ * - A function that receives the reviewer agent's output message and should return:
52
+ * - `true` or truthy value: The output is approved and processing should stop
53
+ * - `false` or falsy value: The output needs improvement and another iteration should run
54
+ * - A string representing a field name in the reviewer's output message to check for approval
55
+ *
56
+ * When using a function, it can be synchronous or asynchronous, allowing for complex approval logic
57
+ * including external validation, scoring systems, or human-in-the-loop approval.
58
+ *
59
+ * When using a string, the specified field in the reviewer's output will be evaluated for truthiness
60
+ * to determine approval status.
61
+ *
62
+ * @param output - The message output from the reviewer agent (when using function form)
63
+ * @returns A boolean or truthy/falsy value indicating approval status (when using function form)
64
+ */
65
+ isApproved: ((output: Message) => PromiseOrValue<boolean | unknown>) | string;
66
+ /**
67
+ * Maximum number of reflection iterations before giving up.
68
+ *
69
+ * This prevents infinite loops when the approval criteria cannot be met.
70
+ * If the maximum iterations are reached without approval, the process will
71
+ * throw an error indicating the reflection failed to converge.
72
+ *
73
+ * @default 3
74
+ */
75
+ maxIterations?: number;
76
+ /**
77
+ * Controls the behavior when maximum iterations are reached without approval.
78
+ *
79
+ * When set to `true`, the TeamAgent will return the last generated output
80
+ * instead of throwing an error when the maximum number of reflection iterations
81
+ * is reached without the reviewer's approval.
82
+ *
83
+ * When set to `false` or undefined, the TeamAgent will throw an error
84
+ * indicating that the reflection process failed to converge within the
85
+ * maximum iteration limit.
86
+ *
87
+ * This option is useful for scenarios where:
88
+ * - You want to get the best available result even if it's not perfect
89
+ * - The approval criteria might be too strict for the given context
90
+ * - You prefer graceful degradation over complete failure
91
+ * - You want to implement custom error handling based on the returned result
92
+ *
93
+ * @default false
94
+ */
95
+ returnLastOnMaxIterations?: boolean;
96
+ }
25
97
  /**
26
98
  * Configuration options for creating a TeamAgent.
27
99
  *
@@ -33,6 +105,21 @@ export interface TeamAgentOptions<I extends Message, O extends Message> extends
33
105
  * @default {ProcessMode.sequential}
34
106
  */
35
107
  mode?: ProcessMode;
108
+ /**
109
+ * Configuration for reflection mode processing.
110
+ *
111
+ * When enabled, the TeamAgent will use an iterative refinement process where:
112
+ * 1. The team processes the input normally
113
+ * 2. A reviewer agent evaluates the output
114
+ * 3. If not approved, the process repeats with the previous output as context
115
+ * 4. This continues until approval or maximum iterations are reached
116
+ *
117
+ * This enables self-improving agent workflows that can iteratively refine
118
+ * their outputs based on feedback from a specialized reviewer agent.
119
+ *
120
+ * @see ReflectionMode for detailed configuration options
121
+ */
122
+ reflection?: ReflectionMode;
36
123
  /**
37
124
  * Specifies which input field should be treated as an array for iterative processing.
38
125
  *
@@ -116,6 +203,14 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
116
203
  * This can be either sequential (one after another) or parallel (all at once).
117
204
  */
118
205
  mode: ProcessMode;
206
+ /**
207
+ * The reflection mode configuration with guaranteed maxIterations value.
208
+ *
209
+ * This is the internal representation after processing the user-provided
210
+ * reflection configuration, ensuring that maxIterations always has a value
211
+ * (defaulting to DEFAULT_REFLECTION_MAX_ITERATIONS if not specified).
212
+ */
213
+ reflection?: ReflectionMode & Required<Pick<ReflectionMode, "maxIterations">>;
119
214
  /**
120
215
  * The input field key to iterate over when processing array inputs.
121
216
  *
@@ -148,8 +243,10 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
148
243
  * @returns A stream of message chunks that collectively form the response
149
244
  */
150
245
  process(input: I, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<O>>;
246
+ private _processNonReflection;
247
+ private _processReflection;
151
248
  private _processIterator;
152
- private _process;
249
+ private _processNonIterator;
153
250
  /**
154
251
  * Process input sequentially through each agent in the team.
155
252
  *
@@ -1,8 +1,2 @@
1
- import { Agent, type FunctionAgentFn } from "../agents/agent.js";
2
- export declare function loadAgentFromJsFile(path: string): Promise<Agent<any, any> | {
3
- process: FunctionAgentFn;
4
- name: string;
5
- description?: string | undefined;
6
- inputSchema?: any;
7
- outputSchema?: any;
8
- }>;
1
+ import { Agent } from "../agents/agent.js";
2
+ export declare function loadAgentFromJsFile(path: string): Promise<Agent<any, any> | import("./agent-yaml.js").AgentSchema>;
@@ -1,6 +1,7 @@
1
1
  import { type ZodType } from "zod";
2
+ import type { FunctionAgentFn } from "../agents/agent.js";
2
3
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
3
- import { ProcessMode } from "../agents/team-agent.js";
4
+ import { ProcessMode, type ReflectionMode } from "../agents/team-agent.js";
4
5
  export interface HooksSchema {
5
6
  onStart?: NestAgentSchema;
6
7
  onSuccess?: NestAgentSchema;
@@ -15,7 +16,7 @@ export type NestAgentSchema = string | {
15
16
  defaultInput?: Record<string, any>;
16
17
  hooks?: HooksSchema | HooksSchema[];
17
18
  } | AgentSchema;
18
- interface BaseAgentSchema {
19
+ export interface BaseAgentSchema {
19
20
  name?: string;
20
21
  description?: string;
21
22
  inputSchema?: ZodType<Record<string, any>>;
@@ -28,28 +29,35 @@ interface BaseAgentSchema {
28
29
  subscribeTopic?: string[];
29
30
  };
30
31
  }
31
- interface AIAgentSchema extends BaseAgentSchema {
32
+ export interface AIAgentSchema extends BaseAgentSchema {
32
33
  type: "ai";
33
34
  instructions?: string;
34
35
  inputKey?: string;
35
36
  outputKey?: string;
36
37
  toolChoice?: AIAgentToolChoice;
37
38
  }
38
- interface MCPAgentSchema extends BaseAgentSchema {
39
+ export interface MCPAgentSchema extends BaseAgentSchema {
39
40
  type: "mcp";
40
41
  url?: string;
41
42
  command?: string;
42
43
  args?: string[];
43
44
  }
44
- interface TeamAgentSchema extends BaseAgentSchema {
45
+ export interface TeamAgentSchema extends BaseAgentSchema {
45
46
  type: "team";
46
47
  mode?: ProcessMode;
47
48
  iterateOn?: string;
49
+ reflection?: Omit<ReflectionMode, "reviewer"> & {
50
+ reviewer: NestAgentSchema;
51
+ };
48
52
  }
49
- interface TransformAgentSchema extends BaseAgentSchema {
53
+ export interface TransformAgentSchema extends BaseAgentSchema {
50
54
  type: "transform";
51
55
  jsonata: string;
52
56
  }
53
- type AgentSchema = AIAgentSchema | MCPAgentSchema | TeamAgentSchema | TransformAgentSchema;
57
+ export interface FunctionAgentSchema extends BaseAgentSchema {
58
+ type: "function";
59
+ process: FunctionAgentFn;
60
+ }
61
+ export type AgentSchema = AIAgentSchema | MCPAgentSchema | TeamAgentSchema | TransformAgentSchema | FunctionAgentSchema;
62
+ export declare function parseAgentFile(path: string, data: object): Promise<AgentSchema>;
54
63
  export declare function loadAgentFromYamlFile(path: string): Promise<AgentSchema>;
55
- export {};
@@ -12,9 +12,12 @@ interface LoadableModelClass {
12
12
  }
13
13
  export interface LoadableModel {
14
14
  name: string;
15
+ apiKeyEnvName?: string;
15
16
  create: (options: {
16
17
  model?: string;
17
18
  modelOptions?: ChatModelOptions;
19
+ accessKey?: string;
20
+ url?: string;
18
21
  }) => ChatModel;
19
22
  }
20
23
  export interface LoadOptions {
@@ -26,7 +29,10 @@ export interface LoadOptions {
26
29
  }
27
30
  export declare function load(options: LoadOptions): Promise<AIGNEOptions>;
28
31
  export declare function loadAgent(path: string, options?: LoadOptions, agentOptions?: AgentOptions): Promise<Agent>;
29
- export declare function loadModel(models: LoadableModel[], model?: Camelize<z.infer<typeof aigneFileSchema>["model"]>, modelOptions?: ChatModelOptions): Promise<ChatModel | undefined>;
32
+ export declare function loadModel(models: LoadableModel[], model?: Camelize<z.infer<typeof aigneFileSchema>["model"]>, modelOptions?: ChatModelOptions, accessKeyOptions?: {
33
+ accessKey?: string;
34
+ url?: string;
35
+ }): Promise<ChatModel | undefined>;
30
36
  declare const aigneFileSchema: z.ZodObject<{
31
37
  name: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
32
38
  description: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
@@ -22,6 +22,78 @@ export declare enum ProcessMode {
22
22
  */
23
23
  parallel = "parallel"
24
24
  }
25
+ export declare const DEFAULT_REFLECTION_MAX_ITERATIONS = 3;
26
+ /**
27
+ * Configuration for reflection mode processing in TeamAgent.
28
+ *
29
+ * Reflection mode enables iterative refinement of agent outputs through a review process.
30
+ * The team agent will repeatedly process the input and have a reviewer agent evaluate
31
+ * the output until it meets approval criteria or reaches the maximum iteration limit.
32
+ *
33
+ * This is particularly useful for:
34
+ * - Quality assurance workflows where outputs need validation
35
+ * - Iterative improvement processes where initial results can be refined
36
+ * - Self-correcting agent systems that learn from feedback
37
+ */
38
+ export interface ReflectionMode {
39
+ /**
40
+ * The agent responsible for reviewing and providing feedback on the team's output.
41
+ *
42
+ * The reviewer agent receives the combined output from the team's processing
43
+ * and should provide feedback or evaluation that can be used to determine
44
+ * whether the output meets the required standards.
45
+ */
46
+ reviewer: Agent;
47
+ /**
48
+ * Function or field name that determines whether the reviewer's output indicates approval.
49
+ *
50
+ * This can be either:
51
+ * - A function that receives the reviewer agent's output message and should return:
52
+ * - `true` or truthy value: The output is approved and processing should stop
53
+ * - `false` or falsy value: The output needs improvement and another iteration should run
54
+ * - A string representing a field name in the reviewer's output message to check for approval
55
+ *
56
+ * When using a function, it can be synchronous or asynchronous, allowing for complex approval logic
57
+ * including external validation, scoring systems, or human-in-the-loop approval.
58
+ *
59
+ * When using a string, the specified field in the reviewer's output will be evaluated for truthiness
60
+ * to determine approval status.
61
+ *
62
+ * @param output - The message output from the reviewer agent (when using function form)
63
+ * @returns A boolean or truthy/falsy value indicating approval status (when using function form)
64
+ */
65
+ isApproved: ((output: Message) => PromiseOrValue<boolean | unknown>) | string;
66
+ /**
67
+ * Maximum number of reflection iterations before giving up.
68
+ *
69
+ * This prevents infinite loops when the approval criteria cannot be met.
70
+ * If the maximum iterations are reached without approval, the process will
71
+ * throw an error indicating the reflection failed to converge.
72
+ *
73
+ * @default 3
74
+ */
75
+ maxIterations?: number;
76
+ /**
77
+ * Controls the behavior when maximum iterations are reached without approval.
78
+ *
79
+ * When set to `true`, the TeamAgent will return the last generated output
80
+ * instead of throwing an error when the maximum number of reflection iterations
81
+ * is reached without the reviewer's approval.
82
+ *
83
+ * When set to `false` or undefined, the TeamAgent will throw an error
84
+ * indicating that the reflection process failed to converge within the
85
+ * maximum iteration limit.
86
+ *
87
+ * This option is useful for scenarios where:
88
+ * - You want to get the best available result even if it's not perfect
89
+ * - The approval criteria might be too strict for the given context
90
+ * - You prefer graceful degradation over complete failure
91
+ * - You want to implement custom error handling based on the returned result
92
+ *
93
+ * @default false
94
+ */
95
+ returnLastOnMaxIterations?: boolean;
96
+ }
25
97
  /**
26
98
  * Configuration options for creating a TeamAgent.
27
99
  *
@@ -33,6 +105,21 @@ export interface TeamAgentOptions<I extends Message, O extends Message> extends
33
105
  * @default {ProcessMode.sequential}
34
106
  */
35
107
  mode?: ProcessMode;
108
+ /**
109
+ * Configuration for reflection mode processing.
110
+ *
111
+ * When enabled, the TeamAgent will use an iterative refinement process where:
112
+ * 1. The team processes the input normally
113
+ * 2. A reviewer agent evaluates the output
114
+ * 3. If not approved, the process repeats with the previous output as context
115
+ * 4. This continues until approval or maximum iterations are reached
116
+ *
117
+ * This enables self-improving agent workflows that can iteratively refine
118
+ * their outputs based on feedback from a specialized reviewer agent.
119
+ *
120
+ * @see ReflectionMode for detailed configuration options
121
+ */
122
+ reflection?: ReflectionMode;
36
123
  /**
37
124
  * Specifies which input field should be treated as an array for iterative processing.
38
125
  *
@@ -116,6 +203,14 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
116
203
  * This can be either sequential (one after another) or parallel (all at once).
117
204
  */
118
205
  mode: ProcessMode;
206
+ /**
207
+ * The reflection mode configuration with guaranteed maxIterations value.
208
+ *
209
+ * This is the internal representation after processing the user-provided
210
+ * reflection configuration, ensuring that maxIterations always has a value
211
+ * (defaulting to DEFAULT_REFLECTION_MAX_ITERATIONS if not specified).
212
+ */
213
+ reflection?: ReflectionMode & Required<Pick<ReflectionMode, "maxIterations">>;
119
214
  /**
120
215
  * The input field key to iterate over when processing array inputs.
121
216
  *
@@ -148,8 +243,10 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
148
243
  * @returns A stream of message chunks that collectively form the response
149
244
  */
150
245
  process(input: I, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<O>>;
246
+ private _processNonReflection;
247
+ private _processReflection;
151
248
  private _processIterator;
152
- private _process;
249
+ private _processNonIterator;
153
250
  /**
154
251
  * Process input sequentially through each agent in the team.
155
252
  *
@@ -26,6 +26,7 @@ export var ProcessMode;
26
26
  */
27
27
  ProcessMode["parallel"] = "parallel";
28
28
  })(ProcessMode || (ProcessMode = {}));
29
+ export const DEFAULT_REFLECTION_MAX_ITERATIONS = 3;
29
30
  /**
30
31
  * TeamAgent coordinates a group of agents working together to accomplish tasks.
31
32
  *
@@ -70,6 +71,10 @@ export class TeamAgent extends Agent {
70
71
  constructor(options) {
71
72
  super(options);
72
73
  this.mode = options.mode ?? ProcessMode.sequential;
74
+ this.reflection = options.reflection && {
75
+ ...options.reflection,
76
+ maxIterations: options.reflection.maxIterations ?? DEFAULT_REFLECTION_MAX_ITERATIONS,
77
+ };
73
78
  this.iterateOn = options.iterateOn;
74
79
  this.iterateWithPreviousOutput = options.iterateWithPreviousOutput;
75
80
  }
@@ -79,6 +84,14 @@ export class TeamAgent extends Agent {
79
84
  * This can be either sequential (one after another) or parallel (all at once).
80
85
  */
81
86
  mode;
87
+ /**
88
+ * The reflection mode configuration with guaranteed maxIterations value.
89
+ *
90
+ * This is the internal representation after processing the user-provided
91
+ * reflection configuration, ensuring that maxIterations always has a value
92
+ * (defaulting to DEFAULT_REFLECTION_MAX_ITERATIONS if not specified).
93
+ */
94
+ reflection;
82
95
  /**
83
96
  * The input field key to iterate over when processing array inputs.
84
97
  *
@@ -113,10 +126,36 @@ export class TeamAgent extends Agent {
113
126
  process(input, options) {
114
127
  if (!this.skills.length)
115
128
  throw new Error("TeamAgent must have at least one skill defined.");
129
+ if (this.reflection)
130
+ return this._processReflection(input, options);
131
+ return this._processNonReflection(input, options);
132
+ }
133
+ _processNonReflection(input, options) {
116
134
  if (this.iterateOn) {
117
135
  return this._processIterator(this.iterateOn, input, options);
118
136
  }
119
- return this._process(input, options);
137
+ return this._processNonIterator(input, options);
138
+ }
139
+ async _processReflection(input, options) {
140
+ assert(this.reflection, "Reflection mode must be defined for reflection processing");
141
+ let iterations = 0;
142
+ const previousOutput = { ...input };
143
+ for (;;) {
144
+ const output = await agentProcessResultToObject(await this._processNonReflection(previousOutput, options));
145
+ Object.assign(previousOutput, output);
146
+ const reviewOutput = await options.context.invoke(this.reflection.reviewer, previousOutput);
147
+ Object.assign(previousOutput, reviewOutput);
148
+ const { isApproved } = this.reflection;
149
+ const approved = typeof isApproved === "string" ? reviewOutput[isApproved] : await isApproved(reviewOutput);
150
+ if (approved)
151
+ return output;
152
+ if (++iterations >= this.reflection.maxIterations) {
153
+ if (this.reflection.returnLastOnMaxIterations)
154
+ return output;
155
+ break;
156
+ }
157
+ }
158
+ throw new Error(`Reflection mode exceeded max iterations ${this.reflection.maxIterations}. Please review the feedback and try again.`);
120
159
  }
121
160
  async *_processIterator(key, input, options) {
122
161
  assert(this.iterateOn, "iterateInputKey must be defined for iterator processing");
@@ -127,7 +166,7 @@ export class TeamAgent extends Agent {
127
166
  const item = arr[i];
128
167
  if (!isRecord(item))
129
168
  throw new TypeError(`Expected ${String(key)} to be an object, got ${typeof item}`);
130
- const res = await agentProcessResultToObject(await this._process({ ...input, [key]: arr, ...item }, { ...options, streaming: false }));
169
+ const res = await agentProcessResultToObject(await this._processNonIterator({ ...input, [key]: arr, ...item }, { ...options, streaming: false }));
131
170
  // Merge the item result with the original item used for next iteration
132
171
  if (this.iterateWithPreviousOutput) {
133
172
  arr = produce(arr, (draft) => {
@@ -140,7 +179,7 @@ export class TeamAgent extends Agent {
140
179
  yield { delta: { json: { [key]: result } } };
141
180
  }
142
181
  }
143
- _process(input, options) {
182
+ _processNonIterator(input, options) {
144
183
  switch (this.mode) {
145
184
  case ProcessMode.sequential:
146
185
  return this._processSequential(input, options);
@@ -1,8 +1,2 @@
1
- import { Agent, type FunctionAgentFn } from "../agents/agent.js";
2
- export declare function loadAgentFromJsFile(path: string): Promise<Agent<any, any> | {
3
- process: FunctionAgentFn;
4
- name: string;
5
- description?: string | undefined;
6
- inputSchema?: any;
7
- outputSchema?: any;
8
- }>;
1
+ import { Agent } from "../agents/agent.js";
2
+ export declare function loadAgentFromJsFile(path: string): Promise<Agent<any, any> | import("./agent-yaml.js").AgentSchema>;
@@ -1,24 +1,16 @@
1
- import { jsonSchemaToZod } from "@aigne/json-schema-to-zod";
2
- import { z } from "zod";
3
1
  import { Agent } from "../agents/agent.js";
4
2
  import { tryOrThrow } from "../utils/type-utils.js";
5
- import { camelizeSchema, inputOutputSchema, optionalize } from "./schema.js";
3
+ import { parseAgentFile } from "./agent-yaml.js";
6
4
  export async function loadAgentFromJsFile(path) {
7
- const agentJsFileSchema = camelizeSchema(z.object({
8
- name: z.string(),
9
- description: optionalize(z.string()),
10
- inputSchema: optionalize(inputOutputSchema({ path })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
11
- outputSchema: optionalize(inputOutputSchema({ path })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
12
- process: z.custom(),
13
- }));
14
5
  const { default: agent } = await tryOrThrow(() => import(/* @vite-ignore */ path), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
15
6
  if (agent instanceof Agent)
16
7
  return agent;
17
8
  if (typeof agent !== "function") {
18
9
  throw new Error(`Agent file ${path} must export a default function, but got ${typeof agent}`);
19
10
  }
20
- return tryOrThrow(() => agentJsFileSchema.parseAsync({
11
+ return tryOrThrow(() => parseAgentFile(path, {
21
12
  ...agent,
13
+ type: "function",
22
14
  name: agent.agent_name || agent.agentName || agent.name,
23
15
  process: agent,
24
16
  }), (error) => new Error(`Failed to parse agent from ${path}: ${error.message}`));
@@ -1,6 +1,7 @@
1
1
  import { type ZodType } from "zod";
2
+ import type { FunctionAgentFn } from "../agents/agent.js";
2
3
  import { AIAgentToolChoice } from "../agents/ai-agent.js";
3
- import { ProcessMode } from "../agents/team-agent.js";
4
+ import { ProcessMode, type ReflectionMode } from "../agents/team-agent.js";
4
5
  export interface HooksSchema {
5
6
  onStart?: NestAgentSchema;
6
7
  onSuccess?: NestAgentSchema;
@@ -15,7 +16,7 @@ export type NestAgentSchema = string | {
15
16
  defaultInput?: Record<string, any>;
16
17
  hooks?: HooksSchema | HooksSchema[];
17
18
  } | AgentSchema;
18
- interface BaseAgentSchema {
19
+ export interface BaseAgentSchema {
19
20
  name?: string;
20
21
  description?: string;
21
22
  inputSchema?: ZodType<Record<string, any>>;
@@ -28,28 +29,35 @@ interface BaseAgentSchema {
28
29
  subscribeTopic?: string[];
29
30
  };
30
31
  }
31
- interface AIAgentSchema extends BaseAgentSchema {
32
+ export interface AIAgentSchema extends BaseAgentSchema {
32
33
  type: "ai";
33
34
  instructions?: string;
34
35
  inputKey?: string;
35
36
  outputKey?: string;
36
37
  toolChoice?: AIAgentToolChoice;
37
38
  }
38
- interface MCPAgentSchema extends BaseAgentSchema {
39
+ export interface MCPAgentSchema extends BaseAgentSchema {
39
40
  type: "mcp";
40
41
  url?: string;
41
42
  command?: string;
42
43
  args?: string[];
43
44
  }
44
- interface TeamAgentSchema extends BaseAgentSchema {
45
+ export interface TeamAgentSchema extends BaseAgentSchema {
45
46
  type: "team";
46
47
  mode?: ProcessMode;
47
48
  iterateOn?: string;
49
+ reflection?: Omit<ReflectionMode, "reviewer"> & {
50
+ reviewer: NestAgentSchema;
51
+ };
48
52
  }
49
- interface TransformAgentSchema extends BaseAgentSchema {
53
+ export interface TransformAgentSchema extends BaseAgentSchema {
50
54
  type: "transform";
51
55
  jsonata: string;
52
56
  }
53
- type AgentSchema = AIAgentSchema | MCPAgentSchema | TeamAgentSchema | TransformAgentSchema;
57
+ export interface FunctionAgentSchema extends BaseAgentSchema {
58
+ type: "function";
59
+ process: FunctionAgentFn;
60
+ }
61
+ export type AgentSchema = AIAgentSchema | MCPAgentSchema | TeamAgentSchema | TransformAgentSchema | FunctionAgentSchema;
62
+ export declare function parseAgentFile(path: string, data: object): Promise<AgentSchema>;
54
63
  export declare function loadAgentFromYamlFile(path: string): Promise<AgentSchema>;
55
- export {};
@@ -6,7 +6,7 @@ import { AIAgentToolChoice } from "../agents/ai-agent.js";
6
6
  import { ProcessMode } from "../agents/team-agent.js";
7
7
  import { tryOrThrow } from "../utils/type-utils.js";
8
8
  import { camelizeSchema, defaultInputSchema, inputOutputSchema, optionalize } from "./schema.js";
9
- export async function loadAgentFromYamlFile(path) {
9
+ export async function parseAgentFile(path, data) {
10
10
  const agentSchema = z.lazy(() => {
11
11
  const nestAgentSchema = z.lazy(() => z.union([
12
12
  agentSchema,
@@ -73,6 +73,12 @@ export async function loadAgentFromYamlFile(path) {
73
73
  type: z.literal("team"),
74
74
  mode: optionalize(z.nativeEnum(ProcessMode)),
75
75
  iterateOn: optionalize(z.string()),
76
+ reflection: camelizeSchema(optionalize(z.object({
77
+ reviewer: nestAgentSchema,
78
+ isApproved: z.string(),
79
+ maxIterations: optionalize(z.number().int().min(1)),
80
+ returnLastOnMaxIterations: optionalize(z.boolean()),
81
+ }))),
76
82
  })
77
83
  .extend(baseAgentSchema.shape),
78
84
  z
@@ -81,11 +87,20 @@ export async function loadAgentFromYamlFile(path) {
81
87
  jsonata: z.string(),
82
88
  })
83
89
  .extend(baseAgentSchema.shape),
90
+ z
91
+ .object({
92
+ type: z.literal("function"),
93
+ process: z.custom(),
94
+ })
95
+ .extend(baseAgentSchema.shape),
84
96
  ]));
85
97
  });
98
+ return agentSchema.parseAsync(data);
99
+ }
100
+ export async function loadAgentFromYamlFile(path) {
86
101
  const raw = await tryOrThrow(() => nodejs.fs.readFile(path, "utf8"), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
87
102
  const json = tryOrThrow(() => parse(raw), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
88
- const agent = await tryOrThrow(async () => await agentSchema.parseAsync({
103
+ const agent = await tryOrThrow(async () => await parseAgentFile(path, {
89
104
  ...json,
90
105
  type: json.type ?? "ai",
91
106
  skills: json.skills ?? json.tools,
@@ -12,9 +12,12 @@ interface LoadableModelClass {
12
12
  }
13
13
  export interface LoadableModel {
14
14
  name: string;
15
+ apiKeyEnvName?: string;
15
16
  create: (options: {
16
17
  model?: string;
17
18
  modelOptions?: ChatModelOptions;
19
+ accessKey?: string;
20
+ url?: string;
18
21
  }) => ChatModel;
19
22
  }
20
23
  export interface LoadOptions {
@@ -26,7 +29,10 @@ export interface LoadOptions {
26
29
  }
27
30
  export declare function load(options: LoadOptions): Promise<AIGNEOptions>;
28
31
  export declare function loadAgent(path: string, options?: LoadOptions, agentOptions?: AgentOptions): Promise<Agent>;
29
- export declare function loadModel(models: LoadableModel[], model?: Camelize<z.infer<typeof aigneFileSchema>["model"]>, modelOptions?: ChatModelOptions): Promise<ChatModel | undefined>;
32
+ export declare function loadModel(models: LoadableModel[], model?: Camelize<z.infer<typeof aigneFileSchema>["model"]>, modelOptions?: ChatModelOptions, accessKeyOptions?: {
33
+ accessKey?: string;
34
+ url?: string;
35
+ }): Promise<ChatModel | undefined>;
30
36
  declare const aigneFileSchema: z.ZodObject<{
31
37
  name: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
32
38
  description: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
@@ -35,7 +35,7 @@ export async function loadAgent(path, options, agentOptions) {
35
35
  const agent = await loadAgentFromJsFile(path);
36
36
  if (agent instanceof Agent)
37
37
  return agent;
38
- return FunctionAgent.from(agent);
38
+ return parseAgent(path, agent, options, agentOptions);
39
39
  }
40
40
  if ([".yml", ".yaml"].includes(nodejs.path.extname(path))) {
41
41
  const agent = await loadAgentFromYamlFile(path);
@@ -116,6 +116,12 @@ async function parseAgent(path, agent, options, agentOptions) {
116
116
  case "team": {
117
117
  return TeamAgent.from({
118
118
  ...baseOptions,
119
+ mode: agent.mode,
120
+ iterateOn: agent.iterateOn,
121
+ reflection: agent.reflection && {
122
+ ...agent.reflection,
123
+ reviewer: await loadNestAgent(path, agent.reflection.reviewer, options),
124
+ },
119
125
  });
120
126
  }
121
127
  case "transform": {
@@ -124,6 +130,12 @@ async function parseAgent(path, agent, options, agentOptions) {
124
130
  jsonata: agent.jsonata,
125
131
  });
126
132
  }
133
+ case "function": {
134
+ return FunctionAgent.from({
135
+ ...baseOptions,
136
+ process: agent.process,
137
+ });
138
+ }
127
139
  }
128
140
  }
129
141
  async function loadMemory(memories, provider, options) {
@@ -136,7 +148,7 @@ async function loadMemory(memories, provider, options) {
136
148
  }
137
149
  const { MODEL_PROVIDER, MODEL_NAME } = nodejs.env;
138
150
  const DEFAULT_MODEL_PROVIDER = "openai";
139
- export async function loadModel(models, model, modelOptions) {
151
+ export async function loadModel(models, model, modelOptions, accessKeyOptions) {
140
152
  const params = {
141
153
  model: MODEL_NAME ?? model?.name ?? undefined,
142
154
  temperature: model?.temperature ?? undefined,
@@ -144,12 +156,13 @@ export async function loadModel(models, model, modelOptions) {
144
156
  frequencyPenalty: model?.frequencyPenalty ?? undefined,
145
157
  presencePenalty: model?.presencePenalty ?? undefined,
146
158
  };
147
- const m = models.find((m) => m.name
148
- .toLowerCase()
149
- .includes((MODEL_PROVIDER ?? model?.provider ?? DEFAULT_MODEL_PROVIDER).toLowerCase()));
159
+ const providerName = MODEL_PROVIDER ?? model?.provider ?? DEFAULT_MODEL_PROVIDER;
160
+ const provider = providerName.replace(/-/g, "");
161
+ const m = models.find((m) => m.name.toLowerCase().includes(provider.toLowerCase()));
150
162
  if (!m)
151
163
  throw new Error(`Unsupported model: ${model?.provider} ${model?.name}`);
152
164
  return m.create({
165
+ ...(accessKeyOptions || {}),
153
166
  model: params.model,
154
167
  modelOptions: { ...params, ...modelOptions },
155
168
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.36.0",
3
+ "version": "1.38.0",
4
4
  "description": "AIGNE core library for building AI-powered applications",
5
5
  "publishConfig": {
6
6
  "access": "public"