@aigne/core 1.28.2 → 1.29.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 +7 -0
- package/lib/cjs/agents/agent.d.ts +1 -0
- package/lib/cjs/agents/agent.js +9 -5
- package/lib/cjs/agents/team-agent.d.ts +59 -2
- package/lib/cjs/agents/team-agent.js +54 -0
- package/lib/cjs/agents/transform-agent.d.ts +82 -0
- package/lib/cjs/agents/transform-agent.js +67 -0
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/loader/agent-js.d.ts +2 -2
- package/lib/cjs/loader/agent-js.js +11 -15
- package/lib/cjs/loader/agent-yaml.d.ts +35 -44
- package/lib/cjs/loader/agent-yaml.js +58 -103
- package/lib/cjs/loader/index.js +28 -11
- package/lib/cjs/loader/schema.d.ts +2 -1
- package/lib/cjs/loader/schema.js +4 -0
- package/lib/dts/agents/agent.d.ts +1 -0
- package/lib/dts/agents/team-agent.d.ts +59 -2
- package/lib/dts/agents/transform-agent.d.ts +82 -0
- package/lib/dts/index.d.ts +1 -0
- package/lib/dts/loader/agent-js.d.ts +2 -2
- package/lib/dts/loader/agent-yaml.d.ts +35 -44
- package/lib/dts/loader/schema.d.ts +2 -1
- package/lib/esm/agents/agent.d.ts +1 -0
- package/lib/esm/agents/agent.js +8 -5
- package/lib/esm/agents/team-agent.d.ts +59 -2
- package/lib/esm/agents/team-agent.js +53 -2
- package/lib/esm/agents/transform-agent.d.ts +82 -0
- package/lib/esm/agents/transform-agent.js +60 -0
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/loader/agent-js.d.ts +2 -2
- package/lib/esm/loader/agent-js.js +9 -16
- package/lib/esm/loader/agent-yaml.d.ts +35 -44
- package/lib/esm/loader/agent-yaml.js +56 -104
- package/lib/esm/loader/index.js +28 -11
- package/lib/esm/loader/schema.d.ts +2 -1
- package/lib/esm/loader/schema.js +3 -0
- package/package.json +2 -1
- package/lib/cjs/utils/camelize.d.ts +0 -13
- package/lib/cjs/utils/camelize.js +0 -16
- package/lib/dts/utils/camelize.d.ts +0 -13
- package/lib/esm/utils/camelize.d.ts +0 -13
- package/lib/esm/utils/camelize.js +0 -10
|
@@ -33,6 +33,42 @@ export interface TeamAgentOptions<I extends Message, O extends Message> extends
|
|
|
33
33
|
* @default {ProcessMode.sequential}
|
|
34
34
|
*/
|
|
35
35
|
mode?: ProcessMode;
|
|
36
|
+
/**
|
|
37
|
+
* Specifies which input field should be treated as an array for iterative processing.
|
|
38
|
+
*
|
|
39
|
+
* When this property is set, the TeamAgent will iterate over the array values in the
|
|
40
|
+
* specified input field, processing each element individually through the team's agents.
|
|
41
|
+
* The results from each iteration are accumulated and returned as a streaming response.
|
|
42
|
+
*
|
|
43
|
+
* This is particularly useful for batch processing scenarios where you need to apply
|
|
44
|
+
* the same agent workflow to multiple similar data items.
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* - The specified field must contain an array or array-like value
|
|
48
|
+
* - Each array element should be an object that can be merged with the base input
|
|
49
|
+
* - Non-array values will be treated as single-element arrays
|
|
50
|
+
* - The processing results are streamed incrementally as each iteration completes
|
|
51
|
+
*/
|
|
52
|
+
iterateOn?: keyof I;
|
|
53
|
+
/**
|
|
54
|
+
* Controls whether to merge the output from each iteration back into the array items
|
|
55
|
+
* for subsequent iterations when using `iterateOn`.
|
|
56
|
+
*
|
|
57
|
+
* When set to `true`, the output from processing each array element is merged back
|
|
58
|
+
* into that element, making it available for the next iteration. This creates a
|
|
59
|
+
* cumulative effect where each iteration builds upon the results of previous ones.
|
|
60
|
+
*
|
|
61
|
+
* When set to `false` or undefined, each array element is processed independently
|
|
62
|
+
* without any cross-iteration data sharing.
|
|
63
|
+
*
|
|
64
|
+
* This is particularly useful for scenarios where:
|
|
65
|
+
* - You need to progressively enrich data across iterations
|
|
66
|
+
* - Later iterations depend on the results of earlier ones
|
|
67
|
+
* - You want to build a chain of transformations on array data
|
|
68
|
+
*
|
|
69
|
+
* @default false
|
|
70
|
+
*/
|
|
71
|
+
iterateWithPreviousOutput?: boolean;
|
|
36
72
|
}
|
|
37
73
|
/**
|
|
38
74
|
* TeamAgent coordinates a group of agents working together to accomplish tasks.
|
|
@@ -80,6 +116,25 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
|
|
|
80
116
|
* This can be either sequential (one after another) or parallel (all at once).
|
|
81
117
|
*/
|
|
82
118
|
mode: ProcessMode;
|
|
119
|
+
/**
|
|
120
|
+
* The input field key to iterate over when processing array inputs.
|
|
121
|
+
*
|
|
122
|
+
* When set, this property enables the TeamAgent to process array values iteratively,
|
|
123
|
+
* where each array element is processed individually through the team's agent workflow.
|
|
124
|
+
* The accumulated results are returned via streaming response chunks.
|
|
125
|
+
*
|
|
126
|
+
* @see TeamAgentOptions.iterateOn for detailed documentation
|
|
127
|
+
*/
|
|
128
|
+
iterateOn?: keyof I;
|
|
129
|
+
/**
|
|
130
|
+
* Controls whether to merge the output from each iteration back into the array items
|
|
131
|
+
* for subsequent iterations when using `iterateOn`.
|
|
132
|
+
*
|
|
133
|
+
* @see TeamAgentOptions.iterateWithPreviousOutput for detailed documentation
|
|
134
|
+
*
|
|
135
|
+
* @default false
|
|
136
|
+
*/
|
|
137
|
+
iterateWithPreviousOutput?: boolean;
|
|
83
138
|
/**
|
|
84
139
|
* Process an input message by routing it through the team's agents.
|
|
85
140
|
*
|
|
@@ -93,6 +148,8 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
|
|
|
93
148
|
* @returns A stream of message chunks that collectively form the response
|
|
94
149
|
*/
|
|
95
150
|
process(input: I, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<O>>;
|
|
151
|
+
private _processIterator;
|
|
152
|
+
private _process;
|
|
96
153
|
/**
|
|
97
154
|
* Process input sequentially through each agent in the team.
|
|
98
155
|
*
|
|
@@ -108,7 +165,7 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
|
|
|
108
165
|
*
|
|
109
166
|
* @private
|
|
110
167
|
*/
|
|
111
|
-
_processSequential(input:
|
|
168
|
+
_processSequential(input: Message, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<O>>;
|
|
112
169
|
/**
|
|
113
170
|
* Process input in parallel through all agents in the team.
|
|
114
171
|
*
|
|
@@ -123,5 +180,5 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
|
|
|
123
180
|
*
|
|
124
181
|
* @private
|
|
125
182
|
*/
|
|
126
|
-
_processParallel(input:
|
|
183
|
+
_processParallel(input: Message, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<O>>;
|
|
127
184
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { produce } from "immer";
|
|
1
3
|
import { mergeAgentResponseChunk } from "../utils/stream-utils.js";
|
|
2
|
-
import { isEmpty } from "../utils/type-utils.js";
|
|
3
|
-
import { Agent, isAgentResponseDelta, } from "./agent.js";
|
|
4
|
+
import { isEmpty, isNil, isRecord, omit } from "../utils/type-utils.js";
|
|
5
|
+
import { Agent, agentProcessResultToObject, isAgentResponseDelta, } from "./agent.js";
|
|
4
6
|
/**
|
|
5
7
|
* Defines the processing modes available for a TeamAgent.
|
|
6
8
|
*
|
|
@@ -68,6 +70,8 @@ export class TeamAgent extends Agent {
|
|
|
68
70
|
constructor(options) {
|
|
69
71
|
super(options);
|
|
70
72
|
this.mode = options.mode ?? ProcessMode.sequential;
|
|
73
|
+
this.iterateOn = options.iterateOn;
|
|
74
|
+
this.iterateWithPreviousOutput = options.iterateWithPreviousOutput;
|
|
71
75
|
}
|
|
72
76
|
/**
|
|
73
77
|
* The processing mode that determines how agents in the team are executed.
|
|
@@ -75,6 +79,25 @@ export class TeamAgent extends Agent {
|
|
|
75
79
|
* This can be either sequential (one after another) or parallel (all at once).
|
|
76
80
|
*/
|
|
77
81
|
mode;
|
|
82
|
+
/**
|
|
83
|
+
* The input field key to iterate over when processing array inputs.
|
|
84
|
+
*
|
|
85
|
+
* When set, this property enables the TeamAgent to process array values iteratively,
|
|
86
|
+
* where each array element is processed individually through the team's agent workflow.
|
|
87
|
+
* The accumulated results are returned via streaming response chunks.
|
|
88
|
+
*
|
|
89
|
+
* @see TeamAgentOptions.iterateOn for detailed documentation
|
|
90
|
+
*/
|
|
91
|
+
iterateOn;
|
|
92
|
+
/**
|
|
93
|
+
* Controls whether to merge the output from each iteration back into the array items
|
|
94
|
+
* for subsequent iterations when using `iterateOn`.
|
|
95
|
+
*
|
|
96
|
+
* @see TeamAgentOptions.iterateWithPreviousOutput for detailed documentation
|
|
97
|
+
*
|
|
98
|
+
* @default false
|
|
99
|
+
*/
|
|
100
|
+
iterateWithPreviousOutput;
|
|
78
101
|
/**
|
|
79
102
|
* Process an input message by routing it through the team's agents.
|
|
80
103
|
*
|
|
@@ -88,6 +111,34 @@ export class TeamAgent extends Agent {
|
|
|
88
111
|
* @returns A stream of message chunks that collectively form the response
|
|
89
112
|
*/
|
|
90
113
|
process(input, options) {
|
|
114
|
+
if (this.iterateOn) {
|
|
115
|
+
return this._processIterator(this.iterateOn, input, options);
|
|
116
|
+
}
|
|
117
|
+
return this._process(input, options);
|
|
118
|
+
}
|
|
119
|
+
async *_processIterator(key, input, options) {
|
|
120
|
+
assert(this.iterateOn, "iterateInputKey must be defined for iterator processing");
|
|
121
|
+
let arr = input[this.iterateOn];
|
|
122
|
+
arr = Array.isArray(arr) ? [...arr] : isNil(arr) ? [arr] : [];
|
|
123
|
+
const result = [];
|
|
124
|
+
for (let i = 0; i < arr.length; i++) {
|
|
125
|
+
const item = arr[i];
|
|
126
|
+
if (!isRecord(item))
|
|
127
|
+
throw new TypeError(`Expected ${String(key)} to be an object, got ${typeof item}`);
|
|
128
|
+
const res = await agentProcessResultToObject(await this._process({ ...input, [key]: arr, ...item }, { ...options, streaming: false }));
|
|
129
|
+
// Merge the item result with the original item used for next iteration
|
|
130
|
+
if (this.iterateWithPreviousOutput) {
|
|
131
|
+
arr = produce(arr, (draft) => {
|
|
132
|
+
const item = draft[i];
|
|
133
|
+
assert(item);
|
|
134
|
+
Object.assign(item, res);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
result.push(omit(res, key));
|
|
138
|
+
yield { delta: { json: { [key]: result } } };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
_process(input, options) {
|
|
91
142
|
switch (this.mode) {
|
|
92
143
|
case ProcessMode.sequential:
|
|
93
144
|
return this._processSequential(input, options);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Agent, type AgentOptions, type Message } from "./agent.js";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration options for TransformAgent
|
|
4
|
+
*
|
|
5
|
+
* TransformAgent is a specialized agent that transforms input data to output data
|
|
6
|
+
* using [JSONata](https://jsonata.org/) expressions. It's particularly useful for:
|
|
7
|
+
* - Data format conversion (e.g., snake_case to camelCase)
|
|
8
|
+
* - Field mapping and renaming
|
|
9
|
+
* - Data structure transformation
|
|
10
|
+
* - Simple data processing without complex logic
|
|
11
|
+
* - API response normalization
|
|
12
|
+
* - Configuration data transformation
|
|
13
|
+
*/
|
|
14
|
+
export interface TransformAgentOptions<I extends Message, O extends Message> extends AgentOptions<I, O> {
|
|
15
|
+
/**
|
|
16
|
+
* JSONata expression string for data transformation
|
|
17
|
+
*
|
|
18
|
+
* JSONata is a lightweight query and transformation language for JSON data.
|
|
19
|
+
* The expression defines how input data should be transformed into output data.
|
|
20
|
+
*
|
|
21
|
+
* Common JSONata patterns:
|
|
22
|
+
* - Field mapping: `{ "newField": oldField }`
|
|
23
|
+
* - Array transformation: `items.{ "name": product_name, "price": price }`
|
|
24
|
+
* - Calculations: `$sum(items.price)`, `$count(items)`
|
|
25
|
+
* - Conditional logic: `condition ? value1 : value2`
|
|
26
|
+
* - String operations: `$uppercase(name)`, `$substring(text, 0, 10)`
|
|
27
|
+
*
|
|
28
|
+
* @see https://jsonata.org/ for complete JSONata syntax documentation
|
|
29
|
+
* @see https://try.jsonata.org/ for interactive JSONata playground
|
|
30
|
+
*/
|
|
31
|
+
jsonata: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* TransformAgent - A specialized agent for data transformation using JSONata expressions
|
|
35
|
+
*
|
|
36
|
+
* This agent provides a declarative way to transform structured data without writing
|
|
37
|
+
* custom processing logic. It leverages the power of JSONata, a lightweight query and
|
|
38
|
+
* transformation language, to handle complex data manipulations through simple expressions.
|
|
39
|
+
*
|
|
40
|
+
* Common Use Cases:
|
|
41
|
+
* - API response normalization and field mapping
|
|
42
|
+
* - Database query result transformation
|
|
43
|
+
* - Configuration data restructuring
|
|
44
|
+
* - Data format conversion (snake_case ↔ camelCase)
|
|
45
|
+
* - Aggregation and calculation operations
|
|
46
|
+
* - Filtering and conditional data processing
|
|
47
|
+
*/
|
|
48
|
+
export declare class TransformAgent<I extends Message = Message, O extends Message = Message> extends Agent<I, O> {
|
|
49
|
+
static type: string;
|
|
50
|
+
/**
|
|
51
|
+
* Factory method to create a new TransformAgent instance
|
|
52
|
+
*
|
|
53
|
+
* Provides a convenient way to create TransformAgent instances with proper typing
|
|
54
|
+
*
|
|
55
|
+
* @param options Configuration options for the TransformAgent
|
|
56
|
+
* @returns A new TransformAgent instance
|
|
57
|
+
*/
|
|
58
|
+
static from<I extends Message, O extends Message>(options: TransformAgentOptions<I, O>): TransformAgent<I, O>;
|
|
59
|
+
/**
|
|
60
|
+
* Create a new TransformAgent instance
|
|
61
|
+
*
|
|
62
|
+
* @param options Configuration options including the JSONata expression
|
|
63
|
+
*/
|
|
64
|
+
constructor(options: TransformAgentOptions<I, O>);
|
|
65
|
+
/**
|
|
66
|
+
* The JSONata expression string used for data transformation
|
|
67
|
+
*
|
|
68
|
+
* This expression is compiled and executed against input data to produce
|
|
69
|
+
* the transformed output. The expression is stored as a string and compiled
|
|
70
|
+
* on each invocation for maximum flexibility.
|
|
71
|
+
*/
|
|
72
|
+
private jsonata;
|
|
73
|
+
/**
|
|
74
|
+
* Process input data using the configured JSONata expression
|
|
75
|
+
*
|
|
76
|
+
* This method compiles the JSONata expression and evaluates it against the input data.
|
|
77
|
+
*
|
|
78
|
+
* @param input The input message to transform
|
|
79
|
+
* @returns Promise resolving to the transformed output message
|
|
80
|
+
*/
|
|
81
|
+
process(input: I): Promise<O>;
|
|
82
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import jsonata from "jsonata";
|
|
2
|
+
import { Agent } from "./agent.js";
|
|
3
|
+
/**
|
|
4
|
+
* TransformAgent - A specialized agent for data transformation using JSONata expressions
|
|
5
|
+
*
|
|
6
|
+
* This agent provides a declarative way to transform structured data without writing
|
|
7
|
+
* custom processing logic. It leverages the power of JSONata, a lightweight query and
|
|
8
|
+
* transformation language, to handle complex data manipulations through simple expressions.
|
|
9
|
+
*
|
|
10
|
+
* Common Use Cases:
|
|
11
|
+
* - API response normalization and field mapping
|
|
12
|
+
* - Database query result transformation
|
|
13
|
+
* - Configuration data restructuring
|
|
14
|
+
* - Data format conversion (snake_case ↔ camelCase)
|
|
15
|
+
* - Aggregation and calculation operations
|
|
16
|
+
* - Filtering and conditional data processing
|
|
17
|
+
*/
|
|
18
|
+
export class TransformAgent extends Agent {
|
|
19
|
+
static type = "TransformAgent";
|
|
20
|
+
/**
|
|
21
|
+
* Factory method to create a new TransformAgent instance
|
|
22
|
+
*
|
|
23
|
+
* Provides a convenient way to create TransformAgent instances with proper typing
|
|
24
|
+
*
|
|
25
|
+
* @param options Configuration options for the TransformAgent
|
|
26
|
+
* @returns A new TransformAgent instance
|
|
27
|
+
*/
|
|
28
|
+
static from(options) {
|
|
29
|
+
return new TransformAgent(options);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create a new TransformAgent instance
|
|
33
|
+
*
|
|
34
|
+
* @param options Configuration options including the JSONata expression
|
|
35
|
+
*/
|
|
36
|
+
constructor(options) {
|
|
37
|
+
super(options);
|
|
38
|
+
this.jsonata = options.jsonata;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The JSONata expression string used for data transformation
|
|
42
|
+
*
|
|
43
|
+
* This expression is compiled and executed against input data to produce
|
|
44
|
+
* the transformed output. The expression is stored as a string and compiled
|
|
45
|
+
* on each invocation for maximum flexibility.
|
|
46
|
+
*/
|
|
47
|
+
jsonata;
|
|
48
|
+
/**
|
|
49
|
+
* Process input data using the configured JSONata expression
|
|
50
|
+
*
|
|
51
|
+
* This method compiles the JSONata expression and evaluates it against the input data.
|
|
52
|
+
*
|
|
53
|
+
* @param input The input message to transform
|
|
54
|
+
* @returns Promise resolving to the transformed output message
|
|
55
|
+
*/
|
|
56
|
+
async process(input) {
|
|
57
|
+
const expression = jsonata(this.jsonata);
|
|
58
|
+
return await expression.evaluate(input);
|
|
59
|
+
}
|
|
60
|
+
}
|
package/lib/esm/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from "./agents/chat-model.js";
|
|
|
4
4
|
export * from "./agents/guide-rail-agent.js";
|
|
5
5
|
export * from "./agents/mcp-agent.js";
|
|
6
6
|
export * from "./agents/team-agent.js";
|
|
7
|
+
export * from "./agents/transform-agent.js";
|
|
7
8
|
export * from "./agents/types.js";
|
|
8
9
|
export * from "./agents/user-agent.js";
|
|
9
10
|
export * from "./aigne/index.js";
|
package/lib/esm/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from "./agents/chat-model.js";
|
|
|
4
4
|
export * from "./agents/guide-rail-agent.js";
|
|
5
5
|
export * from "./agents/mcp-agent.js";
|
|
6
6
|
export * from "./agents/team-agent.js";
|
|
7
|
+
export * from "./agents/transform-agent.js";
|
|
7
8
|
export * from "./agents/types.js";
|
|
8
9
|
export * from "./agents/user-agent.js";
|
|
9
10
|
export * from "./aigne/index.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ZodObject, type ZodType, z } from "zod";
|
|
2
|
-
import { Agent, type
|
|
2
|
+
import { Agent, type FunctionAgentFn } from "../agents/agent.js";
|
|
3
3
|
export declare function loadAgentFromJsFile(path: string): Promise<Agent<any, any> | {
|
|
4
|
-
process:
|
|
4
|
+
process: FunctionAgentFn;
|
|
5
5
|
name: string;
|
|
6
6
|
description?: string | undefined;
|
|
7
7
|
inputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
import { jsonSchemaToZod } from "@aigne/json-schema-to-zod";
|
|
2
|
+
import camelize from "camelize-ts";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
import { Agent } from "../agents/agent.js";
|
|
4
|
-
import { customCamelize } from "../utils/camelize.js";
|
|
5
5
|
import { tryOrThrow } from "../utils/type-utils.js";
|
|
6
|
-
import { inputOutputSchema } from "./schema.js";
|
|
6
|
+
import { inputOutputSchema, optionalize } from "./schema.js";
|
|
7
7
|
const agentJsFileSchema = z.object({
|
|
8
8
|
name: z.string(),
|
|
9
|
-
description: z
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
input_schema: inputOutputSchema
|
|
14
|
-
.nullish()
|
|
15
|
-
.transform((v) => (v ? jsonSchemaToZod(v) : undefined)),
|
|
16
|
-
output_schema: inputOutputSchema
|
|
17
|
-
.nullish()
|
|
18
|
-
.transform((v) => (v ? jsonSchemaToZod(v) : undefined)),
|
|
19
|
-
process: z.function(),
|
|
9
|
+
description: optionalize(z.string()),
|
|
10
|
+
inputSchema: optionalize(inputOutputSchema).transform((v) => v ? jsonSchemaToZod(v) : undefined),
|
|
11
|
+
outputSchema: optionalize(inputOutputSchema).transform((v) => v ? jsonSchemaToZod(v) : undefined),
|
|
12
|
+
process: z.custom(),
|
|
20
13
|
});
|
|
21
14
|
export async function loadAgentFromJsFile(path) {
|
|
22
15
|
const { default: agent } = await tryOrThrow(() => import(path), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
|
|
@@ -25,9 +18,9 @@ export async function loadAgentFromJsFile(path) {
|
|
|
25
18
|
if (typeof agent !== "function") {
|
|
26
19
|
throw new Error(`Agent file ${path} must export a default function, but got ${typeof agent}`);
|
|
27
20
|
}
|
|
28
|
-
return tryOrThrow(() =>
|
|
21
|
+
return tryOrThrow(() => agentJsFileSchema.parse(camelize({
|
|
29
22
|
...agent,
|
|
30
|
-
name: agent.agent_name || agent.name,
|
|
23
|
+
name: agent.agent_name || agent.agentName || agent.name,
|
|
31
24
|
process: agent,
|
|
32
|
-
})
|
|
25
|
+
})), (error) => new Error(`Failed to parse agent from ${path}: ${error.message}`));
|
|
33
26
|
}
|
|
@@ -1,48 +1,39 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ZodType } from "zod";
|
|
2
2
|
import { AIAgentToolChoice } from "../agents/ai-agent.js";
|
|
3
3
|
import { ProcessMode } from "../agents/team-agent.js";
|
|
4
|
-
|
|
4
|
+
interface BaseAgentSchema {
|
|
5
|
+
name?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
inputSchema?: ZodType<Record<string, ZodType>>;
|
|
8
|
+
outputSchema?: ZodType<Record<string, ZodType>>;
|
|
9
|
+
skills?: (string | AgentSchema)[];
|
|
10
|
+
memory?: boolean | {
|
|
11
|
+
provider: string;
|
|
12
|
+
subscribeTopic?: string[];
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
interface AIAgentSchema extends BaseAgentSchema {
|
|
16
|
+
type: "ai";
|
|
17
|
+
instructions?: string;
|
|
18
|
+
inputKey?: string;
|
|
19
|
+
outputKey?: string;
|
|
20
|
+
toolChoice?: AIAgentToolChoice;
|
|
21
|
+
}
|
|
22
|
+
interface MCPAgentSchema {
|
|
5
23
|
type: "mcp";
|
|
6
|
-
url?: string
|
|
7
|
-
command?: string
|
|
8
|
-
args?: string[]
|
|
9
|
-
}
|
|
24
|
+
url?: string;
|
|
25
|
+
command?: string;
|
|
26
|
+
args?: string[];
|
|
27
|
+
}
|
|
28
|
+
interface TeamAgentSchema extends BaseAgentSchema {
|
|
10
29
|
type: "team";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
[x: string]: any;
|
|
22
|
-
}, {
|
|
23
|
-
[x: string]: any;
|
|
24
|
-
}> | undefined;
|
|
25
|
-
} | {
|
|
26
|
-
instructions: string | undefined;
|
|
27
|
-
type: "ai";
|
|
28
|
-
name: string;
|
|
29
|
-
description?: string | undefined;
|
|
30
|
-
skills?: string[] | undefined;
|
|
31
|
-
memory?: true | {
|
|
32
|
-
provider: string;
|
|
33
|
-
subscribeTopic?: string[] | undefined;
|
|
34
|
-
} | undefined;
|
|
35
|
-
inputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
36
|
-
[x: string]: any;
|
|
37
|
-
}, {
|
|
38
|
-
[x: string]: any;
|
|
39
|
-
}> | undefined;
|
|
40
|
-
outputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
41
|
-
[x: string]: any;
|
|
42
|
-
}, {
|
|
43
|
-
[x: string]: any;
|
|
44
|
-
}> | undefined;
|
|
45
|
-
inputKey?: string | undefined;
|
|
46
|
-
outputKey?: string | undefined;
|
|
47
|
-
toolChoice?: AIAgentToolChoice | undefined;
|
|
48
|
-
}>;
|
|
30
|
+
mode?: ProcessMode;
|
|
31
|
+
iterateOn?: string;
|
|
32
|
+
}
|
|
33
|
+
interface TransformAgentSchema extends BaseAgentSchema {
|
|
34
|
+
type: "transform";
|
|
35
|
+
jsonata: string;
|
|
36
|
+
}
|
|
37
|
+
type AgentSchema = AIAgentSchema | MCPAgentSchema | TeamAgentSchema | TransformAgentSchema;
|
|
38
|
+
export declare function loadAgentFromYamlFile(path: string): Promise<AgentSchema>;
|
|
39
|
+
export {};
|
|
@@ -1,120 +1,72 @@
|
|
|
1
1
|
import { jsonSchemaToZod } from "@aigne/json-schema-to-zod";
|
|
2
2
|
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
3
|
+
import camelize from "camelize-ts";
|
|
3
4
|
import { parse } from "yaml";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
import { AIAgentToolChoice } from "../agents/ai-agent.js";
|
|
6
7
|
import { ProcessMode } from "../agents/team-agent.js";
|
|
7
|
-
import { customCamelize } from "../utils/camelize.js";
|
|
8
8
|
import { tryOrThrow } from "../utils/type-utils.js";
|
|
9
|
-
import { inputOutputSchema } from "./schema.js";
|
|
10
|
-
|
|
11
|
-
z.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.
|
|
16
|
-
.
|
|
17
|
-
.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
.nullish()
|
|
44
|
-
.transform((v) => v ?? undefined),
|
|
45
|
-
tool_choice: z
|
|
46
|
-
.nativeEnum(AIAgentToolChoice)
|
|
47
|
-
.nullish()
|
|
48
|
-
.transform((v) => v ?? undefined),
|
|
49
|
-
memory: z
|
|
50
|
-
.union([
|
|
51
|
-
z.boolean(),
|
|
9
|
+
import { inputOutputSchema, optionalize } from "./schema.js";
|
|
10
|
+
export async function loadAgentFromYamlFile(path) {
|
|
11
|
+
const agentSchema = z.lazy(() => {
|
|
12
|
+
const baseAgentSchema = z.object({
|
|
13
|
+
name: optionalize(z.string()),
|
|
14
|
+
description: optionalize(z.string()),
|
|
15
|
+
inputSchema: optionalize(inputOutputSchema).transform((v) => v ? jsonSchemaToZod(v) : undefined),
|
|
16
|
+
outputSchema: optionalize(inputOutputSchema).transform((v) => v ? jsonSchemaToZod(v) : undefined),
|
|
17
|
+
skills: optionalize(z.array(z.union([z.string(), agentSchema]))),
|
|
18
|
+
memory: optionalize(z.union([
|
|
19
|
+
z.boolean(),
|
|
20
|
+
z.object({
|
|
21
|
+
provider: z.string(),
|
|
22
|
+
subscribeTopic: optionalize(z.array(z.string())),
|
|
23
|
+
}),
|
|
24
|
+
])),
|
|
25
|
+
});
|
|
26
|
+
return z.discriminatedUnion("type", [
|
|
27
|
+
z
|
|
28
|
+
.object({
|
|
29
|
+
type: z.literal("ai"),
|
|
30
|
+
instructions: optionalize(z.union([
|
|
31
|
+
z.string(),
|
|
32
|
+
z.object({
|
|
33
|
+
url: z.string(),
|
|
34
|
+
}),
|
|
35
|
+
])).transform((v) => typeof v === "string"
|
|
36
|
+
? v
|
|
37
|
+
: v && nodejs.fs.readFile(nodejs.path.join(nodejs.path.dirname(path), v.url), "utf8")),
|
|
38
|
+
inputKey: optionalize(z.string()),
|
|
39
|
+
outputKey: optionalize(z.string()),
|
|
40
|
+
toolChoice: optionalize(z.nativeEnum(AIAgentToolChoice)),
|
|
41
|
+
})
|
|
42
|
+
.extend(baseAgentSchema.shape),
|
|
52
43
|
z.object({
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
.transform((v) => v ?? undefined),
|
|
44
|
+
type: z.literal("mcp"),
|
|
45
|
+
url: optionalize(z.string()),
|
|
46
|
+
command: optionalize(z.string()),
|
|
47
|
+
args: optionalize(z.array(z.string())),
|
|
58
48
|
}),
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
.array(z.string())
|
|
75
|
-
.nullish()
|
|
76
|
-
.transform((v) => v ?? undefined),
|
|
77
|
-
}),
|
|
78
|
-
z.object({
|
|
79
|
-
type: z.literal("team"),
|
|
80
|
-
name: z.string(),
|
|
81
|
-
description: z
|
|
82
|
-
.string()
|
|
83
|
-
.nullish()
|
|
84
|
-
.transform((v) => v ?? undefined),
|
|
85
|
-
input_schema: inputOutputSchema
|
|
86
|
-
.nullish()
|
|
87
|
-
.transform((v) => (v ? jsonSchemaToZod(v) : undefined)),
|
|
88
|
-
output_schema: inputOutputSchema
|
|
89
|
-
.nullish()
|
|
90
|
-
.transform((v) => (v ? jsonSchemaToZod(v) : undefined)),
|
|
91
|
-
skills: z
|
|
92
|
-
.array(z.string())
|
|
93
|
-
.nullish()
|
|
94
|
-
.transform((v) => v ?? undefined),
|
|
95
|
-
mode: z
|
|
96
|
-
.nativeEnum(ProcessMode)
|
|
97
|
-
.nullish()
|
|
98
|
-
.transform((v) => v ?? undefined),
|
|
99
|
-
}),
|
|
100
|
-
]);
|
|
101
|
-
export async function loadAgentFromYamlFile(path) {
|
|
49
|
+
z
|
|
50
|
+
.object({
|
|
51
|
+
type: z.literal("team"),
|
|
52
|
+
mode: optionalize(z.nativeEnum(ProcessMode)),
|
|
53
|
+
iterateOn: optionalize(z.string()),
|
|
54
|
+
})
|
|
55
|
+
.extend(baseAgentSchema.shape),
|
|
56
|
+
z
|
|
57
|
+
.object({
|
|
58
|
+
type: z.literal("transform"),
|
|
59
|
+
jsonata: z.string(),
|
|
60
|
+
})
|
|
61
|
+
.extend(baseAgentSchema.shape),
|
|
62
|
+
]);
|
|
63
|
+
});
|
|
102
64
|
const raw = await tryOrThrow(() => nodejs.fs.readFile(path, "utf8"), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
|
|
103
65
|
const json = await tryOrThrow(() => parse(raw), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
|
|
104
|
-
const agent = await tryOrThrow(async () =>
|
|
66
|
+
const agent = await tryOrThrow(async () => await agentSchema.parseAsync(camelize({
|
|
105
67
|
...json,
|
|
106
68
|
type: json.type ?? "ai",
|
|
107
69
|
skills: json.skills ?? json.tools,
|
|
108
|
-
}), {
|
|
109
|
-
shallowKeys: ["input_schema", "output_schema"],
|
|
110
|
-
}), (error) => new Error(`Failed to validate agent definition from ${path}: ${error.message}`));
|
|
111
|
-
if (agent.type === "ai") {
|
|
112
|
-
return {
|
|
113
|
-
...agent,
|
|
114
|
-
instructions: typeof agent.instructions === "object" && "url" in agent.instructions
|
|
115
|
-
? await nodejs.fs.readFile(nodejs.path.join(nodejs.path.dirname(path), agent.instructions.url), "utf8")
|
|
116
|
-
: agent.instructions,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
70
|
+
})), (error) => new Error(`Failed to validate agent definition from ${path}: ${error.message}`));
|
|
119
71
|
return agent;
|
|
120
72
|
}
|