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;" />

398 lines (396 loc) 13.6 kB
require("reflect-metadata"); const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs'); const require_runtime$1 = require('./runtime.cjs'); const require_channel_manager = require('./channel-manager.cjs'); const require_hooks = require('./hooks.cjs'); const require_fetch_cors = require('./fetch-cors.cjs'); const require_fetch_router = require('./fetch-router.cjs'); const require_middleware = require('./middleware.cjs'); const require_handle_run = require('../handlers/handle-run.cjs'); const require_handle_suggest = require('../handlers/handle-suggest.cjs'); const require_handle_connect = require('../handlers/handle-connect.cjs'); const require_handle_stop = require('../handlers/handle-stop.cjs'); const require_get_runtime_info = require('../handlers/get-runtime-info.cjs'); const require_handle_transcribe = require('../handlers/handle-transcribe.cjs'); const require_handle_debug_events = require('../handlers/handle-debug-events.cjs'); const require_threads = require('../handlers/intelligence/threads.cjs'); const require_memories = require('../handlers/intelligence/memories.cjs'); const require_annotate = require('../handlers/intelligence/annotate.cjs'); const require_single_route_helpers = require('../endpoints/single-route-helpers.cjs'); const require_instance_created = require('../telemetry/instance-created.cjs'); let _copilotkit_shared = require("@copilotkit/shared"); //#region src/v2/runtime/core/fetch-handler.ts /** * Managed Channel managers keyed by runtime instance. Guarantees a single * manager (and thus a single activation) per runtime: creating the handler more * than once for the same runtime reuses the existing manager instead of * constructing a second one. */ const channelManagers = /* @__PURE__ */ new WeakMap(); /** * Look up (or lazily CREATE) the {@link ChannelManager} for an Intelligence * runtime. First creation constructs the manager and caches it; subsequent * lookups reuse the cached instance so there is exactly one manager per runtime. * * Activation is NOT triggered here. Constructing the manager opens no * transport — the persistent gateway socket is opened lazily on the first * {@link ChannelManager.ready} call (see the factory TSDoc). This keeps the * generic Fetch handler serverless/edge-safe: creating it (e.g. at * Cloudflare-Worker module scope or per Next.js App Router isolate) never * performs network I/O and never mints a listener the host cannot own. * * Caching the un-activated manager is correct: a later `ready()` activates it * once (idempotently), and an up-front misconfiguration (duplicate/missing * channel names) surfaces as a rejected `ready()` rather than a throw at * creation. A manager that has been {@link ChannelManager.stop}ped stays * stopped on reuse — its latches short-circuit any later `activate()`/`ready()`. * * @param runtime - The Intelligence runtime whose Channels the manager drives. * @param engine - Optional injected activation engine (test seam); when * omitted the manager uses its default Realtime Gateway engine. * @returns The runtime's (un-activated) Channel manager. */ function getOrCreateChannelManager(runtime, engine) { const existing = channelManagers.get(runtime); if (existing) return existing; const manager = new require_channel_manager.ChannelManager({ intelligence: runtime.intelligence, channels: runtime.channels, log: (msg, meta) => _copilotkit_shared.logger.warn(meta instanceof Error ? { err: meta } : { meta }, msg), ...engine ? { activateChannel: engine } : {} }); channelManagers.set(runtime, manager); return manager; } function createCopilotRuntimeHandler(options) { const { runtime, basePath, mode = "multi-route", cors, hooks } = options; require_instance_created.fireInstanceCreatedTelemetry({ runtime }); const corsConfig = resolveCorsConfig(cors); const handler = async (request) => { const path = new URL(request.url, "http://localhost").pathname; const requestOrigin = request.headers.get("origin"); const baseCtx = { request, path, runtime }; let route; try { if (corsConfig) { const preflight = require_fetch_cors.handleCors(request, corsConfig); if (preflight) return preflight; } request = await require_hooks.runOnRequest(hooks, { ...baseCtx, request }); try { const maybeModified = await require_middleware.callBeforeRequestMiddleware({ runtime, request, path }); if (maybeModified) request = maybeModified; } catch (mwError) { _copilotkit_shared.logger.error({ err: mwError, url: request.url, path }, "Error running before request middleware"); if (mwError instanceof Response) return maybeAddCors(mwError, corsConfig, requestOrigin); throw mwError; } let response; if (mode === "single-route") { const resolved = await resolveSingleRoute(request, basePath, path); route = resolved.route; const { methodCall } = resolved; request = await require_hooks.runOnBeforeHandler(hooks, { request, path, runtime, route }); if (route.method === "agent/run" || route.method === "agent/suggest" || route.method === "agent/connect" || route.method === "transcribe") request = require_single_route_helpers.createJsonRequest(request, methodCall.body); response = await dispatchRoute(runtime, request, route, { threadEndpointsEnabled: false }); } else { const matched = require_fetch_router.matchRoute(path, basePath); if (!matched) throw jsonResponse({ error: "Not found" }, 404); const methodError = validateHttpMethod(request.method, matched); if (methodError) { route = matched; throw methodError; } route = matched; request = await require_hooks.runOnBeforeHandler(hooks, { request, path, runtime, route }); response = await dispatchRoute(runtime, request, route, { threadEndpointsEnabled: true }); } response = await require_hooks.runOnResponse(hooks, { request, response, path, runtime, route }); response = maybeAddCors(response, corsConfig, requestOrigin); require_middleware.callAfterRequestMiddleware({ runtime, response: response.clone(), path }).catch((error) => { _copilotkit_shared.logger.error({ err: error, url: request.url, path }, "Error running after request middleware"); }); return response; } catch (error) { if (error instanceof Response) return maybeAddCors(await require_hooks.runOnResponse(hooks, { request, response: error, path, runtime, route: route ?? { method: "info" } }), corsConfig, requestOrigin); try { const errorResponse = await require_hooks.runOnError(hooks, { request, error, path, runtime, route }); if (errorResponse) return maybeAddCors(errorResponse, corsConfig, requestOrigin); } catch (hookError) { _copilotkit_shared.logger.error({ err: hookError, originalErr: error, url: request.url, path }, "onError hook threw"); } _copilotkit_shared.logger.error({ err: error, url: request.url, path }, "Unhandled error in CopilotKit runtime handler"); return maybeAddCors(jsonResponse({ error: "internal_error" }, 500), corsConfig, requestOrigin); } }; if (require_runtime$1.isIntelligenceRuntime(runtime) && runtime.channels && runtime.channels.length > 0 && options.activateChannels !== false) handler.channels = getOrCreateChannelManager(runtime, options.__channelEngine); return handler; } function dispatchRoute(runtime, request, route, options) { switch (route.method) { case "agent/run": return require_handle_run.handleRunAgent({ runtime, request, agentId: route.agentId }); case "agent/suggest": return require_handle_suggest.handleSuggestAgent({ runtime, request, agentId: route.agentId }); case "agent/connect": return require_handle_connect.handleConnectAgent({ runtime, request, agentId: route.agentId }); case "agent/stop": return require_handle_stop.handleStopAgent({ runtime, request, agentId: route.agentId, threadId: route.threadId }); case "info": return require_get_runtime_info.handleGetRuntimeInfo({ runtime, request, threadEndpointsEnabled: options.threadEndpointsEnabled }); case "transcribe": return require_handle_transcribe.handleTranscribe({ runtime, request }); case "threads/clear": return Promise.resolve(require_threads.handleClearThreads({ runtime, request })); case "threads/list": return require_threads.handleListThreads({ runtime, request }); case "memories/list": return request.method.toUpperCase() === "POST" ? require_memories.handleCreateMemory({ runtime, request }) : require_memories.handleListMemories({ runtime, request }); case "memories/subscribe": return require_memories.handleSubscribeToMemories({ runtime, request }); case "memories/mutate": return request.method.toUpperCase() === "DELETE" ? require_memories.handleRemoveMemory({ runtime, request, memoryId: route.memoryId }) : require_memories.handleUpdateMemory({ runtime, request, memoryId: route.memoryId }); case "threads/subscribe": return require_threads.handleSubscribeToThreads({ runtime, request }); case "threads/update": if (request.method.toUpperCase() === "DELETE") return require_threads.handleDeleteThread({ runtime, request, threadId: route.threadId }); return require_threads.handleUpdateThread({ runtime, request, threadId: route.threadId }); case "threads/archive": return require_threads.handleArchiveThread({ runtime, request, threadId: route.threadId }); case "threads/messages": return require_threads.handleGetThreadMessages({ runtime, request, threadId: route.threadId }); case "threads/events": return require_threads.handleGetThreadEvents({ runtime, request, threadId: route.threadId }); case "threads/state": return require_threads.handleGetThreadState({ runtime, request, threadId: route.threadId }); case "annotate": return require_annotate.handleAnnotate({ runtime, request }); case "cpk-debug-events": return Promise.resolve(require_handle_debug_events.handleDebugEvents({ runtime, request })); default: throw jsonResponse({ error: "Not found", method: route.method }, 404); } } async function resolveSingleRoute(request, basePath, pathname) { if (basePath) { const normalizedBase = basePath.length > 1 && basePath.endsWith("/") ? basePath.slice(0, -1) : basePath; if (!pathname.startsWith(normalizedBase)) throw jsonResponse({ error: "Not found" }, 404); } if (request.method !== "POST") throw jsonResponse({ error: "Method not allowed" }, 405, { Allow: "POST" }); const methodCall = await require_single_route_helpers.parseMethodCall(request); let route; switch (methodCall.method) { case "agent/run": route = { method: "agent/run", agentId: require_single_route_helpers.expectString(methodCall.params, "agentId") }; break; case "agent/suggest": route = { method: "agent/suggest", agentId: require_single_route_helpers.expectString(methodCall.params, "agentId") }; break; case "agent/connect": route = { method: "agent/connect", agentId: require_single_route_helpers.expectString(methodCall.params, "agentId") }; break; case "agent/stop": route = { method: "agent/stop", agentId: require_single_route_helpers.expectString(methodCall.params, "agentId"), threadId: require_single_route_helpers.expectString(methodCall.params, "threadId") }; break; case "info": route = { method: "info" }; break; case "transcribe": route = { method: "transcribe" }; break; default: { const _exhaustive = methodCall.method; throw jsonResponse({ error: "Not found", method: _exhaustive }, 404); } } return { route, methodCall }; } function validateHttpMethod(httpMethod, route) { const method = httpMethod.toUpperCase(); switch (route.method) { case "info": case "threads/list": case "threads/messages": case "threads/events": case "threads/state": case "cpk-debug-events": if (method === "GET") return null; return jsonResponse({ error: "Method not allowed" }, 405, { Allow: "GET" }); case "memories/list": if (method === "GET" || method === "POST") return null; return jsonResponse({ error: "Method not allowed" }, 405, { Allow: "GET, POST" }); case "memories/mutate": if (method === "PATCH" || method === "DELETE") return null; return jsonResponse({ error: "Method not allowed" }, 405, { Allow: "PATCH, DELETE" }); case "threads/update": if (method === "PATCH" || method === "DELETE") return null; return jsonResponse({ error: "Method not allowed" }, 405, { Allow: "PATCH, DELETE" }); default: if (method === "POST") return null; return jsonResponse({ error: "Method not allowed" }, 405, { Allow: "POST" }); } } function resolveCorsConfig(cors) { if (!cors) return null; if (cors === true) return {}; return cors; } function maybeAddCors(response, config, requestOrigin) { if (!config) return response; return require_fetch_cors.addCorsHeaders(response, config, requestOrigin); } function jsonResponse(body, status, extraHeaders) { return new Response(JSON.stringify(body), { status, headers: { "Content-Type": "application/json", ...extraHeaders } }); } //#endregion exports.createCopilotRuntimeHandler = createCopilotRuntimeHandler; //# sourceMappingURL=fetch-handler.cjs.map