@elasticdash/openai 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -288,7 +288,7 @@ var wrapMethod = (tracedMethod, config, ...args) => {
288
288
  model,
289
289
  input,
290
290
  modelParameters: finalModelParams,
291
- prompt: config == null ? void 0 : config.langfusePrompt,
291
+ prompt: config == null ? void 0 : config.elasticDashPrompt,
292
292
  metadata: finalMetadata
293
293
  },
294
294
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/traceMethod.ts","../src/parseOpenAI.ts","../src/utils.ts","../src/observeOpenAI.ts"],"sourcesContent":["export { observeOpenAI } from \"./observeOpenAI.js\";\nexport * from \"./types.js\";\n","import { LangfuseGeneration, startObservation } from \"@elasticdash/tracing\";\nimport type OpenAI from \"openai\";\n\nimport {\n getToolCallOutput,\n parseChunk,\n parseCompletionOutput,\n parseInputArgs,\n parseUsageDetails,\n parseModelDataFromResponse,\n parseUsageDetailsFromResponse,\n} from \"./parseOpenAI.js\";\nimport type { ElasticDashConfig } from \"./types.js\";\nimport { isAsyncIterable } from \"./utils.js\";\n\n/**\n * Generic method type for any function that can be traced.\n * @internal\n */\ntype GenericMethod = (...args: unknown[]) => unknown;\n\n/**\n * Wraps a method with ElasticDash tracing functionality.\n *\n * This function creates a wrapper around OpenAI SDK methods that automatically\n * creates ElasticDash generations, captures input/output data, handles streaming\n * responses, and records usage metrics and errors.\n *\n * @param tracedMethod - The OpenAI SDK method to wrap with tracing\n * @param config - Configuration for the trace and generation\n * @returns A wrapped version of the method that creates ElasticDash traces\n *\n * @internal\n */\nexport const withTracing = <T extends GenericMethod>(\n tracedMethod: T,\n config?: ElasticDashConfig & Required<{ generationName: string }>,\n): ((...args: Parameters<T>) => Promise<ReturnType<T>>) => {\n return (...args) => wrapMethod(tracedMethod, config, ...args);\n};\n\n/**\n * Internal method that handles the actual tracing logic for OpenAI SDK methods.\n *\n * This function creates a ElasticDash generation, executes the original method,\n * and captures all relevant data including input, output, usage, and errors.\n * It handles both streaming and non-streaming responses appropriately.\n *\n * @param tracedMethod - The original OpenAI SDK method to execute\n * @param config - ElasticDash configuration options\n * @param args - Arguments to pass to the original method\n * @returns The result from the original method, potentially wrapped for streaming\n *\n * @internal\n */\nconst wrapMethod = <T extends GenericMethod>(\n tracedMethod: T,\n config?: ElasticDashConfig,\n ...args: Parameters<T>\n): ReturnType<T> | any => {\n const { model, input, modelParameters } = parseInputArgs(args[0] ?? {});\n\n const finalModelParams = { ...modelParameters, response_format: \"\" };\n const finalMetadata = {\n ...config?.generationMetadata,\n response_format:\n \"response_format\" in modelParameters\n ? modelParameters.response_format\n : undefined,\n };\n\n const generation = startObservation(\n config?.generationName ?? \"OpenAI-completion\",\n {\n model,\n input,\n modelParameters: finalModelParams,\n prompt: config?.langfusePrompt,\n metadata: finalMetadata,\n },\n {\n asType: \"generation\",\n parentSpanContext: config?.parentSpanContext,\n },\n ).updateTrace({\n userId: config?.userId,\n sessionId: config?.sessionId,\n tags: config?.tags,\n name: config?.traceName,\n });\n\n try {\n const res = tracedMethod(...args);\n\n // Handle stream responses\n if (isAsyncIterable(res)) {\n return wrapAsyncIterable(res, generation);\n }\n\n if (res instanceof Promise) {\n const wrappedPromise = res\n .then((result) => {\n if (isAsyncIterable(result)) {\n return wrapAsyncIterable(result, generation);\n }\n\n const output = parseCompletionOutput(result);\n const usageDetails = parseUsageDetailsFromResponse(result);\n const {\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n } = parseModelDataFromResponse(result);\n\n generation\n .update({\n output,\n usageDetails,\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n })\n .end();\n\n return result;\n })\n .catch((err) => {\n generation\n .update({\n statusMessage: String(err),\n level: \"ERROR\",\n costDetails: {\n input: 0,\n output: 0,\n total: 0,\n },\n })\n .end();\n\n throw err;\n });\n\n return wrappedPromise;\n }\n\n return res;\n } catch (error) {\n generation\n .update({\n statusMessage: String(error),\n level: \"ERROR\",\n costDetails: {\n input: 0,\n output: 0,\n total: 0,\n },\n })\n .end();\n\n throw error;\n }\n};\n\n/**\n * Wraps an async iterable (streaming response) with ElasticDash tracing.\n *\n * This function handles streaming OpenAI responses by collecting chunks,\n * parsing usage information, and updating the ElasticDash generation with\n * the complete output and usage details once the stream is consumed.\n *\n * @param iterable - The async iterable from OpenAI (streaming response)\n * @param generation - The ElasticDash generation to update with stream data\n * @returns An async generator that yields original chunks while collecting data\n *\n * @internal\n */\nfunction wrapAsyncIterable<R>(\n iterable: AsyncIterable<unknown>,\n generation: LangfuseGeneration,\n): R {\n async function* tracedOutputGenerator(): AsyncGenerator<\n unknown,\n void,\n unknown\n > {\n const response = iterable;\n const textChunks: string[] = [];\n const toolCallChunks: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall[] =\n [];\n let usage: OpenAI.CompletionUsage | null = null;\n let completionStartTime: Date | undefined = undefined;\n let usageDetails: Record<string, number> | undefined = undefined;\n let output: unknown = null;\n\n for await (const rawChunk of response as AsyncIterable<unknown>) {\n completionStartTime = completionStartTime ?? new Date();\n\n // Handle Response API chunks\n if (typeof rawChunk === \"object\" && rawChunk && \"response\" in rawChunk) {\n const result = rawChunk[\"response\"];\n output = parseCompletionOutput(result);\n usageDetails = parseUsageDetailsFromResponse(result);\n\n const {\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n } = parseModelDataFromResponse(result);\n\n generation.update({\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n });\n }\n\n if (\n typeof rawChunk === \"object\" &&\n rawChunk != null &&\n \"usage\" in rawChunk\n ) {\n usage = rawChunk.usage as OpenAI.CompletionUsage | null;\n }\n\n const processedChunk = parseChunk(rawChunk);\n\n if (!processedChunk.isToolCall) {\n textChunks.push(processedChunk.data);\n } else {\n toolCallChunks.push(processedChunk.data);\n }\n\n yield rawChunk;\n }\n\n output =\n output ??\n (toolCallChunks.length > 0\n ? getToolCallOutput(toolCallChunks)\n : textChunks.join(\"\"));\n\n generation\n .update({\n output,\n completionStartTime,\n usageDetails:\n usageDetails ?? (usage ? parseUsageDetails(usage) : undefined),\n })\n .end();\n }\n\n return tracedOutputGenerator() as R;\n}\n","import type OpenAI from \"openai\";\n\ntype ParsedOpenAIArguments = {\n model: string;\n input: Record<string, any> | string;\n modelParameters: Record<string, any>;\n};\n\nexport const parseInputArgs = (\n args: Record<string, any>,\n): ParsedOpenAIArguments => {\n let params: Record<string, any> = {};\n params = {\n frequency_penalty: args.frequency_penalty,\n logit_bias: args.logit_bias,\n logprobs: args.logprobs,\n max_tokens: args.max_tokens,\n n: args.n,\n presence_penalty: args.presence_penalty,\n seed: args.seed,\n stop: args.stop,\n stream: args.stream,\n temperature: args.temperature,\n top_p: args.top_p,\n user: args.user,\n response_format: args.response_format,\n top_logprobs: args.top_logprobs,\n };\n\n let input: Record<string, any> | string = args.input;\n\n if (\n args &&\n typeof args === \"object\" &&\n !Array.isArray(args) &&\n \"messages\" in args\n ) {\n input = {};\n input.messages = args.messages;\n if (\"function_call\" in args) {\n input.function_call = args.function_call;\n }\n if (\"functions\" in args) {\n input.functions = args.functions;\n }\n if (\"tools\" in args) {\n input.tools = args.tools;\n }\n\n if (\"tool_choice\" in args) {\n input.tool_choice = args.tool_choice;\n }\n } else if (!input) {\n input = args.prompt;\n }\n\n return {\n model: args.model,\n input: input,\n modelParameters: params,\n };\n};\n\nexport const parseCompletionOutput = (res: unknown): unknown => {\n if (\n res instanceof Object &&\n \"output_text\" in res &&\n res[\"output_text\"] !== \"\"\n ) {\n return res[\"output_text\"] as string;\n }\n\n if (\n typeof res === \"object\" &&\n res &&\n \"output\" in res &&\n Array.isArray(res[\"output\"])\n ) {\n const output = res[\"output\"];\n\n if (output.length > 1) {\n return output;\n }\n if (output.length === 1) {\n return output[0] as Record<string, unknown>;\n }\n\n return null;\n }\n\n if (\n !(res instanceof Object && \"choices\" in res && Array.isArray(res.choices))\n ) {\n return \"\";\n }\n\n return \"message\" in res.choices[0]\n ? res.choices[0].message\n : (res.choices[0].text ?? \"\");\n};\n\nexport const parseUsageDetails = (\n completionUsage: OpenAI.CompletionUsage,\n): Record<string, number> | undefined => {\n if (\"prompt_tokens\" in completionUsage) {\n const {\n prompt_tokens,\n completion_tokens,\n total_tokens,\n completion_tokens_details,\n prompt_tokens_details,\n } = completionUsage;\n\n const flatPromptTokensDetails = Object.fromEntries(\n Object.entries(prompt_tokens_details ?? {}).map(([key, value]) => [\n `input_${key}`,\n value as number,\n ]),\n );\n\n const flatCompletionTokensDetails = Object.fromEntries(\n Object.entries(completion_tokens_details ?? {}).map(([key, value]) => [\n `output_${key}`,\n value as number,\n ]),\n );\n\n let finalInputTokens = prompt_tokens as number;\n Object.values(flatPromptTokensDetails).forEach((value) => {\n finalInputTokens = Math.max(finalInputTokens - value, 0);\n });\n\n let finalOutputTokens = completion_tokens as number;\n Object.values(flatCompletionTokensDetails).forEach((value) => {\n finalOutputTokens = Math.max(finalOutputTokens - value, 0);\n });\n\n return {\n input: finalInputTokens,\n output: finalOutputTokens,\n total: total_tokens,\n ...flatPromptTokensDetails,\n ...flatCompletionTokensDetails,\n };\n } else if (\"input_tokens\" in completionUsage) {\n const {\n input_tokens,\n output_tokens,\n total_tokens,\n input_tokens_details,\n output_tokens_details,\n } = completionUsage;\n\n let finalInputTokens = input_tokens as number;\n Object.keys(input_tokens_details ?? {}).forEach((key) => {\n finalInputTokens = Math.max(\n finalInputTokens -\n input_tokens_details[key as keyof typeof input_tokens_details],\n 0,\n );\n });\n\n let finalOutputTokens = output_tokens as number;\n Object.keys(output_tokens_details ?? {}).forEach((key) => {\n finalOutputTokens = Math.max(\n finalOutputTokens -\n output_tokens_details[key as keyof typeof output_tokens_details],\n 0,\n );\n });\n\n return {\n input: finalInputTokens,\n output: finalOutputTokens,\n total: total_tokens,\n ...Object.fromEntries(\n Object.entries(input_tokens_details ?? {}).map(([key, value]) => [\n `input_${key}`,\n value as number,\n ]),\n ),\n ...Object.fromEntries(\n Object.entries(output_tokens_details ?? {}).map(([key, value]) => [\n `output_${key}`,\n value as number,\n ]),\n ),\n };\n }\n};\n\nexport const parseUsageDetailsFromResponse = (\n res: unknown,\n): Record<string, number> | undefined => {\n if (hasCompletionUsage(res)) {\n return parseUsageDetails(res.usage);\n }\n};\n\nexport const parseChunk = (\n rawChunk: unknown,\n):\n | { isToolCall: false; data: string }\n | {\n isToolCall: true;\n data: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall;\n } => {\n let isToolCall = false;\n const _chunk = rawChunk as\n | OpenAI.ChatCompletionChunk\n | OpenAI.Completions.Completion;\n const chunkData = _chunk?.choices?.[0];\n\n try {\n if (\n \"delta\" in chunkData &&\n \"tool_calls\" in chunkData.delta &&\n Array.isArray(chunkData.delta.tool_calls)\n ) {\n isToolCall = true;\n\n return { isToolCall, data: chunkData.delta.tool_calls[0] };\n }\n if (\"delta\" in chunkData) {\n return { isToolCall, data: chunkData.delta?.content || \"\" };\n }\n\n if (\"text\" in chunkData) {\n return { isToolCall, data: chunkData.text || \"\" };\n }\n } catch {}\n\n return { isToolCall: false, data: \"\" };\n};\n\n// Type guard to check if an unknown object is a UsageResponse\nfunction hasCompletionUsage(\n obj: any,\n): obj is { usage: OpenAI.CompletionUsage } {\n return (\n obj instanceof Object &&\n \"usage\" in obj &&\n obj.usage instanceof Object &&\n // Completion API Usage format\n ((typeof obj.usage.prompt_tokens === \"number\" &&\n typeof obj.usage.completion_tokens === \"number\" &&\n typeof obj.usage.total_tokens === \"number\") ||\n // Response API Usage format\n (typeof obj.usage.input_tokens === \"number\" &&\n typeof obj.usage.output_tokens === \"number\" &&\n typeof obj.usage.total_tokens === \"number\"))\n );\n}\n\nexport const getToolCallOutput = (\n toolCallChunks: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall[],\n): {\n tool_calls: {\n function: {\n name: string;\n arguments: string;\n };\n }[];\n} => {\n let name = \"\";\n let toolArguments = \"\";\n\n for (const toolCall of toolCallChunks) {\n name = toolCall.function?.name || name;\n toolArguments += toolCall.function?.arguments || \"\";\n }\n\n return {\n tool_calls: [\n {\n function: {\n name,\n arguments: toolArguments,\n },\n },\n ],\n };\n};\n\nexport const parseModelDataFromResponse = (\n res: unknown,\n): {\n model: string | undefined;\n modelParameters: Record<string, string | number> | undefined;\n metadata: Record<string, unknown> | undefined;\n} => {\n if (typeof res !== \"object\" || res === null) {\n return {\n model: undefined,\n modelParameters: undefined,\n metadata: undefined,\n };\n }\n\n const model = \"model\" in res ? (res[\"model\"] as string) : undefined;\n const modelParameters: Record<string, string | number> = {};\n const modelParamKeys = [\n \"max_output_tokens\",\n \"parallel_tool_calls\",\n \"store\",\n \"temperature\",\n \"tool_choice\",\n \"top_p\",\n \"truncation\",\n \"user\",\n ];\n\n const metadata: Record<string, unknown> = {};\n const metadataKeys = [\n \"reasoning\",\n \"incomplete_details\",\n \"instructions\",\n \"previous_response_id\",\n \"tools\",\n \"metadata\",\n \"status\",\n \"error\",\n ];\n\n for (const key of modelParamKeys) {\n const val =\n key in res ? (res[key as keyof typeof res] as string | number) : null;\n if (val !== null && val !== undefined) {\n modelParameters[key as keyof typeof modelParameters] = val;\n }\n }\n\n for (const key of metadataKeys) {\n const val =\n key in res ? (res[key as keyof typeof res] as string | number) : null;\n if (val) {\n metadata[key as keyof typeof metadata] = val;\n }\n }\n\n return {\n model,\n modelParameters:\n Object.keys(modelParameters).length > 0 ? modelParameters : undefined,\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n };\n};\n","/**\n * Type guard to check if a value is an async iterable.\n *\n * This utility function determines whether a given value implements the\n * AsyncIterable interface, which is used to identify streaming responses\n * from the OpenAI SDK.\n *\n * @param x - The value to check\n * @returns True if the value is an async iterable, false otherwise\n *\n * @example\n * ```typescript\n * import { isAsyncIterable } from './utils.js';\n *\n * const response = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [...],\n * stream: true\n * });\n *\n * if (isAsyncIterable(response)) {\n * // Handle streaming response\n * for await (const chunk of response) {\n * console.log(chunk);\n * }\n * } else {\n * // Handle regular response\n * console.log(response);\n * }\n * ```\n *\n * @public\n */\nexport const isAsyncIterable = (x: unknown): x is AsyncIterable<unknown> =>\n x != null &&\n typeof x === \"object\" &&\n typeof (x as any)[Symbol.asyncIterator] === \"function\";\n","import { withTracing } from \"./traceMethod.js\";\nimport type { ElasticDashConfig } from \"./types.js\";\n\n/**\n * Wraps an OpenAI SDK client with automatic ElasticDash tracing.\n *\n * This function creates a proxy around the OpenAI SDK that automatically\n * traces all method calls, capturing detailed information about requests,\n * responses, token usage, costs, and performance metrics. It works with\n * both streaming and non-streaming OpenAI API calls.\n *\n * The wrapper recursively traces nested objects in the OpenAI SDK, ensuring\n * that all API calls (chat completions, embeddings, fine-tuning, etc.) are\n * automatically captured as ElasticDash generations.\n *\n * @param sdk - The OpenAI SDK client instance to wrap with tracing\n * @param elasticDashConfig - Optional configuration for tracing behavior\n * @returns A proxied version of the OpenAI SDK with automatic tracing\n *\n * @example\n * ```typescript\n * import OpenAI from 'openai';\n * import { observeOpenAI } from '@elasticdash/openai';\n *\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY,\n * }));\n *\n * // All OpenAI calls are now automatically traced\n * const response = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Hello!' }],\n * max_tokens: 100,\n * temperature: 0.7\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With custom tracing configuration\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY\n * }), {\n * traceName: 'AI-Assistant-Chat',\n * userId: 'user-123',\n * sessionId: 'session-456',\n * tags: ['production', 'chat-feature'],\n * generationName: 'gpt-4-chat-completion'\n * });\n *\n * const completion = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Explain quantum computing' }]\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Streaming responses are also automatically traced\n * const stream = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Write a story' }],\n * stream: true\n * });\n *\n * for await (const chunk of stream) {\n * process.stdout.write(chunk.choices[0]?.delta?.content || '');\n * }\n * // Final usage details and complete output are captured automatically\n * ```\n *\n * @example\n * ```typescript\n * // Using with ElasticDash prompt management\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY\n * }), {\n * langfusePrompt: {\n * name: 'chat-assistant-v2',\n * version: 3,\n * isFallback: false\n * },\n * generationMetadata: {\n * environment: 'production',\n * feature: 'chat-assistant'\n * }\n * });\n * ```\n *\n * @public\n */\nexport const observeOpenAI = <SDKType extends object>(\n sdk: SDKType,\n elasticDashConfig?: ElasticDashConfig,\n): SDKType => {\n return new Proxy(sdk, {\n get(wrappedSdk, propKey, proxy) {\n const originalProperty = wrappedSdk[propKey as keyof SDKType];\n\n const defaultGenerationName = `${sdk.constructor?.name}.${propKey.toString()}`;\n const generationName =\n elasticDashConfig?.generationName ?? defaultGenerationName;\n const config = { ...elasticDashConfig, generationName };\n\n // Trace methods of the OpenAI SDK\n if (typeof originalProperty === \"function\") {\n return withTracing(originalProperty.bind(wrappedSdk), config);\n }\n\n const isNestedOpenAIObject =\n originalProperty &&\n !Array.isArray(originalProperty) &&\n !(originalProperty instanceof Date) &&\n typeof originalProperty === \"object\";\n\n // Recursively wrap nested objects to ensure all nested properties or methods are also traced\n if (isNestedOpenAIObject) {\n return observeOpenAI(originalProperty, config);\n }\n\n // Fallback to returning the original value\n return Reflect.get(wrappedSdk, propKey, proxy);\n },\n });\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/traceMethod.ts","../src/parseOpenAI.ts","../src/utils.ts","../src/observeOpenAI.ts"],"sourcesContent":["export { observeOpenAI } from \"./observeOpenAI.js\";\nexport * from \"./types.js\";\n","import { ElasticDashGeneration, startObservation } from \"@elasticdash/tracing\";\nimport type OpenAI from \"openai\";\n\nimport {\n getToolCallOutput,\n parseChunk,\n parseCompletionOutput,\n parseInputArgs,\n parseUsageDetails,\n parseModelDataFromResponse,\n parseUsageDetailsFromResponse,\n} from \"./parseOpenAI.js\";\nimport type { ElasticDashConfig } from \"./types.js\";\nimport { isAsyncIterable } from \"./utils.js\";\n\n/**\n * Generic method type for any function that can be traced.\n * @internal\n */\ntype GenericMethod = (...args: unknown[]) => unknown;\n\n/**\n * Wraps a method with ElasticDash tracing functionality.\n *\n * This function creates a wrapper around OpenAI SDK methods that automatically\n * creates ElasticDash generations, captures input/output data, handles streaming\n * responses, and records usage metrics and errors.\n *\n * @param tracedMethod - The OpenAI SDK method to wrap with tracing\n * @param config - Configuration for the trace and generation\n * @returns A wrapped version of the method that creates ElasticDash traces\n *\n * @internal\n */\nexport const withTracing = <T extends GenericMethod>(\n tracedMethod: T,\n config?: ElasticDashConfig & Required<{ generationName: string }>,\n): ((...args: Parameters<T>) => Promise<ReturnType<T>>) => {\n return (...args) => wrapMethod(tracedMethod, config, ...args);\n};\n\n/**\n * Internal method that handles the actual tracing logic for OpenAI SDK methods.\n *\n * This function creates a ElasticDash generation, executes the original method,\n * and captures all relevant data including input, output, usage, and errors.\n * It handles both streaming and non-streaming responses appropriately.\n *\n * @param tracedMethod - The original OpenAI SDK method to execute\n * @param config - ElasticDash configuration options\n * @param args - Arguments to pass to the original method\n * @returns The result from the original method, potentially wrapped for streaming\n *\n * @internal\n */\nconst wrapMethod = <T extends GenericMethod>(\n tracedMethod: T,\n config?: ElasticDashConfig,\n ...args: Parameters<T>\n): ReturnType<T> | any => {\n const { model, input, modelParameters } = parseInputArgs(args[0] ?? {});\n\n const finalModelParams = { ...modelParameters, response_format: \"\" };\n const finalMetadata = {\n ...config?.generationMetadata,\n response_format:\n \"response_format\" in modelParameters\n ? modelParameters.response_format\n : undefined,\n };\n\n const generation = startObservation(\n config?.generationName ?? \"OpenAI-completion\",\n {\n model,\n input,\n modelParameters: finalModelParams,\n prompt: config?.elasticDashPrompt,\n metadata: finalMetadata,\n },\n {\n asType: \"generation\",\n parentSpanContext: config?.parentSpanContext,\n },\n ).updateTrace({\n userId: config?.userId,\n sessionId: config?.sessionId,\n tags: config?.tags,\n name: config?.traceName,\n });\n\n try {\n const res = tracedMethod(...args);\n\n // Handle stream responses\n if (isAsyncIterable(res)) {\n return wrapAsyncIterable(res, generation);\n }\n\n if (res instanceof Promise) {\n const wrappedPromise = res\n .then((result) => {\n if (isAsyncIterable(result)) {\n return wrapAsyncIterable(result, generation);\n }\n\n const output = parseCompletionOutput(result);\n const usageDetails = parseUsageDetailsFromResponse(result);\n const {\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n } = parseModelDataFromResponse(result);\n\n generation\n .update({\n output,\n usageDetails,\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n })\n .end();\n\n return result;\n })\n .catch((err) => {\n generation\n .update({\n statusMessage: String(err),\n level: \"ERROR\",\n costDetails: {\n input: 0,\n output: 0,\n total: 0,\n },\n })\n .end();\n\n throw err;\n });\n\n return wrappedPromise;\n }\n\n return res;\n } catch (error) {\n generation\n .update({\n statusMessage: String(error),\n level: \"ERROR\",\n costDetails: {\n input: 0,\n output: 0,\n total: 0,\n },\n })\n .end();\n\n throw error;\n }\n};\n\n/**\n * Wraps an async iterable (streaming response) with ElasticDash tracing.\n *\n * This function handles streaming OpenAI responses by collecting chunks,\n * parsing usage information, and updating the ElasticDash generation with\n * the complete output and usage details once the stream is consumed.\n *\n * @param iterable - The async iterable from OpenAI (streaming response)\n * @param generation - The ElasticDash generation to update with stream data\n * @returns An async generator that yields original chunks while collecting data\n *\n * @internal\n */\nfunction wrapAsyncIterable<R>(\n iterable: AsyncIterable<unknown>,\n generation: ElasticDashGeneration,\n): R {\n async function* tracedOutputGenerator(): AsyncGenerator<\n unknown,\n void,\n unknown\n > {\n const response = iterable;\n const textChunks: string[] = [];\n const toolCallChunks: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall[] =\n [];\n let usage: OpenAI.CompletionUsage | null = null;\n let completionStartTime: Date | undefined = undefined;\n let usageDetails: Record<string, number> | undefined = undefined;\n let output: unknown = null;\n\n for await (const rawChunk of response as AsyncIterable<unknown>) {\n completionStartTime = completionStartTime ?? new Date();\n\n // Handle Response API chunks\n if (typeof rawChunk === \"object\" && rawChunk && \"response\" in rawChunk) {\n const result = rawChunk[\"response\"];\n output = parseCompletionOutput(result);\n usageDetails = parseUsageDetailsFromResponse(result);\n\n const {\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n } = parseModelDataFromResponse(result);\n\n generation.update({\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n });\n }\n\n if (\n typeof rawChunk === \"object\" &&\n rawChunk != null &&\n \"usage\" in rawChunk\n ) {\n usage = rawChunk.usage as OpenAI.CompletionUsage | null;\n }\n\n const processedChunk = parseChunk(rawChunk);\n\n if (!processedChunk.isToolCall) {\n textChunks.push(processedChunk.data);\n } else {\n toolCallChunks.push(processedChunk.data);\n }\n\n yield rawChunk;\n }\n\n output =\n output ??\n (toolCallChunks.length > 0\n ? getToolCallOutput(toolCallChunks)\n : textChunks.join(\"\"));\n\n generation\n .update({\n output,\n completionStartTime,\n usageDetails:\n usageDetails ?? (usage ? parseUsageDetails(usage) : undefined),\n })\n .end();\n }\n\n return tracedOutputGenerator() as R;\n}\n","import type OpenAI from \"openai\";\n\ntype ParsedOpenAIArguments = {\n model: string;\n input: Record<string, any> | string;\n modelParameters: Record<string, any>;\n};\n\nexport const parseInputArgs = (\n args: Record<string, any>,\n): ParsedOpenAIArguments => {\n let params: Record<string, any> = {};\n params = {\n frequency_penalty: args.frequency_penalty,\n logit_bias: args.logit_bias,\n logprobs: args.logprobs,\n max_tokens: args.max_tokens,\n n: args.n,\n presence_penalty: args.presence_penalty,\n seed: args.seed,\n stop: args.stop,\n stream: args.stream,\n temperature: args.temperature,\n top_p: args.top_p,\n user: args.user,\n response_format: args.response_format,\n top_logprobs: args.top_logprobs,\n };\n\n let input: Record<string, any> | string = args.input;\n\n if (\n args &&\n typeof args === \"object\" &&\n !Array.isArray(args) &&\n \"messages\" in args\n ) {\n input = {};\n input.messages = args.messages;\n if (\"function_call\" in args) {\n input.function_call = args.function_call;\n }\n if (\"functions\" in args) {\n input.functions = args.functions;\n }\n if (\"tools\" in args) {\n input.tools = args.tools;\n }\n\n if (\"tool_choice\" in args) {\n input.tool_choice = args.tool_choice;\n }\n } else if (!input) {\n input = args.prompt;\n }\n\n return {\n model: args.model,\n input: input,\n modelParameters: params,\n };\n};\n\nexport const parseCompletionOutput = (res: unknown): unknown => {\n if (\n res instanceof Object &&\n \"output_text\" in res &&\n res[\"output_text\"] !== \"\"\n ) {\n return res[\"output_text\"] as string;\n }\n\n if (\n typeof res === \"object\" &&\n res &&\n \"output\" in res &&\n Array.isArray(res[\"output\"])\n ) {\n const output = res[\"output\"];\n\n if (output.length > 1) {\n return output;\n }\n if (output.length === 1) {\n return output[0] as Record<string, unknown>;\n }\n\n return null;\n }\n\n if (\n !(res instanceof Object && \"choices\" in res && Array.isArray(res.choices))\n ) {\n return \"\";\n }\n\n return \"message\" in res.choices[0]\n ? res.choices[0].message\n : (res.choices[0].text ?? \"\");\n};\n\nexport const parseUsageDetails = (\n completionUsage: OpenAI.CompletionUsage,\n): Record<string, number> | undefined => {\n if (\"prompt_tokens\" in completionUsage) {\n const {\n prompt_tokens,\n completion_tokens,\n total_tokens,\n completion_tokens_details,\n prompt_tokens_details,\n } = completionUsage;\n\n const flatPromptTokensDetails = Object.fromEntries(\n Object.entries(prompt_tokens_details ?? {}).map(([key, value]) => [\n `input_${key}`,\n value as number,\n ]),\n );\n\n const flatCompletionTokensDetails = Object.fromEntries(\n Object.entries(completion_tokens_details ?? {}).map(([key, value]) => [\n `output_${key}`,\n value as number,\n ]),\n );\n\n let finalInputTokens = prompt_tokens as number;\n Object.values(flatPromptTokensDetails).forEach((value) => {\n finalInputTokens = Math.max(finalInputTokens - value, 0);\n });\n\n let finalOutputTokens = completion_tokens as number;\n Object.values(flatCompletionTokensDetails).forEach((value) => {\n finalOutputTokens = Math.max(finalOutputTokens - value, 0);\n });\n\n return {\n input: finalInputTokens,\n output: finalOutputTokens,\n total: total_tokens,\n ...flatPromptTokensDetails,\n ...flatCompletionTokensDetails,\n };\n } else if (\"input_tokens\" in completionUsage) {\n const {\n input_tokens,\n output_tokens,\n total_tokens,\n input_tokens_details,\n output_tokens_details,\n } = completionUsage;\n\n let finalInputTokens = input_tokens as number;\n Object.keys(input_tokens_details ?? {}).forEach((key) => {\n finalInputTokens = Math.max(\n finalInputTokens -\n input_tokens_details[key as keyof typeof input_tokens_details],\n 0,\n );\n });\n\n let finalOutputTokens = output_tokens as number;\n Object.keys(output_tokens_details ?? {}).forEach((key) => {\n finalOutputTokens = Math.max(\n finalOutputTokens -\n output_tokens_details[key as keyof typeof output_tokens_details],\n 0,\n );\n });\n\n return {\n input: finalInputTokens,\n output: finalOutputTokens,\n total: total_tokens,\n ...Object.fromEntries(\n Object.entries(input_tokens_details ?? {}).map(([key, value]) => [\n `input_${key}`,\n value as number,\n ]),\n ),\n ...Object.fromEntries(\n Object.entries(output_tokens_details ?? {}).map(([key, value]) => [\n `output_${key}`,\n value as number,\n ]),\n ),\n };\n }\n};\n\nexport const parseUsageDetailsFromResponse = (\n res: unknown,\n): Record<string, number> | undefined => {\n if (hasCompletionUsage(res)) {\n return parseUsageDetails(res.usage);\n }\n};\n\nexport const parseChunk = (\n rawChunk: unknown,\n):\n | { isToolCall: false; data: string }\n | {\n isToolCall: true;\n data: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall;\n } => {\n let isToolCall = false;\n const _chunk = rawChunk as\n | OpenAI.ChatCompletionChunk\n | OpenAI.Completions.Completion;\n const chunkData = _chunk?.choices?.[0];\n\n try {\n if (\n \"delta\" in chunkData &&\n \"tool_calls\" in chunkData.delta &&\n Array.isArray(chunkData.delta.tool_calls)\n ) {\n isToolCall = true;\n\n return { isToolCall, data: chunkData.delta.tool_calls[0] };\n }\n if (\"delta\" in chunkData) {\n return { isToolCall, data: chunkData.delta?.content || \"\" };\n }\n\n if (\"text\" in chunkData) {\n return { isToolCall, data: chunkData.text || \"\" };\n }\n } catch {}\n\n return { isToolCall: false, data: \"\" };\n};\n\n// Type guard to check if an unknown object is a UsageResponse\nfunction hasCompletionUsage(\n obj: any,\n): obj is { usage: OpenAI.CompletionUsage } {\n return (\n obj instanceof Object &&\n \"usage\" in obj &&\n obj.usage instanceof Object &&\n // Completion API Usage format\n ((typeof obj.usage.prompt_tokens === \"number\" &&\n typeof obj.usage.completion_tokens === \"number\" &&\n typeof obj.usage.total_tokens === \"number\") ||\n // Response API Usage format\n (typeof obj.usage.input_tokens === \"number\" &&\n typeof obj.usage.output_tokens === \"number\" &&\n typeof obj.usage.total_tokens === \"number\"))\n );\n}\n\nexport const getToolCallOutput = (\n toolCallChunks: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall[],\n): {\n tool_calls: {\n function: {\n name: string;\n arguments: string;\n };\n }[];\n} => {\n let name = \"\";\n let toolArguments = \"\";\n\n for (const toolCall of toolCallChunks) {\n name = toolCall.function?.name || name;\n toolArguments += toolCall.function?.arguments || \"\";\n }\n\n return {\n tool_calls: [\n {\n function: {\n name,\n arguments: toolArguments,\n },\n },\n ],\n };\n};\n\nexport const parseModelDataFromResponse = (\n res: unknown,\n): {\n model: string | undefined;\n modelParameters: Record<string, string | number> | undefined;\n metadata: Record<string, unknown> | undefined;\n} => {\n if (typeof res !== \"object\" || res === null) {\n return {\n model: undefined,\n modelParameters: undefined,\n metadata: undefined,\n };\n }\n\n const model = \"model\" in res ? (res[\"model\"] as string) : undefined;\n const modelParameters: Record<string, string | number> = {};\n const modelParamKeys = [\n \"max_output_tokens\",\n \"parallel_tool_calls\",\n \"store\",\n \"temperature\",\n \"tool_choice\",\n \"top_p\",\n \"truncation\",\n \"user\",\n ];\n\n const metadata: Record<string, unknown> = {};\n const metadataKeys = [\n \"reasoning\",\n \"incomplete_details\",\n \"instructions\",\n \"previous_response_id\",\n \"tools\",\n \"metadata\",\n \"status\",\n \"error\",\n ];\n\n for (const key of modelParamKeys) {\n const val =\n key in res ? (res[key as keyof typeof res] as string | number) : null;\n if (val !== null && val !== undefined) {\n modelParameters[key as keyof typeof modelParameters] = val;\n }\n }\n\n for (const key of metadataKeys) {\n const val =\n key in res ? (res[key as keyof typeof res] as string | number) : null;\n if (val) {\n metadata[key as keyof typeof metadata] = val;\n }\n }\n\n return {\n model,\n modelParameters:\n Object.keys(modelParameters).length > 0 ? modelParameters : undefined,\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n };\n};\n","/**\n * Type guard to check if a value is an async iterable.\n *\n * This utility function determines whether a given value implements the\n * AsyncIterable interface, which is used to identify streaming responses\n * from the OpenAI SDK.\n *\n * @param x - The value to check\n * @returns True if the value is an async iterable, false otherwise\n *\n * @example\n * ```typescript\n * import { isAsyncIterable } from './utils.js';\n *\n * const response = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [...],\n * stream: true\n * });\n *\n * if (isAsyncIterable(response)) {\n * // Handle streaming response\n * for await (const chunk of response) {\n * console.log(chunk);\n * }\n * } else {\n * // Handle regular response\n * console.log(response);\n * }\n * ```\n *\n * @public\n */\nexport const isAsyncIterable = (x: unknown): x is AsyncIterable<unknown> =>\n x != null &&\n typeof x === \"object\" &&\n typeof (x as any)[Symbol.asyncIterator] === \"function\";\n","import { withTracing } from \"./traceMethod.js\";\nimport type { ElasticDashConfig } from \"./types.js\";\n\n/**\n * Wraps an OpenAI SDK client with automatic ElasticDash tracing.\n *\n * This function creates a proxy around the OpenAI SDK that automatically\n * traces all method calls, capturing detailed information about requests,\n * responses, token usage, costs, and performance metrics. It works with\n * both streaming and non-streaming OpenAI API calls.\n *\n * The wrapper recursively traces nested objects in the OpenAI SDK, ensuring\n * that all API calls (chat completions, embeddings, fine-tuning, etc.) are\n * automatically captured as ElasticDash generations.\n *\n * @param sdk - The OpenAI SDK client instance to wrap with tracing\n * @param elasticDashConfig - Optional configuration for tracing behavior\n * @returns A proxied version of the OpenAI SDK with automatic tracing\n *\n * @example\n * ```typescript\n * import OpenAI from 'openai';\n * import { observeOpenAI } from '@elasticdash/openai';\n *\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY,\n * }));\n *\n * // All OpenAI calls are now automatically traced\n * const response = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Hello!' }],\n * max_tokens: 100,\n * temperature: 0.7\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With custom tracing configuration\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY\n * }), {\n * traceName: 'AI-Assistant-Chat',\n * userId: 'user-123',\n * sessionId: 'session-456',\n * tags: ['production', 'chat-feature'],\n * generationName: 'gpt-4-chat-completion'\n * });\n *\n * const completion = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Explain quantum computing' }]\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Streaming responses are also automatically traced\n * const stream = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Write a story' }],\n * stream: true\n * });\n *\n * for await (const chunk of stream) {\n * process.stdout.write(chunk.choices[0]?.delta?.content || '');\n * }\n * // Final usage details and complete output are captured automatically\n * ```\n *\n * @example\n * ```typescript\n * // Using with ElasticDash prompt management\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY\n * }), {\n * elasticDashPrompt: {\n * name: 'chat-assistant-v2',\n * version: 3,\n * isFallback: false\n * },\n * generationMetadata: {\n * environment: 'production',\n * feature: 'chat-assistant'\n * }\n * });\n * ```\n *\n * @public\n */\nexport const observeOpenAI = <SDKType extends object>(\n sdk: SDKType,\n elasticDashConfig?: ElasticDashConfig,\n): SDKType => {\n return new Proxy(sdk, {\n get(wrappedSdk, propKey, proxy) {\n const originalProperty = wrappedSdk[propKey as keyof SDKType];\n\n const defaultGenerationName = `${sdk.constructor?.name}.${propKey.toString()}`;\n const generationName =\n elasticDashConfig?.generationName ?? defaultGenerationName;\n const config = { ...elasticDashConfig, generationName };\n\n // Trace methods of the OpenAI SDK\n if (typeof originalProperty === \"function\") {\n return withTracing(originalProperty.bind(wrappedSdk), config);\n }\n\n const isNestedOpenAIObject =\n originalProperty &&\n !Array.isArray(originalProperty) &&\n !(originalProperty instanceof Date) &&\n typeof originalProperty === \"object\";\n\n // Recursively wrap nested objects to ensure all nested properties or methods are also traced\n if (isNestedOpenAIObject) {\n return observeOpenAI(originalProperty, config);\n }\n\n // Fallback to returning the original value\n return Reflect.get(wrappedSdk, propKey, proxy);\n },\n });\n};\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -25,7 +25,7 @@ type ElasticDashConfig = {
25
25
  /** Additional metadata to attach to the generation */
26
26
  generationMetadata?: Record<string, unknown>;
27
27
  /** Information about the ElasticDash prompt used for this generation */
28
- langfusePrompt?: {
28
+ elasticDashPrompt?: {
29
29
  /** Name of the prompt template in ElasticDash */
30
30
  name: string;
31
31
  /** Version number of the prompt template */
@@ -110,7 +110,7 @@ type ElasticDashConfig = {
110
110
  * const openai = observeOpenAI(new OpenAI({
111
111
  * apiKey: process.env.OPENAI_API_KEY
112
112
  * }), {
113
- * langfusePrompt: {
113
+ * elasticDashPrompt: {
114
114
  * name: 'chat-assistant-v2',
115
115
  * version: 3,
116
116
  * isFallback: false
package/dist/index.d.ts CHANGED
@@ -25,7 +25,7 @@ type ElasticDashConfig = {
25
25
  /** Additional metadata to attach to the generation */
26
26
  generationMetadata?: Record<string, unknown>;
27
27
  /** Information about the ElasticDash prompt used for this generation */
28
- langfusePrompt?: {
28
+ elasticDashPrompt?: {
29
29
  /** Name of the prompt template in ElasticDash */
30
30
  name: string;
31
31
  /** Version number of the prompt template */
@@ -110,7 +110,7 @@ type ElasticDashConfig = {
110
110
  * const openai = observeOpenAI(new OpenAI({
111
111
  * apiKey: process.env.OPENAI_API_KEY
112
112
  * }), {
113
- * langfusePrompt: {
113
+ * elasticDashPrompt: {
114
114
  * name: 'chat-assistant-v2',
115
115
  * version: 3,
116
116
  * isFallback: false
package/dist/index.mjs CHANGED
@@ -262,7 +262,7 @@ var wrapMethod = (tracedMethod, config, ...args) => {
262
262
  model,
263
263
  input,
264
264
  modelParameters: finalModelParams,
265
- prompt: config == null ? void 0 : config.langfusePrompt,
265
+ prompt: config == null ? void 0 : config.elasticDashPrompt,
266
266
  metadata: finalMetadata
267
267
  },
268
268
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/traceMethod.ts","../src/parseOpenAI.ts","../src/utils.ts","../src/observeOpenAI.ts"],"sourcesContent":["import { LangfuseGeneration, startObservation } from \"@elasticdash/tracing\";\nimport type OpenAI from \"openai\";\n\nimport {\n getToolCallOutput,\n parseChunk,\n parseCompletionOutput,\n parseInputArgs,\n parseUsageDetails,\n parseModelDataFromResponse,\n parseUsageDetailsFromResponse,\n} from \"./parseOpenAI.js\";\nimport type { ElasticDashConfig } from \"./types.js\";\nimport { isAsyncIterable } from \"./utils.js\";\n\n/**\n * Generic method type for any function that can be traced.\n * @internal\n */\ntype GenericMethod = (...args: unknown[]) => unknown;\n\n/**\n * Wraps a method with ElasticDash tracing functionality.\n *\n * This function creates a wrapper around OpenAI SDK methods that automatically\n * creates ElasticDash generations, captures input/output data, handles streaming\n * responses, and records usage metrics and errors.\n *\n * @param tracedMethod - The OpenAI SDK method to wrap with tracing\n * @param config - Configuration for the trace and generation\n * @returns A wrapped version of the method that creates ElasticDash traces\n *\n * @internal\n */\nexport const withTracing = <T extends GenericMethod>(\n tracedMethod: T,\n config?: ElasticDashConfig & Required<{ generationName: string }>,\n): ((...args: Parameters<T>) => Promise<ReturnType<T>>) => {\n return (...args) => wrapMethod(tracedMethod, config, ...args);\n};\n\n/**\n * Internal method that handles the actual tracing logic for OpenAI SDK methods.\n *\n * This function creates a ElasticDash generation, executes the original method,\n * and captures all relevant data including input, output, usage, and errors.\n * It handles both streaming and non-streaming responses appropriately.\n *\n * @param tracedMethod - The original OpenAI SDK method to execute\n * @param config - ElasticDash configuration options\n * @param args - Arguments to pass to the original method\n * @returns The result from the original method, potentially wrapped for streaming\n *\n * @internal\n */\nconst wrapMethod = <T extends GenericMethod>(\n tracedMethod: T,\n config?: ElasticDashConfig,\n ...args: Parameters<T>\n): ReturnType<T> | any => {\n const { model, input, modelParameters } = parseInputArgs(args[0] ?? {});\n\n const finalModelParams = { ...modelParameters, response_format: \"\" };\n const finalMetadata = {\n ...config?.generationMetadata,\n response_format:\n \"response_format\" in modelParameters\n ? modelParameters.response_format\n : undefined,\n };\n\n const generation = startObservation(\n config?.generationName ?? \"OpenAI-completion\",\n {\n model,\n input,\n modelParameters: finalModelParams,\n prompt: config?.langfusePrompt,\n metadata: finalMetadata,\n },\n {\n asType: \"generation\",\n parentSpanContext: config?.parentSpanContext,\n },\n ).updateTrace({\n userId: config?.userId,\n sessionId: config?.sessionId,\n tags: config?.tags,\n name: config?.traceName,\n });\n\n try {\n const res = tracedMethod(...args);\n\n // Handle stream responses\n if (isAsyncIterable(res)) {\n return wrapAsyncIterable(res, generation);\n }\n\n if (res instanceof Promise) {\n const wrappedPromise = res\n .then((result) => {\n if (isAsyncIterable(result)) {\n return wrapAsyncIterable(result, generation);\n }\n\n const output = parseCompletionOutput(result);\n const usageDetails = parseUsageDetailsFromResponse(result);\n const {\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n } = parseModelDataFromResponse(result);\n\n generation\n .update({\n output,\n usageDetails,\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n })\n .end();\n\n return result;\n })\n .catch((err) => {\n generation\n .update({\n statusMessage: String(err),\n level: \"ERROR\",\n costDetails: {\n input: 0,\n output: 0,\n total: 0,\n },\n })\n .end();\n\n throw err;\n });\n\n return wrappedPromise;\n }\n\n return res;\n } catch (error) {\n generation\n .update({\n statusMessage: String(error),\n level: \"ERROR\",\n costDetails: {\n input: 0,\n output: 0,\n total: 0,\n },\n })\n .end();\n\n throw error;\n }\n};\n\n/**\n * Wraps an async iterable (streaming response) with ElasticDash tracing.\n *\n * This function handles streaming OpenAI responses by collecting chunks,\n * parsing usage information, and updating the ElasticDash generation with\n * the complete output and usage details once the stream is consumed.\n *\n * @param iterable - The async iterable from OpenAI (streaming response)\n * @param generation - The ElasticDash generation to update with stream data\n * @returns An async generator that yields original chunks while collecting data\n *\n * @internal\n */\nfunction wrapAsyncIterable<R>(\n iterable: AsyncIterable<unknown>,\n generation: LangfuseGeneration,\n): R {\n async function* tracedOutputGenerator(): AsyncGenerator<\n unknown,\n void,\n unknown\n > {\n const response = iterable;\n const textChunks: string[] = [];\n const toolCallChunks: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall[] =\n [];\n let usage: OpenAI.CompletionUsage | null = null;\n let completionStartTime: Date | undefined = undefined;\n let usageDetails: Record<string, number> | undefined = undefined;\n let output: unknown = null;\n\n for await (const rawChunk of response as AsyncIterable<unknown>) {\n completionStartTime = completionStartTime ?? new Date();\n\n // Handle Response API chunks\n if (typeof rawChunk === \"object\" && rawChunk && \"response\" in rawChunk) {\n const result = rawChunk[\"response\"];\n output = parseCompletionOutput(result);\n usageDetails = parseUsageDetailsFromResponse(result);\n\n const {\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n } = parseModelDataFromResponse(result);\n\n generation.update({\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n });\n }\n\n if (\n typeof rawChunk === \"object\" &&\n rawChunk != null &&\n \"usage\" in rawChunk\n ) {\n usage = rawChunk.usage as OpenAI.CompletionUsage | null;\n }\n\n const processedChunk = parseChunk(rawChunk);\n\n if (!processedChunk.isToolCall) {\n textChunks.push(processedChunk.data);\n } else {\n toolCallChunks.push(processedChunk.data);\n }\n\n yield rawChunk;\n }\n\n output =\n output ??\n (toolCallChunks.length > 0\n ? getToolCallOutput(toolCallChunks)\n : textChunks.join(\"\"));\n\n generation\n .update({\n output,\n completionStartTime,\n usageDetails:\n usageDetails ?? (usage ? parseUsageDetails(usage) : undefined),\n })\n .end();\n }\n\n return tracedOutputGenerator() as R;\n}\n","import type OpenAI from \"openai\";\n\ntype ParsedOpenAIArguments = {\n model: string;\n input: Record<string, any> | string;\n modelParameters: Record<string, any>;\n};\n\nexport const parseInputArgs = (\n args: Record<string, any>,\n): ParsedOpenAIArguments => {\n let params: Record<string, any> = {};\n params = {\n frequency_penalty: args.frequency_penalty,\n logit_bias: args.logit_bias,\n logprobs: args.logprobs,\n max_tokens: args.max_tokens,\n n: args.n,\n presence_penalty: args.presence_penalty,\n seed: args.seed,\n stop: args.stop,\n stream: args.stream,\n temperature: args.temperature,\n top_p: args.top_p,\n user: args.user,\n response_format: args.response_format,\n top_logprobs: args.top_logprobs,\n };\n\n let input: Record<string, any> | string = args.input;\n\n if (\n args &&\n typeof args === \"object\" &&\n !Array.isArray(args) &&\n \"messages\" in args\n ) {\n input = {};\n input.messages = args.messages;\n if (\"function_call\" in args) {\n input.function_call = args.function_call;\n }\n if (\"functions\" in args) {\n input.functions = args.functions;\n }\n if (\"tools\" in args) {\n input.tools = args.tools;\n }\n\n if (\"tool_choice\" in args) {\n input.tool_choice = args.tool_choice;\n }\n } else if (!input) {\n input = args.prompt;\n }\n\n return {\n model: args.model,\n input: input,\n modelParameters: params,\n };\n};\n\nexport const parseCompletionOutput = (res: unknown): unknown => {\n if (\n res instanceof Object &&\n \"output_text\" in res &&\n res[\"output_text\"] !== \"\"\n ) {\n return res[\"output_text\"] as string;\n }\n\n if (\n typeof res === \"object\" &&\n res &&\n \"output\" in res &&\n Array.isArray(res[\"output\"])\n ) {\n const output = res[\"output\"];\n\n if (output.length > 1) {\n return output;\n }\n if (output.length === 1) {\n return output[0] as Record<string, unknown>;\n }\n\n return null;\n }\n\n if (\n !(res instanceof Object && \"choices\" in res && Array.isArray(res.choices))\n ) {\n return \"\";\n }\n\n return \"message\" in res.choices[0]\n ? res.choices[0].message\n : (res.choices[0].text ?? \"\");\n};\n\nexport const parseUsageDetails = (\n completionUsage: OpenAI.CompletionUsage,\n): Record<string, number> | undefined => {\n if (\"prompt_tokens\" in completionUsage) {\n const {\n prompt_tokens,\n completion_tokens,\n total_tokens,\n completion_tokens_details,\n prompt_tokens_details,\n } = completionUsage;\n\n const flatPromptTokensDetails = Object.fromEntries(\n Object.entries(prompt_tokens_details ?? {}).map(([key, value]) => [\n `input_${key}`,\n value as number,\n ]),\n );\n\n const flatCompletionTokensDetails = Object.fromEntries(\n Object.entries(completion_tokens_details ?? {}).map(([key, value]) => [\n `output_${key}`,\n value as number,\n ]),\n );\n\n let finalInputTokens = prompt_tokens as number;\n Object.values(flatPromptTokensDetails).forEach((value) => {\n finalInputTokens = Math.max(finalInputTokens - value, 0);\n });\n\n let finalOutputTokens = completion_tokens as number;\n Object.values(flatCompletionTokensDetails).forEach((value) => {\n finalOutputTokens = Math.max(finalOutputTokens - value, 0);\n });\n\n return {\n input: finalInputTokens,\n output: finalOutputTokens,\n total: total_tokens,\n ...flatPromptTokensDetails,\n ...flatCompletionTokensDetails,\n };\n } else if (\"input_tokens\" in completionUsage) {\n const {\n input_tokens,\n output_tokens,\n total_tokens,\n input_tokens_details,\n output_tokens_details,\n } = completionUsage;\n\n let finalInputTokens = input_tokens as number;\n Object.keys(input_tokens_details ?? {}).forEach((key) => {\n finalInputTokens = Math.max(\n finalInputTokens -\n input_tokens_details[key as keyof typeof input_tokens_details],\n 0,\n );\n });\n\n let finalOutputTokens = output_tokens as number;\n Object.keys(output_tokens_details ?? {}).forEach((key) => {\n finalOutputTokens = Math.max(\n finalOutputTokens -\n output_tokens_details[key as keyof typeof output_tokens_details],\n 0,\n );\n });\n\n return {\n input: finalInputTokens,\n output: finalOutputTokens,\n total: total_tokens,\n ...Object.fromEntries(\n Object.entries(input_tokens_details ?? {}).map(([key, value]) => [\n `input_${key}`,\n value as number,\n ]),\n ),\n ...Object.fromEntries(\n Object.entries(output_tokens_details ?? {}).map(([key, value]) => [\n `output_${key}`,\n value as number,\n ]),\n ),\n };\n }\n};\n\nexport const parseUsageDetailsFromResponse = (\n res: unknown,\n): Record<string, number> | undefined => {\n if (hasCompletionUsage(res)) {\n return parseUsageDetails(res.usage);\n }\n};\n\nexport const parseChunk = (\n rawChunk: unknown,\n):\n | { isToolCall: false; data: string }\n | {\n isToolCall: true;\n data: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall;\n } => {\n let isToolCall = false;\n const _chunk = rawChunk as\n | OpenAI.ChatCompletionChunk\n | OpenAI.Completions.Completion;\n const chunkData = _chunk?.choices?.[0];\n\n try {\n if (\n \"delta\" in chunkData &&\n \"tool_calls\" in chunkData.delta &&\n Array.isArray(chunkData.delta.tool_calls)\n ) {\n isToolCall = true;\n\n return { isToolCall, data: chunkData.delta.tool_calls[0] };\n }\n if (\"delta\" in chunkData) {\n return { isToolCall, data: chunkData.delta?.content || \"\" };\n }\n\n if (\"text\" in chunkData) {\n return { isToolCall, data: chunkData.text || \"\" };\n }\n } catch {}\n\n return { isToolCall: false, data: \"\" };\n};\n\n// Type guard to check if an unknown object is a UsageResponse\nfunction hasCompletionUsage(\n obj: any,\n): obj is { usage: OpenAI.CompletionUsage } {\n return (\n obj instanceof Object &&\n \"usage\" in obj &&\n obj.usage instanceof Object &&\n // Completion API Usage format\n ((typeof obj.usage.prompt_tokens === \"number\" &&\n typeof obj.usage.completion_tokens === \"number\" &&\n typeof obj.usage.total_tokens === \"number\") ||\n // Response API Usage format\n (typeof obj.usage.input_tokens === \"number\" &&\n typeof obj.usage.output_tokens === \"number\" &&\n typeof obj.usage.total_tokens === \"number\"))\n );\n}\n\nexport const getToolCallOutput = (\n toolCallChunks: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall[],\n): {\n tool_calls: {\n function: {\n name: string;\n arguments: string;\n };\n }[];\n} => {\n let name = \"\";\n let toolArguments = \"\";\n\n for (const toolCall of toolCallChunks) {\n name = toolCall.function?.name || name;\n toolArguments += toolCall.function?.arguments || \"\";\n }\n\n return {\n tool_calls: [\n {\n function: {\n name,\n arguments: toolArguments,\n },\n },\n ],\n };\n};\n\nexport const parseModelDataFromResponse = (\n res: unknown,\n): {\n model: string | undefined;\n modelParameters: Record<string, string | number> | undefined;\n metadata: Record<string, unknown> | undefined;\n} => {\n if (typeof res !== \"object\" || res === null) {\n return {\n model: undefined,\n modelParameters: undefined,\n metadata: undefined,\n };\n }\n\n const model = \"model\" in res ? (res[\"model\"] as string) : undefined;\n const modelParameters: Record<string, string | number> = {};\n const modelParamKeys = [\n \"max_output_tokens\",\n \"parallel_tool_calls\",\n \"store\",\n \"temperature\",\n \"tool_choice\",\n \"top_p\",\n \"truncation\",\n \"user\",\n ];\n\n const metadata: Record<string, unknown> = {};\n const metadataKeys = [\n \"reasoning\",\n \"incomplete_details\",\n \"instructions\",\n \"previous_response_id\",\n \"tools\",\n \"metadata\",\n \"status\",\n \"error\",\n ];\n\n for (const key of modelParamKeys) {\n const val =\n key in res ? (res[key as keyof typeof res] as string | number) : null;\n if (val !== null && val !== undefined) {\n modelParameters[key as keyof typeof modelParameters] = val;\n }\n }\n\n for (const key of metadataKeys) {\n const val =\n key in res ? (res[key as keyof typeof res] as string | number) : null;\n if (val) {\n metadata[key as keyof typeof metadata] = val;\n }\n }\n\n return {\n model,\n modelParameters:\n Object.keys(modelParameters).length > 0 ? modelParameters : undefined,\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n };\n};\n","/**\n * Type guard to check if a value is an async iterable.\n *\n * This utility function determines whether a given value implements the\n * AsyncIterable interface, which is used to identify streaming responses\n * from the OpenAI SDK.\n *\n * @param x - The value to check\n * @returns True if the value is an async iterable, false otherwise\n *\n * @example\n * ```typescript\n * import { isAsyncIterable } from './utils.js';\n *\n * const response = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [...],\n * stream: true\n * });\n *\n * if (isAsyncIterable(response)) {\n * // Handle streaming response\n * for await (const chunk of response) {\n * console.log(chunk);\n * }\n * } else {\n * // Handle regular response\n * console.log(response);\n * }\n * ```\n *\n * @public\n */\nexport const isAsyncIterable = (x: unknown): x is AsyncIterable<unknown> =>\n x != null &&\n typeof x === \"object\" &&\n typeof (x as any)[Symbol.asyncIterator] === \"function\";\n","import { withTracing } from \"./traceMethod.js\";\nimport type { ElasticDashConfig } from \"./types.js\";\n\n/**\n * Wraps an OpenAI SDK client with automatic ElasticDash tracing.\n *\n * This function creates a proxy around the OpenAI SDK that automatically\n * traces all method calls, capturing detailed information about requests,\n * responses, token usage, costs, and performance metrics. It works with\n * both streaming and non-streaming OpenAI API calls.\n *\n * The wrapper recursively traces nested objects in the OpenAI SDK, ensuring\n * that all API calls (chat completions, embeddings, fine-tuning, etc.) are\n * automatically captured as ElasticDash generations.\n *\n * @param sdk - The OpenAI SDK client instance to wrap with tracing\n * @param elasticDashConfig - Optional configuration for tracing behavior\n * @returns A proxied version of the OpenAI SDK with automatic tracing\n *\n * @example\n * ```typescript\n * import OpenAI from 'openai';\n * import { observeOpenAI } from '@elasticdash/openai';\n *\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY,\n * }));\n *\n * // All OpenAI calls are now automatically traced\n * const response = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Hello!' }],\n * max_tokens: 100,\n * temperature: 0.7\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With custom tracing configuration\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY\n * }), {\n * traceName: 'AI-Assistant-Chat',\n * userId: 'user-123',\n * sessionId: 'session-456',\n * tags: ['production', 'chat-feature'],\n * generationName: 'gpt-4-chat-completion'\n * });\n *\n * const completion = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Explain quantum computing' }]\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Streaming responses are also automatically traced\n * const stream = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Write a story' }],\n * stream: true\n * });\n *\n * for await (const chunk of stream) {\n * process.stdout.write(chunk.choices[0]?.delta?.content || '');\n * }\n * // Final usage details and complete output are captured automatically\n * ```\n *\n * @example\n * ```typescript\n * // Using with ElasticDash prompt management\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY\n * }), {\n * langfusePrompt: {\n * name: 'chat-assistant-v2',\n * version: 3,\n * isFallback: false\n * },\n * generationMetadata: {\n * environment: 'production',\n * feature: 'chat-assistant'\n * }\n * });\n * ```\n *\n * @public\n */\nexport const observeOpenAI = <SDKType extends object>(\n sdk: SDKType,\n elasticDashConfig?: ElasticDashConfig,\n): SDKType => {\n return new Proxy(sdk, {\n get(wrappedSdk, propKey, proxy) {\n const originalProperty = wrappedSdk[propKey as keyof SDKType];\n\n const defaultGenerationName = `${sdk.constructor?.name}.${propKey.toString()}`;\n const generationName =\n elasticDashConfig?.generationName ?? defaultGenerationName;\n const config = { ...elasticDashConfig, generationName };\n\n // Trace methods of the OpenAI SDK\n if (typeof originalProperty === \"function\") {\n return withTracing(originalProperty.bind(wrappedSdk), config);\n }\n\n const isNestedOpenAIObject =\n originalProperty &&\n !Array.isArray(originalProperty) &&\n !(originalProperty instanceof Date) &&\n typeof originalProperty === \"object\";\n\n // Recursively wrap nested objects to ensure all nested properties or methods are also traced\n if (isNestedOpenAIObject) {\n return observeOpenAI(originalProperty, config);\n }\n\n // Fallback to returning the original value\n return Reflect.get(wrappedSdk, propKey, proxy);\n },\n });\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/traceMethod.ts","../src/parseOpenAI.ts","../src/utils.ts","../src/observeOpenAI.ts"],"sourcesContent":["import { ElasticDashGeneration, startObservation } from \"@elasticdash/tracing\";\nimport type OpenAI from \"openai\";\n\nimport {\n getToolCallOutput,\n parseChunk,\n parseCompletionOutput,\n parseInputArgs,\n parseUsageDetails,\n parseModelDataFromResponse,\n parseUsageDetailsFromResponse,\n} from \"./parseOpenAI.js\";\nimport type { ElasticDashConfig } from \"./types.js\";\nimport { isAsyncIterable } from \"./utils.js\";\n\n/**\n * Generic method type for any function that can be traced.\n * @internal\n */\ntype GenericMethod = (...args: unknown[]) => unknown;\n\n/**\n * Wraps a method with ElasticDash tracing functionality.\n *\n * This function creates a wrapper around OpenAI SDK methods that automatically\n * creates ElasticDash generations, captures input/output data, handles streaming\n * responses, and records usage metrics and errors.\n *\n * @param tracedMethod - The OpenAI SDK method to wrap with tracing\n * @param config - Configuration for the trace and generation\n * @returns A wrapped version of the method that creates ElasticDash traces\n *\n * @internal\n */\nexport const withTracing = <T extends GenericMethod>(\n tracedMethod: T,\n config?: ElasticDashConfig & Required<{ generationName: string }>,\n): ((...args: Parameters<T>) => Promise<ReturnType<T>>) => {\n return (...args) => wrapMethod(tracedMethod, config, ...args);\n};\n\n/**\n * Internal method that handles the actual tracing logic for OpenAI SDK methods.\n *\n * This function creates a ElasticDash generation, executes the original method,\n * and captures all relevant data including input, output, usage, and errors.\n * It handles both streaming and non-streaming responses appropriately.\n *\n * @param tracedMethod - The original OpenAI SDK method to execute\n * @param config - ElasticDash configuration options\n * @param args - Arguments to pass to the original method\n * @returns The result from the original method, potentially wrapped for streaming\n *\n * @internal\n */\nconst wrapMethod = <T extends GenericMethod>(\n tracedMethod: T,\n config?: ElasticDashConfig,\n ...args: Parameters<T>\n): ReturnType<T> | any => {\n const { model, input, modelParameters } = parseInputArgs(args[0] ?? {});\n\n const finalModelParams = { ...modelParameters, response_format: \"\" };\n const finalMetadata = {\n ...config?.generationMetadata,\n response_format:\n \"response_format\" in modelParameters\n ? modelParameters.response_format\n : undefined,\n };\n\n const generation = startObservation(\n config?.generationName ?? \"OpenAI-completion\",\n {\n model,\n input,\n modelParameters: finalModelParams,\n prompt: config?.elasticDashPrompt,\n metadata: finalMetadata,\n },\n {\n asType: \"generation\",\n parentSpanContext: config?.parentSpanContext,\n },\n ).updateTrace({\n userId: config?.userId,\n sessionId: config?.sessionId,\n tags: config?.tags,\n name: config?.traceName,\n });\n\n try {\n const res = tracedMethod(...args);\n\n // Handle stream responses\n if (isAsyncIterable(res)) {\n return wrapAsyncIterable(res, generation);\n }\n\n if (res instanceof Promise) {\n const wrappedPromise = res\n .then((result) => {\n if (isAsyncIterable(result)) {\n return wrapAsyncIterable(result, generation);\n }\n\n const output = parseCompletionOutput(result);\n const usageDetails = parseUsageDetailsFromResponse(result);\n const {\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n } = parseModelDataFromResponse(result);\n\n generation\n .update({\n output,\n usageDetails,\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n })\n .end();\n\n return result;\n })\n .catch((err) => {\n generation\n .update({\n statusMessage: String(err),\n level: \"ERROR\",\n costDetails: {\n input: 0,\n output: 0,\n total: 0,\n },\n })\n .end();\n\n throw err;\n });\n\n return wrappedPromise;\n }\n\n return res;\n } catch (error) {\n generation\n .update({\n statusMessage: String(error),\n level: \"ERROR\",\n costDetails: {\n input: 0,\n output: 0,\n total: 0,\n },\n })\n .end();\n\n throw error;\n }\n};\n\n/**\n * Wraps an async iterable (streaming response) with ElasticDash tracing.\n *\n * This function handles streaming OpenAI responses by collecting chunks,\n * parsing usage information, and updating the ElasticDash generation with\n * the complete output and usage details once the stream is consumed.\n *\n * @param iterable - The async iterable from OpenAI (streaming response)\n * @param generation - The ElasticDash generation to update with stream data\n * @returns An async generator that yields original chunks while collecting data\n *\n * @internal\n */\nfunction wrapAsyncIterable<R>(\n iterable: AsyncIterable<unknown>,\n generation: ElasticDashGeneration,\n): R {\n async function* tracedOutputGenerator(): AsyncGenerator<\n unknown,\n void,\n unknown\n > {\n const response = iterable;\n const textChunks: string[] = [];\n const toolCallChunks: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall[] =\n [];\n let usage: OpenAI.CompletionUsage | null = null;\n let completionStartTime: Date | undefined = undefined;\n let usageDetails: Record<string, number> | undefined = undefined;\n let output: unknown = null;\n\n for await (const rawChunk of response as AsyncIterable<unknown>) {\n completionStartTime = completionStartTime ?? new Date();\n\n // Handle Response API chunks\n if (typeof rawChunk === \"object\" && rawChunk && \"response\" in rawChunk) {\n const result = rawChunk[\"response\"];\n output = parseCompletionOutput(result);\n usageDetails = parseUsageDetailsFromResponse(result);\n\n const {\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n } = parseModelDataFromResponse(result);\n\n generation.update({\n model: modelFromResponse,\n modelParameters: modelParametersFromResponse,\n metadata: metadataFromResponse,\n });\n }\n\n if (\n typeof rawChunk === \"object\" &&\n rawChunk != null &&\n \"usage\" in rawChunk\n ) {\n usage = rawChunk.usage as OpenAI.CompletionUsage | null;\n }\n\n const processedChunk = parseChunk(rawChunk);\n\n if (!processedChunk.isToolCall) {\n textChunks.push(processedChunk.data);\n } else {\n toolCallChunks.push(processedChunk.data);\n }\n\n yield rawChunk;\n }\n\n output =\n output ??\n (toolCallChunks.length > 0\n ? getToolCallOutput(toolCallChunks)\n : textChunks.join(\"\"));\n\n generation\n .update({\n output,\n completionStartTime,\n usageDetails:\n usageDetails ?? (usage ? parseUsageDetails(usage) : undefined),\n })\n .end();\n }\n\n return tracedOutputGenerator() as R;\n}\n","import type OpenAI from \"openai\";\n\ntype ParsedOpenAIArguments = {\n model: string;\n input: Record<string, any> | string;\n modelParameters: Record<string, any>;\n};\n\nexport const parseInputArgs = (\n args: Record<string, any>,\n): ParsedOpenAIArguments => {\n let params: Record<string, any> = {};\n params = {\n frequency_penalty: args.frequency_penalty,\n logit_bias: args.logit_bias,\n logprobs: args.logprobs,\n max_tokens: args.max_tokens,\n n: args.n,\n presence_penalty: args.presence_penalty,\n seed: args.seed,\n stop: args.stop,\n stream: args.stream,\n temperature: args.temperature,\n top_p: args.top_p,\n user: args.user,\n response_format: args.response_format,\n top_logprobs: args.top_logprobs,\n };\n\n let input: Record<string, any> | string = args.input;\n\n if (\n args &&\n typeof args === \"object\" &&\n !Array.isArray(args) &&\n \"messages\" in args\n ) {\n input = {};\n input.messages = args.messages;\n if (\"function_call\" in args) {\n input.function_call = args.function_call;\n }\n if (\"functions\" in args) {\n input.functions = args.functions;\n }\n if (\"tools\" in args) {\n input.tools = args.tools;\n }\n\n if (\"tool_choice\" in args) {\n input.tool_choice = args.tool_choice;\n }\n } else if (!input) {\n input = args.prompt;\n }\n\n return {\n model: args.model,\n input: input,\n modelParameters: params,\n };\n};\n\nexport const parseCompletionOutput = (res: unknown): unknown => {\n if (\n res instanceof Object &&\n \"output_text\" in res &&\n res[\"output_text\"] !== \"\"\n ) {\n return res[\"output_text\"] as string;\n }\n\n if (\n typeof res === \"object\" &&\n res &&\n \"output\" in res &&\n Array.isArray(res[\"output\"])\n ) {\n const output = res[\"output\"];\n\n if (output.length > 1) {\n return output;\n }\n if (output.length === 1) {\n return output[0] as Record<string, unknown>;\n }\n\n return null;\n }\n\n if (\n !(res instanceof Object && \"choices\" in res && Array.isArray(res.choices))\n ) {\n return \"\";\n }\n\n return \"message\" in res.choices[0]\n ? res.choices[0].message\n : (res.choices[0].text ?? \"\");\n};\n\nexport const parseUsageDetails = (\n completionUsage: OpenAI.CompletionUsage,\n): Record<string, number> | undefined => {\n if (\"prompt_tokens\" in completionUsage) {\n const {\n prompt_tokens,\n completion_tokens,\n total_tokens,\n completion_tokens_details,\n prompt_tokens_details,\n } = completionUsage;\n\n const flatPromptTokensDetails = Object.fromEntries(\n Object.entries(prompt_tokens_details ?? {}).map(([key, value]) => [\n `input_${key}`,\n value as number,\n ]),\n );\n\n const flatCompletionTokensDetails = Object.fromEntries(\n Object.entries(completion_tokens_details ?? {}).map(([key, value]) => [\n `output_${key}`,\n value as number,\n ]),\n );\n\n let finalInputTokens = prompt_tokens as number;\n Object.values(flatPromptTokensDetails).forEach((value) => {\n finalInputTokens = Math.max(finalInputTokens - value, 0);\n });\n\n let finalOutputTokens = completion_tokens as number;\n Object.values(flatCompletionTokensDetails).forEach((value) => {\n finalOutputTokens = Math.max(finalOutputTokens - value, 0);\n });\n\n return {\n input: finalInputTokens,\n output: finalOutputTokens,\n total: total_tokens,\n ...flatPromptTokensDetails,\n ...flatCompletionTokensDetails,\n };\n } else if (\"input_tokens\" in completionUsage) {\n const {\n input_tokens,\n output_tokens,\n total_tokens,\n input_tokens_details,\n output_tokens_details,\n } = completionUsage;\n\n let finalInputTokens = input_tokens as number;\n Object.keys(input_tokens_details ?? {}).forEach((key) => {\n finalInputTokens = Math.max(\n finalInputTokens -\n input_tokens_details[key as keyof typeof input_tokens_details],\n 0,\n );\n });\n\n let finalOutputTokens = output_tokens as number;\n Object.keys(output_tokens_details ?? {}).forEach((key) => {\n finalOutputTokens = Math.max(\n finalOutputTokens -\n output_tokens_details[key as keyof typeof output_tokens_details],\n 0,\n );\n });\n\n return {\n input: finalInputTokens,\n output: finalOutputTokens,\n total: total_tokens,\n ...Object.fromEntries(\n Object.entries(input_tokens_details ?? {}).map(([key, value]) => [\n `input_${key}`,\n value as number,\n ]),\n ),\n ...Object.fromEntries(\n Object.entries(output_tokens_details ?? {}).map(([key, value]) => [\n `output_${key}`,\n value as number,\n ]),\n ),\n };\n }\n};\n\nexport const parseUsageDetailsFromResponse = (\n res: unknown,\n): Record<string, number> | undefined => {\n if (hasCompletionUsage(res)) {\n return parseUsageDetails(res.usage);\n }\n};\n\nexport const parseChunk = (\n rawChunk: unknown,\n):\n | { isToolCall: false; data: string }\n | {\n isToolCall: true;\n data: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall;\n } => {\n let isToolCall = false;\n const _chunk = rawChunk as\n | OpenAI.ChatCompletionChunk\n | OpenAI.Completions.Completion;\n const chunkData = _chunk?.choices?.[0];\n\n try {\n if (\n \"delta\" in chunkData &&\n \"tool_calls\" in chunkData.delta &&\n Array.isArray(chunkData.delta.tool_calls)\n ) {\n isToolCall = true;\n\n return { isToolCall, data: chunkData.delta.tool_calls[0] };\n }\n if (\"delta\" in chunkData) {\n return { isToolCall, data: chunkData.delta?.content || \"\" };\n }\n\n if (\"text\" in chunkData) {\n return { isToolCall, data: chunkData.text || \"\" };\n }\n } catch {}\n\n return { isToolCall: false, data: \"\" };\n};\n\n// Type guard to check if an unknown object is a UsageResponse\nfunction hasCompletionUsage(\n obj: any,\n): obj is { usage: OpenAI.CompletionUsage } {\n return (\n obj instanceof Object &&\n \"usage\" in obj &&\n obj.usage instanceof Object &&\n // Completion API Usage format\n ((typeof obj.usage.prompt_tokens === \"number\" &&\n typeof obj.usage.completion_tokens === \"number\" &&\n typeof obj.usage.total_tokens === \"number\") ||\n // Response API Usage format\n (typeof obj.usage.input_tokens === \"number\" &&\n typeof obj.usage.output_tokens === \"number\" &&\n typeof obj.usage.total_tokens === \"number\"))\n );\n}\n\nexport const getToolCallOutput = (\n toolCallChunks: OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta.ToolCall[],\n): {\n tool_calls: {\n function: {\n name: string;\n arguments: string;\n };\n }[];\n} => {\n let name = \"\";\n let toolArguments = \"\";\n\n for (const toolCall of toolCallChunks) {\n name = toolCall.function?.name || name;\n toolArguments += toolCall.function?.arguments || \"\";\n }\n\n return {\n tool_calls: [\n {\n function: {\n name,\n arguments: toolArguments,\n },\n },\n ],\n };\n};\n\nexport const parseModelDataFromResponse = (\n res: unknown,\n): {\n model: string | undefined;\n modelParameters: Record<string, string | number> | undefined;\n metadata: Record<string, unknown> | undefined;\n} => {\n if (typeof res !== \"object\" || res === null) {\n return {\n model: undefined,\n modelParameters: undefined,\n metadata: undefined,\n };\n }\n\n const model = \"model\" in res ? (res[\"model\"] as string) : undefined;\n const modelParameters: Record<string, string | number> = {};\n const modelParamKeys = [\n \"max_output_tokens\",\n \"parallel_tool_calls\",\n \"store\",\n \"temperature\",\n \"tool_choice\",\n \"top_p\",\n \"truncation\",\n \"user\",\n ];\n\n const metadata: Record<string, unknown> = {};\n const metadataKeys = [\n \"reasoning\",\n \"incomplete_details\",\n \"instructions\",\n \"previous_response_id\",\n \"tools\",\n \"metadata\",\n \"status\",\n \"error\",\n ];\n\n for (const key of modelParamKeys) {\n const val =\n key in res ? (res[key as keyof typeof res] as string | number) : null;\n if (val !== null && val !== undefined) {\n modelParameters[key as keyof typeof modelParameters] = val;\n }\n }\n\n for (const key of metadataKeys) {\n const val =\n key in res ? (res[key as keyof typeof res] as string | number) : null;\n if (val) {\n metadata[key as keyof typeof metadata] = val;\n }\n }\n\n return {\n model,\n modelParameters:\n Object.keys(modelParameters).length > 0 ? modelParameters : undefined,\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n };\n};\n","/**\n * Type guard to check if a value is an async iterable.\n *\n * This utility function determines whether a given value implements the\n * AsyncIterable interface, which is used to identify streaming responses\n * from the OpenAI SDK.\n *\n * @param x - The value to check\n * @returns True if the value is an async iterable, false otherwise\n *\n * @example\n * ```typescript\n * import { isAsyncIterable } from './utils.js';\n *\n * const response = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [...],\n * stream: true\n * });\n *\n * if (isAsyncIterable(response)) {\n * // Handle streaming response\n * for await (const chunk of response) {\n * console.log(chunk);\n * }\n * } else {\n * // Handle regular response\n * console.log(response);\n * }\n * ```\n *\n * @public\n */\nexport const isAsyncIterable = (x: unknown): x is AsyncIterable<unknown> =>\n x != null &&\n typeof x === \"object\" &&\n typeof (x as any)[Symbol.asyncIterator] === \"function\";\n","import { withTracing } from \"./traceMethod.js\";\nimport type { ElasticDashConfig } from \"./types.js\";\n\n/**\n * Wraps an OpenAI SDK client with automatic ElasticDash tracing.\n *\n * This function creates a proxy around the OpenAI SDK that automatically\n * traces all method calls, capturing detailed information about requests,\n * responses, token usage, costs, and performance metrics. It works with\n * both streaming and non-streaming OpenAI API calls.\n *\n * The wrapper recursively traces nested objects in the OpenAI SDK, ensuring\n * that all API calls (chat completions, embeddings, fine-tuning, etc.) are\n * automatically captured as ElasticDash generations.\n *\n * @param sdk - The OpenAI SDK client instance to wrap with tracing\n * @param elasticDashConfig - Optional configuration for tracing behavior\n * @returns A proxied version of the OpenAI SDK with automatic tracing\n *\n * @example\n * ```typescript\n * import OpenAI from 'openai';\n * import { observeOpenAI } from '@elasticdash/openai';\n *\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY,\n * }));\n *\n * // All OpenAI calls are now automatically traced\n * const response = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Hello!' }],\n * max_tokens: 100,\n * temperature: 0.7\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With custom tracing configuration\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY\n * }), {\n * traceName: 'AI-Assistant-Chat',\n * userId: 'user-123',\n * sessionId: 'session-456',\n * tags: ['production', 'chat-feature'],\n * generationName: 'gpt-4-chat-completion'\n * });\n *\n * const completion = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Explain quantum computing' }]\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Streaming responses are also automatically traced\n * const stream = await openai.chat.completions.create({\n * model: 'gpt-4',\n * messages: [{ role: 'user', content: 'Write a story' }],\n * stream: true\n * });\n *\n * for await (const chunk of stream) {\n * process.stdout.write(chunk.choices[0]?.delta?.content || '');\n * }\n * // Final usage details and complete output are captured automatically\n * ```\n *\n * @example\n * ```typescript\n * // Using with ElasticDash prompt management\n * const openai = observeOpenAI(new OpenAI({\n * apiKey: process.env.OPENAI_API_KEY\n * }), {\n * elasticDashPrompt: {\n * name: 'chat-assistant-v2',\n * version: 3,\n * isFallback: false\n * },\n * generationMetadata: {\n * environment: 'production',\n * feature: 'chat-assistant'\n * }\n * });\n * ```\n *\n * @public\n */\nexport const observeOpenAI = <SDKType extends object>(\n sdk: SDKType,\n elasticDashConfig?: ElasticDashConfig,\n): SDKType => {\n return new Proxy(sdk, {\n get(wrappedSdk, propKey, proxy) {\n const originalProperty = wrappedSdk[propKey as keyof SDKType];\n\n const defaultGenerationName = `${sdk.constructor?.name}.${propKey.toString()}`;\n const generationName =\n elasticDashConfig?.generationName ?? defaultGenerationName;\n const config = { ...elasticDashConfig, generationName };\n\n // Trace methods of the OpenAI SDK\n if (typeof originalProperty === \"function\") {\n return withTracing(originalProperty.bind(wrappedSdk), config);\n }\n\n const isNestedOpenAIObject =\n originalProperty &&\n !Array.isArray(originalProperty) &&\n !(originalProperty instanceof Date) &&\n typeof originalProperty === \"object\";\n\n // Recursively wrap nested objects to ensure all nested properties or methods are also traced\n if (isNestedOpenAIObject) {\n return observeOpenAI(originalProperty, config);\n }\n\n // Fallback to returning the original value\n return Reflect.get(wrappedSdk, propKey, proxy);\n },\n });\n};\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elasticdash/openai",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "ElasticDash integration for OpenAI SDK",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -25,8 +25,8 @@
25
25
  "dist"
26
26
  ],
27
27
  "dependencies": {
28
- "@elasticdash/core": "^0.0.7",
29
- "@elasticdash/tracing": "^0.0.7"
28
+ "@elasticdash/core": "^0.0.9",
29
+ "@elasticdash/tracing": "^0.0.9"
30
30
  },
31
31
  "devDependencies": {
32
32
  "openai": "^5.0.0"