@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
package/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## 1.1.0-beta.6 (2025-3-13)
2
+
3
+ - chore(examples): default enable mcp debug message for examples
4
+
5
+ ## 1.1.0-beta.5 (2025-3-13)
6
+
7
+ - feat: support chat history in PromptBuilder
8
+ - feat: add `prompts` for MCPAgent to consume prompts from MCP server
9
+ - chore: add sqlite-mcp-server example
10
+ - test: add more unit test cases
11
+
1
12
  ## 1.1.0-beta.4 (2025-3-12)
2
13
 
3
14
  - feat: support run puppeteer example chat loop in terminal
@@ -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) {
@@ -35,9 +36,7 @@ class Agent extends node_events_1.default {
35
36
  includeInputInOutput;
36
37
  subscribeTopic;
37
38
  publishTopic;
38
- tools = new Proxy([], {
39
- get: (t, p, r) => Reflect.get(t, p, r) ?? t.find((t) => t.name === p),
40
- });
39
+ tools = (0, type_utils_1.createAccessorArray)([], (arr, name) => arr.find((t) => t.name === name));
41
40
  disableLogging;
42
41
  addTool(tool) {
43
42
  this.tools.push(typeof tool === "function" ? functionToAgent(tool) : tool);
@@ -54,7 +53,7 @@ class Agent extends node_events_1.default {
54
53
  const parsedOutput = this.outputSchema.passthrough().parse(output);
55
54
  return this.includeInputInOutput ? { ...parsedInput, ...parsedOutput } : parsedOutput;
56
55
  });
57
- return logger_1.logger.debug.spinner(result, `Call agent ${this.name}`, (output) => logger_1.logger.debug("%O", { input, output }), { disabled: this.disableLogging });
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 });
58
57
  }
59
58
  async shutdown() { }
60
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
- modelInput.messages.push(template_1.AgentMessageTemplate.from(executedToolCalls.map(({ call }) => call)).format());
66
- modelInput.messages.push(...executedToolCalls.map(({ call, output }) => template_1.ToolMessageTemplate.from(output, call.id).format()));
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 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,12 +1,12 @@
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";
@@ -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);
@@ -36,36 +36,34 @@ class MCPAgent extends agent_1.Agent {
36
36
  });
37
37
  await debug.spinner(client.connect(transport), "Connecting to MCP server");
38
38
  const mcpServer = getMCPServerName(client);
39
- const { tools: mcpTools } = await debug.spinner(client.listTools(), `Listing tools from ${mcpServer}`, ({ tools }) => debug("%O", tools));
40
- const tools = mcpTools.map((tool) => {
41
- return new MCPTool({
42
- client,
43
- name: tool.name,
44
- description: tool.description,
45
- inputSchema: (0, json_schema_to_zod_1.jsonSchemaToZod)(tool.inputSchema),
46
- outputSchema: zod_1.z
47
- .object({
48
- _meta: zod_1.z.record(zod_1.z.unknown()).optional(),
49
- content: zod_1.z.array(zod_1.z.record(zod_1.z.unknown())),
50
- isError: zod_1.z.boolean().optional(),
51
- })
52
- .passthrough(),
53
- });
54
- });
55
- 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 });
56
51
  }
57
52
  constructor(options) {
58
53
  super(options);
59
54
  this.client = options.client;
55
+ if (options.prompts?.length)
56
+ this.prompts.push(...options.prompts);
60
57
  }
61
58
  client;
59
+ prompts = (0, type_utils_1.createAccessorArray)([], (arr, name) => arr.find((i) => i.name === name));
62
60
  async shutdown() {
63
61
  super.shutdown();
64
62
  await this.client.close();
65
63
  }
66
64
  }
67
65
  exports.MCPAgent = MCPAgent;
68
- class MCPTool extends agent_1.Agent {
66
+ class MCPBase extends agent_1.Agent {
69
67
  constructor(options) {
70
68
  super(options);
71
69
  this.client = options.client;
@@ -74,12 +72,22 @@ class MCPTool extends agent_1.Agent {
74
72
  get mcpServer() {
75
73
  return getMCPServerName(this.client);
76
74
  }
75
+ }
76
+ exports.MCPBase = MCPBase;
77
+ class MCPTool extends MCPBase {
77
78
  async process(input) {
78
- 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 }));
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));
79
80
  return result;
80
81
  }
81
82
  }
