@aigne/core 1.5.1-0 → 1.5.1-2
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/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 +9 -2
- package/lib/cjs/execution-engine/execution-engine.js +14 -3
- package/lib/cjs/loader/ai-agent.d.ts +21 -0
- package/lib/cjs/loader/ai-agent.js +40 -0
- package/lib/cjs/loader/function-agent.d.ts +21 -0
- package/lib/cjs/loader/function-agent.js +67 -0
- package/lib/cjs/loader/index.d.ts +25 -0
- package/lib/cjs/loader/index.js +93 -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 +2 -8
- package/lib/cjs/utils/logger.js +14 -55
- 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 +9 -2
- package/lib/dts/loader/ai-agent.d.ts +21 -0
- package/lib/dts/loader/function-agent.d.ts +21 -0
- package/lib/dts/loader/index.d.ts +25 -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 +2 -8
- 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 +9 -2
- package/lib/esm/execution-engine/execution-engine.js +15 -4
- package/lib/esm/loader/ai-agent.d.ts +21 -0
- package/lib/esm/loader/ai-agent.js +37 -0
- package/lib/esm/loader/function-agent.d.ts +21 -0
- package/lib/esm/loader/function-agent.js +31 -0
- package/lib/esm/loader/index.d.ts +25 -0
- package/lib/esm/loader/index.js +88 -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 +2 -8
- package/lib/esm/utils/logger.js +14 -23
- 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 +12 -7
|
@@ -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 {};
|
|
@@ -2,6 +2,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
|
2
2
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
3
3
|
import { StdioClientTransport, getDefaultEnvironment, } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
4
4
|
import { UriTemplate } from "@modelcontextprotocol/sdk/shared/uriTemplate.js";
|
|
5
|
+
import pRetry from "p-retry";
|
|
5
6
|
import { z } from "zod";
|
|
6
7
|
import { logger } from "../utils/logger.js";
|
|
7
8
|
import { promptFromMCPPrompt, resourceFromMCPResource, toolFromMCPTool, } from "../utils/mcp-utils.js";
|
|
@@ -9,6 +10,7 @@ import { checkArguments, createAccessorArray } from "../utils/type-utils.js";
|
|
|
9
10
|
import { Agent } from "./agent.js";
|
|
10
11
|
const MCP_AGENT_CLIENT_NAME = "MCPAgent";
|
|
11
12
|
const MCP_AGENT_CLIENT_VERSION = "0.0.1";
|
|
13
|
+
const DEFAULT_MAX_RECONNECTS = 10;
|
|
12
14
|
const debug = logger.base.extend("mcp");
|
|
13
15
|
function isSSEServerParameters(options) {
|
|
14
16
|
return "url" in options && typeof options.url === "string";
|
|
@@ -29,11 +31,11 @@ export class MCPAgent extends Agent {
|
|
|
29
31
|
static from(options) {
|
|
30
32
|
checkArguments("MCPAgent.from", mcpAgentOptionsSchema, options);
|
|
31
33
|
if (isSSEServerParameters(options)) {
|
|
32
|
-
const transport = new SSEClientTransport(new URL(options.url));
|
|
34
|
+
const transport = () => new SSEClientTransport(new URL(options.url));
|
|
33
35
|
return MCPAgent.fromTransport(transport, options);
|
|
34
36
|
}
|
|
35
37
|
if (isStdioServerParameters(options)) {
|
|
36
|
-
const transport = new StdioClientTransport({
|
|
38
|
+
const transport = () => new StdioClientTransport({
|
|
37
39
|
...options,
|
|
38
40
|
env: {
|
|
39
41
|
...getDefaultEnvironment(),
|
|
@@ -45,23 +47,24 @@ export class MCPAgent extends Agent {
|
|
|
45
47
|
}
|
|
46
48
|
return new MCPAgent(options);
|
|
47
49
|
}
|
|
48
|
-
static async fromTransport(
|
|
49
|
-
const client = new
|
|
50
|
+
static async fromTransport(transportCreator, options) {
|
|
51
|
+
const client = new ClientWithReconnect({
|
|
50
52
|
name: MCP_AGENT_CLIENT_NAME,
|
|
51
53
|
version: MCP_AGENT_CLIENT_VERSION,
|
|
52
|
-
});
|
|
54
|
+
}, undefined, isSSEServerParameters(options) ? { transportCreator, ...options } : undefined);
|
|
55
|
+
const transport = transportCreator();
|
|
53
56
|
await debug.spinner(client.connect(transport), `Connecting to MCP server: ${getMCPServerString(options)}`);
|
|
54
57
|
const mcpServer = getMCPServerName(client);
|
|
55
58
|
const { tools: isToolsAvailable, prompts: isPromptsAvailable, resources: isResourcesAvailable, } = client.getServerCapabilities() ?? {};
|
|
56
59
|
const tools = isToolsAvailable
|
|
57
60
|
? await debug
|
|
58
61
|
.spinner(client.listTools(), `Listing tools from ${mcpServer}`, ({ tools }) => debug("%O", tools))
|
|
59
|
-
.then(({ tools }) => tools.map((tool) => toolFromMCPTool(
|
|
62
|
+
.then(({ tools }) => tools.map((tool) => toolFromMCPTool(tool, { client })))
|
|
60
63
|
: undefined;
|
|
61
64
|
const prompts = isPromptsAvailable
|
|
62
65
|
? await debug
|
|
63
66
|
.spinner(client.listPrompts(), `Listing prompts from ${mcpServer}`, ({ prompts }) => debug("%O", prompts))
|
|
64
|
-
.then(({ prompts }) => prompts.map((prompt) => promptFromMCPPrompt(
|
|
67
|
+
.then(({ prompts }) => prompts.map((prompt) => promptFromMCPPrompt(prompt, { client })))
|
|
65
68
|
: undefined;
|
|
66
69
|
const resources = isResourcesAvailable
|
|
67
70
|
? await debug
|
|
@@ -72,7 +75,7 @@ export class MCPAgent extends Agent {
|
|
|
72
75
|
client.listResources().catch(() => ({ resources: [] })),
|
|
73
76
|
client.listResourceTemplates().catch(() => ({ resourceTemplates: [] })),
|
|
74
77
|
]), `Listing resources from ${mcpServer}`, ([{ resources }, { resourceTemplates }]) => debug("%O\n%O", resources, resourceTemplates))
|
|
75
|
-
.then(([{ resources }, { resourceTemplates }]) => [...resources, ...resourceTemplates].map((resource) => resourceFromMCPResource(
|
|
78
|
+
.then(([{ resources }, { resourceTemplates }]) => [...resources, ...resourceTemplates].map((resource) => resourceFromMCPResource(resource, { client })))
|
|
76
79
|
: undefined;
|
|
77
80
|
return new MCPAgent({
|
|
78
81
|
name: client.getServerVersion()?.name,
|
|
@@ -104,6 +107,47 @@ export class MCPAgent extends Agent {
|
|
|
104
107
|
await this.client.close();
|
|
105
108
|
}
|
|
106
109
|
}
|
|
110
|
+
class ClientWithReconnect extends Client {
|
|
111
|
+
reconnectOptions;
|
|
112
|
+
constructor(info, options, reconnectOptions) {
|
|
113
|
+
super(info, options);
|
|
114
|
+
this.reconnectOptions = reconnectOptions;
|
|
115
|
+
}
|
|
116
|
+
shouldReconnect(error) {
|
|
117
|
+
const { transportCreator, shouldReconnect, maxReconnects } = this.reconnectOptions || {};
|
|
118
|
+
if (!transportCreator || maxReconnects === 0)
|
|
119
|
+
return false;
|
|
120
|
+
if (!shouldReconnect)
|
|
121
|
+
return true; // default to reconnect on all errors
|
|
122
|
+
return shouldReconnect(error);
|
|
123
|
+
}
|
|
124
|
+
async reconnect() {
|
|
125
|
+
const transportCreator = this.reconnectOptions?.transportCreator;
|
|
126
|
+
if (!transportCreator)
|
|
127
|
+
throw new Error("reconnect requires a transportCreator");
|
|
128
|
+
await pRetry(async () => {
|
|
129
|
+
await this.close();
|
|
130
|
+
await this.connect(await transportCreator());
|
|
131
|
+
}, {
|
|
132
|
+
retries: this.reconnectOptions?.maxReconnects ?? DEFAULT_MAX_RECONNECTS,
|
|
133
|
+
shouldRetry: this.shouldReconnect,
|
|
134
|
+
onFailedAttempt: (error) => debug("Reconnect attempt failed: %O", error),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
async request(request, resultSchema, options) {
|
|
138
|
+
try {
|
|
139
|
+
return await super.request(request, resultSchema, options);
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (this.shouldReconnect(error)) {
|
|
143
|
+
debug("Error occurred, reconnecting to MCP server: %O", error);
|
|
144
|
+
await this.reconnect();
|
|
145
|
+
return await super.request(request, resultSchema, options);
|
|
146
|
+
}
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
107
151
|
export class MCPBase extends Agent {
|
|
108
152
|
constructor(options) {
|
|
109
153
|
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";
|
|
@@ -11,11 +11,18 @@ export interface ExecutionEngineOptions {
|
|
|
11
11
|
limits?: ContextLimits;
|
|
12
12
|
}
|
|
13
13
|
export declare class ExecutionEngine extends EventEmitter {
|
|
14
|
+
static load({ path, ...options }: {
|
|
15
|
+
path: string;
|
|
16
|
+
} & ExecutionEngineOptions): Promise<ExecutionEngine>;
|
|
14
17
|
constructor(options?: ExecutionEngineOptions);
|
|
15
18
|
readonly messageQueue: MessageQueue;
|
|
16
19
|
model?: ChatModel;
|
|
17
|
-
tools: Agent[]
|
|
18
|
-
|
|
20
|
+
readonly tools: Agent<Message, Message>[] & {
|
|
21
|
+
[key: string]: Agent<Message, Message>;
|
|
22
|
+
};
|
|
23
|
+
readonly agents: Agent<Message, Message>[] & {
|
|
24
|
+
[key: string]: Agent<Message, Message>;
|
|
25
|
+
};
|
|
19
26
|
limits?: ContextLimits;
|
|
20
27
|
addAgent(...agents: Agent[]): void;
|
|
21
28
|
newContext(): ExecutionContext;
|
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
import EventEmitter from "node:events";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { Agent } from "../agents/agent.js";
|
|
4
|
+
import { load } from "../loader/index.js";
|
|
4
5
|
import { ChatModel } from "../models/chat-model.js";
|
|
5
|
-
import { checkArguments } from "../utils/type-utils.js";
|
|
6
|
+
import { checkArguments, createAccessorArray } from "../utils/type-utils.js";
|
|
6
7
|
import { ExecutionContext } from "./context.js";
|
|
7
8
|
import { MessageQueue, } from "./message-queue.js";
|
|
8
9
|
export class ExecutionEngine extends EventEmitter {
|
|
10
|
+
static async load({ path, ...options }) {
|
|
11
|
+
const { model, agents, tools } = await load({ path });
|
|
12
|
+
return new ExecutionEngine({
|
|
13
|
+
model,
|
|
14
|
+
...options,
|
|
15
|
+
agents: agents.concat(options.agents ?? []),
|
|
16
|
+
tools: tools.concat(options.tools ?? []),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
9
19
|
constructor(options) {
|
|
10
20
|
if (options)
|
|
11
21
|
checkArguments("ExecutionEngine", executionEngineOptionsSchema, options);
|
|
12
22
|
super();
|
|
13
23
|
this.model = options?.model;
|
|
14
|
-
this.tools = options?.tools ?? [];
|
|
15
24
|
this.limits = options?.limits;
|
|
25
|
+
if (options?.tools?.length)
|
|
26
|
+
this.tools.push(...options.tools);
|
|
16
27
|
if (options?.agents?.length)
|
|
17
28
|
this.addAgent(...options.agents);
|
|
18
29
|
this.initProcessExitHandler();
|
|
19
30
|
}
|
|
20
31
|
messageQueue = new MessageQueue();
|
|
21
32
|
model;
|
|
22
|
-
tools;
|
|
23
|
-
agents = [];
|
|
33
|
+
tools = createAccessorArray([], (arr, name) => arr.find((i) => i.name === name));
|
|
34
|
+
agents = createAccessorArray([], (arr, name) => arr.find((i) => i.name === name));
|
|
24
35
|
limits;
|
|
25
36
|
addAgent(...agents) {
|
|
26
37
|
checkArguments("ExecutionEngine.addAgent", executionEngineAddAgentArgsSchema, agents);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { type ZodObject, type ZodType, z } from "zod";
|
|
3
|
+
export declare function loadAgentFromYamlFile(path: string, { readFile: _readFile }?: {
|
|
4
|
+
readFile?: typeof readFile;
|
|
5
|
+
}): Promise<{
|
|
6
|
+
name: string;
|
|
7
|
+
description?: string | undefined;
|
|
8
|
+
tools?: string[] | undefined;
|
|
9
|
+
instructions?: string | undefined;
|
|
10
|
+
input_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
11
|
+
[x: string]: any;
|
|
12
|
+
}, {
|
|
13
|
+
[x: string]: any;
|
|
14
|
+
}> | undefined;
|
|
15
|
+
output_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
16
|
+
[x: string]: any;
|
|
17
|
+
}, {
|
|
18
|
+
[x: string]: any;
|
|
19
|
+
}> | undefined;
|
|
20
|
+
output_key?: string | undefined;
|
|
21
|
+
}>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { jsonSchemaToZod } from "@aigne/json-schema-to-zod";
|
|
3
|
+
import { parse } from "yaml";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { tryOrThrow } from "../utils/type-utils.js";
|
|
6
|
+
import { inputOutputSchema } from "./schema.js";
|
|
7
|
+
const agentFileSchema = z.object({
|
|
8
|
+
name: z.string(),
|
|
9
|
+
description: z
|
|
10
|
+
.string()
|
|
11
|
+
.nullish()
|
|
12
|
+
.transform((v) => v ?? undefined),
|
|
13
|
+
instructions: z
|
|
14
|
+
.string()
|
|
15
|
+
.nullish()
|
|
16
|
+
.transform((v) => v ?? undefined),
|
|
17
|
+
input_schema: inputOutputSchema
|
|
18
|
+
.nullish()
|
|
19
|
+
.transform((v) => (v ? jsonSchemaToZod(v) : undefined)),
|
|
20
|
+
output_schema: inputOutputSchema
|
|
21
|
+
.nullish()
|
|
22
|
+
.transform((v) => (v ? jsonSchemaToZod(v) : undefined)),
|
|
23
|
+
output_key: z
|
|
24
|
+
.string()
|
|
25
|
+
.nullish()
|
|
26
|
+
.transform((v) => v ?? undefined),
|
|
27
|
+
tools: z
|
|
28
|
+
.array(z.string())
|
|
29
|
+
.nullish()
|
|
30
|
+
.transform((v) => v ?? undefined),
|
|
31
|
+
});
|
|
32
|
+
export async function loadAgentFromYamlFile(path, { readFile: _readFile = readFile } = {}) {
|
|
33
|
+
const raw = await tryOrThrow(() => _readFile(path, "utf8"), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
|
|
34
|
+
const json = await tryOrThrow(() => parse(raw), (error) => new Error(`Failed to parse agent definition from ${path}: ${error.message}`));
|
|
35
|
+
const agent = tryOrThrow(() => agentFileSchema.parse(json), (error) => new Error(`Failed to validate agent definition from ${path}: ${error.message}`));
|
|
36
|
+
return agent;
|
|
37
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ZodObject, type ZodType, z } from "zod";
|
|
2
|
+
import type { Message } from "../agents/agent.js";
|
|
3
|
+
export declare function loadAgentFromJsFile(path: string, { import: _import }?: {
|
|
4
|
+
import?: (path: string) => Promise<{
|
|
5
|
+
default: unknown;
|
|
6
|
+
}>;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
name: string;
|
|
9
|
+
fn: (args_0: Message) => Message;
|
|
10
|
+
description?: string | undefined;
|
|
11
|
+
input_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
12
|
+
[x: string]: any;
|
|
13
|
+
}, {
|
|
14
|
+
[x: string]: any;
|
|
15
|
+
}> | undefined;
|
|
16
|
+
output_schema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
17
|
+
[x: string]: any;
|
|
18
|
+
}, {
|
|
19
|
+
[x: string]: any;
|
|
20
|
+
}> | undefined;
|
|
21
|
+
}>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsonSchemaToZod } from "@aigne/json-schema-to-zod";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { tryOrThrow } from "../utils/type-utils.js";
|
|
4
|
+
import { inputOutputSchema } from "./schema.js";
|
|
5
|
+
const agentJsFileSchema = z.object({
|
|
6
|
+
name: z.string(),
|
|
7
|
+
description: z
|
|
8
|
+
.string()
|
|
9
|
+
.nullish()
|
|
10
|
+
.transform((v) => v ?? undefined),
|
|
11
|
+
input_schema: inputOutputSchema
|
|
12
|
+
.nullish()
|
|
13
|
+
.transform((v) => (v ? jsonSchemaToZod(v) : undefined)),
|
|
14
|
+
output_schema: inputOutputSchema
|
|
15
|
+
.nullish()
|
|
16
|
+
.transform((v) => (v ? jsonSchemaToZod(v) : undefined)),
|
|
17
|
+
fn: z.function(),
|
|
18
|
+
});
|
|
19
|
+
export async function loadAgentFromJsFile(path, { import: _import } = {}) {
|
|
20
|
+
const { default: agent } = await tryOrThrow(() => (_import ? _import(path) : import(path)), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
|
|
21
|
+
if (typeof agent !== "function") {
|
|
22
|
+
throw new Error(`Agent file ${path} must export a default function, but got ${typeof agent}`);
|
|
23
|
+
}
|
|
24
|
+
return tryOrThrow(() => agentJsFileSchema.parse({
|
|
25
|
+
name: agent.name,
|
|
26
|
+
description: agent.description,
|
|
27
|
+
input_schema: agent.input_schema,
|
|
28
|
+
output_schema: agent.output_schema,
|
|
29
|
+
fn: agent,
|
|
30
|
+
}), (error) => new Error(`Failed to parse agent from ${path}: ${error.message}`));
|
|
31
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { type Agent } from "../agents/agent.js";
|
|
3
|
+
import type { ChatModel } from "../models/chat-model.js";
|
|
4
|
+
export interface LoadOptions {
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function load(options: LoadOptions): Promise<{
|
|
8
|
+
model: ChatModel | undefined;
|
|
9
|
+
agents: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
|
|
10
|
+
tools: Agent<import("../agents/agent.js").Message, import("../agents/agent.js").Message>[];
|
|
11
|
+
}>;
|
|
12
|
+
export declare function loadAgent(path: string): Promise<Agent>;
|
|
13
|
+
export declare function loadAIGNEFile(path: string, { readFile: _readFile }?: {
|
|
14
|
+
readFile?: typeof readFile;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
tools?: string[] | null | undefined;
|
|
17
|
+
chat_model?: {
|
|
18
|
+
name?: string | null | undefined;
|
|
19
|
+
temperature?: number | null | undefined;
|
|
20
|
+
top_p?: number | null | undefined;
|
|
21
|
+
frequent_penalty?: number | null | undefined;
|
|
22
|
+
presence_penalty?: number | null | undefined;
|
|
23
|
+
} | null | undefined;
|
|
24
|
+
agents?: string[] | null | undefined;
|
|
25
|
+
}>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, extname, join } from "node:path";
|
|
3
|
+
import { parse } from "yaml";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { FunctionAgent } from "../agents/agent.js";
|
|
6
|
+
import { AIAgent } from "../agents/ai-agent.js";
|
|
7
|
+
import { OpenAIChatModel } from "../models/openai-chat-model.js";
|
|
8
|
+
import { tryOrThrow } from "../utils/type-utils.js";
|
|
9
|
+
import { loadAgentFromYamlFile } from "./ai-agent.js";
|
|
10
|
+
import { loadAgentFromJsFile } from "./function-agent.js";
|
|
11
|
+
const AIGNE_FILE_NAME = "aigne.yaml";
|
|
12
|
+
export async function load(options) {
|
|
13
|
+
const { path } = options;
|
|
14
|
+
const aigneFilePath = path.endsWith(AIGNE_FILE_NAME) ? path : join(path, AIGNE_FILE_NAME);
|
|
15
|
+
const rootDir = dirname(aigneFilePath);
|
|
16
|
+
const aigne = await loadAIGNEFile(aigneFilePath);
|
|
17
|
+
const agents = await Promise.all((aigne.agents ?? []).map((filename) => loadAgent(join(rootDir, filename))));
|
|
18
|
+
const tools = await Promise.all((aigne.tools ?? []).map((filename) => loadAgent(join(rootDir, filename))));
|
|
19
|
+
return {
|
|
20
|
+
model: await loadModel(aigne.chat_model),
|
|
21
|
+
agents,
|
|
22
|
+
tools,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export async function loadAgent(path) {
|
|
26
|
+
if (extname(path) === ".js") {
|
|
27
|
+
const agent = await loadAgentFromJsFile(path);
|
|
28
|
+
return FunctionAgent.from({
|
|
29
|
+
name: agent.name,
|
|
30
|
+
description: agent.description,
|
|
31
|
+
inputSchema: agent.input_schema,
|
|
32
|
+
outputSchema: agent.output_schema,
|
|
33
|
+
fn: agent.fn,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (extname(path) === ".yaml" || extname(path) === ".yml") {
|
|
37
|
+
const agent = await loadAgentFromYamlFile(path);
|
|
38
|
+
return AIAgent.from({
|
|
39
|
+
name: agent.name,
|
|
40
|
+
description: agent.description,
|
|
41
|
+
instructions: agent.instructions,
|
|
42
|
+
inputSchema: agent.input_schema,
|
|
43
|
+
outputSchema: agent.output_schema,
|
|
44
|
+
outputKey: agent.output_key,
|
|
45
|
+
tools: await Promise.all((agent.tools ?? []).map((filename) => loadAgent(join(dirname(path), filename)))),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`Unsupported agent file type: ${path}`);
|
|
49
|
+
}
|
|
50
|
+
async function loadModel(model) {
|
|
51
|
+
if (!model?.name)
|
|
52
|
+
return undefined;
|
|
53
|
+
const params = {
|
|
54
|
+
model: model.name,
|
|
55
|
+
temperature: model.temperature ?? undefined,
|
|
56
|
+
topP: model.top_p ?? undefined,
|
|
57
|
+
frequencyPenalty: model.frequent_penalty ?? undefined,
|
|
58
|
+
presencePenalty: model.presence_penalty ?? undefined,
|
|
59
|
+
};
|
|
60
|
+
// TODO: add support for other models such as AutoChatModel, ClaudeChatModel, etc.
|
|
61
|
+
if (/^o1|gpt-/.test(model.name)) {
|
|
62
|
+
return new OpenAIChatModel(params);
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`Unsupported model: ${model.name}`);
|
|
65
|
+
}
|
|
66
|
+
const aigneFileSchema = z.object({
|
|
67
|
+
chat_model: z
|
|
68
|
+
.union([
|
|
69
|
+
z.string(),
|
|
70
|
+
z.object({
|
|
71
|
+
name: z.string().nullish(),
|
|
72
|
+
temperature: z.number().min(0).max(2).nullish(),
|
|
73
|
+
top_p: z.number().min(0).nullish(),
|
|
74
|
+
frequent_penalty: z.number().min(-2).max(2).nullish(),
|
|
75
|
+
presence_penalty: z.number().min(-2).max(2).nullish(),
|
|
76
|
+
}),
|
|
77
|
+
])
|
|
78
|
+
.nullish()
|
|
79
|
+
.transform((v) => (typeof v === "string" ? { name: v } : v)),
|
|
80
|
+
agents: z.array(z.string()).nullish(),
|
|
81
|
+
tools: z.array(z.string()).nullish(),
|
|
82
|
+
});
|
|
83
|
+
export async function loadAIGNEFile(path, { readFile: _readFile = readFile } = {}) {
|
|
84
|
+
const raw = await tryOrThrow(() => _readFile(path, "utf8"), (error) => new Error(`Failed to load aigne.yaml from ${path}: ${error.message}`));
|
|
85
|
+
const json = await tryOrThrow(() => parse(raw), (error) => new Error(`Failed to parse aigne.yaml from ${path}: ${error.message}`));
|
|
86
|
+
const agent = tryOrThrow(() => aigneFileSchema.parse(json), (error) => new Error(`Failed to validate aigne.yaml from ${path}: ${error.message}`));
|
|
87
|
+
return agent;
|
|
88
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const inputOutputSchema: z.ZodObject<{
|
|
3
|
+
type: z.ZodLiteral<"object">;
|
|
4
|
+
properties: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
5
|
+
required: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
6
|
+
additionalProperties: z.ZodOptional<z.ZodBoolean>;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
type: "object";
|
|
9
|
+
properties: Record<string, any>;
|
|
10
|
+
required?: string[] | undefined;
|
|
11
|
+
additionalProperties?: boolean | undefined;
|
|
12
|
+
}, {
|
|
13
|
+
type: "object";
|
|
14
|
+
properties: Record<string, any>;
|
|
15
|
+
required?: string[] | undefined;
|
|
16
|
+
additionalProperties?: boolean | undefined;
|
|
17
|
+
}>;
|
|
@@ -57,7 +57,7 @@ export declare const claudeChatModelOptionsSchema: z.ZodObject<{
|
|
|
57
57
|
export declare class ClaudeChatModel extends ChatModel {
|
|
58
58
|
options?: ClaudeChatModelOptions | undefined;
|
|
59
59
|
constructor(options?: ClaudeChatModelOptions | undefined);
|
|
60
|
-
|
|
60
|
+
protected _client?: Anthropic;
|
|
61
61
|
get client(): Anthropic;
|
|
62
62
|
get modelOptions(): ChatModelOptions | undefined;
|
|
63
63
|
process(input: ChatModelInput): Promise<ChatModelOutput>;
|
|
@@ -30,9 +30,10 @@ export class ClaudeChatModel extends ChatModel {
|
|
|
30
30
|
}
|
|
31
31
|
_client;
|
|
32
32
|
get client() {
|
|
33
|
-
|
|
33
|
+
const apiKey = this.options?.apiKey || process.env.CLAUDE_API_KEY;
|
|
34
|
+
if (!apiKey)
|
|
34
35
|
throw new Error("Api Key is required for ClaudeChatModel");
|
|
35
|
-
this._client ??= new Anthropic({ apiKey
|
|
36
|
+
this._client ??= new Anthropic({ apiKey });
|
|
36
37
|
return this._client;
|
|
37
38
|
}
|
|
38
39
|
get modelOptions() {
|
|
@@ -61,7 +61,7 @@ export declare const openAIChatModelOptionsSchema: z.ZodObject<{
|
|
|
61
61
|
export declare class OpenAIChatModel extends ChatModel {
|
|
62
62
|
options?: OpenAIChatModelOptions | undefined;
|
|
63
63
|
constructor(options?: OpenAIChatModelOptions | undefined);
|
|
64
|
-
|
|
64
|
+
protected _client?: OpenAI;
|
|
65
65
|
get client(): OpenAI;
|
|
66
66
|
get modelOptions(): ChatModelOptions | undefined;
|
|
67
67
|
process(input: ChatModelInput): Promise<ChatModelOutput>;
|
|
@@ -30,11 +30,12 @@ export class OpenAIChatModel extends ChatModel {
|
|
|
30
30
|
}
|
|
31
31
|
_client;
|
|
32
32
|
get client() {
|
|
33
|
-
|
|
33
|
+
const apiKey = this.options?.apiKey || process.env.OPENAI_API_KEY;
|
|
34
|
+
if (!apiKey)
|
|
34
35
|
throw new Error("Api Key is required for OpenAIChatModel");
|
|
35
36
|
this._client ??= new OpenAI({
|
|
36
|
-
baseURL: this.options
|
|
37
|
-
apiKey
|
|
37
|
+
baseURL: this.options?.baseURL,
|
|
38
|
+
apiKey,
|
|
38
39
|
});
|
|
39
40
|
return this._client;
|
|
40
41
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
1
2
|
import type { ChatModelOptions } from "./chat-model.js";
|
|
2
3
|
import { OpenAIChatModel } from "./openai-chat-model.js";
|
|
3
4
|
export interface XAIChatModelOptions {
|
|
@@ -8,4 +9,5 @@ export interface XAIChatModelOptions {
|
|
|
8
9
|
}
|
|
9
10
|
export declare class XAIChatModel extends OpenAIChatModel {
|
|
10
11
|
constructor(options?: XAIChatModelOptions);
|
|
12
|
+
get client(): OpenAI;
|
|
11
13
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
1
2
|
import { OpenAIChatModel } from "./openai-chat-model.js";
|
|
2
3
|
const XAI_DEFAULT_CHAT_MODEL = "grok-2-latest";
|
|
3
4
|
const XAI_BASE_URL = "https://api.x.ai/v1";
|
|
@@ -9,4 +10,14 @@ export class XAIChatModel extends OpenAIChatModel {
|
|
|
9
10
|
baseURL: options?.baseURL || XAI_BASE_URL,
|
|
10
11
|
});
|
|
11
12
|
}
|
|
13
|
+
get client() {
|
|
14
|
+
const apiKey = this.options?.apiKey || process.env.XAI_API_KEY;
|
|
15
|
+
if (!apiKey)
|
|
16
|
+
throw new Error("Api Key is required for XAIChatModel");
|
|
17
|
+
this._client ??= new OpenAI({
|
|
18
|
+
baseURL: this.options?.baseURL,
|
|
19
|
+
apiKey,
|
|
20
|
+
});
|
|
21
|
+
return this._client;
|
|
22
|
+
}
|
|
12
23
|
}
|
|
@@ -7,7 +7,7 @@ function setAdditionPropertiesDeep(schema, additionalProperties) {
|
|
|
7
7
|
if (Array.isArray(schema)) {
|
|
8
8
|
return schema.map((s) => setAdditionPropertiesDeep(s, additionalProperties));
|
|
9
9
|
}
|
|
10
|
-
if (schema && typeof schema === "object" && !Array.isArray(schema)) {
|
|
10
|
+
if (schema !== null && typeof schema === "object" && !Array.isArray(schema)) {
|
|
11
11
|
return Object.entries(schema).reduce((acc, [key, value]) => {
|
|
12
12
|
acc[key] = setAdditionPropertiesDeep(value, additionalProperties);
|
|
13
13
|
if (acc.type === "object") {
|
|
@@ -11,16 +11,10 @@ export declare const logger: debug.Debug & {
|
|
|
11
11
|
debug: debug.Debug;
|
|
12
12
|
default: debug.Debug;
|
|
13
13
|
} & {
|
|
14
|
-
globalSpinner:
|
|
15
|
-
start: (text?: string | undefined) => Promise<Ora>;
|
|
16
|
-
stop: () => Promise<Ora>;
|
|
17
|
-
fail: (text?: string | undefined) => Promise<Ora>;
|
|
18
|
-
succeed: (text?: string | undefined) => Promise<Ora>;
|
|
19
|
-
} & {
|
|
20
|
-
isSpinning: boolean;
|
|
21
|
-
};
|
|
14
|
+
globalSpinner: Ora | undefined;
|
|
22
15
|
base: DebugWithSpinner;
|
|
23
16
|
debug: DebugWithSpinner;
|
|
24
17
|
spinner: typeof spinner;
|
|
18
|
+
setSpinner: (spinner: Ora) => void;
|
|
25
19
|
};
|
|
26
20
|
export {};
|