@aigne/core 1.5.1-1 → 1.6.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 +14 -0
- package/lib/cjs/agents/mcp-agent.d.ts +34 -7
- package/lib/cjs/agents/mcp-agent.js +55 -8
- package/lib/cjs/agents/user-agent.d.ts +1 -0
- package/lib/cjs/agents/user-agent.js +2 -1
- package/lib/cjs/execution-engine/execution-engine.d.ts +13 -2
- package/lib/cjs/execution-engine/execution-engine.js +20 -3
- package/lib/cjs/loader/agent-js.d.ts +17 -0
- package/lib/cjs/loader/agent-js.js +67 -0
- package/lib/cjs/loader/agent-yaml.d.ts +24 -0
- package/lib/cjs/loader/agent-yaml.js +58 -0
- package/lib/cjs/loader/index.d.ts +35 -0
- package/lib/cjs/loader/index.js +128 -0
- package/lib/cjs/loader/schema.d.ts +17 -0
- package/lib/cjs/loader/schema.js +10 -0
- package/lib/cjs/models/claude-chat-model.d.ts +1 -1
- package/lib/cjs/models/claude-chat-model.js +3 -2
- package/lib/cjs/models/openai-chat-model.d.ts +1 -1
- package/lib/cjs/models/openai-chat-model.js +4 -3
- package/lib/cjs/models/xai-chat-model.d.ts +2 -0
- package/lib/cjs/models/xai-chat-model.js +14 -0
- package/lib/cjs/utils/json-schema.js +1 -1
- package/lib/cjs/utils/logger.d.ts +3 -1
- package/lib/cjs/utils/logger.js +13 -10
- package/lib/cjs/utils/mcp-utils.d.ts +4 -5
- package/lib/cjs/utils/mcp-utils.js +6 -6
- package/lib/cjs/utils/run-chat-loop.js +3 -1
- package/lib/cjs/utils/type-utils.d.ts +2 -0
- package/lib/cjs/utils/type-utils.js +38 -1
- package/lib/dts/agents/mcp-agent.d.ts +34 -7
- package/lib/dts/agents/user-agent.d.ts +1 -0
- package/lib/dts/execution-engine/execution-engine.d.ts +13 -2
- package/lib/dts/loader/agent-js.d.ts +17 -0
- package/lib/dts/loader/agent-yaml.d.ts +24 -0
- package/lib/dts/loader/index.d.ts +35 -0
- package/lib/dts/loader/schema.d.ts +17 -0
- package/lib/dts/models/claude-chat-model.d.ts +1 -1
- package/lib/dts/models/openai-chat-model.d.ts +1 -1
- package/lib/dts/models/xai-chat-model.d.ts +2 -0
- package/lib/dts/utils/logger.d.ts +3 -1
- package/lib/dts/utils/mcp-utils.d.ts +4 -5
- package/lib/dts/utils/type-utils.d.ts +2 -0
- package/lib/esm/agents/mcp-agent.d.ts +34 -7
- package/lib/esm/agents/mcp-agent.js +52 -8
- package/lib/esm/agents/user-agent.d.ts +1 -0
- package/lib/esm/agents/user-agent.js +1 -0
- package/lib/esm/execution-engine/execution-engine.d.ts +13 -2
- package/lib/esm/execution-engine/execution-engine.js +21 -4
- package/lib/esm/loader/agent-js.d.ts +17 -0
- package/lib/esm/loader/agent-js.js +31 -0
- package/lib/esm/loader/agent-yaml.d.ts +24 -0
- package/lib/esm/loader/agent-yaml.js +55 -0
- package/lib/esm/loader/index.d.ts +35 -0
- package/lib/esm/loader/index.js +123 -0
- package/lib/esm/loader/schema.d.ts +17 -0
- package/lib/esm/loader/schema.js +7 -0
- package/lib/esm/models/claude-chat-model.d.ts +1 -1
- package/lib/esm/models/claude-chat-model.js +3 -2
- package/lib/esm/models/openai-chat-model.d.ts +1 -1
- package/lib/esm/models/openai-chat-model.js +4 -3
- package/lib/esm/models/xai-chat-model.d.ts +2 -0
- package/lib/esm/models/xai-chat-model.js +11 -0
- package/lib/esm/utils/json-schema.js +1 -1
- package/lib/esm/utils/logger.d.ts +3 -1
- package/lib/esm/utils/logger.js +13 -10
- package/lib/esm/utils/mcp-utils.d.ts +4 -5
- package/lib/esm/utils/mcp-utils.js +6 -6
- package/lib/esm/utils/run-chat-loop.js +3 -1
- package/lib/esm/utils/type-utils.d.ts +2 -0
- package/lib/esm/utils/type-utils.js +36 -1
- package/package.json +15 -9
package/CHANGELOG.md
CHANGED
|
@@ -22,6 +22,20 @@
|
|
|
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.6.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.5.0...core-v1.6.0) (2025-04-08)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
* add `serve` command for @aigne/cli ([#54](https://github.com/AIGNE-io/aigne-framework/issues/54)) ([1cca843](https://github.com/AIGNE-io/aigne-framework/commit/1cca843f1760abe832b6651108fa858130f47355))
|
|
31
|
+
* add agent library support ([#51](https://github.com/AIGNE-io/aigne-framework/issues/51)) ([1f0d34d](https://github.com/AIGNE-io/aigne-framework/commit/1f0d34ddda3154283a4bc958ddb9b68b4ac106b0))
|
|
32
|
+
* support token/call/time limits for ExecutionEngine ([#44](https://github.com/AIGNE-io/aigne-framework/issues/44)) ([5a2ca0a](https://github.com/AIGNE-io/aigne-framework/commit/5a2ca0a033267dd4765f574b53dca71e932e53d4))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### Bug Fixes
|
|
36
|
+
|
|
37
|
+
* support reconnect to the MCP server automatically ([#50](https://github.com/AIGNE-io/aigne-framework/issues/50)) ([898d83f](https://github.com/AIGNE-io/aigne-framework/commit/898d83f75fc655142b93c70a1afeda376a2e92b4))
|
|
38
|
+
|
|
25
39
|
## [1.5.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.4.0...core-v1.5.0) (2025-03-27)
|
|
26
40
|
|
|
27
41
|
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
1
|
+
import { Client, type ClientOptions } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
2
|
import { type StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { RequestOptions } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
4
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
5
|
+
import type { CallToolResult, GetPromptResult, Implementation, ReadResourceResult, Request } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
import { type ZodType, z } from "zod";
|
|
4
7
|
import type { Context } from "../execution-engine/context.js";
|
|
8
|
+
import { type PromiseOrValue } from "../utils/type-utils.js";
|
|
5
9
|
import { Agent, type AgentOptions, type Message } from "./agent.js";
|
|
6
10
|
export interface MCPAgentOptions extends AgentOptions {
|
|
7
11
|
client: Client;
|
|
@@ -11,6 +15,16 @@ export interface MCPAgentOptions extends AgentOptions {
|
|
|
11
15
|
export type MCPServerOptions = SSEServerParameters | StdioServerParameters;
|
|
12
16
|
export type SSEServerParameters = {
|
|
13
17
|
url: string;
|
|
18
|
+
/**
|
|
19
|
+
* Whether to automatically reconnect to the server if the connection is lost.
|
|
20
|
+
* @default 10 set to 0 to disable automatic reconnection
|
|
21
|
+
*/
|
|
22
|
+
maxReconnects?: number;
|
|
23
|
+
/**
|
|
24
|
+
* A function that determines whether to reconnect to the server based on the error.
|
|
25
|
+
* default to reconnect on all errors.
|
|
26
|
+
*/
|
|
27
|
+
shouldReconnect?: (error: Error) => boolean;
|
|
14
28
|
};
|
|
15
29
|
export declare class MCPAgent extends Agent {
|
|
16
30
|
static from(options: MCPServerOptions): Promise<MCPAgent>;
|
|
@@ -28,12 +42,24 @@ export declare class MCPAgent extends Agent {
|
|
|
28
42
|
process(_input: Message, _context?: Context): Promise<Message>;
|
|
29
43
|
shutdown(): Promise<void>;
|
|
30
44
|
}
|
|
31
|
-
export interface
|
|
32
|
-
|
|
45
|
+
export interface ClientWithReconnectOptions {
|
|
46
|
+
transportCreator?: () => PromiseOrValue<Transport>;
|
|
47
|
+
maxReconnects?: number;
|
|
48
|
+
shouldReconnect?: (error: Error) => boolean;
|
|
49
|
+
}
|
|
50
|
+
declare class ClientWithReconnect extends Client {
|
|
51
|
+
private reconnectOptions?;
|
|
52
|
+
constructor(info: Implementation, options?: ClientOptions, reconnectOptions?: ClientWithReconnectOptions | undefined);
|
|
53
|
+
private shouldReconnect;
|
|
54
|
+
private reconnect;
|
|
55
|
+
request<T extends ZodType<object>>(request: Request, resultSchema: T, options?: RequestOptions): Promise<z.infer<T>>;
|
|
56
|
+
}
|
|
57
|
+
export interface MCPBaseOptions<I extends Message = Message, O extends Message = Message> extends AgentOptions<I, O> {
|
|
58
|
+
client: ClientWithReconnect;
|
|
33
59
|
}
|
|
34
60
|
export declare abstract class MCPBase<I extends Message, O extends Message> extends Agent<I, O> {
|
|
35
|
-
constructor(options:
|
|
36
|
-
protected client:
|
|
61
|
+
constructor(options: MCPBaseOptions<I, O>);
|
|
62
|
+
protected client: ClientWithReconnect;
|
|
37
63
|
protected get mcpServer(): string | undefined;
|
|
38
64
|
}
|
|
39
65
|
export declare class MCPTool extends MCPBase<Message, CallToolResult> {
|
|
@@ -45,7 +71,7 @@ export interface MCPPromptInput extends Message {
|
|
|
45
71
|
export declare class MCPPrompt extends MCPBase<MCPPromptInput, GetPromptResult> {
|
|
46
72
|
process(input: MCPPromptInput): Promise<GetPromptResult>;
|
|
47
73
|
}
|
|
48
|
-
export interface MCPResourceOptions extends
|
|
74
|
+
export interface MCPResourceOptions extends MCPBaseOptions<MCPPromptInput, ReadResourceResult> {
|
|
49
75
|
uri: string;
|
|
50
76
|
}
|
|
51
77
|
export declare class MCPResource extends MCPBase<MCPPromptInput, ReadResourceResult> {
|
|
@@ -53,3 +79,4 @@ export declare class MCPResource extends MCPBase<MCPPromptInput, ReadResourceRes
|
|
|
53
79
|
uri: string;
|
|
54
80
|
process(input: MCPPromptInput): Promise<ReadResourceResult>;
|
|
55
81
|
}
|
|
82
|
+
export {};
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.MCPResource = exports.MCPPrompt = exports.MCPTool = exports.MCPBase = exports.MCPAgent = void 0;
|
|
4
7
|
const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
|
|
5
8
|
const sse_js_1 = require("@modelcontextprotocol/sdk/client/sse.js");
|
|
6
9
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
|
|
7
10
|
const uriTemplate_js_1 = require("@modelcontextprotocol/sdk/shared/uriTemplate.js");
|
|
11
|
+
const p_retry_1 = __importDefault(require("p-retry"));
|
|
8
12
|
const zod_1 = require("zod");
|
|
9
13
|
const logger_js_1 = require("../utils/logger.js");
|
|
10
14
|
const mcp_utils_js_1 = require("../utils/mcp-utils.js");
|
|
@@ -12,6 +16,7 @@ const type_utils_js_1 = require("../utils/type-utils.js");
|
|
|
12
16
|
const agent_js_1 = require("./agent.js");
|
|
13
17
|
const MCP_AGENT_CLIENT_NAME = "MCPAgent";
|
|
14
18
|
const MCP_AGENT_CLIENT_VERSION = "0.0.1";
|
|
19
|
+
const DEFAULT_MAX_RECONNECTS = 10;
|
|
15
20
|
const debug = logger_js_1.logger.base.extend("mcp");
|
|
16
21
|
function isSSEServerParameters(options) {
|
|
17
22
|
return "url" in options && typeof options.url === "string";
|
|
@@ -32,11 +37,11 @@ class MCPAgent extends agent_js_1.Agent {
|
|
|
32
37
|
static from(options) {
|
|
33
38
|
(0, type_utils_js_1.checkArguments)("MCPAgent.from", mcpAgentOptionsSchema, options);
|
|
34
39
|
if (isSSEServerParameters(options)) {
|
|
35
|
-
const transport = new sse_js_1.SSEClientTransport(new URL(options.url));
|
|
40
|
+
const transport = () => new sse_js_1.SSEClientTransport(new URL(options.url));
|
|
36
41
|
return MCPAgent.fromTransport(transport, options);
|
|
37
42
|
}
|
|
38
43
|
if (isStdioServerParameters(options)) {
|
|
39
|
-
const transport = new stdio_js_1.StdioClientTransport({
|
|
44
|
+
const transport = () => new stdio_js_1.StdioClientTransport({
|
|
40
45
|
...options,
|
|
41
46
|
env: {
|
|
42
47
|
...(0, stdio_js_1.getDefaultEnvironment)(),
|
|
@@ -48,23 +53,24 @@ class MCPAgent extends agent_js_1.Agent {
|
|
|
48
53
|
}
|
|
49
54
|
return new MCPAgent(options);
|
|
50
55
|
}
|
|
51
|
-
static async fromTransport(
|
|
52
|
-
const client = new
|
|
56
|
+
static async fromTransport(transportCreator, options) {
|
|
57
|
+
const client = new ClientWithReconnect({
|
|
53
58
|
name: MCP_AGENT_CLIENT_NAME,
|
|
54
59
|
version: MCP_AGENT_CLIENT_VERSION,
|
|
55
|
-
});
|
|
60
|
+
}, undefined, isSSEServerParameters(options) ? { transportCreator, ...options } : undefined);
|
|
61
|
+
const transport = transportCreator();
|
|
56
62
|
await debug.spinner(client.connect(transport), `Connecting to MCP server: ${getMCPServerString(options)}`);
|
|
57
63
|
const mcpServer = getMCPServerName(client);
|
|
58
64
|
const { tools: isToolsAvailable, prompts: isPromptsAvailable, resources: isResourcesAvailable, } = client.getServerCapabilities() ?? {};
|
|
59
65
|
const tools = isToolsAvailable
|
|
60
66
|
? await debug
|
|
61
67
|
.spinner(client.listTools(), `Listing tools from ${mcpServer}`, ({ tools }) => debug("%O", tools))
|
|
62
|
-
.then(({ tools }) => tools.map((tool) => (0, mcp_utils_js_1.toolFromMCPTool)(
|
|
68
|
+
.then(({ tools }) => tools.map((tool) => (0, mcp_utils_js_1.toolFromMCPTool)(tool, { client })))
|
|
63
69
|
: undefined;
|
|
64
70
|
const prompts = isPromptsAvailable
|
|
65
71
|
? await debug
|
|
66
72
|
.spinner(client.listPrompts(), `Listing prompts from ${mcpServer}`, ({ prompts }) => debug("%O", prompts))
|
|
67
|
-
.then(({ prompts }) => prompts.map((prompt) => (0, mcp_utils_js_1.promptFromMCPPrompt)(
|
|
73
|
+
.then(({ prompts }) => prompts.map((prompt) => (0, mcp_utils_js_1.promptFromMCPPrompt)(prompt, { client })))
|
|
68
74
|
: undefined;
|
|
69
75
|
const resources = isResourcesAvailable
|
|
70
76
|
? await debug
|
|
@@ -75,7 +81,7 @@ class MCPAgent extends agent_js_1.Agent {
|
|
|
75
81
|
client.listResources().catch(() => ({ resources: [] })),
|
|
76
82
|
client.listResourceTemplates().catch(() => ({ resourceTemplates: [] })),
|
|
77
83
|
]), `Listing resources from ${mcpServer}`, ([{ resources }, { resourceTemplates }]) => debug("%O\n%O", resources, resourceTemplates))
|
|
78
|
-
.then(([{ resources }, { resourceTemplates }]) => [...resources, ...resourceTemplates].map((resource) => (0, mcp_utils_js_1.resourceFromMCPResource)(
|
|
84
|
+
.then(([{ resources }, { resourceTemplates }]) => [...resources, ...resourceTemplates].map((resource) => (0, mcp_utils_js_1.resourceFromMCPResource)(resource, { client })))
|
|
79
85
|
: undefined;
|
|
80
86
|
return new MCPAgent({
|
|
81
87
|
name: client.getServerVersion()?.name,
|
|
@@ -108,6 +114,47 @@ class MCPAgent extends agent_js_1.Agent {
|
|
|
108
114
|
}
|
|
109
115
|
}
|
|
110
116
|
exports.MCPAgent = MCPAgent;
|
|
117
|
+
class ClientWithReconnect extends index_js_1.Client {
|
|
118
|
+
reconnectOptions;
|
|
119
|
+
constructor(info, options, reconnectOptions) {
|
|
120
|
+
super(info, options);
|
|
121
|
+
this.reconnectOptions = reconnectOptions;
|
|
122
|
+
}
|
|
123
|
+
shouldReconnect(error) {
|
|
124
|
+
const { transportCreator, shouldReconnect, maxReconnects } = this.reconnectOptions || {};
|
|
125
|
+
if (!transportCreator || maxReconnects === 0)
|
|
126
|
+
return false;
|
|
127
|
+
if (!shouldReconnect)
|
|
128
|
+
return true; // default to reconnect on all errors
|
|
129
|
+
return shouldReconnect(error);
|
|
130
|
+
}
|
|
131
|
+
async reconnect() {
|
|
132
|
+
const transportCreator = this.reconnectOptions?.transportCreator;
|
|
133
|
+
if (!transportCreator)
|
|
134
|
+
throw new Error("reconnect requires a transportCreator");
|
|
135
|
+
await (0, p_retry_1.default)(async () => {
|
|
136
|
+
await this.close();
|
|
137
|
+
await this.connect(await transportCreator());
|
|
138
|
+
}, {
|
|
139
|
+
retries: this.reconnectOptions?.maxReconnects ?? DEFAULT_MAX_RECONNECTS,
|
|
140
|
+
shouldRetry: this.shouldReconnect,
|
|
141
|
+
onFailedAttempt: (error) => debug("Reconnect attempt failed: %O", error),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
async request(request, resultSchema, options) {
|
|
145
|
+
try {
|
|
146
|
+
return await super.request(request, resultSchema, options);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (this.shouldReconnect(error)) {
|
|
150
|
+
debug("Error occurred, reconnecting to MCP server: %O", error);
|
|
151
|
+
await this.reconnect();
|
|
152
|
+
return await super.request(request, resultSchema, options);
|
|
153
|
+
}
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
111
158
|
class MCPBase extends agent_js_1.Agent {
|
|
112
159
|
constructor(options) {
|
|
113
160
|
super(options);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ReadableStream } from "node:stream/web";
|
|
1
2
|
import type { Context } from "../execution-engine/context.js";
|
|
2
3
|
import type { MessagePayload, MessageQueueListener, Unsubscribe } from "../execution-engine/message-queue.js";
|
|
3
4
|
import { type PromiseOrValue } from "../utils/type-utils.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.UserAgent = void 0;
|
|
4
|
+
const web_1 = require("node:stream/web");
|
|
4
5
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
5
6
|
const agent_js_1 = require("./agent.js");
|
|
6
7
|
class UserAgent extends agent_js_1.Agent {
|
|
@@ -44,7 +45,7 @@ class UserAgent extends agent_js_1.Agent {
|
|
|
44
45
|
}
|
|
45
46
|
get stream() {
|
|
46
47
|
let subscriptions = [];
|
|
47
|
-
return new ReadableStream({
|
|
48
|
+
return new web_1.ReadableStream({
|
|
48
49
|
start: (controller) => {
|
|
49
50
|
const subscribeTopic = (0, type_utils_js_1.orArrayToArray)(this.subscribeTopic);
|
|
50
51
|
subscriptions = subscribeTopic.map((topic) => this.subscribe(topic, (message) => {
|
|
@@ -5,17 +5,28 @@ import { ChatModel } from "../models/chat-model.js";
|
|
|
5
5
|
import { type ContextLimits, ExecutionContext, type Runnable } from "./context.js";
|
|
6
6
|
import { type MessagePayload, MessageQueue, type MessageQueueListener, type Unsubscribe } from "./message-queue.js";
|
|
7
7
|
export interface ExecutionEngineOptions {
|
|
8
|
+
name?: string;
|
|
9
|
+
description?: string;
|
|
8
10
|
model?: ChatModel;
|
|
9
11
|
tools?: Agent[];
|
|
10
12
|
agents?: Agent[];
|
|
11
13
|
limits?: ContextLimits;
|
|
12
14
|
}
|
|
13
15
|
export declare class ExecutionEngine extends EventEmitter {
|
|
16
|
+
static load({ path, ...options }: {
|
|
17
|
+
path: string;
|
|
18
|
+
} & ExecutionEngineOptions): Promise<ExecutionEngine>;
|
|
14
19
|
constructor(options?: ExecutionEngineOptions);
|
|
20
|
+
name?: string;
|
|
21
|
+
description?: string;
|
|
15
22
|
readonly messageQueue: MessageQueue;
|
|
16
23
|
model?: ChatModel;
|
|
17
|
-
tools: Agent[]
|
|
18
|
-
|
|
24
|
+
readonly tools: Agent<Message, Message>[] & {
|
|
25
|
+
[key: string]: Agent<Message, Message>;
|
|
26
|
+
};
|
|
27
|
+
readonly agents: Agent<Message, Message>[] & {
|
|
28
|
+
[key: string]: Agent<Message, Message>;
|
|
29
|
+
};
|
|
19
30
|
limits?: ContextLimits;
|
|
20
31
|
addAgent(...agents: Agent[]): void;
|
|
21
32
|
newContext(): ExecutionContext;
|
|
@@ -7,26 +7,43 @@ exports.ExecutionEngine = void 0;
|
|
|
7
7
|
const node_events_1 = __importDefault(require("node:events"));
|
|
8
8
|
const zod_1 = require("zod");
|
|
9
9
|
const agent_js_1 = require("../agents/agent.js");
|
|
10
|
+
const index_js_1 = require("../loader/index.js");
|
|
10
11
|
const chat_model_js_1 = require("../models/chat-model.js");
|
|
11
12
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
12
13
|
const context_js_1 = require("./context.js");
|
|
13
14
|
const message_queue_js_1 = require("./message-queue.js");
|
|
14
15
|
class ExecutionEngine extends node_events_1.default {
|
|
16
|
+
static async load({ path, ...options }) {
|
|
17
|
+
const { model, agents, tools, ...aigne } = await (0, index_js_1.load)({ path });
|
|
18
|
+
return new ExecutionEngine({
|
|
19
|
+
model,
|
|
20
|
+
...options,
|
|
21
|
+
name: options.name || aigne.name || undefined,
|
|
22
|
+
description: options.description || aigne.description || undefined,
|
|
23
|
+
agents: agents.concat(options.agents ?? []),
|
|
24
|
+
tools: tools.concat(options.tools ?? []),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
15
27
|
constructor(options) {
|
|
16
28
|
if (options)
|
|
17
29
|
(0, type_utils_js_1.checkArguments)("ExecutionEngine", executionEngineOptionsSchema, options);
|
|
18
30
|
super();
|
|
31
|
+
this.name = options?.name;
|
|
32
|
+
this.description = options?.description;
|
|
19
33
|
this.model = options?.model;
|
|
20
|
-
this.tools = options?.tools ?? [];
|
|
21
34
|
this.limits = options?.limits;
|
|
35
|
+
if (options?.tools?.length)
|
|
36
|
+
this.tools.push(...options.tools);
|
|
22
37
|
if (options?.agents?.length)
|
|
23
38
|
this.addAgent(...options.agents);
|
|
24
39
|
this.initProcessExitHandler();
|
|
25
40
|
}
|
|
41
|
+
name;
|
|
42
|
+
description;
|
|
26
43
|
messageQueue = new message_queue_js_1.MessageQueue();
|
|
27
44
|
model;
|
|
28
|
-
tools;
|
|
29
|
-
agents = [];
|
|
45
|
+
tools = (0, type_utils_js_1.createAccessorArray)([], (arr, name) => arr.find((i) => i.name === name));
|
|
46
|
+
agents = (0, type_utils_js_1.createAccessorArray)([], (arr, name) => arr.find((i) => i.name === name));
|
|
30
47
|
limits;
|
|
31
48
|
addAgent(...agents) {
|
|
32
49
|
(0, type_utils_js_1.checkArguments)("ExecutionEngine.addAgent", executionEngineAddAgentArgsSchema, agents);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ZodObject, type ZodType, z } from "zod";
|
|
2
|
+
import type { Message } from "../agents/agent.js";
|
|
3
|
+
export declare function loadAgentFromJsFile(path: string): Promise<{
|
|
4
|
+
name: string;
|
|
5
|
+
fn: (args_0: Message) => Message;
|
|
6
|
+
description?: string | undefined;
|
|
7
|
+
input_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
8
|
+
[x: string]: any;
|
|
9
|
+
}, {
|
|
10
|
+
[x: string]: any;
|
|
11
|
+
}> | undefined;
|
|
12
|
+
output_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
13
|
+
[x: string]: any;
|
|
14
|
+
}, {
|
|
15
|
+
[x: string]: any;
|
|
16
|
+
}> | undefined;
|
|
17
|
+
}>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadAgentFromJsFile = loadAgentFromJsFile;
|
|
37
|
+
const json_schema_to_zod_1 = require("@aigne/json-schema-to-zod");
|
|
38
|
+
const zod_1 = require("zod");
|
|
39
|
+
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
40
|
+
const schema_js_1 = require("./schema.js");
|
|
41
|
+
const agentJsFileSchema = zod_1.z.object({
|
|
42
|
+
name: zod_1.z.string(),
|
|
43
|
+
description: zod_1.z
|
|
44
|
+
.string()
|
|
45
|
+
.nullish()
|
|
46
|
+
.transform((v) => v ?? undefined),
|
|
47
|
+
input_schema: schema_js_1.inputOutputSchema
|
|
48
|
+
.nullish()
|
|
49
|
+
.transform((v) => (v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined)),
|
|
50
|
+
output_schema: schema_js_1.inputOutputSchema
|
|
51
|
+
.nullish()
|
|
52
|
+
.transform((v) => (v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined)),
|
|
53
|
+
fn: zod_1.z.function(),
|
|
54
|
+
});
|
|
55
|
+
async function loadAgentFromJsFile(path) {
|
|
56
|
+
const { default: agent } = await (0, type_utils_js_1.tryOrThrow)(() => Promise.resolve(`${path}`).then(s => __importStar(require(s))), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
|
|
57
|
+
if (typeof agent !== "function") {
|
|
58
|
+
throw new Error(`Agent file ${path} must export a default function, but got ${typeof agent}`);
|
|
59
|
+
}
|
|
60
|
+
return (0, type_utils_js_1.tryOrThrow)(() => agentJsFileSchema.parse({
|
|
61
|
+
name: agent.name,
|
|
62
|
+
description: agent.description,
|
|
63
|
+
input_schema: agent.input_schema,
|
|
64
|
+
output_schema: agent.output_schema,
|
|
65
|
+
fn: agent,
|
|
66
|
+
}), (error) => new Error(`Failed to parse agent from ${path}: ${error.message}`));
|
|
67
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ZodObject, type ZodType, z } from "zod";
|
|
2
|
+
export declare function loadAgentFromYamlFile(path: string): Promise<{
|
|
3
|
+
type: "ai";
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string | undefined;
|
|
6
|
+
tools?: string[] | undefined;
|
|
7
|
+
instructions?: string | undefined;
|
|
8
|
+
input_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
9
|
+
[x: string]: any;
|
|
10
|
+
}, {
|
|
11
|
+
[x: string]: any;
|
|
12
|
+
}> | undefined;
|
|
13
|
+
output_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
14
|
+
[x: string]: any;
|
|
15
|
+
}, {
|
|
16
|
+
[x: string]: any;
|
|
17
|
+
}> | undefined;
|
|
18
|
+
output_key?: string | undefined;
|
|
19
|
+
} | {
|
|
20
|
+
type: "mcp";
|
|
21
|
+
url?: string | undefined;
|
|
22
|
+
command?: string | undefined;
|
|
23
|
+
args?: string[] | undefined;
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadAgentFromYamlFile = loadAgentFromYamlFile;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const json_schema_to_zod_1 = require("@aigne/json-schema-to-zod");
|
|
6
|
+
const yaml_1 = require("yaml");
|
|
7
|
+
const zod_1 = require("zod");
|
|
8
|
+
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
9
|
+
const schema_js_1 = require("./schema.js");
|
|
10
|
+
const agentFileSchema = zod_1.z.discriminatedUnion("type", [
|
|
11
|
+
zod_1.z.object({
|
|
12
|
+
type: zod_1.z.literal("ai"),
|
|
13
|
+
name: zod_1.z.string(),
|
|
14
|
+
description: zod_1.z
|
|
15
|
+
.string()
|
|
16
|
+
.nullish()
|
|
17
|
+
.transform((v) => v ?? undefined),
|
|
18
|
+
instructions: zod_1.z
|
|
19
|
+
.string()
|
|
20
|
+
.nullish()
|
|
21
|
+
.transform((v) => v ?? undefined),
|
|
22
|
+
input_schema: schema_js_1.inputOutputSchema
|
|
23
|
+
.nullish()
|
|
24
|
+
.transform((v) => (v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined)),
|
|
25
|
+
output_schema: schema_js_1.inputOutputSchema
|
|
26
|
+
.nullish()
|
|
27
|
+
.transform((v) => (v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined)),
|
|
28
|
+
output_key: zod_1.z
|
|
29
|
+
.string()
|
|
30
|
+
.nullish()
|
|
31
|
+
.transform((v) => v ?? undefined),
|
|
32
|
+
tools: zod_1.z
|
|
33
|
+
.array(zod_1.z.string())
|
|
34
|
+
.nullish()
|
|
35
|
+
.transform((v) => v ?? undefined),
|
|
36
|
+
}),
|
|
37
|
+
zod_1.z.object({
|
|
38
|
+
type: zod_1.z.literal("mcp"),
|
|
39
|
+
url: zod_1.z
|
|
40
|
+
.string()
|
|
41
|
+
.nullish()
|
|
42
|
+
.transform((v) => v ?? undefined),
|
|
43
|
+
command: zod_1.z
|
|
44
|
+
.string()
|
|
45
|
+
.nullish()
|
|
46
|
+
.transform((v) => v ?? undefined),
|
|
47
|
+
args: zod_1.z
|
|
48
|
+
.array(zod_1.z.string())
|
|
49
|
+
.nullish()
|
|
50
|
+
.transform((v) => v ?? undefined),
|
|
51
|
+
}),
|
|
52
|
+
]);
|
|
53
|
+
async function loadAgentFromYamlFile(path) {
|
|
54
|
+
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}`));
|
|
55
|
+
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}`));
|
|
56
|
+
const agent = (0, type_utils_js_1.tryOrThrow)(() => agentFileSchema.parse({ ...json, type: json.type ?? "ai" }), (error) => new Error(`Failed to validate agent definition from ${path}: ${error.message}`));
|
|
57
|
+
return agent;
|
|
58
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Agent } from "../agents/agent.js";
|
|
2
|
+
import type { ChatModel } from "../models/chat-model.js";
|
|
3
|
+
export interface LoadOptions {
|
|
4
|
+
path: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function load(options: LoadOptions): Promise<{
|
|
7
|
+
model: ChatModel | undefined;
|
|
8
|
+
agents: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
|
|
9
|
+
tools: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
|
|
10
|
+
description?: string | null | undefined;
|
|
11
|
+
name?: string | null | undefined;
|
|
12
|
+
chat_model?: {
|
|
13
|
+
name?: string | null | undefined;
|
|
14
|
+
temperature?: number | null | undefined;
|
|
15
|
+
provider?: string | null | undefined;
|
|
16
|
+
top_p?: number | null | undefined;
|
|
17
|
+
frequent_penalty?: number | null | undefined;
|
|
18
|
+
presence_penalty?: number | null | undefined;
|
|
19
|
+
} | null | undefined;
|
|
20
|
+
}>;
|
|
21
|
+
export declare function loadAgent(path: string): Promise<Agent>;
|
|
22
|
+
export declare function loadAIGNEFile(path: string): Promise<{
|
|
23
|
+
description?: string | null | undefined;
|
|
24
|
+
tools?: string[] | null | undefined;
|
|
25
|
+
name?: string | null | undefined;
|
|
26
|
+
chat_model?: {
|
|
27
|
+
name?: string | null | undefined;
|
|
28
|
+
temperature?: number | null | undefined;
|
|
29
|
+
provider?: string | null | undefined;
|
|
30
|
+
top_p?: number | null | undefined;
|
|
31
|
+
frequent_penalty?: number | null | undefined;
|
|
32
|
+
presence_penalty?: number | null | undefined;
|
|
33
|
+
} | null | undefined;
|
|
34
|
+
agents?: string[] | null | undefined;
|
|
35
|
+
}>;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.load = load;
|
|
4
|
+
exports.loadAgent = loadAgent;
|
|
5
|
+
exports.loadAIGNEFile = loadAIGNEFile;
|
|
6
|
+
const promises_1 = require("node:fs/promises");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const yaml_1 = require("yaml");
|
|
9
|
+
const zod_1 = require("zod");
|
|
10
|
+
const agent_js_1 = require("../agents/agent.js");
|
|
11
|
+
const ai_agent_js_1 = require("../agents/ai-agent.js");
|
|
12
|
+
const mcp_agent_js_1 = require("../agents/mcp-agent.js");
|
|
13
|
+
const claude_chat_model_js_1 = require("../models/claude-chat-model.js");
|
|
14
|
+
const openai_chat_model_js_1 = require("../models/openai-chat-model.js");
|
|
15
|
+
const xai_chat_model_js_1 = require("../models/xai-chat-model.js");
|
|
16
|
+
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
17
|
+
const agent_js_js_1 = require("./agent-js.js");
|
|
18
|
+
const agent_yaml_js_1 = require("./agent-yaml.js");
|
|
19
|
+
const DEFAULT_MODEL_PROVIDER = "openai";
|
|
20
|
+
const AIGNE_FILE_NAME = ["aigne.yaml", "aigne.yml"];
|
|
21
|
+
async function load(options) {
|
|
22
|
+
const { path } = options;
|
|
23
|
+
const aigneFilePath = await getAIGNEFilePath(path);
|
|
24
|
+
const rootDir = (0, node_path_1.dirname)(aigneFilePath);
|
|
25
|
+
const aigne = await loadAIGNEFile(aigneFilePath);
|
|
26
|
+
const agents = await Promise.all((aigne.agents ?? []).map((filename) => loadAgent((0, node_path_1.join)(rootDir, filename))));
|
|
27
|
+
const tools = await Promise.all((aigne.tools ?? []).map((filename) => loadAgent((0, node_path_1.join)(rootDir, filename))));
|
|
28
|
+
return {
|
|
29
|
+
...aigne,
|
|
30
|
+
model: await loadModel(aigne.chat_model),
|
|
31
|
+
agents,
|
|
32
|
+
tools,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async function loadAgent(path) {
|
|
36
|
+
if ((0, node_path_1.extname)(path) === ".js") {
|
|
37
|
+
const agent = await (0, agent_js_js_1.loadAgentFromJsFile)(path);
|
|
38
|
+
return agent_js_1.FunctionAgent.from({
|
|
39
|
+
name: agent.name,
|
|
40
|
+
description: agent.description,
|
|
41
|
+
inputSchema: agent.input_schema,
|
|
42
|
+
outputSchema: agent.output_schema,
|
|
43
|
+
fn: agent.fn,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if ((0, node_path_1.extname)(path) === ".yaml" || (0, node_path_1.extname)(path) === ".yml") {
|
|
47
|
+
const agent = await (0, agent_yaml_js_1.loadAgentFromYamlFile)(path);
|
|
48
|
+
if (agent.type === "ai") {
|
|
49
|
+
return ai_agent_js_1.AIAgent.from({
|
|
50
|
+
name: agent.name,
|
|
51
|
+
description: agent.description,
|
|
52
|
+
instructions: agent.instructions,
|
|
53
|
+
inputSchema: agent.input_schema,
|
|
54
|
+
outputSchema: agent.output_schema,
|
|
55
|
+
outputKey: agent.output_key,
|
|
56
|
+
tools: await Promise.all((agent.tools ?? []).map((filename) => loadAgent((0, node_path_1.join)((0, node_path_1.dirname)(path), filename)))),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (agent.type === "mcp") {
|
|
60
|
+
if (agent.url) {
|
|
61
|
+
return mcp_agent_js_1.MCPAgent.from({
|
|
62
|
+
url: agent.url,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (agent.command) {
|
|
66
|
+
return mcp_agent_js_1.MCPAgent.from({
|
|
67
|
+
command: agent.command,
|
|
68
|
+
args: agent.args,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
throw new Error(`Missing url or command in mcp agent: ${path}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
throw new Error(`Unsupported agent file type: ${path}`);
|
|
75
|
+
}
|
|
76
|
+
async function loadModel(model) {
|
|
77
|
+
if (!model?.name)
|
|
78
|
+
return undefined;
|
|
79
|
+
const params = {
|
|
80
|
+
model: model.name,
|
|
81
|
+
temperature: model.temperature ?? undefined,
|
|
82
|
+
topP: model.top_p ?? undefined,
|
|
83
|
+
frequencyPenalty: model.frequent_penalty ?? undefined,
|
|
84
|
+
presencePenalty: model.presence_penalty ?? undefined,
|
|
85
|
+
};
|
|
86
|
+
const availableModels = [openai_chat_model_js_1.OpenAIChatModel, claude_chat_model_js_1.ClaudeChatModel, xai_chat_model_js_1.XAIChatModel];
|
|
87
|
+
const M = availableModels.find((m) => m.name.toLowerCase().includes(model.provider || DEFAULT_MODEL_PROVIDER));
|
|
88
|
+
if (!M)
|
|
89
|
+
throw new Error(`Unsupported model: ${model.provider} ${model.name}`);
|
|
90
|
+
return new M(params);
|
|
91
|
+
}
|
|
92
|
+
const aigneFileSchema = zod_1.z.object({
|
|
93
|
+
name: zod_1.z.string().nullish(),
|
|
94
|
+
description: zod_1.z.string().nullish(),
|
|
95
|
+
chat_model: zod_1.z
|
|
96
|
+
.union([
|
|
97
|
+
zod_1.z.string(),
|
|
98
|
+
zod_1.z.object({
|
|
99
|
+
provider: zod_1.z.string().nullish(),
|
|
100
|
+
name: zod_1.z.string().nullish(),
|
|
101
|
+
temperature: zod_1.z.number().min(0).max(2).nullish(),
|
|
102
|
+
top_p: zod_1.z.number().min(0).nullish(),
|
|
103
|
+
frequent_penalty: zod_1.z.number().min(-2).max(2).nullish(),
|
|
104
|
+
presence_penalty: zod_1.z.number().min(-2).max(2).nullish(),
|
|
105
|
+
}),
|
|
106
|
+
])
|
|
107
|
+
.nullish()
|
|
108
|
+
.transform((v) => (typeof v === "string" ? { name: v } : v)),
|
|
109
|
+
agents: zod_1.z.array(zod_1.z.string()).nullish(),
|
|
110
|
+
tools: zod_1.z.array(zod_1.z.string()).nullish(),
|
|
111
|
+
});
|
|
112
|
+
async function loadAIGNEFile(path) {
|
|
113
|
+
const raw = await (0, type_utils_js_1.tryOrThrow)(() => (0, promises_1.readFile)(path, "utf8"), (error) => new Error(`Failed to load aigne.yaml from ${path}: ${error.message}`));
|
|
114
|
+
const json = await (0, type_utils_js_1.tryOrThrow)(() => (0, yaml_1.parse)(raw), (error) => new Error(`Failed to parse aigne.yaml from ${path}: ${error.message}`));
|
|
115
|
+
const agent = (0, type_utils_js_1.tryOrThrow)(() => aigneFileSchema.parse(json), (error) => new Error(`Failed to validate aigne.yaml from ${path}: ${error.message}`));
|
|
116
|
+
return agent;
|
|
117
|
+
}
|
|
118
|
+
async function getAIGNEFilePath(path) {
|
|
119
|
+
const s = await (0, promises_1.stat)(path);
|
|
120
|
+
if (s.isDirectory()) {
|
|
121
|
+
for (const file of AIGNE_FILE_NAME) {
|
|
122
|
+
const filePath = (0, node_path_1.join)(path, file);
|
|
123
|
+
if (await (0, promises_1.exists)(filePath))
|
|
124
|
+
return filePath;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return path;
|
|
128
|
+
}
|