82
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;
83
91
  function getMCPServerName(client) {
84
92
  const info = client.getServerVersion();
85
93
  if (!info)
@@ -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/cjs/index.js CHANGED
@@ -24,4 +24,5 @@ __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/logger"), exports);
27
28
  __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
- return PromptBuilder.fromFile(instructions.path);
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 template = template_1.ChatMessagesTemplate.from([]);
62
- if (this.instructions)
63
- template.messages.push(template_1.SystemMessageTemplate.from(this.instructions));
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
- if (typeof userInputMessage === "string") {
66
- template.messages.push(template_1.UserMessageTemplate.from(userInputMessage));
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
- else if (userInputMessage) {
69
- const messages = (0, template_1.parseChatMessages)(userInputMessage);
70
- if (messages)
71
- template.messages.push(...messages);
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 template.format(input);
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,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;
@@ -33,35 +33,51 @@ function createDebugger(namespace) {
33
33
  return i;
34
34
  }
35
35
  const globalSpinner = (0, ora_1.default)();
36
+ const globalSpinnerTasks = [];
36
37
  async function spinner(promise, message, callback) {
37
- const { isSpinning, text } = globalSpinner;
38
- try {
39
- globalSpinner.start(message || " ");
40
- const result = await promise;
41
- if (message)
42
- globalSpinner.succeed(message);
43
- else
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 {
44
68
  globalSpinner.stop();
69
+ }
45
70
  // NOTE: This is a workaround to make sure the spinner stops spinning before the next tick
46
- await new Promise((resolve) => setTimeout(resolve, 100));
47
- callback?.(result);
48
- // NOTE: This is a workaround to make sure the spinner stops spinning before the next tick
49
- await new Promise((resolve) => setTimeout(resolve, 100));
50
- return result;
51
- }
52
- catch (error) {
53
- globalSpinner.fail(message || " ");
54
- throw error;
55
- }
56
- finally {
57
- // Recover the spinner state
58
- if (isSpinning)
59
- globalSpinner.start(text || " ");
71
+ await new Promise((resolve) => setTimeout(resolve, 10));
72
+ if (task.status === "succeed")
73
+ task.callback?.(task.result);
60
74
  }
75
+ return promise;
61
76
  }
62
77
  const base = createDebugger("aigne");
63
- exports.logger = {
78
+ exports.logger = Object.assign(debug_1.default, {
79
+ globalSpinner,
64
80
  base,
65
81
  debug: base.extend("core"),
66
82
  spinner,
67
- };
83
+ });
@@ -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;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toolFromMCPTool = toolFromMCPTool;
4
+ exports.promptFromMCPPrompt = promptFromMCPPrompt;
5
+ const json_schema_to_zod_1 = require("@n8n/json-schema-to-zod");
6
+ const zod_1 = require("zod");
7
+ const mcp_agent_1 = require("../agents/mcp-agent");
8
+ function toolFromMCPTool(client, tool) {
9
+ return new mcp_agent_1.MCPTool({
10
+ client,
11
+ name: tool.name,
12
+ description: tool.description,
13
+ inputSchema: (0, json_schema_to_zod_1.jsonSchemaToZod)(tool.inputSchema),
14
+ outputSchema: zod_1.z
15
+ .object({
16
+ _meta: zod_1.z.record(zod_1.z.unknown()).optional(),
17
+ content: zod_1.z.array(zod_1.z.record(zod_1.z.unknown())),
18
+ isError: zod_1.z.boolean().optional(),
19
+ })
20
+ .passthrough(),
21
+ });
22
+ }
23
+ function promptFromMCPPrompt(client, prompt) {
24
+ return new mcp_agent_1.MCPPrompt({
25
+ client,
26
+ name: prompt.name,
27
+ description: prompt.description,
28
+ inputSchema: (0, json_schema_to_zod_1.jsonSchemaToZod)({
29
+ type: "object",
30
+ properties: prompt.arguments &&
31
+ Object.fromEntries(prompt.arguments.map((i) => [i.name, { type: "string", description: i.description }])),
32
+ required: prompt.arguments?.filter((i) => i.required).map((i) => i.name),
33
+ }),
34
+ outputSchema: zod_1.z
35
+ .object({
36
+ description: zod_1.z.string().optional(),
37
+ messages: zod_1.z.array(zod_1.z.record(zod_1.z.unknown())),
38
+ })
39
+ .passthrough(),
40
+ });
41
+ }
@@ -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>;