@aigne/core 1.9.0 → 1.10.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 +12 -0
- package/lib/cjs/agents/agent.d.ts +29 -3
- package/lib/cjs/agents/agent.js +47 -22
- package/lib/cjs/agents/ai-agent.d.ts +3 -2
- package/lib/cjs/agents/ai-agent.js +22 -9
- 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/models/chat-model.d.ts +4 -0
- package/lib/cjs/models/chat-model.js +6 -0
- 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 +112 -46
- package/lib/cjs/utils/stream-utils.d.ts +15 -0
- package/lib/cjs/utils/stream-utils.js +159 -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 +29 -3
- package/lib/dts/agents/ai-agent.d.ts +3 -2
- package/lib/dts/agents/user-agent.d.ts +3 -3
- package/lib/dts/execution-engine/context.d.ts +18 -7
- package/lib/dts/models/chat-model.d.ts +4 -0
- 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/stream-utils.d.ts +15 -0
- package/lib/dts/utils/type-utils.d.ts +1 -0
- package/lib/esm/agents/agent.d.ts +29 -3
- package/lib/esm/agents/agent.js +47 -22
- package/lib/esm/agents/ai-agent.d.ts +3 -2
- package/lib/esm/agents/ai-agent.js +23 -10
- 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/models/chat-model.d.ts +4 -0
- package/lib/esm/models/chat-model.js +6 -0
- 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 +112 -45
- package/lib/esm/utils/stream-utils.d.ts +15 -0
- package/lib/esm/utils/stream-utils.js +144 -0
- package/lib/esm/utils/type-utils.d.ts +1 -0
- package/lib/esm/utils/type-utils.js +6 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -22,6 +22,18 @@
|
|
|
22
22
|
* rename @aigne/core-next to @aigne/core ([3a81009](https://github.com/AIGNE-io/aigne-framework/commit/3a8100962c81813217b687ae28e8de604419c622))
|
|
23
23
|
* use text resource from MCP correctly ([8b9eba8](https://github.com/AIGNE-io/aigne-framework/commit/8b9eba83352ec096a2a5d4f410d4c4bde7420bce))
|
|
24
24
|
|
|
25
|
+
## [1.10.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.9.0...core-v1.10.0) (2025-04-22)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
* **stream:** add streaming output support for agent ([#73](https://github.com/AIGNE-io/aigne-framework/issues/73)) ([5f3ea4b](https://github.com/AIGNE-io/aigne-framework/commit/5f3ea4bccda7c8c457d6e9518b3d6a8b254ec041))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Bug Fixes
|
|
34
|
+
|
|
35
|
+
* **core:** support dynamic model capability detection ([#72](https://github.com/AIGNE-io/aigne-framework/issues/72)) ([9d56d98](https://github.com/AIGNE-io/aigne-framework/commit/9d56d9885778962e5bef806445ad8c4d199f2c65))
|
|
36
|
+
|
|
25
37
|
## [1.9.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.8.0...core-v1.9.0) (2025-04-20)
|
|
26
38
|
|
|
27
39
|
|
|
@@ -19,6 +19,9 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
|
|
|
19
19
|
disableEvents?: boolean;
|
|
20
20
|
memory?: AgentMemory | AgentMemoryOptions | true;
|
|
21
21
|
}
|
|
22
|
+
export interface AgentCallOptions {
|
|
23
|
+
streaming?: boolean;
|
|
24
|
+
}
|
|
22
25
|
export declare abstract class Agent<I extends Message = Message, O extends Message = Message> {
|
|
23
26
|
constructor({ inputSchema, outputSchema, ...options }: AgentOptions<I, O>);
|
|
24
27
|
readonly memory?: AgentMemory;
|
|
@@ -50,14 +53,37 @@ export declare abstract class Agent<I extends Message = Message, O extends Messa
|
|
|
50
53
|
get isCallable(): boolean;
|
|
51
54
|
private checkContextStatus;
|
|
52
55
|
private newDefaultContext;
|
|
53
|
-
call(input: I | string, context
|
|
56
|
+
call(input: I | string, context: Context | undefined, options: AgentCallOptions & {
|
|
57
|
+
streaming: true;
|
|
58
|
+
}): Promise<AgentResponseStream<O>>;
|
|
59
|
+
call(input: I | string, context?: Context, options?: AgentCallOptions & {
|
|
60
|
+
streaming?: false;
|
|
61
|
+
}): Promise<O>;
|
|
62
|
+
call(input: I | string, context?: Context, options?: AgentCallOptions): Promise<AgentResponse<O>>;
|
|
63
|
+
private processAgentOutput;
|
|
64
|
+
private processAgentError;
|
|
54
65
|
protected checkUsageAgentCalls(context: Context): void;
|
|
55
66
|
protected preprocess(_: I, context: Context): void;
|
|
56
67
|
protected postprocess(input: I, output: O, context: Context): void;
|
|
57
|
-
abstract process(input: I, context: Context):
|
|
68
|
+
abstract process(input: I, context: Context, options?: AgentCallOptions): AgentProcessResult<O | TransferAgentOutput>;
|
|
58
69
|
shutdown(): Promise<void>;
|
|
59
70
|
[inspect.custom](): string;
|
|
60
71
|
}
|
|
72
|
+
export type AgentResponse<T> = T | AgentResponseStream<T>;
|
|
73
|
+
export type AgentResponseStream<T> = ReadableStream<AgentResponseChunk<T>>;
|
|
74
|
+
export type AgentResponseChunk<T> = AgentResponseDelta<T>;
|
|
75
|
+
export interface AgentResponseDelta<T> {
|
|
76
|
+
delta: {
|
|
77
|
+
text?: Partial<{
|
|
78
|
+
[key in keyof T as Extract<T[key], string> extends string ? key : never]: string;
|
|
79
|
+
}> | {
|
|
80
|
+
[key: string]: string;
|
|
81
|
+
};
|
|
82
|
+
json?: Partial<T>;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export type AgentProcessAsyncGenerator<O extends Message> = AsyncGenerator<AgentResponseChunk<O>, Partial<O> | undefined | void>;
|
|
86
|
+
export type AgentProcessResult<O extends Message> = Promise<AgentResponse<O>> | AgentProcessAsyncGenerator<O>;
|
|
61
87
|
export type AgentInputOutputSchema<I extends Message = Message> = ZodType<I> | ((agent: Agent) => ZodType<I>);
|
|
62
88
|
export interface FunctionAgentOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
|
|
63
89
|
fn?: FunctionAgentFn<I, O>;
|
|
@@ -66,6 +92,6 @@ export declare class FunctionAgent<I extends Message = Message, O extends Messag
|
|
|
66
92
|
static from<I extends Message, O extends Message>(options: FunctionAgentOptions<I, O> | FunctionAgentFn<I, O>): FunctionAgent<I, O>;
|
|
67
93
|
constructor(options: FunctionAgentOptions<I, O>);
|
|
68
94
|
fn: FunctionAgentFn<I, O>;
|
|
69
|
-
process(input: I, context: Context): Promise<
|
|
95
|
+
process(input: I, context: Context, options?: AgentCallOptions): Promise<AgentResponse<O | TransferAgentOutput>>;
|
|
70
96
|
}
|
|
71
97
|
export type FunctionAgentFn<I extends Message = Message, O extends Message = Message> = (input: I, context: Context) => O | Promise<O> | Agent | Promise<Agent>;
|
package/lib/cjs/agents/agent.js
CHANGED
|
@@ -38,6 +38,7 @@ const node_util_1 = require("node:util");
|
|
|
38
38
|
const zod_1 = require("zod");
|
|
39
39
|
const prompt_builder_js_1 = require("../prompt/prompt-builder.js");
|
|
40
40
|
const logger_js_1 = require("../utils/logger.js");
|
|
41
|
+
const stream_utils_js_1 = require("../utils/stream-utils.js");
|
|
41
42
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
42
43
|
const memory_js_1 = require("./memory.js");
|
|
43
44
|
const types_js_1 = require("./types.js");
|
|
@@ -130,7 +131,7 @@ class Agent {
|
|
|
130
131
|
async newDefaultContext() {
|
|
131
132
|
return Promise.resolve().then(() => __importStar(require("../execution-engine/context.js"))).then((m) => new m.ExecutionContext());
|
|
132
133
|
}
|
|
133
|
-
async call(input, context) {
|
|
134
|
+
async call(input, context, options) {
|
|
134
135
|
const ctx = context ?? (await this.newDefaultContext());
|
|
135
136
|
const message = typeof input === "string" ? (0, prompt_builder_js_1.createMessage)(input) : input;
|
|
136
137
|
logger_js_1.logger.core("Call agent %s started with input: %O", this.name, input);
|
|
@@ -140,27 +141,51 @@ class Agent {
|
|
|
140
141
|
const parsedInput = (0, type_utils_js_1.checkArguments)(`Agent ${this.name} input`, this.inputSchema, message);
|
|
141
142
|
this.preprocess(parsedInput, ctx);
|
|
142
143
|
this.checkContextStatus(ctx);
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
144
|
+
const response = await this.process(parsedInput, ctx, options);
|
|
145
|
+
if (options?.streaming) {
|
|
146
|
+
const stream = response instanceof ReadableStream
|
|
147
|
+
? response
|
|
148
|
+
: (0, stream_utils_js_1.isAsyncGenerator)(response)
|
|
149
|
+
? (0, stream_utils_js_1.asyncGeneratorToReadableStream)(response)
|
|
150
|
+
: (0, stream_utils_js_1.objectToAgentResponseStream)(response);
|
|
151
|
+
return (0, stream_utils_js_1.onAgentResponseStreamEnd)(stream, async (result) => {
|
|
152
|
+
return await this.processAgentOutput(parsedInput, result, ctx);
|
|
153
|
+
}, {
|
|
154
|
+
errorCallback: (error) => {
|
|
155
|
+
try {
|
|
156
|
+
this.processAgentError(error, ctx);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
return error;
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return await this.processAgentOutput(parsedInput, response instanceof ReadableStream
|
|
165
|
+
? await (0, stream_utils_js_1.agentResponseStreamToObject)(response)
|
|
166
|
+
: (0, stream_utils_js_1.isAsyncGenerator)(response)
|
|
167
|
+
? await (0, stream_utils_js_1.agentResponseStreamToObject)(response)
|
|
168
|
+
: response, ctx);
|
|
156
169
|
}
|
|
157
170
|
catch (error) {
|
|
158
|
-
|
|
159
|
-
if (!this.disableEvents)
|
|
160
|
-
ctx.emit("agentFailed", { agent: this, error });
|
|
161
|
-
throw error;
|
|
171
|
+
this.processAgentError(error, ctx);
|
|
162
172
|
}
|
|
163
173
|
}
|
|
174
|
+
async processAgentOutput(input, output, context) {
|
|
175
|
+
const parsedOutput = (0, type_utils_js_1.checkArguments)(`Agent ${this.name} output`, this.outputSchema, output);
|
|
176
|
+
const finalOutput = this.includeInputInOutput ? { ...input, ...parsedOutput } : parsedOutput;
|
|
177
|
+
this.postprocess(input, finalOutput, context);
|
|
178
|
+
logger_js_1.logger.core("Call agent %s succeed with output: %O", this.name, finalOutput);
|
|
179
|
+
if (!this.disableEvents)
|
|
180
|
+
context.emit("agentSucceed", { agent: this, output: finalOutput });
|
|
181
|
+
return finalOutput;
|
|
182
|
+
}
|
|
183
|
+
processAgentError(error, context) {
|
|
184
|
+
logger_js_1.logger.core("Call agent %s failed with error: %O", this.name, error);
|
|
185
|
+
if (!this.disableEvents)
|
|
186
|
+
context.emit("agentFailed", { agent: this, error });
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
164
189
|
checkUsageAgentCalls(context) {
|
|
165
190
|
const { limits, usage } = context;
|
|
166
191
|
if (limits?.maxAgentCalls && usage.agentCalls >= limits.maxAgentCalls) {
|
|
@@ -203,12 +228,12 @@ class FunctionAgent extends Agent {
|
|
|
203
228
|
this.fn = options.fn ?? (() => ({}));
|
|
204
229
|
}
|
|
205
230
|
fn;
|
|
206
|
-
async process(input, context) {
|
|
207
|
-
|
|
231
|
+
async process(input, context, options) {
|
|
232
|
+
let result = await this.fn(input, context);
|
|
208
233
|
if (result instanceof Agent) {
|
|
209
|
-
|
|
234
|
+
result = (0, types_js_1.transferToAgentOutput)(result);
|
|
210
235
|
}
|
|
211
|
-
return result;
|
|
236
|
+
return options?.streaming ? (0, stream_utils_js_1.objectToAgentResponseStream)(result) : result;
|
|
212
237
|
}
|
|
213
238
|
}
|
|
214
239
|
exports.FunctionAgent = FunctionAgent;
|
|
@@ -2,7 +2,8 @@ import { z } from "zod";
|
|
|
2
2
|
import type { Context } from "../execution-engine/context.js";
|
|
3
3
|
import { ChatModel } from "../models/chat-model.js";
|
|
4
4
|
import { PromptBuilder } from "../prompt/prompt-builder.js";
|
|
5
|
-
import { Agent, type AgentOptions, type Message } from "./agent.js";
|
|
5
|
+
import { Agent, type AgentOptions, type AgentProcessAsyncGenerator, type Message } from "./agent.js";
|
|
6
|
+
import { type TransferAgentOutput } from "./types.js";
|
|
6
7
|
export interface AIAgentOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
|
|
7
8
|
model?: ChatModel;
|
|
8
9
|
instructions?: string | PromptBuilder;
|
|
@@ -64,5 +65,5 @@ export declare class AIAgent<I extends Message = Message, O extends Message = Me
|
|
|
64
65
|
instructions: PromptBuilder;
|
|
65
66
|
outputKey?: string;
|
|
66
67
|
toolChoice?: AIAgentToolChoice;
|
|
67
|
-
process(input: I, context: Context):
|
|
68
|
+
process(input: I, context: Context): AgentProcessAsyncGenerator<O | TransferAgentOutput>;
|
|
68
69
|
}
|
|
@@ -5,6 +5,8 @@ const zod_1 = require("zod");
|
|
|
5
5
|
const chat_model_js_1 = require("../models/chat-model.js");
|
|
6
6
|
const prompt_builder_js_1 = require("../prompt/prompt-builder.js");
|
|
7
7
|
const template_js_1 = require("../prompt/template.js");
|
|
8
|
+
const stream_utils_js_1 = require("../utils/stream-utils.js");
|
|
9
|
+
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
8
10
|
const agent_js_1 = require("./agent.js");
|
|
9
11
|
const types_js_1 = require("./types.js");
|
|
10
12
|
exports.aiAgentToolChoiceSchema = zod_1.z.union([
|
|
@@ -49,7 +51,7 @@ class AIAgent extends agent_js_1.Agent {
|
|
|
49
51
|
instructions;
|
|
50
52
|
outputKey;
|
|
51
53
|
toolChoice;
|
|
52
|
-
async process(input, context) {
|
|
54
|
+
async *process(input, context) {
|
|
53
55
|
const model = context.model ?? this.model;
|
|
54
56
|
if (!model)
|
|
55
57
|
throw new Error("model is required to run AIAgent");
|
|
@@ -61,11 +63,19 @@ class AIAgent extends agent_js_1.Agent {
|
|
|
61
63
|
});
|
|
62
64
|
const toolsMap = new Map(toolAgents?.map((i) => [i.name, i]));
|
|
63
65
|
const toolCallMessages = [];
|
|
66
|
+
const outputKey = this.outputKey || prompt_builder_js_1.MESSAGE_KEY;
|
|
64
67
|
for (;;) {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
const modelOutput = {};
|
|
69
|
+
const stream = await context.call(model, { ...modelInput, messages: messages.concat(toolCallMessages) }, { streaming: true });
|
|
70
|
+
for await (const value of (0, stream_utils_js_1.readableStreamToAsyncIterator)(stream)) {
|
|
71
|
+
if (value.delta.text?.text) {
|
|
72
|
+
yield { delta: { text: { [outputKey]: value.delta.text.text } } };
|
|
73
|
+
}
|
|
74
|
+
if (value.delta.json) {
|
|
75
|
+
Object.assign(modelOutput, value.delta.json);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const { toolCalls, json, text } = modelOutput;
|
|
69
79
|
if (toolCalls?.length) {
|
|
70
80
|
const executedToolCalls = [];
|
|
71
81
|
// Execute tools
|
|
@@ -87,7 +97,8 @@ class AIAgent extends agent_js_1.Agent {
|
|
|
87
97
|
// Return the output of the first tool if the toolChoice is "router"
|
|
88
98
|
if (this.toolChoice === "router") {
|
|
89
99
|
const output = executedToolCalls[0]?.output;
|
|
90
|
-
|
|
100
|
+
const { supportsParallelToolCalls } = model.getModelCapabilities();
|
|
101
|
+
if (!output || (supportsParallelToolCalls && executedToolCalls.length !== 1)) {
|
|
91
102
|
throw new Error("Router toolChoice requires exactly one tool to be executed");
|
|
92
103
|
}
|
|
93
104
|
return output;
|
|
@@ -99,11 +110,13 @@ class AIAgent extends agent_js_1.Agent {
|
|
|
99
110
|
if (modelInput.responseFormat?.type === "json_schema") {
|
|
100
111
|
Object.assign(result, json);
|
|
101
112
|
}
|
|
102
|
-
else {
|
|
103
|
-
const outputKey = this.outputKey || prompt_builder_js_1.MESSAGE_KEY;
|
|
113
|
+
else if (text) {
|
|
104
114
|
Object.assign(result, { [outputKey]: text });
|
|
105
115
|
}
|
|
106
|
-
|
|
116
|
+
if (!(0, type_utils_js_1.isEmpty)(result)) {
|
|
117
|
+
yield { delta: { json: result } };
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
107
120
|
}
|
|
108
121
|
}
|
|
109
122
|
}
|
|
@@ -2,7 +2,7 @@ import { ReadableStream } from "node:stream/web";
|
|
|
2
2
|
import { type Context, type Runnable } from "../execution-engine/context.js";
|
|
3
3
|
import type { MessagePayload } from "../execution-engine/message-queue.js";
|
|
4
4
|
import { type PromiseOrValue } from "../utils/type-utils.js";
|
|
5
|
-
import { Agent, type AgentOptions, type Message } from "./agent.js";
|
|
5
|
+
import { Agent, type AgentOptions, type AgentProcessAsyncGenerator, type Message } from "./agent.js";
|
|
6
6
|
export interface UserAgentOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
|
|
7
7
|
context: Context;
|
|
8
8
|
process?: (input: I, context: Context) => PromiseOrValue<O>;
|
|
@@ -14,8 +14,8 @@ export declare class UserAgent<I extends Message = Message, O extends Message =
|
|
|
14
14
|
context: Context;
|
|
15
15
|
private _process?;
|
|
16
16
|
private activeAgent?;
|
|
17
|
-
call
|
|
18
|
-
process(input: I, context: Context):
|
|
17
|
+
call: Agent<I, O>["call"];
|
|
18
|
+
process(input: I, context: Context): AgentProcessAsyncGenerator<O>;
|
|
19
19
|
publish: Context["publish"];
|
|
20
20
|
subscribe: Context["subscribe"];
|
|
21
21
|
unsubscribe: Context["unsubscribe"];
|
|
@@ -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)]),
|
|
@@ -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;
|
|
@@ -2,4 +2,5 @@ import { OpenAIChatModel, type OpenAIChatModelOptions } from "./openai-chat-mode
|
|
|
2
2
|
export declare class OpenRouterChatModel extends OpenAIChatModel {
|
|
3
3
|
constructor(options?: OpenAIChatModelOptions);
|
|
4
4
|
protected apiKeyEnvName: string;
|
|
5
|
+
protected supportsParallelToolCalls: boolean;
|
|
5
6
|
}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
2
|
import type { ChatCompletionMessageParam, ChatCompletionTool } from "openai/resources";
|
|
3
|
-
import type { Stream } from "openai/streaming.js";
|
|
4
3
|
import { z } from "zod";
|
|
4
|
+
import type { AgentCallOptions, AgentResponse } from "../agents/agent.js";
|
|
5
|
+
import type { Context } from "../execution-engine/context.js";
|
|
5
6
|
import { ChatModel, type ChatModelInput, type ChatModelInputMessage, type ChatModelInputTool, type ChatModelOptions, type ChatModelOutput, type Role } from "./chat-model.js";
|
|
7
|
+
export interface OpenAIChatModelCapabilities {
|
|
8
|
+
supportsNativeStructuredOutputs: boolean;
|
|
9
|
+
supportsEndWithSystemMessage: boolean;
|
|
10
|
+
supportsToolsUseWithJsonSchema: boolean;
|
|
11
|
+
supportsParallelToolCalls: boolean;
|
|
12
|
+
supportsToolsEmptyParameters: boolean;
|
|
13
|
+
supportsTemperature: boolean;
|
|
14
|
+
}
|
|
6
15
|
export interface OpenAIChatModelOptions {
|
|
7
16
|
apiKey?: string;
|
|
8
17
|
baseURL?: string;
|
|
@@ -71,9 +80,10 @@ export declare class OpenAIChatModel extends ChatModel {
|
|
|
71
80
|
protected supportsToolsUseWithJsonSchema: boolean;
|
|
72
81
|
protected supportsParallelToolCalls: boolean;
|
|
73
82
|
protected supportsToolsEmptyParameters: boolean;
|
|
83
|
+
protected supportsTemperature: boolean;
|
|
74
84
|
get client(): OpenAI;
|
|
75
85
|
get modelOptions(): ChatModelOptions | undefined;
|
|
76
|
-
process(input: ChatModelInput): Promise<ChatModelOutput
|
|
86
|
+
process(input: ChatModelInput, _context: Context, options?: AgentCallOptions): Promise<AgentResponse<ChatModelOutput>>;
|
|
77
87
|
private getParallelToolCalls;
|
|
78
88
|
private getRunMessages;
|
|
79
89
|
private getRunResponseFormat;
|
|
@@ -87,4 +97,3 @@ export declare function toolsFromInputTools(tools?: ChatModelInputTool[], option
|
|
|
87
97
|
addTypeToEmptyParameters?: boolean;
|
|
88
98
|
}): ChatCompletionTool[] | undefined;
|
|
89
99
|
export declare function jsonSchemaToOpenAIJsonSchema(schema: Record<string, unknown>): Record<string, unknown>;
|
|
90
|
-
export declare function extractResultFromStream(stream: Stream<OpenAI.Chat.Completions.ChatCompletionChunk>, jsonMode?: boolean): Promise<ChatModelOutput>;
|