/
alexefan136
/
flowstack
Обзор
Документация
Войти
/
alexefan136
/
flowstack
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
ui/src/lib/tools-api.ts
359 строк
9 KB
Alexander Efanov
Обновление репозитория
15 июл 2026, 12:19
15 июл 2026, 12:19
76704c6
Код
Авторство
О чём код?
// src/lib/tools-api.ts import { getAuthHeaders } from './stores/auth-store'; import type { ToolInfo, ToolCallRequest, ToolCallResult, ToolsStats, MCPBundleInfo, MCPJsonRpcRequest, MCPJsonRpcResponse, MCPInitializeResult, MCPToolsListResult, MCPToolsCallResult, MCPResourcesListResult, MCPPromptsListResult, } from './types/tool-types'; // ✅ Импортируем TOOL_CONSTANTS как value (без 'type') import { TOOL_CONSTANTS } from './types/tool-types'; const API_BASE = 'http://localhost:8080'; // ============================================================================ // Helpers // ============================================================================ function getRequestHeaders(workspaceId?: string): Record<string, string> { return { 'Content-Type': 'application/json', ...getAuthHeaders(), ...(workspaceId ? { 'X-Workspace-ID': workspaceId } : {}), }; } async function extractErrorMessage(res: Response): Promise<string> { try { const text = await res.text(); const data = JSON.parse(text); if (typeof data === 'string') return data; if (data.detail) { if (typeof data.detail === 'string') return data.detail; return data.detail.message || data.detail.error || JSON.stringify(data.detail); } if (data.error) { if (typeof data.error === 'string') return data.error; return data.error.message || JSON.stringify(data.error); } if (data.message) return data.message; return JSON.stringify(data); } catch { return `Ошибка ${res.status}`; } } // ============================================================================ // Tools Registry API // ============================================================================ /** * Получить список всех доступных tools (встроенных и MCP). */ export async function fetchTools(workspaceId: string): Promise<ToolInfo[]> { const res = await fetch(`${API_BASE}/api/v1/tools`, { headers: getRequestHeaders(workspaceId), }); if (!res.ok) { throw new Error(`Failed to fetch tools: ${await extractErrorMessage(res)}`); } return res.json(); } /** * Быстрый список имён tools (без полной информации). */ export async function fetchToolNames(workspaceId: string): Promise<string[]> { const res = await fetch(`${API_BASE}/api/v1/tools/names`, { headers: getRequestHeaders(workspaceId), }); if (!res.ok) { throw new Error(`Failed to fetch tool names: ${await extractErrorMessage(res)}`); } const data = await res.json(); return data.tools || []; } /** * Получить статистику Tool Registry. */ export async function fetchToolsStats(workspaceId: string): Promise<ToolsStats> { const res = await fetch(`${API_BASE}/api/v1/tools/stats`, { headers: getRequestHeaders(workspaceId), }); if (!res.ok) { throw new Error(`Failed to fetch tools stats: ${await extractErrorMessage(res)}`); } return res.json(); } /** * Получить детальную информацию о конкретном tool. */ export async function fetchTool( toolName: string, workspaceId: string ): Promise<ToolInfo> { const res = await fetch(`${API_BASE}/api/v1/tools/${encodeURIComponent(toolName)}`, { headers: getRequestHeaders(workspaceId), }); if (!res.ok) { throw new Error(`Failed to fetch tool: ${await extractErrorMessage(res)}`); } return res.json(); } /** * Вызвать tool по имени с аргументами. */ export async function callTool( data: ToolCallRequest, workspaceId: string ): Promise<ToolCallResult> { const res = await fetch(`${API_BASE}/api/v1/tools/call`, { method: 'POST', headers: getRequestHeaders(workspaceId), body: JSON.stringify(data), }); if (!res.ok) { throw new Error(`Failed to call tool: ${await extractErrorMessage(res)}`); } return res.json(); } // ============================================================================ // MCP Bundles Management API // ============================================================================ /** * Получить список MCP bundles с их статусами. * ✅ ИСПРАВЛЕНО: убран пробел в имени функции */ export async function fetchMCPBundles(workspaceId: string): Promise<MCPBundleInfo[]> { const res = await fetch(`${API_BASE}/api/v1/tools/bundles`, { headers: getRequestHeaders(workspaceId), }); if (!res.ok) { throw new Error(`Failed to fetch MCP bundles: ${await extractErrorMessage(res)}`); } return res.json(); } /** * Включить MCP bundle. */ export async function enableMCPBundle( bundleName: string, workspaceId: string ): Promise<{ success: boolean; bundle: string; message: string }> { const res = await fetch( `${API_BASE}/api/v1/tools/bundles/${encodeURIComponent(bundleName)}/enable`, { method: 'POST', headers: getRequestHeaders(workspaceId), } ); if (!res.ok) { throw new Error(`Failed to enable bundle: ${await extractErrorMessage(res)}`); } return res.json(); } /** * Отключить MCP bundle. */ export async function disableMCPBundle( bundleName: string, workspaceId: string ): Promise<{ success: boolean; bundle: string; message: string }> { const res = await fetch( `${API_BASE}/api/v1/tools/bundles/${encodeURIComponent(bundleName)}/disable`, { method: 'POST', headers: getRequestHeaders(workspaceId), } ); if (!res.ok) { throw new Error(`Failed to disable bundle: ${await extractErrorMessage(res)}`); } return res.json(); } // ============================================================================ // MCP JSON-RPC 2024-11-05 API // ============================================================================ /** * Выполнить MCP JSON-RPC запрос. * * Низкоуровневая функция. Используйте специализированные методы ниже. */ export async function mcpJsonRpc<T = unknown>( request: MCPJsonRpcRequest, workspaceId: string ): Promise<MCPJsonRpcResponse & { result?: T }> { const res = await fetch(`${API_BASE}/api/v1/tools/mcp`, { method: 'POST', headers: getRequestHeaders(workspaceId), body: JSON.stringify(request), }); if (!res.ok) { throw new Error(`MCP JSON-RPC failed: ${await extractErrorMessage(res)}`); } return res.json(); } /** * MCP initialize — handshake. */ export async function mcpInitialize( clientName: string, clientVersion: string, workspaceId: string ): Promise<MCPInitializeResult> { const response = await mcpJsonRpc<MCPInitializeResult>( { jsonrpc: '2.0', id: 1, method: 'initialize', params: { // ✅ Теперь TOOL_CONSTANTS доступен как value protocolVersion: TOOL_CONSTANTS.MCP_PROTOCOL_VERSION, clientInfo: { name: clientName, version: clientVersion, }, }, }, workspaceId ); if (response.error) { throw new Error(`MCP initialize error: ${response.error.message}`); } return response.result!; } /** * MCP tools/list — список всех tools. */ export async function mcpListTools(workspaceId: string): Promise<MCPToolsListResult> { const response = await mcpJsonRpc<MCPToolsListResult>( { jsonrpc: '2.0', id: 2, method: 'tools/list', params: {}, }, workspaceId ); if (response.error) { throw new Error(`MCP tools/list error: ${response.error.message}`); } return response.result!; } /** * MCP tools/call — вызвать tool. */ export async function mcpCallTool( toolName: string, args: Record<string, unknown>, workspaceId: string ): Promise<MCPToolsCallResult> { const response = await mcpJsonRpc<MCPToolsCallResult>( { jsonrpc: '2.0', id: 3, method: 'tools/call', params: { name: toolName, arguments: args, }, }, workspaceId ); if (response.error) { throw new Error(`MCP tools/call error: ${response.error.message}`); } return response.result!; } /** * MCP resources/list — список всех resources. */ export async function mcpListResources( workspaceId: string ): Promise<MCPResourcesListResult> { const response = await mcpJsonRpc<MCPResourcesListResult>( { jsonrpc: '2.0', id: 4, method: 'resources/list', params: {}, }, workspaceId ); if (response.error) { throw new Error(`MCP resources/list error: ${response.error.message}`); } return response.result!; } /** * MCP prompts/list — список всех prompts. */ export async function mcpListPrompts( workspaceId: string ): Promise<MCPPromptsListResult> { const response = await mcpJsonRpc<MCPPromptsListResult>( { jsonrpc: '2.0', id: 5, method: 'prompts/list', params: {}, }, workspaceId ); if (response.error) { throw new Error(`MCP prompts/list error: ${response.error.message}`); } return response.result!; }