@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.
Files changed (70) hide show
  1. package/lib/cjs/agents/mcp-agent.d.ts +34 -7
  2. package/lib/cjs/agents/mcp-agent.js +55 -8
  3. package/lib/cjs/agents/user-agent.d.ts +1 -0
  4. package/lib/cjs/agents/user-agent.js +2 -1
  5. package/lib/cjs/execution-engine/execution-engine.d.ts +9 -2
  6. package/lib/cjs/execution-engine/execution-engine.js +14 -3
  7. package/lib/cjs/loader/ai-agent.d.ts +21 -0
  8. package/lib/cjs/loader/ai-agent.js +40 -0
  9. package/lib/cjs/loader/function-agent.d.ts +21 -0
  10. package/lib/cjs/loader/function-agent.js +67 -0
  11. package/lib/cjs/loader/index.d.ts +25 -0
  12. package/lib/cjs/loader/index.js +93 -0
  13. package/lib/cjs/loader/schema.d.ts +17 -0
  14. package/lib/cjs/loader/schema.js +10 -0
  15. package/lib/cjs/models/claude-chat-model.d.ts +1 -1
  16. package/lib/cjs/models/claude-chat-model.js +3 -2
  17. package/lib/cjs/models/openai-chat-model.d.ts +1 -1
  18. package/lib/cjs/models/openai-chat-model.js +4 -3
  19. package/lib/cjs/models/xai-chat-model.d.ts +2 -0
  20. package/lib/cjs/models/xai-chat-model.js +14 -0
  21. package/lib/cjs/utils/json-schema.js +1 -1
  22. package/lib/cjs/utils/logger.d.ts +2 -8
  23. package/lib/cjs/utils/logger.js +14 -55
  24. package/lib/cjs/utils/mcp-utils.d.ts +4 -5
  25. package/lib/cjs/utils/mcp-utils.js +6 -6
  26. package/lib/cjs/utils/run-chat-loop.js +3 -1
  27. package/lib/cjs/utils/type-utils.d.ts +2 -0
  28. package/lib/cjs/utils/type-utils.js +38 -1
  29. package/lib/dts/agents/mcp-agent.d.ts +34 -7
  30. package/lib/dts/agents/user-agent.d.ts +1 -0
  31. package/lib/dts/execution-engine/execution-engine.d.ts +9 -2
  32. package/lib/dts/loader/ai-agent.d.ts +21 -0
  33. package/lib/dts/loader/function-agent.d.ts +21 -0
  34. package/lib/dts/loader/index.d.ts +25 -0
  35. package/lib/dts/loader/schema.d.ts +17 -0
  36. package/lib/dts/models/claude-chat-model.d.ts +1 -1
  37. package/lib/dts/models/openai-chat-model.d.ts +1 -1
  38. package/lib/dts/models/xai-chat-model.d.ts +2 -0
  39. package/lib/dts/utils/logger.d.ts +2 -8
  40. package/lib/dts/utils/mcp-utils.d.ts +4 -5
  41. package/lib/dts/utils/type-utils.d.ts +2 -0
  42. package/lib/esm/agents/mcp-agent.d.ts +34 -7
  43. package/lib/esm/agents/mcp-agent.js +52 -8
  44. package/lib/esm/agents/user-agent.d.ts +1 -0
  45. package/lib/esm/agents/user-agent.js +1 -0
  46. package/lib/esm/execution-engine/execution-engine.d.ts +9 -2
  47. package/lib/esm/execution-engine/execution-engine.js +15 -4
  48. package/lib/esm/loader/ai-agent.d.ts +21 -0
  49. package/lib/esm/loader/ai-agent.js +37 -0
  50. package/lib/esm/loader/function-agent.d.ts +21 -0
  51. package/lib/esm/loader/function-agent.js +31 -0
  52. package/lib/esm/loader/index.d.ts +25 -0
  53. package/lib/esm/loader/index.js +88 -0
  54. package/lib/esm/loader/schema.d.ts +17 -0
  55. package/lib/esm/loader/schema.js +7 -0
  56. package/lib/esm/models/claude-chat-model.d.ts +1 -1
  57. package/lib/esm/models/claude-chat-model.js +3 -2
  58. package/lib/esm/models/openai-chat-model.d.ts +1 -1
  59. package/lib/esm/models/openai-chat-model.js +4 -3
  60. package/lib/esm/models/xai-chat-model.d.ts +2 -0
  61. package/lib/esm/models/xai-chat-model.js +11 -0
  62. package/lib/esm/utils/json-schema.js +1 -1
  63. package/lib/esm/utils/logger.d.ts +2 -8
  64. package/lib/esm/utils/logger.js +14 -23
  65. package/lib/esm/utils/mcp-utils.d.ts +4 -5
  66. package/lib/esm/utils/mcp-utils.js +6 -6
  67. package/lib/esm/utils/run-chat-loop.js +3 -1
  68. package/lib/esm/utils/type-utils.d.ts +2 -0
  69. package/lib/esm/utils/type-utils.js +36 -1
  70. 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 { CallToolResult, GetPromptResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
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 MCPToolBaseOptions<I extends Message, O extends Message> extends AgentOptions<I, O> {
32
- client: Client;
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: MCPToolBaseOptions<I, O>);
36
- protected client: 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 MCPToolBaseOptions<MCPPromptInput, ReadResourceResult> {
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(transport, options) {
49
- const client = new Client({
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(client, tool)))
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(client, prompt)))
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(client, resource)))
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";
@@ -1,3 +1,4 @@
1
+ import { ReadableStream } from "node:stream/web";
1
2
  import { orArrayToArray } from "../utils/type-utils.js";
2
3
  import { Agent } from "./agent.js";
3
4
  export class UserAgent extends Agent {
@@ -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
- private agents;
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
+ }>;
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ export const inputOutputSchema = z.object({
3
+ type: z.literal("object"),
4
+ properties: z.record(z.any()),
5
+ required: z.array(z.string()).optional(),
6
+ additionalProperties: z.boolean().optional(),
7
+ });
@@ -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
- private _client?;
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
- if (!this.options?.apiKey)
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: this.options.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
- private _client?;
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
- if (!this.options?.apiKey)
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.baseURL,
37
- apiKey: this.options.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 {};