@aigne/core 1.70.1-beta → 1.71.0-beta
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 +24 -0
- package/lib/cjs/agents/agent.d.ts +4 -0
- package/lib/cjs/agents/agent.js +3 -0
- package/lib/cjs/agents/image-agent.js +2 -2
- package/lib/cjs/agents/types.d.ts +9 -1
- package/lib/cjs/loader/agent-js.d.ts +1 -2
- package/lib/cjs/loader/agent-js.js +2 -2
- package/lib/cjs/loader/agent-yaml.d.ts +19 -3
- package/lib/cjs/loader/agent-yaml.js +151 -110
- package/lib/cjs/loader/index.d.ts +10 -1
- package/lib/cjs/loader/index.js +42 -17
- package/lib/cjs/prompt/prompt-builder.d.ts +3 -3
- package/lib/cjs/prompt/prompt-builder.js +8 -2
- package/lib/cjs/prompt/skills/afs.js +41 -4
- package/lib/cjs/prompt/template.d.ts +1 -0
- package/lib/cjs/prompt/template.js +5 -3
- package/lib/cjs/utils/agent-utils.d.ts +3 -2
- package/lib/cjs/utils/agent-utils.js +7 -0
- package/lib/cjs/utils/token-estimator.d.ts +9 -0
- package/lib/cjs/utils/token-estimator.js +66 -0
- package/lib/dts/agents/agent.d.ts +4 -0
- package/lib/dts/agents/types.d.ts +9 -1
- package/lib/dts/loader/agent-js.d.ts +1 -2
- package/lib/dts/loader/agent-yaml.d.ts +19 -3
- package/lib/dts/loader/index.d.ts +10 -1
- package/lib/dts/prompt/prompt-builder.d.ts +3 -3
- package/lib/dts/prompt/template.d.ts +1 -0
- package/lib/dts/utils/agent-utils.d.ts +3 -2
- package/lib/dts/utils/token-estimator.d.ts +9 -0
- package/lib/esm/agents/agent.d.ts +4 -0
- package/lib/esm/agents/agent.js +3 -0
- package/lib/esm/agents/image-agent.js +2 -2
- package/lib/esm/agents/types.d.ts +9 -1
- package/lib/esm/loader/agent-js.d.ts +1 -2
- package/lib/esm/loader/agent-js.js +2 -2
- package/lib/esm/loader/agent-yaml.d.ts +19 -3
- package/lib/esm/loader/agent-yaml.js +147 -110
- package/lib/esm/loader/index.d.ts +10 -1
- package/lib/esm/loader/index.js +41 -19
- package/lib/esm/prompt/prompt-builder.d.ts +3 -3
- package/lib/esm/prompt/prompt-builder.js +8 -2
- package/lib/esm/prompt/skills/afs.js +41 -4
- package/lib/esm/prompt/template.d.ts +1 -0
- package/lib/esm/prompt/template.js +5 -3
- package/lib/esm/utils/agent-utils.d.ts +3 -2
- package/lib/esm/utils/agent-utils.js +6 -0
- package/lib/esm/utils/token-estimator.d.ts +9 -0
- package/lib/esm/utils/token-estimator.js +63 -0
- package/package.json +4 -4
|
@@ -9,6 +9,68 @@ import { tryOrThrow } from "../utils/type-utils.js";
|
|
|
9
9
|
import { codeToFunctionAgentFn } from "./function-agent.js";
|
|
10
10
|
import { camelizeSchema, chatModelSchema, defaultInputSchema, imageModelSchema, inputOutputSchema, optionalize, } from "./schema.js";
|
|
11
11
|
export async function parseAgentFile(path, data) {
|
|
12
|
+
const agentSchema = getAgentSchema({ filepath: path });
|
|
13
|
+
return agentSchema.parseAsync({
|
|
14
|
+
...data,
|
|
15
|
+
model: data.model || data.chatModel || data.chat_model,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
export async function loadAgentFromYamlFile(path, options) {
|
|
19
|
+
const raw = await tryOrThrow(() => nodejs.fs.readFile(path, "utf8"), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
|
|
20
|
+
const json = tryOrThrow(() => parse(raw), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
|
|
21
|
+
if (!["ai", "image", "mcp", "team", "transform", "function"].includes(json?.type)) {
|
|
22
|
+
if (typeof json?.type === "string") {
|
|
23
|
+
if (!options?.require)
|
|
24
|
+
throw new Error(`Module loader is not provided to load agent type module ${json.type} from ${path}`);
|
|
25
|
+
const Mod = await options.require(json.type, { parent: path });
|
|
26
|
+
if (typeof Mod?.default?.prototype?.constructor !== "function") {
|
|
27
|
+
throw new Error(`The agent type module ${json.type} does not export a default Agent class`);
|
|
28
|
+
}
|
|
29
|
+
json.agentClass = Mod.default;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const agent = await tryOrThrow(async () => await parseAgentFile(path, {
|
|
33
|
+
...json,
|
|
34
|
+
type: json.type ?? "ai",
|
|
35
|
+
skills: json.skills ?? json.tools,
|
|
36
|
+
}), (error) => new Error(`Failed to validate agent definition from ${path}: ${error.message}`));
|
|
37
|
+
return agent;
|
|
38
|
+
}
|
|
39
|
+
const instructionItemSchema = z.union([
|
|
40
|
+
z.object({
|
|
41
|
+
role: roleSchema.default("system"),
|
|
42
|
+
url: z.string(),
|
|
43
|
+
}),
|
|
44
|
+
z.object({
|
|
45
|
+
role: roleSchema.default("system"),
|
|
46
|
+
content: z.string(),
|
|
47
|
+
}),
|
|
48
|
+
]);
|
|
49
|
+
const parseInstructionItem = ({ filepath }) => async ({ role, ...v }) => {
|
|
50
|
+
if (role === "tool")
|
|
51
|
+
throw new Error(`'tool' role is not allowed in instruction item in agent file ${filepath}`);
|
|
52
|
+
if ("content" in v && typeof v.content === "string") {
|
|
53
|
+
return { role, content: v.content, path: filepath };
|
|
54
|
+
}
|
|
55
|
+
if ("url" in v && typeof v.url === "string") {
|
|
56
|
+
const url = nodejs.path.isAbsolute(v.url)
|
|
57
|
+
? v.url
|
|
58
|
+
: nodejs.path.join(nodejs.path.dirname(filepath), v.url);
|
|
59
|
+
return nodejs.fs.readFile(url, "utf8").then((content) => ({ role, content, path: url }));
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Invalid instruction item in agent file ${filepath}. Expected 'content' or 'url' property`);
|
|
62
|
+
};
|
|
63
|
+
export const getInstructionsSchema = ({ filepath }) => z
|
|
64
|
+
.union([z.string(), instructionItemSchema, z.array(instructionItemSchema)])
|
|
65
|
+
.transform(async (v) => {
|
|
66
|
+
if (typeof v === "string")
|
|
67
|
+
return [{ role: "system", content: v, path: filepath }];
|
|
68
|
+
if (Array.isArray(v)) {
|
|
69
|
+
return Promise.all(v.map((item) => parseInstructionItem({ filepath })(item)));
|
|
70
|
+
}
|
|
71
|
+
return [await parseInstructionItem({ filepath })(v)];
|
|
72
|
+
});
|
|
73
|
+
export const getAgentSchema = ({ filepath }) => {
|
|
12
74
|
const agentSchema = z.lazy(() => {
|
|
13
75
|
const nestAgentSchema = z.lazy(() => z.union([
|
|
14
76
|
agentSchema,
|
|
@@ -37,9 +99,9 @@ export async function parseAgentFile(path, data) {
|
|
|
37
99
|
imageModel: optionalize(imageModelSchema),
|
|
38
100
|
taskTitle: optionalize(z.string()),
|
|
39
101
|
taskRenderMode: optionalize(z.union([z.literal("hide"), z.literal("collapse")])),
|
|
40
|
-
inputSchema: optionalize(inputOutputSchema({ path })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
|
|
102
|
+
inputSchema: optionalize(inputOutputSchema({ path: filepath })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
|
|
41
103
|
defaultInput: optionalize(defaultInputSchema),
|
|
42
|
-
outputSchema: optionalize(inputOutputSchema({ path })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
|
|
104
|
+
outputSchema: optionalize(inputOutputSchema({ path: filepath })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
|
|
43
105
|
includeInputInOutput: optionalize(z.boolean()),
|
|
44
106
|
hooks: optionalize(z.union([hooksSchema, z.array(hooksSchema)])),
|
|
45
107
|
skills: optionalize(z.array(nestAgentSchema)),
|
|
@@ -62,117 +124,92 @@ export async function parseAgentFile(path, data) {
|
|
|
62
124
|
]))),
|
|
63
125
|
})),
|
|
64
126
|
])),
|
|
127
|
+
shareAFS: optionalize(z.boolean()),
|
|
65
128
|
});
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
role: roleSchema.default("system"),
|
|
69
|
-
url: z.string(),
|
|
70
|
-
}),
|
|
71
|
-
z.object({
|
|
72
|
-
role: roleSchema.default("system"),
|
|
73
|
-
content: z.string(),
|
|
74
|
-
}),
|
|
75
|
-
]);
|
|
76
|
-
const parseInstructionItem = async ({ role, ...v }) => {
|
|
77
|
-
if (role === "tool")
|
|
78
|
-
throw new Error(`'tool' role is not allowed in instruction item in agent file ${path}`);
|
|
79
|
-
if ("content" in v && typeof v.content === "string") {
|
|
80
|
-
return { role, content: v.content, path };
|
|
81
|
-
}
|
|
82
|
-
if ("url" in v && typeof v.url === "string") {
|
|
83
|
-
const url = nodejs.path.isAbsolute(v.url)
|
|
84
|
-
? v.url
|
|
85
|
-
: nodejs.path.join(nodejs.path.dirname(path), v.url);
|
|
86
|
-
return nodejs.fs.readFile(url, "utf8").then((content) => ({ role, content, path: url }));
|
|
87
|
-
}
|
|
88
|
-
throw new Error(`Invalid instruction item in agent file ${path}. Expected 'content' or 'url' property`);
|
|
89
|
-
};
|
|
90
|
-
const instructionsSchema = z
|
|
91
|
-
.union([z.string(), instructionItemSchema, z.array(instructionItemSchema)])
|
|
92
|
-
.transform(async (v) => {
|
|
93
|
-
if (typeof v === "string")
|
|
94
|
-
return [{ role: "system", content: v, path }];
|
|
95
|
-
if (Array.isArray(v)) {
|
|
96
|
-
return Promise.all(v.map((item) => parseInstructionItem(item)));
|
|
97
|
-
}
|
|
98
|
-
return [await parseInstructionItem(v)];
|
|
99
|
-
});
|
|
100
|
-
return camelizeSchema(z.discriminatedUnion("type", [
|
|
101
|
-
z
|
|
102
|
-
.object({
|
|
103
|
-
type: z.literal("ai"),
|
|
104
|
-
instructions: optionalize(instructionsSchema),
|
|
105
|
-
autoReorderSystemMessages: optionalize(z.boolean()),
|
|
106
|
-
autoMergeSystemMessages: optionalize(z.boolean()),
|
|
107
|
-
inputKey: optionalize(z.string()),
|
|
108
|
-
outputKey: optionalize(z.string()),
|
|
109
|
-
inputFileKey: optionalize(z.string()),
|
|
110
|
-
outputFileKey: optionalize(z.string()),
|
|
111
|
-
toolChoice: optionalize(z.nativeEnum(AIAgentToolChoice)),
|
|
112
|
-
toolCallsConcurrency: optionalize(z.number().int().min(0)),
|
|
113
|
-
keepTextInToolUses: optionalize(z.boolean()),
|
|
114
|
-
catchToolsError: optionalize(z.boolean()),
|
|
115
|
-
structuredStreamMode: optionalize(z.boolean()),
|
|
116
|
-
})
|
|
117
|
-
.extend(baseAgentSchema.shape),
|
|
118
|
-
z
|
|
119
|
-
.object({
|
|
120
|
-
type: z.literal("image"),
|
|
121
|
-
instructions: instructionsSchema,
|
|
122
|
-
inputFileKey: optionalize(z.string()),
|
|
123
|
-
})
|
|
124
|
-
.extend(baseAgentSchema.shape),
|
|
125
|
-
z
|
|
126
|
-
.object({
|
|
127
|
-
type: z.literal("mcp"),
|
|
128
|
-
url: optionalize(z.string()),
|
|
129
|
-
command: optionalize(z.string()),
|
|
130
|
-
args: optionalize(z.array(z.string())),
|
|
131
|
-
})
|
|
132
|
-
.extend(baseAgentSchema.shape),
|
|
133
|
-
z
|
|
134
|
-
.object({
|
|
135
|
-
type: z.literal("team"),
|
|
136
|
-
mode: optionalize(z.nativeEnum(ProcessMode)),
|
|
137
|
-
iterateOn: optionalize(z.string()),
|
|
138
|
-
concurrency: optionalize(z.number().int().min(1)),
|
|
139
|
-
iterateWithPreviousOutput: optionalize(z.boolean()),
|
|
140
|
-
includeAllStepsOutput: optionalize(z.boolean()),
|
|
141
|
-
reflection: camelizeSchema(optionalize(z.object({
|
|
142
|
-
reviewer: nestAgentSchema,
|
|
143
|
-
isApproved: z.string(),
|
|
144
|
-
maxIterations: optionalize(z.number().int().min(1)),
|
|
145
|
-
returnLastOnMaxIterations: optionalize(z.boolean()),
|
|
146
|
-
customErrorMessage: optionalize(z.string()),
|
|
147
|
-
}))),
|
|
148
|
-
})
|
|
149
|
-
.extend(baseAgentSchema.shape),
|
|
129
|
+
const instructionsSchema = getInstructionsSchema({ filepath: filepath });
|
|
130
|
+
return camelizeSchema(z.union([
|
|
150
131
|
z
|
|
151
132
|
.object({
|
|
152
|
-
type: z.
|
|
153
|
-
|
|
133
|
+
type: z.string(),
|
|
134
|
+
agentClass: z.custom((v) => typeof v?.prototype?.constructor === "function"),
|
|
154
135
|
})
|
|
155
|
-
.extend(baseAgentSchema.shape)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
136
|
+
.extend(baseAgentSchema.shape)
|
|
137
|
+
.passthrough(),
|
|
138
|
+
z.discriminatedUnion("type", [
|
|
139
|
+
z
|
|
140
|
+
.object({
|
|
141
|
+
type: z.literal("ai"),
|
|
142
|
+
instructions: optionalize(instructionsSchema),
|
|
143
|
+
autoReorderSystemMessages: optionalize(z.boolean()),
|
|
144
|
+
autoMergeSystemMessages: optionalize(z.boolean()),
|
|
145
|
+
inputKey: optionalize(z.string()),
|
|
146
|
+
outputKey: optionalize(z.string()),
|
|
147
|
+
inputFileKey: optionalize(z.string()),
|
|
148
|
+
outputFileKey: optionalize(z.string()),
|
|
149
|
+
toolChoice: optionalize(z.nativeEnum(AIAgentToolChoice)),
|
|
150
|
+
toolCallsConcurrency: optionalize(z.number().int().min(0)),
|
|
151
|
+
keepTextInToolUses: optionalize(z.boolean()),
|
|
152
|
+
catchToolsError: optionalize(z.boolean()),
|
|
153
|
+
structuredStreamMode: optionalize(z.boolean()),
|
|
154
|
+
})
|
|
155
|
+
.extend(baseAgentSchema.shape),
|
|
156
|
+
z
|
|
157
|
+
.object({
|
|
158
|
+
type: z.literal("image"),
|
|
159
|
+
instructions: instructionsSchema,
|
|
160
|
+
inputFileKey: optionalize(z.string()),
|
|
161
|
+
})
|
|
162
|
+
.extend(baseAgentSchema.shape),
|
|
163
|
+
z
|
|
164
|
+
.object({
|
|
165
|
+
type: z.literal("mcp"),
|
|
166
|
+
url: optionalize(z.string()),
|
|
167
|
+
command: optionalize(z.string()),
|
|
168
|
+
args: optionalize(z.array(z.string())),
|
|
169
|
+
})
|
|
170
|
+
.extend(baseAgentSchema.shape),
|
|
171
|
+
z
|
|
172
|
+
.object({
|
|
173
|
+
type: z.literal("team"),
|
|
174
|
+
mode: optionalize(z.nativeEnum(ProcessMode)),
|
|
175
|
+
iterateOn: optionalize(z.string()),
|
|
176
|
+
concurrency: optionalize(z.number().int().min(1)),
|
|
177
|
+
iterateWithPreviousOutput: optionalize(z.boolean()),
|
|
178
|
+
includeAllStepsOutput: optionalize(z.boolean()),
|
|
179
|
+
reflection: camelizeSchema(optionalize(z.object({
|
|
180
|
+
reviewer: nestAgentSchema,
|
|
181
|
+
isApproved: z.string(),
|
|
182
|
+
maxIterations: optionalize(z.number().int().min(1)),
|
|
183
|
+
returnLastOnMaxIterations: optionalize(z.boolean()),
|
|
184
|
+
customErrorMessage: optionalize(z.string()),
|
|
185
|
+
}))),
|
|
186
|
+
})
|
|
187
|
+
.extend(baseAgentSchema.shape),
|
|
188
|
+
z
|
|
189
|
+
.object({
|
|
190
|
+
type: z.literal("transform"),
|
|
191
|
+
jsonata: z.string(),
|
|
192
|
+
})
|
|
193
|
+
.extend(baseAgentSchema.shape),
|
|
194
|
+
z
|
|
195
|
+
.object({
|
|
196
|
+
type: z.literal("function"),
|
|
197
|
+
process: z.preprocess((v) => (typeof v === "string" ? codeToFunctionAgentFn(v) : v), z.custom()),
|
|
198
|
+
})
|
|
199
|
+
.extend(baseAgentSchema.shape),
|
|
200
|
+
]),
|
|
162
201
|
]));
|
|
163
202
|
});
|
|
164
|
-
return agentSchema
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return agent;
|
|
178
|
-
}
|
|
203
|
+
return agentSchema;
|
|
204
|
+
};
|
|
205
|
+
export const getNestAgentSchema = ({ filepath, }) => {
|
|
206
|
+
const agentSchema = getAgentSchema({ filepath });
|
|
207
|
+
return z.lazy(() => z.union([
|
|
208
|
+
agentSchema,
|
|
209
|
+
z.string(),
|
|
210
|
+
camelizeSchema(z.object({
|
|
211
|
+
url: z.string(),
|
|
212
|
+
defaultInput: optionalize(defaultInputSchema),
|
|
213
|
+
})),
|
|
214
|
+
]));
|
|
215
|
+
};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { type AFSModule } from "@aigne/afs";
|
|
1
|
+
import { AFS, type AFSModule } from "@aigne/afs";
|
|
2
2
|
import { type ZodType, z } from "zod";
|
|
3
3
|
import { Agent, type AgentOptions } from "../agents/agent.js";
|
|
4
4
|
import type { ChatModel } from "../agents/chat-model.js";
|
|
5
5
|
import type { ImageModel } from "../agents/image-model.js";
|
|
6
6
|
import type { AIGNEOptions } from "../aigne/aigne.js";
|
|
7
7
|
import type { MemoryAgent, MemoryAgentOptions } from "../memory/memory.js";
|
|
8
|
+
import { PromptBuilder } from "../prompt/prompt-builder.js";
|
|
8
9
|
import { type PromiseOrValue } from "../utils/type-utils.js";
|
|
10
|
+
import { type Instructions, loadAgentFromYamlFile, type NestAgentSchema } from "./agent-yaml.js";
|
|
9
11
|
export interface LoadOptions {
|
|
10
12
|
memories?: {
|
|
11
13
|
new (parameters?: MemoryAgentOptions): MemoryAgent;
|
|
@@ -13,6 +15,7 @@ export interface LoadOptions {
|
|
|
13
15
|
model?: ChatModel | ((model?: z.infer<typeof aigneFileSchema>["model"]) => PromiseOrValue<ChatModel | undefined>);
|
|
14
16
|
imageModel?: ImageModel | ((model?: z.infer<typeof aigneFileSchema>["imageModel"]) => PromiseOrValue<ImageModel | undefined>);
|
|
15
17
|
afs?: {
|
|
18
|
+
sharedAFS?: AFS;
|
|
16
19
|
availableModules?: {
|
|
17
20
|
module: string;
|
|
18
21
|
alias?: string[];
|
|
@@ -20,9 +23,14 @@ export interface LoadOptions {
|
|
|
20
23
|
}[];
|
|
21
24
|
};
|
|
22
25
|
aigne?: z.infer<typeof aigneFileSchema>;
|
|
26
|
+
require?: (modulePath: string, options: {
|
|
27
|
+
parent?: string;
|
|
28
|
+
}) => Promise<any>;
|
|
23
29
|
}
|
|
24
30
|
export declare function load(path: string, options?: LoadOptions): Promise<AIGNEOptions>;
|
|
25
31
|
export declare function loadAgent(path: string, options?: LoadOptions, agentOptions?: AgentOptions): Promise<Agent>;
|
|
32
|
+
export declare function loadNestAgent(path: string, agent: NestAgentSchema, options?: LoadOptions, agentOptions?: AgentOptions & Record<string, unknown>): Promise<Agent>;
|
|
33
|
+
export declare function parseAgent(path: string, agent: Awaited<ReturnType<typeof loadAgentFromYamlFile>>, options?: LoadOptions, agentOptions?: AgentOptions): Promise<Agent>;
|
|
26
34
|
type CliAgent = string | {
|
|
27
35
|
url?: string;
|
|
28
36
|
name?: string;
|
|
@@ -230,4 +238,5 @@ export declare function loadAIGNEFile(path: string): Promise<{
|
|
|
230
238
|
aigne: z.infer<typeof aigneFileSchema>;
|
|
231
239
|
rootDir: string;
|
|
232
240
|
}>;
|
|
241
|
+
export declare function instructionsToPromptBuilder(instructions: Instructions): PromptBuilder;
|
|
233
242
|
export {};
|
package/lib/esm/loader/index.js
CHANGED
|
@@ -10,9 +10,10 @@ import { TeamAgent } from "../agents/team-agent.js";
|
|
|
10
10
|
import { TransformAgent } from "../agents/transform-agent.js";
|
|
11
11
|
import { PromptBuilder } from "../prompt/prompt-builder.js";
|
|
12
12
|
import { ChatMessagesTemplate, parseChatMessages } from "../prompt/template.js";
|
|
13
|
+
import { isAgent } from "../utils/agent-utils.js";
|
|
13
14
|
import { flat, isNil, isNonNullable, omitBy, tryOrThrow, } from "../utils/type-utils.js";
|
|
14
15
|
import { loadAgentFromJsFile } from "./agent-js.js";
|
|
15
|
-
import { loadAgentFromYamlFile } from "./agent-yaml.js";
|
|
16
|
+
import { loadAgentFromYamlFile, } from "./agent-yaml.js";
|
|
16
17
|
import { camelizeSchema, chatModelSchema, imageModelSchema, optionalize } from "./schema.js";
|
|
17
18
|
const AIGNE_FILE_NAME = ["aigne.yaml", "aigne.yml"];
|
|
18
19
|
export async function load(path, options = {}) {
|
|
@@ -66,17 +67,18 @@ export async function loadAgent(path, options, agentOptions) {
|
|
|
66
67
|
return parseAgent(path, agent, options, agentOptions);
|
|
67
68
|
}
|
|
68
69
|
if ([".yml", ".yaml"].includes(nodejs.path.extname(path))) {
|
|
69
|
-
const agent = await loadAgentFromYamlFile(path);
|
|
70
|
+
const agent = await loadAgentFromYamlFile(path, options);
|
|
70
71
|
return parseAgent(path, agent, options, agentOptions);
|
|
71
72
|
}
|
|
72
73
|
throw new Error(`Unsupported agent file type: ${path}`);
|
|
73
74
|
}
|
|
74
|
-
async function loadNestAgent(path, agent, options) {
|
|
75
|
+
export async function loadNestAgent(path, agent, options, agentOptions) {
|
|
75
76
|
return typeof agent === "object" && "type" in agent
|
|
76
|
-
? parseAgent(path, agent, options)
|
|
77
|
+
? parseAgent(path, agent, options, agentOptions)
|
|
77
78
|
: typeof agent === "string"
|
|
78
|
-
? loadAgent(nodejs.path.join(nodejs.path.dirname(path), agent), options)
|
|
79
|
+
? loadAgent(nodejs.path.join(nodejs.path.dirname(path), agent), options, agentOptions)
|
|
79
80
|
: loadAgent(nodejs.path.join(nodejs.path.dirname(path), agent.url), options, {
|
|
81
|
+
...agentOptions,
|
|
80
82
|
defaultInput: agent.defaultInput,
|
|
81
83
|
hooks: await parseHooks(path, agent.hooks, options),
|
|
82
84
|
});
|
|
@@ -107,15 +109,18 @@ async function loadSkills(path, skills, options) {
|
|
|
107
109
|
}
|
|
108
110
|
return loadedSkills;
|
|
109
111
|
}
|
|
110
|
-
async function parseAgent(path, agent, options, agentOptions) {
|
|
111
|
-
|
|
112
|
+
export async function parseAgent(path, agent, options, agentOptions) {
|
|
113
|
+
if (isAgent(agent))
|
|
114
|
+
return agent;
|
|
112
115
|
const memory = "memory" in agent && options?.memories?.length
|
|
113
116
|
? await loadMemory(options.memories, typeof agent.memory === "object" ? agent.memory.provider : undefined, typeof agent.memory === "object" ? agent.memory : {})
|
|
114
117
|
: undefined;
|
|
115
118
|
let afs;
|
|
116
|
-
if (
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
if (agent.afs !== false && (!agent.afs || agent.afs === true) && options?.afs?.sharedAFS) {
|
|
120
|
+
afs = options.afs.sharedAFS;
|
|
121
|
+
}
|
|
122
|
+
else if (agent.afs === true) {
|
|
123
|
+
afs = new AFS();
|
|
119
124
|
}
|
|
120
125
|
else if (agent.afs) {
|
|
121
126
|
afs = new AFS();
|
|
@@ -128,6 +133,12 @@ async function parseAgent(path, agent, options, agentOptions) {
|
|
|
128
133
|
afs.mount(module);
|
|
129
134
|
}
|
|
130
135
|
}
|
|
136
|
+
const skills = "skills" in agent && agent.skills
|
|
137
|
+
? await loadSkills(path, agent.skills, {
|
|
138
|
+
...options,
|
|
139
|
+
afs: { ...options?.afs, sharedAFS: (agent.shareAFS && afs) || options?.afs?.sharedAFS },
|
|
140
|
+
})
|
|
141
|
+
: [];
|
|
131
142
|
const model = agent.model && typeof options?.model === "function"
|
|
132
143
|
? await options.model({ ...options.aigne?.model, ...omitBy(agent.model, (v) => isNil(v)) })
|
|
133
144
|
: undefined;
|
|
@@ -142,22 +153,17 @@ async function parseAgent(path, agent, options, agentOptions) {
|
|
|
142
153
|
...agent,
|
|
143
154
|
model,
|
|
144
155
|
imageModel,
|
|
145
|
-
skills,
|
|
146
156
|
memory,
|
|
147
157
|
hooks: [
|
|
148
158
|
...((await parseHooks(path, agent.hooks, options)) ?? []),
|
|
149
159
|
...[agentOptions?.hooks].flat().filter(isNonNullable),
|
|
150
160
|
],
|
|
151
|
-
|
|
161
|
+
skills: [...(agentOptions?.skills || []), ...skills],
|
|
162
|
+
afs: afs || agentOptions?.afs,
|
|
152
163
|
};
|
|
153
164
|
let instructions;
|
|
154
|
-
if ("instructions" in agent && agent.instructions) {
|
|
155
|
-
instructions =
|
|
156
|
-
instructions: ChatMessagesTemplate.from(parseChatMessages(agent.instructions.map((i) => ({
|
|
157
|
-
...i,
|
|
158
|
-
options: { workingDir: nodejs.path.dirname(i.path) },
|
|
159
|
-
})))),
|
|
160
|
-
});
|
|
165
|
+
if ("instructions" in agent && agent.instructions && ["ai", "image"].includes(agent.type)) {
|
|
166
|
+
instructions = instructionsToPromptBuilder(agent.instructions);
|
|
161
167
|
}
|
|
162
168
|
switch (agent.type) {
|
|
163
169
|
case "ai": {
|
|
@@ -214,6 +220,14 @@ async function parseAgent(path, agent, options, agentOptions) {
|
|
|
214
220
|
});
|
|
215
221
|
}
|
|
216
222
|
}
|
|
223
|
+
if ("agentClass" in agent && agent.agentClass) {
|
|
224
|
+
return await agent.agentClass.load({
|
|
225
|
+
filepath: path,
|
|
226
|
+
parsed: baseOptions,
|
|
227
|
+
options,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
throw new Error(`Unsupported agent type: ${"type" in agent ? agent.type : "unknown"} at path: ${path}`);
|
|
217
231
|
}
|
|
218
232
|
async function loadMemory(memories, provider, options) {
|
|
219
233
|
const M = !provider
|
|
@@ -269,3 +283,11 @@ async function findAIGNEFile(path) {
|
|
|
269
283
|
}
|
|
270
284
|
throw new Error(`aigne.yaml not found in ${path}. Please ensure you are in the correct directory or provide a valid path.`);
|
|
271
285
|
}
|
|
286
|
+
export function instructionsToPromptBuilder(instructions) {
|
|
287
|
+
return new PromptBuilder({
|
|
288
|
+
instructions: ChatMessagesTemplate.from(parseChatMessages(instructions.map((i) => ({
|
|
289
|
+
...i,
|
|
290
|
+
options: { workingDir: nodejs.path.dirname(i.path) },
|
|
291
|
+
})))),
|
|
292
|
+
});
|
|
293
|
+
}
|
|
@@ -2,7 +2,6 @@ import type { GetPromptResult } from "@modelcontextprotocol/sdk/types.js";
|
|
|
2
2
|
import { Agent, type AgentInvokeOptions, type Message } from "../agents/agent.js";
|
|
3
3
|
import { type AIAgent } from "../agents/ai-agent.js";
|
|
4
4
|
import type { ChatModel, ChatModelInput } from "../agents/chat-model.js";
|
|
5
|
-
import type { ImageAgent } from "../agents/image-agent.js";
|
|
6
5
|
import { type FileUnionContent } from "../agents/model.js";
|
|
7
6
|
import { ChatMessagesTemplate } from "./template.js";
|
|
8
7
|
export interface PromptBuilderOptions {
|
|
@@ -26,11 +25,12 @@ export declare class PromptBuilder {
|
|
|
26
25
|
constructor(options?: PromptBuilderOptions);
|
|
27
26
|
instructions?: string | ChatMessagesTemplate;
|
|
28
27
|
workingDir?: string;
|
|
28
|
+
copy(): PromptBuilder;
|
|
29
29
|
build(options: PromptBuildOptions): Promise<ChatModelInput & {
|
|
30
30
|
toolAgents?: Agent[];
|
|
31
31
|
}>;
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
buildPrompt(options: Pick<PromptBuildOptions, "input" | "context"> & {
|
|
33
|
+
inputFileKey?: string;
|
|
34
34
|
}): Promise<{
|
|
35
35
|
prompt: string;
|
|
36
36
|
image?: FileUnionContent[];
|
|
@@ -62,6 +62,12 @@ export class PromptBuilder {
|
|
|
62
62
|
}
|
|
63
63
|
instructions;
|
|
64
64
|
workingDir;
|
|
65
|
+
copy() {
|
|
66
|
+
return new PromptBuilder({
|
|
67
|
+
instructions: typeof this.instructions === "string" ? this.instructions : this.instructions?.copy(),
|
|
68
|
+
workingDir: this.workingDir,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
65
71
|
async build(options) {
|
|
66
72
|
return {
|
|
67
73
|
messages: await this.buildMessages(options),
|
|
@@ -72,11 +78,11 @@ export class PromptBuilder {
|
|
|
72
78
|
...(await this.buildTools(options)),
|
|
73
79
|
};
|
|
74
80
|
}
|
|
75
|
-
async
|
|
81
|
+
async buildPrompt(options) {
|
|
76
82
|
const messages = (await (typeof this.instructions === "string"
|
|
77
83
|
? ChatMessagesTemplate.from([SystemMessageTemplate.from(this.instructions)])
|
|
78
84
|
: this.instructions)?.format(this.getTemplateVariables(options), { workingDir: this.workingDir })) ?? [];
|
|
79
|
-
const inputFileKey = options.
|
|
85
|
+
const inputFileKey = options.inputFileKey;
|
|
80
86
|
const files = flat(inputFileKey
|
|
81
87
|
? checkArguments("Check input files", optionalize(fileUnionContentsSchema), options.input?.[inputFileKey])
|
|
82
88
|
: null);
|
|
@@ -52,19 +52,39 @@ export async function getAFSSkills(afs) {
|
|
|
52
52
|
}),
|
|
53
53
|
FunctionAgent.from({
|
|
54
54
|
name: "afs_read",
|
|
55
|
-
description:
|
|
55
|
+
description: `\
|
|
56
|
+
Read file contents from the AFS - path must be an exact file path from list or search results
|
|
57
|
+
|
|
58
|
+
Usage:
|
|
59
|
+
- Use withLineNumbers=true to get line numbers for code reviews or edits
|
|
60
|
+
`,
|
|
56
61
|
inputSchema: z.object({
|
|
57
62
|
path: z
|
|
58
63
|
.string()
|
|
59
64
|
.describe("Exact file path from list or search results (e.g., '/docs/api.md', '/src/utils/helper.js')"),
|
|
65
|
+
withLineNumbers: z
|
|
66
|
+
.boolean()
|
|
67
|
+
.optional()
|
|
68
|
+
.describe(`Whether to include line numbers in the returned content, default is false`),
|
|
60
69
|
}),
|
|
61
70
|
process: async (input) => {
|
|
62
71
|
const result = await afs.read(input.path);
|
|
72
|
+
let content = result.result?.content;
|
|
73
|
+
if (input.withLineNumbers && typeof content === "string") {
|
|
74
|
+
content = content
|
|
75
|
+
.split("\n")
|
|
76
|
+
.map((line, idx) => `${idx + 1}| ${line}`)
|
|
77
|
+
.join("\n");
|
|
78
|
+
}
|
|
63
79
|
return {
|
|
64
80
|
status: "success",
|
|
65
81
|
tool: "afs_read",
|
|
66
82
|
path: input.path,
|
|
67
83
|
...result,
|
|
84
|
+
result: {
|
|
85
|
+
...result.result,
|
|
86
|
+
content,
|
|
87
|
+
},
|
|
68
88
|
};
|
|
69
89
|
},
|
|
70
90
|
}),
|
|
@@ -106,7 +126,9 @@ export async function getAFSSkills(afs) {
|
|
|
106
126
|
}
|
|
107
127
|
function buildTreeView(entries) {
|
|
108
128
|
const tree = {};
|
|
129
|
+
const entryMap = new Map();
|
|
109
130
|
for (const entry of entries) {
|
|
131
|
+
entryMap.set(entry.path, entry);
|
|
110
132
|
const parts = entry.path.split("/").filter(Boolean);
|
|
111
133
|
let current = tree;
|
|
112
134
|
for (const part of parts) {
|
|
@@ -116,13 +138,28 @@ function buildTreeView(entries) {
|
|
|
116
138
|
current = current[part];
|
|
117
139
|
}
|
|
118
140
|
}
|
|
119
|
-
function renderTree(node, prefix = "") {
|
|
141
|
+
function renderTree(node, prefix = "", currentPath = "") {
|
|
120
142
|
let result = "";
|
|
121
143
|
const keys = Object.keys(node);
|
|
122
144
|
keys.forEach((key, index) => {
|
|
123
145
|
const isLast = index === keys.length - 1;
|
|
124
|
-
|
|
125
|
-
|
|
146
|
+
const fullPath = currentPath ? `${currentPath}/${key}` : `/${key}`;
|
|
147
|
+
const entry = entryMap.get(fullPath);
|
|
148
|
+
// Build metadata suffix
|
|
149
|
+
const metadataParts = [];
|
|
150
|
+
// Children count
|
|
151
|
+
const childrenCount = entry?.metadata?.childrenCount;
|
|
152
|
+
if (childrenCount !== undefined && childrenCount > 0) {
|
|
153
|
+
metadataParts.push(`${childrenCount} items`);
|
|
154
|
+
}
|
|
155
|
+
// Executable
|
|
156
|
+
if (entry?.metadata?.execute) {
|
|
157
|
+
metadataParts.push("executable");
|
|
158
|
+
}
|
|
159
|
+
const metadataSuffix = metadataParts.length > 0 ? ` [${metadataParts.join(", ")}]` : "";
|
|
160
|
+
result += `${prefix}${isLast ? "└── " : "├── "}${key}${metadataSuffix}`;
|
|
161
|
+
result += `\n`;
|
|
162
|
+
result += renderTree(node[key], `${prefix}${isLast ? " " : "│ "}`, fullPath);
|
|
126
163
|
});
|
|
127
164
|
return result;
|
|
128
165
|
}
|
|
@@ -62,6 +62,7 @@ export declare class ChatMessagesTemplate {
|
|
|
62
62
|
messages: ChatMessageTemplate[];
|
|
63
63
|
static from(messages: ChatMessageTemplate[] | string): ChatMessagesTemplate;
|
|
64
64
|
constructor(messages: ChatMessageTemplate[]);
|
|
65
|
+
copy(): ChatMessagesTemplate;
|
|
65
66
|
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<ChatModelInputMessage[]>;
|
|
66
67
|
}
|
|
67
68
|
declare const chatMessageSchema: z.ZodUnion<[z.ZodObject<{
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
2
2
|
import nunjucks from "nunjucks";
|
|
3
|
+
import { stringify } from "yaml";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
import { isNil, omitBy } from "../utils/type-utils.js";
|
|
5
6
|
import { setupFilters } from "./filters/index.js";
|
|
@@ -130,9 +131,7 @@ export class ToolMessageTemplate extends ChatMessageTemplate {
|
|
|
130
131
|
return new ToolMessageTemplate(content, toolCallId, name, options);
|
|
131
132
|
}
|
|
132
133
|
constructor(content, toolCallId, name, options) {
|
|
133
|
-
super("tool", typeof content === "string"
|
|
134
|
-
? content
|
|
135
|
-
: JSON.stringify(content, (_, value) => typeof value === "bigint" ? value.toString() : value), name, options);
|
|
134
|
+
super("tool", typeof content === "string" ? content : stringify(content), name, options);
|
|
136
135
|
this.toolCallId = toolCallId;
|
|
137
136
|
}
|
|
138
137
|
async format(_variables, _options) {
|
|
@@ -153,6 +152,9 @@ export class ChatMessagesTemplate {
|
|
|
153
152
|
constructor(messages) {
|
|
154
153
|
this.messages = messages;
|
|
155
154
|
}
|
|
155
|
+
copy() {
|
|
156
|
+
return new ChatMessagesTemplate(this.messages.map((m) => m));
|
|
157
|
+
}
|
|
156
158
|
async format(variables, options) {
|
|
157
159
|
return Promise.all(this.messages.map((message) => message.format(variables, options)));
|
|
158
160
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentHooks } from "../agents/agent.js";
|
|
1
|
+
import type { Agent, AgentHooks } from "../agents/agent.js";
|
|
2
2
|
import type { AIGNECLIAgents } from "../aigne/type.js";
|
|
3
3
|
export declare function sortHooks(hooks: AgentHooks[]): AgentHooks[];
|
|
4
4
|
export interface CLIAgent<T> {
|
|
@@ -9,4 +9,5 @@ export interface CLIAgent<T> {
|
|
|
9
9
|
agents?: CLIAgent<T>[];
|
|
10
10
|
}
|
|
11
11
|
export declare function mapCliAgent<A, O>({ agent, agents, ...input }: CLIAgent<A>, transform: (input: A) => O): CLIAgent<O>;
|
|
12
|
-
export declare function findCliAgent(cli: AIGNECLIAgents, parent: string[] | "*", name: string):
|
|
12
|
+
export declare function findCliAgent(cli: AIGNECLIAgents, parent: string[] | "*", name: string): Agent<any, any> | undefined;
|
|
13
|
+
export declare function isAgent<A extends Agent>(obj: any): obj is A;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Estimate tokens in text by analyzing character types
|
|
3
|
+
* This function handles mixed-language text (Chinese and English) by counting
|
|
4
|
+
* different character types and applying appropriate token ratios for each type
|
|
5
|
+
*
|
|
6
|
+
* @param text - The text to estimate
|
|
7
|
+
* @returns Estimated token count
|
|
8
|
+
*/
|
|
9
|
+
export declare function estimateTokens(text: string): number;
|