2025-11-15 01:51:22 +05:30
|
|
|
import { ToolAttachment } from "../entities/agent.js";
|
2025-11-07 11:42:10 +05:30
|
|
|
import { z } from "zod";
|
|
|
|
|
import { McpServers } from "../config/config.js";
|
|
|
|
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
|
|
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
|
|
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
|
|
|
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
|
|
|
import { Client } from "@modelcontextprotocol/sdk/client";
|
|
|
|
|
import { AssistantMessage } from "../entities/message.js";
|
2025-11-15 01:51:22 +05:30
|
|
|
import { BuiltinTools } from "./builtin-tools.js";
|
2025-11-16 20:58:31 +05:30
|
|
|
import { loadAgent, streamAgentTurn } from "./agent.js";
|
|
|
|
|
import { app } from "@/app.js";
|
2025-11-07 11:42:10 +05:30
|
|
|
|
2025-11-15 01:51:22 +05:30
|
|
|
async function execMcpTool(agentTool: z.infer<typeof ToolAttachment> & { type: "mcp" }, input: any): Promise<any> {
|
2025-11-07 11:42:10 +05:30
|
|
|
// load mcp configuration from the tool
|
|
|
|
|
const mcpConfig = McpServers[agentTool.mcpServerName];
|
|
|
|
|
if (!mcpConfig) {
|
|
|
|
|
throw new Error(`MCP server ${agentTool.mcpServerName} not found`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create transport
|
|
|
|
|
let transport: Transport;
|
|
|
|
|
if ("command" in mcpConfig) {
|
|
|
|
|
transport = new StdioClientTransport({
|
|
|
|
|
command: mcpConfig.command,
|
|
|
|
|
args: mcpConfig.args,
|
|
|
|
|
env: mcpConfig.env,
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
// first try streamable http transport
|
|
|
|
|
try {
|
|
|
|
|
transport = new StreamableHTTPClientTransport(new URL(mcpConfig.url));
|
|
|
|
|
} catch (error) {
|
|
|
|
|
// if that fails, try sse transport
|
|
|
|
|
transport = new SSEClientTransport(new URL(mcpConfig.url));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!transport) {
|
|
|
|
|
throw new Error(`No transport found for ${agentTool.mcpServerName}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create client
|
|
|
|
|
const client = new Client({
|
|
|
|
|
name: 'rowboatx',
|
|
|
|
|
version: '1.0.0',
|
|
|
|
|
});
|
|
|
|
|
await client.connect(transport);
|
|
|
|
|
|
|
|
|
|
// call tool
|
|
|
|
|
const result = await client.callTool({ name: agentTool.name, arguments: input });
|
|
|
|
|
client.close();
|
|
|
|
|
transport.close();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-15 01:51:22 +05:30
|
|
|
async function execAgentTool(agentTool: z.infer<typeof ToolAttachment> & { type: "agent" }, input: any): Promise<any> {
|
2025-11-07 11:42:10 +05:30
|
|
|
let lastMsg: z.infer<typeof AssistantMessage> | null = null;
|
2025-11-16 20:58:31 +05:30
|
|
|
const agent = await loadAgent(agentTool.name);
|
|
|
|
|
for await (const event of streamAgentTurn({
|
|
|
|
|
agent,
|
|
|
|
|
messages: [{
|
|
|
|
|
role: "user",
|
|
|
|
|
content: JSON.stringify(input),
|
|
|
|
|
}],
|
2025-11-15 01:51:22 +05:30
|
|
|
})) {
|
2025-11-11 12:32:46 +05:30
|
|
|
if (event.type === "message" && event.message.role === "assistant") {
|
2025-11-07 11:42:10 +05:30
|
|
|
lastMsg = event.message;
|
|
|
|
|
}
|
2025-11-11 12:32:46 +05:30
|
|
|
if (event.type === "error") {
|
2025-11-07 11:42:10 +05:30
|
|
|
throw new Error(event.error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!lastMsg) {
|
2025-11-15 01:51:22 +05:30
|
|
|
throw new Error("No message received from agent");
|
2025-11-07 11:42:10 +05:30
|
|
|
}
|
|
|
|
|
if (typeof lastMsg.content === "string") {
|
|
|
|
|
return lastMsg.content;
|
|
|
|
|
}
|
|
|
|
|
return lastMsg.content.reduce((acc, part) => {
|
|
|
|
|
if (part.type === "text") {
|
|
|
|
|
acc += part.text;
|
|
|
|
|
}
|
|
|
|
|
return acc;
|
|
|
|
|
}, "");
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-15 01:51:22 +05:30
|
|
|
export async function execTool(agentTool: z.infer<typeof ToolAttachment>, input: any): Promise<any> {
|
2025-11-07 11:42:10 +05:30
|
|
|
switch (agentTool.type) {
|
|
|
|
|
case "mcp":
|
|
|
|
|
return execMcpTool(agentTool, input);
|
2025-11-15 01:51:22 +05:30
|
|
|
case "agent":
|
|
|
|
|
return execAgentTool(agentTool, input);
|
2025-11-07 11:42:10 +05:30
|
|
|
case "builtin":
|
2025-11-15 01:51:22 +05:30
|
|
|
const builtinTool = BuiltinTools[agentTool.name];
|
|
|
|
|
if (!builtinTool || !builtinTool.execute) {
|
|
|
|
|
throw new Error(`Unsupported builtin tool: ${agentTool.name}`);
|
2025-11-10 16:56:30 +05:30
|
|
|
}
|
2025-11-15 01:51:22 +05:30
|
|
|
return builtinTool.execute(input);
|
2025-11-07 11:42:10 +05:30
|
|
|
}
|
|
|
|
|
}
|