fix: harden assistant authoring and UI

This commit is contained in:
ajnart authored and Thomas Camlong committed 2026-08-09 18:09:11 +02:00
1 parent fa0e55cc93
commit edc7b4d55b
51 files changed
+4118 -916

No files matched your search

+3 -1
View File
@@ -21,6 +21,7 @@ import { customJsxExamples, getCustomWidgetJsonSchema } from "@homarr/custom-wid
import { db } from "@homarr/db";
import { getPackageVersion } from "~/versions/package-reader";
import { getSafeAssistantToolError } from "../assistant/chat/assistant-tool-error";
import { extractMcpTools } from "./_extract-tools";
import { createMcpProtocolHandler } from "./_protocol";
@@ -204,7 +205,8 @@ const SAFE_ERROR_MESSAGES: Record<string, string> = {
PRECONDITION_FAILED: "A precondition for this operation was not met",
};
function sanitizeErrorMessage(error: unknown): string {
function sanitizeErrorMessage(error: unknown, toolName: string): string {
if (toolName.startsWith("customWidget_")) return getSafeAssistantToolError(error, { toolName });
if (error instanceof Error && "code" in error) {
const trpcCode = (error as Error & { code: string }).code;
const safeMessage = SAFE_ERROR_MESSAGES[trpcCode];
@@ -99,6 +99,30 @@ describe("MCP v2 protocol", () => {
expect(response.result.content).toEqual([{ type: "text", text: '{"message":"hello"}' }]);
});
test("passes the tool name to safe error formatting", async () => {
const formatToolError = vi.fn((_error: unknown, toolName: string) => `${toolName} input was invalid`);
const handler = createMcpProtocolHandler({
caller: {
echo: vi.fn(async () => {
throw new Error("private details");
}),
},
tools: [echoTool],
version: "1.0.0",
instructions: "Test server",
formatToolError,
});
const response = await parseResponse(
await handler.fetch(createRequest("tools/call", { name: "echo", arguments: { message: "hello" } }, "echo")),
);
expect(formatToolError).toHaveBeenCalledWith(expect.any(Error), "echo");
expect(response.result).toMatchObject({
isError: true,
content: [{ type: "text", text: '{"error":"echo input was invalid"}' }],
});
});
test("keeps stateless compatibility with 2025 Streamable HTTP clients", async () => {
const { handler } = createTestHandler();
const request = new Request("http://homarr.test/api/mcp", {
+4 -2
View File
@@ -8,7 +8,7 @@ interface CreateMcpProtocolHandlerOptions {
version: string;
instructions: string;
configureServer?: (server: McpServer) => void;
formatToolError: (error: unknown) => string;
formatToolError: (error: unknown, toolName: string) => string;
onToolError?: (toolName: string, error: unknown) => void;
onProtocolError?: (error: Error) => void;
}
@@ -70,7 +70,9 @@ export const createMcpProtocolHandler = ({
} catch (error) {
onToolError?.(tool.name, error);
return {
content: [{ type: "text" as const, text: JSON.stringify({ error: formatToolError(error) }) }],
content: [
{ type: "text" as const, text: JSON.stringify({ error: formatToolError(error, tool.name) }) },
],
isError: true,
};
}