@copilotkit/runtime 1.79.2-canary.1792172552 → 1.81.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.
Files changed (165) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +15 -1
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.d.cts +5 -3
  4. package/dist/agent/index.d.cts.map +1 -1
  5. package/dist/agent/index.d.mts +4 -2
  6. package/dist/agent/index.d.mts.map +1 -1
  7. package/dist/agent/index.mjs.map +1 -1
  8. package/dist/lib/runtime/agent-integrations/langgraph/agent.cjs +25 -1
  9. package/dist/lib/runtime/agent-integrations/langgraph/agent.cjs.map +1 -1
  10. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts.map +1 -1
  11. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts.map +1 -1
  12. package/dist/lib/runtime/agent-integrations/langgraph/agent.mjs +25 -1
  13. package/dist/lib/runtime/agent-integrations/langgraph/agent.mjs.map +1 -1
  14. package/dist/lib/runtime/copilot-runtime.cjs +17 -3
  15. package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
  16. package/dist/lib/runtime/copilot-runtime.d.cts +2 -3
  17. package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
  18. package/dist/lib/runtime/copilot-runtime.d.mts +2 -3
  19. package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
  20. package/dist/lib/runtime/copilot-runtime.mjs +18 -4
  21. package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
  22. package/dist/lib/runtime/legacy-service-adapter-agent.cjs +360 -0
  23. package/dist/lib/runtime/legacy-service-adapter-agent.cjs.map +1 -0
  24. package/dist/lib/runtime/legacy-service-adapter-agent.mjs +359 -0
  25. package/dist/lib/runtime/legacy-service-adapter-agent.mjs.map +1 -0
  26. package/dist/lib/telemetry-client.cjs +12 -1
  27. package/dist/lib/telemetry-client.cjs.map +1 -1
  28. package/dist/lib/telemetry-client.mjs +12 -1
  29. package/dist/lib/telemetry-client.mjs.map +1 -1
  30. package/dist/package.cjs +6 -6
  31. package/dist/package.mjs +6 -6
  32. package/dist/service-adapters/events.cjs +91 -0
  33. package/dist/service-adapters/events.cjs.map +1 -1
  34. package/dist/service-adapters/events.d.cts +6 -1
  35. package/dist/service-adapters/events.d.cts.map +1 -1
  36. package/dist/service-adapters/events.d.mts +6 -1
  37. package/dist/service-adapters/events.d.mts.map +1 -1
  38. package/dist/service-adapters/events.mjs +90 -1
  39. package/dist/service-adapters/events.mjs.map +1 -1
  40. package/dist/service-adapters/langchain/langchain-adapter.cjs +1 -1
  41. package/dist/service-adapters/langchain/langchain-adapter.cjs.map +1 -1
  42. package/dist/service-adapters/langchain/langchain-adapter.d.cts.map +1 -1
  43. package/dist/service-adapters/langchain/langchain-adapter.d.mts.map +1 -1
  44. package/dist/service-adapters/langchain/langchain-adapter.mjs +2 -2
  45. package/dist/service-adapters/langchain/langchain-adapter.mjs.map +1 -1
  46. package/dist/service-adapters/langchain/utils.cjs +53 -15
  47. package/dist/service-adapters/langchain/utils.cjs.map +1 -1
  48. package/dist/service-adapters/langchain/utils.mjs +53 -16
  49. package/dist/service-adapters/langchain/utils.mjs.map +1 -1
  50. package/dist/v2/index.cjs +6 -0
  51. package/dist/v2/index.d.cts +7 -4
  52. package/dist/v2/index.d.mts +7 -4
  53. package/dist/v2/index.mjs +5 -3
  54. package/dist/v2/runtime/core/middleware-sse-parser.cjs +11 -2
  55. package/dist/v2/runtime/core/middleware-sse-parser.cjs.map +1 -1
  56. package/dist/v2/runtime/core/middleware-sse-parser.mjs +11 -2
  57. package/dist/v2/runtime/core/middleware-sse-parser.mjs.map +1 -1
  58. package/dist/v2/runtime/core/package-info.cjs +1 -1
  59. package/dist/v2/runtime/core/package-info.mjs +1 -1
  60. package/dist/v2/runtime/core/runtime.cjs +6 -3
  61. package/dist/v2/runtime/core/runtime.cjs.map +1 -1
  62. package/dist/v2/runtime/core/runtime.d.cts +15 -3
  63. package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
  64. package/dist/v2/runtime/core/runtime.d.mts +15 -3
  65. package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
  66. package/dist/v2/runtime/core/runtime.mjs +6 -3
  67. package/dist/v2/runtime/core/runtime.mjs.map +1 -1
  68. package/dist/v2/runtime/endpoints/express.cjs +2 -2
  69. package/dist/v2/runtime/endpoints/express.cjs.map +1 -1
  70. package/dist/v2/runtime/endpoints/express.mjs +2 -2
  71. package/dist/v2/runtime/endpoints/express.mjs.map +1 -1
  72. package/dist/v2/runtime/endpoints/node-fetch-handler.cjs +51 -1
  73. package/dist/v2/runtime/endpoints/node-fetch-handler.cjs.map +1 -1
  74. package/dist/v2/runtime/endpoints/node-fetch-handler.d.cts.map +1 -1
  75. package/dist/v2/runtime/endpoints/node-fetch-handler.d.mts.map +1 -1
  76. package/dist/v2/runtime/endpoints/node-fetch-handler.mjs +52 -2
  77. package/dist/v2/runtime/endpoints/node-fetch-handler.mjs.map +1 -1
  78. package/dist/v2/runtime/generative-ui/generative-ui-middleware.cjs +394 -0
  79. package/dist/v2/runtime/generative-ui/generative-ui-middleware.cjs.map +1 -0
  80. package/dist/v2/runtime/generative-ui/generative-ui-middleware.d.cts +21 -0
  81. package/dist/v2/runtime/generative-ui/generative-ui-middleware.d.cts.map +1 -0
  82. package/dist/v2/runtime/generative-ui/generative-ui-middleware.d.mts +21 -0
  83. package/dist/v2/runtime/generative-ui/generative-ui-middleware.d.mts.map +1 -0
  84. package/dist/v2/runtime/generative-ui/generative-ui-middleware.mjs +393 -0
  85. package/dist/v2/runtime/generative-ui/generative-ui-middleware.mjs.map +1 -0
  86. package/dist/v2/runtime/generative-ui/index.d.cts +3 -0
  87. package/dist/v2/runtime/generative-ui/index.d.mts +3 -0
  88. package/dist/v2/runtime/generative-ui/surface-writer.cjs +86 -0
  89. package/dist/v2/runtime/generative-ui/surface-writer.cjs.map +1 -0
  90. package/dist/v2/runtime/generative-ui/surface-writer.d.cts +33 -0
  91. package/dist/v2/runtime/generative-ui/surface-writer.d.cts.map +1 -0
  92. package/dist/v2/runtime/generative-ui/surface-writer.d.mts +33 -0
  93. package/dist/v2/runtime/generative-ui/surface-writer.d.mts.map +1 -0
  94. package/dist/v2/runtime/generative-ui/surface-writer.mjs +85 -0
  95. package/dist/v2/runtime/generative-ui/surface-writer.mjs.map +1 -0
  96. package/dist/v2/runtime/handlers/handle-run.cjs +8 -3
  97. package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
  98. package/dist/v2/runtime/handlers/handle-run.mjs +5 -1
  99. package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
  100. package/dist/v2/runtime/handlers/intelligence/run.cjs +2 -3
  101. package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
  102. package/dist/v2/runtime/handlers/intelligence/run.mjs +2 -3
  103. package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
  104. package/dist/v2/runtime/handlers/shared/agent-utils.cjs +7 -0
  105. package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
  106. package/dist/v2/runtime/handlers/shared/agent-utils.mjs +7 -0
  107. package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
  108. package/dist/v2/runtime/handlers/shared/sse-response.cjs +39 -0
  109. package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -1
  110. package/dist/v2/runtime/handlers/shared/sse-response.mjs +39 -0
  111. package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -1
  112. package/dist/v2/runtime/index.d.cts +7 -3
  113. package/dist/v2/runtime/index.d.cts.map +1 -1
  114. package/dist/v2/runtime/index.d.mts +7 -3
  115. package/dist/v2/runtime/index.d.mts.map +1 -1
  116. package/dist/v2/runtime/intelligence-platform/client.cjs +100 -1
  117. package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
  118. package/dist/v2/runtime/intelligence-platform/client.d.cts +33 -1
  119. package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
  120. package/dist/v2/runtime/intelligence-platform/client.d.mts +33 -1
  121. package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
  122. package/dist/v2/runtime/intelligence-platform/client.mjs +100 -1
  123. package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
  124. package/dist/v2/runtime/intelligence-platform/experimental.d.cts +27 -0
  125. package/dist/v2/runtime/intelligence-platform/experimental.d.cts.map +1 -0
  126. package/dist/v2/runtime/intelligence-platform/experimental.d.mts +27 -0
  127. package/dist/v2/runtime/intelligence-platform/experimental.d.mts.map +1 -0
  128. package/dist/v2/runtime/intelligence-platform/index.d.cts +2 -1
  129. package/dist/v2/runtime/intelligence-platform/index.d.mts +2 -1
  130. package/dist/v2/runtime/intelligence-platform/learning-management.cjs +204 -0
  131. package/dist/v2/runtime/intelligence-platform/learning-management.cjs.map +1 -0
  132. package/dist/v2/runtime/intelligence-platform/learning-management.d.cts +112 -0
  133. package/dist/v2/runtime/intelligence-platform/learning-management.d.cts.map +1 -0
  134. package/dist/v2/runtime/intelligence-platform/learning-management.d.mts +112 -0
  135. package/dist/v2/runtime/intelligence-platform/learning-management.d.mts.map +1 -0
  136. package/dist/v2/runtime/intelligence-platform/learning-management.mjs +194 -0
  137. package/dist/v2/runtime/intelligence-platform/learning-management.mjs.map +1 -0
  138. package/dist/v2/runtime/runner/agent-runner.cjs +16 -0
  139. package/dist/v2/runtime/runner/agent-runner.cjs.map +1 -1
  140. package/dist/v2/runtime/runner/agent-runner.d.cts +11 -1
  141. package/dist/v2/runtime/runner/agent-runner.d.cts.map +1 -1
  142. package/dist/v2/runtime/runner/agent-runner.d.mts +11 -1
  143. package/dist/v2/runtime/runner/agent-runner.d.mts.map +1 -1
  144. package/dist/v2/runtime/runner/agent-runner.mjs +16 -1
  145. package/dist/v2/runtime/runner/agent-runner.mjs.map +1 -1
  146. package/dist/v2/runtime/runner/in-memory.cjs +1 -1
  147. package/dist/v2/runtime/runner/in-memory.cjs.map +1 -1
  148. package/dist/v2/runtime/runner/in-memory.mjs +2 -2
  149. package/dist/v2/runtime/runner/in-memory.mjs.map +1 -1
  150. package/dist/v2/runtime/runner/index.d.cts +2 -2
  151. package/dist/v2/runtime/runner/index.d.mts +2 -2
  152. package/dist/v2/runtime/runner/index.mjs +1 -1
  153. package/dist/v2/runtime/runner/intelligence.cjs +25 -85
  154. package/dist/v2/runtime/runner/intelligence.cjs.map +1 -1
  155. package/dist/v2/runtime/runner/intelligence.d.cts +2 -31
  156. package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -1
  157. package/dist/v2/runtime/runner/intelligence.d.mts +2 -31
  158. package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -1
  159. package/dist/v2/runtime/runner/intelligence.mjs +27 -87
  160. package/dist/v2/runtime/runner/intelligence.mjs.map +1 -1
  161. package/package.json +8 -8
  162. package/dist/v2/runtime/endpoints/express-fetch-bridge.cjs +0 -82
  163. package/dist/v2/runtime/endpoints/express-fetch-bridge.cjs.map +0 -1
  164. package/dist/v2/runtime/endpoints/express-fetch-bridge.mjs +0 -81
  165. package/dist/v2/runtime/endpoints/express-fetch-bridge.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"agent-utils.cjs","names":["resolveAgents","isA2UIEnabled","A2UIMiddleware","isIntelligenceRuntime","resolveMcpAppsServers","MCPAppsMiddleware","OpenGenerativeUIMiddleware","mergeForwardableHeaders","resolveForwardHeadersPolicy","resolveIntelligenceUser","resolveWebMemory","grantAllowsMemory","errorResponse","MCPMiddleware","INTELLIGENCE_USER_ID_HEADER","INTELLIGENCE_MEMORY_GRANT_HEADER","RunAgentInputSchema"],"sources":["../../../../../src/v2/runtime/handlers/shared/agent-utils.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { RunAgentInputSchema } from \"@ag-ui/core/schemas\";\nimport {\n A2UIMiddleware,\n OpenGenerativeUIMiddleware,\n} from \"@copilotkit/shared/event-transforms\";\nimport { MCPAppsMiddleware } from \"@ag-ui/mcp-apps-middleware\";\nimport { MCPMiddleware } from \"@ag-ui/mcp-middleware\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport {\n isA2UIEnabled,\n isIntelligenceRuntime,\n resolveAgents,\n} from \"../../core/runtime\";\nimport {\n INTELLIGENCE_MEMORY_GRANT_HEADER,\n INTELLIGENCE_USER_ID_HEADER,\n} from \"../../intelligence-platform/client\";\nimport {\n mergeForwardableHeaders,\n resolveForwardHeadersPolicy,\n} from \"../header-utils\";\nimport { resolveMcpAppsServers } from \"./mcp-apps-servers\";\nimport { resolveIntelligenceUser } from \"./resolve-intelligence-user\";\nimport { grantAllowsMemory, resolveWebMemory } from \"./memory-policy\";\nimport { errorResponse } from \"./json-response\";\nimport { logger } from \"@copilotkit/shared\";\n\ntype MiddlewareCapableAgent = AbstractAgent & {\n use?: (middleware: unknown) => void;\n headers?: Record<string, string>;\n};\n\nexport interface RunAgentParameters {\n request: Request;\n runtime: CopilotRuntimeLike;\n agentId: string;\n}\n\nexport interface ConnectRequestBody extends RunAgentInput {\n lastSeenEventId?: string | null;\n}\n\n/**\n * Resolve `agentId` against the runtime's agents and return a per-request\n * clone of the matching agent.\n *\n * Dual return contract — both callers (`handle-run.ts`, `handle-connect.ts`)\n * depend on it:\n * - Returns a cloned `AbstractAgent` when the agent exists.\n * - Returns a 404 `Response` (`{ error: \"Agent not found\", ... }`) when the\n * agent is unknown. Callers MUST `instanceof Response`-check the result and\n * return it directly; this doubles as the connect/run path's agent-existence\n * guard, so skipping the check would let unknown agent ids slip through.\n *\n * The clone is what subsequent per-request mutation (middleware attach,\n * `agent.headers` merge) operates on, leaving the shared agent registration\n * untouched.\n */\nexport async function cloneAgentForRequest(\n runtime: CopilotRuntimeLike,\n agentId: string,\n request?: Request,\n): Promise<AbstractAgent | Response> {\n const agents = await resolveAgents(runtime.agents, request);\n\n if (!agents[agentId]) {\n return new Response(\n JSON.stringify({\n error: \"Agent not found\",\n message: `Agent '${agentId}' does not exist`,\n }),\n {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n return (agents[agentId] as AbstractAgent).clone() as AbstractAgent;\n}\n\nexport function configureAgentForRequest(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n /**\n * True when the React provider was given an A2UI catalog\n * (`<CopilotKit a2ui={{ catalog }}>`), forwarded per-run. A catalog alone is\n * enough to enable A2UI and inject the render tool — the developer no longer\n * has to also set `a2ui.injectA2UITool` on the runtime.\n */\n providerA2UIHasCatalog?: boolean;\n /** Retain proxy rejection even when no server is available to this agent. */\n isMcpProxyRequest?: boolean;\n}): void {\n const {\n runtime,\n request,\n agentId,\n providerA2UIHasCatalog,\n isMcpProxyRequest,\n } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n // A2UI is on when the runtime explicitly enables it, OR when the provider\n // forwarded a catalog — but an explicit `enabled: false` always wins (we\n // provide a quick default, never override a deeper opt-out).\n const a2uiEnabledByCatalog =\n !!providerA2UIHasCatalog && runtime.a2ui?.enabled !== false;\n\n if (isA2UIEnabled(runtime.a2ui) || a2uiEnabledByCatalog) {\n // `enabled` is a CopilotKit-level switch, not an A2UIMiddleware option —\n // drop it (alongside the agent filter) before forwarding to the middleware.\n const {\n agents: targetAgents,\n enabled: _enabled,\n injectA2UITool,\n ...a2uiOptions\n } = runtime.a2ui ?? {};\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(\n new A2UIMiddleware({\n ...a2uiOptions,\n // Default render-tool injection on when a catalog is present and the\n // developer hasn't set it explicitly. `??` means an explicit value\n // (including `false`) is always respected.\n injectA2UITool:\n injectA2UITool ?? (providerA2UIHasCatalog ? true : undefined),\n }),\n );\n }\n }\n\n if (isIntelligenceRuntime(runtime) && typeof agent.use === \"function\") {\n // Ordinary runs need no middleware without selected servers. Proxy requests\n // still need the upstream guard so they cannot fall through to the model.\n const mcpServers = resolveMcpAppsServers(\n runtime.mcpApps?.servers ?? [],\n agentId,\n );\n if (mcpServers.length > 0 || isMcpProxyRequest) {\n agent.use(\n new MCPAppsMiddleware({ mcpServers, discoveryFailureMode: \"throw\" }),\n );\n }\n } else if (runtime.mcpApps?.servers?.length) {\n const mcpServers = resolveMcpAppsServers(runtime.mcpApps.servers, agentId);\n\n if (mcpServers.length > 0 && typeof agent.use === \"function\") {\n agent.use(new MCPAppsMiddleware({ mcpServers }));\n }\n }\n\n if (runtime.openGenerativeUI) {\n const config = runtime.openGenerativeUI;\n const targetAgents = typeof config === \"object\" ? config.agents : undefined;\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(new OpenGenerativeUIMiddleware());\n }\n }\n\n // Forward eligible inbound headers onto the outgoing agent call under the\n // runtime's resolved forwarding policy (`authorization` / custom `x-*`, with\n // known infra/proxy/platform headers stripped by the default denylist —\n // #5712), but let headers the server explicitly configured on the agent WIN\n // on collision (case-insensitively): a server-set service-to-service token\n // (e.g. an IAM bearer) must never be silently overridden by a\n // browser/edge/platform-injected inbound header. See `mergeForwardableHeaders`\n // for the casing/duplicate-key rationale and `shouldForwardHeader` for breadth.\n agent.headers = mergeForwardableHeaders(\n agent.headers,\n request,\n // `forwardHeadersPolicy` is optional on the published `CopilotRuntimeLike`\n // interface (non-breaking minor release). Concrete runtimes always set it;\n // a policy-less external implementor falls back to the default resolved\n // policy (default-on denylist) so behavior stays identical and never derefs\n // undefined.\n runtime.forwardHeadersPolicy ?? resolveForwardHeadersPolicy(undefined),\n );\n}\n\n/**\n * Shared by the two places a run meets a middleware-less agent: before Memory\n * is resolved (nothing left to resolve) and after (Memory resolved to nothing).\n */\nconst NO_MIDDLEWARE_WARNING =\n \"CopilotKitIntelligence.enableEnterpriseLearning is enabled, but the agent \" +\n \"does not support middleware (no `.use()` method); Intelligence tools were \" +\n \"not attached for this run.\";\n\n/**\n * Attach CopilotKit Intelligence's MCP tools to the agent run when\n * `CopilotKitIntelligence` was constructed with\n * `enableEnterpriseLearning: true`. Uses `@ag-ui/mcp-middleware`, so the\n * tools are available uniformly across agent frameworks (not just\n * `BuiltInAgent`).\n *\n * The middleware sits on a per-request agent clone, so the per-request\n * auth (Bearer apiKey + resolved user-id) is baked into the transport\n * headers at attach time. If user resolution fails, attachment is\n * skipped silently — the intelligence run handler will reject the\n * request with the same error. Note this means `identifyUser` is\n * resolved twice per learning-enabled run (here and in the run handler);\n * the callback is expected to be idempotent and side-effect-free.\n *\n * Intentionally split out from `configureAgentForRequest`: this is only\n * relevant to actual agent runs, not auxiliary flows like thread-name\n * generation (which has no need for MCP tools and shouldn't pay the\n * `listTools` round-trip).\n */\nexport async function attachIntelligenceEnterpriseLearning(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n}): Promise<void | Response> {\n const { runtime, request } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n if (!isIntelligenceRuntime(runtime)) return;\n\n const learningEnabled =\n runtime.intelligence?.ɵisEnterpriseLearningEnabled?.() === true;\n if (runtime.memory === undefined && !learningEnabled) return;\n\n // Nothing here is resolvable for an agent whose framework can't take\n // middleware and whose runtime configures no Memory — bail before paying for\n // `identifyUser`, so an enterprise-learning-only run keeps warning rather\n // than acquiring a new way to fail.\n if (runtime.memory === undefined && typeof agent.use !== \"function\") {\n logger.warn(NO_MIDDLEWARE_WARNING);\n return;\n }\n\n const userResult = await resolveIntelligenceUser({ runtime, request });\n if (userResult instanceof Response) return userResult;\n const access = await resolveWebMemory(runtime, request, userResult, \"agent\");\n if (access instanceof Response) return access;\n\n const memoryGranted =\n runtime.memory !== undefined && grantAllowsMemory(access.grant);\n\n // A policy that grants no scope means this run gets no Memory — it does NOT\n // mean the run is refused. Attach nothing and let the conversation proceed,\n // exactly as a Channel does when its grant asks for nothing\n // (`hasMemoryAccess` in @copilotkit/channels-core). Returning a 403 here\n // instead fails the whole run, so switching Memory off for one tenant would\n // leave that tenant with no assistant, and the only signal is a run error the\n // chat surface has no reason to render.\n //\n // Enterprise learning rides the SAME MCP server, so \"no Memory\" must not cost\n // an operator the learning tools too. When it is on, attach anyway and let\n // Intelligence filter: it registers one Memory tool per granted scope and\n // none at all for an all-none grant, leaving the learning tools untouched.\n if (!memoryGranted && !learningEnabled) return;\n\n // Whatever is left to attach needs middleware. Failing the run is right only\n // when Memory was actually granted and cannot be delivered; a run that merely\n // wanted learning tools warns and proceeds, as it always has.\n if (typeof agent.use !== \"function\") {\n if (memoryGranted) {\n return errorResponse(\n \"Memory is configured, but this agent does not support middleware\",\n 500,\n );\n }\n logger.warn(NO_MIDDLEWARE_WARNING);\n return;\n }\n\n agent.use(\n new MCPMiddleware([\n {\n type: \"http\",\n url: `${runtime.intelligence.ɵgetApiUrl()}/mcp`,\n serverId: \"intelligence\",\n headers: {\n Authorization: `Bearer ${runtime.intelligence.ɵgetApiKey()}`,\n [INTELLIGENCE_USER_ID_HEADER]: userResult.id,\n ...(runtime.memory\n ? {\n [INTELLIGENCE_MEMORY_GRANT_HEADER]: JSON.stringify(\n access.grant,\n ),\n }\n : {}),\n },\n },\n ]),\n );\n}\n\n// Intentional local exception: HTTP request parsing runs before AG-UI's event\n// compatibility boundary. Mirror its historically accepted optional-null rules\n// and its legacy binary-part upgrade here, without depending on a new public\n// AG-UI helper (AG-UI does not export one). Keep these aligned\n// with client/src/middleware/compatibility-boundary.ts and AG-UI's migration guide.\n// Required nulls and nulls within application data must remain untouched.\nfunction warnCompatibility(what: string, replacement: string) {\n if (\n typeof process !== \"undefined\" &&\n typeof process.env !== \"undefined\" &&\n process.env.SUPPRESS_TRANSFORMATION_WARNINGS\n )\n return;\n console.warn(\n `[ag-ui][compat] Converting deprecated ${what} to ${replacement}. The old shape leaves the protocol after its shim window — see the repo-root DEPRECATIONS.md. Set SUPPRESS_TRANSFORMATION_WARNINGS=true to silence.`,\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction omitLegacyNull(\n value: unknown,\n field: string,\n context: string,\n): unknown {\n if (!isRecord(value) || value[field] !== null) return value;\n warnCompatibility(`${context}.${field}: null`, \"an absent field\");\n const { [field]: _null, ...rest } = value;\n return rest;\n}\n\nfunction mapProtocolArray(\n value: unknown,\n field: string,\n normalize: (entry: unknown) => unknown,\n): unknown {\n if (!isRecord(value) || !Array.isArray(value[field])) return value;\n const original = value[field];\n const entries = original.map(normalize);\n return entries.some((entry, index) => entry !== original[index])\n ? { ...value, [field]: entries }\n : value;\n}\n\nfunction mediaTypeFor(\n mimeType: string,\n): \"image\" | \"audio\" | \"video\" | \"document\" {\n if (mimeType.startsWith(\"image/\")) return \"image\";\n if (mimeType.startsWith(\"audio/\")) return \"audio\";\n if (mimeType.startsWith(\"video/\")) return \"video\";\n return \"document\";\n}\n\nfunction sameSource(part: unknown, converted: Record<string, unknown>) {\n if (!isRecord(part) || part.type !== converted.type) return false;\n const a = part.source;\n const b = converted.source as Record<string, unknown>;\n return (\n isRecord(a) &&\n a.type === b.type &&\n a.value === b.value &&\n a.mimeType === b.mimeType\n );\n}\n\n/**\n * The 0.x `{ type: \"binary\" }` part, which 1.0 retired and main accepted.\n * Mirrors AG-UI's outgoing upgrade (client/src/middleware/legacy-content.ts):\n * data or url becomes the media part its mime type names, and a binary part\n * that only mirrors a modern part already in the message is dropped. A part\n * with only an `id` has no 1.0 form; it is dropped with a warning instead of\n * failing the whole request, which is what BuiltInAgent already did with it.\n */\nfunction upgradeLegacyBinaryParts(content: unknown[]): unknown[] {\n return content.flatMap((part) => {\n if (\n !isRecord(part) ||\n part.type !== \"binary\" ||\n typeof part.mimeType !== \"string\"\n )\n return [part];\n const kind =\n typeof part.data === \"string\"\n ? \"data\"\n : typeof part.url === \"string\"\n ? \"url\"\n : null;\n if (kind === null) {\n console.warn(\n \"[CopilotKit] Dropping a legacy binary content part that has no data or url; AG-UI 1.0 has no equivalent for it.\",\n );\n return [];\n }\n warnCompatibility(\"binary input content\", \"the modern media content part\");\n const converted: Record<string, unknown> = {\n type: mediaTypeFor(part.mimeType),\n source: {\n type: kind,\n value: kind === \"data\" ? part.data : part.url,\n mimeType: part.mimeType,\n },\n ...(typeof part.filename === \"string\"\n ? { metadata: { filename: part.filename } }\n : {}),\n };\n return content.some((other) => sameSource(other, converted))\n ? []\n : [converted];\n });\n}\n\nfunction normalizeLegacyMessageContent(message: unknown): unknown {\n const upgraded =\n isRecord(message) &&\n Array.isArray(message.content) &&\n message.content.some((part) => isRecord(part) && part.type === \"binary\")\n ? {\n ...message,\n content: upgradeLegacyBinaryParts(message.content),\n }\n : message;\n return mapProtocolArray(upgraded, \"content\", (part) => {\n if (!isRecord(part)) return part;\n switch (part.type) {\n case \"image\":\n case \"audio\":\n case \"video\":\n case \"document\":\n return omitLegacyNull(part, \"metadata\", `${part.type} input content`);\n default:\n return part;\n }\n });\n}\n\nfunction normalizeLegacyRunAgentInput(input: unknown): unknown {\n let normalized = omitLegacyNull(input, \"forwardedProps\", \"RunAgentInput\");\n normalized = mapProtocolArray(normalized, \"tools\", (tool) =>\n omitLegacyNull(tool, \"parameters\", \"Tool\"),\n );\n normalized = mapProtocolArray(normalized, \"resume\", (entry) =>\n omitLegacyNull(entry, \"payload\", \"ResumeEntry\"),\n );\n return mapProtocolArray(\n normalized,\n \"messages\",\n normalizeLegacyMessageContent,\n );\n}\n\nfunction parseRunAgentInput(value: unknown): RunAgentInput {\n // With strictNullChecks disabled, Zod infers some required nested fields\n // (such as image.source) as optional. The schema still validates them.\n return RunAgentInputSchema.parse(\n normalizeLegacyRunAgentInput(value),\n ) as RunAgentInput;\n}\n\nexport async function parseRunRequest(\n request: Request,\n): Promise<RunAgentInput | Response> {\n try {\n const requestBody = await request.json();\n return parseRunAgentInput(requestBody);\n } catch (error) {\n logger.error(\"Invalid run request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n\nexport async function parseConnectRequest(request: Request): Promise<\n | Response\n | {\n input: RunAgentInput;\n lastSeenEventId: string | null;\n }\n> {\n try {\n const requestBody = await request.json();\n const input = parseRunAgentInput(requestBody);\n let lastSeenEventId: string | null = null;\n\n if (\n \"lastSeenEventId\" in (requestBody as Record<string, unknown>) &&\n (typeof (requestBody as Record<string, unknown>).lastSeenEventId ===\n \"string\" ||\n (requestBody as Record<string, unknown>).lastSeenEventId === null)\n ) {\n lastSeenEventId =\n (requestBody as ConnectRequestBody).lastSeenEventId ?? null;\n }\n\n return { input, lastSeenEventId };\n } catch (error) {\n logger.error(\"Invalid connect request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent-utils.cjs","names":["resolveAgents","isA2UIEnabled","A2UIMiddleware","isIntelligenceRuntime","resolveMcpAppsServers","MCPAppsMiddleware","OpenGenerativeUIMiddleware","GenerativeUIMiddleware","mergeForwardableHeaders","resolveForwardHeadersPolicy","resolveIntelligenceUser","resolveWebMemory","grantAllowsMemory","errorResponse","MCPMiddleware","INTELLIGENCE_USER_ID_HEADER","INTELLIGENCE_MEMORY_GRANT_HEADER","RunAgentInputSchema"],"sources":["../../../../../src/v2/runtime/handlers/shared/agent-utils.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { RunAgentInputSchema } from \"@ag-ui/core/schemas\";\nimport type { CopilotKitUIEnvelope } from \"@copilotkit/shared\";\nimport {\n A2UIMiddleware,\n OpenGenerativeUIMiddleware,\n} from \"@copilotkit/shared/event-transforms\";\nimport { MCPAppsMiddleware } from \"@ag-ui/mcp-apps-middleware\";\nimport { MCPMiddleware } from \"@ag-ui/mcp-middleware\";\nimport { GenerativeUIMiddleware } from \"../../generative-ui\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport {\n isA2UIEnabled,\n isIntelligenceRuntime,\n resolveAgents,\n} from \"../../core/runtime\";\nimport {\n INTELLIGENCE_MEMORY_GRANT_HEADER,\n INTELLIGENCE_USER_ID_HEADER,\n} from \"../../intelligence-platform/client\";\nimport {\n mergeForwardableHeaders,\n resolveForwardHeadersPolicy,\n} from \"../header-utils\";\nimport { resolveMcpAppsServers } from \"./mcp-apps-servers\";\nimport { resolveIntelligenceUser } from \"./resolve-intelligence-user\";\nimport { grantAllowsMemory, resolveWebMemory } from \"./memory-policy\";\nimport { errorResponse } from \"./json-response\";\nimport { logger } from \"@copilotkit/shared\";\n\ntype MiddlewareCapableAgent = AbstractAgent & {\n use?: (middleware: unknown) => void;\n headers?: Record<string, string>;\n};\n\nexport interface RunAgentParameters {\n request: Request;\n runtime: CopilotRuntimeLike;\n agentId: string;\n}\n\nexport interface ConnectRequestBody extends RunAgentInput {\n lastSeenEventId?: string | null;\n}\n\n/**\n * Resolve `agentId` against the runtime's agents and return a per-request\n * clone of the matching agent.\n *\n * Dual return contract — both callers (`handle-run.ts`, `handle-connect.ts`)\n * depend on it:\n * - Returns a cloned `AbstractAgent` when the agent exists.\n * - Returns a 404 `Response` (`{ error: \"Agent not found\", ... }`) when the\n * agent is unknown. Callers MUST `instanceof Response`-check the result and\n * return it directly; this doubles as the connect/run path's agent-existence\n * guard, so skipping the check would let unknown agent ids slip through.\n *\n * The clone is what subsequent per-request mutation (middleware attach,\n * `agent.headers` merge) operates on, leaving the shared agent registration\n * untouched.\n */\nexport async function cloneAgentForRequest(\n runtime: CopilotRuntimeLike,\n agentId: string,\n request?: Request,\n): Promise<AbstractAgent | Response> {\n const agents = await resolveAgents(runtime.agents, request);\n\n if (!agents[agentId]) {\n return new Response(\n JSON.stringify({\n error: \"Agent not found\",\n message: `Agent '${agentId}' does not exist`,\n }),\n {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n return (agents[agentId] as AbstractAgent).clone() as AbstractAgent;\n}\n\nexport function configureAgentForRequest(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n /**\n * True when the React provider was given an A2UI catalog\n * (`<CopilotKit a2ui={{ catalog }}>`), forwarded per-run. A catalog alone is\n * enough to enable A2UI and inject the render tool — the developer no longer\n * has to also set `a2ui.injectA2UITool` on the runtime.\n */\n providerA2UIHasCatalog?: boolean;\n /**\n * The transport of the generative UI envelope that the client sent on this\n * run (`forwardedProps.copilotkit.ui`). Not set when the run has no envelope.\n */\n providerGenerativeUITransport?: CopilotKitUIEnvelope[\"metadata\"][\"extensions\"][\"copilotkit_transport\"];\n /** Retain proxy rejection even when no server is available to this agent. */\n isMcpProxyRequest?: boolean;\n}): void {\n const {\n runtime,\n request,\n agentId,\n providerA2UIHasCatalog,\n isMcpProxyRequest,\n } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n // A2UI is on when the runtime explicitly enables it, OR when the provider\n // forwarded a catalog — but an explicit `enabled: false` always wins (we\n // provide a quick default, never override a deeper opt-out).\n const a2uiEnabledByCatalog =\n !!providerA2UIHasCatalog && runtime.a2ui?.enabled !== false;\n\n if (isA2UIEnabled(runtime.a2ui) || a2uiEnabledByCatalog) {\n // `enabled` is a CopilotKit-level switch, not an A2UIMiddleware option —\n // drop it (alongside the agent filter) before forwarding to the middleware.\n const {\n agents: targetAgents,\n enabled: _enabled,\n injectA2UITool,\n ...a2uiOptions\n } = runtime.a2ui ?? {};\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(\n new A2UIMiddleware({\n ...a2uiOptions,\n // Default render-tool injection on when a catalog is present and the\n // developer hasn't set it explicitly. `??` means an explicit value\n // (including `false`) is always respected.\n injectA2UITool:\n injectA2UITool ?? (providerA2UIHasCatalog ? true : undefined),\n }),\n );\n }\n }\n\n if (isIntelligenceRuntime(runtime) && typeof agent.use === \"function\") {\n // Ordinary runs need no middleware without selected servers. Proxy requests\n // still need the upstream guard so they cannot fall through to the model.\n const mcpServers = resolveMcpAppsServers(\n runtime.mcpApps?.servers ?? [],\n agentId,\n );\n if (mcpServers.length > 0 || isMcpProxyRequest) {\n agent.use(\n new MCPAppsMiddleware({ mcpServers, discoveryFailureMode: \"throw\" }),\n );\n }\n } else if (runtime.mcpApps?.servers?.length) {\n const mcpServers = resolveMcpAppsServers(runtime.mcpApps.servers, agentId);\n\n if (mcpServers.length > 0 && typeof agent.use === \"function\") {\n agent.use(new MCPAppsMiddleware({ mcpServers }));\n }\n }\n\n if (runtime.openGenerativeUI) {\n const config = runtime.openGenerativeUI;\n const targetAgents = typeof config === \"object\" ? config.agents : undefined;\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(new OpenGenerativeUIMiddleware());\n }\n }\n\n // A \"markdown\" envelope means the model writes ```a2ui fences, so the run\n // gets no render tool, even when the runtime turns generative UI on.\n const generativeUI = runtime.generativeUI;\n const transport = params.providerGenerativeUITransport;\n const isGenerativeUIRun =\n transport === \"tool\" || (transport !== \"markdown\" && !!generativeUI);\n if (\n isGenerativeUIRun &&\n generativeUI !== false &&\n typeof agent.use === \"function\"\n ) {\n const targetAgents =\n typeof generativeUI === \"object\" ? generativeUI.agents : undefined;\n if (!targetAgents || targetAgents.includes(agentId)) {\n agent.use(new GenerativeUIMiddleware());\n }\n }\n\n // Forward eligible inbound headers onto the outgoing agent call under the\n // runtime's resolved forwarding policy (`authorization` / custom `x-*`, with\n // known infra/proxy/platform headers stripped by the default denylist —\n // #5712), but let headers the server explicitly configured on the agent WIN\n // on collision (case-insensitively): a server-set service-to-service token\n // (e.g. an IAM bearer) must never be silently overridden by a\n // browser/edge/platform-injected inbound header. See `mergeForwardableHeaders`\n // for the casing/duplicate-key rationale and `shouldForwardHeader` for breadth.\n agent.headers = mergeForwardableHeaders(\n agent.headers,\n request,\n // `forwardHeadersPolicy` is optional on the published `CopilotRuntimeLike`\n // interface (non-breaking minor release). Concrete runtimes always set it;\n // a policy-less external implementor falls back to the default resolved\n // policy (default-on denylist) so behavior stays identical and never derefs\n // undefined.\n runtime.forwardHeadersPolicy ?? resolveForwardHeadersPolicy(undefined),\n );\n}\n\n/**\n * Shared by the two places a run meets a middleware-less agent: before Memory\n * is resolved (nothing left to resolve) and after (Memory resolved to nothing).\n */\nconst NO_MIDDLEWARE_WARNING =\n \"CopilotKitIntelligence.enableEnterpriseLearning is enabled, but the agent \" +\n \"does not support middleware (no `.use()` method); Intelligence tools were \" +\n \"not attached for this run.\";\n\n/**\n * Attach CopilotKit Intelligence's MCP tools to the agent run when\n * `CopilotKitIntelligence` was constructed with\n * `enableEnterpriseLearning: true`. Uses `@ag-ui/mcp-middleware`, so the\n * tools are available uniformly across agent frameworks (not just\n * `BuiltInAgent`).\n *\n * The middleware sits on a per-request agent clone, so the per-request\n * auth (Bearer apiKey + resolved user-id) is baked into the transport\n * headers at attach time. If user resolution fails, attachment is\n * skipped silently — the intelligence run handler will reject the\n * request with the same error. Note this means `identifyUser` is\n * resolved twice per learning-enabled run (here and in the run handler);\n * the callback is expected to be idempotent and side-effect-free.\n *\n * Intentionally split out from `configureAgentForRequest`: this is only\n * relevant to actual agent runs, not auxiliary flows like thread-name\n * generation (which has no need for MCP tools and shouldn't pay the\n * `listTools` round-trip).\n */\nexport async function attachIntelligenceEnterpriseLearning(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n}): Promise<void | Response> {\n const { runtime, request } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n if (!isIntelligenceRuntime(runtime)) return;\n\n const learningEnabled =\n runtime.intelligence?.ɵisEnterpriseLearningEnabled?.() === true;\n if (runtime.memory === undefined && !learningEnabled) return;\n\n // Nothing here is resolvable for an agent whose framework can't take\n // middleware and whose runtime configures no Memory — bail before paying for\n // `identifyUser`, so an enterprise-learning-only run keeps warning rather\n // than acquiring a new way to fail.\n if (runtime.memory === undefined && typeof agent.use !== \"function\") {\n logger.warn(NO_MIDDLEWARE_WARNING);\n return;\n }\n\n const userResult = await resolveIntelligenceUser({ runtime, request });\n if (userResult instanceof Response) return userResult;\n const access = await resolveWebMemory(runtime, request, userResult, \"agent\");\n if (access instanceof Response) return access;\n\n const memoryGranted =\n runtime.memory !== undefined && grantAllowsMemory(access.grant);\n\n // A policy that grants no scope means this run gets no Memory — it does NOT\n // mean the run is refused. Attach nothing and let the conversation proceed,\n // exactly as a Channel does when its grant asks for nothing\n // (`hasMemoryAccess` in @copilotkit/channels-core). Returning a 403 here\n // instead fails the whole run, so switching Memory off for one tenant would\n // leave that tenant with no assistant, and the only signal is a run error the\n // chat surface has no reason to render.\n //\n // Enterprise learning rides the SAME MCP server, so \"no Memory\" must not cost\n // an operator the learning tools too. When it is on, attach anyway and let\n // Intelligence filter: it registers one Memory tool per granted scope and\n // none at all for an all-none grant, leaving the learning tools untouched.\n if (!memoryGranted && !learningEnabled) return;\n\n // Whatever is left to attach needs middleware. Failing the run is right only\n // when Memory was actually granted and cannot be delivered; a run that merely\n // wanted learning tools warns and proceeds, as it always has.\n if (typeof agent.use !== \"function\") {\n if (memoryGranted) {\n return errorResponse(\n \"Memory is configured, but this agent does not support middleware\",\n 500,\n );\n }\n logger.warn(NO_MIDDLEWARE_WARNING);\n return;\n }\n\n agent.use(\n new MCPMiddleware([\n {\n type: \"http\",\n url: `${runtime.intelligence.ɵgetApiUrl()}/mcp`,\n serverId: \"intelligence\",\n headers: {\n Authorization: `Bearer ${runtime.intelligence.ɵgetApiKey()}`,\n [INTELLIGENCE_USER_ID_HEADER]: userResult.id,\n ...(runtime.memory\n ? {\n [INTELLIGENCE_MEMORY_GRANT_HEADER]: JSON.stringify(\n access.grant,\n ),\n }\n : {}),\n },\n },\n ]),\n );\n}\n\n// Intentional local exception: HTTP request parsing runs before AG-UI's event\n// compatibility boundary. Mirror its historically accepted optional-null rules\n// and its legacy binary-part upgrade here, without depending on a new public\n// AG-UI helper (AG-UI does not export one). Keep these aligned\n// with client/src/middleware/compatibility-boundary.ts and AG-UI's migration guide.\n// Required nulls and nulls within application data must remain untouched.\nfunction warnCompatibility(what: string, replacement: string) {\n if (\n typeof process !== \"undefined\" &&\n typeof process.env !== \"undefined\" &&\n process.env.SUPPRESS_TRANSFORMATION_WARNINGS\n )\n return;\n console.warn(\n `[ag-ui][compat] Converting deprecated ${what} to ${replacement}. The old shape leaves the protocol after its shim window — see the repo-root DEPRECATIONS.md. Set SUPPRESS_TRANSFORMATION_WARNINGS=true to silence.`,\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction omitLegacyNull(\n value: unknown,\n field: string,\n context: string,\n): unknown {\n if (!isRecord(value) || value[field] !== null) return value;\n warnCompatibility(`${context}.${field}: null`, \"an absent field\");\n const { [field]: _null, ...rest } = value;\n return rest;\n}\n\nfunction mapProtocolArray(\n value: unknown,\n field: string,\n normalize: (entry: unknown) => unknown,\n): unknown {\n if (!isRecord(value) || !Array.isArray(value[field])) return value;\n const original = value[field];\n const entries = original.map(normalize);\n return entries.some((entry, index) => entry !== original[index])\n ? { ...value, [field]: entries }\n : value;\n}\n\nfunction mediaTypeFor(\n mimeType: string,\n): \"image\" | \"audio\" | \"video\" | \"document\" {\n if (mimeType.startsWith(\"image/\")) return \"image\";\n if (mimeType.startsWith(\"audio/\")) return \"audio\";\n if (mimeType.startsWith(\"video/\")) return \"video\";\n return \"document\";\n}\n\nfunction sameSource(part: unknown, converted: Record<string, unknown>) {\n if (!isRecord(part) || part.type !== converted.type) return false;\n const a = part.source;\n const b = converted.source as Record<string, unknown>;\n return (\n isRecord(a) &&\n a.type === b.type &&\n a.value === b.value &&\n a.mimeType === b.mimeType\n );\n}\n\n/**\n * The 0.x `{ type: \"binary\" }` part, which 1.0 retired and main accepted.\n * Mirrors AG-UI's outgoing upgrade (client/src/middleware/legacy-content.ts):\n * data or url becomes the media part its mime type names, and a binary part\n * that only mirrors a modern part already in the message is dropped. A part\n * with only an `id` has no 1.0 form; it is dropped with a warning instead of\n * failing the whole request, which is what BuiltInAgent already did with it.\n */\nfunction upgradeLegacyBinaryParts(content: unknown[]): unknown[] {\n return content.flatMap((part) => {\n if (\n !isRecord(part) ||\n part.type !== \"binary\" ||\n typeof part.mimeType !== \"string\"\n )\n return [part];\n const kind =\n typeof part.data === \"string\"\n ? \"data\"\n : typeof part.url === \"string\"\n ? \"url\"\n : null;\n if (kind === null) {\n console.warn(\n \"[CopilotKit] Dropping a legacy binary content part that has no data or url; AG-UI 1.0 has no equivalent for it.\",\n );\n return [];\n }\n warnCompatibility(\"binary input content\", \"the modern media content part\");\n const converted: Record<string, unknown> = {\n type: mediaTypeFor(part.mimeType),\n source: {\n type: kind,\n value: kind === \"data\" ? part.data : part.url,\n mimeType: part.mimeType,\n },\n ...(typeof part.filename === \"string\"\n ? { metadata: { filename: part.filename } }\n : {}),\n };\n return content.some((other) => sameSource(other, converted))\n ? []\n : [converted];\n });\n}\n\nfunction normalizeLegacyMessageContent(message: unknown): unknown {\n const upgraded =\n isRecord(message) &&\n Array.isArray(message.content) &&\n message.content.some((part) => isRecord(part) && part.type === \"binary\")\n ? {\n ...message,\n content: upgradeLegacyBinaryParts(message.content),\n }\n : message;\n return mapProtocolArray(upgraded, \"content\", (part) => {\n if (!isRecord(part)) return part;\n switch (part.type) {\n case \"image\":\n case \"audio\":\n case \"video\":\n case \"document\":\n return omitLegacyNull(part, \"metadata\", `${part.type} input content`);\n default:\n return part;\n }\n });\n}\n\nfunction normalizeLegacyRunAgentInput(input: unknown): unknown {\n let normalized = omitLegacyNull(input, \"forwardedProps\", \"RunAgentInput\");\n normalized = mapProtocolArray(normalized, \"tools\", (tool) =>\n omitLegacyNull(tool, \"parameters\", \"Tool\"),\n );\n normalized = mapProtocolArray(normalized, \"resume\", (entry) =>\n omitLegacyNull(entry, \"payload\", \"ResumeEntry\"),\n );\n return mapProtocolArray(\n normalized,\n \"messages\",\n normalizeLegacyMessageContent,\n );\n}\n\nfunction parseRunAgentInput(value: unknown): RunAgentInput {\n // With strictNullChecks disabled, Zod infers some required nested fields\n // (such as image.source) as optional. The schema still validates them.\n return RunAgentInputSchema.parse(\n normalizeLegacyRunAgentInput(value),\n ) as RunAgentInput;\n}\n\nexport async function parseRunRequest(\n request: Request,\n): Promise<RunAgentInput | Response> {\n try {\n const requestBody = await request.json();\n return parseRunAgentInput(requestBody);\n } catch (error) {\n logger.error(\"Invalid run request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n\nexport async function parseConnectRequest(request: Request): Promise<\n | Response\n | {\n input: RunAgentInput;\n lastSeenEventId: string | null;\n }\n> {\n try {\n const requestBody = await request.json();\n const input = parseRunAgentInput(requestBody);\n let lastSeenEventId: string | null = null;\n\n if (\n \"lastSeenEventId\" in (requestBody as Record<string, unknown>) &&\n (typeof (requestBody as Record<string, unknown>).lastSeenEventId ===\n \"string\" ||\n (requestBody as Record<string, unknown>).lastSeenEventId === null)\n ) {\n lastSeenEventId =\n (requestBody as ConnectRequestBody).lastSeenEventId ?? null;\n }\n\n return { input, lastSeenEventId };\n } catch (error) {\n logger.error(\"Invalid connect request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n"],"mappings":"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"}
