@copilotkit/runtime 1.67.0 → 1.68.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.cjs +5 -0
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +2 -1
- package/dist/agent/index.d.cts.map +1 -1
- package/dist/agent/index.d.mts +2 -1
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +5 -0
- package/dist/agent/index.mjs.map +1 -1
- package/dist/lib/integrations/node-http/request-handler.cjs +1 -2
- package/dist/lib/integrations/node-http/request-handler.cjs.map +1 -1
- package/dist/lib/integrations/node-http/request-handler.mjs +1 -2
- package/dist/lib/integrations/node-http/request-handler.mjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.cjs +25 -4
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts +14 -3
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts +14 -3
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +25 -4
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/package.cjs +2 -2
- package/dist/runtime/package.mjs +2 -2
- package/dist/v2/index.d.cts +2 -1
- package/dist/v2/index.d.mts +2 -1
- package/dist/v2/runtime/core/channel-manager.cjs +14 -2
- package/dist/v2/runtime/core/channel-manager.cjs.map +1 -1
- package/dist/v2/runtime/core/channel-manager.d.cts.map +1 -1
- package/dist/v2/runtime/core/channel-manager.d.mts +1 -0
- package/dist/v2/runtime/core/channel-manager.d.mts.map +1 -1
- package/dist/v2/runtime/core/channel-manager.mjs +14 -2
- package/dist/v2/runtime/core/channel-manager.mjs.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.cjs +1 -0
- package/dist/v2/runtime/core/fetch-handler.cjs.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.d.cts.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.d.mts.map +1 -1
- package/dist/v2/runtime/core/fetch-handler.mjs +1 -0
- package/dist/v2/runtime/core/fetch-handler.mjs.map +1 -1
- package/dist/v2/runtime/core/learning.cjs +21 -0
- package/dist/v2/runtime/core/learning.cjs.map +1 -0
- package/dist/v2/runtime/core/learning.d.cts +27 -0
- package/dist/v2/runtime/core/learning.d.cts.map +1 -0
- package/dist/v2/runtime/core/learning.d.mts +27 -0
- package/dist/v2/runtime/core/learning.d.mts.map +1 -0
- package/dist/v2/runtime/core/learning.mjs +19 -0
- package/dist/v2/runtime/core/learning.mjs.map +1 -0
- package/dist/v2/runtime/core/runtime-error-reporter.cjs +72 -0
- package/dist/v2/runtime/core/runtime-error-reporter.cjs.map +1 -0
- package/dist/v2/runtime/core/runtime-error-reporter.mjs +67 -0
- package/dist/v2/runtime/core/runtime-error-reporter.mjs.map +1 -0
- package/dist/v2/runtime/core/runtime.cjs +11 -0
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +8 -0
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +8 -0
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +11 -0
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.cjs +14 -2
- package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.mjs +14 -2
- package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/annotate.cjs +1 -1
- package/dist/v2/runtime/handlers/intelligence/annotate.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/annotate.mjs +1 -1
- package/dist/v2/runtime/handlers/intelligence/annotate.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.cjs +51 -8
- package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.mjs +51 -8
- package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.cjs +24 -1
- package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs +24 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/connect.cjs +1 -0
- package/dist/v2/runtime/handlers/sse/connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/connect.mjs +1 -0
- package/dist/v2/runtime/handlers/sse/connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/run.cjs +4 -1
- package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/run.mjs +4 -1
- package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -1
- package/dist/v2/runtime/index.d.cts +1 -0
- package/dist/v2/runtime/index.d.cts.map +1 -1
- package/dist/v2/runtime/index.d.mts +1 -0
- package/dist/v2/runtime/index.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.cjs +6 -4
- package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.cts +10 -7
- package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.d.mts +10 -7
- package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
- package/dist/v2/runtime/intelligence-platform/client.mjs +6 -4
- package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.cjs.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.d.cts +1 -0
- package/dist/v2/runtime/runner/agent-runner.d.cts.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.d.mts +1 -0
- package/dist/v2/runtime/runner/agent-runner.d.mts.map +1 -1
- package/dist/v2/runtime/runner/agent-runner.mjs.map +1 -1
- package/package.json +6 -6
- package/skills/runtime/SKILL.md +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.cjs","names":["resolveIntelligenceUser","isHandlerResponse","generateThreadNameForNewThread","EventType"],"sources":["../../../../../src/v2/runtime/handlers/intelligence/run.ts"],"sourcesContent":["import type {\n AbstractAgent,\n BaseEvent,\n Message,\n RunAgentInput,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport { generateThreadNameForNewThread } from \"./thread-names\";\nimport { logger } from \"@copilotkit/shared\";\nimport { telemetry } from \"../../telemetry\";\nimport { resolveIntelligenceUser } from \"../shared/resolve-intelligence-user\";\nimport { isHandlerResponse } from \"../shared/json-response\";\nimport type { AgentRunnerRunRequest } from \"../../runner/agent-runner\";\nimport type { Observable } from \"rxjs\";\n\n/**\n * Builds browser-facing realtime connection metadata owned by the runtime.\n */\nfunction buildRealtimeConnectionInfo(params: {\n clientUrl: string;\n threadId: string;\n}): { clientUrl: string; topic: string } {\n return {\n clientUrl: params.clientUrl,\n topic: `thread:${params.threadId}`,\n };\n}\n\ninterface RunnerStartupBoundary {\n events: Observable<BaseEvent>;\n startup: Promise<void>;\n}\n\ninterface RunnerWithStartupBoundary {\n runWithStartupBoundary(request: AgentRunnerRunRequest): RunnerStartupBoundary;\n}\n\nfunction hasRunnerStartupBoundary(\n runner: CopilotIntelligenceRuntimeLike[\"runner\"],\n): runner is CopilotIntelligenceRuntimeLike[\"runner\"] &\n RunnerWithStartupBoundary {\n const candidate = runner as { runWithStartupBoundary?: unknown };\n\n return (\n typeof candidate.runWithStartupBoundary === \"function\" &&\n (Object.prototype.hasOwnProperty.call(runner, \"runWithStartupBoundary\") ||\n Object.prototype.hasOwnProperty.call(runner, \"threads\"))\n );\n}\n\ninterface HandleIntelligenceRunParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n input: RunAgentInput;\n}\n\nexport async function handleIntelligenceRun({\n runtime,\n request,\n agentId,\n agent,\n input,\n}: HandleIntelligenceRunParams): Promise<Response> {\n if (!runtime.intelligence) {\n return Response.json(\n {\n error: \"Intelligence not configured\",\n message: \"Intelligence mode requires a CopilotKitIntelligence\",\n },\n { status: 500 },\n );\n }\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) {\n return user;\n }\n const userId = user.id;\n\n try {\n const { thread, created } = await runtime.intelligence.getOrCreateThread({\n threadId: input.threadId,\n userId,\n agentId,\n });\n\n if (created && runtime.generateThreadNames && !thread.name?.trim()) {\n void generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput: input,\n thread,\n userId,\n }).catch((nameError) => {\n logger.error(\"Failed to generate thread name:\", nameError);\n });\n }\n } catch (error) {\n logger.error(\"Failed to get or create thread:\", error);\n return Response.json(\n {\n error: \"Failed to initialize thread\",\n },\n { status: 502 },\n );\n }\n\n let canonicalThreadId = input.threadId;\n let canonicalRunId = input.runId;\n let joinToken: string | undefined;\n try {\n const lockResult = await runtime.intelligence.ɵacquireThreadLock({\n threadId: input.threadId,\n runId: input.runId,\n userId,\n agentId,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n ttlSeconds: runtime.lockTtlSeconds,\n });\n canonicalThreadId = lockResult.threadId;\n canonicalRunId = lockResult.runId;\n joinToken = lockResult.joinToken;\n } catch (error) {\n logger.error(\"Thread lock denied:\", error);\n return Response.json(\n {\n error: \"Thread lock denied\",\n },\n { status: 409 },\n );\n }\n\n const cleanupLock = (reason: string): Promise<void> =>\n runtime.intelligence\n .ɵcleanupThreadLock({\n threadId: canonicalThreadId || input.threadId,\n runId: canonicalRunId || input.runId,\n })\n .catch((cleanupError) => {\n logger.error(\n { err: cleanupError, reason },\n \"Failed to cleanup thread lock\",\n );\n });\n\n if (!canonicalThreadId || !canonicalRunId || !joinToken) {\n await cleanupLock(\"malformed-lock-response\");\n return Response.json(\n {\n error: \"Run connection credentials not available\",\n message:\n \"Intelligence platform did not return canonical threadId, runId, and joinToken\",\n },\n { status: 502 },\n );\n }\n\n const canonicalInput: RunAgentInput = {\n ...input,\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n };\n\n let persistedInputMessages: Message[] | undefined;\n if (Array.isArray(input.messages)) {\n try {\n const history = await runtime.intelligence.getThreadMessages({\n threadId: canonicalThreadId,\n userId,\n });\n const historicMessageIds = new Set(\n history.messages.map((message) => message.id),\n );\n persistedInputMessages = input.messages.filter(\n (message) => !historicMessageIds.has(message.id),\n );\n } catch (error) {\n logger.error(\"Thread history lookup failed:\", error);\n await cleanupLock(\"thread-history-lookup-failed\");\n return Response.json(\n {\n error: \"Thread history lookup failed\",\n },\n { status: 502 },\n );\n }\n }\n\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n\n // Start heartbeat timer to renew the thread lock.\n let heartbeatStopped = false;\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n heartbeatTimer = setInterval(() => {\n runtime.intelligence\n .ɵrenewThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n ttlSeconds: runtime.lockTtlSeconds,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n })\n .catch((err) => {\n if (heartbeatStopped) {\n return;\n }\n\n logger.error(\"Failed to renew thread lock:\", err);\n clearHeartbeat();\n try {\n agent.abortRun();\n } catch (abortError) {\n logger.error(\n \"Failed to abort agent after lock renewal failure:\",\n abortError,\n );\n }\n });\n }, runtime.lockHeartbeatIntervalSeconds * 1_000);\n\n const clearHeartbeat = () => {\n heartbeatStopped = true;\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n };\n\n const runStarted = { current: false };\n let immediateStartupErrorMessage: string | undefined;\n let immediateStartupCleanup: Promise<void> | undefined;\n\n const runRequest: AgentRunnerRunRequest = {\n threadId: canonicalThreadId,\n agent,\n input: canonicalInput,\n ...(persistedInputMessages !== undefined ? { persistedInputMessages } : {}),\n };\n\n try {\n const runStart = hasRunnerStartupBoundary(runtime.runner)\n ? runtime.runner.runWithStartupBoundary(runRequest)\n : {\n events: runtime.runner.run(runRequest),\n startup: Promise.resolve(),\n };\n\n runStart.events.subscribe({\n next: (event: BaseEvent) => {\n if (event.type === EventType.RUN_STARTED) {\n runStarted.current = true;\n }\n if (event.type === EventType.RUN_ERROR && !runStarted.current) {\n clearHeartbeat();\n immediateStartupErrorMessage =\n \"message\" in event && typeof event.message === \"string\"\n ? event.message\n : \"Runner failed before the run started\";\n immediateStartupCleanup = cleanupLock(\"runner-start-failed\");\n }\n },\n error: (error) => {\n clearHeartbeat();\n if (!runStarted.current) {\n immediateStartupErrorMessage =\n error instanceof Error ? error.message : String(error);\n immediateStartupCleanup = cleanupLock(\"runner-start-error\");\n } else {\n cleanupLock(\"runner-error\");\n }\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n logger.error(\"Error running agent:\", error);\n },\n complete: () => {\n clearHeartbeat();\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n },\n });\n\n await runStart.startup;\n } catch (error) {\n clearHeartbeat();\n await (immediateStartupCleanup ?? cleanupLock(\"runner-start-threw\"));\n logger.error(\"Error starting agent runner:\", error);\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: error instanceof Error ? error.message : String(error),\n },\n { status: 502 },\n );\n }\n\n if (immediateStartupErrorMessage) {\n await immediateStartupCleanup;\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: immediateStartupErrorMessage,\n },\n { status: 502 },\n );\n }\n\n // IntelligenceAgentRunner resolves this boundary after Phoenix channel join.\n // Other runner implementations fall back to construction/subscription errors.\n return Response.json(\n {\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n joinToken,\n realtime: buildRealtimeConnectionInfo({\n clientUrl: runtime.intelligence.ɵgetClientWsUrl(),\n threadId: canonicalThreadId,\n }),\n },\n {\n headers: { \"Cache-Control\": \"no-cache\" },\n },\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAmBA,SAAS,4BAA4B,QAGI;AACvC,QAAO;EACL,WAAW,OAAO;EAClB,OAAO,UAAU,OAAO;EACzB;;AAYH,SAAS,yBACP,QAE0B;AAG1B,QACE,OAHgB,OAGC,2BAA2B,eAC3C,OAAO,UAAU,eAAe,KAAK,QAAQ,yBAAyB,IACrE,OAAO,UAAU,eAAe,KAAK,QAAQ,UAAU;;AAY7D,eAAsB,sBAAsB,EAC1C,SACA,SACA,SACA,OACA,SACiD;AACjD,KAAI,CAAC,QAAQ,aACX,QAAO,SAAS,KACd;EACE,OAAO;EACP,SAAS;EACV,EACD,EAAE,QAAQ,KAAK,CAChB;CAGH,MAAM,OAAO,MAAMA,0DAAwB;EAAE;EAAS;EAAS,CAAC;AAChE,KAAIC,wCAAkB,KAAK,CACzB,QAAO;CAET,MAAM,SAAS,KAAK;AAEpB,KAAI;EACF,MAAM,EAAE,QAAQ,YAAY,MAAM,QAAQ,aAAa,kBAAkB;GACvE,UAAU,MAAM;GAChB;GACA;GACD,CAAC;AAEF,MAAI,WAAW,QAAQ,uBAAuB,CAAC,OAAO,MAAM,MAAM,CAChE,CAAKC,oDAA+B;GAClC;GACA;GACA;GACA,aAAa;GACb;GACA;GACD,CAAC,CAAC,OAAO,cAAc;AACtB,6BAAO,MAAM,mCAAmC,UAAU;IAC1D;UAEG,OAAO;AACd,4BAAO,MAAM,mCAAmC,MAAM;AACtD,SAAO,SAAS,KACd,EACE,OAAO,+BACR,EACD,EAAE,QAAQ,KAAK,CAChB;;CAGH,IAAI,oBAAoB,MAAM;CAC9B,IAAI,iBAAiB,MAAM;CAC3B,IAAI;AACJ,KAAI;EACF,MAAM,aAAa,MAAM,QAAQ,aAAa,mBAAmB;GAC/D,UAAU,MAAM;GAChB,OAAO,MAAM;GACb;GACA;GACA,GAAI,QAAQ,kBAAkB,SAC1B,EAAE,eAAe,QAAQ,eAAe,GACxC,EAAE;GACN,YAAY,QAAQ;GACrB,CAAC;AACF,sBAAoB,WAAW;AAC/B,mBAAiB,WAAW;AAC5B,cAAY,WAAW;UAChB,OAAO;AACd,4BAAO,MAAM,uBAAuB,MAAM;AAC1C,SAAO,SAAS,KACd,EACE,OAAO,sBACR,EACD,EAAE,QAAQ,KAAK,CAChB;;CAGH,MAAM,eAAe,WACnB,QAAQ,aACL,mBAAmB;EAClB,UAAU,qBAAqB,MAAM;EACrC,OAAO,kBAAkB,MAAM;EAChC,CAAC,CACD,OAAO,iBAAiB;AACvB,4BAAO,MACL;GAAE,KAAK;GAAc;GAAQ,EAC7B,gCACD;GACD;AAEN,KAAI,CAAC,qBAAqB,CAAC,kBAAkB,CAAC,WAAW;AACvD,QAAM,YAAY,0BAA0B;AAC5C,SAAO,SAAS,KACd;GACE,OAAO;GACP,SACE;GACH,EACD,EAAE,QAAQ,KAAK,CAChB;;CAGH,MAAM,iBAAgC;EACpC,GAAG;EACH,UAAU;EACV,OAAO;EACR;CAED,IAAI;AACJ,KAAI,MAAM,QAAQ,MAAM,SAAS,CAC/B,KAAI;EACF,MAAM,UAAU,MAAM,QAAQ,aAAa,kBAAkB;GAC3D,UAAU;GACV;GACD,CAAC;EACF,MAAM,qBAAqB,IAAI,IAC7B,QAAQ,SAAS,KAAK,YAAY,QAAQ,GAAG,CAC9C;AACD,2BAAyB,MAAM,SAAS,QACrC,YAAY,CAAC,mBAAmB,IAAI,QAAQ,GAAG,CACjD;UACM,OAAO;AACd,4BAAO,MAAM,iCAAiC,MAAM;AACpD,QAAM,YAAY,+BAA+B;AACjD,SAAO,SAAS,KACd,EACE,OAAO,gCACR,EACD,EAAE,QAAQ,KAAK,CAChB;;AAIL,kCAAU,QAAQ,8CAA8C,EAAE,CAAC;CAGnE,IAAI,mBAAmB;CACvB,IAAI;AACJ,kBAAiB,kBAAkB;AACjC,UAAQ,aACL,iBAAiB;GAChB,UAAU;GACV,OAAO;GACP,YAAY,QAAQ;GACpB,GAAI,QAAQ,kBAAkB,SAC1B,EAAE,eAAe,QAAQ,eAAe,GACxC,EAAE;GACP,CAAC,CACD,OAAO,QAAQ;AACd,OAAI,iBACF;AAGF,6BAAO,MAAM,gCAAgC,IAAI;AACjD,mBAAgB;AAChB,OAAI;AACF,UAAM,UAAU;YACT,YAAY;AACnB,8BAAO,MACL,qDACA,WACD;;IAEH;IACH,QAAQ,+BAA+B,IAAM;CAEhD,MAAM,uBAAuB;AAC3B,qBAAmB;AACnB,MAAI,mBAAmB,QAAW;AAChC,iBAAc,eAAe;AAC7B,oBAAiB;;;CAIrB,MAAM,aAAa,EAAE,SAAS,OAAO;CACrC,IAAI;CACJ,IAAI;CAEJ,MAAM,aAAoC;EACxC,UAAU;EACV;EACA,OAAO;EACP,GAAI,2BAA2B,SAAY,EAAE,wBAAwB,GAAG,EAAE;EAC3E;AAED,KAAI;EACF,MAAM,WAAW,yBAAyB,QAAQ,OAAO,GACrD,QAAQ,OAAO,uBAAuB,WAAW,GACjD;GACE,QAAQ,QAAQ,OAAO,IAAI,WAAW;GACtC,SAAS,QAAQ,SAAS;GAC3B;AAEL,WAAS,OAAO,UAAU;GACxB,OAAO,UAAqB;AAC1B,QAAI,MAAM,SAASC,wBAAU,YAC3B,YAAW,UAAU;AAEvB,QAAI,MAAM,SAASA,wBAAU,aAAa,CAAC,WAAW,SAAS;AAC7D,qBAAgB;AAChB,oCACE,aAAa,SAAS,OAAO,MAAM,YAAY,WAC3C,MAAM,UACN;AACN,+BAA0B,YAAY,sBAAsB;;;GAGhE,QAAQ,UAAU;AAChB,oBAAgB;AAChB,QAAI,CAAC,WAAW,SAAS;AACvB,oCACE,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACxD,+BAA0B,YAAY,qBAAqB;UAE3D,aAAY,eAAe;AAE7B,qCAAU,QAAQ,8CAA8C,EAC9D,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAC9D,CAAC;AACF,8BAAO,MAAM,wBAAwB,MAAM;;GAE7C,gBAAgB;AACd,oBAAgB;AAChB,qCAAU,QAAQ,4CAA4C,EAAE,CAAC;;GAEpE,CAAC;AAEF,QAAM,SAAS;UACR,OAAO;AACd,kBAAgB;AAChB,SAAO,2BAA2B,YAAY,qBAAqB;AACnE,4BAAO,MAAM,gCAAgC,MAAM;AACnD,SAAO,SAAS,KACd;GACE,OAAO;GACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAChE,EACD,EAAE,QAAQ,KAAK,CAChB;;AAGH,KAAI,8BAA8B;AAChC,QAAM;AACN,SAAO,SAAS,KACd;GACE,OAAO;GACP,SAAS;GACV,EACD,EAAE,QAAQ,KAAK,CAChB;;AAKH,QAAO,SAAS,KACd;EACE,UAAU;EACV,OAAO;EACP;EACA,UAAU,4BAA4B;GACpC,WAAW,QAAQ,aAAa,iBAAiB;GACjD,UAAU;GACX,CAAC;EACH,EACD,EACE,SAAS,EAAE,iBAAiB,YAAY,EACzC,CACF"}
|
|
1
|
+
{"version":3,"file":"run.cjs","names":["resolveIntelligenceUser","isHandlerResponse","resolveLearningContainerId","generateThreadNameForNewThread","getPlatformErrorStatus","getRuntimeErrorReporter","EventType"],"sources":["../../../../../src/v2/runtime/handlers/intelligence/run.ts"],"sourcesContent":["import type {\n AbstractAgent,\n BaseEvent,\n Message,\n RunAgentInput,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport { generateThreadNameForNewThread } from \"./thread-names\";\nimport { logger } from \"@copilotkit/shared\";\nimport { telemetry } from \"../../telemetry\";\nimport { resolveIntelligenceUser } from \"../shared/resolve-intelligence-user\";\nimport { isHandlerResponse } from \"../shared/json-response\";\nimport type { AgentRunnerRunRequest } from \"../../runner/agent-runner\";\nimport type { Observable } from \"rxjs\";\nimport { getRuntimeErrorReporter } from \"../../core/runtime-error-reporter\";\nimport type { RuntimeErrorPhase } from \"../../core/runtime-error-reporter\";\nimport { resolveLearningContainerId } from \"../../core/learning\";\nimport { getPlatformErrorStatus } from \"../shared/intelligence-utils\";\n\n/**\n * Builds browser-facing realtime connection metadata owned by the runtime.\n */\nfunction buildRealtimeConnectionInfo(params: {\n clientUrl: string;\n threadId: string;\n}): { clientUrl: string; topic: string } {\n return {\n clientUrl: params.clientUrl,\n topic: `thread:${params.threadId}`,\n };\n}\n\ninterface RunnerStartupBoundary {\n events: Observable<BaseEvent>;\n startup: Promise<void>;\n}\n\ninterface RunnerWithStartupBoundary {\n runWithStartupBoundary(request: AgentRunnerRunRequest): RunnerStartupBoundary;\n}\n\nfunction hasRunnerStartupBoundary(\n runner: CopilotIntelligenceRuntimeLike[\"runner\"],\n): runner is CopilotIntelligenceRuntimeLike[\"runner\"] &\n RunnerWithStartupBoundary {\n const candidate = runner as { runWithStartupBoundary?: unknown };\n\n return (\n typeof candidate.runWithStartupBoundary === \"function\" &&\n (Object.prototype.hasOwnProperty.call(runner, \"runWithStartupBoundary\") ||\n Object.prototype.hasOwnProperty.call(runner, \"threads\"))\n );\n}\n\ninterface HandleIntelligenceRunParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n input: RunAgentInput;\n startTime?: number;\n}\n\nexport async function handleIntelligenceRun({\n runtime,\n request,\n agentId,\n agent,\n input,\n startTime,\n}: HandleIntelligenceRunParams): Promise<Response> {\n if (!runtime.intelligence) {\n return Response.json(\n {\n error: \"Intelligence not configured\",\n message: \"Intelligence mode requires a CopilotKitIntelligence\",\n },\n { status: 500 },\n );\n }\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) {\n return user;\n }\n const userId = user.id;\n\n let learningContainerId: string | undefined;\n try {\n learningContainerId = await resolveLearningContainerId(runtime.learning, {\n surface: \"web\",\n request,\n threadId: input.threadId,\n runId: input.runId,\n agentId,\n userId,\n });\n } catch (error) {\n logger.error(\"Failed to resolve Learning Container:\", error);\n return Response.json(\n { error: \"Failed to resolve Learning Container\" },\n { status: 500 },\n );\n }\n\n try {\n const { thread, created } = await runtime.intelligence.getOrCreateThread({\n threadId: input.threadId,\n userId,\n agentId,\n ...(learningContainerId !== undefined ? { learningContainerId } : {}),\n });\n\n if (created && runtime.generateThreadNames && !thread.name?.trim()) {\n void generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput: input,\n thread,\n userId,\n }).catch((nameError) => {\n logger.error(\"Failed to generate thread name:\", nameError);\n });\n }\n } catch (error) {\n logger.error(\"Failed to get or create thread:\", error);\n const platformStatus = getPlatformErrorStatus(error);\n return Response.json(\n {\n error: \"Failed to initialize thread\",\n },\n {\n status:\n platformStatus !== undefined &&\n platformStatus >= 400 &&\n platformStatus < 500\n ? platformStatus\n : 502,\n },\n );\n }\n\n let canonicalThreadId = input.threadId;\n let canonicalRunId = input.runId;\n let joinToken: string | undefined;\n try {\n const lockResult = await runtime.intelligence.ɵacquireThreadLock({\n threadId: input.threadId,\n runId: input.runId,\n userId,\n agentId,\n ...(learningContainerId !== undefined ? { learningContainerId } : {}),\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n ttlSeconds: runtime.lockTtlSeconds,\n });\n canonicalThreadId = lockResult.threadId;\n canonicalRunId = lockResult.runId;\n joinToken = lockResult.joinToken;\n } catch (error) {\n logger.error(\"Thread lock denied:\", error);\n const platformStatus = getPlatformErrorStatus(error);\n return Response.json(\n {\n error: \"Thread lock denied\",\n },\n {\n status: platformStatus === 409 ? 409 : 502,\n },\n );\n }\n\n const cleanupLock = (reason: string): Promise<void> =>\n runtime.intelligence\n .ɵcleanupThreadLock({\n threadId: canonicalThreadId || input.threadId,\n runId: canonicalRunId || input.runId,\n })\n .catch((cleanupError) => {\n logger.error(\n { err: cleanupError, reason },\n \"Failed to cleanup thread lock\",\n );\n });\n\n if (!canonicalThreadId || !canonicalRunId || !joinToken) {\n await cleanupLock(\"malformed-lock-response\");\n return Response.json(\n {\n error: \"Run connection credentials not available\",\n message:\n \"Intelligence platform did not return canonical threadId, runId, and joinToken\",\n },\n { status: 502 },\n );\n }\n\n const canonicalInput: RunAgentInput = {\n ...input,\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n };\n\n let persistedInputMessages: Message[] | undefined;\n if (Array.isArray(input.messages)) {\n try {\n const history = await runtime.intelligence.getThreadMessages({\n threadId: canonicalThreadId,\n userId,\n });\n const historicMessageIds = new Set(\n history.messages.map((message) => message.id),\n );\n persistedInputMessages = input.messages.filter(\n (message) => !historicMessageIds.has(message.id),\n );\n } catch (error) {\n logger.error(\"Thread history lookup failed:\", error);\n await cleanupLock(\"thread-history-lookup-failed\");\n return Response.json(\n {\n error: \"Thread history lookup failed\",\n },\n { status: 502 },\n );\n }\n }\n\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n\n // Start heartbeat timer to renew the thread lock.\n let heartbeatStopped = false;\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n heartbeatTimer = setInterval(() => {\n runtime.intelligence\n .ɵrenewThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n ttlSeconds: runtime.lockTtlSeconds,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n })\n .catch((err) => {\n if (heartbeatStopped) {\n return;\n }\n\n logger.error(\"Failed to renew thread lock:\", err);\n clearHeartbeat();\n try {\n agent.abortRun();\n } catch (abortError) {\n logger.error(\n \"Failed to abort agent after lock renewal failure:\",\n abortError,\n );\n }\n });\n }, runtime.lockHeartbeatIntervalSeconds * 1_000);\n\n const clearHeartbeat = () => {\n heartbeatStopped = true;\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n };\n\n const runStarted = { current: false };\n let immediateStartupErrorMessage: string | undefined;\n let immediateStartupCleanup: Promise<void> | undefined;\n\n const runRequest: AgentRunnerRunRequest = {\n threadId: canonicalThreadId,\n agent,\n input: canonicalInput,\n ...(persistedInputMessages !== undefined ? { persistedInputMessages } : {}),\n };\n\n const runtimeErrorReporter = getRuntimeErrorReporter(runtime);\n let agentErrorReported = false;\n const reportAgentError = (error: unknown, phase: RuntimeErrorPhase) => {\n if (agentErrorReported) return;\n agentErrorReported = true;\n runtimeErrorReporter?.report({\n request,\n error,\n operation: \"agent.run\",\n agentId,\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n phase,\n startTime,\n });\n };\n\n try {\n const runStart = hasRunnerStartupBoundary(runtime.runner)\n ? runtime.runner.runWithStartupBoundary(runRequest)\n : {\n events: runtime.runner.run(runRequest),\n startup: Promise.resolve(),\n };\n\n runStart.events.subscribe({\n next: (event: BaseEvent) => {\n if (event.type === EventType.RUN_STARTED) {\n runStarted.current = true;\n }\n if (event.type === EventType.RUN_ERROR) {\n const message =\n \"message\" in event && typeof event.message === \"string\"\n ? event.message\n : \"Runner failed before the run started\";\n reportAgentError(\n new Error(message),\n runStarted.current\n ? \"intelligence.subscription\"\n : \"intelligence.startup\",\n );\n if (!runStarted.current) {\n clearHeartbeat();\n immediateStartupErrorMessage = message;\n immediateStartupCleanup = cleanupLock(\"runner-start-failed\");\n }\n }\n },\n error: (error) => {\n reportAgentError(\n error,\n runStarted.current\n ? \"intelligence.subscription\"\n : \"intelligence.startup\",\n );\n clearHeartbeat();\n if (!runStarted.current) {\n immediateStartupErrorMessage =\n error instanceof Error ? error.message : String(error);\n immediateStartupCleanup = cleanupLock(\"runner-start-error\");\n } else {\n cleanupLock(\"runner-error\");\n }\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n logger.error(\"Error running agent:\", error);\n },\n complete: () => {\n clearHeartbeat();\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n },\n });\n\n await runStart.startup;\n } catch (error) {\n reportAgentError(error, \"intelligence.startup\");\n clearHeartbeat();\n await (immediateStartupCleanup ?? cleanupLock(\"runner-start-threw\"));\n logger.error(\"Error starting agent runner:\", error);\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: error instanceof Error ? error.message : String(error),\n },\n { status: 502 },\n );\n }\n\n if (immediateStartupErrorMessage) {\n await immediateStartupCleanup;\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: immediateStartupErrorMessage,\n },\n { status: 502 },\n );\n }\n\n // IntelligenceAgentRunner resolves this boundary after Phoenix channel join.\n // Other runner implementations fall back to construction/subscription errors.\n return Response.json(\n {\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n joinToken,\n realtime: buildRealtimeConnectionInfo({\n clientUrl: runtime.intelligence.ɵgetClientWsUrl(),\n threadId: canonicalThreadId,\n }),\n },\n {\n headers: { \"Cache-Control\": \"no-cache\" },\n },\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
import telemetry from "../../telemetry/telemetry-client.mjs";
|
|
3
|
+
import { getRuntimeErrorReporter } from "../../core/runtime-error-reporter.mjs";
|
|
4
|
+
import { resolveLearningContainerId } from "../../core/learning.mjs";
|
|
3
5
|
import { isHandlerResponse } from "../shared/json-response.mjs";
|
|
6
|
+
import { getPlatformErrorStatus } from "../shared/intelligence-utils.mjs";
|
|
4
7
|
import { resolveIntelligenceUser } from "../shared/resolve-intelligence-user.mjs";
|
|
5
8
|
import { generateThreadNameForNewThread } from "./thread-names.mjs";
|
|
6
9
|
import { logger } from "@copilotkit/shared";
|
|
@@ -19,7 +22,7 @@ function buildRealtimeConnectionInfo(params) {
|
|
|
19
22
|
function hasRunnerStartupBoundary(runner) {
|
|
20
23
|
return typeof runner.runWithStartupBoundary === "function" && (Object.prototype.hasOwnProperty.call(runner, "runWithStartupBoundary") || Object.prototype.hasOwnProperty.call(runner, "threads"));
|
|
21
24
|
}
|
|
22
|
-
async function handleIntelligenceRun({ runtime, request, agentId, agent, input }) {
|
|
25
|
+
async function handleIntelligenceRun({ runtime, request, agentId, agent, input, startTime }) {
|
|
23
26
|
if (!runtime.intelligence) return Response.json({
|
|
24
27
|
error: "Intelligence not configured",
|
|
25
28
|
message: "Intelligence mode requires a CopilotKitIntelligence"
|
|
@@ -30,11 +33,26 @@ async function handleIntelligenceRun({ runtime, request, agentId, agent, input }
|
|
|
30
33
|
});
|
|
31
34
|
if (isHandlerResponse(user)) return user;
|
|
32
35
|
const userId = user.id;
|
|
36
|
+
let learningContainerId;
|
|
37
|
+
try {
|
|
38
|
+
learningContainerId = await resolveLearningContainerId(runtime.learning, {
|
|
39
|
+
surface: "web",
|
|
40
|
+
request,
|
|
41
|
+
threadId: input.threadId,
|
|
42
|
+
runId: input.runId,
|
|
43
|
+
agentId,
|
|
44
|
+
userId
|
|
45
|
+
});
|
|
46
|
+
} catch (error) {
|
|
47
|
+
logger.error("Failed to resolve Learning Container:", error);
|
|
48
|
+
return Response.json({ error: "Failed to resolve Learning Container" }, { status: 500 });
|
|
49
|
+
}
|
|
33
50
|
try {
|
|
34
51
|
const { thread, created } = await runtime.intelligence.getOrCreateThread({
|
|
35
52
|
threadId: input.threadId,
|
|
36
53
|
userId,
|
|
37
|
-
agentId
|
|
54
|
+
agentId,
|
|
55
|
+
...learningContainerId !== void 0 ? { learningContainerId } : {}
|
|
38
56
|
});
|
|
39
57
|
if (created && runtime.generateThreadNames && !thread.name?.trim()) generateThreadNameForNewThread({
|
|
40
58
|
runtime,
|
|
@@ -48,7 +66,8 @@ async function handleIntelligenceRun({ runtime, request, agentId, agent, input }
|
|
|
48
66
|
});
|
|
49
67
|
} catch (error) {
|
|
50
68
|
logger.error("Failed to get or create thread:", error);
|
|
51
|
-
|
|
69
|
+
const platformStatus = getPlatformErrorStatus(error);
|
|
70
|
+
return Response.json({ error: "Failed to initialize thread" }, { status: platformStatus !== void 0 && platformStatus >= 400 && platformStatus < 500 ? platformStatus : 502 });
|
|
52
71
|
}
|
|
53
72
|
let canonicalThreadId = input.threadId;
|
|
54
73
|
let canonicalRunId = input.runId;
|
|
@@ -59,6 +78,7 @@ async function handleIntelligenceRun({ runtime, request, agentId, agent, input }
|
|
|
59
78
|
runId: input.runId,
|
|
60
79
|
userId,
|
|
61
80
|
agentId,
|
|
81
|
+
...learningContainerId !== void 0 ? { learningContainerId } : {},
|
|
62
82
|
...runtime.lockKeyPrefix !== void 0 ? { lockKeyPrefix: runtime.lockKeyPrefix } : {},
|
|
63
83
|
ttlSeconds: runtime.lockTtlSeconds
|
|
64
84
|
});
|
|
@@ -67,7 +87,8 @@ async function handleIntelligenceRun({ runtime, request, agentId, agent, input }
|
|
|
67
87
|
joinToken = lockResult.joinToken;
|
|
68
88
|
} catch (error) {
|
|
69
89
|
logger.error("Thread lock denied:", error);
|
|
70
|
-
|
|
90
|
+
const platformStatus = getPlatformErrorStatus(error);
|
|
91
|
+
return Response.json({ error: "Thread lock denied" }, { status: platformStatus === 409 ? 409 : 502 });
|
|
71
92
|
}
|
|
72
93
|
const cleanupLock = (reason) => runtime.intelligence.ɵcleanupThreadLock({
|
|
73
94
|
threadId: canonicalThreadId || input.threadId,
|
|
@@ -139,6 +160,22 @@ async function handleIntelligenceRun({ runtime, request, agentId, agent, input }
|
|
|
139
160
|
input: canonicalInput,
|
|
140
161
|
...persistedInputMessages !== void 0 ? { persistedInputMessages } : {}
|
|
141
162
|
};
|
|
163
|
+
const runtimeErrorReporter = getRuntimeErrorReporter(runtime);
|
|
164
|
+
let agentErrorReported = false;
|
|
165
|
+
const reportAgentError = (error, phase) => {
|
|
166
|
+
if (agentErrorReported) return;
|
|
167
|
+
agentErrorReported = true;
|
|
168
|
+
runtimeErrorReporter?.report({
|
|
169
|
+
request,
|
|
170
|
+
error,
|
|
171
|
+
operation: "agent.run",
|
|
172
|
+
agentId,
|
|
173
|
+
threadId: canonicalThreadId,
|
|
174
|
+
runId: canonicalRunId,
|
|
175
|
+
phase,
|
|
176
|
+
startTime
|
|
177
|
+
});
|
|
178
|
+
};
|
|
142
179
|
try {
|
|
143
180
|
const runStart = hasRunnerStartupBoundary(runtime.runner) ? runtime.runner.runWithStartupBoundary(runRequest) : {
|
|
144
181
|
events: runtime.runner.run(runRequest),
|
|
@@ -147,13 +184,18 @@ async function handleIntelligenceRun({ runtime, request, agentId, agent, input }
|
|
|
147
184
|
runStart.events.subscribe({
|
|
148
185
|
next: (event) => {
|
|
149
186
|
if (event.type === EventType.RUN_STARTED) runStarted.current = true;
|
|
150
|
-
if (event.type === EventType.RUN_ERROR
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
187
|
+
if (event.type === EventType.RUN_ERROR) {
|
|
188
|
+
const message = "message" in event && typeof event.message === "string" ? event.message : "Runner failed before the run started";
|
|
189
|
+
reportAgentError(new Error(message), runStarted.current ? "intelligence.subscription" : "intelligence.startup");
|
|
190
|
+
if (!runStarted.current) {
|
|
191
|
+
clearHeartbeat();
|
|
192
|
+
immediateStartupErrorMessage = message;
|
|
193
|
+
immediateStartupCleanup = cleanupLock("runner-start-failed");
|
|
194
|
+
}
|
|
154
195
|
}
|
|
155
196
|
},
|
|
156
197
|
error: (error) => {
|
|
198
|
+
reportAgentError(error, runStarted.current ? "intelligence.subscription" : "intelligence.startup");
|
|
157
199
|
clearHeartbeat();
|
|
158
200
|
if (!runStarted.current) {
|
|
159
201
|
immediateStartupErrorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -169,6 +211,7 @@ async function handleIntelligenceRun({ runtime, request, agentId, agent, input }
|
|
|
169
211
|
});
|
|
170
212
|
await runStart.startup;
|
|
171
213
|
} catch (error) {
|
|
214
|
+
reportAgentError(error, "intelligence.startup");
|
|
172
215
|
clearHeartbeat();
|
|
173
216
|
await (immediateStartupCleanup ?? cleanupLock("runner-start-threw"));
|
|
174
217
|
logger.error("Error starting agent runner:", error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/intelligence/run.ts"],"sourcesContent":["import type {\n AbstractAgent,\n BaseEvent,\n Message,\n RunAgentInput,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport { generateThreadNameForNewThread } from \"./thread-names\";\nimport { logger } from \"@copilotkit/shared\";\nimport { telemetry } from \"../../telemetry\";\nimport { resolveIntelligenceUser } from \"../shared/resolve-intelligence-user\";\nimport { isHandlerResponse } from \"../shared/json-response\";\nimport type { AgentRunnerRunRequest } from \"../../runner/agent-runner\";\nimport type { Observable } from \"rxjs\";\n\n/**\n * Builds browser-facing realtime connection metadata owned by the runtime.\n */\nfunction buildRealtimeConnectionInfo(params: {\n clientUrl: string;\n threadId: string;\n}): { clientUrl: string; topic: string } {\n return {\n clientUrl: params.clientUrl,\n topic: `thread:${params.threadId}`,\n };\n}\n\ninterface RunnerStartupBoundary {\n events: Observable<BaseEvent>;\n startup: Promise<void>;\n}\n\ninterface RunnerWithStartupBoundary {\n runWithStartupBoundary(request: AgentRunnerRunRequest): RunnerStartupBoundary;\n}\n\nfunction hasRunnerStartupBoundary(\n runner: CopilotIntelligenceRuntimeLike[\"runner\"],\n): runner is CopilotIntelligenceRuntimeLike[\"runner\"] &\n RunnerWithStartupBoundary {\n const candidate = runner as { runWithStartupBoundary?: unknown };\n\n return (\n typeof candidate.runWithStartupBoundary === \"function\" &&\n (Object.prototype.hasOwnProperty.call(runner, \"runWithStartupBoundary\") ||\n Object.prototype.hasOwnProperty.call(runner, \"threads\"))\n );\n}\n\ninterface HandleIntelligenceRunParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n input: RunAgentInput;\n}\n\nexport async function handleIntelligenceRun({\n runtime,\n request,\n agentId,\n agent,\n input,\n}: HandleIntelligenceRunParams): Promise<Response> {\n if (!runtime.intelligence) {\n return Response.json(\n {\n error: \"Intelligence not configured\",\n message: \"Intelligence mode requires a CopilotKitIntelligence\",\n },\n { status: 500 },\n );\n }\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) {\n return user;\n }\n const userId = user.id;\n\n try {\n const { thread, created } = await runtime.intelligence.getOrCreateThread({\n threadId: input.threadId,\n userId,\n agentId,\n });\n\n if (created && runtime.generateThreadNames && !thread.name?.trim()) {\n void generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput: input,\n thread,\n userId,\n }).catch((nameError) => {\n logger.error(\"Failed to generate thread name:\", nameError);\n });\n }\n } catch (error) {\n logger.error(\"Failed to get or create thread:\", error);\n return Response.json(\n {\n error: \"Failed to initialize thread\",\n },\n { status: 502 },\n );\n }\n\n let canonicalThreadId = input.threadId;\n let canonicalRunId = input.runId;\n let joinToken: string | undefined;\n try {\n const lockResult = await runtime.intelligence.ɵacquireThreadLock({\n threadId: input.threadId,\n runId: input.runId,\n userId,\n agentId,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n ttlSeconds: runtime.lockTtlSeconds,\n });\n canonicalThreadId = lockResult.threadId;\n canonicalRunId = lockResult.runId;\n joinToken = lockResult.joinToken;\n } catch (error) {\n logger.error(\"Thread lock denied:\", error);\n return Response.json(\n {\n error: \"Thread lock denied\",\n },\n { status: 409 },\n );\n }\n\n const cleanupLock = (reason: string): Promise<void> =>\n runtime.intelligence\n .ɵcleanupThreadLock({\n threadId: canonicalThreadId || input.threadId,\n runId: canonicalRunId || input.runId,\n })\n .catch((cleanupError) => {\n logger.error(\n { err: cleanupError, reason },\n \"Failed to cleanup thread lock\",\n );\n });\n\n if (!canonicalThreadId || !canonicalRunId || !joinToken) {\n await cleanupLock(\"malformed-lock-response\");\n return Response.json(\n {\n error: \"Run connection credentials not available\",\n message:\n \"Intelligence platform did not return canonical threadId, runId, and joinToken\",\n },\n { status: 502 },\n );\n }\n\n const canonicalInput: RunAgentInput = {\n ...input,\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n };\n\n let persistedInputMessages: Message[] | undefined;\n if (Array.isArray(input.messages)) {\n try {\n const history = await runtime.intelligence.getThreadMessages({\n threadId: canonicalThreadId,\n userId,\n });\n const historicMessageIds = new Set(\n history.messages.map((message) => message.id),\n );\n persistedInputMessages = input.messages.filter(\n (message) => !historicMessageIds.has(message.id),\n );\n } catch (error) {\n logger.error(\"Thread history lookup failed:\", error);\n await cleanupLock(\"thread-history-lookup-failed\");\n return Response.json(\n {\n error: \"Thread history lookup failed\",\n },\n { status: 502 },\n );\n }\n }\n\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n\n // Start heartbeat timer to renew the thread lock.\n let heartbeatStopped = false;\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n heartbeatTimer = setInterval(() => {\n runtime.intelligence\n .ɵrenewThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n ttlSeconds: runtime.lockTtlSeconds,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n })\n .catch((err) => {\n if (heartbeatStopped) {\n return;\n }\n\n logger.error(\"Failed to renew thread lock:\", err);\n clearHeartbeat();\n try {\n agent.abortRun();\n } catch (abortError) {\n logger.error(\n \"Failed to abort agent after lock renewal failure:\",\n abortError,\n );\n }\n });\n }, runtime.lockHeartbeatIntervalSeconds * 1_000);\n\n const clearHeartbeat = () => {\n heartbeatStopped = true;\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n };\n\n const runStarted = { current: false };\n let immediateStartupErrorMessage: string | undefined;\n let immediateStartupCleanup: Promise<void> | undefined;\n\n const runRequest: AgentRunnerRunRequest = {\n threadId: canonicalThreadId,\n agent,\n input: canonicalInput,\n ...(persistedInputMessages !== undefined ? { persistedInputMessages } : {}),\n };\n\n try {\n const runStart = hasRunnerStartupBoundary(runtime.runner)\n ? runtime.runner.runWithStartupBoundary(runRequest)\n : {\n events: runtime.runner.run(runRequest),\n startup: Promise.resolve(),\n };\n\n runStart.events.subscribe({\n next: (event: BaseEvent) => {\n if (event.type === EventType.RUN_STARTED) {\n runStarted.current = true;\n }\n if (event.type === EventType.RUN_ERROR && !runStarted.current) {\n clearHeartbeat();\n immediateStartupErrorMessage =\n \"message\" in event && typeof event.message === \"string\"\n ? event.message\n : \"Runner failed before the run started\";\n immediateStartupCleanup = cleanupLock(\"runner-start-failed\");\n }\n },\n error: (error) => {\n clearHeartbeat();\n if (!runStarted.current) {\n immediateStartupErrorMessage =\n error instanceof Error ? error.message : String(error);\n immediateStartupCleanup = cleanupLock(\"runner-start-error\");\n } else {\n cleanupLock(\"runner-error\");\n }\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n logger.error(\"Error running agent:\", error);\n },\n complete: () => {\n clearHeartbeat();\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n },\n });\n\n await runStart.startup;\n } catch (error) {\n clearHeartbeat();\n await (immediateStartupCleanup ?? cleanupLock(\"runner-start-threw\"));\n logger.error(\"Error starting agent runner:\", error);\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: error instanceof Error ? error.message : String(error),\n },\n { status: 502 },\n );\n }\n\n if (immediateStartupErrorMessage) {\n await immediateStartupCleanup;\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: immediateStartupErrorMessage,\n },\n { status: 502 },\n );\n }\n\n // IntelligenceAgentRunner resolves this boundary after Phoenix channel join.\n // Other runner implementations fall back to construction/subscription errors.\n return Response.json(\n {\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n joinToken,\n realtime: buildRealtimeConnectionInfo({\n clientUrl: runtime.intelligence.ɵgetClientWsUrl(),\n threadId: canonicalThreadId,\n }),\n },\n {\n headers: { \"Cache-Control\": \"no-cache\" },\n },\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/intelligence/run.ts"],"sourcesContent":["import type {\n AbstractAgent,\n BaseEvent,\n Message,\n RunAgentInput,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport { generateThreadNameForNewThread } from \"./thread-names\";\nimport { logger } from \"@copilotkit/shared\";\nimport { telemetry } from \"../../telemetry\";\nimport { resolveIntelligenceUser } from \"../shared/resolve-intelligence-user\";\nimport { isHandlerResponse } from \"../shared/json-response\";\nimport type { AgentRunnerRunRequest } from \"../../runner/agent-runner\";\nimport type { Observable } from \"rxjs\";\nimport { getRuntimeErrorReporter } from \"../../core/runtime-error-reporter\";\nimport type { RuntimeErrorPhase } from \"../../core/runtime-error-reporter\";\nimport { resolveLearningContainerId } from \"../../core/learning\";\nimport { getPlatformErrorStatus } from \"../shared/intelligence-utils\";\n\n/**\n * Builds browser-facing realtime connection metadata owned by the runtime.\n */\nfunction buildRealtimeConnectionInfo(params: {\n clientUrl: string;\n threadId: string;\n}): { clientUrl: string; topic: string } {\n return {\n clientUrl: params.clientUrl,\n topic: `thread:${params.threadId}`,\n };\n}\n\ninterface RunnerStartupBoundary {\n events: Observable<BaseEvent>;\n startup: Promise<void>;\n}\n\ninterface RunnerWithStartupBoundary {\n runWithStartupBoundary(request: AgentRunnerRunRequest): RunnerStartupBoundary;\n}\n\nfunction hasRunnerStartupBoundary(\n runner: CopilotIntelligenceRuntimeLike[\"runner\"],\n): runner is CopilotIntelligenceRuntimeLike[\"runner\"] &\n RunnerWithStartupBoundary {\n const candidate = runner as { runWithStartupBoundary?: unknown };\n\n return (\n typeof candidate.runWithStartupBoundary === \"function\" &&\n (Object.prototype.hasOwnProperty.call(runner, \"runWithStartupBoundary\") ||\n Object.prototype.hasOwnProperty.call(runner, \"threads\"))\n );\n}\n\ninterface HandleIntelligenceRunParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n input: RunAgentInput;\n startTime?: number;\n}\n\nexport async function handleIntelligenceRun({\n runtime,\n request,\n agentId,\n agent,\n input,\n startTime,\n}: HandleIntelligenceRunParams): Promise<Response> {\n if (!runtime.intelligence) {\n return Response.json(\n {\n error: \"Intelligence not configured\",\n message: \"Intelligence mode requires a CopilotKitIntelligence\",\n },\n { status: 500 },\n );\n }\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) {\n return user;\n }\n const userId = user.id;\n\n let learningContainerId: string | undefined;\n try {\n learningContainerId = await resolveLearningContainerId(runtime.learning, {\n surface: \"web\",\n request,\n threadId: input.threadId,\n runId: input.runId,\n agentId,\n userId,\n });\n } catch (error) {\n logger.error(\"Failed to resolve Learning Container:\", error);\n return Response.json(\n { error: \"Failed to resolve Learning Container\" },\n { status: 500 },\n );\n }\n\n try {\n const { thread, created } = await runtime.intelligence.getOrCreateThread({\n threadId: input.threadId,\n userId,\n agentId,\n ...(learningContainerId !== undefined ? { learningContainerId } : {}),\n });\n\n if (created && runtime.generateThreadNames && !thread.name?.trim()) {\n void generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput: input,\n thread,\n userId,\n }).catch((nameError) => {\n logger.error(\"Failed to generate thread name:\", nameError);\n });\n }\n } catch (error) {\n logger.error(\"Failed to get or create thread:\", error);\n const platformStatus = getPlatformErrorStatus(error);\n return Response.json(\n {\n error: \"Failed to initialize thread\",\n },\n {\n status:\n platformStatus !== undefined &&\n platformStatus >= 400 &&\n platformStatus < 500\n ? platformStatus\n : 502,\n },\n );\n }\n\n let canonicalThreadId = input.threadId;\n let canonicalRunId = input.runId;\n let joinToken: string | undefined;\n try {\n const lockResult = await runtime.intelligence.ɵacquireThreadLock({\n threadId: input.threadId,\n runId: input.runId,\n userId,\n agentId,\n ...(learningContainerId !== undefined ? { learningContainerId } : {}),\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n ttlSeconds: runtime.lockTtlSeconds,\n });\n canonicalThreadId = lockResult.threadId;\n canonicalRunId = lockResult.runId;\n joinToken = lockResult.joinToken;\n } catch (error) {\n logger.error(\"Thread lock denied:\", error);\n const platformStatus = getPlatformErrorStatus(error);\n return Response.json(\n {\n error: \"Thread lock denied\",\n },\n {\n status: platformStatus === 409 ? 409 : 502,\n },\n );\n }\n\n const cleanupLock = (reason: string): Promise<void> =>\n runtime.intelligence\n .ɵcleanupThreadLock({\n threadId: canonicalThreadId || input.threadId,\n runId: canonicalRunId || input.runId,\n })\n .catch((cleanupError) => {\n logger.error(\n { err: cleanupError, reason },\n \"Failed to cleanup thread lock\",\n );\n });\n\n if (!canonicalThreadId || !canonicalRunId || !joinToken) {\n await cleanupLock(\"malformed-lock-response\");\n return Response.json(\n {\n error: \"Run connection credentials not available\",\n message:\n \"Intelligence platform did not return canonical threadId, runId, and joinToken\",\n },\n { status: 502 },\n );\n }\n\n const canonicalInput: RunAgentInput = {\n ...input,\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n };\n\n let persistedInputMessages: Message[] | undefined;\n if (Array.isArray(input.messages)) {\n try {\n const history = await runtime.intelligence.getThreadMessages({\n threadId: canonicalThreadId,\n userId,\n });\n const historicMessageIds = new Set(\n history.messages.map((message) => message.id),\n );\n persistedInputMessages = input.messages.filter(\n (message) => !historicMessageIds.has(message.id),\n );\n } catch (error) {\n logger.error(\"Thread history lookup failed:\", error);\n await cleanupLock(\"thread-history-lookup-failed\");\n return Response.json(\n {\n error: \"Thread history lookup failed\",\n },\n { status: 502 },\n );\n }\n }\n\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n\n // Start heartbeat timer to renew the thread lock.\n let heartbeatStopped = false;\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n heartbeatTimer = setInterval(() => {\n runtime.intelligence\n .ɵrenewThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n ttlSeconds: runtime.lockTtlSeconds,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n })\n .catch((err) => {\n if (heartbeatStopped) {\n return;\n }\n\n logger.error(\"Failed to renew thread lock:\", err);\n clearHeartbeat();\n try {\n agent.abortRun();\n } catch (abortError) {\n logger.error(\n \"Failed to abort agent after lock renewal failure:\",\n abortError,\n );\n }\n });\n }, runtime.lockHeartbeatIntervalSeconds * 1_000);\n\n const clearHeartbeat = () => {\n heartbeatStopped = true;\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n };\n\n const runStarted = { current: false };\n let immediateStartupErrorMessage: string | undefined;\n let immediateStartupCleanup: Promise<void> | undefined;\n\n const runRequest: AgentRunnerRunRequest = {\n threadId: canonicalThreadId,\n agent,\n input: canonicalInput,\n ...(persistedInputMessages !== undefined ? { persistedInputMessages } : {}),\n };\n\n const runtimeErrorReporter = getRuntimeErrorReporter(runtime);\n let agentErrorReported = false;\n const reportAgentError = (error: unknown, phase: RuntimeErrorPhase) => {\n if (agentErrorReported) return;\n agentErrorReported = true;\n runtimeErrorReporter?.report({\n request,\n error,\n operation: \"agent.run\",\n agentId,\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n phase,\n startTime,\n });\n };\n\n try {\n const runStart = hasRunnerStartupBoundary(runtime.runner)\n ? runtime.runner.runWithStartupBoundary(runRequest)\n : {\n events: runtime.runner.run(runRequest),\n startup: Promise.resolve(),\n };\n\n runStart.events.subscribe({\n next: (event: BaseEvent) => {\n if (event.type === EventType.RUN_STARTED) {\n runStarted.current = true;\n }\n if (event.type === EventType.RUN_ERROR) {\n const message =\n \"message\" in event && typeof event.message === \"string\"\n ? event.message\n : \"Runner failed before the run started\";\n reportAgentError(\n new Error(message),\n runStarted.current\n ? \"intelligence.subscription\"\n : \"intelligence.startup\",\n );\n if (!runStarted.current) {\n clearHeartbeat();\n immediateStartupErrorMessage = message;\n immediateStartupCleanup = cleanupLock(\"runner-start-failed\");\n }\n }\n },\n error: (error) => {\n reportAgentError(\n error,\n runStarted.current\n ? \"intelligence.subscription\"\n : \"intelligence.startup\",\n );\n clearHeartbeat();\n if (!runStarted.current) {\n immediateStartupErrorMessage =\n error instanceof Error ? error.message : String(error);\n immediateStartupCleanup = cleanupLock(\"runner-start-error\");\n } else {\n cleanupLock(\"runner-error\");\n }\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n logger.error(\"Error running agent:\", error);\n },\n complete: () => {\n clearHeartbeat();\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n },\n });\n\n await runStart.startup;\n } catch (error) {\n reportAgentError(error, \"intelligence.startup\");\n clearHeartbeat();\n await (immediateStartupCleanup ?? cleanupLock(\"runner-start-threw\"));\n logger.error(\"Error starting agent runner:\", error);\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: error instanceof Error ? error.message : String(error),\n },\n { status: 502 },\n );\n }\n\n if (immediateStartupErrorMessage) {\n await immediateStartupCleanup;\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: immediateStartupErrorMessage,\n },\n { status: 502 },\n );\n }\n\n // IntelligenceAgentRunner resolves this boundary after Phoenix channel join.\n // Other runner implementations fall back to construction/subscription errors.\n return Response.json(\n {\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n joinToken,\n realtime: buildRealtimeConnectionInfo({\n clientUrl: runtime.intelligence.ɵgetClientWsUrl(),\n threadId: canonicalThreadId,\n }),\n },\n {\n headers: { \"Cache-Control\": \"no-cache\" },\n },\n );\n}\n"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ const require_telemetry_client = require('../../telemetry/telemetry-client.cjs')
|
|
|
5
5
|
let _ag_ui_encoder = require("@ag-ui/encoder");
|
|
6
6
|
|
|
7
7
|
//#region src/v2/runtime/handlers/shared/sse-response.ts
|
|
8
|
-
function createSseEventResponse({ request, observableFactory, debugEventBus, agentId, debug, logger, captureTelemetry = true }) {
|
|
8
|
+
function createSseEventResponse({ request, observableFactory, debugEventBus, agentId, debug, logger, captureTelemetry = true, runtimeErrorReporter, startTime }) {
|
|
9
9
|
const stream = new TransformStream();
|
|
10
10
|
const writer = stream.writable.getWriter();
|
|
11
11
|
const encoder = new _ag_ui_encoder.EventEncoder();
|
|
@@ -32,6 +32,21 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
34
|
let subscription;
|
|
35
|
+
let agentErrorReported = false;
|
|
36
|
+
const reportAgentError = (error, phase) => {
|
|
37
|
+
if (agentErrorReported) return;
|
|
38
|
+
agentErrorReported = true;
|
|
39
|
+
runtimeErrorReporter?.report({
|
|
40
|
+
request,
|
|
41
|
+
error,
|
|
42
|
+
operation: "agent.run",
|
|
43
|
+
agentId,
|
|
44
|
+
threadId: debugThreadId || void 0,
|
|
45
|
+
runId: debugRunId || void 0,
|
|
46
|
+
phase,
|
|
47
|
+
startTime
|
|
48
|
+
});
|
|
49
|
+
};
|
|
35
50
|
(async () => {
|
|
36
51
|
const observable = await observableFactory();
|
|
37
52
|
if (captureTelemetry) require_telemetry_client.default.capture("oss.runtime.agent_execution_stream_started", {});
|
|
@@ -45,6 +60,12 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
45
60
|
debugThreadId = e.threadId ?? "";
|
|
46
61
|
debugRunId = e.runId ?? "";
|
|
47
62
|
}
|
|
63
|
+
if (event.type === "RUN_ERROR") {
|
|
64
|
+
const e = event;
|
|
65
|
+
debugThreadId = e.threadId ?? debugThreadId;
|
|
66
|
+
debugRunId = e.runId ?? debugRunId;
|
|
67
|
+
reportAgentError(new Error(typeof e.message === "string" ? e.message : "Runner reported a run error"), "sse.subscription");
|
|
68
|
+
}
|
|
48
69
|
if (debugEventBus) try {
|
|
49
70
|
debugEventBus.broadcast(event, {
|
|
50
71
|
agentId: agentId ?? "",
|
|
@@ -74,6 +95,7 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
74
95
|
}
|
|
75
96
|
},
|
|
76
97
|
error: async (error) => {
|
|
98
|
+
reportAgentError(error, "sse.subscription");
|
|
77
99
|
if (captureTelemetry) require_telemetry_client.default.capture("oss.runtime.agent_execution_stream_errored", { error: error instanceof Error ? error.message : String(error) });
|
|
78
100
|
if (debug?.lifecycle) debugLogger.debug({ error: error instanceof Error ? error.message : String(error) }, "SSE stream errored");
|
|
79
101
|
logError(error);
|
|
@@ -90,6 +112,7 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
90
112
|
});
|
|
91
113
|
if (request.signal.aborted) subscription.unsubscribe();
|
|
92
114
|
})().catch(async (error) => {
|
|
115
|
+
reportAgentError(error, "sse.factory");
|
|
93
116
|
logError(error);
|
|
94
117
|
await closeStream();
|
|
95
118
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse-response.cjs","names":["EventEncoder","createLogger"],"sources":["../../../../../src/v2/runtime/handlers/shared/sse-response.ts"],"sourcesContent":["import type { BaseEvent } from \"@ag-ui/client\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { createLogger } from \"../../../../lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../../lib/logger\";\nimport { telemetry } from \"../../telemetry\";\nimport type { DebugEventBus } from \"../../core/debug-event-bus\";\n\ninterface CreateSseEventResponseParams {\n request: Request;\n observableFactory: () =>\n | Promise<Observable<BaseEvent>>\n | Observable<BaseEvent>;\n debugEventBus?: DebugEventBus;\n agentId?: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n /**\n * Whether to emit `oss.runtime.agent_execution_stream_*` telemetry for this\n * stream. Defaults to `true`. The stateless `/suggest` path sets this to\n * `false`: a suggestion is a side-effect-free structured completion, not a\n * tracked run, and under `available: \"always\"` it fires often enough to flood\n * run telemetry.\n */\n captureTelemetry?: boolean;\n}\n\nexport function createSseEventResponse({\n request,\n observableFactory,\n debugEventBus,\n agentId,\n debug,\n logger,\n captureTelemetry = true,\n}: CreateSseEventResponseParams): Response {\n const stream = new TransformStream();\n const writer = stream.writable.getWriter();\n const encoder = new EventEncoder();\n let streamClosed = false;\n let debugThreadId = \"\";\n let debugRunId = \"\";\n\n const debugLogger = debug?.enabled\n ? (logger ??\n createLogger({ level: \"debug\", component: \"copilotkit-debug\" }))\n : undefined;\n\n const closeStream = async () => {\n if (!streamClosed) {\n try {\n await writer.close();\n streamClosed = true;\n } catch {\n // Stream already closed.\n }\n }\n };\n\n const logError = (error: unknown) => {\n console.error(\"Error running agent:\", error);\n console.error(\n \"Error stack:\",\n error instanceof Error ? error.stack : \"No stack trace\",\n );\n console.error(\"Error details:\", {\n name: error instanceof Error ? error.name : \"Unknown\",\n message: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.cause : undefined,\n });\n };\n\n let subscription: Subscription | undefined;\n\n (async () => {\n const observable = await observableFactory();\n\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n }\n\n if (debug?.lifecycle) {\n debugLogger!.debug(\"SSE stream opened\");\n }\n\n let eventCount = 0;\n let loggedEventCount = 0;\n\n subscription = observable.subscribe({\n next: async (event) => {\n // Extract threadId/runId from RUN_STARTED\n if (event.type === \"RUN_STARTED\") {\n const e = event as { threadId?: string; runId?: string };\n debugThreadId = e.threadId ?? \"\";\n debugRunId = e.runId ?? \"\";\n }\n\n // Broadcast to debug listeners BEFORE the stream-closed gate below.\n // Intentional: debug subscribers (e.g. the VS Code Inspector panel)\n // should still receive trailing events after the SSE client for\n // this request closed its connection — they're independent\n // consumers observing the underlying runtime, not the request's\n // response stream.\n //\n // Wrapped in try/catch so a buggy debug subscriber can't propagate\n // an exception into this observer — if the throw reached the\n // `next` callback it would get routed to `error` by RxJS, closing\n // the SSE stream for an unrelated reason. Log via `logError` and\n // move on.\n if (debugEventBus) {\n try {\n debugEventBus.broadcast(event, {\n agentId: agentId ?? \"\",\n threadId: debugThreadId,\n runId: debugRunId,\n });\n } catch (broadcastError) {\n logError(broadcastError);\n }\n }\n\n if (!request.signal.aborted && !streamClosed) {\n try {\n eventCount++;\n if (debug?.events) {\n loggedEventCount++;\n if (debug.verbose) {\n debugLogger!.debug({ event }, \"Event emitted\");\n } else {\n debugLogger!.debug(\n { type: event.type, ...summarizeEvent(event) },\n \"Event emitted\",\n );\n }\n }\n await writer.write(encoder.encode(event));\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n streamClosed = true;\n } else {\n // Non-abort write failures (backpressure disconnects,\n // transform-stream exceptions, …) were previously swallowed\n // silently — `streamClosed` stayed `false` and the next\n // event re-attempted a broken writer. Log and mark the\n // stream closed so we stop trying.\n logError(error);\n streamClosed = true;\n }\n }\n }\n },\n error: async (error) => {\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { error: error instanceof Error ? error.message : String(error) },\n \"SSE stream errored\",\n );\n }\n logError(error);\n await closeStream();\n },\n complete: async () => {\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { eventCount, loggedEventCount },\n \"SSE stream completed\",\n );\n }\n await closeStream();\n },\n });\n\n // If the client disconnected before the subscription was created,\n // unsubscribe immediately to avoid leaking the observable.\n if (request.signal.aborted) {\n subscription.unsubscribe();\n }\n })().catch(async (error) => {\n logError(error);\n await closeStream();\n });\n\n request.signal.addEventListener(\"abort\", () => {\n subscription?.unsubscribe();\n });\n\n return new Response(stream.readable, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n\nfunction summarizeEvent(event: BaseEvent): Record<string, unknown> {\n const e = event as any;\n const summary: Record<string, unknown> = {};\n\n if (e.messageId) summary.messageId = e.messageId;\n if (e.toolCallId) summary.toolCallId = e.toolCallId;\n if (e.toolCallName) summary.toolCallName = e.toolCallName;\n if (e.role) summary.role = e.role;\n if (e.delta != null && typeof e.delta === \"string\")\n summary.deltaLength = e.delta.length;\n if (e.snapshot && typeof e.snapshot === \"object\")\n summary.snapshotKeys = Object.keys(e.snapshot);\n if (e.delta && Array.isArray(e.delta))\n summary.operationCount = e.delta.length;\n if (e.threadId) summary.threadId = e.threadId;\n if (e.runId) summary.runId = e.runId;\n if (e.message) summary.message = e.message;\n if (e.code) summary.code = e.code;\n if (e.stepName) summary.stepName = e.stepName;\n\n return summary;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sse-response.cjs","names":["EventEncoder","createLogger"],"sources":["../../../../../src/v2/runtime/handlers/shared/sse-response.ts"],"sourcesContent":["import type { BaseEvent } from \"@ag-ui/client\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { createLogger } from \"../../../../lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../../lib/logger\";\nimport { telemetry } from \"../../telemetry\";\nimport type { DebugEventBus } from \"../../core/debug-event-bus\";\nimport type {\n RuntimeErrorPhase,\n RuntimeErrorReporter,\n} from \"../../core/runtime-error-reporter\";\n\ninterface CreateSseEventResponseParams {\n request: Request;\n observableFactory: () =>\n | Promise<Observable<BaseEvent>>\n | Observable<BaseEvent>;\n debugEventBus?: DebugEventBus;\n agentId?: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n /**\n * Whether to emit `oss.runtime.agent_execution_stream_*` telemetry for this\n * stream. Defaults to `true`. The stateless `/suggest` path sets this to\n * `false`: a suggestion is a side-effect-free structured completion, not a\n * tracked run, and under `available: \"always\"` it fires often enough to flood\n * run telemetry.\n */\n captureTelemetry?: boolean;\n runtimeErrorReporter?: RuntimeErrorReporter;\n startTime?: number;\n}\n\nexport function createSseEventResponse({\n request,\n observableFactory,\n debugEventBus,\n agentId,\n debug,\n logger,\n captureTelemetry = true,\n runtimeErrorReporter,\n startTime,\n}: CreateSseEventResponseParams): Response {\n const stream = new TransformStream();\n const writer = stream.writable.getWriter();\n const encoder = new EventEncoder();\n let streamClosed = false;\n let debugThreadId = \"\";\n let debugRunId = \"\";\n\n const debugLogger = debug?.enabled\n ? (logger ??\n createLogger({ level: \"debug\", component: \"copilotkit-debug\" }))\n : undefined;\n\n const closeStream = async () => {\n if (!streamClosed) {\n try {\n await writer.close();\n streamClosed = true;\n } catch {\n // Stream already closed.\n }\n }\n };\n\n const logError = (error: unknown) => {\n console.error(\"Error running agent:\", error);\n console.error(\n \"Error stack:\",\n error instanceof Error ? error.stack : \"No stack trace\",\n );\n console.error(\"Error details:\", {\n name: error instanceof Error ? error.name : \"Unknown\",\n message: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.cause : undefined,\n });\n };\n\n let subscription: Subscription | undefined;\n let agentErrorReported = false;\n\n const reportAgentError = (error: unknown, phase: RuntimeErrorPhase) => {\n if (agentErrorReported) return;\n agentErrorReported = true;\n runtimeErrorReporter?.report({\n request,\n error,\n operation: \"agent.run\",\n agentId,\n threadId: debugThreadId || undefined,\n runId: debugRunId || undefined,\n phase,\n startTime,\n });\n };\n\n (async () => {\n const observable = await observableFactory();\n\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n }\n\n if (debug?.lifecycle) {\n debugLogger!.debug(\"SSE stream opened\");\n }\n\n let eventCount = 0;\n let loggedEventCount = 0;\n\n subscription = observable.subscribe({\n next: async (event) => {\n // Extract threadId/runId from RUN_STARTED\n if (event.type === \"RUN_STARTED\") {\n const e = event as { threadId?: string; runId?: string };\n debugThreadId = e.threadId ?? \"\";\n debugRunId = e.runId ?? \"\";\n }\n\n if (event.type === \"RUN_ERROR\") {\n const e = event as {\n message?: unknown;\n threadId?: string;\n runId?: string;\n };\n debugThreadId = e.threadId ?? debugThreadId;\n debugRunId = e.runId ?? debugRunId;\n reportAgentError(\n new Error(\n typeof e.message === \"string\"\n ? e.message\n : \"Runner reported a run error\",\n ),\n \"sse.subscription\",\n );\n }\n\n // Broadcast to debug listeners BEFORE the stream-closed gate below.\n // Intentional: debug subscribers (e.g. the VS Code Inspector panel)\n // should still receive trailing events after the SSE client for\n // this request closed its connection — they're independent\n // consumers observing the underlying runtime, not the request's\n // response stream.\n //\n // Wrapped in try/catch so a buggy debug subscriber can't propagate\n // an exception into this observer — if the throw reached the\n // `next` callback it would get routed to `error` by RxJS, closing\n // the SSE stream for an unrelated reason. Log via `logError` and\n // move on.\n if (debugEventBus) {\n try {\n debugEventBus.broadcast(event, {\n agentId: agentId ?? \"\",\n threadId: debugThreadId,\n runId: debugRunId,\n });\n } catch (broadcastError) {\n logError(broadcastError);\n }\n }\n\n if (!request.signal.aborted && !streamClosed) {\n try {\n eventCount++;\n if (debug?.events) {\n loggedEventCount++;\n if (debug.verbose) {\n debugLogger!.debug({ event }, \"Event emitted\");\n } else {\n debugLogger!.debug(\n { type: event.type, ...summarizeEvent(event) },\n \"Event emitted\",\n );\n }\n }\n await writer.write(encoder.encode(event));\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n streamClosed = true;\n } else {\n // Non-abort write failures (backpressure disconnects,\n // transform-stream exceptions, …) were previously swallowed\n // silently — `streamClosed` stayed `false` and the next\n // event re-attempted a broken writer. Log and mark the\n // stream closed so we stop trying.\n logError(error);\n streamClosed = true;\n }\n }\n }\n },\n error: async (error) => {\n reportAgentError(error, \"sse.subscription\");\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { error: error instanceof Error ? error.message : String(error) },\n \"SSE stream errored\",\n );\n }\n logError(error);\n await closeStream();\n },\n complete: async () => {\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { eventCount, loggedEventCount },\n \"SSE stream completed\",\n );\n }\n await closeStream();\n },\n });\n\n // If the client disconnected before the subscription was created,\n // unsubscribe immediately to avoid leaking the observable.\n if (request.signal.aborted) {\n subscription.unsubscribe();\n }\n })().catch(async (error) => {\n reportAgentError(error, \"sse.factory\");\n logError(error);\n await closeStream();\n });\n\n request.signal.addEventListener(\"abort\", () => {\n subscription?.unsubscribe();\n });\n\n return new Response(stream.readable, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n\nfunction summarizeEvent(event: BaseEvent): Record<string, unknown> {\n const e = event as any;\n const summary: Record<string, unknown> = {};\n\n if (e.messageId) summary.messageId = e.messageId;\n if (e.toolCallId) summary.toolCallId = e.toolCallId;\n if (e.toolCallName) summary.toolCallName = e.toolCallName;\n if (e.role) summary.role = e.role;\n if (e.delta != null && typeof e.delta === \"string\")\n summary.deltaLength = e.delta.length;\n if (e.snapshot && typeof e.snapshot === \"object\")\n summary.snapshotKeys = Object.keys(e.snapshot);\n if (e.delta && Array.isArray(e.delta))\n summary.operationCount = e.delta.length;\n if (e.threadId) summary.threadId = e.threadId;\n if (e.runId) summary.runId = e.runId;\n if (e.message) summary.message = e.message;\n if (e.code) summary.code = e.code;\n if (e.stepName) summary.stepName = e.stepName;\n\n return summary;\n}\n"],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import telemetry from "../../telemetry/telemetry-client.mjs";
|
|
|
4
4
|
import { EventEncoder } from "@ag-ui/encoder";
|
|
5
5
|
|
|
6
6
|
//#region src/v2/runtime/handlers/shared/sse-response.ts
|
|
7
|
-
function createSseEventResponse({ request, observableFactory, debugEventBus, agentId, debug, logger, captureTelemetry = true }) {
|
|
7
|
+
function createSseEventResponse({ request, observableFactory, debugEventBus, agentId, debug, logger, captureTelemetry = true, runtimeErrorReporter, startTime }) {
|
|
8
8
|
const stream = new TransformStream();
|
|
9
9
|
const writer = stream.writable.getWriter();
|
|
10
10
|
const encoder = new EventEncoder();
|
|
@@ -31,6 +31,21 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
31
31
|
});
|
|
32
32
|
};
|
|
33
33
|
let subscription;
|
|
34
|
+
let agentErrorReported = false;
|
|
35
|
+
const reportAgentError = (error, phase) => {
|
|
36
|
+
if (agentErrorReported) return;
|
|
37
|
+
agentErrorReported = true;
|
|
38
|
+
runtimeErrorReporter?.report({
|
|
39
|
+
request,
|
|
40
|
+
error,
|
|
41
|
+
operation: "agent.run",
|
|
42
|
+
agentId,
|
|
43
|
+
threadId: debugThreadId || void 0,
|
|
44
|
+
runId: debugRunId || void 0,
|
|
45
|
+
phase,
|
|
46
|
+
startTime
|
|
47
|
+
});
|
|
48
|
+
};
|
|
34
49
|
(async () => {
|
|
35
50
|
const observable = await observableFactory();
|
|
36
51
|
if (captureTelemetry) telemetry.capture("oss.runtime.agent_execution_stream_started", {});
|
|
@@ -44,6 +59,12 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
44
59
|
debugThreadId = e.threadId ?? "";
|
|
45
60
|
debugRunId = e.runId ?? "";
|
|
46
61
|
}
|
|
62
|
+
if (event.type === "RUN_ERROR") {
|
|
63
|
+
const e = event;
|
|
64
|
+
debugThreadId = e.threadId ?? debugThreadId;
|
|
65
|
+
debugRunId = e.runId ?? debugRunId;
|
|
66
|
+
reportAgentError(new Error(typeof e.message === "string" ? e.message : "Runner reported a run error"), "sse.subscription");
|
|
67
|
+
}
|
|
47
68
|
if (debugEventBus) try {
|
|
48
69
|
debugEventBus.broadcast(event, {
|
|
49
70
|
agentId: agentId ?? "",
|
|
@@ -73,6 +94,7 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
73
94
|
}
|
|
74
95
|
},
|
|
75
96
|
error: async (error) => {
|
|
97
|
+
reportAgentError(error, "sse.subscription");
|
|
76
98
|
if (captureTelemetry) telemetry.capture("oss.runtime.agent_execution_stream_errored", { error: error instanceof Error ? error.message : String(error) });
|
|
77
99
|
if (debug?.lifecycle) debugLogger.debug({ error: error instanceof Error ? error.message : String(error) }, "SSE stream errored");
|
|
78
100
|
logError(error);
|
|
@@ -89,6 +111,7 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
|
|
|
89
111
|
});
|
|
90
112
|
if (request.signal.aborted) subscription.unsubscribe();
|
|
91
113
|
})().catch(async (error) => {
|
|
114
|
+
reportAgentError(error, "sse.factory");
|
|
92
115
|
logError(error);
|
|
93
116
|
await closeStream();
|
|
94
117
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse-response.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/shared/sse-response.ts"],"sourcesContent":["import type { BaseEvent } from \"@ag-ui/client\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { createLogger } from \"../../../../lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../../lib/logger\";\nimport { telemetry } from \"../../telemetry\";\nimport type { DebugEventBus } from \"../../core/debug-event-bus\";\n\ninterface CreateSseEventResponseParams {\n request: Request;\n observableFactory: () =>\n | Promise<Observable<BaseEvent>>\n | Observable<BaseEvent>;\n debugEventBus?: DebugEventBus;\n agentId?: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n /**\n * Whether to emit `oss.runtime.agent_execution_stream_*` telemetry for this\n * stream. Defaults to `true`. The stateless `/suggest` path sets this to\n * `false`: a suggestion is a side-effect-free structured completion, not a\n * tracked run, and under `available: \"always\"` it fires often enough to flood\n * run telemetry.\n */\n captureTelemetry?: boolean;\n}\n\nexport function createSseEventResponse({\n request,\n observableFactory,\n debugEventBus,\n agentId,\n debug,\n logger,\n captureTelemetry = true,\n}: CreateSseEventResponseParams): Response {\n const stream = new TransformStream();\n const writer = stream.writable.getWriter();\n const encoder = new EventEncoder();\n let streamClosed = false;\n let debugThreadId = \"\";\n let debugRunId = \"\";\n\n const debugLogger = debug?.enabled\n ? (logger ??\n createLogger({ level: \"debug\", component: \"copilotkit-debug\" }))\n : undefined;\n\n const closeStream = async () => {\n if (!streamClosed) {\n try {\n await writer.close();\n streamClosed = true;\n } catch {\n // Stream already closed.\n }\n }\n };\n\n const logError = (error: unknown) => {\n console.error(\"Error running agent:\", error);\n console.error(\n \"Error stack:\",\n error instanceof Error ? error.stack : \"No stack trace\",\n );\n console.error(\"Error details:\", {\n name: error instanceof Error ? error.name : \"Unknown\",\n message: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.cause : undefined,\n });\n };\n\n let subscription: Subscription | undefined;\n\n (async () => {\n const observable = await observableFactory();\n\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n }\n\n if (debug?.lifecycle) {\n debugLogger!.debug(\"SSE stream opened\");\n }\n\n let eventCount = 0;\n let loggedEventCount = 0;\n\n subscription = observable.subscribe({\n next: async (event) => {\n // Extract threadId/runId from RUN_STARTED\n if (event.type === \"RUN_STARTED\") {\n const e = event as { threadId?: string; runId?: string };\n debugThreadId = e.threadId ?? \"\";\n debugRunId = e.runId ?? \"\";\n }\n\n // Broadcast to debug listeners BEFORE the stream-closed gate below.\n // Intentional: debug subscribers (e.g. the VS Code Inspector panel)\n // should still receive trailing events after the SSE client for\n // this request closed its connection — they're independent\n // consumers observing the underlying runtime, not the request's\n // response stream.\n //\n // Wrapped in try/catch so a buggy debug subscriber can't propagate\n // an exception into this observer — if the throw reached the\n // `next` callback it would get routed to `error` by RxJS, closing\n // the SSE stream for an unrelated reason. Log via `logError` and\n // move on.\n if (debugEventBus) {\n try {\n debugEventBus.broadcast(event, {\n agentId: agentId ?? \"\",\n threadId: debugThreadId,\n runId: debugRunId,\n });\n } catch (broadcastError) {\n logError(broadcastError);\n }\n }\n\n if (!request.signal.aborted && !streamClosed) {\n try {\n eventCount++;\n if (debug?.events) {\n loggedEventCount++;\n if (debug.verbose) {\n debugLogger!.debug({ event }, \"Event emitted\");\n } else {\n debugLogger!.debug(\n { type: event.type, ...summarizeEvent(event) },\n \"Event emitted\",\n );\n }\n }\n await writer.write(encoder.encode(event));\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n streamClosed = true;\n } else {\n // Non-abort write failures (backpressure disconnects,\n // transform-stream exceptions, …) were previously swallowed\n // silently — `streamClosed` stayed `false` and the next\n // event re-attempted a broken writer. Log and mark the\n // stream closed so we stop trying.\n logError(error);\n streamClosed = true;\n }\n }\n }\n },\n error: async (error) => {\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { error: error instanceof Error ? error.message : String(error) },\n \"SSE stream errored\",\n );\n }\n logError(error);\n await closeStream();\n },\n complete: async () => {\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { eventCount, loggedEventCount },\n \"SSE stream completed\",\n );\n }\n await closeStream();\n },\n });\n\n // If the client disconnected before the subscription was created,\n // unsubscribe immediately to avoid leaking the observable.\n if (request.signal.aborted) {\n subscription.unsubscribe();\n }\n })().catch(async (error) => {\n logError(error);\n await closeStream();\n });\n\n request.signal.addEventListener(\"abort\", () => {\n subscription?.unsubscribe();\n });\n\n return new Response(stream.readable, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n\nfunction summarizeEvent(event: BaseEvent): Record<string, unknown> {\n const e = event as any;\n const summary: Record<string, unknown> = {};\n\n if (e.messageId) summary.messageId = e.messageId;\n if (e.toolCallId) summary.toolCallId = e.toolCallId;\n if (e.toolCallName) summary.toolCallName = e.toolCallName;\n if (e.role) summary.role = e.role;\n if (e.delta != null && typeof e.delta === \"string\")\n summary.deltaLength = e.delta.length;\n if (e.snapshot && typeof e.snapshot === \"object\")\n summary.snapshotKeys = Object.keys(e.snapshot);\n if (e.delta && Array.isArray(e.delta))\n summary.operationCount = e.delta.length;\n if (e.threadId) summary.threadId = e.threadId;\n if (e.runId) summary.runId = e.runId;\n if (e.message) summary.message = e.message;\n if (e.code) summary.code = e.code;\n if (e.stepName) summary.stepName = e.stepName;\n\n return summary;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sse-response.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/shared/sse-response.ts"],"sourcesContent":["import type { BaseEvent } from \"@ag-ui/client\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { Observable, Subscription } from \"rxjs\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { createLogger } from \"../../../../lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../../lib/logger\";\nimport { telemetry } from \"../../telemetry\";\nimport type { DebugEventBus } from \"../../core/debug-event-bus\";\nimport type {\n RuntimeErrorPhase,\n RuntimeErrorReporter,\n} from \"../../core/runtime-error-reporter\";\n\ninterface CreateSseEventResponseParams {\n request: Request;\n observableFactory: () =>\n | Promise<Observable<BaseEvent>>\n | Observable<BaseEvent>;\n debugEventBus?: DebugEventBus;\n agentId?: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n /**\n * Whether to emit `oss.runtime.agent_execution_stream_*` telemetry for this\n * stream. Defaults to `true`. The stateless `/suggest` path sets this to\n * `false`: a suggestion is a side-effect-free structured completion, not a\n * tracked run, and under `available: \"always\"` it fires often enough to flood\n * run telemetry.\n */\n captureTelemetry?: boolean;\n runtimeErrorReporter?: RuntimeErrorReporter;\n startTime?: number;\n}\n\nexport function createSseEventResponse({\n request,\n observableFactory,\n debugEventBus,\n agentId,\n debug,\n logger,\n captureTelemetry = true,\n runtimeErrorReporter,\n startTime,\n}: CreateSseEventResponseParams): Response {\n const stream = new TransformStream();\n const writer = stream.writable.getWriter();\n const encoder = new EventEncoder();\n let streamClosed = false;\n let debugThreadId = \"\";\n let debugRunId = \"\";\n\n const debugLogger = debug?.enabled\n ? (logger ??\n createLogger({ level: \"debug\", component: \"copilotkit-debug\" }))\n : undefined;\n\n const closeStream = async () => {\n if (!streamClosed) {\n try {\n await writer.close();\n streamClosed = true;\n } catch {\n // Stream already closed.\n }\n }\n };\n\n const logError = (error: unknown) => {\n console.error(\"Error running agent:\", error);\n console.error(\n \"Error stack:\",\n error instanceof Error ? error.stack : \"No stack trace\",\n );\n console.error(\"Error details:\", {\n name: error instanceof Error ? error.name : \"Unknown\",\n message: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.cause : undefined,\n });\n };\n\n let subscription: Subscription | undefined;\n let agentErrorReported = false;\n\n const reportAgentError = (error: unknown, phase: RuntimeErrorPhase) => {\n if (agentErrorReported) return;\n agentErrorReported = true;\n runtimeErrorReporter?.report({\n request,\n error,\n operation: \"agent.run\",\n agentId,\n threadId: debugThreadId || undefined,\n runId: debugRunId || undefined,\n phase,\n startTime,\n });\n };\n\n (async () => {\n const observable = await observableFactory();\n\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n }\n\n if (debug?.lifecycle) {\n debugLogger!.debug(\"SSE stream opened\");\n }\n\n let eventCount = 0;\n let loggedEventCount = 0;\n\n subscription = observable.subscribe({\n next: async (event) => {\n // Extract threadId/runId from RUN_STARTED\n if (event.type === \"RUN_STARTED\") {\n const e = event as { threadId?: string; runId?: string };\n debugThreadId = e.threadId ?? \"\";\n debugRunId = e.runId ?? \"\";\n }\n\n if (event.type === \"RUN_ERROR\") {\n const e = event as {\n message?: unknown;\n threadId?: string;\n runId?: string;\n };\n debugThreadId = e.threadId ?? debugThreadId;\n debugRunId = e.runId ?? debugRunId;\n reportAgentError(\n new Error(\n typeof e.message === \"string\"\n ? e.message\n : \"Runner reported a run error\",\n ),\n \"sse.subscription\",\n );\n }\n\n // Broadcast to debug listeners BEFORE the stream-closed gate below.\n // Intentional: debug subscribers (e.g. the VS Code Inspector panel)\n // should still receive trailing events after the SSE client for\n // this request closed its connection — they're independent\n // consumers observing the underlying runtime, not the request's\n // response stream.\n //\n // Wrapped in try/catch so a buggy debug subscriber can't propagate\n // an exception into this observer — if the throw reached the\n // `next` callback it would get routed to `error` by RxJS, closing\n // the SSE stream for an unrelated reason. Log via `logError` and\n // move on.\n if (debugEventBus) {\n try {\n debugEventBus.broadcast(event, {\n agentId: agentId ?? \"\",\n threadId: debugThreadId,\n runId: debugRunId,\n });\n } catch (broadcastError) {\n logError(broadcastError);\n }\n }\n\n if (!request.signal.aborted && !streamClosed) {\n try {\n eventCount++;\n if (debug?.events) {\n loggedEventCount++;\n if (debug.verbose) {\n debugLogger!.debug({ event }, \"Event emitted\");\n } else {\n debugLogger!.debug(\n { type: event.type, ...summarizeEvent(event) },\n \"Event emitted\",\n );\n }\n }\n await writer.write(encoder.encode(event));\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n streamClosed = true;\n } else {\n // Non-abort write failures (backpressure disconnects,\n // transform-stream exceptions, …) were previously swallowed\n // silently — `streamClosed` stayed `false` and the next\n // event re-attempted a broken writer. Log and mark the\n // stream closed so we stop trying.\n logError(error);\n streamClosed = true;\n }\n }\n }\n },\n error: async (error) => {\n reportAgentError(error, \"sse.subscription\");\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { error: error instanceof Error ? error.message : String(error) },\n \"SSE stream errored\",\n );\n }\n logError(error);\n await closeStream();\n },\n complete: async () => {\n if (captureTelemetry) {\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n }\n if (debug?.lifecycle) {\n debugLogger!.debug(\n { eventCount, loggedEventCount },\n \"SSE stream completed\",\n );\n }\n await closeStream();\n },\n });\n\n // If the client disconnected before the subscription was created,\n // unsubscribe immediately to avoid leaking the observable.\n if (request.signal.aborted) {\n subscription.unsubscribe();\n }\n })().catch(async (error) => {\n reportAgentError(error, \"sse.factory\");\n logError(error);\n await closeStream();\n });\n\n request.signal.addEventListener(\"abort\", () => {\n subscription?.unsubscribe();\n });\n\n return new Response(stream.readable, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n\nfunction summarizeEvent(event: BaseEvent): Record<string, unknown> {\n const e = event as any;\n const summary: Record<string, unknown> = {};\n\n if (e.messageId) summary.messageId = e.messageId;\n if (e.toolCallId) summary.toolCallId = e.toolCallId;\n if (e.toolCallName) summary.toolCallName = e.toolCallName;\n if (e.role) summary.role = e.role;\n if (e.delta != null && typeof e.delta === \"string\")\n summary.deltaLength = e.delta.length;\n if (e.snapshot && typeof e.snapshot === \"object\")\n summary.snapshotKeys = Object.keys(e.snapshot);\n if (e.delta && Array.isArray(e.delta))\n summary.operationCount = e.delta.length;\n if (e.threadId) summary.threadId = e.threadId;\n if (e.runId) summary.runId = e.runId;\n if (e.message) summary.message = e.message;\n if (e.code) summary.code = e.code;\n if (e.stepName) summary.stepName = e.stepName;\n\n return summary;\n}\n"],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@ function handleSseConnect({ runtime, request, agentId, threadId, agent }) {
|
|
|
10
10
|
agentId,
|
|
11
11
|
observableFactory: () => runtime.runner.connect({
|
|
12
12
|
threadId,
|
|
13
|
+
agentId,
|
|
13
14
|
headers: require_header_utils.mergeForwardableHeaders(agent?.headers, request, runtime.forwardHeadersPolicy ?? require_header_utils.resolveForwardHeadersPolicy(void 0))
|
|
14
15
|
})
|
|
15
16
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect.cjs","names":["createSseEventResponse","mergeForwardableHeaders","resolveForwardHeadersPolicy"],"sources":["../../../../../src/v2/runtime/handlers/sse/connect.ts"],"sourcesContent":["import type { AbstractAgent } from \"@ag-ui/client\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\nimport {\n mergeForwardableHeaders,\n resolveForwardHeadersPolicy,\n} from \"../header-utils\";\n\n/**\n * `headers` lives on the HTTP-backed agent configs (e.g. `HttpAgent`), not on\n * the base `AbstractAgent`. Mirror the runtime's own optional-headers shape so\n * we can read server-configured headers off the per-request clone without a\n * cast. See `agent-utils.ts`.\n */\ntype AgentWithHeaders = AbstractAgent & {\n headers?: Record<string, string>;\n};\n\ninterface HandleSseConnectParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n threadId: string;\n /**\n * The per-request agent clone, carrying any server-configured `agent.headers`\n * (e.g. service-to-service auth). Used only to compute the merged header set\n * threaded into `runner.connect` below — see the note there for why that\n * merge is forward-looking plumbing rather than active outbound auth today.\n */\n agent?: AgentWithHeaders;\n}\n\nexport function handleSseConnect({\n runtime,\n request,\n agentId,\n threadId,\n agent,\n}: HandleSseConnectParams): Response {\n return createSseEventResponse({\n request,\n debugEventBus: runtime.debugEventBus,\n // Forward the real agentId so debug envelopes reflect the agent the\n // route resolved to — not the literal string \"connect\".\n agentId,\n observableFactory: () =>\n runtime.runner.connect({\n threadId,\n // Forward-looking plumbing: we compute the merged header set (server\n // `agent.headers` win on collision, case-insensitively; non-colliding\n // inbound headers still forward — see `mergeForwardableHeaders`, #5712)\n // and thread it into `runner.connect`. NO shipped runner consumes the\n // `headers` field of `AgentRunnerConnectRequest` today — every runner\n // (in-memory, intelligence, telemetry, sqlite) reads only `threadId`.\n // The real outbound header forwarding is the /run path, where\n // `cloneAgentForRequest` mutates `agent.headers` directly\n // (agent-utils.ts). This wiring exists so a future outbound-connecting\n // runner can pick the merged headers up without a route change; the\n // collision precedence noted here is purely about that merge, not about\n // middleware/mutation parity with /run.\n headers: mergeForwardableHeaders(\n agent?.headers,\n request,\n // Optional on `CopilotRuntimeLike` (non-breaking minor release);\n // coalesce a policy-less external implementor to the default resolved\n // policy (default-on denylist) instead of dereffing undefined.\n runtime.forwardHeadersPolicy ??\n resolveForwardHeadersPolicy(undefined),\n ),\n }),\n });\n}\n"],"mappings":";;;;;AAgCA,SAAgB,iBAAiB,EAC/B,SACA,SACA,SACA,UACA,SACmC;AACnC,QAAOA,4CAAuB;EAC5B;EACA,eAAe,QAAQ;EAGvB;EACA,yBACE,QAAQ,OAAO,QAAQ;GACrB;GAaA,SAASC,6CACP,OAAO,SACP,SAIA,QAAQ,wBACNC,iDAA4B,OAAU,CACzC;GACF,CAAC;EACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"connect.cjs","names":["createSseEventResponse","mergeForwardableHeaders","resolveForwardHeadersPolicy"],"sources":["../../../../../src/v2/runtime/handlers/sse/connect.ts"],"sourcesContent":["import type { AbstractAgent } from \"@ag-ui/client\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\nimport {\n mergeForwardableHeaders,\n resolveForwardHeadersPolicy,\n} from \"../header-utils\";\n\n/**\n * `headers` lives on the HTTP-backed agent configs (e.g. `HttpAgent`), not on\n * the base `AbstractAgent`. Mirror the runtime's own optional-headers shape so\n * we can read server-configured headers off the per-request clone without a\n * cast. See `agent-utils.ts`.\n */\ntype AgentWithHeaders = AbstractAgent & {\n headers?: Record<string, string>;\n};\n\ninterface HandleSseConnectParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n threadId: string;\n /**\n * The per-request agent clone, carrying any server-configured `agent.headers`\n * (e.g. service-to-service auth). Used only to compute the merged header set\n * threaded into `runner.connect` below — see the note there for why that\n * merge is forward-looking plumbing rather than active outbound auth today.\n */\n agent?: AgentWithHeaders;\n}\n\nexport function handleSseConnect({\n runtime,\n request,\n agentId,\n threadId,\n agent,\n}: HandleSseConnectParams): Response {\n return createSseEventResponse({\n request,\n debugEventBus: runtime.debugEventBus,\n // Forward the real agentId so debug envelopes reflect the agent the\n // route resolved to — not the literal string \"connect\".\n agentId,\n observableFactory: () =>\n runtime.runner.connect({\n threadId,\n agentId,\n // Forward-looking plumbing: we compute the merged header set (server\n // `agent.headers` win on collision, case-insensitively; non-colliding\n // inbound headers still forward — see `mergeForwardableHeaders`, #5712)\n // and thread it into `runner.connect`. NO shipped runner consumes the\n // `headers` field of `AgentRunnerConnectRequest` today — every runner\n // (in-memory, intelligence, telemetry, sqlite) reads only `threadId`.\n // The real outbound header forwarding is the /run path, where\n // `cloneAgentForRequest` mutates `agent.headers` directly\n // (agent-utils.ts). This wiring exists so a future outbound-connecting\n // runner can pick the merged headers up without a route change; the\n // collision precedence noted here is purely about that merge, not about\n // middleware/mutation parity with /run.\n headers: mergeForwardableHeaders(\n agent?.headers,\n request,\n // Optional on `CopilotRuntimeLike` (non-breaking minor release);\n // coalesce a policy-less external implementor to the default resolved\n // policy (default-on denylist) instead of dereffing undefined.\n runtime.forwardHeadersPolicy ??\n resolveForwardHeadersPolicy(undefined),\n ),\n }),\n });\n}\n"],"mappings":";;;;;AAgCA,SAAgB,iBAAiB,EAC/B,SACA,SACA,SACA,UACA,SACmC;AACnC,QAAOA,4CAAuB;EAC5B;EACA,eAAe,QAAQ;EAGvB;EACA,yBACE,QAAQ,OAAO,QAAQ;GACrB;GACA;GAaA,SAASC,6CACP,OAAO,SACP,SAIA,QAAQ,wBACNC,iDAA4B,OAAU,CACzC;GACF,CAAC;EACL,CAAC"}
|
|
@@ -10,6 +10,7 @@ function handleSseConnect({ runtime, request, agentId, threadId, agent }) {
|
|
|
10
10
|
agentId,
|
|
11
11
|
observableFactory: () => runtime.runner.connect({
|
|
12
12
|
threadId,
|
|
13
|
+
agentId,
|
|
13
14
|
headers: mergeForwardableHeaders(agent?.headers, request, runtime.forwardHeadersPolicy ?? resolveForwardHeadersPolicy(void 0))
|
|
14
15
|
})
|
|
15
16
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/sse/connect.ts"],"sourcesContent":["import type { AbstractAgent } from \"@ag-ui/client\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\nimport {\n mergeForwardableHeaders,\n resolveForwardHeadersPolicy,\n} from \"../header-utils\";\n\n/**\n * `headers` lives on the HTTP-backed agent configs (e.g. `HttpAgent`), not on\n * the base `AbstractAgent`. Mirror the runtime's own optional-headers shape so\n * we can read server-configured headers off the per-request clone without a\n * cast. See `agent-utils.ts`.\n */\ntype AgentWithHeaders = AbstractAgent & {\n headers?: Record<string, string>;\n};\n\ninterface HandleSseConnectParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n threadId: string;\n /**\n * The per-request agent clone, carrying any server-configured `agent.headers`\n * (e.g. service-to-service auth). Used only to compute the merged header set\n * threaded into `runner.connect` below — see the note there for why that\n * merge is forward-looking plumbing rather than active outbound auth today.\n */\n agent?: AgentWithHeaders;\n}\n\nexport function handleSseConnect({\n runtime,\n request,\n agentId,\n threadId,\n agent,\n}: HandleSseConnectParams): Response {\n return createSseEventResponse({\n request,\n debugEventBus: runtime.debugEventBus,\n // Forward the real agentId so debug envelopes reflect the agent the\n // route resolved to — not the literal string \"connect\".\n agentId,\n observableFactory: () =>\n runtime.runner.connect({\n threadId,\n // Forward-looking plumbing: we compute the merged header set (server\n // `agent.headers` win on collision, case-insensitively; non-colliding\n // inbound headers still forward — see `mergeForwardableHeaders`, #5712)\n // and thread it into `runner.connect`. NO shipped runner consumes the\n // `headers` field of `AgentRunnerConnectRequest` today — every runner\n // (in-memory, intelligence, telemetry, sqlite) reads only `threadId`.\n // The real outbound header forwarding is the /run path, where\n // `cloneAgentForRequest` mutates `agent.headers` directly\n // (agent-utils.ts). This wiring exists so a future outbound-connecting\n // runner can pick the merged headers up without a route change; the\n // collision precedence noted here is purely about that merge, not about\n // middleware/mutation parity with /run.\n headers: mergeForwardableHeaders(\n agent?.headers,\n request,\n // Optional on `CopilotRuntimeLike` (non-breaking minor release);\n // coalesce a policy-less external implementor to the default resolved\n // policy (default-on denylist) instead of dereffing undefined.\n runtime.forwardHeadersPolicy ??\n resolveForwardHeadersPolicy(undefined),\n ),\n }),\n });\n}\n"],"mappings":";;;;;AAgCA,SAAgB,iBAAiB,EAC/B,SACA,SACA,SACA,UACA,SACmC;AACnC,QAAO,uBAAuB;EAC5B;EACA,eAAe,QAAQ;EAGvB;EACA,yBACE,QAAQ,OAAO,QAAQ;GACrB;GAaA,SAAS,wBACP,OAAO,SACP,SAIA,QAAQ,wBACN,4BAA4B,OAAU,CACzC;GACF,CAAC;EACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"connect.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/sse/connect.ts"],"sourcesContent":["import type { AbstractAgent } from \"@ag-ui/client\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\nimport {\n mergeForwardableHeaders,\n resolveForwardHeadersPolicy,\n} from \"../header-utils\";\n\n/**\n * `headers` lives on the HTTP-backed agent configs (e.g. `HttpAgent`), not on\n * the base `AbstractAgent`. Mirror the runtime's own optional-headers shape so\n * we can read server-configured headers off the per-request clone without a\n * cast. See `agent-utils.ts`.\n */\ntype AgentWithHeaders = AbstractAgent & {\n headers?: Record<string, string>;\n};\n\ninterface HandleSseConnectParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n threadId: string;\n /**\n * The per-request agent clone, carrying any server-configured `agent.headers`\n * (e.g. service-to-service auth). Used only to compute the merged header set\n * threaded into `runner.connect` below — see the note there for why that\n * merge is forward-looking plumbing rather than active outbound auth today.\n */\n agent?: AgentWithHeaders;\n}\n\nexport function handleSseConnect({\n runtime,\n request,\n agentId,\n threadId,\n agent,\n}: HandleSseConnectParams): Response {\n return createSseEventResponse({\n request,\n debugEventBus: runtime.debugEventBus,\n // Forward the real agentId so debug envelopes reflect the agent the\n // route resolved to — not the literal string \"connect\".\n agentId,\n observableFactory: () =>\n runtime.runner.connect({\n threadId,\n agentId,\n // Forward-looking plumbing: we compute the merged header set (server\n // `agent.headers` win on collision, case-insensitively; non-colliding\n // inbound headers still forward — see `mergeForwardableHeaders`, #5712)\n // and thread it into `runner.connect`. NO shipped runner consumes the\n // `headers` field of `AgentRunnerConnectRequest` today — every runner\n // (in-memory, intelligence, telemetry, sqlite) reads only `threadId`.\n // The real outbound header forwarding is the /run path, where\n // `cloneAgentForRequest` mutates `agent.headers` directly\n // (agent-utils.ts). This wiring exists so a future outbound-connecting\n // runner can pick the merged headers up without a route change; the\n // collision precedence noted here is purely about that merge, not about\n // middleware/mutation parity with /run.\n headers: mergeForwardableHeaders(\n agent?.headers,\n request,\n // Optional on `CopilotRuntimeLike` (non-breaking minor release);\n // coalesce a policy-less external implementor to the default resolved\n // policy (default-on denylist) instead of dereffing undefined.\n runtime.forwardHeadersPolicy ??\n resolveForwardHeadersPolicy(undefined),\n ),\n }),\n });\n}\n"],"mappings":";;;;;AAgCA,SAAgB,iBAAiB,EAC/B,SACA,SACA,SACA,UACA,SACmC;AACnC,QAAO,uBAAuB;EAC5B;EACA,eAAe,QAAQ;EAGvB;EACA,yBACE,QAAQ,OAAO,QAAQ;GACrB;GACA;GAaA,SAAS,wBACP,OAAO,SACP,SAIA,QAAQ,wBACN,4BAA4B,OAAU,CACzC;GACF,CAAC;EACL,CAAC"}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
require("reflect-metadata");
|
|
2
|
+
const require_runtime_error_reporter = require('../../core/runtime-error-reporter.cjs');
|
|
2
3
|
const require_sse_response = require('../shared/sse-response.cjs');
|
|
3
4
|
|
|
4
5
|
//#region src/v2/runtime/handlers/sse/run.ts
|
|
5
|
-
function handleSseRun({ runtime, request, agent, input, agentId, debug, logger }) {
|
|
6
|
+
function handleSseRun({ runtime, request, agent, input, agentId, debug, logger, startTime }) {
|
|
6
7
|
return require_sse_response.createSseEventResponse({
|
|
7
8
|
request,
|
|
8
9
|
debugEventBus: runtime.debugEventBus,
|
|
9
10
|
agentId,
|
|
10
11
|
debug,
|
|
11
12
|
logger,
|
|
13
|
+
runtimeErrorReporter: require_runtime_error_reporter.getRuntimeErrorReporter(runtime),
|
|
14
|
+
startTime,
|
|
12
15
|
observableFactory: () => runtime.runner.run({
|
|
13
16
|
threadId: input.threadId,
|
|
14
17
|
agent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.cjs","names":["createSseEventResponse"],"sources":["../../../../../src/v2/runtime/handlers/sse/run.ts"],"sourcesContent":["import { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport {
|
|
1
|
+
{"version":3,"file":"run.cjs","names":["createSseEventResponse","getRuntimeErrorReporter"],"sources":["../../../../../src/v2/runtime/handlers/sse/run.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport type { CopilotRuntimeLogger } from \"../../../../lib/logger\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { getRuntimeErrorReporter } from \"../../core/runtime-error-reporter\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\n\ninterface HandleSseRunParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n input: RunAgentInput;\n agentId: string;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n startTime?: number;\n}\n\nexport function handleSseRun({\n runtime,\n request,\n agent,\n input,\n agentId,\n debug,\n logger,\n startTime,\n}: HandleSseRunParams): Response {\n return createSseEventResponse({\n request,\n debugEventBus: runtime.debugEventBus,\n agentId,\n debug,\n logger,\n runtimeErrorReporter: getRuntimeErrorReporter(runtime),\n startTime,\n observableFactory: () =>\n runtime.runner.run({\n threadId: input.threadId,\n agent,\n input,\n }),\n });\n}\n"],"mappings":";;;;;AAmBA,SAAgB,aAAa,EAC3B,SACA,SACA,OACA,OACA,SACA,OACA,QACA,aAC+B;AAC/B,QAAOA,4CAAuB;EAC5B;EACA,eAAe,QAAQ;EACvB;EACA;EACA;EACA,sBAAsBC,uDAAwB,QAAQ;EACtD;EACA,yBACE,QAAQ,OAAO,IAAI;GACjB,UAAU,MAAM;GAChB;GACA;GACD,CAAC;EACL,CAAC"}
|