UNPKG

@copilotkit/runtime

Version:

<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />

283 lines (281 loc) • 11.7 kB
import "reflect-metadata"; import { aguiToGQL } from "../../graphql/message-conversion/agui-to-gql.mjs"; import { logRuntimeTelemetryDisclosure } from "../telemetry-disclosure.mjs"; import { InMemoryAgentRunner } from "../../v2/runtime/runner/in-memory.mjs"; import { CopilotRuntime as CopilotRuntime$1 } from "../../v2/runtime/core/runtime.mjs"; import { TelemetryAgentRunner } from "./telemetry-agent-runner.mjs"; import { EndpointType } from "./types.mjs"; import { extractParametersFromSchema } from "./mcp-tools-utils.mjs"; import { BuiltInAgent } from "../../agent/index.mjs"; import telemetryClient from "../telemetry-client.mjs"; import { CopilotKitMisuseError, getZodParameters, isTelemetryDisabled, readBody } from "@copilotkit/shared"; //#region src/lib/runtime/copilot-runtime.ts /** * <Callout type="info"> * This is the reference for the `CopilotRuntime` class. For more information and example code snippets, please see [Concept: Copilot Runtime](/concepts/copilot-runtime). * </Callout> * * ## Usage * * ```tsx * import { CopilotRuntime } from "@copilotkit/runtime"; * * const copilotKit = new CopilotRuntime(); * ``` */ /** * Central runtime object passed to all request handlers. */ var CopilotRuntime = class { constructor(params) { this.mcpToolsCache = /* @__PURE__ */ new Map(); logRuntimeTelemetryDisclosure(); const agents = params?.agents ?? {}; const endpointAgents = this.assignEndpointsToAgents(params?.remoteEndpoints ?? []); let mergedAgents; if (typeof agents === "function") mergedAgents = async (ctx) => { const resolved = await agents(ctx); return { ...endpointAgents, ...resolved }; }; else mergedAgents = Promise.resolve(agents).then((resolved) => ({ ...endpointAgents, ...resolved })); const baseRunner = params?.runner ?? new InMemoryAgentRunner(); const runner = isTelemetryDisabled() ? baseRunner : new TelemetryAgentRunner({ runner: baseRunner }); const resolvedLicenseToken = params?.licenseToken ?? process.env.COPILOTKIT_LICENSE_TOKEN; if (resolvedLicenseToken) telemetryClient.setLicenseToken(resolvedLicenseToken); this.runtimeArgs = { agents: mergedAgents, runner, licenseToken: params?.licenseToken, debug: params?.debug, beforeRequestMiddleware: this.createOnBeforeRequestHandler(params).bind(this), ...params?.afterRequestMiddleware || params?.middleware?.onAfterRequest ? { afterRequestMiddleware: this.createOnAfterRequestHandler(params).bind(this) } : {}, a2ui: params?.a2ui, mcpApps: params?.mcpApps, openGenerativeUI: params?.openGenerativeUI }; this.params = params; this.observability = params?.observability_c; } get instance() { if (!this._instance) this._instance = new CopilotRuntime$1(this.runtimeArgs); return this._instance; } assignEndpointsToAgents(endpoints) { let result = {}; if (endpoints.some((endpoint) => resolveEndpointType(endpoint) == EndpointType.LangGraphPlatform)) throw new CopilotKitMisuseError({ message: "LangGraphPlatformEndpoint in remoteEndpoints is deprecated. Please use the \"agents\" option instead with LangGraphAgent from \"@copilotkit/runtime/langgraph\". Example: agents: { myAgent: new LangGraphAgent({ deploymentUrl: \"...\", graphId: \"...\" }) }" }); return result; } handleServiceAdapter(serviceAdapter) { this.runtimeArgs.agents = Promise.resolve(this.runtimeArgs.agents ?? {}).then(async (agents) => { let agentsList = agents; const isAgentsListEmpty = !Object.keys(agents).length; const hasServiceAdapter = Boolean(serviceAdapter); const serviceAdapterCanBeUsedForAgent = !["EmptyAdapter"].includes(serviceAdapter.name); if (isAgentsListEmpty && (!hasServiceAdapter || !serviceAdapterCanBeUsedForAgent)) throw new CopilotKitMisuseError({ message: "No default agent provided. Please provide a default agent in the runtime config." }); if (isAgentsListEmpty) { const languageModel = serviceAdapter.getLanguageModel?.(); if (languageModel) agentsList.default = new BuiltInAgent({ model: languageModel }); else if (serviceAdapter.provider && serviceAdapter.model) agentsList.default = new BuiltInAgent({ model: `${serviceAdapter.provider}/${serviceAdapter.model}` }); else throw new CopilotKitMisuseError({ message: `Service adapter "${serviceAdapter.name ?? "unknown"}" does not provide model information. When using adapters like LangChainAdapter without an explicit agents list, please provide a default agent in the runtime config. Example:\n new CopilotRuntime({\n agents: { default: new BuiltInAgent({ model: "openai/gpt-4o" }) }\n })` }); } const actions = this.params?.actions; if (actions) { const mcpTools = await this.getToolsFromMCP(); agentsList = this.assignToolsToAgents(agents, [...this.getToolsFromActions(actions), ...mcpTools]); } return agentsList; }); } getToolsFromActions(actions) { return (typeof actions === "function" ? actions({ properties: {}, url: void 0 }) : actions).map((action) => { const zodSchema = getZodParameters(action.parameters || []); return { name: action.name, description: action.description || "", parameters: zodSchema, execute: () => Promise.resolve() }; }); } assignToolsToAgents(agents, tools) { if (!tools?.length) return agents; const enrichedAgents = { ...agents }; for (const [agentId, agent] of Object.entries(enrichedAgents)) { const existingConfig = Reflect.get(agent, "config") ?? {}; if ("factory" in existingConfig) continue; const classicConfig = existingConfig; const existingTools = classicConfig.tools ?? []; const updatedConfig = { ...classicConfig, tools: [...existingTools, ...tools] }; Reflect.set(agent, "config", updatedConfig); enrichedAgents[agentId] = agent; } return enrichedAgents; } createOnBeforeRequestHandler(params) { return async (hookParams) => { const { request } = hookParams; const publicApiKey = request.headers.get("x-copilotcloud-public-api-key"); const body = await readBody(request); const forwardedProps = body?.forwardedProps; const cloudBaseUrl = process.env.COPILOT_CLOUD_BASE_URL || "https://api.cloud.copilotkit.ai"; telemetryClient.capture("oss.runtime.copilot_request_created", { "cloud.guardrails.enabled": forwardedProps?.cloud?.guardrails !== void 0, requestType: forwardedProps?.metadata?.requestType ?? "unknown", "cloud.api_key_provided": !!publicApiKey, ...publicApiKey ? { "cloud.public_api_key": publicApiKey } : {}, "cloud.base_url": cloudBaseUrl }); if (request.method === "GET" || !body) return; const middlewareResult = await params?.beforeRequestMiddleware?.(hookParams); if (params?.middleware?.onBeforeRequest) { const { request, runtime, path } = hookParams; const { inputMessages, outputMessages } = aguiToGQL(body.messages).reduce((acc, msg) => { if ("role" in msg && msg.role === "user") acc.inputMessages.push(msg); else acc.outputMessages.push(msg); return acc; }, { inputMessages: [], outputMessages: [] }); params.middleware.onBeforeRequest({ threadId: body.threadId, runId: body.runId, inputMessages, properties: body.forwardedProps, url: request.url }); } return middlewareResult; }; } createOnAfterRequestHandler(params) { return async (hookParams) => { params?.afterRequestMiddleware?.(hookParams); if (params?.middleware?.onAfterRequest) { const messages = hookParams.messages ?? []; params.middleware.onAfterRequest({ threadId: hookParams.threadId ?? "", runId: hookParams.runId, inputMessages: messages.filter((m) => "role" in m && m.role === "user"), outputMessages: messages.filter((m) => "role" in m && m.role !== "user"), properties: {}, url: hookParams.path }); } }; } /** * Log LLM request if observability is enabled */ async logObservabilityBeforeRequest(requestData) { try { await this.observability.hooks.handleRequest(requestData); } catch (error) { console.error("Error logging LLM request:", error); } } /** * Log final LLM response after request completes */ logObservabilityAfterRequest(outputMessagesPromise, baseData, streamedChunks, requestStartTime, publicApiKey) { try { outputMessagesPromise.then((outputMessages) => { const responseData = { threadId: baseData.threadId, runId: baseData.runId, model: baseData.model, output: this.observability.progressive ? streamedChunks : outputMessages, latency: Date.now() - requestStartTime, timestamp: Date.now(), provider: baseData.provider, isFinalResponse: true, agentName: baseData.agentName, nodeName: baseData.nodeName }; try { this.observability.hooks.handleResponse(responseData); } catch (logError) { console.error("Error logging LLM response:", logError); } }).catch((error) => { console.error("Failed to get output messages for logging:", error); }); } catch (error) { console.error("Error setting up logging for LLM response:", error); } } async getToolsFromMCP(options) { const runtimeMcpServers = this.params?.mcpServers ?? []; const createMCPClient = this.params?.createMCPClient; const requestMcpServers = (options?.properties)?.mcpServers ?? (options?.properties)?.mcpEndpoints ?? []; if (!((runtimeMcpServers?.length ?? 0) > 0 || (requestMcpServers?.length ?? 0) > 0)) return []; if (!createMCPClient) throw new CopilotKitMisuseError({ message: "MCP Integration Error: `mcpServers` were provided, but the `createMCPClient` function was not passed to the CopilotRuntime constructor. Please provide an implementation for `createMCPClient`." }); const effectiveEndpoints = (() => { const byUrl = /* @__PURE__ */ new Map(); for (const ep of runtimeMcpServers) if (ep?.endpoint) byUrl.set(ep.endpoint, ep); for (const ep of requestMcpServers) if (ep?.endpoint) byUrl.set(ep.endpoint, ep); return Array.from(byUrl.values()); })(); const allTools = []; for (const config of effectiveEndpoints) { const endpointUrl = config.endpoint; const cached = this.mcpToolsCache.get(endpointUrl); if (cached) { allTools.push(...cached); continue; } try { const toolsMap = await (await createMCPClient(config)).tools(); const toolDefs = Object.entries(toolsMap).map(([toolName, tool]) => { const zodSchema = getZodParameters(extractParametersFromSchema(tool)); return { name: toolName, description: tool.description || `MCP tool: ${toolName} (from ${endpointUrl})`, parameters: zodSchema, execute: () => Promise.resolve() }; }); this.mcpToolsCache.set(endpointUrl, toolDefs); allTools.push(...toolDefs); } catch (error) { console.error(`MCP: Failed to fetch tools from endpoint ${endpointUrl}. Skipping. Error:`, error); this.mcpToolsCache.set(endpointUrl, []); } } const dedupedByName = /* @__PURE__ */ new Map(); for (const tool of allTools) dedupedByName.set(tool.name, tool); return Array.from(dedupedByName.values()); } }; function copilotKitEndpoint(config) { return { ...config, type: EndpointType.CopilotKit }; } function langGraphPlatformEndpoint(config) { return { ...config, type: EndpointType.LangGraphPlatform }; } function resolveEndpointType(endpoint) { if (!endpoint.type) if ("deploymentUrl" in endpoint && "agents" in endpoint) return EndpointType.LangGraphPlatform; else return EndpointType.CopilotKit; return endpoint.type; } //#endregion export { CopilotRuntime, copilotKitEndpoint, langGraphPlatformEndpoint, resolveEndpointType }; //# sourceMappingURL=copilot-runtime.mjs.map