@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.
- package/CHANGELOG.md +11 -0
- package/lib/cjs/agents/agent.js +3 -4
- package/lib/cjs/agents/ai-agent.d.ts +4 -0
- package/lib/cjs/agents/ai-agent.js +26 -11
- package/lib/cjs/agents/mcp-agent.d.ts +18 -6
- package/lib/cjs/agents/mcp-agent.js +31 -23
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/prompt/prompt-builder.d.ts +11 -3
- package/lib/cjs/prompt/prompt-builder.js +56 -15
- package/lib/cjs/utils/logger.d.ts +6 -2
- package/lib/cjs/utils/logger.js +39 -23
- package/lib/cjs/utils/mcp-utils.d.ts +5 -0
- package/lib/cjs/utils/mcp-utils.js +41 -0
- package/lib/cjs/utils/run-chat-loop.d.ts +4 -2
- package/lib/cjs/utils/run-chat-loop.js +24 -14
- package/lib/cjs/utils/type-utils.d.ts +3 -0
- package/lib/cjs/utils/type-utils.js +6 -0
- package/lib/dts/agents/ai-agent.d.ts +4 -0
- package/lib/dts/agents/mcp-agent.d.ts +18 -6
- package/lib/dts/index.d.ts +1 -0
- package/lib/dts/prompt/prompt-builder.d.ts +11 -3
- package/lib/dts/utils/logger.d.ts +6 -2
- package/lib/dts/utils/mcp-utils.d.ts +5 -0
- package/lib/dts/utils/run-chat-loop.d.ts +4 -2
- package/lib/dts/utils/type-utils.d.ts +3 -0
- package/lib/esm/agents/agent.js +3 -4
- package/lib/esm/agents/ai-agent.d.ts +4 -0
- package/lib/esm/agents/ai-agent.js +26 -11
- package/lib/esm/agents/mcp-agent.d.ts +18 -6
- package/lib/esm/agents/mcp-agent.js +28 -22
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/prompt/prompt-builder.d.ts +11 -3
- package/lib/esm/prompt/prompt-builder.js +57 -16
- package/lib/esm/utils/logger.d.ts +6 -2
- package/lib/esm/utils/logger.js +39 -23
- package/lib/esm/utils/mcp-utils.d.ts +5 -0
- package/lib/esm/utils/mcp-utils.js +37 -0
- package/lib/esm/utils/run-chat-loop.d.ts +4 -2
- package/lib/esm/utils/run-chat-loop.js +24 -14
- package/lib/esm/utils/type-utils.d.ts +3 -0
- package/lib/esm/utils/type-utils.js +5 -0
- 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
|
-
|
|
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
|
-
|
|
28
|
+
const result = cmd();
|
|
29
|
+
if (result.message)
|
|
30
|
+
log(result.message);
|
|
31
|
+
if (result?.exit)
|
|
32
|
+
break;
|
|
26
33
|
continue;
|
|
27
34
|
}
|
|
28
|
-
|
|
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": () =>
|
|
37
|
-
"/help": () => {
|
|
38
|
-
|
|
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
|
|
24
|
+
export interface MCPToolBaseOptions<I extends AgentInput, O extends AgentOutput> extends AgentOptions<I, O> {
|
|
20
25
|
client: Client;
|
|
21
26
|
}
|
|
22
|
-
export declare class
|
|
23
|
-
constructor(options:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
}
|
package/lib/dts/index.d.ts
CHANGED
|
@@ -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
|
+
};
|
package/lib/esm/agents/agent.js
CHANGED
|
@@ -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 =
|
|
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",
|
|
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
|
-
|
|
63
|
-
|
|
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
|
|
24
|
+
export interface MCPToolBaseOptions<I extends AgentInput, O extends AgentOutput> extends AgentOptions<I, O> {
|
|
20
25
|
client: Client;
|
|
21
26
|
}
|
|
22
|
-
export declare class
|
|
23
|
-
constructor(options:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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:
|
|
37
|
-
const tools =
|
|
38
|
-
|
|
39
|
-
client,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
|
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.
|
|
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
|
}
|
package/lib/esm/index.d.ts
CHANGED
package/lib/esm/index.js
CHANGED
|
@@ -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
|
}>;
|