@aigne/core 1.9.0 → 1.11.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 +25 -0
- package/LICENSE +93 -0
- package/README.md +89 -0
- package/README.zh.md +89 -0
- package/lib/cjs/agents/agent.d.ts +30 -3
- package/lib/cjs/agents/agent.js +51 -22
- package/lib/cjs/agents/ai-agent.d.ts +14 -11
- package/lib/cjs/agents/ai-agent.js +36 -17
- package/lib/cjs/agents/user-agent.d.ts +3 -3
- package/lib/cjs/agents/user-agent.js +14 -8
- package/lib/cjs/execution-engine/context.d.ts +18 -7
- package/lib/cjs/execution-engine/context.js +76 -28
- package/lib/cjs/loader/agent-js.d.ts +2 -2
- package/lib/cjs/loader/agent-js.js +4 -5
- package/lib/cjs/loader/agent-yaml.d.ts +8 -5
- package/lib/cjs/loader/agent-yaml.js +13 -1
- package/lib/cjs/loader/index.d.ts +4 -4
- package/lib/cjs/loader/index.js +4 -15
- package/lib/cjs/models/chat-model.d.ts +4 -0
- package/lib/cjs/models/chat-model.js +6 -0
- package/lib/cjs/models/claude-chat-model.d.ts +3 -1
- package/lib/cjs/models/claude-chat-model.js +75 -60
- package/lib/cjs/models/open-router-chat-model.d.ts +1 -0
- package/lib/cjs/models/open-router-chat-model.js +1 -0
- package/lib/cjs/models/openai-chat-model.d.ts +12 -3
- package/lib/cjs/models/openai-chat-model.js +110 -46
- package/lib/cjs/utils/camelize.d.ts +13 -0
- package/lib/cjs/utils/camelize.js +16 -0
- package/lib/cjs/utils/stream-utils.d.ts +17 -0
- package/lib/cjs/utils/stream-utils.js +165 -0
- package/lib/cjs/utils/type-utils.d.ts +1 -0
- package/lib/cjs/utils/type-utils.js +7 -0
- package/lib/dts/agents/agent.d.ts +30 -3
- package/lib/dts/agents/ai-agent.d.ts +14 -11
- package/lib/dts/agents/user-agent.d.ts +3 -3
- package/lib/dts/execution-engine/context.d.ts +18 -7
- package/lib/dts/loader/agent-js.d.ts +2 -2
- package/lib/dts/loader/agent-yaml.d.ts +8 -5
- package/lib/dts/loader/index.d.ts +4 -4
- package/lib/dts/models/chat-model.d.ts +4 -0
- package/lib/dts/models/claude-chat-model.d.ts +3 -1
- package/lib/dts/models/open-router-chat-model.d.ts +1 -0
- package/lib/dts/models/openai-chat-model.d.ts +12 -3
- package/lib/dts/utils/camelize.d.ts +13 -0
- package/lib/dts/utils/stream-utils.d.ts +17 -0
- package/lib/dts/utils/type-utils.d.ts +1 -0
- package/lib/esm/agents/agent.d.ts +30 -3
- package/lib/esm/agents/agent.js +51 -23
- package/lib/esm/agents/ai-agent.d.ts +14 -11
- package/lib/esm/agents/ai-agent.js +37 -18
- package/lib/esm/agents/user-agent.d.ts +3 -3
- package/lib/esm/agents/user-agent.js +15 -9
- package/lib/esm/execution-engine/context.d.ts +18 -7
- package/lib/esm/execution-engine/context.js +78 -30
- package/lib/esm/loader/agent-js.d.ts +2 -2
- package/lib/esm/loader/agent-js.js +4 -5
- package/lib/esm/loader/agent-yaml.d.ts +8 -5
- package/lib/esm/loader/agent-yaml.js +13 -1
- package/lib/esm/loader/index.d.ts +4 -4
- package/lib/esm/loader/index.js +4 -15
- package/lib/esm/models/chat-model.d.ts +4 -0
- package/lib/esm/models/chat-model.js +6 -0
- package/lib/esm/models/claude-chat-model.d.ts +3 -1
- package/lib/esm/models/claude-chat-model.js +75 -60
- package/lib/esm/models/open-router-chat-model.d.ts +1 -0
- package/lib/esm/models/open-router-chat-model.js +1 -0
- package/lib/esm/models/openai-chat-model.d.ts +12 -3
- package/lib/esm/models/openai-chat-model.js +110 -45
- package/lib/esm/utils/camelize.d.ts +13 -0
- package/lib/esm/utils/camelize.js +10 -0
- package/lib/esm/utils/stream-utils.d.ts +17 -0
- package/lib/esm/utils/stream-utils.js +149 -0
- package/lib/esm/utils/type-utils.d.ts +1 -0
- package/lib/esm/utils/type-utils.js +6 -0
- package/package.json +4 -2
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.UserAgent = void 0;
|
|
4
4
|
const web_1 = require("node:stream/web");
|
|
5
5
|
const context_js_1 = require("../execution-engine/context.js");
|
|
6
|
+
const stream_utils_js_1 = require("../utils/stream-utils.js");
|
|
6
7
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
7
8
|
const agent_js_1 = require("./agent.js");
|
|
8
9
|
class UserAgent extends agent_js_1.Agent {
|
|
@@ -18,26 +19,31 @@ class UserAgent extends agent_js_1.Agent {
|
|
|
18
19
|
context;
|
|
19
20
|
_process;
|
|
20
21
|
activeAgent;
|
|
21
|
-
call(input, context) {
|
|
22
|
+
call = ((input, context, options) => {
|
|
22
23
|
if (!context)
|
|
23
24
|
this.context = this.context.newContext({ reset: true });
|
|
24
|
-
return super.call(input, context ?? this.context);
|
|
25
|
-
}
|
|
26
|
-
async process(input, context) {
|
|
25
|
+
return super.call(input, context ?? this.context, options);
|
|
26
|
+
});
|
|
27
|
+
async *process(input, context) {
|
|
27
28
|
if (this._process) {
|
|
28
|
-
|
|
29
|
+
yield { delta: { json: await this._process(input, context) } };
|
|
30
|
+
return;
|
|
29
31
|
}
|
|
30
32
|
if (this.activeAgent) {
|
|
31
33
|
const [output, agent] = await context.call(this.activeAgent, input, {
|
|
32
34
|
returnActiveAgent: true,
|
|
35
|
+
streaming: true,
|
|
36
|
+
});
|
|
37
|
+
agent.then((agent) => {
|
|
38
|
+
this.activeAgent = agent;
|
|
33
39
|
});
|
|
34
|
-
|
|
35
|
-
return
|
|
40
|
+
yield* (0, stream_utils_js_1.readableStreamToAsyncIterator)(output);
|
|
41
|
+
return;
|
|
36
42
|
}
|
|
37
43
|
const publicTopic = typeof this.publishTopic === "function" ? await this.publishTopic(input) : this.publishTopic;
|
|
38
44
|
if (publicTopic?.length) {
|
|
39
45
|
context.publish(publicTopic, (0, context_js_1.createPublishMessage)(input, this));
|
|
40
|
-
return
|
|
46
|
+
return;
|
|
41
47
|
}
|
|
42
48
|
throw new Error("UserAgent must have a process function or a publishTopic");
|
|
43
49
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import EventEmitter from "node:events";
|
|
2
|
-
import { Agent, type FunctionAgentFn, type Message } from "../agents/agent.js";
|
|
2
|
+
import { Agent, type AgentCallOptions, type AgentProcessAsyncGenerator, type AgentResponse, type AgentResponseStream, type FunctionAgentFn, type Message } from "../agents/agent.js";
|
|
3
3
|
import { UserAgent } from "../agents/user-agent.js";
|
|
4
4
|
import type { ChatModel } from "../models/chat-model.js";
|
|
5
5
|
import { type OmitPropertiesFromArrayFirstElement } from "../utils/type-utils.js";
|
|
@@ -27,7 +27,7 @@ export interface ContextEventMap {
|
|
|
27
27
|
export type ContextEmitEventMap = {
|
|
28
28
|
[K in keyof ContextEventMap]: OmitPropertiesFromArrayFirstElement<ContextEventMap[K], "contextId" | "parentContextId" | "timestamp">;
|
|
29
29
|
};
|
|
30
|
-
export interface CallOptions {
|
|
30
|
+
export interface CallOptions extends AgentCallOptions {
|
|
31
31
|
returnActiveAgent?: boolean;
|
|
32
32
|
disableTransfer?: boolean;
|
|
33
33
|
}
|
|
@@ -48,19 +48,30 @@ export interface Context extends TypedEventEmitter<ContextEventMap, ContextEmitE
|
|
|
48
48
|
* @param agent Agent to call
|
|
49
49
|
* @param message Message to pass to the agent
|
|
50
50
|
* @param options.returnActiveAgent return the active agent
|
|
51
|
+
* @param options.streaming return a stream of the output
|
|
51
52
|
* @returns the output of the agent and the final active agent
|
|
52
53
|
*/
|
|
53
54
|
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string, options: CallOptions & {
|
|
54
55
|
returnActiveAgent: true;
|
|
56
|
+
streaming?: false;
|
|
55
57
|
}): Promise<[O, Runnable]>;
|
|
58
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string, options: CallOptions & {
|
|
59
|
+
returnActiveAgent: true;
|
|
60
|
+
streaming: true;
|
|
61
|
+
}): Promise<[AgentResponseStream<O>, Promise<Runnable>]>;
|
|
56
62
|
/**
|
|
57
63
|
* Call an agent with a message
|
|
58
64
|
* @param agent Agent to call
|
|
59
65
|
* @param message Message to pass to the agent
|
|
60
66
|
* @returns the output of the agent
|
|
61
67
|
*/
|
|
62
|
-
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string, options?: CallOptions
|
|
63
|
-
|
|
68
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string, options?: CallOptions & {
|
|
69
|
+
streaming?: false;
|
|
70
|
+
}): Promise<O>;
|
|
71
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message: I | string, options: CallOptions & {
|
|
72
|
+
streaming: true;
|
|
73
|
+
}): Promise<AgentResponseStream<O>>;
|
|
74
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>, message?: I | string, options?: CallOptions): UserAgent<I, O> | Promise<AgentResponse<O> | [AgentResponse<O>, Runnable]>;
|
|
64
75
|
/**
|
|
65
76
|
* Publish a message to a topic, the engine will call the listeners of the topic
|
|
66
77
|
* @param topic topic name, or an array of topic names
|
|
@@ -99,6 +110,7 @@ export declare class ExecutionContext implements Context {
|
|
|
99
110
|
reset?: boolean;
|
|
100
111
|
}): ExecutionContext;
|
|
101
112
|
call: Context["call"];
|
|
113
|
+
private onCallSuccess;
|
|
102
114
|
publish: Context["publish"];
|
|
103
115
|
subscribe: Context["subscribe"];
|
|
104
116
|
unsubscribe: Context["unsubscribe"];
|
|
@@ -122,9 +134,8 @@ declare class ExecutionContextInternal {
|
|
|
122
134
|
private timer?;
|
|
123
135
|
private initTimeout;
|
|
124
136
|
get status(): "normal" | "timeout";
|
|
125
|
-
call<I extends Message, O extends Message>(agent: Runnable<I, O>, input: I, context: Context, options?: CallOptions):
|
|
126
|
-
|
|
127
|
-
output: O;
|
|
137
|
+
call<I extends Message, O extends Message>(agent: Runnable<I, O>, input: I, context: Context, options?: CallOptions): AgentProcessAsyncGenerator<O & {
|
|
138
|
+
__activeAgent__: Runnable;
|
|
128
139
|
}>;
|
|
129
140
|
private callAgent;
|
|
130
141
|
}
|
|
@@ -12,6 +12,7 @@ const agent_js_1 = require("../agents/agent.js");
|
|
|
12
12
|
const types_js_1 = require("../agents/types.js");
|
|
13
13
|
const user_agent_js_1 = require("../agents/user-agent.js");
|
|
14
14
|
const prompt_builder_js_1 = require("../prompt/prompt-builder.js");
|
|
15
|
+
const stream_utils_js_1 = require("../utils/stream-utils.js");
|
|
15
16
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
16
17
|
const message_queue_js_1 = require("./message-queue.js");
|
|
17
18
|
const usage_js_1 = require("./usage.js");
|
|
@@ -69,23 +70,49 @@ class ExecutionContext {
|
|
|
69
70
|
}
|
|
70
71
|
const newContext = this.newContext();
|
|
71
72
|
const msg = (0, prompt_builder_js_1.createMessage)(message);
|
|
72
|
-
return newContext.internal
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
: activeAgent.publishTopic;
|
|
79
|
-
if (publishTopics?.length) {
|
|
80
|
-
newContext.publish(publishTopics, createPublishMessage(output, activeAgent));
|
|
73
|
+
return Promise.resolve(newContext.internal.call(agent, msg, newContext, options)).then(async (response) => {
|
|
74
|
+
if (!options?.streaming) {
|
|
75
|
+
const { __activeAgent__: activeAgent, ...output } = await (0, stream_utils_js_1.agentResponseStreamToObject)(response);
|
|
76
|
+
this.onCallSuccess(activeAgent, output, newContext);
|
|
77
|
+
if (options?.returnActiveAgent) {
|
|
78
|
+
return [output, activeAgent];
|
|
81
79
|
}
|
|
80
|
+
return output;
|
|
82
81
|
}
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
const activeAgentPromise = Promise.withResolvers();
|
|
83
|
+
const stream = (0, stream_utils_js_1.onAgentResponseStreamEnd)((0, stream_utils_js_1.asyncGeneratorToReadableStream)(response), async ({ __activeAgent__: activeAgent, ...output }) => {
|
|
84
|
+
this.onCallSuccess(activeAgent, output, newContext);
|
|
85
|
+
activeAgentPromise.resolve(activeAgent);
|
|
86
|
+
}, {
|
|
87
|
+
processChunk(chunk) {
|
|
88
|
+
if (chunk.delta.json) {
|
|
89
|
+
return {
|
|
90
|
+
...chunk,
|
|
91
|
+
delta: {
|
|
92
|
+
...chunk.delta,
|
|
93
|
+
json: (0, type_utils_js_1.omitBy)(chunk.delta.json, (_, k) => k === "__activeAgent__"),
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return chunk;
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
if (options.returnActiveAgent) {
|
|
101
|
+
return [stream, activeAgentPromise.promise];
|
|
85
102
|
}
|
|
86
|
-
return
|
|
103
|
+
return stream;
|
|
87
104
|
});
|
|
88
105
|
});
|
|
106
|
+
async onCallSuccess(activeAgent, output, context) {
|
|
107
|
+
if (activeAgent instanceof agent_js_1.Agent) {
|
|
108
|
+
const publishTopics = typeof activeAgent.publishTopic === "function"
|
|
109
|
+
? await activeAgent.publishTopic(output)
|
|
110
|
+
: activeAgent.publishTopic;
|
|
111
|
+
if (publishTopics?.length) {
|
|
112
|
+
context.publish(publishTopics, createPublishMessage(output, activeAgent));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
89
116
|
publish = ((topic, payload) => {
|
|
90
117
|
return this.internal.messageQueue.publish(topic, { ...payload, context: this });
|
|
91
118
|
});
|
|
@@ -152,11 +179,11 @@ class ExecutionContextInternal {
|
|
|
152
179
|
get status() {
|
|
153
180
|
return this.abortController.signal.aborted ? "timeout" : "normal";
|
|
154
181
|
}
|
|
155
|
-
|
|
182
|
+
call(agent, input, context, options) {
|
|
156
183
|
this.initTimeout();
|
|
157
184
|
return withAbortSignal(this.abortController.signal, new Error("ExecutionContext is timeout"), () => this.callAgent(agent, input, context, options));
|
|
158
185
|
}
|
|
159
|
-
async callAgent(agent, input, context, options) {
|
|
186
|
+
async *callAgent(agent, input, context, options) {
|
|
160
187
|
let activeAgent = agent;
|
|
161
188
|
let output;
|
|
162
189
|
for (;;) {
|
|
@@ -165,7 +192,16 @@ class ExecutionContextInternal {
|
|
|
165
192
|
result = await activeAgent(input, context);
|
|
166
193
|
}
|
|
167
194
|
else {
|
|
168
|
-
result =
|
|
195
|
+
result = {};
|
|
196
|
+
const stream = await activeAgent.call(input, context, { streaming: true });
|
|
197
|
+
for await (const value of (0, stream_utils_js_1.readableStreamToAsyncIterator)(stream)) {
|
|
198
|
+
if (value.delta.text) {
|
|
199
|
+
yield { delta: { text: value.delta.text } };
|
|
200
|
+
}
|
|
201
|
+
if (value.delta.json) {
|
|
202
|
+
Object.assign(result, value.delta.json);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
169
205
|
}
|
|
170
206
|
if (result instanceof agent_js_1.Agent) {
|
|
171
207
|
activeAgent = result;
|
|
@@ -185,22 +221,34 @@ class ExecutionContextInternal {
|
|
|
185
221
|
}
|
|
186
222
|
if (!output)
|
|
187
223
|
throw new Error("Unexpected empty output");
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
224
|
+
yield {
|
|
225
|
+
delta: {
|
|
226
|
+
json: {
|
|
227
|
+
...output,
|
|
228
|
+
__activeAgent__: activeAgent,
|
|
229
|
+
},
|
|
230
|
+
},
|
|
191
231
|
};
|
|
192
232
|
}
|
|
193
233
|
}
|
|
194
|
-
function withAbortSignal(signal, error, fn) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
234
|
+
async function* withAbortSignal(signal, error, fn) {
|
|
235
|
+
const iterator = fn();
|
|
236
|
+
const timeoutPromise = Promise.withResolvers();
|
|
237
|
+
const listener = () => {
|
|
238
|
+
timeoutPromise.reject(error);
|
|
239
|
+
};
|
|
240
|
+
signal.addEventListener("abort", listener);
|
|
241
|
+
try {
|
|
242
|
+
for (;;) {
|
|
243
|
+
const next = await Promise.race([iterator.next(), timeoutPromise.promise]);
|
|
244
|
+
if (next.done)
|
|
245
|
+
break;
|
|
246
|
+
yield next.value;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
signal.removeEventListener("abort", listener);
|
|
251
|
+
}
|
|
204
252
|
}
|
|
205
253
|
const executionContextCallArgsSchema = zod_1.z.object({
|
|
206
254
|
agent: zod_1.z.union([zod_1.z.function(), zod_1.z.instanceof(agent_js_1.Agent)]),
|
|
@@ -4,12 +4,12 @@ export declare function loadAgentFromJsFile(path: string): Promise<{
|
|
|
4
4
|
name: string;
|
|
5
5
|
fn: (args_0: Message) => Message;
|
|
6
6
|
description?: string | undefined;
|
|
7
|
-
|
|
7
|
+
inputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
8
8
|
[x: string]: any;
|
|
9
9
|
}, {
|
|
10
10
|
[x: string]: any;
|
|
11
11
|
}> | undefined;
|
|
12
|
-
|
|
12
|
+
outputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
13
13
|
[x: string]: any;
|
|
14
14
|
}, {
|
|
15
15
|
[x: string]: any;
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.loadAgentFromJsFile = loadAgentFromJsFile;
|
|
37
37
|
const json_schema_to_zod_1 = require("@aigne/json-schema-to-zod");
|
|
38
38
|
const zod_1 = require("zod");
|
|
39
|
+
const camelize_js_1 = require("../utils/camelize.js");
|
|
39
40
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
40
41
|
const schema_js_1 = require("./schema.js");
|
|
41
42
|
const agentJsFileSchema = zod_1.z.object({
|
|
@@ -57,11 +58,9 @@ async function loadAgentFromJsFile(path) {
|
|
|
57
58
|
if (typeof agent !== "function") {
|
|
58
59
|
throw new Error(`Agent file ${path} must export a default function, but got ${typeof agent}`);
|
|
59
60
|
}
|
|
60
|
-
return (0, type_utils_js_1.tryOrThrow)(() => agentJsFileSchema.parse({
|
|
61
|
+
return (0, type_utils_js_1.tryOrThrow)(() => (0, camelize_js_1.customCamelize)(agentJsFileSchema.parse({
|
|
62
|
+
...agent,
|
|
61
63
|
name: agent.agent_name || agent.name,
|
|
62
|
-
description: agent.description,
|
|
63
|
-
input_schema: agent.input_schema,
|
|
64
|
-
output_schema: agent.output_schema,
|
|
65
64
|
fn: agent,
|
|
66
|
-
}), (error) => new Error(`Failed to parse agent from ${path}: ${error.message}`));
|
|
65
|
+
}), { shallowKeys: ["input_schema", "output_schema"] }), (error) => new Error(`Failed to parse agent from ${path}: ${error.message}`));
|
|
67
66
|
}
|
|
@@ -2,21 +2,24 @@ import { type ZodObject, type ZodType, z } from "zod";
|
|
|
2
2
|
export declare function loadAgentFromYamlFile(path: string): Promise<{
|
|
3
3
|
type: "ai";
|
|
4
4
|
name: string;
|
|
5
|
-
description?: string | undefined;
|
|
6
5
|
tools?: string[] | undefined;
|
|
6
|
+
description?: string | undefined;
|
|
7
7
|
instructions?: string | undefined;
|
|
8
|
-
|
|
8
|
+
memory?: true | {
|
|
9
|
+
subscribeTopic: string[];
|
|
10
|
+
} | undefined;
|
|
11
|
+
inputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
9
12
|
[x: string]: any;
|
|
10
13
|
}, {
|
|
11
14
|
[x: string]: any;
|
|
12
15
|
}> | undefined;
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
toolChoice?: "auto" | "none" | "required" | "router" | undefined;
|
|
17
|
+
outputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
15
18
|
[x: string]: any;
|
|
16
19
|
}, {
|
|
17
20
|
[x: string]: any;
|
|
18
21
|
}> | undefined;
|
|
19
|
-
|
|
22
|
+
outputKey?: string | undefined;
|
|
20
23
|
} | {
|
|
21
24
|
type: "mcp";
|
|
22
25
|
url?: string | undefined;
|
|
@@ -5,6 +5,7 @@ const promises_1 = require("node:fs/promises");
|
|
|
5
5
|
const json_schema_to_zod_1 = require("@aigne/json-schema-to-zod");
|
|
6
6
|
const yaml_1 = require("yaml");
|
|
7
7
|
const zod_1 = require("zod");
|
|
8
|
+
const camelize_js_1 = require("../utils/camelize.js");
|
|
8
9
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
9
10
|
const schema_js_1 = require("./schema.js");
|
|
10
11
|
const agentFileSchema = zod_1.z.discriminatedUnion("type", [
|
|
@@ -37,6 +38,15 @@ const agentFileSchema = zod_1.z.discriminatedUnion("type", [
|
|
|
37
38
|
.union([zod_1.z.literal("auto"), zod_1.z.literal("none"), zod_1.z.literal("required"), zod_1.z.literal("router")])
|
|
38
39
|
.nullish()
|
|
39
40
|
.transform((v) => v ?? undefined),
|
|
41
|
+
memory: zod_1.z
|
|
42
|
+
.union([
|
|
43
|
+
zod_1.z.boolean(),
|
|
44
|
+
zod_1.z.object({
|
|
45
|
+
subscribe_topic: zod_1.z.array(zod_1.z.string()),
|
|
46
|
+
}),
|
|
47
|
+
])
|
|
48
|
+
.nullish()
|
|
49
|
+
.transform((v) => v || undefined),
|
|
40
50
|
}),
|
|
41
51
|
zod_1.z.object({
|
|
42
52
|
type: zod_1.z.literal("mcp"),
|
|
@@ -57,6 +67,8 @@ const agentFileSchema = zod_1.z.discriminatedUnion("type", [
|
|
|
57
67
|
async function loadAgentFromYamlFile(path) {
|
|
58
68
|
const raw = await (0, type_utils_js_1.tryOrThrow)(() => (0, promises_1.readFile)(path, "utf8"), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
|
|
59
69
|
const json = await (0, type_utils_js_1.tryOrThrow)(() => (0, yaml_1.parse)(raw), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
|
|
60
|
-
const agent = (0, type_utils_js_1.tryOrThrow)(() => agentFileSchema.parse({ ...json, type: json.type ?? "ai" }),
|
|
70
|
+
const agent = (0, type_utils_js_1.tryOrThrow)(() => (0, camelize_js_1.customCamelize)(agentFileSchema.parse({ ...json, type: json.type ?? "ai" }), {
|
|
71
|
+
shallowKeys: ["input_schema", "output_schema"],
|
|
72
|
+
}), (error) => new Error(`Failed to validate agent definition from ${path}: ${error.message}`));
|
|
61
73
|
return agent;
|
|
62
74
|
}
|
|
@@ -8,8 +8,8 @@ export declare function load(options: LoadOptions): Promise<{
|
|
|
8
8
|
model: ChatModel | undefined;
|
|
9
9
|
agents: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
|
|
10
10
|
tools: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
|
|
11
|
-
description?: string | null | undefined;
|
|
12
11
|
name?: string | null | undefined;
|
|
12
|
+
description?: string | null | undefined;
|
|
13
13
|
chat_model?: {
|
|
14
14
|
name?: string | null | undefined;
|
|
15
15
|
temperature?: number | null | undefined;
|
|
@@ -63,9 +63,9 @@ declare const aigneFileSchema: z.ZodObject<{
|
|
|
63
63
|
agents: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
|
|
64
64
|
tools: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
|
|
65
65
|
}, "strip", z.ZodTypeAny, {
|
|
66
|
-
description?: string | null | undefined;
|
|
67
66
|
tools?: string[] | null | undefined;
|
|
68
67
|
name?: string | null | undefined;
|
|
68
|
+
description?: string | null | undefined;
|
|
69
69
|
chat_model?: {
|
|
70
70
|
name?: string | null | undefined;
|
|
71
71
|
temperature?: number | null | undefined;
|
|
@@ -76,9 +76,9 @@ declare const aigneFileSchema: z.ZodObject<{
|
|
|
76
76
|
} | null | undefined;
|
|
77
77
|
agents?: string[] | null | undefined;
|
|
78
78
|
}, {
|
|
79
|
-
description?: string | null | undefined;
|
|
80
79
|
tools?: string[] | null | undefined;
|
|
81
80
|
name?: string | null | undefined;
|
|
81
|
+
description?: string | null | undefined;
|
|
82
82
|
chat_model?: string | {
|
|
83
83
|
name?: string | null | undefined;
|
|
84
84
|
temperature?: number | null | undefined;
|
|
@@ -90,9 +90,9 @@ declare const aigneFileSchema: z.ZodObject<{
|
|
|
90
90
|
agents?: string[] | null | undefined;
|
|
91
91
|
}>;
|
|
92
92
|
export declare function loadAIGNEFile(path: string): Promise<{
|
|
93
|
-
description?: string | null | undefined;
|
|
94
93
|
tools?: string[] | null | undefined;
|
|
95
94
|
name?: string | null | undefined;
|
|
95
|
+
description?: string | null | undefined;
|
|
96
96
|
chat_model?: {
|
|
97
97
|
name?: string | null | undefined;
|
|
98
98
|
temperature?: number | null | undefined;
|
package/lib/cjs/loader/index.js
CHANGED
|
@@ -39,26 +39,15 @@ async function load(options) {
|
|
|
39
39
|
async function loadAgent(path) {
|
|
40
40
|
if ((0, node_path_1.extname)(path) === ".js") {
|
|
41
41
|
const agent = await (0, agent_js_js_1.loadAgentFromJsFile)(path);
|
|
42
|
-
return agent_js_1.FunctionAgent.from(
|
|
43
|
-
name: agent.name,
|
|
44
|
-
description: agent.description,
|
|
45
|
-
inputSchema: agent.input_schema,
|
|
46
|
-
outputSchema: agent.output_schema,
|
|
47
|
-
fn: agent.fn,
|
|
48
|
-
});
|
|
42
|
+
return agent_js_1.FunctionAgent.from(agent);
|
|
49
43
|
}
|
|
50
44
|
if ((0, node_path_1.extname)(path) === ".yaml" || (0, node_path_1.extname)(path) === ".yml") {
|
|
51
45
|
const agent = await (0, agent_yaml_js_1.loadAgentFromYamlFile)(path);
|
|
52
46
|
if (agent.type === "ai") {
|
|
53
47
|
return ai_agent_js_1.AIAgent.from({
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
inputSchema: agent.input_schema,
|
|
58
|
-
outputSchema: agent.output_schema,
|
|
59
|
-
outputKey: agent.output_key,
|
|
60
|
-
tools: await Promise.all((agent.tools ?? []).map((filename) => loadAgent((0, node_path_1.join)((0, node_path_1.dirname)(path), filename)))),
|
|
61
|
-
toolChoice: agent.tool_choice,
|
|
48
|
+
...agent,
|
|
49
|
+
tools: agent.tools &&
|
|
50
|
+
(await Promise.all(agent.tools.map((filename) => loadAgent((0, node_path_1.join)((0, node_path_1.dirname)(path), filename))))),
|
|
62
51
|
});
|
|
63
52
|
}
|
|
64
53
|
if (agent.type === "mcp") {
|
|
@@ -2,6 +2,10 @@ import { Agent, type Message } from "../agents/agent.js";
|
|
|
2
2
|
import type { Context } from "../execution-engine/context.js";
|
|
3
3
|
export declare abstract class ChatModel extends Agent<ChatModelInput, ChatModelOutput> {
|
|
4
4
|
constructor();
|
|
5
|
+
protected supportsParallelToolCalls: boolean;
|
|
6
|
+
getModelCapabilities(): {
|
|
7
|
+
supportsParallelToolCalls: boolean;
|
|
8
|
+
};
|
|
5
9
|
protected preprocess(input: ChatModelInput, context: Context): void;
|
|
6
10
|
protected postprocess(input: ChatModelInput, output: ChatModelOutput, context: Context): void;
|
|
7
11
|
}
|
|
@@ -10,6 +10,12 @@ class ChatModel extends agent_js_1.Agent {
|
|
|
10
10
|
outputSchema: chatModelOutputSchema,
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
|
+
supportsParallelToolCalls = true;
|
|
14
|
+
getModelCapabilities() {
|
|
15
|
+
return {
|
|
16
|
+
supportsParallelToolCalls: this.supportsParallelToolCalls,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
13
19
|
preprocess(input, context) {
|
|
14
20
|
super.preprocess(input, context);
|
|
15
21
|
const { limits, usage } = context;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import type { AgentCallOptions, AgentResponse } from "../agents/agent.js";
|
|
4
|
+
import type { Context } from "../execution-engine/context.js";
|
|
3
5
|
import { ChatModel, type ChatModelInput, type ChatModelOptions, type ChatModelOutput } from "./chat-model.js";
|
|
4
6
|
export interface ClaudeChatModelOptions {
|
|
5
7
|
apiKey?: string;
|
|
@@ -60,7 +62,7 @@ export declare class ClaudeChatModel extends ChatModel {
|
|
|
60
62
|
protected _client?: Anthropic;
|
|
61
63
|
get client(): Anthropic;
|
|
62
64
|
get modelOptions(): ChatModelOptions | undefined;
|
|
63
|
-
process(input: ChatModelInput): Promise<ChatModelOutput
|
|
65
|
+
process(input: ChatModelInput, _context: Context, options?: AgentCallOptions): Promise<AgentResponse<ChatModelOutput>>;
|
|
64
66
|
private extractResultFromClaudeStream;
|
|
65
67
|
private requestStructuredOutput;
|
|
66
68
|
}
|
|
@@ -7,8 +7,8 @@ exports.ClaudeChatModel = exports.claudeChatModelOptionsSchema = void 0;
|
|
|
7
7
|
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
8
8
|
const zod_1 = require("zod");
|
|
9
9
|
const json_schema_js_1 = require("../utils/json-schema.js");
|
|
10
|
-
const logger_js_1 = require("../utils/logger.js");
|
|
11
10
|
const model_utils_js_1 = require("../utils/model-utils.js");
|
|
11
|
+
const stream_utils_js_1 = require("../utils/stream-utils.js");
|
|
12
12
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
13
13
|
const chat_model_js_1 = require("./chat-model.js");
|
|
14
14
|
const CHAT_MODEL_CLAUDE_DEFAULT_MODEL = "claude-3-7-sonnet-latest";
|
|
@@ -45,7 +45,7 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
|
|
|
45
45
|
get modelOptions() {
|
|
46
46
|
return this.options?.modelOptions;
|
|
47
47
|
}
|
|
48
|
-
async process(input) {
|
|
48
|
+
async process(input, _context, options) {
|
|
49
49
|
const model = this.options?.model || CHAT_MODEL_CLAUDE_DEFAULT_MODEL;
|
|
50
50
|
const disableParallelToolUse = input.modelOptions?.parallelToolCalls === false ||
|
|
51
51
|
this.modelOptions?.parallelToolCalls === false;
|
|
@@ -62,6 +62,9 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
|
|
|
62
62
|
...body,
|
|
63
63
|
stream: true,
|
|
64
64
|
});
|
|
65
|
+
if (options?.streaming && input.responseFormat?.type !== "json_schema") {
|
|
66
|
+
return this.extractResultFromClaudeStream(stream, true);
|
|
67
|
+
}
|
|
65
68
|
const result = await this.extractResultFromClaudeStream(stream);
|
|
66
69
|
// Claude doesn't support json_schema response and tool calls in the same request,
|
|
67
70
|
// so we need to make a separate request for json_schema response when the tool calls is empty
|
|
@@ -75,67 +78,79 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
|
|
|
75
78
|
}
|
|
76
79
|
return result;
|
|
77
80
|
}
|
|
78
|
-
async extractResultFromClaudeStream(stream) {
|
|
81
|
+
async extractResultFromClaudeStream(stream, streaming) {
|
|
79
82
|
const logs = [];
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
83
|
+
const result = new ReadableStream({
|
|
84
|
+
async start(controller) {
|
|
85
|
+
try {
|
|
86
|
+
const toolCalls = [];
|
|
87
|
+
let usage;
|
|
88
|
+
let model;
|
|
89
|
+
for await (const chunk of stream) {
|
|
90
|
+
if (chunk.type === "message_start") {
|
|
91
|
+
if (!model) {
|
|
92
|
+
model = chunk.message.model;
|
|
93
|
+
controller.enqueue({ delta: { json: { model } } });
|
|
94
|
+
}
|
|
95
|
+
const { input_tokens, output_tokens } = chunk.message.usage;
|
|
96
|
+
usage = {
|
|
97
|
+
inputTokens: input_tokens,
|
|
98
|
+
outputTokens: output_tokens,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (chunk.type === "message_delta" && usage) {
|
|
102
|
+
usage.outputTokens = chunk.usage.output_tokens;
|
|
103
|
+
}
|
|
104
|
+
logs.push(JSON.stringify(chunk));
|
|
105
|
+
// handle streaming text
|
|
106
|
+
if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
|
|
107
|
+
controller.enqueue({ delta: { text: { text: chunk.delta.text } } });
|
|
108
|
+
}
|
|
109
|
+
if (chunk.type === "content_block_start" && chunk.content_block.type === "tool_use") {
|
|
110
|
+
toolCalls[chunk.index] = {
|
|
111
|
+
type: "function",
|
|
112
|
+
id: chunk.content_block.id,
|
|
113
|
+
function: {
|
|
114
|
+
name: chunk.content_block.name,
|
|
115
|
+
arguments: {},
|
|
116
|
+
},
|
|
117
|
+
args: "",
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (chunk.type === "content_block_delta" && chunk.delta.type === "input_json_delta") {
|
|
121
|
+
const call = toolCalls[chunk.index];
|
|
122
|
+
if (!call)
|
|
123
|
+
throw new Error("Tool call not found");
|
|
124
|
+
call.args += chunk.delta.partial_json;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
controller.enqueue({ delta: { json: { usage } } });
|
|
128
|
+
if (toolCalls.length) {
|
|
129
|
+
controller.enqueue({
|
|
130
|
+
delta: {
|
|
131
|
+
json: {
|
|
132
|
+
toolCalls: toolCalls
|
|
133
|
+
.map(({ args, ...c }) => ({
|
|
134
|
+
...c,
|
|
135
|
+
function: {
|
|
136
|
+
...c.function,
|
|
137
|
+
// NOTE: claude may return a blank string for empty object (the tool's input schema is a empty object)
|
|
138
|
+
arguments: args.trim() ? (0, json_schema_js_1.parseJSON)(args) : {},
|
|
139
|
+
},
|
|
140
|
+
}))
|
|
141
|
+
.filter(type_utils_js_1.isNonNullable),
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
controller.close();
|
|
101
147
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
type: "function",
|
|
105
|
-
id: chunk.content_block.id,
|
|
106
|
-
function: {
|
|
107
|
-
name: chunk.content_block.name,
|
|
108
|
-
arguments: {},
|
|
109
|
-
},
|
|
110
|
-
args: "",
|
|
111
|
-
};
|
|
148
|
+
catch (error) {
|
|
149
|
+
controller.error(error);
|
|
112
150
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
throw new Error("Tool call not found");
|
|
117
|
-
call.args += chunk.delta.partial_json;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
const result = { usage, model, text };
|
|
121
|
-
if (toolCalls.length) {
|
|
122
|
-
result.toolCalls = toolCalls
|
|
123
|
-
.map(({ args, ...c }) => ({
|
|
124
|
-
...c,
|
|
125
|
-
function: {
|
|
126
|
-
...c.function,
|
|
127
|
-
// NOTE: claude may return a blank string for empty object (the tool's input schema is a empty object)
|
|
128
|
-
arguments: args.trim() ? (0, json_schema_js_1.parseJSON)(args) : {},
|
|
129
|
-
},
|
|
130
|
-
}))
|
|
131
|
-
.filter(type_utils_js_1.isNonNullable);
|
|
132
|
-
}
|
|
133
|
-
return result;
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
logger_js_1.logger.core("Failed to process Claude stream", { error, logs });
|
|
137
|
-
throw error;
|
|
138
|
-
}
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
return streaming ? result : await (0, stream_utils_js_1.agentResponseStreamToObject)(result);
|
|
139
154
|
}
|
|
140
155
|
async requestStructuredOutput(body, responseFormat) {
|
|
141
156
|
if (responseFormat?.type !== "json_schema") {
|