@morsehq-dev/sdk 0.4.1-rc.1 → 0.5.0-rc.1

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 (149) hide show
  1. package/dist/anthropic/index.cjs +12 -10
  2. package/dist/anthropic/index.js +5 -3
  3. package/dist/anthropic-agent-sdk/index.cjs +52 -34
  4. package/dist/anthropic-agent-sdk/index.cjs.map +1 -1
  5. package/dist/anthropic-agent-sdk/index.js +25 -7
  6. package/dist/anthropic-agent-sdk/index.js.map +1 -1
  7. package/dist/browser/anthropic/index.cjs +12 -10
  8. package/dist/browser/anthropic/index.js +5 -3
  9. package/dist/browser/anthropic-agent-sdk/index.cjs +52 -34
  10. package/dist/browser/anthropic-agent-sdk/index.cjs.map +1 -1
  11. package/dist/browser/anthropic-agent-sdk/index.js +25 -7
  12. package/dist/browser/anthropic-agent-sdk/index.js.map +1 -1
  13. package/dist/browser/chunk-32U547L3.js +118 -0
  14. package/dist/browser/chunk-32U547L3.js.map +1 -0
  15. package/dist/{chunk-SBGY5NS4.js → browser/chunk-454FDWBM.js} +6 -4
  16. package/dist/browser/chunk-454FDWBM.js.map +1 -0
  17. package/dist/browser/{chunk-EFUQVASI.cjs → chunk-5EFKNOO7.cjs} +17 -15
  18. package/dist/browser/chunk-5EFKNOO7.cjs.map +1 -0
  19. package/dist/browser/{chunk-DOLWR7LD.js → chunk-5IWGFPKQ.js} +4 -4
  20. package/dist/browser/{chunk-DOLWR7LD.js.map → chunk-5IWGFPKQ.js.map} +1 -1
  21. package/dist/browser/{chunk-F3B4UR64.js → chunk-6DOP3MTY.js} +386 -53
  22. package/dist/browser/chunk-6DOP3MTY.js.map +1 -0
  23. package/dist/browser/{chunk-GWJYOQNC.js → chunk-A7P3ZBZX.js} +10 -4
  24. package/dist/browser/chunk-A7P3ZBZX.js.map +1 -0
  25. package/dist/browser/{chunk-M2GZJ3RS.cjs → chunk-AV35EOER.cjs} +20 -14
  26. package/dist/browser/chunk-AV35EOER.cjs.map +1 -0
  27. package/dist/browser/{chunk-AYNX24P5.js → chunk-AZ3SVK3K.js} +3 -3
  28. package/dist/browser/{chunk-AYNX24P5.js.map → chunk-AZ3SVK3K.js.map} +1 -1
  29. package/dist/browser/chunk-FNZWJU64.cjs +31 -0
  30. package/dist/browser/chunk-FNZWJU64.cjs.map +1 -0
  31. package/dist/browser/chunk-HZZK2EMO.cjs +126 -0
  32. package/dist/browser/chunk-HZZK2EMO.cjs.map +1 -0
  33. package/dist/browser/{chunk-QWRQJO57.js → chunk-MLDVXMQD.js} +3 -3
  34. package/dist/browser/{chunk-QWRQJO57.js.map → chunk-MLDVXMQD.js.map} +1 -1
  35. package/dist/{chunk-Y7SVGUKY.cjs → browser/chunk-NT37C2TK.cjs} +7 -7
  36. package/dist/browser/{chunk-YNUZGKUA.cjs.map → chunk-NT37C2TK.cjs.map} +1 -1
  37. package/dist/browser/{chunk-3643DC7K.cjs → chunk-RBNCTHK3.cjs} +5 -2
  38. package/dist/browser/{chunk-3643DC7K.cjs.map → chunk-RBNCTHK3.cjs.map} +1 -1
  39. package/dist/browser/chunk-VFNNU3AX.js +28 -0
  40. package/dist/browser/chunk-VFNNU3AX.js.map +1 -0
  41. package/dist/browser/{chunk-HGN7J3EU.cjs → chunk-WY2VLKRR.cjs} +12 -12
  42. package/dist/browser/{chunk-HGN7J3EU.cjs.map → chunk-WY2VLKRR.cjs.map} +1 -1
  43. package/dist/browser/{chunk-DXWHT3HK.cjs → chunk-ZGYZZCUK.cjs} +391 -55
  44. package/dist/browser/chunk-ZGYZZCUK.cjs.map +1 -0
  45. package/dist/browser/index.cjs +112 -82
  46. package/dist/browser/index.cjs.map +1 -1
  47. package/dist/browser/index.js +40 -10
  48. package/dist/browser/index.js.map +1 -1
  49. package/dist/browser/integrations/pino.cjs +4 -4
  50. package/dist/browser/integrations/pino.js +3 -3
  51. package/dist/browser/langchain/index.cjs +19 -19
  52. package/dist/browser/langchain/index.js +3 -3
  53. package/dist/browser/langgraph/index.cjs +34 -26
  54. package/dist/browser/langgraph/index.cjs.map +1 -1
  55. package/dist/browser/langgraph/index.js +16 -8
  56. package/dist/browser/langgraph/index.js.map +1 -1
  57. package/dist/browser/openai/index.cjs +22 -8
  58. package/dist/browser/openai/index.cjs.map +1 -1
  59. package/dist/browser/openai/index.js +17 -3
  60. package/dist/browser/openai/index.js.map +1 -1
  61. package/dist/browser/openai-agents/index.cjs +42 -34
  62. package/dist/browser/openai-agents/index.cjs.map +1 -1
  63. package/dist/browser/openai-agents/index.js +13 -5
  64. package/dist/browser/openai-agents/index.js.map +1 -1
  65. package/dist/browser/vercel-ai/index.cjs +16 -16
  66. package/dist/browser/vercel-ai/index.js +4 -4
  67. package/dist/{chunk-4R4SHGOK.js → chunk-4JPZV2VZ.js} +3 -3
  68. package/dist/{chunk-4R4SHGOK.js.map → chunk-4JPZV2VZ.js.map} +1 -1
  69. package/dist/{chunk-HNCWTENX.cjs → chunk-5B3IUESN.cjs} +415 -70
  70. package/dist/chunk-5B3IUESN.cjs.map +1 -0
  71. package/dist/chunk-5RXSICEJ.js +118 -0
  72. package/dist/chunk-5RXSICEJ.js.map +1 -0
  73. package/dist/chunk-7A2EWXZK.cjs +31 -0
  74. package/dist/chunk-7A2EWXZK.cjs.map +1 -0
  75. package/dist/{chunk-STK4KJQ6.js → chunk-AAR4FYFO.js} +10 -4
  76. package/dist/chunk-AAR4FYFO.js.map +1 -0
  77. package/dist/{chunk-LQI63FHF.cjs → chunk-ADRVMGAW.cjs} +20 -14
  78. package/dist/chunk-ADRVMGAW.cjs.map +1 -0
  79. package/dist/{chunk-V5J6J4ZR.js → chunk-CECVNM7R.js} +4 -4
  80. package/dist/{chunk-V5J6J4ZR.js.map → chunk-CECVNM7R.js.map} +1 -1
  81. package/dist/{chunk-KJEO52QS.cjs → chunk-HICEJ4LV.cjs} +5 -2
  82. package/dist/{chunk-KJEO52QS.cjs.map → chunk-HICEJ4LV.cjs.map} +1 -1
  83. package/dist/{chunk-QXRJUPDP.cjs → chunk-HSY7V4RG.cjs} +12 -12
  84. package/dist/{chunk-QXRJUPDP.cjs.map → chunk-HSY7V4RG.cjs.map} +1 -1
  85. package/dist/chunk-LB6ZLJUR.js +28 -0
  86. package/dist/chunk-LB6ZLJUR.js.map +1 -0
  87. package/dist/{browser/chunk-F7BGQ26H.js → chunk-O3Q5L2HY.js} +6 -4
  88. package/dist/chunk-O3Q5L2HY.js.map +1 -0
  89. package/dist/{chunk-5D6SBSEI.cjs → chunk-RF7NI5VN.cjs} +17 -15
  90. package/dist/chunk-RF7NI5VN.cjs.map +1 -0
  91. package/dist/{chunk-AEFUXEKV.js → chunk-TP3N3S2D.js} +3 -3
  92. package/dist/{chunk-AEFUXEKV.js.map → chunk-TP3N3S2D.js.map} +1 -1
  93. package/dist/{chunk-LTKGLXAE.js → chunk-UEKQIRRA.js} +410 -68
  94. package/dist/chunk-UEKQIRRA.js.map +1 -0
  95. package/dist/{browser/chunk-YNUZGKUA.cjs → chunk-UWQPOWJQ.cjs} +7 -7
  96. package/dist/{chunk-Y7SVGUKY.cjs.map → chunk-UWQPOWJQ.cjs.map} +1 -1
  97. package/dist/chunk-VD3KRXSP.cjs +126 -0
  98. package/dist/chunk-VD3KRXSP.cjs.map +1 -0
  99. package/dist/index.cjs +119 -89
  100. package/dist/index.cjs.map +1 -1
  101. package/dist/index.d.cts +2 -2
  102. package/dist/index.d.ts +2 -2
  103. package/dist/index.js +41 -11
  104. package/dist/index.js.map +1 -1
  105. package/dist/integrations/pino.cjs +4 -4
  106. package/dist/integrations/pino.js +3 -3
  107. package/dist/langchain/index.cjs +19 -19
  108. package/dist/langchain/index.d.cts +1 -1
  109. package/dist/langchain/index.d.ts +1 -1
  110. package/dist/langchain/index.js +3 -3
  111. package/dist/langgraph/index.cjs +34 -26
  112. package/dist/langgraph/index.cjs.map +1 -1
  113. package/dist/langgraph/index.d.cts +1 -1
  114. package/dist/langgraph/index.d.ts +1 -1
  115. package/dist/langgraph/index.js +16 -8
  116. package/dist/langgraph/index.js.map +1 -1
  117. package/dist/openai/index.cjs +22 -8
  118. package/dist/openai/index.cjs.map +1 -1
  119. package/dist/openai/index.js +17 -3
  120. package/dist/openai/index.js.map +1 -1
  121. package/dist/openai-agents/index.cjs +42 -34
  122. package/dist/openai-agents/index.cjs.map +1 -1
  123. package/dist/openai-agents/index.js +13 -5
  124. package/dist/openai-agents/index.js.map +1 -1
  125. package/dist/{tracing-BYAqjT5Q.d.cts → tracing-CNlre8TK.d.cts} +1 -0
  126. package/dist/{tracing-rz9cWQ8d.d.ts → tracing-J8ZgxVzU.d.ts} +1 -0
  127. package/dist/vercel-ai/index.cjs +16 -16
  128. package/dist/vercel-ai/index.js +4 -4
  129. package/package.json +1 -9
  130. package/dist/browser/chunk-3BGG7GH3.cjs +0 -183
  131. package/dist/browser/chunk-3BGG7GH3.cjs.map +0 -1
  132. package/dist/browser/chunk-DXWHT3HK.cjs.map +0 -1
  133. package/dist/browser/chunk-EFUQVASI.cjs.map +0 -1
  134. package/dist/browser/chunk-F3B4UR64.js.map +0 -1
  135. package/dist/browser/chunk-F7BGQ26H.js.map +0 -1
  136. package/dist/browser/chunk-GWJYOQNC.js.map +0 -1
  137. package/dist/browser/chunk-M2GZJ3RS.cjs.map +0 -1
  138. package/dist/browser/chunk-YHV5GL32.js +0 -178
  139. package/dist/browser/chunk-YHV5GL32.js.map +0 -1
  140. package/dist/chunk-5D6SBSEI.cjs.map +0 -1
  141. package/dist/chunk-HNCWTENX.cjs.map +0 -1
  142. package/dist/chunk-LQI63FHF.cjs.map +0 -1
  143. package/dist/chunk-LTKGLXAE.js.map +0 -1
  144. package/dist/chunk-POCQNSVD.js +0 -178
  145. package/dist/chunk-POCQNSVD.js.map +0 -1
  146. package/dist/chunk-SBGY5NS4.js.map +0 -1
  147. package/dist/chunk-STK4KJQ6.js.map +0 -1
  148. package/dist/chunk-T2KW3P23.cjs +0 -183
  149. package/dist/chunk-T2KW3P23.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/openai/index.ts"],"names":["init_tracing","getActiveTraceState","startSpan","calculateCost","runAsync","decomposeOpenAiMessages"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * `@morsehq-dev/sdk/openai` — plain OpenAI SDK instrumentation.\n *\n * Wraps a raw `openai` npm package client (`new OpenAI()` /\n * `new AzureOpenAI()` / any structurally-compatible client) so every\n * `chat.completions.create` call emits an `llm` span carrying model,\n * token counts, `cost_usd`, and pre-segmented `context_segments`.\n *\n * TS port of `apps/sdk/python/src/morse_ai/adapters/openai.py`'s `wrap()`.\n * This module intentionally covers only the `wrap(client)` recommended\n * path (mirrors the Python module's three-layer doc comment, layer 2) —\n * no module-level monkey-patch / `install()` layer, since plain `openai`\n * is not one of the auto-detect targets on either SDK (see\n * `_internal/auto-detect.ts` and Python's `_internal/auto_detect.py`\n * `_adapter_targets()`, which both omit bare `openai`).\n *\n * Distinct from `@morsehq-dev/sdk/openai-agents`, which instruments the\n * `@openai/agents` Agents SDK (a different package with its own Runner /\n * Agent abstractions). This module is for customers calling\n * `openai.chat.completions.create` directly.\n *\n * Context segments are extracted via the shared\n * `_agent-sdk-common/context-decomposer.ts` (`decomposeOpenAiMessages`,\n * MHQ-750) — the request's `messages`/`tools` are already in the native\n * OpenAI wire format the decomposer expects, so no translation layer is\n * needed.\n *\n * Idempotent — wrapping an already-wrapped client instance is a no-op\n * that returns the same wrapper. Recording is best-effort: any failure\n * while building/emitting the span is swallowed so it can never break the\n * customer's OpenAI call. The customer's own API error (thrown by the\n * underlying `create()` call) always propagates unchanged — the span is\n * marked `status: \"failed\"` first, then the error is re-raised.\n *\n * Mirrors `apps/sdk/typescript/src/anthropic/index.ts` in shape.\n */\n\nimport { decomposeOpenAiMessages } from \"../_agent-sdk-common/context-decomposer\";\nimport { calculateCost } from \"../_internal/pricing\";\nimport type { ContextSegment } from \"../_internal/spans\";\nimport { getActiveTraceState, runAsync as _runAsync, startSpan } from \"../_internal/tracing\";\n\n/* ------------------------------------------------------------------------ */\n/* Public types — minimal structural shapes, NOT a hard dep on `openai` */\n/* ------------------------------------------------------------------------ */\n\n/** Subset of the `openai` package's chat message shape we read from. */\nexport interface OpenAiChatMessageParam {\n role: string;\n content?: unknown;\n tool_call_id?: string;\n [key: string]: unknown;\n}\n\n/** Subset of the `openai` package's tool-definition shape we read from. */\nexport interface OpenAiToolParam {\n type?: string;\n function?: { name?: string; [key: string]: unknown };\n [key: string]: unknown;\n}\n\n/**\n * Subset of `openai`'s `ChatCompletionCreateParams` we read from. We\n * deliberately decline to import the real types so the SDK works even when\n * `openai` isn't installed (it's an optional peer dep).\n */\nexport interface OpenAiChatCompletionCreateParams {\n model: string;\n messages: OpenAiChatMessageParam[];\n tools?: OpenAiToolParam[];\n // Allow forward-compat fields without complaint.\n [key: string]: unknown;\n}\n\nexport interface OpenAiCompletionUsageDetails {\n cached_tokens?: number;\n reasoning_tokens?: number;\n [key: string]: unknown;\n}\n\nexport interface OpenAiCompletionUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n prompt_tokens_details?: OpenAiCompletionUsageDetails;\n completion_tokens_details?: OpenAiCompletionUsageDetails;\n [key: string]: unknown;\n}\n\nexport interface OpenAiChatCompletionResponse {\n id?: string;\n model?: string;\n usage?: OpenAiCompletionUsage;\n choices?: Array<{ message?: { content?: unknown; [k: string]: unknown }; [k: string]: unknown }>;\n [key: string]: unknown;\n}\n\n/**\n * Structural shape of the plain OpenAI client we wrap. We only require\n * that `client.chat.completions.create` is a function returning a Promise.\n */\nexport interface OpenAiClientLike {\n chat: {\n completions: {\n create(\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n ): Promise<OpenAiChatCompletionResponse>;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n/* ------------------------------------------------------------------------ */\n/* Module-level sentinel */\n/* ------------------------------------------------------------------------ */\n\nconst WRAPPED_CLIENT = Symbol.for(\"morse.openai.wrapped\");\n\n/* ------------------------------------------------------------------------ */\n/* Public API */\n/* ------------------------------------------------------------------------ */\n\nexport interface WrapOpenAiOptions {\n /**\n * When provided, used as the parent agent span's name when\n * `chat.completions.create` is called outside an active trace. Defaults\n * to `\"openai.chat.completions.create\"`.\n */\n defaultAgentName?: string;\n}\n\n/**\n * Wrap an OpenAI client so every `chat.completions.create` call records an\n * `llm` span with `model`, token counts, `cost_usd`, and `context_segments`.\n * The wrapper preserves the rest of the client's surface (other resources,\n * helpers, etc.) via a Proxy.\n *\n * Idempotent — a previously wrapped client is returned as-is.\n *\n * @example\n * ```ts\n * import { wrapOpenAI } from \"@morsehq-dev/sdk/openai\";\n * import OpenAI from \"openai\";\n *\n * const client = wrapOpenAI(new OpenAI());\n * const response = await client.chat.completions.create({\n * model: \"gpt-4o-mini\",\n * messages: [{ role: \"user\", content: \"hello\" }],\n * });\n * ```\n */\nexport function wrapOpenAI<C extends OpenAiClientLike>(\n client: C,\n options: WrapOpenAiOptions = {},\n): C {\n if (!client || typeof client !== \"object\") return client;\n // Already wrapped? Pass through.\n if ((client as Record<string | symbol, unknown>)[WRAPPED_CLIENT]) return client;\n\n const originalCreate = client.chat?.completions?.create?.bind(client.chat.completions);\n if (typeof originalCreate !== \"function\") return client;\n\n const patchedCreate = buildPatchedCreate(originalCreate, options);\n\n // Construct a new `completions` object that proxies to the original for\n // any non-`create` access, wrapped in a `chat` proxy, wrapped in a\n // top-level client proxy — mirrors `wrapAnthropic`'s nested-Proxy shape.\n const patchedCompletions = new Proxy(client.chat.completions, {\n get(target, prop, receiver) {\n if (prop === \"create\") return patchedCreate;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n const patchedChat = new Proxy(client.chat, {\n get(target, prop, receiver) {\n if (prop === \"completions\") return patchedCompletions;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n const wrapper = new Proxy(client, {\n get(target, prop, receiver) {\n if (prop === WRAPPED_CLIENT) return true;\n if (prop === \"chat\") return patchedChat;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n return wrapper as C;\n}\n\n/** True when a wrapped OpenAI client is passed in. */\nexport function isOpenAiWrapped(client: unknown): boolean {\n if (!client || typeof client !== \"object\") return false;\n return (client as Record<string | symbol, unknown>)[WRAPPED_CLIENT] === true;\n}\n\n/* ------------------------------------------------------------------------ */\n/* Internals — wrapper that records an `llm` span */\n/* ------------------------------------------------------------------------ */\n\nfunction buildPatchedCreate(\n original: (\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n ) => Promise<OpenAiChatCompletionResponse>,\n options: WrapOpenAiOptions,\n): (\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n) => Promise<OpenAiChatCompletionResponse> {\n const agentName = options.defaultAgentName ?? \"openai.chat.completions.create\";\n\n return async function patchedCreate(\n this: unknown,\n params: OpenAiChatCompletionCreateParams,\n callOptions?: unknown,\n ): Promise<OpenAiChatCompletionResponse> {\n const inTrace = getActiveTraceState() !== null;\n\n const work = async (): Promise<OpenAiChatCompletionResponse> => {\n const handle = startSpan({\n name: \"openai.chat.completions.create\",\n type: \"llm\",\n metadata: { model: params?.model },\n });\n let response: OpenAiChatCompletionResponse | undefined;\n try {\n response = await original.call(this, params, callOptions);\n } catch (err) {\n // Customer's own API error — mark the span failed, then re-raise\n // unchanged. Never swallow the caller's real error.\n handle?.end(err);\n throw err;\n }\n\n // Recording is best-effort — never let it throw at the caller.\n try {\n if (handle) {\n const segments = safeExtractSegments(params);\n const usage = response?.usage ?? {};\n const inputTokens = usage.prompt_tokens ?? 0;\n const outputTokens = usage.completion_tokens ?? 0;\n const cachedTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;\n const model = response?.model ?? params?.model;\n\n handle.span.model = model;\n if (inputTokens > 0) handle.span.input_tokens = inputTokens;\n if (outputTokens > 0) handle.span.output_tokens = outputTokens;\n if (cachedTokens > 0) handle.span.cached_input_tokens = cachedTokens;\n const totalTokens =\n usage.total_tokens ??\n (inputTokens > 0 || outputTokens > 0 ? inputTokens + outputTokens : 0);\n if (totalTokens > 0) handle.span.total_tokens = totalTokens;\n\n if (model && (inputTokens > 0 || outputTokens > 0)) {\n const cost = calculateCost({\n inputTokens,\n outputTokens,\n model,\n cachedInputTokens: cachedTokens,\n });\n if (cost !== undefined) handle.span.cost_usd = cost;\n }\n handle.span.context_segments = segments;\n }\n } catch {\n // swallow — telemetry must never break the caller\n }\n handle?.end();\n return response;\n };\n\n if (inTrace) {\n return work();\n }\n\n // No active trace — open a fresh agent span around the call so the\n // llm span has a parent. Mirrors `wrapAnthropic`'s pattern: we can't\n // return `work()`'s Promise from inside `_runAsync`'s callback while\n // preserving typing AND having the fresh trace own the lifecycle, so\n // we wrap explicitly.\n let result: OpenAiChatCompletionResponse | undefined;\n let thrown: unknown;\n await _runAsync({ agentName }, async (runHandle) => {\n runHandle.setOutcome(true);\n try {\n result = await work();\n } catch (err) {\n thrown = err;\n throw err;\n }\n return null;\n });\n if (thrown !== undefined) throw thrown;\n return result as OpenAiChatCompletionResponse;\n };\n}\n\nfunction safeExtractSegments(params: OpenAiChatCompletionCreateParams): ContextSegment[] {\n try {\n if (!params || typeof params !== \"object\") return [];\n return decomposeOpenAiMessages(params.messages, params.tools);\n } catch {\n return [];\n }\n}\n"]}