@@ -2,6 +2,7 @@ import "reflect-metadata";
2
2
  import { mergeForwardableHeaders, resolveForwardHeadersPolicy } from "../header-utils.mjs";
3
3
  import { isA2UIEnabled, isIntelligenceRuntime, resolveAgents } from "../../core/runtime.mjs";
4
4
  import { INTELLIGENCE_MEMORY_GRANT_HEADER, INTELLIGENCE_USER_ID_HEADER } from "../../intelligence-platform/client.mjs";
5
+ import { GenerativeUIMiddleware } from "../../generative-ui/generative-ui-middleware.mjs";
5
6
  import { resolveMcpAppsServers } from "./mcp-apps-servers.mjs";
6
7
  import { errorResponse } from "./json-response.mjs";
7
8
  import { resolveIntelligenceUser } from "./resolve-intelligence-user.mjs";
@@ -66,6 +67,12 @@ function configureAgentForRequest(params) {
66
67
  const targetAgents = typeof config === "object" ? config.agents : void 0;
67
68
  if ((!targetAgents || targetAgents.includes(agentId)) && typeof agent.use === "function") agent.use(new OpenGenerativeUIMiddleware());
68
69
  }
70
+ const generativeUI = runtime.generativeUI;
71
+ const transport = params.providerGenerativeUITransport;
72
+ if ((transport === "tool" || transport !== "markdown" && !!generativeUI) && generativeUI !== false && typeof agent.use === "function") {
73
+ const targetAgents = typeof generativeUI === "object" ? generativeUI.agents : void 0;
74
+ if (!targetAgents || targetAgents.includes(agentId)) agent.use(new GenerativeUIMiddleware());
75
+ }
69
76
  agent.headers = mergeForwardableHeaders(agent.headers, request, runtime.forwardHeadersPolicy ?? resolveForwardHeadersPolicy(void 0));
