@aigne/core 1.1.0-beta.4 → 1.1.0-beta.6

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 (44) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/lib/cjs/agents/agent.js +3 -4
  3. package/lib/cjs/agents/ai-agent.d.ts +4 -0
  4. package/lib/cjs/agents/ai-agent.js +26 -11
  5. package/lib/cjs/agents/mcp-agent.d.ts +18 -6
  6. package/lib/cjs/agents/mcp-agent.js +31 -23
  7. package/lib/cjs/index.d.ts +1 -0
  8. package/lib/cjs/index.js +1 -0
  9. package/lib/cjs/prompt/prompt-builder.d.ts +11 -3
  10. package/lib/cjs/prompt/prompt-builder.js +56 -15
  11. package/lib/cjs/utils/logger.d.ts +6 -2
  12. package/lib/cjs/utils/logger.js +39 -23
  13. package/lib/cjs/utils/mcp-utils.d.ts +5 -0
  14. package/lib/cjs/utils/mcp-utils.js +41 -0
  15. package/lib/cjs/utils/run-chat-loop.d.ts +4 -2
  16. package/lib/cjs/utils/run-chat-loop.js +24 -14
  17. package/lib/cjs/utils/type-utils.d.ts +3 -0
  18. package/lib/cjs/utils/type-utils.js +6 -0
  19. package/lib/dts/agents/ai-agent.d.ts +4 -0
  20. package/lib/dts/agents/mcp-agent.d.ts +18 -6
  21. package/lib/dts/index.d.ts +1 -0
  22. package/lib/dts/prompt/prompt-builder.d.ts +11 -3
  23. package/lib/dts/utils/logger.d.ts +6 -2
  24. package/lib/dts/utils/mcp-utils.d.ts +5 -0
  25. package/lib/dts/utils/run-chat-loop.d.ts +4 -2
  26. package/lib/dts/utils/type-utils.d.ts +3 -0
  27. package/lib/esm/agents/agent.js +3 -4
  28. package/lib/esm/agents/ai-agent.d.ts +4 -0
  29. package/lib/esm/agents/ai-agent.js +26 -11
  30. package/lib/esm/agents/mcp-agent.d.ts +18 -6
  31. package/lib/esm/agents/mcp-agent.js +28 -22
  32. package/lib/esm/index.d.ts +1 -0
  33. package/lib/esm/index.js +1 -0
  34. package/lib/esm/prompt/prompt-builder.d.ts +11 -3
  35. package/lib/esm/prompt/prompt-builder.js +57 -16
  36. package/lib/esm/utils/logger.d.ts +6 -2
  37. package/lib/esm/utils/logger.js +39 -23
  38. package/lib/esm/utils/mcp-utils.d.ts +5 -0
  39. package/lib/esm/utils/mcp-utils.js +37 -0
  40. package/lib/esm/utils/run-chat-loop.d.ts +4 -2
  41. package/lib/esm/utils/run-chat-loop.js +24 -14
  42. package/lib/esm/utils/type-utils.d.ts +3 -0
  43. package/lib/esm/utils/type-utils.js +5 -0
  44. package/package.json +1 -1
@@ -6,15 +6,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runChatLoopInTerminal = runChatLoopInTerminal;
7
7
  const inquirer_1 = __importDefault(require("inquirer"));
8
8
  const logger_1 = require("./logger");
