@hashgraphonline/conversational-agent
Version:
Hashgraph Online conversational AI agent implementing HCS-10 communication, HCS-2 registries, and content inscription on Hedera
156 lines (153 loc) • 5.18 kB
JavaScript
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
import { shouldUseReference, ContentStoreService } from "@hashgraphonline/standards-sdk";
function convertMCPToolToLangChain(tool, mcpManager, serverConfig) {
const zodSchema = jsonSchemaToZod(tool.inputSchema);
const sanitizedName = `${tool.serverName}_${tool.name}`.replace(
/[^a-zA-Z0-9_]/g,
"_"
);
let description = tool.description || `MCP tool ${tool.name} from ${tool.serverName}`;
if (serverConfig?.toolDescriptions?.[tool.name]) {
description = `${description}
${serverConfig.toolDescriptions[tool.name]}`;
}
if (serverConfig?.additionalContext) {
description = `${description}
Context: ${serverConfig.additionalContext}`;
}
return new DynamicStructuredTool({
name: sanitizedName,
description,
schema: zodSchema,
func: async (input) => {
try {
const result = await mcpManager.executeTool(
tool.serverName,
tool.name,
input
);
let responseText = "";
if (typeof result === "string") {
responseText = result;
} else if (result && typeof result === "object" && "content" in result) {
const content = result.content;
if (Array.isArray(content)) {
const textParts = content.filter(
(item) => typeof item === "object" && item !== null && "type" in item && item.type === "text" && "text" in item
).map((item) => item.text);
responseText = textParts.join("\n");
} else {
responseText = JSON.stringify(content);
}
} else {
responseText = JSON.stringify(result);
}
const responseBuffer = Buffer.from(responseText, "utf8");
const MCP_REFERENCE_THRESHOLD = 10 * 1024;
const shouldStoreMCPContent = responseBuffer.length > MCP_REFERENCE_THRESHOLD;
if (shouldStoreMCPContent || shouldUseReference(responseBuffer)) {
const contentStore = ContentStoreService.getInstance();
if (contentStore) {
try {
const referenceId = await contentStore.storeContent(responseBuffer, {
contentType: "text",
source: "mcp",
mcpToolName: `${tool.serverName}_${tool.name}`,
originalSize: responseBuffer.length
});
return `content-ref:${referenceId}`;
} catch (storeError) {
}
}
}
return responseText;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "Unknown error";
return `Error executing MCP tool ${tool.name}: ${errorMessage}`;
}
}
});
}
function jsonSchemaToZod(schema) {
if (!schema || typeof schema !== "object") {
return z.object({});
}
const schemaObj = schema;
if (schemaObj.type && schemaObj.type !== "object") {
return convertType(schemaObj);
}
if (!schemaObj.properties || typeof schemaObj.properties !== "object") {
return z.object({});
}
const shape = {};
for (const [key, value] of Object.entries(schemaObj.properties)) {
let zodType = convertType(value);
const isRequired = Array.isArray(schemaObj.required) && schemaObj.required.includes(key);
if (!isRequired) {
zodType = zodType.optional();
}
shape[key] = zodType;
}
return z.object(shape);
}
function convertType(schema) {
if (!schema || typeof schema !== "object" || !("type" in schema)) {
return z.unknown();
}
const schemaObj = schema;
let zodType;
switch (schemaObj.type) {
case "string":
zodType = z.string();
if (schemaObj.enum && Array.isArray(schemaObj.enum)) {
zodType = z.enum(schemaObj.enum);
}
break;
case "number":
zodType = z.number();
if ("minimum" in schemaObj && typeof schemaObj.minimum === "number") {
zodType = zodType.min(schemaObj.minimum);
}
if ("maximum" in schemaObj && typeof schemaObj.maximum === "number") {
zodType = zodType.max(schemaObj.maximum);
}
break;
case "integer":
zodType = z.number().int();
if ("minimum" in schemaObj && typeof schemaObj.minimum === "number") {
zodType = zodType.min(schemaObj.minimum);
}
if ("maximum" in schemaObj && typeof schemaObj.maximum === "number") {
zodType = zodType.max(schemaObj.maximum);
}
break;
case "boolean":
zodType = z.boolean();
break;
case "array":
if (schemaObj.items) {
zodType = z.array(convertType(schemaObj.items));
} else {
zodType = z.array(z.unknown());
}
break;
case "object":
if ("properties" in schemaObj) {
zodType = jsonSchemaToZod(schemaObj);
} else {
zodType = z.object({}).passthrough();
}
break;
default:
zodType = z.unknown();
}
if ("description" in schemaObj && typeof schemaObj.description === "string") {
zodType = zodType.describe(schemaObj.description);
}
return zodType;
}
export {
convertMCPToolToLangChain
};
//# sourceMappingURL=index23.js.map