70
77
  }
71
78
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"agent-utils.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/shared/agent-utils.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { RunAgentInputSchema } from \"@ag-ui/core/schemas\";\nimport {\n A2UIMiddleware,\n OpenGenerativeUIMiddleware,\n} from \"@copilotkit/shared/event-transforms\";\nimport { MCPAppsMiddleware } from \"@ag-ui/mcp-apps-middleware\";\nimport { MCPMiddleware } from \"@ag-ui/mcp-middleware\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport {\n isA2UIEnabled,\n isIntelligenceRuntime,\n resolveAgents,\n} from \"../../core/runtime\";\nimport {\n INTELLIGENCE_MEMORY_GRANT_HEADER,\n INTELLIGENCE_USER_ID_HEADER,\n} from \"../../intelligence-platform/client\";\nimport {\n mergeForwardableHeaders,\n resolveForwardHeadersPolicy,\n} from \"../header-utils\";\nimport { resolveMcpAppsServers } from \"./mcp-apps-servers\";\nimport { resolveIntelligenceUser } from \"./resolve-intelligence-user\";\nimport { grantAllowsMemory, resolveWebMemory } from \"./memory-policy\";\nimport { errorResponse } from \"./json-response\";\nimport { logger } from \"@copilotkit/shared\";\n\ntype MiddlewareCapableAgent = AbstractAgent & {\n use?: (middleware: unknown) => void;\n headers?: Record<string, string>;\n};\n\nexport interface RunAgentParameters {\n request: Request;\n runtime: CopilotRuntimeLike;\n agentId: string;\n}\n\nexport interface ConnectRequestBody extends RunAgentInput {\n lastSeenEventId?: string | null;\n}\n\n/**\n * Resolve `agentId` against the runtime's agents and return a per-request\n * clone of the matching agent.\n *\n * Dual return contract — both callers (`handle-run.ts`, `handle-connect.ts`)\n * depend on it:\n * - Returns a cloned `AbstractAgent` when the agent exists.\n * - Returns a 404 `Response` (`{ error: \"Agent not found\", ... }`) when the\n * agent is unknown. Callers MUST `instanceof Response`-check the result and\n * return it directly; this doubles as the connect/run path's agent-existence\n * guard, so skipping the check would let unknown agent ids slip through.\n *\n * The clone is what subsequent per-request mutation (middleware attach,\n * `agent.headers` merge) operates on, leaving the shared agent registration\n * untouched.\n */\nexport async function cloneAgentForRequest(\n runtime: CopilotRuntimeLike,\n agentId: string,\n request?: Request,\n): Promise<AbstractAgent | Response> {\n const agents = await resolveAgents(runtime.agents, request);\n\n if (!agents[agentId]) {\n return new Response(\n JSON.stringify({\n error: \"Agent not found\",\n message: `Agent '${agentId}' does not exist`,\n }),\n {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n return (agents[agentId] as AbstractAgent).clone() as AbstractAgent;\n}\n\nexport function configureAgentForRequest(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n /**\n * True when the React provider was given an A2UI catalog\n * (`<CopilotKit a2ui={{ catalog }}>`), forwarded per-run. A catalog alone is\n * enough to enable A2UI and inject the render tool — the developer no longer\n * has to also set `a2ui.injectA2UITool` on the runtime.\n */\n providerA2UIHasCatalog?: boolean;\n /** Retain proxy rejection even when no server is available to this agent. */\n isMcpProxyRequest?: boolean;\n}): void {\n const {\n runtime,\n request,\n agentId,\n providerA2UIHasCatalog,\n isMcpProxyRequest,\n } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n // A2UI is on when the runtime explicitly enables it, OR when the provider\n // forwarded a catalog — but an explicit `enabled: false` always wins (we\n // provide a quick default, never override a deeper opt-out).\n const a2uiEnabledByCatalog =\n !!providerA2UIHasCatalog && runtime.a2ui?.enabled !== false;\n\n if (isA2UIEnabled(runtime.a2ui) || a2uiEnabledByCatalog) {\n // `enabled` is a CopilotKit-level switch, not an A2UIMiddleware option —\n // drop it (alongside the agent filter) before forwarding to the middleware.\n const {\n agents: targetAgents,\n enabled: _enabled,\n injectA2UITool,\n ...a2uiOptions\n } = runtime.a2ui ?? {};\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(\n new A2UIMiddleware({\n ...a2uiOptions,\n // Default render-tool injection on when a catalog is present and the\n // developer hasn't set it explicitly. `??` means an explicit value\n // (including `false`) is always respected.\n injectA2UITool:\n injectA2UITool ?? (providerA2UIHasCatalog ? true : undefined),\n }),\n );\n }\n }\n\n if (isIntelligenceRuntime(runtime) && typeof agent.use === \"function\") {\n // Ordinary runs need no middleware without selected servers. Proxy requests\n // still need the upstream guard so they cannot fall through to the model.\n const mcpServers = resolveMcpAppsServers(\n runtime.mcpApps?.servers ?? [],\n agentId,\n );\n if (mcpServers.length > 0 || isMcpProxyRequest) {\n agent.use(\n new MCPAppsMiddleware({ mcpServers, discoveryFailureMode: \"throw\" }),\n );\n }\n } else if (runtime.mcpApps?.servers?.length) {\n const mcpServers = resolveMcpAppsServers(runtime.mcpApps.servers, agentId);\n\n if (mcpServers.length > 0 && typeof agent.use === \"function\") {\n agent.use(new MCPAppsMiddleware({ mcpServers }));\n }\n }\n\n if (runtime.openGenerativeUI) {\n const config = runtime.openGenerativeUI;\n const targetAgents = typeof config === \"object\" ? config.agents : undefined;\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(new OpenGenerativeUIMiddleware());\n }\n }\n\n // Forward eligible inbound headers onto the outgoing agent call under the\n // runtime's resolved forwarding policy (`authorization` / custom `x-*`, with\n // known infra/proxy/platform headers stripped by the default denylist —\n // #5712), but let headers the server explicitly configured on the agent WIN\n // on collision (case-insensitively): a server-set service-to-service token\n // (e.g. an IAM bearer) must never be silently overridden by a\n // browser/edge/platform-injected inbound header. See `mergeForwardableHeaders`\n // for the casing/duplicate-key rationale and `shouldForwardHeader` for breadth.\n agent.headers = mergeForwardableHeaders(\n agent.headers,\n request,\n // `forwardHeadersPolicy` is optional on the published `CopilotRuntimeLike`\n // interface (non-breaking minor release). Concrete runtimes always set it;\n // a policy-less external implementor falls back to the default resolved\n // policy (default-on denylist) so behavior stays identical and never derefs\n // undefined.\n runtime.forwardHeadersPolicy ?? resolveForwardHeadersPolicy(undefined),\n );\n}\n\n/**\n * Shared by the two places a run meets a middleware-less agent: before Memory\n * is resolved (nothing left to resolve) and after (Memory resolved to nothing).\n */\nconst NO_MIDDLEWARE_WARNING =\n \"CopilotKitIntelligence.enableEnterpriseLearning is enabled, but the agent \" +\n \"does not support middleware (no `.use()` method); Intelligence tools were \" +\n \"not attached for this run.\";\n\n/**\n * Attach CopilotKit Intelligence's MCP tools to the agent run when\n * `CopilotKitIntelligence` was constructed with\n * `enableEnterpriseLearning: true`. Uses `@ag-ui/mcp-middleware`, so the\n * tools are available uniformly across agent frameworks (not just\n * `BuiltInAgent`).\n *\n * The middleware sits on a per-request agent clone, so the per-request\n * auth (Bearer apiKey + resolved user-id) is baked into the transport\n * headers at attach time. If user resolution fails, attachment is\n * skipped silently — the intelligence run handler will reject the\n * request with the same error. Note this means `identifyUser` is\n * resolved twice per learning-enabled run (here and in the run handler);\n * the callback is expected to be idempotent and side-effect-free.\n *\n * Intentionally split out from `configureAgentForRequest`: this is only\n * relevant to actual agent runs, not auxiliary flows like thread-name\n * generation (which has no need for MCP tools and shouldn't pay the\n * `listTools` round-trip).\n */\nexport async function attachIntelligenceEnterpriseLearning(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n}): Promise<void | Response> {\n const { runtime, request } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n if (!isIntelligenceRuntime(runtime)) return;\n\n const learningEnabled =\n runtime.intelligence?.ɵisEnterpriseLearningEnabled?.() === true;\n if (runtime.memory === undefined && !learningEnabled) return;\n\n // Nothing here is resolvable for an agent whose framework can't take\n // middleware and whose runtime configures no Memory — bail before paying for\n // `identifyUser`, so an enterprise-learning-only run keeps warning rather\n // than acquiring a new way to fail.\n if (runtime.memory === undefined && typeof agent.use !== \"function\") {\n logger.warn(NO_MIDDLEWARE_WARNING);\n return;\n }\n\n const userResult = await resolveIntelligenceUser({ runtime, request });\n if (userResult instanceof Response) return userResult;\n const access = await resolveWebMemory(runtime, request, userResult, \"agent\");\n if (access instanceof Response) return access;\n\n const memoryGranted =\n runtime.memory !== undefined && grantAllowsMemory(access.grant);\n\n // A policy that grants no scope means this run gets no Memory — it does NOT\n // mean the run is refused. Attach nothing and let the conversation proceed,\n // exactly as a Channel does when its grant asks for nothing\n // (`hasMemoryAccess` in @copilotkit/channels-core). Returning a 403 here\n // instead fails the whole run, so switching Memory off for one tenant would\n // leave that tenant with no assistant, and the only signal is a run error the\n // chat surface has no reason to render.\n //\n // Enterprise learning rides the SAME MCP server, so \"no Memory\" must not cost\n // an operator the learning tools too. When it is on, attach anyway and let\n // Intelligence filter: it registers one Memory tool per granted scope and\n // none at all for an all-none grant, leaving the learning tools untouched.\n if (!memoryGranted && !learningEnabled) return;\n\n // Whatever is left to attach needs middleware. Failing the run is right only\n // when Memory was actually granted and cannot be delivered; a run that merely\n // wanted learning tools warns and proceeds, as it always has.\n if (typeof agent.use !== \"function\") {\n if (memoryGranted) {\n return errorResponse(\n \"Memory is configured, but this agent does not support middleware\",\n 500,\n );\n }\n logger.warn(NO_MIDDLEWARE_WARNING);\n return;\n }\n\n agent.use(\n new MCPMiddleware([\n {\n type: \"http\",\n url: `${runtime.intelligence.ɵgetApiUrl()}/mcp`,\n serverId: \"intelligence\",\n headers: {\n Authorization: `Bearer ${runtime.intelligence.ɵgetApiKey()}`,\n [INTELLIGENCE_USER_ID_HEADER]: userResult.id,\n ...(runtime.memory\n ? {\n [INTELLIGENCE_MEMORY_GRANT_HEADER]: JSON.stringify(\n access.grant,\n ),\n }\n : {}),\n },\n },\n ]),\n );\n}\n\n// Intentional local exception: HTTP request parsing runs before AG-UI's event\n// compatibility boundary. Mirror its historically accepted optional-null rules\n// and its legacy binary-part upgrade here, without depending on a new public\n// AG-UI helper (AG-UI does not export one). Keep these aligned\n// with client/src/middleware/compatibility-boundary.ts and AG-UI's migration guide.\n// Required nulls and nulls within application data must remain untouched.\nfunction warnCompatibility(what: string, replacement: string) {\n if (\n typeof process !== \"undefined\" &&\n typeof process.env !== \"undefined\" &&\n process.env.SUPPRESS_TRANSFORMATION_WARNINGS\n )\n return;\n console.warn(\n `[ag-ui][compat] Converting deprecated ${what} to ${replacement}. The old shape leaves the protocol after its shim window — see the repo-root DEPRECATIONS.md. Set SUPPRESS_TRANSFORMATION_WARNINGS=true to silence.`,\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction omitLegacyNull(\n value: unknown,\n field: string,\n context: string,\n): unknown {\n if (!isRecord(value) || value[field] !== null) return value;\n warnCompatibility(`${context}.${field}: null`, \"an absent field\");\n const { [field]: _null, ...rest } = value;\n return rest;\n}\n\nfunction mapProtocolArray(\n value: unknown,\n field: string,\n normalize: (entry: unknown) => unknown,\n): unknown {\n if (!isRecord(value) || !Array.isArray(value[field])) return value;\n const original = value[field];\n const entries = original.map(normalize);\n return entries.some((entry, index) => entry !== original[index])\n ? { ...value, [field]: entries }\n : value;\n}\n\nfunction mediaTypeFor(\n mimeType: string,\n): \"image\" | \"audio\" | \"video\" | \"document\" {\n if (mimeType.startsWith(\"image/\")) return \"image\";\n if (mimeType.startsWith(\"audio/\")) return \"audio\";\n if (mimeType.startsWith(\"video/\")) return \"video\";\n return \"document\";\n}\n\nfunction sameSource(part: unknown, converted: Record<string, unknown>) {\n if (!isRecord(part) || part.type !== converted.type) return false;\n const a = part.source;\n const b = converted.source as Record<string, unknown>;\n return (\n isRecord(a) &&\n a.type === b.type &&\n a.value === b.value &&\n a.mimeType === b.mimeType\n );\n}\n\n/**\n * The 0.x `{ type: \"binary\" }` part, which 1.0 retired and main accepted.\n * Mirrors AG-UI's outgoing upgrade (client/src/middleware/legacy-content.ts):\n * data or url becomes the media part its mime type names, and a binary part\n * that only mirrors a modern part already in the message is dropped. A part\n * with only an `id` has no 1.0 form; it is dropped with a warning instead of\n * failing the whole request, which is what BuiltInAgent already did with it.\n */\nfunction upgradeLegacyBinaryParts(content: unknown[]): unknown[] {\n return content.flatMap((part) => {\n if (\n !isRecord(part) ||\n part.type !== \"binary\" ||\n typeof part.mimeType !== \"string\"\n )\n return [part];\n const kind =\n typeof part.data === \"string\"\n ? \"data\"\n : typeof part.url === \"string\"\n ? \"url\"\n : null;\n if (kind === null) {\n console.warn(\n \"[CopilotKit] Dropping a legacy binary content part that has no data or url; AG-UI 1.0 has no equivalent for it.\",\n );\n return [];\n }\n warnCompatibility(\"binary input content\", \"the modern media content part\");\n const converted: Record<string, unknown> = {\n type: mediaTypeFor(part.mimeType),\n source: {\n type: kind,\n value: kind === \"data\" ? part.data : part.url,\n mimeType: part.mimeType,\n },\n ...(typeof part.filename === \"string\"\n ? { metadata: { filename: part.filename } }\n : {}),\n };\n return content.some((other) => sameSource(other, converted))\n ? []\n : [converted];\n });\n}\n\nfunction normalizeLegacyMessageContent(message: unknown): unknown {\n const upgraded =\n isRecord(message) &&\n Array.isArray(message.content) &&\n message.content.some((part) => isRecord(part) && part.type === \"binary\")\n ? {\n ...message,\n content: upgradeLegacyBinaryParts(message.content),\n }\n : message;\n return mapProtocolArray(upgraded, \"content\", (part) => {\n if (!isRecord(part)) return part;\n switch (part.type) {\n case \"image\":\n case \"audio\":\n case \"video\":\n case \"document\":\n return omitLegacyNull(part, \"metadata\", `${part.type} input content`);\n default:\n return part;\n }\n });\n}\n\nfunction normalizeLegacyRunAgentInput(input: unknown): unknown {\n let normalized = omitLegacyNull(input, \"forwardedProps\", \"RunAgentInput\");\n normalized = mapProtocolArray(normalized, \"tools\", (tool) =>\n omitLegacyNull(tool, \"parameters\", \"Tool\"),\n );\n normalized = mapProtocolArray(normalized, \"resume\", (entry) =>\n omitLegacyNull(entry, \"payload\", \"ResumeEntry\"),\n );\n return mapProtocolArray(\n normalized,\n \"messages\",\n normalizeLegacyMessageContent,\n );\n}\n\nfunction parseRunAgentInput(value: unknown): RunAgentInput {\n // With strictNullChecks disabled, Zod infers some required nested fields\n // (such as image.source) as optional. The schema still validates them.\n return RunAgentInputSchema.parse(\n normalizeLegacyRunAgentInput(value),\n ) as RunAgentInput;\n}\n\nexport async function parseRunRequest(\n request: Request,\n): Promise<RunAgentInput | Response> {\n try {\n const requestBody = await request.json();\n return parseRunAgentInput(requestBody);\n } catch (error) {\n logger.error(\"Invalid run request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n\nexport async function parseConnectRequest(request: Request): Promise<\n | Response\n | {\n input: RunAgentInput;\n lastSeenEventId: string | null;\n }\n> {\n try {\n const requestBody = await request.json();\n const input = parseRunAgentInput(requestBody);\n let lastSeenEventId: string | null = null;\n\n if (\n \"lastSeenEventId\" in (requestBody as Record<string, unknown>) &&\n (typeof (requestBody as Record<string, unknown>).lastSeenEventId ===\n \"string\" ||\n (requestBody as Record<string, unknown>).lastSeenEventId === null)\n ) {\n lastSeenEventId =\n (requestBody as ConnectRequestBody).lastSeenEventId ?? null;\n }\n\n return { input, lastSeenEventId };\n } catch (error) {\n logger.error(\"Invalid connect request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent-utils.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/shared/agent-utils.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { RunAgentInputSchema } from \"@ag-ui/core/schemas\";\nimport type { CopilotKitUIEnvelope } from \"@copilotkit/shared\";\nimport {\n A2UIMiddleware,\n OpenGenerativeUIMiddleware,\n} from \"@copilotkit/shared/event-transforms\";\nimport { MCPAppsMiddleware } from \"@ag-ui/mcp-apps-middleware\";\nimport { MCPMiddleware } from \"@ag-ui/mcp-middleware\";\nimport { GenerativeUIMiddleware } from \"../../generative-ui\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport {\n isA2UIEnabled,\n isIntelligenceRuntime,\n resolveAgents,\n} from \"../../core/runtime\";\nimport {\n INTELLIGENCE_MEMORY_GRANT_HEADER,\n INTELLIGENCE_USER_ID_HEADER,\n} from \"../../intelligence-platform/client\";\nimport {\n mergeForwardableHeaders,\n resolveForwardHeadersPolicy,\n} from \"../header-utils\";\nimport { resolveMcpAppsServers } from \"./mcp-apps-servers\";\nimport { resolveIntelligenceUser } from \"./resolve-intelligence-user\";\nimport { grantAllowsMemory, resolveWebMemory } from \"./memory-policy\";\nimport { errorResponse } from \"./json-response\";\nimport { logger } from \"@copilotkit/shared\";\n\ntype MiddlewareCapableAgent = AbstractAgent & {\n use?: (middleware: unknown) => void;\n headers?: Record<string, string>;\n};\n\nexport interface RunAgentParameters {\n request: Request;\n runtime: CopilotRuntimeLike;\n agentId: string;\n}\n\nexport interface ConnectRequestBody extends RunAgentInput {\n lastSeenEventId?: string | null;\n}\n\n/**\n * Resolve `agentId` against the runtime's agents and return a per-request\n * clone of the matching agent.\n *\n * Dual return contract — both callers (`handle-run.ts`, `handle-connect.ts`)\n * depend on it:\n * - Returns a cloned `AbstractAgent` when the agent exists.\n * - Returns a 404 `Response` (`{ error: \"Agent not found\", ... }`) when the\n * agent is unknown. Callers MUST `instanceof Response`-check the result and\n * return it directly; this doubles as the connect/run path's agent-existence\n * guard, so skipping the check would let unknown agent ids slip through.\n *\n * The clone is what subsequent per-request mutation (middleware attach,\n * `agent.headers` merge) operates on, leaving the shared agent registration\n * untouched.\n */\nexport async function cloneAgentForRequest(\n runtime: CopilotRuntimeLike,\n agentId: string,\n request?: Request,\n): Promise<AbstractAgent | Response> {\n const agents = await resolveAgents(runtime.agents, request);\n\n if (!agents[agentId]) {\n return new Response(\n JSON.stringify({\n error: \"Agent not found\",\n message: `Agent '${agentId}' does not exist`,\n }),\n {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n return (agents[agentId] as AbstractAgent).clone() as AbstractAgent;\n}\n\nexport function configureAgentForRequest(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n /**\n * True when the React provider was given an A2UI catalog\n * (`<CopilotKit a2ui={{ catalog }}>`), forwarded per-run. A catalog alone is\n * enough to enable A2UI and inject the render tool — the developer no longer\n * has to also set `a2ui.injectA2UITool` on the runtime.\n */\n providerA2UIHasCatalog?: boolean;\n /**\n * The transport of the generative UI envelope that the client sent on this\n * run (`forwardedProps.copilotkit.ui`). Not set when the run has no envelope.\n */\n providerGenerativeUITransport?: CopilotKitUIEnvelope[\"metadata\"][\"extensions\"][\"copilotkit_transport\"];\n /** Retain proxy rejection even when no server is available to this agent. */\n isMcpProxyRequest?: boolean;\n}): void {\n const {\n runtime,\n request,\n agentId,\n providerA2UIHasCatalog,\n isMcpProxyRequest,\n } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n // A2UI is on when the runtime explicitly enables it, OR when the provider\n // forwarded a catalog — but an explicit `enabled: false` always wins (we\n // provide a quick default, never override a deeper opt-out).\n const a2uiEnabledByCatalog =\n !!providerA2UIHasCatalog && runtime.a2ui?.enabled !== false;\n\n if (isA2UIEnabled(runtime.a2ui) || a2uiEnabledByCatalog) {\n // `enabled` is a CopilotKit-level switch, not an A2UIMiddleware option —\n // drop it (alongside the agent filter) before forwarding to the middleware.\n const {\n agents: targetAgents,\n enabled: _enabled,\n injectA2UITool,\n ...a2uiOptions\n } = runtime.a2ui ?? {};\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(\n new A2UIMiddleware({\n ...a2uiOptions,\n // Default render-tool injection on when a catalog is present and the\n // developer hasn't set it explicitly. `??` means an explicit value\n // (including `false`) is always respected.\n injectA2UITool:\n injectA2UITool ?? (providerA2UIHasCatalog ? true : undefined),\n }),\n );\n }\n }\n\n if (isIntelligenceRuntime(runtime) && typeof agent.use === \"function\") {\n // Ordinary runs need no middleware without selected servers. Proxy requests\n // still need the upstream guard so they cannot fall through to the model.\n const mcpServers = resolveMcpAppsServers(\n runtime.mcpApps?.servers ?? [],\n agentId,\n );\n if (mcpServers.length > 0 || isMcpProxyRequest) {\n agent.use(\n new MCPAppsMiddleware({ mcpServers, discoveryFailureMode: \"throw\" }),\n );\n }\n } else if (runtime.mcpApps?.servers?.length) {\n const mcpServers = resolveMcpAppsServers(runtime.mcpApps.servers, agentId);\n\n if (mcpServers.length > 0 && typeof agent.use === \"function\") {\n agent.use(new MCPAppsMiddleware({ mcpServers }));\n }\n }\n\n if (runtime.openGenerativeUI) {\n const config = runtime.openGenerativeUI;\n const targetAgents = typeof config === \"object\" ? config.agents : undefined;\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(new OpenGenerativeUIMiddleware());\n }\n }\n\n // A \"markdown\" envelope means the model writes ```a2ui fences, so the run\n // gets no render tool, even when the runtime turns generative UI on.\n const generativeUI = runtime.generativeUI;\n const transport = params.providerGenerativeUITransport;\n const isGenerativeUIRun =\n transport === \"tool\" || (transport !== \"markdown\" && !!generativeUI);\n if (\n isGenerativeUIRun &&\n generativeUI !== false &&\n typeof agent.use === \"function\"\n ) {\n const targetAgents =\n typeof generativeUI === \"object\" ? generativeUI.agents : undefined;\n if (!targetAgents || targetAgents.includes(agentId)) {\n agent.use(new GenerativeUIMiddleware());\n }\n }\n\n // Forward eligible inbound headers onto the outgoing agent call under the\n // runtime's resolved forwarding policy (`authorization` / custom `x-*`, with\n // known infra/proxy/platform headers stripped by the default denylist —\n // #5712), but let headers the server explicitly configured on the agent WIN\n // on collision (case-insensitively): a server-set service-to-service token\n // (e.g. an IAM bearer) must never be silently overridden by a\n // browser/edge/platform-injected inbound header. See `mergeForwardableHeaders`\n // for the casing/duplicate-key rationale and `shouldForwardHeader` for breadth.\n agent.headers = mergeForwardableHeaders(\n agent.headers,\n request,\n // `forwardHeadersPolicy` is optional on the published `CopilotRuntimeLike`\n // interface (non-breaking minor release). Concrete runtimes always set it;\n // a policy-less external implementor falls back to the default resolved\n // policy (default-on denylist) so behavior stays identical and never derefs\n // undefined.\n runtime.forwardHeadersPolicy ?? resolveForwardHeadersPolicy(undefined),\n );\n}\n\n/**\n * Shared by the two places a run meets a middleware-less agent: before Memory\n * is resolved (nothing left to resolve) and after (Memory resolved to nothing).\n */\nconst NO_MIDDLEWARE_WARNING =\n \"CopilotKitIntelligence.enableEnterpriseLearning is enabled, but the agent \" +\n \"does not support middleware (no `.use()` method); Intelligence tools were \" +\n \"not attached for this run.\";\n\n/**\n * Attach CopilotKit Intelligence's MCP tools to the agent run when\n * `CopilotKitIntelligence` was constructed with\n * `enableEnterpriseLearning: true`. Uses `@ag-ui/mcp-middleware`, so the\n * tools are available uniformly across agent frameworks (not just\n * `BuiltInAgent`).\n *\n * The middleware sits on a per-request agent clone, so the per-request\n * auth (Bearer apiKey + resolved user-id) is baked into the transport\n * headers at attach time. If user resolution fails, attachment is\n * skipped silently — the intelligence run handler will reject the\n * request with the same error. Note this means `identifyUser` is\n * resolved twice per learning-enabled run (here and in the run handler);\n * the callback is expected to be idempotent and side-effect-free.\n *\n * Intentionally split out from `configureAgentForRequest`: this is only\n * relevant to actual agent runs, not auxiliary flows like thread-name\n * generation (which has no need for MCP tools and shouldn't pay the\n * `listTools` round-trip).\n */\nexport async function attachIntelligenceEnterpriseLearning(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n}): Promise<void | Response> {\n const { runtime, request } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n if (!isIntelligenceRuntime(runtime)) return;\n\n const learningEnabled =\n runtime.intelligence?.ɵisEnterpriseLearningEnabled?.() === true;\n if (runtime.memory === undefined && !learningEnabled) return;\n\n // Nothing here is resolvable for an agent whose framework can't take\n // middleware and whose runtime configures no Memory — bail before paying for\n // `identifyUser`, so an enterprise-learning-only run keeps warning rather\n // than acquiring a new way to fail.\n if (runtime.memory === undefined && typeof agent.use !== \"function\") {\n logger.warn(NO_MIDDLEWARE_WARNING);\n return;\n }\n\n const userResult = await resolveIntelligenceUser({ runtime, request });\n if (userResult instanceof Response) return userResult;\n const access = await resolveWebMemory(runtime, request, userResult, \"agent\");\n if (access instanceof Response) return access;\n\n const memoryGranted =\n runtime.memory !== undefined && grantAllowsMemory(access.grant);\n\n // A policy that grants no scope means this run gets no Memory — it does NOT\n // mean the run is refused. Attach nothing and let the conversation proceed,\n // exactly as a Channel does when its grant asks for nothing\n // (`hasMemoryAccess` in @copilotkit/channels-core). Returning a 403 here\n // instead fails the whole run, so switching Memory off for one tenant would\n // leave that tenant with no assistant, and the only signal is a run error the\n // chat surface has no reason to render.\n //\n // Enterprise learning rides the SAME MCP server, so \"no Memory\" must not cost\n // an operator the learning tools too. When it is on, attach anyway and let\n // Intelligence filter: it registers one Memory tool per granted scope and\n // none at all for an all-none grant, leaving the learning tools untouched.\n if (!memoryGranted && !learningEnabled) return;\n\n // Whatever is left to attach needs middleware. Failing the run is right only\n // when Memory was actually granted and cannot be delivered; a run that merely\n // wanted learning tools warns and proceeds, as it always has.\n if (typeof agent.use !== \"function\") {\n if (memoryGranted) {\n return errorResponse(\n \"Memory is configured, but this agent does not support middleware\",\n 500,\n );\n }\n logger.warn(NO_MIDDLEWARE_WARNING);\n return;\n }\n\n agent.use(\n new MCPMiddleware([\n {\n type: \"http\",\n url: `${runtime.intelligence.ɵgetApiUrl()}/mcp`,\n serverId: \"intelligence\",\n headers: {\n Authorization: `Bearer ${runtime.intelligence.ɵgetApiKey()}`,\n [INTELLIGENCE_USER_ID_HEADER]: userResult.id,\n ...(runtime.memory\n ? {\n [INTELLIGENCE_MEMORY_GRANT_HEADER]: JSON.stringify(\n access.grant,\n ),\n }\n : {}),\n },\n },\n ]),\n );\n}\n\n// Intentional local exception: HTTP request parsing runs before AG-UI's event\n// compatibility boundary. Mirror its historically accepted optional-null rules\n// and its legacy binary-part upgrade here, without depending on a new public\n// AG-UI helper (AG-UI does not export one). Keep these aligned\n// with client/src/middleware/compatibility-boundary.ts and AG-UI's migration guide.\n// Required nulls and nulls within application data must remain untouched.\nfunction warnCompatibility(what: string, replacement: string) {\n if (\n typeof process !== \"undefined\" &&\n typeof process.env !== \"undefined\" &&\n process.env.SUPPRESS_TRANSFORMATION_WARNINGS\n )\n return;\n console.warn(\n `[ag-ui][compat] Converting deprecated ${what} to ${replacement}. The old shape leaves the protocol after its shim window — see the repo-root DEPRECATIONS.md. Set SUPPRESS_TRANSFORMATION_WARNINGS=true to silence.`,\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction omitLegacyNull(\n value: unknown,\n field: string,\n context: string,\n): unknown {\n if (!isRecord(value) || value[field] !== null) return value;\n warnCompatibility(`${context}.${field}: null`, \"an absent field\");\n const { [field]: _null, ...rest } = value;\n return rest;\n}\n\nfunction mapProtocolArray(\n value: unknown,\n field: string,\n normalize: (entry: unknown) => unknown,\n): unknown {\n if (!isRecord(value) || !Array.isArray(value[field])) return value;\n const original = value[field];\n const entries = original.map(normalize);\n return entries.some((entry, index) => entry !== original[index])\n ? { ...value, [field]: entries }\n : value;\n}\n\nfunction mediaTypeFor(\n mimeType: string,\n): \"image\" | \"audio\" | \"video\" | \"document\" {\n if (mimeType.startsWith(\"image/\")) return \"image\";\n if (mimeType.startsWith(\"audio/\")) return \"audio\";\n if (mimeType.startsWith(\"video/\")) return \"video\";\n return \"document\";\n}\n\nfunction sameSource(part: unknown, converted: Record<string, unknown>) {\n if (!isRecord(part) || part.type !== converted.type) return false;\n const a = part.source;\n const b = converted.source as Record<string, unknown>;\n return (\n isRecord(a) &&\n a.type === b.type &&\n a.value === b.value &&\n a.mimeType === b.mimeType\n );\n}\n\n/**\n * The 0.x `{ type: \"binary\" }` part, which 1.0 retired and main accepted.\n * Mirrors AG-UI's outgoing upgrade (client/src/middleware/legacy-content.ts):\n * data or url becomes the media part its mime type names, and a binary part\n * that only mirrors a modern part already in the message is dropped. A part\n * with only an `id` has no 1.0 form; it is dropped with a warning instead of\n * failing the whole request, which is what BuiltInAgent already did with it.\n */\nfunction upgradeLegacyBinaryParts(content: unknown[]): unknown[] {\n return content.flatMap((part) => {\n if (\n !isRecord(part) ||\n part.type !== \"binary\" ||\n typeof part.mimeType !== \"string\"\n )\n return [part];\n const kind =\n typeof part.data === \"string\"\n ? \"data\"\n : typeof part.url === \"string\"\n ? \"url\"\n : null;\n if (kind === null) {\n console.warn(\n \"[CopilotKit] Dropping a legacy binary content part that has no data or url; AG-UI 1.0 has no equivalent for it.\",\n );\n return [];\n }\n warnCompatibility(\"binary input content\", \"the modern media content part\");\n const converted: Record<string, unknown> = {\n type: mediaTypeFor(part.mimeType),\n source: {\n type: kind,\n value: kind === \"data\" ? part.data : part.url,\n mimeType: part.mimeType,\n },\n ...(typeof part.filename === \"string\"\n ? { metadata: { filename: part.filename } }\n : {}),\n };\n return content.some((other) => sameSource(other, converted))\n ? []\n : [converted];\n });\n}\n\nfunction normalizeLegacyMessageContent(message: unknown): unknown {\n const upgraded =\n isRecord(message) &&\n Array.isArray(message.content) &&\n message.content.some((part) => isRecord(part) && part.type === \"binary\")\n ? {\n ...message,\n content: upgradeLegacyBinaryParts(message.content),\n }\n : message;\n return mapProtocolArray(upgraded, \"content\", (part) => {\n if (!isRecord(part)) return part;\n switch (part.type) {\n case \"image\":\n case \"audio\":\n case \"video\":\n case \"document\":\n return omitLegacyNull(part, \"metadata\", `${part.type} input content`);\n default:\n return part;\n }\n });\n}\n\nfunction normalizeLegacyRunAgentInput(input: unknown): unknown {\n let normalized = omitLegacyNull(input, \"forwardedProps\", \"RunAgentInput\");\n normalized = mapProtocolArray(normalized, \"tools\", (tool) =>\n omitLegacyNull(tool, \"parameters\", \"Tool\"),\n );\n normalized = mapProtocolArray(normalized, \"resume\", (entry) =>\n omitLegacyNull(entry, \"payload\", \"ResumeEntry\"),\n );\n return mapProtocolArray(\n normalized,\n \"messages\",\n normalizeLegacyMessageContent,\n );\n}\n\nfunction parseRunAgentInput(value: unknown): RunAgentInput {\n // With strictNullChecks disabled, Zod infers some required nested fields\n // (such as image.source) as optional. The schema still validates them.\n return RunAgentInputSchema.parse(\n normalizeLegacyRunAgentInput(value),\n ) as RunAgentInput;\n}\n\nexport async function parseRunRequest(\n request: Request,\n): Promise<RunAgentInput | Response> {\n try {\n const requestBody = await request.json();\n return parseRunAgentInput(requestBody);\n } catch (error) {\n logger.error(\"Invalid run request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n\nexport async function parseConnectRequest(request: Request): Promise<\n | Response\n | {\n input: RunAgentInput;\n lastSeenEventId: string | null;\n }\n> {\n try {\n const requestBody = await request.json();\n const input = parseRunAgentInput(requestBody);\n let lastSeenEventId: string | null = null;\n\n if (\n \"lastSeenEventId\" in (requestBody as Record<string, unknown>) &&\n (typeof (requestBody as Record<string, unknown>).lastSeenEventId ===\n \"string\" ||\n (requestBody as Record<string, unknown>).lastSeenEventId === null)\n ) {\n lastSeenEventId =\n (requestBody as ConnectRequestBody).lastSeenEventId ?? null;\n }\n\n return { input, lastSeenEventId };\n } catch (error) {\n logger.error(\"Invalid connect request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n"],"mappings":"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"}
@@ -3,15 +3,26 @@ const require_runtime = require('../../../../_virtual/_rolldown/runtime.cjs');
3
3
  const require_logger = require('../../../../lib/logger.cjs');