9
- async function runChatLoopInTerminal(userAgent, options) {
9
+ async function runChatLoopInTerminal(userAgent, { log = console.log.bind(console), ...options } = {}) {
10
10
  if (options?.welcome)
11
- console.log(options.welcome);
11
+ log(options.welcome);
12
+ if (options?.initialCall) {
13
+ await callAgent(userAgent, options.initialCall, { ...options, log });
14
+ }
12
15
  for (let i = 0;; i++) {
13
16
  const { question } = await inquirer_1.default.prompt([
14
17
  {
15
18
  type: "input",
16
19
  name: "question",
17
- message: ">",
20
+ message: "💬",
18
21
  default: i === 0 ? options?.defaultQuestion : undefined,
19
22
  },
20
23
  ]);
@@ -22,23 +25,30 @@ async function runChatLoopInTerminal(userAgent, options) {
22
25
  continue;
23
26
  const cmd = COMMANDS[question.trim()];
24
27
  if (cmd) {
25
- await cmd();
28
+ const result = cmd();
29
+ if (result.message)
30
+ log(result.message);
31
+ if (result?.exit)
32
+ break;
26
33
  continue;
27
34
  }
28
- const response = await logger_1.logger.spinner(userAgent.call(question));
29
- if (options?.onResponse)
30
- options.onResponse(response);
31
- else
32
- console.log(response);
35
+ await callAgent(userAgent, question, { ...options, log });
33
36
  }
34
37
  }
38
+ async function callAgent(agent, input, options) {
39
+ const response = await logger_1.logger.spinner(agent.call(input), "🤖");
40
+ if (options?.onResponse)
41
+ options.onResponse(response);
42
+ else
43
+ options.log(response);
44
+ }
35
45
  const COMMANDS = {
36
- "/exit": () => process.exit(0),
37
- "/help": () => {
38
- console.log(`\
46
+ "/exit": () => ({ exit: true }),
47
+ "/help": () => ({
48
+ message: `\
39
49
  Commands:
40
50
  /exit - exit the chat loop
41
51
  /help - show this help message
42
- `);
43
- },
52
+ `,
53
+ }),
44
54
  };
@@ -3,3 +3,6 @@ export declare function orArrayToArray<T>(value?: T | T[]): T[];
3
3
  export declare function get(obj: unknown, path: string | string[], type?: undefined): unknown | undefined;
4
4
  export declare function get(obj: unknown, path: string | string[], type: "string"): string | undefined;
5
5
  export declare function get(obj: unknown, path: string | string[], type: "number"): number | undefined;
6
+ export declare function createAccessorArray<T>(array: T[], accessor: (array: T[], name: string) => T | undefined): T[] & {
7
+ [key: string]: T;
8
+ };
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.isNonNullable = isNonNullable;
7
7
  exports.orArrayToArray = orArrayToArray;
8
8
  exports.get = get;
9
+ exports.createAccessorArray = createAccessorArray;
9
10
  const lodash_1 = require("lodash");
10
11
  const isNil_1 = __importDefault(require("lodash/isNil"));
11
12
  function isNonNullable(value) {
@@ -23,3 +24,8 @@ function get(obj, path, type) {
23
24
  if (type === "number" && typeof v === "number")
24
25
  return v;
25
26
  }
27
+ function createAccessorArray(array, accessor) {
28
+ return new Proxy(array, {
29
+ get: (t, p, r) => Reflect.get(t, p, r) ?? accessor(array, p),
30
+ });
31
+ }
@@ -7,6 +7,8 @@ export interface AIAgentOptions<I extends AgentInput = AgentInput, O extends Age
7
7
  instructions?: string | PromptBuilder;
8
8
  outputKey?: string;
9
9
  toolChoice?: AIAgentToolChoice;
10
+ enableHistory?: boolean;
11
+ maxHistoryMessages?: number;
10
12
  }
11
13
  export type AIAgentToolChoice = "auto" | "none" | "required" | "router" | Agent;
12
14
  export declare class AIAgent<I extends AgentInput = AgentInput, O extends AgentOutput = AgentOutput> extends Agent<I, O> {
@@ -16,5 +18,7 @@ export declare class AIAgent<I extends AgentInput = AgentInput, O extends AgentO
16
18
  instructions: PromptBuilder;
17
19
  outputKey?: string;
18
20
  toolChoice?: AIAgentToolChoice;
21
+ enableHistory?: boolean;
22
+ maxHistoryMessages: number;
19
23
  process(input: I, context?: Context): Promise<O>;
20
24
  }
@@ -1,8 +1,10 @@
1
1
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
2
  import { type StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js";
3
+ import type { CallToolResult, GetPromptResult } from "@modelcontextprotocol/sdk/types";
3
4
  import { Agent, type AgentInput, type AgentOptions, type AgentOutput } from "./agent";
4
5
  export interface MCPAgentOptions extends AgentOptions {
5
6
  client: Client;
7
+ prompts?: MCPPrompt[];
6
8
  }
7
9
  export type MCPServerOptions = SSEServerParameters | StdioServerParameters;
8
10
  export type SSEServerParameters = {
@@ -14,14 +16,24 @@ export declare class MCPAgent extends Agent {
14
16
  private static fromTransport;
15
17
  constructor(options: MCPAgentOptions);
16
18
  private client;
19
+ readonly prompts: MCPPrompt[] & {
20
+ [key: string]: MCPPrompt;
21
+ };
17
22
  shutdown(): Promise<void>;
18
23
  }
19
- export interface MCPToolOptions extends AgentOptions {
24
+ export interface MCPToolBaseOptions<I extends AgentInput, O extends AgentOutput> extends AgentOptions<I, O> {
20
25
  client: Client;
21
26
  }
22
- export declare class MCPTool extends Agent {
23
- constructor(options: MCPToolOptions);
24
- private client;
25
- private get mcpServer();
26
- process(input: AgentInput): Promise<AgentOutput>;
27
+ export declare abstract class MCPBase<I extends AgentInput, O extends AgentOutput> extends Agent<I, O> {
28
+ constructor(options: MCPToolBaseOptions<I, O>);
29
+ protected client: Client;
30
+ protected get mcpServer(): string | undefined;
31
+ }
32
+ export declare class MCPTool extends MCPBase<AgentInput, CallToolResult> {
33
+ process(input: AgentInput): Promise<CallToolResult>;
34
+ }
35
+ export declare class MCPPrompt extends MCPBase<{
36
+ [key: string]: string;
37
+ }, GetPromptResult> {
38
+ process(input: AgentInput): Promise<GetPromptResult>;
27
39
  }
@@ -8,4 +8,5 @@ export * from "./models/chat";
8
8
  export * from "./models/chat-openai";
9
9
  export * from "./prompt/prompt-builder";
10
10
  export * from "./prompt/template";
11
+ export * from "./utils/logger";
11
12
  export * from "./utils/run-chat-loop";
@@ -1,14 +1,18 @@
1
+ import type { GetPromptResult } from "@modelcontextprotocol/sdk/types";
1
2
  import { Agent, type AgentInput } from "../agents/agent";
2
3
  import type { AIAgent } from "../agents/ai-agent";
3
4
  import type { Context } from "../execution-engine/context";
4
5
  import type { ChatModel, ChatModelInput, ChatModelInputMessage } from "../models/chat";
6
+ import { ChatMessagesTemplate } from "./template";
5
7
  export declare const USER_INPUT_MESSAGE_KEY = "$user_input_message";
6
8
  export declare function userInput(message: string | object): AgentInput;
7
9
  export declare function addMessagesToInput(input: AgentInput, messages: ChatModelInputMessage[]): AgentInput;
8
10
  export interface PromptBuilderOptions {
9
- instructions?: string;
11
+ instructions?: string | ChatMessagesTemplate;
10
12
  }
11
13
  export interface PromptBuilderBuildOptions {
14
+ enableHistory?: boolean;
15
+ maxHistoryMessages?: number;
12
16
  context?: Context;
13
17
  agent?: AIAgent;
14
18
  input?: AgentInput;
@@ -16,15 +20,19 @@ export interface PromptBuilderBuildOptions {
16
20
  }
17
21
  export declare class PromptBuilder {
18
22
  static from(instructions: string): PromptBuilder;
23
+ static from(instructions: GetPromptResult): PromptBuilder;
19
24
  static from(instructions: {
20
25
  path: string;
21
26
  }): Promise<PromptBuilder>;
22
27
  static from(instructions: string | {
23
28
  path: string;
24
- }): PromptBuilder | Promise<PromptBuilder>;
29
+ } | GetPromptResult): PromptBuilder | Promise<PromptBuilder>;
25
30
  private static fromFile;
31
+ private static fromMCPPromptResult;
26
32
  constructor(options?: PromptBuilderOptions);
27
- instructions?: string;
33
+ instructions?: string | ChatMessagesTemplate;
34
+ histories: ChatModelInputMessage[];
35
+ addHistory(...messages: ChatModelInputMessage[]): void;
28
36
  build(options: PromptBuilderBuildOptions): Promise<ChatModelInput & {
29
37
  toolAgents?: Agent[];
30
38
  }>;
@@ -1,4 +1,4 @@
1
- import { type Debugger } from "debug";
1
+ import debug, { type Debugger } from "debug";
2
2
  interface DebugWithSpinner extends Debugger {
3
3
  spinner<T>(promise: Promise<T>, message?: string, callback?: (result: T) => void, options?: {
4
4
  disabled?: boolean;
@@ -6,7 +6,11 @@ interface DebugWithSpinner extends Debugger {
6
6
  extend: (namespace: string) => DebugWithSpinner;
7
7
  }
8
8
  declare function spinner<T>(promise: Promise<T>, message?: string, callback?: (result: T) => void): Promise<T>;
9
- export declare const logger: {
9
+ export declare const logger: debug.Debug & {
10
+ debug: debug.Debug;
11
+ default: debug.Debug;
12
+ } & {
13
+ globalSpinner: import("ora").Ora;
10
14
  base: DebugWithSpinner;
11
15
  debug: DebugWithSpinner;
12
16
  spinner: typeof spinner;
@@ -0,0 +1,5 @@
1
+ import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import type { ListPromptsResult, ListToolsResult } from "@modelcontextprotocol/sdk/types";
3
+ import { MCPPrompt, MCPTool } from "../agents/mcp-agent";
4
+ export declare function toolFromMCPTool(client: Client, tool: ListToolsResult["tools"][number]): MCPTool;
5
+ export declare function promptFromMCPPrompt(client: Client, prompt: ListPromptsResult["prompts"][number]): MCPPrompt;
@@ -1,8 +1,10 @@
1
- import type { AgentOutput } from "../agents/agent";
1
+ import type { AgentInput, AgentOutput } from "../agents/agent";
2
2
  import type { UserAgent } from "../execution-engine";
3
3
  export interface ChatLoopOptions {
4
+ log?: typeof console.log;
5
+ initialCall?: AgentInput | string;
4
6
  welcome?: string;
5
7
  defaultQuestion?: string;
6
8
  onResponse?: (response: AgentOutput) => void;
7
9
  }
8
- export declare function runChatLoopInTerminal(userAgent: UserAgent, options?: ChatLoopOptions): Promise<void>;
10
+ export declare function runChatLoopInTerminal(userAgent: UserAgent, { log, ...options }?: ChatLoopOptions): Promise<void>;
@@ -3,3 +3,6 @@ export declare function orArrayToArray<T>(value?: T | T[]): T[];
3
3
  export declare function get(obj: unknown, path: string | string[], type?: undefined): unknown | undefined;
4
4
  export declare function get(obj: unknown, path: string | string[], type: "string"): string | undefined;
5
5
  export declare function get(obj: unknown, path: string | string[], type: "number"): number | undefined;
6
+ export declare function createAccessorArray<T>(array: T[], accessor: (array: T[], name: string) => T | undefined): T[] & {
7
+ [key: string]: T;
8
+ };
@@ -2,6 +2,7 @@ import EventEmitter from "node:events";
2
2
  import { z } from "zod";
3
3
  import { userInput } from "../prompt/prompt-builder";
4
4
  import { logger } from "../utils/logger";
5
+ import { createAccessorArray } from "../utils/type-utils";
5
6
  import { transferToAgentOutput } from "./types";
6
7
  export class Agent extends EventEmitter {
7
8
  static from(options) {
@@ -29,9 +30,7 @@ export class Agent extends EventEmitter {
29
30
  includeInputInOutput;
30
31
  subscribeTopic;
31
32
  publishTopic;
32
- tools = new Proxy([], {
33
- get: (t, p, r) => Reflect.get(t, p, r) ?? t.find((t) => t.name === p),
34
- });
33
+ tools = createAccessorArray([], (arr, name) => arr.find((t) => t.name === name));
35
34
  disableLogging;
36
35
  addTool(tool) {
37
36
  this.tools.push(typeof tool === "function" ? functionToAgent(tool) : tool);
@@ -48,7 +47,7 @@ export class Agent extends EventEmitter {
48
47
  const parsedOutput = this.outputSchema.passthrough().parse(output);
49
48
  return this.includeInputInOutput ? { ...parsedInput, ...parsedOutput } : parsedOutput;
50
49
  });
51
- return logger.debug.spinner(result, `Call agent ${this.name}`, (output) => logger.debug("%O", { input, output }), { disabled: this.disableLogging });
50
+ return logger.debug.spinner(result, `Call agent ${this.name}`, (output) => logger.debug("input: %O\noutput: %O", input, output), { disabled: this.disableLogging });
52
51
  }
53
52
  async shutdown() { }
54
53
  }
@@ -7,6 +7,8 @@ export interface AIAgentOptions<I extends AgentInput = AgentInput, O extends Age
7
7
  instructions?: string | PromptBuilder;
8
8
  outputKey?: string;
9
9
  toolChoice?: AIAgentToolChoice;
10
+ enableHistory?: boolean;
11
+ maxHistoryMessages?: number;
10
12
  }
11
13
  export type AIAgentToolChoice = "auto" | "none" | "required" | "router" | Agent;
12
14
  export declare class AIAgent<I extends AgentInput = AgentInput, O extends AgentOutput = AgentOutput> extends Agent<I, O> {
@@ -16,5 +18,7 @@ export declare class AIAgent<I extends AgentInput = AgentInput, O extends AgentO
16
18
  instructions: PromptBuilder;
17
19
  outputKey?: string;
18
20
  toolChoice?: AIAgentToolChoice;
21
+ enableHistory?: boolean;
22
+ maxHistoryMessages: number;
19
23
  process(input: I, context?: Context): Promise<O>;
20
24
  }
@@ -3,6 +3,7 @@ import { AgentMessageTemplate, ToolMessageTemplate } from "../prompt/template";
3
3
  import { Agent } from "./agent";
4
4
  import { isTransferAgentOutput, transferAgentOutputKey } from "./types";
5
5
  const DEFAULT_OUTPUT_KEY = "text";
6
+ const DEFAULT_MAX_HISTORY_MESSAGES = 10;
6
7
  export class AIAgent extends Agent {
7
8
  static from(options) {
8
9
  return new AIAgent(options);
@@ -16,27 +17,35 @@ export class AIAgent extends Agent {
16
17
  : (options.instructions ?? new PromptBuilder());
17
18
  this.outputKey = options.outputKey;
18
19
  this.toolChoice = options.toolChoice;
20
+ this.enableHistory = options.enableHistory;
21
+ this.maxHistoryMessages = options.maxHistoryMessages ?? DEFAULT_MAX_HISTORY_MESSAGES;
19
22
  }
20
23
  model;
21
24
  instructions;
22
25
  outputKey;
23
26
  toolChoice;
27
+ enableHistory;
28
+ maxHistoryMessages;
24
29
  async process(input, context) {
25
30
  const model = context?.model ?? this.model;
26
31
  if (!model)
27
32
  throw new Error("model is required to run AIAgent");
28
33
  let transferOutput;
29
- const { toolAgents, ...modelInput } = await this.instructions.build({
34
+ const { toolAgents, messages, ...modelInput } = await this.instructions.build({
35
+ enableHistory: this.enableHistory,
36
+ maxHistoryMessages: this.maxHistoryMessages,
30
37
  agent: this,
31
38
  input,
32
39
  model,
33
40
  context,
34
41
  });
35
42
  const toolsMap = new Map(toolAgents?.map((i) => [i.name, i]));
43
+ const toolCallMessages = [];
36
44
  for (;;) {
37
- const { text, json, toolCalls } = await model.call(modelInput, context);
45
+ const { text, json, toolCalls } = await model.call({ ...modelInput, messages: messages.concat(toolCallMessages) }, context);
38
46
  if (toolCalls?.length) {
39
47
  const executedToolCalls = [];
48
+ // Execute tools
40
49
  for (const call of toolCalls) {
41
50
  const tool = toolsMap.get(call.function.name);
42
51
  if (!tool)
@@ -50,21 +59,27 @@ export class AIAgent extends Agent {
50
59
  executedToolCalls.push({ call, output });
51
60
  }
52
61
  }
53
- if (this.toolChoice === "router") {
54
- const output = executedToolCalls[0]?.output;
55
- if (!output || executedToolCalls.length !== 1) {
56
- throw new Error("Router toolChoice requires exactly one tool to be executed");
57
- }
58
- return output;
59
- }
60
62
  // Continue LLM function calling loop if any tools were executed
61
63
  if (executedToolCalls.length) {
62
- modelInput.messages.push(AgentMessageTemplate.from(executedToolCalls.map(({ call }) => call)).format());
63
- modelInput.messages.push(...executedToolCalls.map(({ call, output }) => ToolMessageTemplate.from(output, call.id).format()));
64
+ toolCallMessages.push(AgentMessageTemplate.from(executedToolCalls.map(({ call }) => call)).format(), ...executedToolCalls.map(({ call, output }) => ToolMessageTemplate.from(output, call.id).format()));
65
+ // Return the output of the first tool if the toolChoice is "router"
66
+ if (this.toolChoice === "router") {
67
+ const output = executedToolCalls[0]?.output;
68
+ if (!output || executedToolCalls.length !== 1) {
69
+ throw new Error("Router toolChoice requires exactly one tool to be executed");
70
+ }
71
+ return output;
72
+ }
64
73
  continue;
65
74
  }
66
75
  }
67
76
  const result = {};
77
+ if (json) {
78
+ this.instructions.addHistory(AgentMessageTemplate.from(JSON.stringify(json)).format());
79
+ }
80
+ else if (text) {
81
+ this.instructions.addHistory(AgentMessageTemplate.from(text).format());
82
+ }
68
83
  if (modelInput.responseFormat?.type === "json_schema") {
69
84
  Object.assign(result, json);
70
85
  }
@@ -1,8 +1,10 @@
1
1
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
2
  import { type StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js";
3
+ import type { CallToolResult, GetPromptResult } from "@modelcontextprotocol/sdk/types";
3
4
  import { Agent, type AgentInput, type AgentOptions, type AgentOutput } from "./agent";
4
5
  export interface MCPAgentOptions extends AgentOptions {
5
6
  client: Client;
7
+ prompts?: MCPPrompt[];
6
8
  }
7
9
  export type MCPServerOptions = SSEServerParameters | StdioServerParameters;
8
10
  export type SSEServerParameters = {
@@ -14,14 +16,24 @@ export declare class MCPAgent extends Agent {
14
16
  private static fromTransport;
15
17
  constructor(options: MCPAgentOptions);
16
18
  private client;
19
+ readonly prompts: MCPPrompt[] & {
20
+ [key: string]: MCPPrompt;
21
+ };
17
22
  shutdown(): Promise<void>;
18
23
  }
19
- export interface MCPToolOptions extends AgentOptions {
24
+ export interface MCPToolBaseOptions<I extends AgentInput, O extends AgentOutput> extends AgentOptions<I, O> {
20
25
  client: Client;
21
26
  }
22
- export declare class MCPTool extends Agent {
23
- constructor(options: MCPToolOptions);
24
- private client;
25
- private get mcpServer();
26
- process(input: AgentInput): Promise<AgentOutput>;
27
+ export declare abstract class MCPBase<I extends AgentInput, O extends AgentOutput> extends Agent<I, O> {
28
+ constructor(options: MCPToolBaseOptions<I, O>);
29
+ protected client: Client;
30
+ protected get mcpServer(): string | undefined;
31
+ }
32
+ export declare class MCPTool extends MCPBase<AgentInput, CallToolResult> {
33
+ process(input: AgentInput): Promise<CallToolResult>;
34
+ }
35
+ export declare class MCPPrompt extends MCPBase<{
36
+ [key: string]: string;
37
+ }, GetPromptResult> {
38
+ process(input: AgentInput): Promise<GetPromptResult>;
27
39
  }
@@ -1,9 +1,9 @@
1
1
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
2
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
3
3
  import { StdioClientTransport, } from "@modelcontextprotocol/sdk/client/stdio.js";
4
- import { jsonSchemaToZod } from "@n8n/json-schema-to-zod";
5
- import { z } from "zod";
6
4
  import { logger } from "../utils/logger";
5
+ import { promptFromMCPPrompt, toolFromMCPTool } from "../utils/mcp-utils";
6
+ import { createAccessorArray } from "../utils/type-utils";
7
7
  import { Agent } from "./agent";
8
8
  const MCP_AGENT_CLIENT_NAME = "MCPAgent";
9
9
  const MCP_AGENT_CLIENT_VERSION = "0.0.1";
@@ -21,7 +21,7 @@ export class MCPAgent extends Agent {
21
21
  return MCPAgent.fromTransport(transport);
22
22
  }
23
23
  if (isStdioServerParameters(options)) {
24
- const transport = new StdioClientTransport(options);
24
+ const transport = new StdioClientTransport({ ...options, stderr: "pipe" });
25
25
  return MCPAgent.fromTransport(transport);
26
26
  }
27
27
  return new MCPAgent(options);
@@ -33,35 +33,33 @@ export class MCPAgent extends Agent {
33
33
  });
34
34
  await debug.spinner(client.connect(transport), "Connecting to MCP server");
35
35
  const mcpServer = getMCPServerName(client);
36
- const { tools: mcpTools } = await debug.spinner(client.listTools(), `Listing tools from ${mcpServer}`, ({ tools }) => debug("%O", tools));
37
- const tools = mcpTools.map((tool) => {
38
- return new MCPTool({
39
- client,
40
- name: tool.name,
41
- description: tool.description,
42
- inputSchema: jsonSchemaToZod(tool.inputSchema),
43
- outputSchema: z
44
- .object({
45
- _meta: z.record(z.unknown()).optional(),
46
- content: z.array(z.record(z.unknown())),
47
- isError: z.boolean().optional(),
48
- })
49
- .passthrough(),
50
- });
51
- });
52
- return new MCPAgent({ client, tools });
36
+ const { tools: isToolsAvailable, prompts: isPromptsAvailable } = client.getServerCapabilities() ?? {};
37
+ const tools = isToolsAvailable
38
+ ? await debug
39
+ .spinner(client.listTools(), `Listing tools from ${mcpServer}`, ({ tools }) => debug("%O", tools))
40
+ .then(({ tools }) => tools.map((tool) => toolFromMCPTool(client, tool)))
41
+ : undefined;
42
+ const prompts = isPromptsAvailable
43
+ ? await debug
44
+ .spinner(client.listPrompts(), `Listing prompts from ${mcpServer}`, ({ prompts }) => debug("%O", prompts))
45
+ .then(({ prompts }) => prompts.map((prompt) => promptFromMCPPrompt(client, prompt)))
46
+ : undefined;
47
+ return new MCPAgent({ client, tools, prompts });
53
48
  }
54
49
  constructor(options) {
55
50
  super(options);
56
51
  this.client = options.client;
52
+ if (options.prompts?.length)
53
+ this.prompts.push(...options.prompts);
57
54
  }
58
55
  client;
56
+ prompts = createAccessorArray([], (arr, name) => arr.find((i) => i.name === name));
59
57
  async shutdown() {
60
58
  super.shutdown();
61
59
  await this.client.close();
62
60
  }
63
61
  }
64
- export class MCPTool extends Agent {
62
+ export class MCPBase extends Agent {
65
63
  constructor(options) {
66
64
  super(options);
67
65
  this.client = options.client;
@@ -70,8 +68,16 @@ export class MCPTool extends Agent {
70
68
  get mcpServer() {
71
69
  return getMCPServerName(this.client);
72
70
  }
71
+ }
72
+ export class MCPTool extends MCPBase {
73
+ async process(input) {
74
+ const result = await debug.spinner(this.client.callTool({ name: this.name, arguments: input }), `Call tool ${this.name} from ${this.mcpServer}`, (output) => debug("input: %O\noutput: %O", input, output));
75
+ return result;
76
+ }
77
+ }
78
+ export class MCPPrompt extends MCPBase {
73
79
  async process(input) {
74
- const result = await debug.spinner(this.client.callTool({ name: this.name, arguments: input }), `Call tool ${this.name} from ${this.mcpServer}`, (output) => debug("%O", { input, output }));
80
+ const result = await debug.spinner(this.client.getPrompt({ name: this.name, arguments: input }), `Get prompt ${this.name} from ${this.mcpServer}`, (output) => debug("input: %O\noutput: %O", input, output));
75
81
  return result;
76
82
  }
77
83
  }
@@ -8,4 +8,5 @@ export * from "./models/chat";
8
8
  export * from "./models/chat-openai";
9
9
  export * from "./prompt/prompt-builder";
10
10
  export * from "./prompt/template";
11
+ export * from "./utils/logger";
11
12
  export * from "./utils/run-chat-loop";
package/lib/esm/index.js CHANGED
@@ -8,4 +8,5 @@ export * from "./models/chat";
8
8
  export * from "./models/chat-openai";
9
9
  export * from "./prompt/prompt-builder";
10
10
  export * from "./prompt/template";
11
+ export * from "./utils/logger";
11
12
  export * from "./utils/run-chat-loop";
@@ -1,14 +1,18 @@
1
+ import type { GetPromptResult } from "@modelcontextprotocol/sdk/types";
1
2
  import { Agent, type AgentInput } from "../agents/agent";
2
3
  import type { AIAgent } from "../agents/ai-agent";
3
4
  import type { Context } from "../execution-engine/context";
4
5
  import type { ChatModel, ChatModelInput, ChatModelInputMessage } from "../models/chat";
6
+ import { ChatMessagesTemplate } from "./template";
5
7
  export declare const USER_INPUT_MESSAGE_KEY = "$user_input_message";
6
8
  export declare function userInput(message: string | object): AgentInput;
7
9
  export declare function addMessagesToInput(input: AgentInput, messages: ChatModelInputMessage[]): AgentInput;
8
10
  export interface PromptBuilderOptions {
9
- instructions?: string;
11
+ instructions?: string | ChatMessagesTemplate;
10
12
  }
11
13
  export interface PromptBuilderBuildOptions {
14
+ enableHistory?: boolean;
15
+ maxHistoryMessages?: number;
12
16
  context?: Context;
13
17
  agent?: AIAgent;
14
18
  input?: AgentInput;
@@ -16,15 +20,19 @@ export interface PromptBuilderBuildOptions {
16
20
  }
17
21
  export declare class PromptBuilder {
18
22
  static from(instructions: string): PromptBuilder;
23
+ static from(instructions: GetPromptResult): PromptBuilder;
19
24
  static from(instructions: {
20
25
  path: string;
21
26
  }): Promise<PromptBuilder>;
22
27
  static from(instructions: string | {
23
28
  path: string;
24
- }): PromptBuilder | Promise<PromptBuilder>;
29
+ } | GetPromptResult): PromptBuilder | Promise<PromptBuilder>;
25
30
  private static fromFile;
31
+ private static fromMCPPromptResult;
26
32
  constructor(options?: PromptBuilderOptions);
27
- instructions?: string;
33
+ instructions?: string | ChatMessagesTemplate;
34
+ histories: ChatModelInputMessage[];
35
+ addHistory(...messages: ChatModelInputMessage[]): void;
28
36
  build(options: PromptBuilderBuildOptions): Promise<ChatModelInput & {
29
37
  toolAgents?: Agent[];
30
38
  }>;