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

82 lines (80 loc) 3.71 kB
import "reflect-metadata"; import { mergeForwardableHeaders, resolveForwardHeadersPolicy } from "./header-utils.mjs"; import { cloneAgentForRequest, parseRunRequest } from "./shared/agent-utils.mjs"; import { createSseEventResponse } from "./shared/sse-response.mjs"; import { finalizeRunEvents } from "@copilotkit/shared"; import { Observable } from "rxjs"; //#region src/v2/runtime/handlers/handle-suggest.ts /** * Stateless suggestion run. * * Executes the provider agent **directly** and streams its AG-UI events back as * SSE — the same wire format as `/agent/:id/run`, so the client consumes it with * the stock `HttpAgent` transport and chips fill in as the provider emits them. * It deliberately does not go through `runtime.runner`: the runner's * `run()` writes to a module-level store keyed by threadId (backing the SSE * runtime's local thread endpoints), which would leak the throwaway suggestion * thread. This handler runs the agent's event pipeline **without** that * persistence — no thread, lock, gateway, name-gen, or run telemetry — so * dynamic suggestions are side-effect-free in every runtime mode. * * The only per-request configuration it applies is forwarding the request's * allowlisted headers (`authorization` + `x-*`) onto the agent clone. It does * **not** attach any request middleware — no A2UI, no MCPApps, no * OpenGenerativeUI, no Intelligence enterprise-learning tools. The **client** * (the core suggestion engine) forces `toolChoice: copilotkitSuggest` in the * request body; this handler does not set tool choice itself and relies on it * being present in the incoming `input`. Given that forced tool choice, any * middleware-injected tools are dead weight, and MCPApps setup can incur a * `listTools` network round-trip per suggestion under `available: "always"` — a * side effect this path must never pay. * * When the client aborts the HTTP request (via its `AbortController`), the * server-side run is cancelled best-effort so an aborted suggestion does not * keep running a provider call to completion. * * @param params - The runtime, request, and resolved agent id. * @returns A `text/event-stream` `Response` of the provider agent's AG-UI events * on success, or the resolution `Response` (e.g. 404/400) when agent/body * resolution fails before streaming begins. */ async function handleSuggestAgent({ runtime, request, agentId }) { const agent = await cloneAgentForRequest(runtime, agentId, request); if (agent instanceof Response) return agent; agent.agentId = agentId; const input = await parseRunRequest(request); if (input instanceof Response) return input; const headerCarryingAgent = agent; headerCarryingAgent.headers = mergeForwardableHeaders(headerCarryingAgent.headers, request, runtime.forwardHeadersPolicy ?? resolveForwardHeadersPolicy(void 0)); agent.setMessages(input.messages); agent.setState(input.state); agent.threadId = input.threadId; return createSseEventResponse({ request, agentId, captureTelemetry: false, observableFactory: () => new Observable((subscriber) => { const collected = []; let settled = false; agent.runAgent(input, { onEvent: ({ event }) => { collected.push(event); subscriber.next(event); } }).then(() => { for (const event of finalizeRunEvents(collected, { stopRequested: false })) subscriber.next(event); settled = true; subscriber.complete(); }).catch((error) => { settled = true; subscriber.error(error); }); return () => { if (!settled && typeof agent.abortRun === "function") try { agent.abortRun(); } catch {} }; }) }); } //#endregion export { handleSuggestAgent }; //# sourceMappingURL=handle-suggest.mjs.map