1
+ {"version":3,"sources":["../../../src/openai/index.ts"],"names":["init_tracing","init_diagnostics","getActiveTraceState","setActiveFramework","startSpan","calculateCost","captureInputMessages","extractOpenAiOutputText","runAsync","decomposeOpenAiMessages","report"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * `@morsehq-dev/sdk/openai` — plain OpenAI SDK instrumentation.\n *\n * Wraps a raw `openai` npm package client (`new OpenAI()` /\n * `new AzureOpenAI()` / any structurally-compatible client) so every\n * `chat.completions.create` call emits an `llm` span carrying model,\n * token counts, `cost_usd`, and pre-segmented `context_segments`.\n *\n * TS port of `apps/sdk/python/src/morse_ai/adapters/openai.py`'s `wrap()`.\n * This module intentionally covers only the `wrap(client)` recommended\n * path (mirrors the Python module's three-layer doc comment, layer 2) —\n * no module-level monkey-patch / `install()` layer, since plain `openai`\n * is not one of the auto-detect targets on either SDK (see\n * `_internal/auto-detect.ts` and Python's `_internal/auto_detect.py`\n * `_adapter_targets()`, which both omit bare `openai`).\n *\n * Distinct from `@morsehq-dev/sdk/openai-agents`, which instruments the\n * `@openai/agents` Agents SDK (a different package with its own Runner /\n * Agent abstractions). This module is for customers calling\n * `openai.chat.completions.create` directly.\n *\n * Context segments are extracted via the shared\n * `_agent-sdk-common/context-decomposer.ts` (`decomposeOpenAiMessages`,\n * MHQ-750) — the request's `messages`/`tools` are already in the native\n * OpenAI wire format the decomposer expects, so no translation layer is\n * needed.\n *\n * Idempotent — wrapping an already-wrapped client instance is a no-op\n * that returns the same wrapper. Recording is best-effort: any failure\n * while building/emitting the span is swallowed so it can never break the\n * customer's OpenAI call. The customer's own API error (thrown by the\n * underlying `create()` call) always propagates unchanged — the span is\n * marked `status: \"failed\"` first, then the error is re-raised.\n *\n * Mirrors `apps/sdk/typescript/src/anthropic/index.ts` in shape.\n */\n\nimport { decomposeOpenAiMessages } from \"../_agent-sdk-common/context-decomposer\";\nimport { setActiveFramework } from \"../_internal/active-framework\";\nimport { captureInputMessages, extractOpenAiOutputText } from \"../_internal/llm-io\";\nimport { calculateCost } from \"../_internal/pricing\";\nimport type { ContextSegment } from \"../_internal/spans\";\nimport { getActiveTraceState, runAsync as _runAsync, startSpan } from \"../_internal/tracing\";\nimport { report } from \"../_internal/diagnostics\";\n\n/* ------------------------------------------------------------------------ */\n/* Public types — minimal structural shapes, NOT a hard dep on `openai` */\n/* ------------------------------------------------------------------------ */\n\n/** Subset of the `openai` package's chat message shape we read from. */\nexport interface OpenAiChatMessageParam {\n role: string;\n content?: unknown;\n tool_call_id?: string;\n [key: string]: unknown;\n}\n\n/** Subset of the `openai` package's tool-definition shape we read from. */\nexport interface OpenAiToolParam {\n type?: string;\n function?: { name?: string; [key: string]: unknown };\n [key: string]: unknown;\n}\n\n/**\n * Subset of `openai`'s `ChatCompletionCreateParams` we read from. We\n * deliberately decline to import the real types so the SDK works even when\n * `openai` isn't installed (it's an optional peer dep).\n */\nexport interface OpenAiChatCompletionCreateParams {\n model: string;\n messages: OpenAiChatMessageParam[];\n tools?: OpenAiToolParam[];\n // Allow forward-compat fields without complaint.\n [key: string]: unknown;\n}\n\nexport interface OpenAiCompletionUsageDetails {\n cached_tokens?: number;\n reasoning_tokens?: number;\n [key: string]: unknown;\n}\n\nexport interface OpenAiCompletionUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n prompt_tokens_details?: OpenAiCompletionUsageDetails;\n completion_tokens_details?: OpenAiCompletionUsageDetails;\n [key: string]: unknown;\n}\n\nexport interface OpenAiChatCompletionResponse {\n id?: string;\n model?: string;\n usage?: OpenAiCompletionUsage;\n choices?: Array<{ message?: { content?: unknown; [k: string]: unknown }; [k: string]: unknown }>;\n [key: string]: unknown;\n}\n\n/**\n * Structural shape of the plain OpenAI client we wrap. We only require\n * that `client.chat.completions.create` is a function returning a Promise.\n */\nexport interface OpenAiClientLike {\n chat: {\n completions: {\n create(\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n ): Promise<OpenAiChatCompletionResponse>;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n/* ------------------------------------------------------------------------ */\n/* Module-level sentinel */\n/* ------------------------------------------------------------------------ */\n\nconst WRAPPED_CLIENT = Symbol.for(\"morse.openai.wrapped\");\n\n/* ------------------------------------------------------------------------ */\n/* Public API */\n/* ------------------------------------------------------------------------ */\n\nexport interface WrapOpenAiOptions {\n /**\n * When provided, used as the parent agent span's name when\n * `chat.completions.create` is called outside an active trace. Defaults\n * to `\"openai.chat.completions.create\"`.\n */\n defaultAgentName?: string;\n}\n\n/**\n * Wrap an OpenAI client so every `chat.completions.create` call records an\n * `llm` span with `model`, token counts, `cost_usd`, and `context_segments`.\n * The wrapper preserves the rest of the client's surface (other resources,\n * helpers, etc.) via a Proxy.\n *\n * Idempotent — a previously wrapped client is returned as-is.\n *\n * @example\n * ```ts\n * import { wrapOpenAI } from \"@morsehq-dev/sdk/openai\";\n * import OpenAI from \"openai\";\n *\n * const client = wrapOpenAI(new OpenAI());\n * const response = await client.chat.completions.create({\n * model: \"gpt-4o-mini\",\n * messages: [{ role: \"user\", content: \"hello\" }],\n * });\n * ```\n */\nexport function wrapOpenAI<C extends OpenAiClientLike>(\n client: C,\n options: WrapOpenAiOptions = {},\n): C {\n if (!client || typeof client !== \"object\") return client;\n // Already wrapped? Pass through.\n if ((client as Record<string | symbol, unknown>)[WRAPPED_CLIENT]) return client;\n\n const originalCreate = client.chat?.completions?.create?.bind(client.chat.completions);\n if (typeof originalCreate !== \"function\") return client;\n\n const patchedCreate = buildPatchedCreate(originalCreate, options);\n\n // Construct a new `completions` object that proxies to the original for\n // any non-`create` access, wrapped in a `chat` proxy, wrapped in a\n // top-level client proxy — mirrors `wrapAnthropic`'s nested-Proxy shape.\n const patchedCompletions = new Proxy(client.chat.completions, {\n get(target, prop, receiver) {\n if (prop === \"create\") return patchedCreate;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n const patchedChat = new Proxy(client.chat, {\n get(target, prop, receiver) {\n if (prop === \"completions\") return patchedCompletions;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n const wrapper = new Proxy(client, {\n get(target, prop, receiver) {\n if (prop === WRAPPED_CLIENT) return true;\n if (prop === \"chat\") return patchedChat;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n return wrapper as C;\n}\n\n/** True when a wrapped OpenAI client is passed in. */\nexport function isOpenAiWrapped(client: unknown): boolean {\n if (!client || typeof client !== \"object\") return false;\n return (client as Record<string | symbol, unknown>)[WRAPPED_CLIENT] === true;\n}\n\n/* ------------------------------------------------------------------------ */\n/* Internals — wrapper that records an `llm` span */\n/* ------------------------------------------------------------------------ */\n\nfunction buildPatchedCreate(\n original: (\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n ) => Promise<OpenAiChatCompletionResponse>,\n options: WrapOpenAiOptions,\n): (\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n) => Promise<OpenAiChatCompletionResponse> {\n const agentName = options.defaultAgentName ?? \"openai.chat.completions.create\";\n\n return async function patchedCreate(\n this: unknown,\n params: OpenAiChatCompletionCreateParams,\n callOptions?: unknown,\n ): Promise<OpenAiChatCompletionResponse> {\n const inTrace = getActiveTraceState() !== null;\n\n const work = async (): Promise<OpenAiChatCompletionResponse> => {\n setActiveFramework(\"openai\");\n const handle = startSpan({\n name: \"openai.chat.completions.create\",\n type: \"llm\",\n metadata: { model: params?.model },\n });\n let response: OpenAiChatCompletionResponse | undefined;\n try {\n response = await original.call(this, params, callOptions);\n } catch (err) {\n // Customer's own API error — mark the span failed, then re-raise\n // unchanged. Never swallow the caller's real error.\n handle?.end(err);\n throw err;\n }\n\n // Recording is best-effort — never let it throw at the caller.\n try {\n if (handle) {\n const segments = safeExtractSegments(params);\n const usage = response?.usage ?? {};\n const inputTokens = usage.prompt_tokens ?? 0;\n const outputTokens = usage.completion_tokens ?? 0;\n const cachedTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;\n const model = response?.model ?? params?.model;\n\n handle.span.model = model;\n if (inputTokens > 0) handle.span.input_tokens = inputTokens;\n if (outputTokens > 0) handle.span.output_tokens = outputTokens;\n if (cachedTokens > 0) handle.span.cached_input_tokens = cachedTokens;\n const totalTokens =\n usage.total_tokens ??\n (inputTokens > 0 || outputTokens > 0 ? inputTokens + outputTokens : 0);\n if (totalTokens > 0) handle.span.total_tokens = totalTokens;\n\n if (model && (inputTokens > 0 || outputTokens > 0)) {\n const cost = calculateCost({\n inputTokens,\n outputTokens,\n model,\n cachedInputTokens: cachedTokens,\n });\n if (cost !== undefined) handle.span.cost_usd = cost;\n }\n handle.span.context_segments = segments;\n // MHQ-858: prompt/response capture, parity with the Python\n // adapter's input_data/output_data.\n const inputData = captureInputMessages(params?.messages);\n if (inputData !== undefined) handle.span.input_data = inputData;\n const outputText = extractOpenAiOutputText(response?.choices);\n if (outputText !== undefined) handle.span.output_data = { content: outputText };\n }\n } catch (err) {\n // swallow — telemetry must never break the caller\n reportSwallowed(err, \"morse.openai.stream_wrap\");\n }\n handle?.end();\n return response;\n };\n\n if (inTrace) {\n return work();\n }\n\n // No active trace — open a fresh agent span around the call so the\n // llm span has a parent. Mirrors `wrapAnthropic`'s pattern: we can't\n // return `work()`'s Promise from inside `_runAsync`'s callback while\n // preserving typing AND having the fresh trace own the lifecycle, so\n // we wrap explicitly.\n let result: OpenAiChatCompletionResponse | undefined;\n let thrown: unknown;\n await _runAsync({ agentName }, async (runHandle) => {\n runHandle.setOutcome(true);\n try {\n result = await work();\n } catch (err) {\n thrown = err;\n throw err;\n }\n return null;\n });\n if (thrown !== undefined) throw thrown;\n return result as OpenAiChatCompletionResponse;\n };\n}\n\nfunction safeExtractSegments(params: OpenAiChatCompletionCreateParams): ContextSegment[] {\n try {\n if (!params || typeof params !== \"object\") return [];\n return decomposeOpenAiMessages(params.messages, params.tools);\n } catch {\n return [];\n }\n}\n\n/**\n * Route a swallowed internal error to the diagnostics channel (SDKDIAG-07).\n *\n * Control flow is unchanged — the site still swallows, still returns the same\n * value. It is simply no longer invisible to us.\n */\nfunction reportSwallowed(err: unknown, fingerprint: string): void {\n try {\n report(err, { fingerprint });\n } catch {\n // Reporting must never break the swallow it is reporting on.\n }\n}\n"]}
@@ -1,9 +1,11 @@
1
+ import { setActiveFramework, captureInputMessages, extractOpenAiOutputText } from '../chunk-32U547L3.js';
1
2
  import { calculateCost } from '../chunk-4FALQMOZ.js';
