{"version":3,"file":"sse-response.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/shared/sse-response.ts"],"sourcesContent":["import { BaseEvent } from \"@ag-ui/client\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport { Observable, Subscription } from \"rxjs\";\nimport { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport {\n  createLogger,\n  type CopilotRuntimeLogger,\n} from \"../../../../lib/logger\";\nimport { telemetry } from \"../../telemetry\";\n\ninterface CreateSseEventResponseParams {\n  request: Request;\n  observableFactory: () =>\n    | Promise<Observable<BaseEvent>>\n    | Observable<BaseEvent>;\n  debug?: ResolvedDebugConfig;\n  /** Pre-created logger instance to avoid creating a new pino logger per request. */\n  logger?: CopilotRuntimeLogger;\n}\n\nexport function createSseEventResponse({\n  request,\n  observableFactory,\n  debug,\n  logger,\n}: CreateSseEventResponseParams): Response {\n  const stream = new TransformStream();\n  const writer = stream.writable.getWriter();\n  const encoder = new EventEncoder();\n  let streamClosed = false;\n\n  const debugLogger = debug?.enabled\n    ? (logger ??\n      createLogger({ level: \"debug\", component: \"copilotkit-debug\" }))\n    : undefined;\n\n  const closeStream = async () => {\n    if (!streamClosed) {\n      try {\n        await writer.close();\n        streamClosed = true;\n      } catch {\n        // Stream already closed.\n      }\n    }\n  };\n\n  const logError = (error: unknown) => {\n    console.error(\"Error running agent:\", error);\n    console.error(\n      \"Error stack:\",\n      error instanceof Error ? error.stack : \"No stack trace\",\n    );\n    console.error(\"Error details:\", {\n      name: error instanceof Error ? error.name : \"Unknown\",\n      message: error instanceof Error ? error.message : String(error),\n      cause: error instanceof Error ? error.cause : undefined,\n    });\n  };\n\n  let subscription: Subscription | undefined;\n\n  (async () => {\n    const observable = await observableFactory();\n\n    telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n\n    if (debug?.lifecycle) {\n      debugLogger!.debug(\"SSE stream opened\");\n    }\n\n    let eventCount = 0;\n    let loggedEventCount = 0;\n\n    subscription = observable.subscribe({\n      next: async (event) => {\n        if (!request.signal.aborted && !streamClosed) {\n          try {\n            eventCount++;\n            if (debug?.events) {\n              loggedEventCount++;\n              if (debug.verbose) {\n                debugLogger!.debug({ event }, \"Event emitted\");\n              } else {\n                debugLogger!.debug(\n                  { type: event.type, ...summarizeEvent(event) },\n                  \"Event emitted\",\n                );\n              }\n            }\n            await writer.write(encoder.encode(event));\n          } catch (error) {\n            if (error instanceof Error && error.name === \"AbortError\") {\n              streamClosed = true;\n            }\n          }\n        }\n      },\n      error: async (error) => {\n        telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n          error: error instanceof Error ? error.message : String(error),\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        telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n        if (debug?.lifecycle) {\n          debugLogger!.debug(\n            { eventCount, loggedEventCount },\n            \"SSE stream completed\",\n          );\n        }\n        await closeStream();\n      },\n    });\n\n    // If the client disconnected before the subscription was created,\n    // unsubscribe immediately to avoid leaking the observable.\n    if (request.signal.aborted) {\n      subscription.unsubscribe();\n    }\n  })().catch(async (error) => {\n    logError(error);\n    await closeStream();\n  });\n\n  request.signal.addEventListener(\"abort\", () => {\n    subscription?.unsubscribe();\n  });\n\n  return new Response(stream.readable, {\n    status: 200,\n    headers: {\n      \"Content-Type\": \"text/event-stream\",\n      \"Cache-Control\": \"no-cache\",\n      Connection: \"keep-alive\",\n    },\n  });\n}\n\nfunction summarizeEvent(event: BaseEvent): Record<string, unknown> {\n  const e = event as any;\n  const summary: Record<string, unknown> = {};\n\n  if (e.messageId) summary.messageId = e.messageId;\n  if (e.toolCallId) summary.toolCallId = e.toolCallId;\n  if (e.toolCallName) summary.toolCallName = e.toolCallName;\n  if (e.role) summary.role = e.role;\n  if (e.delta != null && typeof e.delta === \"string\")\n    summary.deltaLength = e.delta.length;\n  if (e.snapshot && typeof e.snapshot === \"object\")\n    summary.snapshotKeys = Object.keys(e.snapshot);\n  if (e.delta && Array.isArray(e.delta))\n    summary.operationCount = e.delta.length;\n  if (e.threadId) summary.threadId = e.threadId;\n  if (e.runId) summary.runId = e.runId;\n  if (e.message) summary.message = e.message;\n  if (e.code) summary.code = e.code;\n  if (e.stepName) summary.stepName = e.stepName;\n\n  return summary;\n}\n"],"mappings":"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"}