4
4
  const require_sse_keep_alive = require('./sse-keep-alive.cjs');
5
5
  const require_telemetry_client = require('../../telemetry/telemetry-client.cjs');
6
+ let _copilotkit_shared = require("@copilotkit/shared");
7
+ let _ag_ui_client = require("@ag-ui/client");
6
8
  let _ag_ui_encoder = require("@ag-ui/encoder");
7
9
 
8
10
  //#region src/v2/runtime/handlers/shared/sse-response.ts
11
+ /**
12
+ * Whether a runner rejected the run because the thread is busy. Matches the
13
+ * `code` of {@link ThreadAlreadyRunningError}, and the plain message that
14
+ * custom runners copied from the built-in ones still throw.
15
+ */
16
+ function isThreadAlreadyRunning(error) {
17
+ return error instanceof Error && (error.code === _copilotkit_shared.THREAD_ALREADY_RUNNING_ERROR_CODE || error.message === "Thread already running");
18
+ }
9
19
  function createSseEventResponse({ request, observableFactory, debugEventBus, agentId, debug, logger, telemetry: telemetry$1 = require_telemetry_client.default, executionSeed, captureTelemetry = true, runtimeErrorReporter, startTime, keepAliveIntervalSeconds }) {
10
20
  const keepAliveSeconds = require_sse_keep_alive.resolveSseKeepAliveIntervalSeconds(keepAliveIntervalSeconds);
11
21
  const stream = new TransformStream();
12
22
  const writer = stream.writable.getWriter();
13
23
  const encoder = new _ag_ui_encoder.EventEncoder();
14
24
  let streamClosed = false;
25
+ let terminalEventWritten = false;
15
26
  let debugThreadId = "";
16
27
  let debugRunId = "";
17
28
  const debugLogger = debug?.enabled ? logger ?? require_logger.createLogger({
@@ -24,6 +35,30 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
24
35
  streamClosed = true;
25
36
  } catch {}
26
37
  };
38
+ const writeRunError = async (error) => {
39
+ if (terminalEventWritten || streamClosed || request.signal.aborted) return;
40
+ terminalEventWritten = true;
41
+ const event = isThreadAlreadyRunning(error) ? {
42
+ type: _ag_ui_client.EventType.RUN_ERROR,
43
+ message: "Thread already running",
44
+ code: _copilotkit_shared.THREAD_ALREADY_RUNNING_ERROR_CODE
45
+ } : {
46
+ type: _ag_ui_client.EventType.RUN_ERROR,
47
+ message: "Agent run failed"
48
+ };
49
+ if (debugEventBus && debugRunId) try {
50
+ debugEventBus.broadcast(event, {
51
+ agentId: agentId ?? "",
52
+ threadId: debugThreadId,
53
+ runId: debugRunId
54
+ });
55
+ } catch (broadcastError) {
56
+ logError(broadcastError);
57
+ }
58
+ try {
59
+ await writer.write(encoder.encodeBinary(event));
60
+ } catch {}
61
+ };
27
62
  const logError = (error) => {
28
63
  console.error("Error running agent:", error);
29
64
  console.error("Error stack:", error instanceof Error ? error.stack : "No stack trace");
@@ -89,6 +124,8 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
89
124
  ...summarizeEvent(event)
90
125
  }, "Event emitted");