2
- import { decomposeOpenAiMessages } from '../chunk-QWRQJO57.js';
3
- import { init_tracing, getActiveTraceState, runAsync, startSpan } from '../chunk-F3B4UR64.js';
3
+ import { decomposeOpenAiMessages } from '../chunk-MLDVXMQD.js';
4
+ import { init_tracing, init_diagnostics, getActiveTraceState, runAsync, startSpan, report } from '../chunk-6DOP3MTY.js';
4
5
 
5
6
  // src/openai/index.ts
6
7
  init_tracing();
8
+ init_diagnostics();
7
9
  var WRAPPED_CLIENT = /* @__PURE__ */ Symbol.for("morse.openai.wrapped");
8
10
  function wrapOpenAI(client, options = {}) {
9
11
  if (!client || typeof client !== "object") return client;
@@ -47,6 +49,7 @@ function buildPatchedCreate(original, options) {
47
49
  return async function patchedCreate(params, callOptions) {
48
50
  const inTrace = getActiveTraceState() !== null;
49
51
  const work = async () => {
52
+ setActiveFramework("openai");
50
53
  const handle = startSpan({
51
54
  name: "openai.chat.completions.create",
52
55
  type: "llm",
@@ -83,8 +86,13 @@ function buildPatchedCreate(original, options) {
83
86
  if (cost !== void 0) handle.span.cost_usd = cost;
84
87
  }
85
88
  handle.span.context_segments = segments;
89
+ const inputData = captureInputMessages(params?.messages);
90
+ if (inputData !== void 0) handle.span.input_data = inputData;
91
+ const outputText = extractOpenAiOutputText(response?.choices);
92
+ if (outputText !== void 0) handle.span.output_data = { content: outputText };
86
93
  }
87
- } catch {
94
+ } catch (err) {
95
+ reportSwallowed(err, "morse.openai.stream_wrap");
88
96
  }
89
97
  handle?.end();
90
98
  return response;
@@ -116,6 +124,12 @@ function safeExtractSegments(params) {
116
124
  return [];
117
125
  }
118
126
  }
127
+ function reportSwallowed(err, fingerprint) {
128
+ try {
129
+ report(err, { fingerprint });
130
+ } catch {
131
+ }
132
+ }
119
133
 
120
134
  export { isOpenAiWrapped, wrapOpenAI };
121
135
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/openai/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * `@morsehq-dev/sdk/openai` — plain OpenAI SDK instrumentation.\n *\n * Wraps a raw `openai` npm package client (`new OpenAI()` /\n * `new AzureOpenAI()` / any structurally-compatible client) so every\n * `chat.completions.create` call emits an `llm` span carrying model,\n * token counts, `cost_usd`, and pre-segmented `context_segments`.\n *\n * TS port of `apps/sdk/python/src/morse_ai/adapters/openai.py`'s `wrap()`.\n * This module intentionally covers only the `wrap(client)` recommended\n * path (mirrors the Python module's three-layer doc comment, layer 2) —\n * no module-level monkey-patch / `install()` layer, since plain `openai`\n * is not one of the auto-detect targets on either SDK (see\n * `_internal/auto-detect.ts` and Python's `_internal/auto_detect.py`\n * `_adapter_targets()`, which both omit bare `openai`).\n *\n * Distinct from `@morsehq-dev/sdk/openai-agents`, which instruments the\n * `@openai/agents` Agents SDK (a different package with its own Runner /\n * Agent abstractions). This module is for customers calling\n * `openai.chat.completions.create` directly.\n *\n * Context segments are extracted via the shared\n * `_agent-sdk-common/context-decomposer.ts` (`decomposeOpenAiMessages`,\n * MHQ-750) — the request's `messages`/`tools` are already in the native\n * OpenAI wire format the decomposer expects, so no translation layer is\n * needed.\n *\n * Idempotent — wrapping an already-wrapped client instance is a no-op\n * that returns the same wrapper. Recording is best-effort: any failure\n * while building/emitting the span is swallowed so it can never break the\n * customer's OpenAI call. The customer's own API error (thrown by the\n * underlying `create()` call) always propagates unchanged — the span is\n * marked `status: \"failed\"` first, then the error is re-raised.\n *\n * Mirrors `apps/sdk/typescript/src/anthropic/index.ts` in shape.\n */\n\nimport { decomposeOpenAiMessages } from \"../_agent-sdk-common/context-decomposer\";\nimport { calculateCost } from \"../_internal/pricing\";\nimport type { ContextSegment } from \"../_internal/spans\";\nimport { getActiveTraceState, runAsync as _runAsync, startSpan } from \"../_internal/tracing\";\n\n/* ------------------------------------------------------------------------ */\n/* Public types — minimal structural shapes, NOT a hard dep on `openai` */\n/* ------------------------------------------------------------------------ */\n\n/** Subset of the `openai` package's chat message shape we read from. */\nexport interface OpenAiChatMessageParam {\n role: string;\n content?: unknown;\n tool_call_id?: string;\n [key: string]: unknown;\n}\n\n/** Subset of the `openai` package's tool-definition shape we read from. */\nexport interface OpenAiToolParam {\n type?: string;\n function?: { name?: string; [key: string]: unknown };\n [key: string]: unknown;\n}\n\n/**\n * Subset of `openai`'s `ChatCompletionCreateParams` we read from. We\n * deliberately decline to import the real types so the SDK works even when\n * `openai` isn't installed (it's an optional peer dep).\n */\nexport interface OpenAiChatCompletionCreateParams {\n model: string;\n messages: OpenAiChatMessageParam[];\n tools?: OpenAiToolParam[];\n // Allow forward-compat fields without complaint.\n [key: string]: unknown;\n}\n\nexport interface OpenAiCompletionUsageDetails {\n cached_tokens?: number;\n reasoning_tokens?: number;\n [key: string]: unknown;\n}\n\nexport interface OpenAiCompletionUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n prompt_tokens_details?: OpenAiCompletionUsageDetails;\n completion_tokens_details?: OpenAiCompletionUsageDetails;\n [key: string]: unknown;\n}\n\nexport interface OpenAiChatCompletionResponse {\n id?: string;\n model?: string;\n usage?: OpenAiCompletionUsage;\n choices?: Array<{ message?: { content?: unknown; [k: string]: unknown }; [k: string]: unknown }>;\n [key: string]: unknown;\n}\n\n/**\n * Structural shape of the plain OpenAI client we wrap. We only require\n * that `client.chat.completions.create` is a function returning a Promise.\n */\nexport interface OpenAiClientLike {\n chat: {\n completions: {\n create(\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n ): Promise<OpenAiChatCompletionResponse>;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n/* ------------------------------------------------------------------------ */\n/* Module-level sentinel */\n/* ------------------------------------------------------------------------ */\n\nconst WRAPPED_CLIENT = Symbol.for(\"morse.openai.wrapped\");\n\n/* ------------------------------------------------------------------------ */\n/* Public API */\n/* ------------------------------------------------------------------------ */\n\nexport interface WrapOpenAiOptions {\n /**\n * When provided, used as the parent agent span's name when\n * `chat.completions.create` is called outside an active trace. Defaults\n * to `\"openai.chat.completions.create\"`.\n */\n defaultAgentName?: string;\n}\n\n/**\n * Wrap an OpenAI client so every `chat.completions.create` call records an\n * `llm` span with `model`, token counts, `cost_usd`, and `context_segments`.\n * The wrapper preserves the rest of the client's surface (other resources,\n * helpers, etc.) via a Proxy.\n *\n * Idempotent — a previously wrapped client is returned as-is.\n *\n * @example\n * ```ts\n * import { wrapOpenAI } from \"@morsehq-dev/sdk/openai\";\n * import OpenAI from \"openai\";\n *\n * const client = wrapOpenAI(new OpenAI());\n * const response = await client.chat.completions.create({\n * model: \"gpt-4o-mini\",\n * messages: [{ role: \"user\", content: \"hello\" }],\n * });\n * ```\n */\nexport function wrapOpenAI<C extends OpenAiClientLike>(\n client: C,\n options: WrapOpenAiOptions = {},\n): C {\n if (!client || typeof client !== \"object\") return client;\n // Already wrapped? Pass through.\n if ((client as Record<string | symbol, unknown>)[WRAPPED_CLIENT]) return client;\n\n const originalCreate = client.chat?.completions?.create?.bind(client.chat.completions);\n if (typeof originalCreate !== \"function\") return client;\n\n const patchedCreate = buildPatchedCreate(originalCreate, options);\n\n // Construct a new `completions` object that proxies to the original for\n // any non-`create` access, wrapped in a `chat` proxy, wrapped in a\n // top-level client proxy — mirrors `wrapAnthropic`'s nested-Proxy shape.\n const patchedCompletions = new Proxy(client.chat.completions, {\n get(target, prop, receiver) {\n if (prop === \"create\") return patchedCreate;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n const patchedChat = new Proxy(client.chat, {\n get(target, prop, receiver) {\n if (prop === \"completions\") return patchedCompletions;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n const wrapper = new Proxy(client, {\n get(target, prop, receiver) {\n if (prop === WRAPPED_CLIENT) return true;\n if (prop === \"chat\") return patchedChat;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n return wrapper as C;\n}\n\n/** True when a wrapped OpenAI client is passed in. */\nexport function isOpenAiWrapped(client: unknown): boolean {\n if (!client || typeof client !== \"object\") return false;\n return (client as Record<string | symbol, unknown>)[WRAPPED_CLIENT] === true;\n}\n\n/* ------------------------------------------------------------------------ */\n/* Internals — wrapper that records an `llm` span */\n/* ------------------------------------------------------------------------ */\n\nfunction buildPatchedCreate(\n original: (\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n ) => Promise<OpenAiChatCompletionResponse>,\n options: WrapOpenAiOptions,\n): (\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n) => Promise<OpenAiChatCompletionResponse> {\n const agentName = options.defaultAgentName ?? \"openai.chat.completions.create\";\n\n return async function patchedCreate(\n this: unknown,\n params: OpenAiChatCompletionCreateParams,\n callOptions?: unknown,\n ): Promise<OpenAiChatCompletionResponse> {\n const inTrace = getActiveTraceState() !== null;\n\n const work = async (): Promise<OpenAiChatCompletionResponse> => {\n const handle = startSpan({\n name: \"openai.chat.completions.create\",\n type: \"llm\",\n metadata: { model: params?.model },\n });\n let response: OpenAiChatCompletionResponse | undefined;\n try {\n response = await original.call(this, params, callOptions);\n } catch (err) {\n // Customer's own API error — mark the span failed, then re-raise\n // unchanged. Never swallow the caller's real error.\n handle?.end(err);\n throw err;\n }\n\n // Recording is best-effort — never let it throw at the caller.\n try {\n if (handle) {\n const segments = safeExtractSegments(params);\n const usage = response?.usage ?? {};\n const inputTokens = usage.prompt_tokens ?? 0;\n const outputTokens = usage.completion_tokens ?? 0;\n const cachedTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;\n const model = response?.model ?? params?.model;\n\n handle.span.model = model;\n if (inputTokens > 0) handle.span.input_tokens = inputTokens;\n if (outputTokens > 0) handle.span.output_tokens = outputTokens;\n if (cachedTokens > 0) handle.span.cached_input_tokens = cachedTokens;\n const totalTokens =\n usage.total_tokens ??\n (inputTokens > 0 || outputTokens > 0 ? inputTokens + outputTokens : 0);\n if (totalTokens > 0) handle.span.total_tokens = totalTokens;\n\n if (model && (inputTokens > 0 || outputTokens > 0)) {\n const cost = calculateCost({\n inputTokens,\n outputTokens,\n model,\n cachedInputTokens: cachedTokens,\n });\n if (cost !== undefined) handle.span.cost_usd = cost;\n }\n handle.span.context_segments = segments;\n }\n } catch {\n // swallow — telemetry must never break the caller\n }\n handle?.end();\n return response;\n };\n\n if (inTrace) {\n return work();\n }\n\n // No active trace — open a fresh agent span around the call so the\n // llm span has a parent. Mirrors `wrapAnthropic`'s pattern: we can't\n // return `work()`'s Promise from inside `_runAsync`'s callback while\n // preserving typing AND having the fresh trace own the lifecycle, so\n // we wrap explicitly.\n let result: OpenAiChatCompletionResponse | undefined;\n let thrown: unknown;\n await _runAsync({ agentName }, async (runHandle) => {\n runHandle.setOutcome(true);\n try {\n result = await work();\n } catch (err) {\n thrown = err;\n throw err;\n }\n return null;\n });\n if (thrown !== undefined) throw thrown;\n return result as OpenAiChatCompletionResponse;\n };\n}\n\nfunction safeExtractSegments(params: OpenAiChatCompletionCreateParams): ContextSegment[] {\n try {\n if (!params || typeof params !== \"object\") return [];\n return decomposeOpenAiMessages(params.messages, params.tools);\n } catch {\n return [];\n }\n}\n"]}
1
+ {"version":3,"sources":["../../../src/openai/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * `@morsehq-dev/sdk/openai` — plain OpenAI SDK instrumentation.\n *\n * Wraps a raw `openai` npm package client (`new OpenAI()` /\n * `new AzureOpenAI()` / any structurally-compatible client) so every\n * `chat.completions.create` call emits an `llm` span carrying model,\n * token counts, `cost_usd`, and pre-segmented `context_segments`.\n *\n * TS port of `apps/sdk/python/src/morse_ai/adapters/openai.py`'s `wrap()`.\n * This module intentionally covers only the `wrap(client)` recommended\n * path (mirrors the Python module's three-layer doc comment, layer 2) —\n * no module-level monkey-patch / `install()` layer, since plain `openai`\n * is not one of the auto-detect targets on either SDK (see\n * `_internal/auto-detect.ts` and Python's `_internal/auto_detect.py`\n * `_adapter_targets()`, which both omit bare `openai`).\n *\n * Distinct from `@morsehq-dev/sdk/openai-agents`, which instruments the\n * `@openai/agents` Agents SDK (a different package with its own Runner /\n * Agent abstractions). This module is for customers calling\n * `openai.chat.completions.create` directly.\n *\n * Context segments are extracted via the shared\n * `_agent-sdk-common/context-decomposer.ts` (`decomposeOpenAiMessages`,\n * MHQ-750) — the request's `messages`/`tools` are already in the native\n * OpenAI wire format the decomposer expects, so no translation layer is\n * needed.\n *\n * Idempotent — wrapping an already-wrapped client instance is a no-op\n * that returns the same wrapper. Recording is best-effort: any failure\n * while building/emitting the span is swallowed so it can never break the\n * customer's OpenAI call. The customer's own API error (thrown by the\n * underlying `create()` call) always propagates unchanged — the span is\n * marked `status: \"failed\"` first, then the error is re-raised.\n *\n * Mirrors `apps/sdk/typescript/src/anthropic/index.ts` in shape.\n */\n\nimport { decomposeOpenAiMessages } from \"../_agent-sdk-common/context-decomposer\";\nimport { setActiveFramework } from \"../_internal/active-framework\";\nimport { captureInputMessages, extractOpenAiOutputText } from \"../_internal/llm-io\";\nimport { calculateCost } from \"../_internal/pricing\";\nimport type { ContextSegment } from \"../_internal/spans\";\nimport { getActiveTraceState, runAsync as _runAsync, startSpan } from \"../_internal/tracing\";\nimport { report } from \"../_internal/diagnostics\";\n\n/* ------------------------------------------------------------------------ */\n/* Public types — minimal structural shapes, NOT a hard dep on `openai` */\n/* ------------------------------------------------------------------------ */\n\n/** Subset of the `openai` package's chat message shape we read from. */\nexport interface OpenAiChatMessageParam {\n role: string;\n content?: unknown;\n tool_call_id?: string;\n [key: string]: unknown;\n}\n\n/** Subset of the `openai` package's tool-definition shape we read from. */\nexport interface OpenAiToolParam {\n type?: string;\n function?: { name?: string; [key: string]: unknown };\n [key: string]: unknown;\n}\n\n/**\n * Subset of `openai`'s `ChatCompletionCreateParams` we read from. We\n * deliberately decline to import the real types so the SDK works even when\n * `openai` isn't installed (it's an optional peer dep).\n */\nexport interface OpenAiChatCompletionCreateParams {\n model: string;\n messages: OpenAiChatMessageParam[];\n tools?: OpenAiToolParam[];\n // Allow forward-compat fields without complaint.\n [key: string]: unknown;\n}\n\nexport interface OpenAiCompletionUsageDetails {\n cached_tokens?: number;\n reasoning_tokens?: number;\n [key: string]: unknown;\n}\n\nexport interface OpenAiCompletionUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n prompt_tokens_details?: OpenAiCompletionUsageDetails;\n completion_tokens_details?: OpenAiCompletionUsageDetails;\n [key: string]: unknown;\n}\n\nexport interface OpenAiChatCompletionResponse {\n id?: string;\n model?: string;\n usage?: OpenAiCompletionUsage;\n choices?: Array<{ message?: { content?: unknown; [k: string]: unknown }; [k: string]: unknown }>;\n [key: string]: unknown;\n}\n\n/**\n * Structural shape of the plain OpenAI client we wrap. We only require\n * that `client.chat.completions.create` is a function returning a Promise.\n */\nexport interface OpenAiClientLike {\n chat: {\n completions: {\n create(\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n ): Promise<OpenAiChatCompletionResponse>;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n/* ------------------------------------------------------------------------ */\n/* Module-level sentinel */\n/* ------------------------------------------------------------------------ */\n\nconst WRAPPED_CLIENT = Symbol.for(\"morse.openai.wrapped\");\n\n/* ------------------------------------------------------------------------ */\n/* Public API */\n/* ------------------------------------------------------------------------ */\n\nexport interface WrapOpenAiOptions {\n /**\n * When provided, used as the parent agent span's name when\n * `chat.completions.create` is called outside an active trace. Defaults\n * to `\"openai.chat.completions.create\"`.\n */\n defaultAgentName?: string;\n}\n\n/**\n * Wrap an OpenAI client so every `chat.completions.create` call records an\n * `llm` span with `model`, token counts, `cost_usd`, and `context_segments`.\n * The wrapper preserves the rest of the client's surface (other resources,\n * helpers, etc.) via a Proxy.\n *\n * Idempotent — a previously wrapped client is returned as-is.\n *\n * @example\n * ```ts\n * import { wrapOpenAI } from \"@morsehq-dev/sdk/openai\";\n * import OpenAI from \"openai\";\n *\n * const client = wrapOpenAI(new OpenAI());\n * const response = await client.chat.completions.create({\n * model: \"gpt-4o-mini\",\n * messages: [{ role: \"user\", content: \"hello\" }],\n * });\n * ```\n */\nexport function wrapOpenAI<C extends OpenAiClientLike>(\n client: C,\n options: WrapOpenAiOptions = {},\n): C {\n if (!client || typeof client !== \"object\") return client;\n // Already wrapped? Pass through.\n if ((client as Record<string | symbol, unknown>)[WRAPPED_CLIENT]) return client;\n\n const originalCreate = client.chat?.completions?.create?.bind(client.chat.completions);\n if (typeof originalCreate !== \"function\") return client;\n\n const patchedCreate = buildPatchedCreate(originalCreate, options);\n\n // Construct a new `completions` object that proxies to the original for\n // any non-`create` access, wrapped in a `chat` proxy, wrapped in a\n // top-level client proxy — mirrors `wrapAnthropic`'s nested-Proxy shape.\n const patchedCompletions = new Proxy(client.chat.completions, {\n get(target, prop, receiver) {\n if (prop === \"create\") return patchedCreate;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n const patchedChat = new Proxy(client.chat, {\n get(target, prop, receiver) {\n if (prop === \"completions\") return patchedCompletions;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n const wrapper = new Proxy(client, {\n get(target, prop, receiver) {\n if (prop === WRAPPED_CLIENT) return true;\n if (prop === \"chat\") return patchedChat;\n const value = Reflect.get(target, prop, receiver);\n if (typeof value === \"function\") return (value as (...a: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n\n return wrapper as C;\n}\n\n/** True when a wrapped OpenAI client is passed in. */\nexport function isOpenAiWrapped(client: unknown): boolean {\n if (!client || typeof client !== \"object\") return false;\n return (client as Record<string | symbol, unknown>)[WRAPPED_CLIENT] === true;\n}\n\n/* ------------------------------------------------------------------------ */\n/* Internals — wrapper that records an `llm` span */\n/* ------------------------------------------------------------------------ */\n\nfunction buildPatchedCreate(\n original: (\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n ) => Promise<OpenAiChatCompletionResponse>,\n options: WrapOpenAiOptions,\n): (\n params: OpenAiChatCompletionCreateParams,\n options?: unknown,\n) => Promise<OpenAiChatCompletionResponse> {\n const agentName = options.defaultAgentName ?? \"openai.chat.completions.create\";\n\n return async function patchedCreate(\n this: unknown,\n params: OpenAiChatCompletionCreateParams,\n callOptions?: unknown,\n ): Promise<OpenAiChatCompletionResponse> {\n const inTrace = getActiveTraceState() !== null;\n\n const work = async (): Promise<OpenAiChatCompletionResponse> => {\n setActiveFramework(\"openai\");\n const handle = startSpan({\n name: \"openai.chat.completions.create\",\n type: \"llm\",\n metadata: { model: params?.model },\n });\n let response: OpenAiChatCompletionResponse | undefined;\n try {\n response = await original.call(this, params, callOptions);\n } catch (err) {\n // Customer's own API error — mark the span failed, then re-raise\n // unchanged. Never swallow the caller's real error.\n handle?.end(err);\n throw err;\n }\n\n // Recording is best-effort — never let it throw at the caller.\n try {\n if (handle) {\n const segments = safeExtractSegments(params);\n const usage = response?.usage ?? {};\n const inputTokens = usage.prompt_tokens ?? 0;\n const outputTokens = usage.completion_tokens ?? 0;\n const cachedTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;\n const model = response?.model ?? params?.model;\n\n handle.span.model = model;\n if (inputTokens > 0) handle.span.input_tokens = inputTokens;\n if (outputTokens > 0) handle.span.output_tokens = outputTokens;\n if (cachedTokens > 0) handle.span.cached_input_tokens = cachedTokens;\n const totalTokens =\n usage.total_tokens ??\n (inputTokens > 0 || outputTokens > 0 ? inputTokens + outputTokens : 0);\n if (totalTokens > 0) handle.span.total_tokens = totalTokens;\n\n if (model && (inputTokens > 0 || outputTokens > 0)) {\n const cost = calculateCost({\n inputTokens,\n outputTokens,\n model,\n cachedInputTokens: cachedTokens,\n });\n if (cost !== undefined) handle.span.cost_usd = cost;\n }\n handle.span.context_segments = segments;\n // MHQ-858: prompt/response capture, parity with the Python\n // adapter's input_data/output_data.\n const inputData = captureInputMessages(params?.messages);\n if (inputData !== undefined) handle.span.input_data = inputData;\n const outputText = extractOpenAiOutputText(response?.choices);\n if (outputText !== undefined) handle.span.output_data = { content: outputText };\n }\n } catch (err) {\n // swallow — telemetry must never break the caller\n reportSwallowed(err, \"morse.openai.stream_wrap\");\n }\n handle?.end();\n return response;\n };\n\n if (inTrace) {\n return work();\n }\n\n // No active trace — open a fresh agent span around the call so the\n // llm span has a parent. Mirrors `wrapAnthropic`'s pattern: we can't\n // return `work()`'s Promise from inside `_runAsync`'s callback while\n // preserving typing AND having the fresh trace own the lifecycle, so\n // we wrap explicitly.\n let result: OpenAiChatCompletionResponse | undefined;\n let thrown: unknown;\n await _runAsync({ agentName }, async (runHandle) => {\n runHandle.setOutcome(true);\n try {\n result = await work();\n } catch (err) {\n thrown = err;\n throw err;\n }\n return null;\n });\n if (thrown !== undefined) throw thrown;\n return result as OpenAiChatCompletionResponse;\n };\n}\n\nfunction safeExtractSegments(params: OpenAiChatCompletionCreateParams): ContextSegment[] {\n try {\n if (!params || typeof params !== \"object\") return [];\n return decomposeOpenAiMessages(params.messages, params.tools);\n } catch {\n return [];\n }\n}\n\n/**\n * Route a swallowed internal error to the diagnostics channel (SDKDIAG-07).\n *\n * Control flow is unchanged — the site still swallows, still returns the same\n * value. It is simply no longer invisible to us.\n */\nfunction reportSwallowed(err: unknown, fingerprint: string): void {\n try {\n report(err, { fingerprint });\n } catch {\n // Reporting must never break the swallow it is reporting on.\n }\n}\n"]}
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
- var chunkYNUZGKUA_cjs = require('../chunk-YNUZGKUA.cjs');
4
- var chunkEFUQVASI_cjs = require('../chunk-EFUQVASI.cjs');
5
- var chunk3BGG7GH3_cjs = require('../chunk-3BGG7GH3.cjs');
3
+ var chunkNT37C2TK_cjs = require('../chunk-NT37C2TK.cjs');
4
+ var chunk5EFKNOO7_cjs = require('../chunk-5EFKNOO7.cjs');
5
+ var chunkFNZWJU64_cjs = require('../chunk-FNZWJU64.cjs');
6
6
  var chunkSWQOPFE4_cjs = require('../chunk-SWQOPFE4.cjs');
7
- var chunk3643DC7K_cjs = require('../chunk-3643DC7K.cjs');
8
- var chunkDXWHT3HK_cjs = require('../chunk-DXWHT3HK.cjs');
7
+ var chunkRBNCTHK3_cjs = require('../chunk-RBNCTHK3.cjs');
8
+ var chunkZGYZZCUK_cjs = require('../chunk-ZGYZZCUK.cjs');
9
9
 
10
10
  // src/openai-agents/runner-wrapper.ts
11
- chunkDXWHT3HK_cjs.init_tracing();
11
+ chunkZGYZZCUK_cjs.init_tracing();
12
12
  var WRAPPED_RUNNER = /* @__PURE__ */ Symbol.for("morse.openai-agents.wrapped");
13
13
  var INSTALL_SENTINEL = /* @__PURE__ */ Symbol.for("morse.openai-agents.installed");
14
14
  var ORIGINALS_SENTINEL = /* @__PURE__ */ Symbol.for("morse.openai-agents.originals");
@@ -34,7 +34,7 @@ function wrapRunner(runner, options = {}) {
34
34
  });
