Files
homarr/apps/nextjs/src/app/api/assistant/chat/assistant-tool-groups.ts
T
Thomas 5e23659d99 feat(assistant): optimize MCP and custom widget authoring (#6743)
* feat(assistant): optimize MCP and custom widget authoring

* fix(assistant): isolate server-safe JSX analyzer

* refactor(assistant): generate MCP tool staging

* fix(assistant): preserve widget placement follow-up

* fix(ci): allow fast gate to finish

* fix(custom-widgets): address review findings

* fix(custom-widgets): split preview evidence module

* style: format assistant custom widget files

* fix(custom-widgets): sync formatted skill schema
2026-08-30 23:43:29 +02:00

39 lines
1.4 KiB
TypeScript

import type { McpTool } from "@homarr/api/mcp";
type AssistantMcpTool = Pick<McpTool, "name" | "pathInRouter">;
export interface AssistantMcpToolGroup<TTool extends AssistantMcpTool = AssistantMcpTool> {
id: string;
tools: readonly TTool[];
}
export const createAssistantMcpToolGroups = <TTool extends AssistantMcpTool>(tools: readonly TTool[]) => {
const toolsByGroup = new Map<string, TTool[]>();
for (const tool of tools) {
const groupId = tool.pathInRouter[0];
if (!groupId) throw new Error(`Assistant MCP tool '${tool.name}' has no router group`);
const groupedTools = toolsByGroup.get(groupId) ?? [];
groupedTools.push(tool);
toolsByGroup.set(groupId, groupedTools);
}
const groups = [...toolsByGroup.entries()]
.toSorted(([left], [right]) => left.localeCompare(right))
.map(([id, groupedTools]) => ({
id,
tools: groupedTools.toSorted((left, right) => left.name.localeCompare(right.name)),
}));
const groupsById = new Map(groups.map((group) => [group.id, group]));
return {
ids: groups.map(({ id }) => id),
resolve(groupIds: readonly string[]): AssistantMcpToolGroup<TTool>[] {
return [...new Set(groupIds)].map((groupId) => {
const group = groupsById.get(groupId);
if (!group) throw new Error(`Unknown Assistant MCP tool group '${groupId}'`);
return group;
});
},
};
};