91
126
  }
127
+ if (event.type === _ag_ui_client.EventType.RUN_STARTED) terminalEventWritten = false;
128
+ else if (event.type === _ag_ui_client.EventType.RUN_FINISHED || event.type === _ag_ui_client.EventType.RUN_ERROR) terminalEventWritten = true;
92
129
  await writer.write(encoder.encodeBinary(event));
93
130
  } catch (error) {
94
131
  if (error instanceof Error && error.name === "AbortError") streamClosed = true;
@@ -106,6 +143,7 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
106
143
  });
107
144
  if (debug?.lifecycle) debugLogger.debug({ error: error instanceof Error ? error.message : String(error) }, "SSE stream errored");
108
145
  logError(error);
146
+ await writeRunError(error);
109
147
  await closeStream();
110
148
  },
111
149
  complete: async () => {
@@ -121,6 +159,7 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
121
159
  })().catch(async (error) => {
122
160
  reportAgentError(error, "sse.factory");
123
161
  logError(error);
162
+ await writeRunError(error);
124
163
  await closeStream();
125
164
  });
126
165
  request.signal.addEventListener("abort", () => {
@@ -1 +1 @@
1
- {"version":3,"file":"sse-response.cjs","names":["defaultTelemetry","resolveSseKeepAliveIntervalSeconds","EventEncoder","createLogger","keepAliveSse"],"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 {\n keepAliveSse,\n resolveSseKeepAliveIntervalSeconds,\n} from \"./sse-keep-alive\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { createLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport { telemetry as defaultTelemetry } from \"../../telemetry\";\nimport type { TelemetryCapture } from \"../../telemetry/telemetry-client\";\nimport type { AgentExecutionResponseInfo } from \"../../telemetry/events\";\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 /** Runtime-bound telemetry capture. Falls back for external direct callers. */\n telemetry?: TelemetryCapture;\n /**\n * Execution facts known before the stream opens, merged under anything the\n * upstream reports as it runs. Carries `llmHostClass`, which is knowable\n * from the agent's configuration and never appears on a streamed event.\n */\n executionSeed?: AgentExecutionResponseInfo;\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 * Seconds of silence before a `: keep-alive` SSE comment is written.\n * `0` disables the keep-alive. Resolved by\n * {@link resolveSseKeepAliveIntervalSeconds}, which supplies the default\n * and enforces the timer bound for every caller.\n */\n keepAliveIntervalSeconds?: number;\n}\n\nexport function createSseEventResponse({\n request,\n observableFactory,\n debugEventBus,\n agentId,\n debug,\n logger,\n telemetry = defaultTelemetry,\n executionSeed,\n captureTelemetry = true,\n runtimeErrorReporter,\n startTime,\n keepAliveIntervalSeconds,\n}: CreateSseEventResponseParams): Response {\n const keepAliveSeconds = resolveSseKeepAliveIntervalSeconds(\n keepAliveIntervalSeconds,\n );\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 // Provider/model/LangGraph facts, scraped off raw upstream events as\n // they pass and reported once the stream finishes. This moved here from\n // the v1 TelemetryAgentRunner, which wrapped the runner purely to\n // collect it and emitted its own duplicate copy of every stream event\n // to carry it. v2 callers had no equivalent and reported `{}`.\n // Seeded rather than empty: `llmHostClass` comes from the agent's config,\n // not from the wire, so nothing streamed will ever fill it in. Scraped\n // fields still win, since `collectExecutionInfo` writes over this.\n const executionInfo: AgentExecutionResponseInfo = { ...executionSeed };\n\n subscription = observable.subscribe({\n next: async (event) => {\n collectExecutionInfo(event, executionInfo);\n\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.encodeBinary(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 ...executionInfo,\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(\n \"oss.runtime.agent_execution_stream_ended\",\n executionInfo,\n );\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 const body =\n keepAliveSeconds > 0\n ? keepAliveSse(stream.readable, keepAliveSeconds * 1_000)\n : stream.readable;\n\n return new Response(body, {\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\n/**\n * Accumulate provider, model, and LangGraph facts from one upstream event.\n *\n * Mutates rather than returns so the caller keeps one record across the whole\n * stream: these arrive on different events and the last one wins. Only fields\n * the upstream actually sent are set, so an agent that reports none leaves the\n * record empty and the stream events carry `{}` as before.\n *\n * `rawEvent` is the untransformed upstream payload, present on AG-UI events\n * that wrap one. Its shape is the provider's, not ours, hence the narrowing.\n */\nfunction collectExecutionInfo(\n event: BaseEvent,\n into: AgentExecutionResponseInfo,\n): void {\n const rawEvent = (\n event as {\n rawEvent?: {\n metadata?: Record<string, unknown>;\n data?: Record<string, unknown>;\n };\n }\n ).rawEvent;\n if (!rawEvent) return;\n\n const model = (rawEvent.data as { output?: { model?: string } } | undefined)\n ?.output?.model;\n if (model) {\n into.model = model;\n // Carried forward from the v1 implementation, which set both from the\n // same field. The upstream sends no separate provider name.\n into.provider = model;\n }\n\n const metadata = rawEvent.metadata as\n | { langgraph_host?: string; langgraph_version?: string }\n | undefined;\n if (metadata?.langgraph_host) into.langGraphHost = metadata.langgraph_host;\n if (metadata?.langgraph_version) {\n into.langGraphVersion = metadata.langgraph_version;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sse-response.cjs","names":["THREAD_ALREADY_RUNNING_ERROR_CODE","defaultTelemetry","resolveSseKeepAliveIntervalSeconds","EventEncoder","createLogger","EventType","keepAliveSse"],"sources":["../../../../../src/v2/runtime/handlers/shared/sse-response.ts"],"sourcesContent":["import { EventType } from \"@ag-ui/client\";\nimport type { BaseEvent } from \"@ag-ui/client\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { Observable, Subscription } from \"rxjs\";\nimport {\n keepAliveSse,\n resolveSseKeepAliveIntervalSeconds,\n} from \"./sse-keep-alive\";\nimport { THREAD_ALREADY_RUNNING_ERROR_CODE } from \"@copilotkit/shared\";\nimport type { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { createLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../../v1-deprecated/lib/logger\";\nimport { telemetry as defaultTelemetry } from \"../../telemetry\";\nimport type { TelemetryCapture } from \"../../telemetry/telemetry-client\";\nimport type { AgentExecutionResponseInfo } from \"../../telemetry/events\";\nimport type { DebugEventBus } from \"../../core/debug-event-bus\";\nimport type {\n RuntimeErrorPhase,\n RuntimeErrorReporter,\n} from \"../../core/runtime-error-reporter\";\n\n/**\n * Whether a runner rejected the run because the thread is busy. Matches the\n * `code` of {@link ThreadAlreadyRunningError}, and the plain message that\n * custom runners copied from the built-in ones still throw.\n */\nfunction isThreadAlreadyRunning(error: unknown): boolean {\n return (\n error instanceof Error &&\n ((error as { code?: unknown }).code === THREAD_ALREADY_RUNNING_ERROR_CODE ||\n error.message === \"Thread already running\")\n );\n}\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 /** Runtime-bound telemetry capture. Falls back for external direct callers. */\n telemetry?: TelemetryCapture;\n /**\n * Execution facts known before the stream opens, merged under anything the\n * upstream reports as it runs. Carries `llmHostClass`, which is knowable\n * from the agent's configuration and never appears on a streamed event.\n */\n executionSeed?: AgentExecutionResponseInfo;\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 * Seconds of silence before a `: keep-alive` SSE comment is written.\n * `0` disables the keep-alive. Resolved by\n * {@link resolveSseKeepAliveIntervalSeconds}, which supplies the default\n * and enforces the timer bound for every caller.\n */\n keepAliveIntervalSeconds?: number;\n}\n\nexport function createSseEventResponse({\n request,\n observableFactory,\n debugEventBus,\n agentId,\n debug,\n logger,\n telemetry = defaultTelemetry,\n executionSeed,\n captureTelemetry = true,\n runtimeErrorReporter,\n startTime,\n keepAliveIntervalSeconds,\n}: CreateSseEventResponseParams): Response {\n const keepAliveSeconds = resolveSseKeepAliveIntervalSeconds(\n keepAliveIntervalSeconds,\n );\n const stream = new TransformStream();\n const writer = stream.writable.getWriter();\n const encoder = new EventEncoder();\n let streamClosed = false;\n // Set once the current run's RUN_FINISHED or RUN_ERROR has been queued for\n // the client. AG-UI allows nothing after either until the next RUN_STARTED,\n // so a later failure must not add a RUN_ERROR.\n let terminalEventWritten = 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 // Report a failure to the client as a terminal RUN_ERROR. Without it the\n // client sees an empty stream that ends normally, so its run \"succeeds\"\n // with no reply and no error (e.g. \"Thread already running\" on a busy\n // thread). Only a busy thread is named, with a code clients can branch on;\n // anything else may carry internal detail, so the client gets a generic\n // message and the full error stays in the server log.\n const writeRunError = async (error: unknown) => {\n if (terminalEventWritten || streamClosed || request.signal.aborted) {\n return;\n }\n terminalEventWritten = true;\n const event = isThreadAlreadyRunning(error)\n ? {\n type: EventType.RUN_ERROR,\n message: \"Thread already running\",\n code: THREAD_ALREADY_RUNNING_ERROR_CODE,\n }\n : { type: EventType.RUN_ERROR, message: \"Agent run failed\" };\n // The inspector sees every streamed event, so it needs this one too or\n // the run it saw start never ends there. A run that never started has\n // no ids to file it under, so it is not sent.\n if (debugEventBus && debugRunId) {\n try {\n debugEventBus.broadcast(event as BaseEvent, {\n agentId: agentId ?? \"\",\n threadId: debugThreadId,\n runId: debugRunId,\n });\n } catch (broadcastError) {\n logError(broadcastError);\n }\n }\n try {\n await writer.write(encoder.encodeBinary(event as BaseEvent));\n } catch {\n // The client is already gone; closeStream() handles the rest.\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 // Provider/model/LangGraph facts, scraped off raw upstream events as\n // they pass and reported once the stream finishes. This moved here from\n // the v1 TelemetryAgentRunner, which wrapped the runner purely to\n // collect it and emitted its own duplicate copy of every stream event\n // to carry it. v2 callers had no equivalent and reported `{}`.\n // Seeded rather than empty: `llmHostClass` comes from the agent's config,\n // not from the wire, so nothing streamed will ever fill it in. Scraped\n // fields still win, since `collectExecutionInfo` writes over this.\n const executionInfo: AgentExecutionResponseInfo = { ...executionSeed };\n\n subscription = observable.subscribe({\n next: async (event) => {\n collectExecutionInfo(event, executionInfo);\n\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 // /connect replays finished runs before the live one, so a new\n // RUN_STARTED reopens the stream for a RUN_ERROR.\n if (event.type === EventType.RUN_STARTED) {\n terminalEventWritten = false;\n } else if (\n event.type === EventType.RUN_FINISHED ||\n event.type === EventType.RUN_ERROR\n ) {\n terminalEventWritten = true;\n }\n await writer.write(encoder.encodeBinary(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 ...executionInfo,\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 writeRunError(error);\n await closeStream();\n },\n complete: async () => {\n if (captureTelemetry) {\n telemetry.capture(\n \"oss.runtime.agent_execution_stream_ended\",\n executionInfo,\n );\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 writeRunError(error);\n await closeStream();\n });\n\n request.signal.addEventListener(\"abort\", () => {\n subscription?.unsubscribe();\n });\n\n const body =\n keepAliveSeconds > 0\n ? keepAliveSse(stream.readable, keepAliveSeconds * 1_000)\n : stream.readable;\n\n return new Response(body, {\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\n/**\n * Accumulate provider, model, and LangGraph facts from one upstream event.\n *\n * Mutates rather than returns so the caller keeps one record across the whole\n * stream: these arrive on different events and the last one wins. Only fields\n * the upstream actually sent are set, so an agent that reports none leaves the\n * record empty and the stream events carry `{}` as before.\n *\n * `rawEvent` is the untransformed upstream payload, present on AG-UI events\n * that wrap one. Its shape is the provider's, not ours, hence the narrowing.\n */\nfunction collectExecutionInfo(\n event: BaseEvent,\n into: AgentExecutionResponseInfo,\n): void {\n const rawEvent = (\n event as {\n rawEvent?: {\n metadata?: Record<string, unknown>;\n data?: Record<string, unknown>;\n };\n }\n ).rawEvent;\n if (!rawEvent) return;\n\n const model = (rawEvent.data as { output?: { model?: string } } | undefined)\n ?.output?.model;\n if (model) {\n into.model = model;\n // Carried forward from the v1 implementation, which set both from the\n // same field. The upstream sends no separate provider name.\n into.provider = model;\n }\n\n const metadata = rawEvent.metadata as\n | { langgraph_host?: string; langgraph_version?: string }\n | undefined;\n if (metadata?.langgraph_host) into.langGraphHost = metadata.langgraph_host;\n if (metadata?.langgraph_version) {\n into.langGraphVersion = metadata.langgraph_version;\n }\n}\n"],"mappings":"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"}
@@ -2,15 +2,26 @@ import "reflect-metadata";
2
2
  import { createLogger } from "../../../../lib/logger.mjs";
3
3
  import { keepAliveSse, resolveSseKeepAliveIntervalSeconds } from "./sse-keep-alive.mjs";
4
4
  import telemetry from "../../telemetry/telemetry-client.mjs";
5
+ import { THREAD_ALREADY_RUNNING_ERROR_CODE } from "@copilotkit/shared";
6
+ import { EventType } from "@ag-ui/client";
5
7
  import { EventEncoder } from "@ag-ui/encoder";
6
8
 
7
9
  //#region src/v2/runtime/handlers/shared/sse-response.ts
10
+ /**
11
+ * Whether a runner rejected the run because the thread is busy. Matches the
12
+ * `code` of {@link ThreadAlreadyRunningError}, and the plain message that
13
+ * custom runners copied from the built-in ones still throw.
14
+ */
15
+ function isThreadAlreadyRunning(error) {
16
+ return error instanceof Error && (error.code === THREAD_ALREADY_RUNNING_ERROR_CODE || error.message === "Thread already running");
17
+ }
8
18
  function createSseEventResponse({ request, observableFactory, debugEventBus, agentId, debug, logger, telemetry: telemetry$1 = telemetry, executionSeed, captureTelemetry = true, runtimeErrorReporter, startTime, keepAliveIntervalSeconds }) {
9
19
  const keepAliveSeconds = resolveSseKeepAliveIntervalSeconds(keepAliveIntervalSeconds);
10
20
  const stream = new TransformStream();
11
21
  const writer = stream.writable.getWriter();
12
22
  const encoder = new EventEncoder();
13
23
  let streamClosed = false;
24
+ let terminalEventWritten = false;
14
25
  let debugThreadId = "";
15
26
  let debugRunId = "";
16
27
  const debugLogger = debug?.enabled ? logger ?? createLogger({
@@ -23,6 +34,30 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
23
34
  streamClosed = true;
24
35
  } catch {}
25
36
  };
37
+ const writeRunError = async (error) => {
38
+ if (terminalEventWritten || streamClosed || request.signal.aborted) return;
39
+ terminalEventWritten = true;
40
+ const event = isThreadAlreadyRunning(error) ? {
41
+ type: EventType.RUN_ERROR,
42
+ message: "Thread already running",
43
+ code: THREAD_ALREADY_RUNNING_ERROR_CODE
44
+ } : {
45
+ type: EventType.RUN_ERROR,
46
+ message: "Agent run failed"
47
+ };
48
+ if (debugEventBus && debugRunId) try {
49
+ debugEventBus.broadcast(event, {
50
+ agentId: agentId ?? "",
51
+ threadId: debugThreadId,
52
+ runId: debugRunId
53
+ });
54
+ } catch (broadcastError) {
55
+ logError(broadcastError);
56
+ }
57
+ try {
58
+ await writer.write(encoder.encodeBinary(event));
59
+ } catch {}
60
+ };
26
61
  const logError = (error) => {
27
62
  console.error("Error running agent:", error);
28
63
  console.error("Error stack:", error instanceof Error ? error.stack : "No stack trace");
@@ -88,6 +123,8 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
88
123
  ...summarizeEvent(event)
89
124
  }, "Event emitted");
90
125
  }
126
+ if (event.type === EventType.RUN_STARTED) terminalEventWritten = false;
127
+ else if (event.type === EventType.RUN_FINISHED || event.type === EventType.RUN_ERROR) terminalEventWritten = true;
91
128
  await writer.write(encoder.encodeBinary(event));
92
129
  } catch (error) {
93
130
  if (error instanceof Error && error.name === "AbortError") streamClosed = true;
@@ -105,6 +142,7 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
105
142
  });
106
143
  if (debug?.lifecycle) debugLogger.debug({ error: error instanceof Error ? error.message : String(error) }, "SSE stream errored");
107
144
  logError(error);
145
+ await writeRunError(error);
108
146
  await closeStream();
109
147
  },
110
148
  complete: async () => {
@@ -120,6 +158,7 @@ function createSseEventResponse({ request, observableFactory, debugEventBus, age
120
158
  })().catch(async (error) => {
121
159
  reportAgentError(error, "sse.factory");
122
160
  logError(error);
161
+ await writeRunError(error);
123
162
  await closeStream();
124
163
  });
125
164
  request.signal.addEventListener("abort", () => {