35
35
  return wrapper;
36
36
  }
37
- var instrumentOpenAIAgents = chunk3BGG7GH3_cjs.absorbErrorsAsync(
37
+ var instrumentOpenAIAgents = chunkFNZWJU64_cjs.absorbErrorsAsync(
38
38
  async (runnerOrOptions = void 0, maybeOptions = {}) => {
39
39
  if (runnerOrOptions && isRunner(runnerOrOptions)) {
40
40
  const opts2 = maybeOptions ?? {};
@@ -67,7 +67,7 @@ var instrumentOpenAIAgents = chunk3BGG7GH3_cjs.absorbErrorsAsync(
67
67
  },
68
68
  { fingerprint: "morse.adapters.openai-agents.install" }
69
69
  );
70
- var uninstallOpenAIAgents = chunk3BGG7GH3_cjs.absorbErrorsSync(
70
+ var uninstallOpenAIAgents = chunkFNZWJU64_cjs.absorbErrorsSync(
71
71
  (openaiAgentsModule) => {
72
72
  if (!openaiAgentsModule || typeof openaiAgentsModule !== "object") return;
73
73
  const mod = openaiAgentsModule;
@@ -120,7 +120,7 @@ function buildPatchedRun(original, options) {
120
120
  const agentName = (agent && typeof agent === "object" && typeof agent.name === "string" && agent.name.length > 0 ? agent.name : void 0) ?? options.defaultAgentName ?? "openai-agent";
121
121
  const model = stringifyModel(agent?.model);
122
122
  const runWithSpan = async () => {
123
- const handle = chunkEFUQVASI_cjs.emitAgentSpan({
123
+ const handle = chunk5EFKNOO7_cjs.emitAgentSpan({
124
124
  adapter: "openai-agents",
125
125
  agentName,
126
126
  model
@@ -138,13 +138,13 @@ function buildPatchedRun(original, options) {
138
138
  throw err;
139
139
  }
140
140
  };
141
- if (chunkDXWHT3HK_cjs.getActiveTraceState() !== null) {
141
+ if (chunkZGYZZCUK_cjs.getActiveTraceState() !== null) {
142
142
  return runWithSpan();
143
143
  }
144
144
  return (async () => {
145
145
  let captured;
146
146
  let caughtErr;
147
- const runResult = await chunkDXWHT3HK_cjs.runAsync({ agentName }, async (runHandle) => {
147
+ const runResult = await chunkZGYZZCUK_cjs.runAsync({ agentName }, async (runHandle) => {
148
148
  try {
149
149
  captured = await runWithSpan();
150
150
  runHandle.setOutcome(true);
@@ -173,10 +173,10 @@ function installLlmAndToolInstrumentation(runner, options) {
173
173
  const opts = options ?? {};
174
174
  const llmStack = [];
175
175
  const toolStack = [];
176
- const onLlmStart = chunk3BGG7GH3_cjs.absorbErrorsSync(
176
+ const onLlmStart = chunkFNZWJU64_cjs.absorbErrorsSync(
177
177
  (event) => {
178
- const contextSegments = chunk3643DC7K_cjs.decomposeOpenAiMessages(event.llm?.messages, event.llm?.tools);
179
- const handle = chunkEFUQVASI_cjs.emitLlmSpan({
178
+ const contextSegments = chunkRBNCTHK3_cjs.decomposeOpenAiMessages(event.llm?.messages, event.llm?.tools);
179
+ const handle = chunk5EFKNOO7_cjs.emitLlmSpan({
180
180
  adapter: ADAPTER,
181
181
  model: typeof event.llm?.model === "string" && event.llm.model.length > 0 ? event.llm.model : "unknown",
182
182
  provider: typeof event.llm?.provider === "string" ? event.llm.provider : void 0,
@@ -186,7 +186,7 @@ function installLlmAndToolInstrumentation(runner, options) {
186
186
  },
187
187
  { fingerprint: "morse.openai-agents.llm_call_start" }
188
188
  );
189
- const onLlmEnd = chunk3BGG7GH3_cjs.absorbErrorsSync(
189
+ const onLlmEnd = chunkFNZWJU64_cjs.absorbErrorsSync(
190
190
  (event) => {
191
191
  const handle = llmStack.shift();
192
192
  if (handle === void 0) return;
@@ -218,14 +218,14 @@ function installLlmAndToolInstrumentation(runner, options) {
218
218
  },
219
219
  { fingerprint: "morse.openai-agents.llm_call_end" }
220
220
  );
221
- const onToolStart = chunk3BGG7GH3_cjs.absorbErrorsSync(
221
+ const onToolStart = chunkFNZWJU64_cjs.absorbErrorsSync(
222
222
  (event) => {
223
223
  const toolName = typeof event.tool?.name === "string" && event.tool.name.length > 0 ? event.tool.name : "unknown";
224
- const inputSummary = chunkYNUZGKUA_cjs.summarizeToolInput(
224
+ const inputSummary = chunkNT37C2TK_cjs.summarizeToolInput(
225
225
  event.tool?.input,
226
226
  opts.toolInputMaxBytes !== void 0 ? { maxBytes: opts.toolInputMaxBytes } : void 0
227
227
  );
228
- const handle = chunkEFUQVASI_cjs.emitToolSpan({
228
+ const handle = chunk5EFKNOO7_cjs.emitToolSpan({
229
229
  adapter: ADAPTER,
230
230
  toolName,
231
231
  inputSummary
@@ -234,11 +234,11 @@ function installLlmAndToolInstrumentation(runner, options) {
234
234
  },
235
235
  { fingerprint: "morse.openai-agents.tool_call_start" }
236
236
  );
237
- const onToolEnd = chunk3BGG7GH3_cjs.absorbErrorsSync(
237
+ const onToolEnd = chunkFNZWJU64_cjs.absorbErrorsSync(
238
238
  (event) => {
239
239
  const handle = toolStack.shift();
240
240
  if (handle === void 0) return;
241
- const outputSummary = chunkYNUZGKUA_cjs.summarizeToolOutput(
241
+ const outputSummary = chunkNT37C2TK_cjs.summarizeToolOutput(
242
242
  event.tool?.output,
243
243
  opts.toolOutputMaxBytes !== void 0 ? { maxBytes: opts.toolOutputMaxBytes } : void 0
244
244
  );
@@ -292,7 +292,7 @@ var _handleHandoffEvent = (event) => {
292
292
  handoff_from: from
293
293
  };
294
294
  if (reason !== void 0) attributes.handoff_reason = reason;
295
- const handle = chunkEFUQVASI_cjs.emitSubagentSpan({
295
+ const handle = chunk5EFKNOO7_cjs.emitSubagentSpan({
296
296
  adapter: "openai-agents",
297
297
  parentAgentName: from,
298
298
  subagentName: to,
@@ -301,7 +301,7 @@ var _handleHandoffEvent = (event) => {
301
301
  });
302
302
  handle?.end();
303
303
  };
304
- var handleHandoffEvent = chunk3BGG7GH3_cjs.absorbErrorsSync(_handleHandoffEvent, {
304
+ var handleHandoffEvent = chunkFNZWJU64_cjs.absorbErrorsSync(_handleHandoffEvent, {
305
305
  fingerprint: "morse.adapters.openai-agents.handoff.listener"
306
306
  });
307
307
  function installHandoffInstrumentation(runner) {
@@ -338,7 +338,7 @@ var _handleGuardrailEvent = (payload) => {
338
338
  const guardrailMeta = { passed };
339
339
  if (name !== void 0) guardrailMeta.name = name;
340
340
  if (reason !== void 0) guardrailMeta.reason = reason;
341
- const handle = chunkEFUQVASI_cjs.emitToolSpan({
341
+ const handle = chunk5EFKNOO7_cjs.emitToolSpan({
342
342
  adapter: "openai-agents",
343
343
  toolName: `guardrail.${name ?? "anon"}`,
344
344
  success: passed
@@ -355,7 +355,7 @@ var _handleGuardrailEvent = (payload) => {
355
355
  handle.end(new Error(`guardrail failed: ${reason ?? "no reason"}`));
356
356
  }
357
357
  };
358
- var handleGuardrailEvent = chunk3BGG7GH3_cjs.absorbErrorsSync(
358
+ var handleGuardrailEvent = chunkFNZWJU64_cjs.absorbErrorsSync(
359
359
  _handleGuardrailEvent,
360
360
  { fingerprint: "morse.openai-agents.guardrail.handle" }
361
361
  );
@@ -384,6 +384,7 @@ function installGuardrailInstrumentation(runner) {
384
384
  }
385
385
 
386
386
  // src/openai-agents/trace-processor.ts
387
+ chunkZGYZZCUK_cjs.init_diagnostics();
387
388
  var ADAPTER2 = "openai-agents";
388
389
  function safe(fn) {
389
390
  try {
@@ -500,32 +501,32 @@ var MorseTraceProcessor = class {
500
501
  const name = typeof d.name === "string" && d.name.length > 0 ? d.name : void 0;
501
502
  switch (type) {
502
503
  case "agent":
503
- return chunkEFUQVASI_cjs.emitAgentSpan({
504
+ return chunk5EFKNOO7_cjs.emitAgentSpan({
504
505
  adapter: ADAPTER2,
505
506
  agentName: name ?? "openai-agent"
506
507
  });
507
508
  case "generation":
508
509
  case "response": {
509
510
  const model = typeof d.model === "string" && d.model.length > 0 ? d.model : "unknown";
510
- return chunkEFUQVASI_cjs.emitLlmSpan({ adapter: ADAPTER2, model });
511
+ return chunk5EFKNOO7_cjs.emitLlmSpan({ adapter: ADAPTER2, model });
511
512
  }
512
513
  case "function": {
513
514
  const inputOpts = this.options.toolInputMaxBytes ? { maxBytes: this.options.toolInputMaxBytes } : void 0;
514
- return chunkEFUQVASI_cjs.emitToolSpan({
515
+ return chunk5EFKNOO7_cjs.emitToolSpan({
515
516
  adapter: ADAPTER2,
516
517
  toolName: name ?? "function",
517
- inputSummary: d.input !== void 0 ? chunkYNUZGKUA_cjs.summarizeToolInput(d.input, inputOpts) : void 0
518
+ inputSummary: d.input !== void 0 ? chunkNT37C2TK_cjs.summarizeToolInput(d.input, inputOpts) : void 0
518
519
  });
519
520
  }
520
521
  case "handoff":
521
- return chunkEFUQVASI_cjs.emitSubagentSpan({
522
+ return chunk5EFKNOO7_cjs.emitSubagentSpan({
522
523
  adapter: ADAPTER2,
523
524
  parentAgentName: typeof d.from_agent === "string" ? d.from_agent : "unknown",
524
525
  subagentName: typeof d.to_agent === "string" ? d.to_agent : name ?? "unknown",
525
526
  taskDescription: typeof d.reason === "string" ? d.reason : void 0
526
527
  });
527
528
  case "guardrail": {
528
- const handle = chunkEFUQVASI_cjs.emitToolSpan({
529
+ const handle = chunk5EFKNOO7_cjs.emitToolSpan({
529
530
  adapter: ADAPTER2,
530
531
  toolName: `guardrail.${name ?? "anon"}`
531
532
  });
@@ -543,17 +544,17 @@ var MorseTraceProcessor = class {
543
544
  return handle;
544
545
  }
545
546
  case "mcp_list_tools":
546
- return chunkEFUQVASI_cjs.emitToolSpan({
547
+ return chunk5EFKNOO7_cjs.emitToolSpan({
547
548
  adapter: ADAPTER2,
548
549
  toolName: `mcp.list_tools.${name ?? "anon"}`
549
550
  });
550
551
  case "custom":
551
- return chunkEFUQVASI_cjs.emitToolSpan({
552
+ return chunk5EFKNOO7_cjs.emitToolSpan({
552
553
  adapter: ADAPTER2,
553
554
  toolName: `custom.${name ?? "anon"}`
554
555
  });
555
556
  default:
556
- return chunkEFUQVASI_cjs.emitToolSpan({
557
+ return chunk5EFKNOO7_cjs.emitToolSpan({
557
558
  adapter: ADAPTER2,
558
559
  toolName: `${type || "unknown"}.${name ?? "anon"}`
559
560
  });
@@ -582,7 +583,7 @@ var MorseTraceProcessor = class {
582
583
  const outputOpts = this.options.toolOutputMaxBytes ? { maxBytes: this.options.toolOutputMaxBytes } : void 0;
583
584
  handle.span.metadata = {
584
585
  ...handle.span.metadata ?? {},
585
- tool_output_summary: chunkYNUZGKUA_cjs.summarizeToolOutput(d.output, outputOpts)
586
+ tool_output_summary: chunkNT37C2TK_cjs.summarizeToolOutput(d.output, outputOpts)
586
587
  };
587
588
  }
588
589
  }
@@ -612,6 +613,13 @@ function safeEnd(handle, err) {
612
613
  } else {
613
614
  handle.end();
614
615
  }
616
+ } catch (err2) {
617
+ reportSwallowed(err2, "morse.openai_agents.trace_processor");
618
+ }
619
+ }
620
+ function reportSwallowed(err, fingerprint) {
621
+ try {
622
+ chunkZGYZZCUK_cjs.report(err, { fingerprint });
615
623
  } catch {
616
624
  }
617
625
  }