@aigne/core 1.1.0-beta.3 → 1.1.0-beta.5
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.d.ts +2 -0
- package/lib/cjs/agents/agent.js +8 -15
- 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 +33 -31
- package/lib/cjs/execution-engine/index.d.ts +1 -0
- package/lib/cjs/execution-engine/index.js +7 -1
- 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 +17 -5
- package/lib/cjs/utils/logger.js +75 -4
- 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 +10 -0
- package/lib/cjs/utils/run-chat-loop.js +54 -0
- package/lib/cjs/utils/type-utils.d.ts +3 -0
- package/lib/cjs/utils/type-utils.js +6 -0
- package/lib/dts/agents/agent.d.ts +2 -0
- package/lib/dts/agents/ai-agent.d.ts +4 -0
- package/lib/dts/agents/mcp-agent.d.ts +18 -6
- package/lib/dts/execution-engine/index.d.ts +1 -0
- 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 +17 -5
- package/lib/dts/utils/mcp-utils.d.ts +5 -0
- package/lib/dts/utils/run-chat-loop.d.ts +10 -0
- package/lib/dts/utils/type-utils.d.ts +3 -0
- package/lib/esm/agents/agent.d.ts +2 -0
- package/lib/esm/agents/agent.js +9 -16
- 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 +30 -30
- package/lib/esm/execution-engine/index.d.ts +1 -0
- package/lib/esm/execution-engine/index.js +7 -1
- 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 +17 -5
- package/lib/esm/utils/logger.js +75 -4
- 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 +10 -0
- package/lib/esm/utils/run-chat-loop.js +48 -0
- package/lib/esm/utils/type-utils.d.ts +3 -0
- package/lib/esm/utils/type-utils.js +5 -0
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## 1.1.0-beta.5 (2025-3-13)
|
|
2
|
+
|
|
3
|
+
- feat: support chat history in PromptBuilder
|
|
4
|
+
- feat: add `prompts` for MCPAgent to consume prompts from MCP server
|
|
5
|
+
- chore: add sqlite-mcp-server example
|
|
6
|
+
- test: add more unit test cases
|
|
7
|
+
|
|
8
|
+
## 1.1.0-beta.4 (2025-3-12)
|
|
9
|
+
|
|
10
|
+
- feat: support run puppeteer example chat loop in terminal
|
|
11
|
+
|
|
1
12
|
## 1.1.0-beta.3 (2025-3-11)
|
|
2
13
|
|
|
3
14
|
- chore: set module type for core package
|
|
@@ -19,6 +19,7 @@ export interface AgentOptions<I extends AgentInput = AgentInput, O extends Agent
|
|
|
19
19
|
}>;
|
|
20
20
|
includeInputInOutput?: boolean;
|
|
21
21
|
tools?: (Agent | FunctionAgentFn)[];
|
|
22
|
+
disableLogging?: boolean;
|
|
22
23
|
}
|
|
23
24
|
export declare class Agent<I extends AgentInput = AgentInput, O extends AgentOutput = AgentOutput> extends EventEmitter {
|
|
24
25
|
static from<I extends AgentInput = AgentInput, O extends AgentOutput = AgentOutput>(options: AgentOptions<I, O>): Agent<I, O>;
|
|
@@ -37,6 +38,7 @@ export declare class Agent<I extends AgentInput = AgentInput, O extends AgentOut
|
|
|
37
38
|
readonly tools: Agent<AgentInput, AgentOutput>[] & {
|
|
38
39
|
[key: string]: Agent<AgentInput, AgentOutput>;
|
|
39
40
|
};
|
|
41
|
+
private disableLogging?;
|
|
40
42
|
addTool<I extends AgentInput, O extends AgentOutput>(tool: Agent<I, O> | FunctionAgentFn<I, O>): void;
|
|
41
43
|
get isCallable(): boolean;
|
|
42
44
|
call(input: I | string, context?: Context): Promise<O>;
|
package/lib/cjs/agents/agent.js
CHANGED
|
@@ -8,6 +8,7 @@ const node_events_1 = __importDefault(require("node:events"));
|
|
|
8
8
|
const zod_1 = require("zod");
|
|
9
9
|
const prompt_builder_1 = require("../prompt/prompt-builder");
|
|
10
10
|
const logger_1 = require("../utils/logger");
|
|
11
|
+
const type_utils_1 = require("../utils/type-utils");
|
|
11
12
|
const types_1 = require("./types");
|
|
12
13
|
class Agent extends node_events_1.default {
|
|
13
14
|
static from(options) {
|
|
@@ -26,6 +27,7 @@ class Agent extends node_events_1.default {
|
|
|
26
27
|
this.publishTopic = options.publishTopic;
|
|
27
28
|
if (options.tools?.length)
|
|
28
29
|
this.tools.push(...options.tools.map(functionToAgent));
|
|
30
|
+
this.disableLogging = options.disableLogging;
|
|
29
31
|
}
|
|
30
32
|
name;
|
|
31
33
|
description;
|
|
@@ -34,9 +36,8 @@ class Agent extends node_events_1.default {
|
|
|
34
36
|
includeInputInOutput;
|
|
35
37
|
subscribeTopic;
|
|
36
38
|
publishTopic;
|
|
37
|
-
tools =
|
|
38
|
-
|
|
39
|
-
});
|
|
39
|
+
tools = (0, type_utils_1.createAccessorArray)([], (arr, name) => arr.find((t) => t.name === name));
|
|
40
|
+
disableLogging;
|
|
40
41
|
addTool(tool) {
|
|
41
42
|
this.tools.push(typeof tool === "function" ? functionToAgent(tool) : tool);
|
|
42
43
|
}
|
|
@@ -48,19 +49,11 @@ class Agent extends node_events_1.default {
|
|
|
48
49
|
throw new Error("Agent must implement process method");
|
|
49
50
|
const _input = typeof input === "string" ? (0, prompt_builder_1.userInput)(input) : input;
|
|
50
51
|
const parsedInput = this.inputSchema.passthrough().parse(_input);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const finalOutput = this.includeInputInOutput
|
|
55
|
-
? { ...parsedInput, ...parsedOutput }
|
|
56
|
-
: parsedOutput;
|
|
57
|
-
logger_1.logger.debug(`Call agent ${this.name} successfully`, {
|
|
58
|
-
...finalOutput,
|
|
59
|
-
...(finalOutput[types_1.transferAgentOutputKey]
|
|
60
|
-
? { [types_1.transferAgentOutputKey]: finalOutput[types_1.transferAgentOutputKey].agent.name }
|
|
61
|
-
: {}),
|
|
52
|
+
const result = this.process(parsedInput, context).then((output) => {
|
|
53
|
+
const parsedOutput = this.outputSchema.passthrough().parse(output);
|
|
54
|
+
return this.includeInputInOutput ? { ...parsedInput, ...parsedOutput } : parsedOutput;
|
|
62
55
|
});
|
|
63
|
-
return
|
|
56
|
+
return logger_1.logger.debug.spinner(result, `Call agent ${this.name}`, (output) => logger_1.logger.debug("input: %O\noutput: %O", input, output), { disabled: this.disableLogging });
|
|
64
57
|
}
|
|
65
58
|
async shutdown() { }
|
|
66
59
|
}
|
|
@@ -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
|
}
|
|
@@ -6,6 +6,7 @@ const template_1 = require("../prompt/template");
|
|
|
6
6
|
const agent_1 = require("./agent");
|
|
7
7
|
const types_1 = require("./types");
|
|
8
8
|
const DEFAULT_OUTPUT_KEY = "text";
|
|
9
|
+
const DEFAULT_MAX_HISTORY_MESSAGES = 10;
|
|
9
10
|
class AIAgent extends agent_1.Agent {
|
|
10
11
|
static from(options) {
|
|
11
12
|
return new AIAgent(options);
|
|
@@ -19,27 +20,35 @@ class AIAgent extends agent_1.Agent {
|
|
|
19
20
|
: (options.instructions ?? new prompt_builder_1.PromptBuilder());
|
|
20
21
|
this.outputKey = options.outputKey;
|
|
21
22
|
this.toolChoice = options.toolChoice;
|
|
23
|
+
this.enableHistory = options.enableHistory;
|
|
24
|
+
this.maxHistoryMessages = options.maxHistoryMessages ?? DEFAULT_MAX_HISTORY_MESSAGES;
|
|
22
25
|
}
|
|
23
26
|
model;
|
|
24
27
|
instructions;
|
|
25
28
|
outputKey;
|
|
26
29
|
toolChoice;
|
|
30
|
+
enableHistory;
|
|
31
|
+
maxHistoryMessages;
|
|
27
32
|
async process(input, context) {
|
|
28
33
|
const model = context?.model ?? this.model;
|
|
29
34
|
if (!model)
|
|
30
35
|
throw new Error("model is required to run AIAgent");
|
|
31
36
|
let transferOutput;
|
|
32
|
-
const { toolAgents, ...modelInput } = await this.instructions.build({
|
|
37
|
+
const { toolAgents, messages, ...modelInput } = await this.instructions.build({
|
|
38
|
+
enableHistory: this.enableHistory,
|
|
39
|
+
maxHistoryMessages: this.maxHistoryMessages,
|
|
33
40
|
agent: this,
|
|
34
41
|
input,
|
|
35
42
|
model,
|
|
36
43
|
context,
|
|
37
44
|
});
|
|
38
45
|
const toolsMap = new Map(toolAgents?.map((i) => [i.name, i]));
|
|
46
|
+
const toolCallMessages = [];
|
|
39
47
|
for (;;) {
|
|
40
|
-
const { text, json, toolCalls } = await model.call(modelInput, context);
|
|
48
|
+
const { text, json, toolCalls } = await model.call({ ...modelInput, messages: messages.concat(toolCallMessages) }, context);
|
|
41
49
|
if (toolCalls?.length) {
|
|
42
50
|
const executedToolCalls = [];
|
|
51
|
+
// Execute tools
|
|
43
52
|
for (const call of toolCalls) {
|
|
44
53
|
const tool = toolsMap.get(call.function.name);
|
|
45
54
|
if (!tool)
|
|
@@ -53,21 +62,27 @@ class AIAgent extends agent_1.Agent {
|
|
|
53
62
|
executedToolCalls.push({ call, output });
|
|
54
63
|
}
|
|
55
64
|
}
|
|
56
|
-
if (this.toolChoice === "router") {
|
|
57
|
-
const output = executedToolCalls[0]?.output;
|
|
58
|
-
if (!output || executedToolCalls.length !== 1) {
|
|
59
|
-
throw new Error("Router toolChoice requires exactly one tool to be executed");
|
|
60
|
-
}
|
|
61
|
-
return output;
|
|
62
|
-
}
|
|
63
65
|
// Continue LLM function calling loop if any tools were executed
|
|
64
66
|
if (executedToolCalls.length) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
toolCallMessages.push(template_1.AgentMessageTemplate.from(executedToolCalls.map(({ call }) => call)).format(), ...executedToolCalls.map(({ call, output }) => template_1.ToolMessageTemplate.from(output, call.id).format()));
|
|
68
|
+
// Return the output of the first tool if the toolChoice is "router"
|
|
69
|
+
if (this.toolChoice === "router") {
|
|
70
|
+
const output = executedToolCalls[0]?.output;
|
|
71
|
+
if (!output || executedToolCalls.length !== 1) {
|
|
72
|
+
throw new Error("Router toolChoice requires exactly one tool to be executed");
|
|
73
|
+
}
|
|
74
|
+
return output;
|
|
75
|
+
}
|
|
67
76
|
continue;
|
|
68
77
|
}
|
|
69
78
|
}
|
|
70
79
|
const result = {};
|
|
80
|
+
if (json) {
|
|
81
|
+
this.instructions.addHistory(template_1.AgentMessageTemplate.from(JSON.stringify(json)).format());
|
|
82
|
+
}
|
|
83
|
+
else if (text) {
|
|
84
|
+
this.instructions.addHistory(template_1.AgentMessageTemplate.from(text).format());
|
|
85
|
+
}
|
|
71
86
|
if (modelInput.responseFormat?.type === "json_schema") {
|
|
72
87
|
Object.assign(result, json);
|
|
73
88
|
}
|
|
@@ -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,16 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MCPTool = exports.MCPAgent = void 0;
|
|
3
|
+
exports.MCPPrompt = exports.MCPTool = exports.MCPBase = exports.MCPAgent = void 0;
|
|
4
4
|
const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
|
|
5
5
|
const sse_js_1 = require("@modelcontextprotocol/sdk/client/sse.js");
|
|
6
6
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
|
|
7
|
-
const json_schema_to_zod_1 = require("@n8n/json-schema-to-zod");
|
|
8
|
-
const zod_1 = require("zod");
|
|
9
7
|
const logger_1 = require("../utils/logger");
|
|
8
|
+
const mcp_utils_1 = require("../utils/mcp-utils");
|
|
9
|
+
const type_utils_1 = require("../utils/type-utils");
|
|
10
10
|
const agent_1 = require("./agent");
|
|
11
11
|
const MCP_AGENT_CLIENT_NAME = "MCPAgent";
|
|
12
12
|
const MCP_AGENT_CLIENT_VERSION = "0.0.1";
|
|
13
|
-
const debug = logger_1.logger.base.extend("mcp
|
|
13
|
+
const debug = logger_1.logger.base.extend("mcp");
|
|
14
14
|
function isSSEServerParameters(options) {
|
|
15
15
|
return "url" in options && typeof options.url === "string";
|
|
16
16
|
}
|
|
@@ -24,7 +24,7 @@ class MCPAgent extends agent_1.Agent {
|
|
|
24
24
|
return MCPAgent.fromTransport(transport);
|
|
25
25
|
}
|
|
26
26
|
if (isStdioServerParameters(options)) {
|
|
27
|
-
const transport = new stdio_js_1.StdioClientTransport(options);
|
|
27
|
+
const transport = new stdio_js_1.StdioClientTransport({ ...options, stderr: "pipe" });
|
|
28
28
|
return MCPAgent.fromTransport(transport);
|
|
29
29
|
}
|
|
30
30
|
return new MCPAgent(options);
|
|
@@ -34,42 +34,36 @@ class MCPAgent extends agent_1.Agent {
|
|
|
34
34
|
name: MCP_AGENT_CLIENT_NAME,
|
|
35
35
|
version: MCP_AGENT_CLIENT_VERSION,
|
|
36
36
|
});
|
|
37
|
-
debug(
|
|
38
|
-
await client.connect(transport);
|
|
39
|
-
debug(`Connected to MCP server with transport ${transport.constructor.name}`);
|
|
37
|
+
await debug.spinner(client.connect(transport), "Connecting to MCP server");
|
|
40
38
|
const mcpServer = getMCPServerName(client);
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
content: zod_1.z.array(zod_1.z.record(zod_1.z.unknown())),
|
|
54
|
-
isError: zod_1.z.boolean().optional(),
|
|
55
|
-
})
|
|
56
|
-
.passthrough(),
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
return new MCPAgent({ client, tools });
|
|
39
|
+
const { tools: isToolsAvailable, prompts: isPromptsAvailable } = client.getServerCapabilities() ?? {};
|
|
40
|
+
const tools = isToolsAvailable
|
|
41
|
+
? await debug
|
|
42
|
+
.spinner(client.listTools(), `Listing tools from ${mcpServer}`, ({ tools }) => debug("%O", tools))
|
|
43
|
+
.then(({ tools }) => tools.map((tool) => (0, mcp_utils_1.toolFromMCPTool)(client, tool)))
|
|
44
|
+
: undefined;
|
|
45
|
+
const prompts = isPromptsAvailable
|
|
46
|
+
? await debug
|
|
47
|
+
.spinner(client.listPrompts(), `Listing prompts from ${mcpServer}`, ({ prompts }) => debug("%O", prompts))
|
|
48
|
+
.then(({ prompts }) => prompts.map((prompt) => (0, mcp_utils_1.promptFromMCPPrompt)(client, prompt)))
|
|
49
|
+
: undefined;
|
|
50
|
+
return new MCPAgent({ client, tools, prompts });
|
|
60
51
|
}
|
|
61
52
|
constructor(options) {
|
|
62
53
|
super(options);
|
|
63
54
|
this.client = options.client;
|
|
55
|
+
if (options.prompts?.length)
|
|
56
|
+
this.prompts.push(...options.prompts);
|
|
64
57
|
}
|
|
65
58
|
client;
|
|
59
|
+
prompts = (0, type_utils_1.createAccessorArray)([], (arr, name) => arr.find((i) => i.name === name));
|
|
66
60
|
async shutdown() {
|
|
67
61
|
super.shutdown();
|
|
68
62
|
await this.client.close();
|
|
69
63
|
}
|
|
70
64
|
}
|
|
71
65
|
exports.MCPAgent = MCPAgent;
|
|
72
|
-
class
|
|
66
|
+
class MCPBase extends agent_1.Agent {
|
|
73
67
|
constructor(options) {
|
|
74
68
|
super(options);
|
|
75
69
|
this.client = options.client;
|
|
@@ -78,14 +72,22 @@ class MCPTool extends agent_1.Agent {
|
|
|
78
72
|
get mcpServer() {
|
|
79
73
|
return getMCPServerName(this.client);
|
|
80
74
|
}
|
|
75
|
+
}
|
|
76
|
+
exports.MCPBase = MCPBase;
|
|
77
|
+
class MCPTool extends MCPBase {
|
|
81
78
|
async process(input) {
|
|
82
|
-
debug(`
|
|
83
|
-
const result = await this.client.callTool({ name: this.name, arguments: input });
|
|
84
|
-
debug(`End call tool ${this.name} from ${this.mcpServer} with result`, result);
|
|
79
|
+
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));
|
|
85
80
|
return result;
|
|
86
81
|
}
|
|
87
82
|
}
|
|
88
83
|
exports.MCPTool = MCPTool;
|
|
84
|
+
class MCPPrompt extends MCPBase {
|
|
85
|
+
async process(input) {
|
|
86
|
+
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));
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.MCPPrompt = MCPPrompt;
|
|
89
91
|
function getMCPServerName(client) {
|
|
90
92
|
const info = client.getServerVersion();
|
|
91
93
|
if (!info)
|
|
@@ -33,6 +33,7 @@ export declare class ExecutionEngine extends EventEmitter implements Context {
|
|
|
33
33
|
private runChatLoop;
|
|
34
34
|
private callAgent;
|
|
35
35
|
shutdown(): Promise<void>;
|
|
36
|
+
private initProcessExitHandler;
|
|
36
37
|
}
|
|
37
38
|
export declare class UserAgent<I extends AgentInput = AgentInput, O extends AgentOutput = AgentOutput> extends Agent<I, O> {
|
|
38
39
|
options: AgentOptions<I, O> & {
|
|
@@ -18,6 +18,7 @@ class ExecutionEngine extends node_events_1.default {
|
|
|
18
18
|
this.tools = options?.tools ?? [];
|
|
19
19
|
if (options?.agents?.length)
|
|
20
20
|
this.addAgent(...options.agents);
|
|
21
|
+
this.initProcessExitHandler();
|
|
21
22
|
}
|
|
22
23
|
messageQueue = new message_queue_1.MessageQueue();
|
|
23
24
|
model;
|
|
@@ -175,12 +176,17 @@ class ExecutionEngine extends node_events_1.default {
|
|
|
175
176
|
await agent.shutdown();
|
|
176
177
|
}
|
|
177
178
|
}
|
|
179
|
+
initProcessExitHandler() {
|
|
180
|
+
const shutdownAndExit = () => this.shutdown().finally(() => process.exit(0));
|
|
181
|
+
process.on("SIGINT", shutdownAndExit);
|
|
182
|
+
process.on("exit", shutdownAndExit);
|
|
183
|
+
}
|
|
178
184
|
}
|
|
179
185
|
exports.ExecutionEngine = ExecutionEngine;
|
|
180
186
|
class UserAgent extends agent_1.Agent {
|
|
181
187
|
options;
|
|
182
188
|
constructor(options) {
|
|
183
|
-
super(options);
|
|
189
|
+
super({ ...options, disableLogging: true });
|
|
184
190
|
this.options = options;
|
|
185
191
|
}
|
|
186
192
|
process(input) {
|
package/lib/cjs/index.d.ts
CHANGED
package/lib/cjs/index.js
CHANGED
|
@@ -24,3 +24,4 @@ __exportStar(require("./models/chat"), exports);
|
|
|
24
24
|
__exportStar(require("./models/chat-openai"), exports);
|
|
25
25
|
__exportStar(require("./prompt/prompt-builder"), exports);
|
|
26
26
|
__exportStar(require("./prompt/template"), exports);
|
|
27
|
+
__exportStar(require("./utils/run-chat-loop"), exports);
|
|
@@ -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
|
}>;
|
|
@@ -7,6 +7,7 @@ exports.PromptBuilder = exports.USER_INPUT_MESSAGE_KEY = void 0;
|
|
|
7
7
|
exports.userInput = userInput;
|
|
8
8
|
exports.addMessagesToInput = addMessagesToInput;
|
|
9
9
|
const promises_1 = require("node:fs/promises");
|
|
10
|
+
const lodash_1 = require("lodash");
|
|
10
11
|
const zod_1 = require("zod");
|
|
11
12
|
const zod_to_json_schema_1 = __importDefault(require("zod-to-json-schema"));
|
|
12
13
|
const agent_1 = require("../agents/agent");
|
|
@@ -36,19 +37,39 @@ function addMessagesToInput(input, messages) {
|
|
|
36
37
|
}
|
|
37
38
|
class PromptBuilder {
|
|
38
39
|
static from(instructions) {
|
|
39
|
-
if (typeof instructions === "string")
|
|
40
|
+
if (typeof instructions === "string")
|
|
40
41
|
return new PromptBuilder({ instructions });
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
if (isFromPromptResult(instructions))
|
|
43
|
+
return PromptBuilder.fromMCPPromptResult(instructions);
|
|
44
|
+
if (isFromPath(instructions))
|
|
45
|
+
return PromptBuilder.fromFile(instructions.path);
|
|
46
|
+
throw new Error(`Invalid instructions ${instructions}`);
|
|
43
47
|
}
|
|
44
48
|
static async fromFile(path) {
|
|
45
49
|
const text = await (0, promises_1.readFile)(path, "utf-8");
|
|
46
50
|
return PromptBuilder.from(text);
|
|
47
51
|
}
|
|
52
|
+
static fromMCPPromptResult(result) {
|
|
53
|
+
return new PromptBuilder({
|
|
54
|
+
instructions: template_1.ChatMessagesTemplate.from(result.messages.map((i) => {
|
|
55
|
+
if (i.content.type !== "text")
|
|
56
|
+
throw new Error(`Unsupported content type ${i.content.type}`);
|
|
57
|
+
if (i.role === "user")
|
|
58
|
+
return template_1.UserMessageTemplate.from(i.content.text);
|
|
59
|
+
if (i.role === "assistant")
|
|
60
|
+
return template_1.AgentMessageTemplate.from(i.content.text);
|
|
61
|
+
throw new Error(`Unsupported role ${i.role}`);
|
|
62
|
+
})),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
48
65
|
constructor(options) {
|
|
49
66
|
this.instructions = options?.instructions;
|
|
50
67
|
}
|
|
51
68
|
instructions;
|
|
69
|
+
histories = [];
|
|
70
|
+
addHistory(...messages) {
|
|
71
|
+
this.histories.push(...messages);
|
|
72
|
+
}
|
|
52
73
|
async build(options) {
|
|
53
74
|
return {
|
|
54
75
|
messages: this.buildMessages(options),
|
|
@@ -58,21 +79,35 @@ class PromptBuilder {
|
|
|
58
79
|
}
|
|
59
80
|
buildMessages(options) {
|
|
60
81
|
const { input } = options;
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
82
|
+
const messages = (typeof this.instructions === "string"
|
|
83
|
+
? template_1.ChatMessagesTemplate.from([template_1.SystemMessageTemplate.from(this.instructions)])
|
|
84
|
+
: this.instructions)?.format(options.input) ?? [];
|
|
85
|
+
if (options.enableHistory) {
|
|
86
|
+
messages.push(...(options.maxHistoryMessages
|
|
87
|
+
? this.histories.slice(-options.maxHistoryMessages)
|
|
88
|
+
: this.histories));
|
|
89
|
+
}
|
|
90
|
+
const userMessages = [];
|
|
64
91
|
const userInputMessage = input?.[exports.USER_INPUT_MESSAGE_KEY];
|
|
65
|
-
|
|
66
|
-
|
|
92
|
+
// Parse messages from the user input with the key $user_input_message
|
|
93
|
+
if (!(0, lodash_1.isNil)(userInputMessage)) {
|
|
94
|
+
if (typeof userInputMessage === "string") {
|
|
95
|
+
userMessages.push(template_1.UserMessageTemplate.from(userInputMessage).format());
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const messages = (0, template_1.parseChatMessages)(userInputMessage);
|
|
99
|
+
if (messages)
|
|
100
|
+
userMessages.push(...messages.map((i) => i.format()));
|
|
101
|
+
else
|
|
102
|
+
userMessages.push(template_1.UserMessageTemplate.from(JSON.stringify(userInputMessage)).format());
|
|
103
|
+
}
|
|
67
104
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
else
|
|
73
|
-
template.messages.push(template_1.UserMessageTemplate.from(JSON.stringify(userInputMessage)));
|
|
105
|
+
if (userMessages.length) {
|
|
106
|
+
if (options.enableHistory)
|
|
107
|
+
this.addHistory(...userMessages);
|
|
108
|
+
messages.push(...userMessages);
|
|
74
109
|
}
|
|
75
|
-
return
|
|
110
|
+
return messages;
|
|
76
111
|
}
|
|
77
112
|
buildResponseFormat(options) {
|
|
78
113
|
const outputSchema = options.agent?.outputSchema;
|
|
@@ -135,6 +170,12 @@ class PromptBuilder {
|
|
|
135
170
|
}
|
|
136
171
|
}
|
|
137
172
|
exports.PromptBuilder = PromptBuilder;
|
|
173
|
+
function isFromPromptResult(value) {
|
|
174
|
+
return typeof value === "object" && "messages" in value && Array.isArray(value.messages);
|
|
175
|
+
}
|
|
176
|
+
function isFromPath(value) {
|
|
177
|
+
return typeof value === "object" && "path" in value && typeof value.path === "string";
|
|
178
|
+
}
|
|
138
179
|
function isEmptyObjectType(schema) {
|
|
139
180
|
return schema instanceof zod_1.ZodObject && Object.keys(schema.shape).length === 0;
|
|
140
181
|
}
|
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import debug from "debug";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import debug, { type Debugger } from "debug";
|
|
2
|
+
interface DebugWithSpinner extends Debugger {
|
|
3
|
+
spinner<T>(promise: Promise<T>, message?: string, callback?: (result: T) => void, options?: {
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
}): Promise<T>;
|
|
6
|
+
extend: (namespace: string) => DebugWithSpinner;
|
|
7
|
+
}
|
|
8
|
+
declare function spinner<T>(promise: Promise<T>, message?: string, callback?: (result: T) => void): Promise<T>;
|
|
9
|
+
export declare const logger: debug.Debug & {
|
|
10
|
+
debug: debug.Debug;
|
|
11
|
+
default: debug.Debug;
|
|
12
|
+
} & {
|
|
13
|
+
globalSpinner: import("ora").Ora;
|
|
14
|
+
base: DebugWithSpinner;
|
|
15
|
+
debug: DebugWithSpinner;
|
|
16
|
+
spinner: typeof spinner;
|
|
6
17
|
};
|
|
18
|
+
export {};
|
package/lib/cjs/utils/logger.js
CHANGED
|
@@ -5,8 +5,79 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.logger = void 0;
|
|
7
7
|
const debug_1 = __importDefault(require("debug"));
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
debug_1.default.log = (...args) => {
|
|
10
|
+
const { isSpinning } = globalSpinner;
|
|
11
|
+
if (isSpinning)
|
|
12
|
+
globalSpinner.stop();
|
|
13
|
+
console.log(...args);
|
|
14
|
+
if (isSpinning)
|
|
15
|
+
globalSpinner.start();
|
|
12
16
|
};
|
|
17
|
+
function createDebugger(namespace) {
|
|
18
|
+
const i = (0, debug_1.default)(namespace);
|
|
19
|
+
function overrideExtend(debug) {
|
|
20
|
+
const originalExtend = debug.extend;
|
|
21
|
+
debug.extend = (namespace) => {
|
|
22
|
+
const extended = originalExtend.call(debug, namespace);
|
|
23
|
+
overrideExtend(extended);
|
|
24
|
+
extended.spinner = async (promise, message, callback, options) => {
|
|
25
|
+
if (!extended.enabled || options?.disabled)
|
|
26
|
+
return promise;
|
|
27
|
+
return spinner(promise, message, callback);
|
|
28
|
+
};
|
|
29
|
+
return extended;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
overrideExtend(i);
|
|
33
|
+
return i;
|
|
34
|
+
}
|
|
35
|
+
const globalSpinner = (0, ora_1.default)();
|
|
36
|
+
const globalSpinnerTasks = [];
|
|
37
|
+
async function spinner(promise, message, callback) {
|
|
38
|
+
const task = { promise, message, callback };
|
|
39
|
+
globalSpinnerTasks.push(task);
|
|
40
|
+
globalSpinner.start(message || " ");
|
|
41
|
+
await promise
|
|
42
|
+
.then((result) => {
|
|
43
|
+
task.result = result;
|
|
44
|
+
task.status = "succeed";
|
|
45
|
+
})
|
|
46
|
+
.catch(() => {
|
|
47
|
+
task.status = "fail";
|
|
48
|
+
});
|
|
49
|
+
// Once the promise resolves or rejects, it updates the spinner status and processes
|
|
50
|
+
// all completed tasks in a Last-In-First-Out (LIFO) order.
|
|
51
|
+
for (;;) {
|
|
52
|
+
const task = globalSpinnerTasks.at(-1);
|
|
53
|
+
if (!task)
|
|
54
|
+
break;
|
|
55
|
+
// Recover spinner state for last running task
|
|
56
|
+
if (!task.status) {
|
|
57
|
+
globalSpinner.start(task.message || " ");
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
globalSpinnerTasks.pop();
|
|
61
|
+
if (task.message) {
|
|
62
|
+
if (task.status === "fail")
|
|
63
|
+
globalSpinner.fail(task.message);
|
|
64
|
+
else
|
|
65
|
+
globalSpinner.succeed(task.message);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
globalSpinner.stop();
|
|
69
|
+
}
|
|
70
|
+
// NOTE: This is a workaround to make sure the spinner stops spinning before the next tick
|
|
71
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
72
|
+
if (task.status === "succeed")
|
|
73
|
+
task.callback?.(task.result);
|
|
74
|
+
}
|
|
75
|
+
return promise;
|
|
76
|
+
}
|
|
77
|
+
const base = createDebugger("aigne");
|
|
78
|
+
exports.logger = Object.assign(debug_1.default, {
|
|
79
|
+
globalSpinner,
|
|
80
|
+
base,
|
|
81
|
+
debug: base.extend("core"),
|
|
82
|
+
spinner,
|
|
83
|
+
});
|