neatlogs 1.0.4 → 1.0.6

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mastra-wrap.ts"],"sourcesContent":["/**\n * Neatlogs Mastra wrapper — full nested tracing via method-wrapping.\n *\n * Usage:\n * import { wrapMastra } from 'neatlogs/mastra';\n * import { Agent } from '@mastra/core/agent';\n * const agent = wrapMastra(new Agent({ ... }));\n * const result = await agent.generate('Hello');\n *\n * Philosophy (same as wrapAISDK): we own the capturing layer. Instead of\n * depending on Mastra's internal observability bus or @mastra/observability,\n * we wrap Mastra's own methods and emit OpenTelemetry spans ourselves. Every\n * parent span is opened as the ACTIVE span, so child operations (LLM calls,\n * tool executions, workflow steps) nest automatically.\n *\n * Coverage (duck-typed by the methods present on the entity):\n * - Agent.generate()/stream() → AGENT (parent)\n * ↳ resolved model doGenerate/doStream → LLM (child, per model step)\n * ↳ each tool's execute() → TOOL (child, per tool call)\n * - Workflow.createRun().start()/resume() → WORKFLOW\n * - MastraVector.query() → RETRIEVER\n * - MastraVector.upsert/update/delete() → VECTOR_STORE\n * - MastraMemory.recall/saveMessages/... → CHAIN (memory ops)\n * - MDocument.chunk() → CHAIN\n * - rerank() (standalone fn) → RERANKER\n * - root Mastra (getAgent + getWorkflow) → proxy that wraps what it returns\n */\n\nimport { trace, context as otelContext, SpanStatusCode, type Span } from '@opentelemetry/api';\n\nconst TRACER_NAME = 'neatlogs.mastra';\nconst PATCH_FLAG = '_neatlogs_patched';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport function wrapMastra<T extends object>(entity: T): T {\n if (!entity || (entity as any)[PATCH_FLAG]) return entity;\n\n const e = entity as any;\n const className = entity.constructor?.name ?? '';\n\n // Root Mastra: wrap the agents/workflows it hands out (it itself has neither\n // generate nor createRun). Detect by the getter pair.\n if (isRootMastra(e)) {\n const proxied = wrapRootMastra(e);\n markPatched(proxied);\n return proxied as T;\n }\n\n if (isAgent(e, className)) {\n patchAgent(e);\n } else if (isWorkflow(e, className)) {\n patchWorkflow(e);\n } else if (isVector(e, className)) {\n patchVector(e);\n } else if (isMemory(e, className)) {\n patchMemory(e);\n } else if (isDocument(e, className)) {\n patchDocument(e);\n }\n\n markPatched(e);\n return entity;\n}\n\n/**\n * Wrap a standalone `rerank()` function (from `@mastra/rag`) so each call emits\n * a RERANKER span. Returns a wrapped function; the original is unchanged.\n *\n * import { rerank } from '@mastra/rag';\n * const tracedRerank = wrapMastraRerank(rerank);\n */\nexport function wrapMastraRerank<F extends (...args: any[]) => any>(rerankFn: F): F {\n return (async function tracedRerank(...args: any[]) {\n return withSpan('mastra.rerank', { 'neatlogs.span.kind': 'RERANKER' }, (span) => {\n // rerank(results, query, model, options)\n const results = args?.[0];\n const query = args?.[1];\n const options = args?.[3];\n if (typeof query === 'string') {\n span.setAttribute('neatlogs.reranker.query', query.slice(0, 10000));\n span.setAttribute('input.value', query.slice(0, 10000));\n }\n if (Array.isArray(results)) span.setAttribute('neatlogs.reranker.input_documents', safeStringify(results).slice(0, 10000));\n if (options?.topK != null) span.setAttribute('neatlogs.reranker.top_k', options.topK);\n return Promise.resolve(rerankFn(...args)).then((result) => {\n span.setAttribute('neatlogs.reranker.output_documents', safeStringify(result).slice(0, 10000));\n span.setAttribute('output.value', safeStringify(result).slice(0, 10000));\n return result;\n });\n });\n }) as unknown as F;\n}\n\n// ---------------------------------------------------------------------------\n// Detection (duck-typed — robust across Mastra versions / build shapes)\n// ---------------------------------------------------------------------------\n\nfunction isRootMastra(e: any): boolean {\n return typeof e.getAgent === 'function' && typeof e.getWorkflow === 'function';\n}\n\nfunction isAgent(e: any, className: string): boolean {\n // An agent exposes generate()/stream(). getLLM()/listTools() are wrapped\n // opportunistically when present (installAgentLlmHook/installAgentToolHooks\n // no-op otherwise), so they are not required for detection.\n return className === 'Agent' || typeof e.generate === 'function' || typeof e.stream === 'function';\n}\n\nfunction isWorkflow(e: any, className: string): boolean {\n return className === 'Workflow' || typeof e.createRun === 'function';\n}\n\nfunction isVector(e: any, className: string): boolean {\n return /Vector/.test(className) || (typeof e.query === 'function' && typeof e.upsert === 'function');\n}\n\nfunction isMemory(e: any, className: string): boolean {\n return /Memory/.test(className) || (typeof e.recall === 'function' && typeof e.saveMessages === 'function');\n}\n\nfunction isDocument(e: any, className: string): boolean {\n return className === 'MDocument' || (typeof e.chunk === 'function' && typeof e.getDocs === 'function');\n}\n\n// ---------------------------------------------------------------------------\n// Agent\n// ---------------------------------------------------------------------------\n\nfunction patchAgent(agent: any): void {\n patchAgentMethod(agent, 'generate', false);\n patchAgentMethod(agent, 'stream', true);\n}\n\n/**\n * Wrap generate()/stream() with an AGENT parent span. Before delegating, also\n * install child-span hooks on this agent's resolved model (LLM) and tools\n * (TOOL) so they nest under the AGENT span. Hooks are installed lazily/once.\n */\nfunction patchAgentMethod(agent: any, method: 'generate' | 'stream', streaming: boolean): void {\n if (typeof agent[method] !== 'function') return;\n const orig = agent[method].bind(agent);\n\n agent[method] = async function tracedAgentMethod(input: any, opts?: any): Promise<any> {\n const agentName = agent.name ?? agent.id ?? 'mastra_agent';\n const model = extractModelId(agent.model);\n\n // Ensure LLM + TOOL child hooks are present (idempotent).\n installAgentLlmHook(agent);\n installAgentToolHooks(agent);\n\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'AGENT',\n 'neatlogs.agent.name': agentName,\n 'input.value': toInputValue(input),\n };\n if (model) attrs['neatlogs.llm.model_name'] = model;\n if (agent.instructions && typeof agent.instructions === 'string') {\n attrs['neatlogs.llm.system_prompt'] = agent.instructions.slice(0, 5000);\n }\n if (streaming) attrs['neatlogs.llm.is_streaming'] = true;\n\n if (streaming) {\n // stream() returns immediately; the model only runs when the caller drains\n // the stream. Keep the AGENT span open + active across the whole stream so\n // doStream (LLM) children nest, and finalize when the output completes.\n const tracer = trace.getTracer(TRACER_NAME);\n const span = tracer.startSpan(`mastra.agent.${agentName}`, { attributes: attrs }, otelContext.active());\n const ctx = trace.setSpan(otelContext.active(), span);\n try {\n const result = await otelContext.with(ctx, () => orig(input, opts));\n return wrapStreamingOutput(result, span, ctx);\n } catch (err) {\n recordError(span, err);\n span.end();\n throw err;\n }\n }\n\n return withActiveSpan(`mastra.agent.${agentName}`, attrs, async (span) => {\n const result = await orig(input, opts);\n finalizeAgentResult(span, result);\n return result;\n });\n };\n}\n\n/**\n * Patch agent.getLLM so the model it returns has doGenerate/doStream wrapped\n * (emitting LLM child spans). Mastra calls this.getLLM() inside generate/stream,\n * and the resolved model is the single chokepoint for the real provider call.\n */\nfunction installAgentLlmHook(agent: any): void {\n if (agent.__neatlogs_llm_hook || typeof agent.getLLM !== 'function') return;\n agent.__neatlogs_llm_hook = true;\n\n const origGetLLM = agent.getLLM.bind(agent);\n agent.getLLM = function patchedGetLLM(...args: any[]): any {\n const out = origGetLLM(...args);\n return Promise.resolve(out).then((llm: any) => {\n try {\n const model = typeof llm?.getModel === 'function' ? llm.getModel() : llm;\n patchModelInPlace(model);\n } catch {\n /* best-effort */\n }\n return llm;\n });\n };\n}\n\n/** Wrap a resolved language model's doGenerate/doStream in place (idempotent). */\nfunction patchModelInPlace(model: any): void {\n if (!model || model.__neatlogs_model_patched) return;\n model.__neatlogs_model_patched = true;\n const modelId = model.modelId ?? model.modelName ?? '';\n const provider = model.provider ?? '';\n\n for (const fn of ['doGenerate', 'doStream'] as const) {\n if (typeof model[fn] !== 'function') continue;\n const orig = model[fn].bind(model);\n const isStream = fn === 'doStream';\n\n model[fn] = function tracedModelCall(callOpts: any): any {\n const attrs: Record<string, any> = { 'neatlogs.span.kind': 'LLM' };\n if (modelId) attrs['neatlogs.llm.model_name'] = modelId;\n if (provider) attrs['neatlogs.llm.provider'] = provider;\n if (isStream) attrs['neatlogs.llm.is_streaming'] = true;\n const promptInput = callOpts?.prompt ?? callOpts?.messages;\n if (promptInput !== undefined) attrs['input.value'] = safeStringify(promptInput).slice(0, 10000);\n captureInvocationParams(attrs, callOpts);\n\n return withActiveSpan(`mastra.llm.${modelId || 'model'}.${fn}`, attrs, async (span) => {\n const result = await orig(callOpts);\n if (!isStream) finalizeModelResult(span, result);\n // Streaming doGenerate-style results serialize lazily; record what we can.\n else if (result?.usage) recordUsage(span, result.usage);\n return result;\n });\n };\n }\n}\n\n/** Patch each tool's execute() so tool calls become TOOL child spans. */\nfunction installAgentToolHooks(agent: any): void {\n if (agent.__neatlogs_tool_hook) return;\n let tools: Record<string, any> | undefined;\n try {\n tools = typeof agent.listTools === 'function' ? agent.listTools() : undefined;\n } catch {\n tools = undefined;\n }\n if (!tools || typeof tools !== 'object') return;\n agent.__neatlogs_tool_hook = true;\n\n for (const [key, tool] of Object.entries<any>(tools)) {\n patchToolExecute(tool, key);\n }\n}\n\nfunction patchToolExecute(tool: any, key: string): void {\n if (!tool || typeof tool.execute !== 'function' || tool.__neatlogs_tool_patched) return;\n tool.__neatlogs_tool_patched = true;\n const toolName = tool.id ?? key;\n const orig = tool.execute.bind(tool);\n\n tool.execute = function tracedToolExecute(params: any, options?: any): any {\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'TOOL',\n 'neatlogs.tool.name': toolName,\n 'input.value': safeStringify(params).slice(0, 10000),\n };\n if (tool.description) attrs['neatlogs.tool.description'] = String(tool.description).slice(0, 2000);\n\n return withActiveSpan(`mastra.tool.${toolName}`, attrs, async (span) => {\n const result = await orig(params, options);\n span.setAttribute('output.value', safeStringify(result).slice(0, 10000));\n return result;\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// Workflow\n// ---------------------------------------------------------------------------\n\nfunction patchWorkflow(workflow: any): void {\n if (typeof workflow.createRun !== 'function') return;\n const origCreateRun = workflow.createRun.bind(workflow);\n const workflowName = workflow.name ?? workflow.id ?? 'mastra_workflow';\n\n workflow.createRun = async function tracedCreateRun(...args: any[]): Promise<any> {\n const run = await origCreateRun(...args);\n if (!run) return run;\n patchRunMethod(run, 'start', workflowName);\n patchRunMethod(run, 'resume', workflowName);\n return run;\n };\n}\n\nfunction patchRunMethod(run: any, method: 'start' | 'resume', workflowName: string): void {\n if (typeof run[method] !== 'function') return;\n const orig = run[method].bind(run);\n\n run[method] = async function tracedRunMethod(startOpts: any): Promise<any> {\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'WORKFLOW',\n 'neatlogs.workflow.name': workflowName,\n };\n if (startOpts?.inputData !== undefined) {\n attrs['input.value'] = safeStringify(startOpts.inputData).slice(0, 10000);\n }\n\n return withActiveSpan(`mastra.workflow.${workflowName}`, attrs, async (span) => {\n const result = await orig(startOpts);\n if (result?.status) span.setAttribute('neatlogs.metadata', safeStringify({ status: result.status }));\n if (result?.result !== undefined) {\n span.setAttribute('output.value', safeStringify(result.result).slice(0, 10000));\n }\n return result;\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// Vector store\n// ---------------------------------------------------------------------------\n\nconst VECTOR_READ_OPS = ['query'];\nconst VECTOR_WRITE_OPS = ['upsert', 'updateVector', 'deleteVector', 'createIndex', 'deleteIndex'];\n\nfunction patchVector(vector: any): void {\n for (const op of VECTOR_READ_OPS) patchVectorOp(vector, op, 'RETRIEVER');\n for (const op of VECTOR_WRITE_OPS) patchVectorOp(vector, op, 'VECTOR_STORE');\n}\n\nfunction patchVectorOp(vector: any, op: string, kind: 'RETRIEVER' | 'VECTOR_STORE'): void {\n if (typeof vector[op] !== 'function') return;\n const orig = vector[op].bind(vector);\n const dbName = vector.constructor?.name ?? 'vector';\n\n vector[op] = async function tracedVectorOp(params: any): Promise<any> {\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': kind,\n 'neatlogs.db.system': dbName,\n 'neatlogs.db.operation': op,\n 'input.value': safeStringify(params).slice(0, 10000),\n };\n const indexName = params?.indexName;\n if (indexName) attrs['neatlogs.vectordb.index_name'] = String(indexName);\n if (kind === 'RETRIEVER' && params?.topK != null) attrs['neatlogs.retriever.top_k'] = params.topK;\n return withActiveSpan(`mastra.vector.${op}`, attrs, async (span) => {\n const result = await orig(params);\n span.setAttribute('output.value', safeStringify(result).slice(0, 10000));\n return result;\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// Memory\n// ---------------------------------------------------------------------------\n\nconst MEMORY_OPS = ['recall', 'saveMessages', 'updateWorkingMemory', 'deleteMessages'];\n\nfunction patchMemory(memory: any): void {\n for (const op of MEMORY_OPS) {\n if (typeof memory[op] !== 'function') continue;\n const orig = memory[op].bind(memory);\n memory[op] = async function tracedMemoryOp(...args: any[]): Promise<any> {\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'CHAIN',\n 'neatlogs.db.operation': op,\n 'input.value': safeStringify(args?.[0]).slice(0, 10000),\n };\n return withActiveSpan(`mastra.memory.${op}`, attrs, async (span) => {\n const result = await orig(...args);\n span.setAttribute('output.value', safeStringify(result).slice(0, 8000));\n return result;\n });\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// MDocument\n// ---------------------------------------------------------------------------\n\nfunction patchDocument(doc: any): void {\n if (typeof doc.chunk !== 'function') return;\n const orig = doc.chunk.bind(doc);\n doc.chunk = async function tracedChunk(...args: any[]): Promise<any> {\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'CHAIN',\n 'neatlogs.db.operation': 'chunk',\n };\n return withActiveSpan('mastra.document.chunk', attrs, async (span) => {\n const result = await orig(...args);\n if (Array.isArray(result)) span.setAttribute('neatlogs.db.documents_count', result.length);\n return result;\n });\n };\n}\n\n// ---------------------------------------------------------------------------\n// Root Mastra proxy\n// ---------------------------------------------------------------------------\n\nfunction wrapRootMastra(mastra: any): any {\n const AGENT_GETTERS = new Set(['getAgent', 'getAgentById']);\n const WORKFLOW_GETTERS = new Set(['getWorkflow', 'getWorkflowById']);\n\n return new Proxy(mastra, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (typeof value !== 'function') return value;\n const name = String(prop);\n\n if (AGENT_GETTERS.has(name) || WORKFLOW_GETTERS.has(name)) {\n return (...args: any[]) => {\n const entity = value.apply(target, args);\n return entity && typeof entity === 'object' ? wrapMastra(entity) : entity;\n };\n }\n return value.bind(target);\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// Streaming output wrapping\n// ---------------------------------------------------------------------------\n\n/**\n * Finalize the AGENT span for a streaming result.\n *\n * Mastra's `stream()` returns a `MastraModelOutput` (NOT a plain async-iterable):\n * the model only runs when the caller drains `.textStream`/`.fullStream` or\n * awaits `.text`. We therefore:\n * 1. Re-establish the AGENT span's context around stream consumption so the\n * model's `doStream` (LLM) child nests under it.\n * 2. Tap the `.text`/`.usage`/`.finishReason` promises — which resolve when the\n * stream completes regardless of how the caller consumes — to record output\n * and end the span exactly once.\n * Falls back to legacy async-iterable / thenable shapes for older Mastra.\n */\nfunction wrapStreamingOutput(output: any, span: Span, ctx: ReturnType<typeof otelContext.active>): any {\n if (!output) {\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n return output;\n }\n\n let ended = false;\n const endOnce = (err?: unknown) => {\n if (ended) return;\n ended = true;\n if (err) recordError(span, err);\n else span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n };\n\n // MastraModelOutput: has awaitable .text (thenable). Tap completion promises.\n if (output.text && typeof output.text.then === 'function') {\n const finalize = async () => {\n try {\n const [text, usage, finishReason] = await Promise.all([\n Promise.resolve(output.text).catch(() => undefined),\n Promise.resolve(output.usage).catch(() => undefined),\n Promise.resolve(output.finishReason).catch(() => undefined),\n ]);\n if (typeof text === 'string' && text) {\n span.setAttribute('neatlogs.llm.output_messages.0.role', 'assistant');\n span.setAttribute('neatlogs.llm.output_messages.0.content', text.slice(0, 10000));\n }\n if (usage) recordUsage(span, usage);\n if (finishReason) span.setAttribute('neatlogs.llm.stop_reason', normalizeFinishReason(finishReason));\n endOnce();\n } catch (err) {\n endOnce(err);\n }\n };\n // Drive finalization without requiring the caller to consume; the promises\n // resolve when Mastra finishes the stream internally.\n void finalize();\n\n // Re-establish span context around stream getters so doStream children nest.\n return rebindStreamContext(output, ctx);\n }\n\n // Legacy async-iterable\n if (output[Symbol.asyncIterator]) {\n const origIterator = output[Symbol.asyncIterator].bind(output);\n const textParts: string[] = [];\n const wrapped = Object.create(Object.getPrototypeOf(output));\n Object.assign(wrapped, output);\n wrapped[Symbol.asyncIterator] = function () {\n const iterator = origIterator();\n const finish = () => {\n if (textParts.length) {\n span.setAttribute('neatlogs.llm.output_messages.0.role', 'assistant');\n span.setAttribute('neatlogs.llm.output_messages.0.content', textParts.join('').slice(0, 10000));\n }\n endOnce();\n };\n return {\n async next(): Promise<IteratorResult<any>> {\n try {\n const r = await iterator.next();\n if (r.done) { finish(); return r; }\n const chunk = r.value;\n if (typeof chunk === 'string') textParts.push(chunk);\n else if (chunk?.text) textParts.push(chunk.text);\n else if (chunk?.delta) textParts.push(chunk.delta);\n return r;\n } catch (err) { endOnce(err); throw err; }\n },\n async return(value?: any): Promise<IteratorResult<any>> {\n finish();\n return iterator.return?.(value) ?? { done: true, value: undefined };\n },\n async throw(err?: any): Promise<IteratorResult<any>> {\n endOnce(err);\n return iterator.throw?.(err) ?? { done: true, value: undefined };\n },\n };\n };\n return wrapped;\n }\n\n // Thenable (awaited result)\n if (typeof output.then === 'function') {\n return output\n .then((resolved: any) => { finalizeAgentResult(span, resolved); endOnce(); return resolved; })\n .catch((err: any) => { endOnce(err); throw err; });\n }\n\n endOnce();\n return output;\n}\n\n/**\n * Wrap the async-iterable getters on a MastraModelOutput so that draining the\n * stream runs inside the AGENT span's context (lets the model's doStream child\n * span attach to the right parent). Returns a proxy; non-stream props pass through.\n */\nfunction rebindStreamContext(output: any, ctx: ReturnType<typeof otelContext.active>): any {\n const STREAM_PROPS = new Set(['textStream', 'fullStream', 'objectStream', 'elementStream']);\n return new Proxy(output, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (typeof prop === 'string' && STREAM_PROPS.has(prop) && value && value[Symbol.asyncIterator]) {\n const origIterator = value[Symbol.asyncIterator].bind(value);\n return {\n [Symbol.asyncIterator]() {\n return otelContext.with(ctx, () => origIterator());\n },\n };\n }\n if (typeof value === 'function') return value.bind(target);\n return value;\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// Result finalization\n// ---------------------------------------------------------------------------\n\nfunction finalizeAgentResult(span: Span, result: any): void {\n if (!result) return;\n\n if (result.text) {\n span.setAttribute('neatlogs.llm.output_messages.0.role', 'assistant');\n span.setAttribute('neatlogs.llm.output_messages.0.content', String(result.text).slice(0, 10000));\n }\n\n if (Array.isArray(result.toolCalls)) {\n for (let i = 0; i < result.toolCalls.length; i++) {\n const tc = result.toolCalls[i];\n const p = tc.payload ?? tc;\n setToolCall(span, i, p.toolName ?? p.name, p.args ?? p.arguments, p.toolCallId ?? p.id);\n }\n }\n\n if (result.usage) recordUsage(span, result.usage);\n if (result.finishReason) span.setAttribute('neatlogs.llm.stop_reason', normalizeFinishReason(result.finishReason));\n if (result.model) span.setAttribute('neatlogs.llm.model_name', result.model);\n}\n\nfunction finalizeModelResult(span: Span, result: any): void {\n if (!result) return;\n // AI SDK v5 doGenerate result: { content[], finishReason, usage, ... }.\n // `content` is an array of typed parts (text / tool-call); `text` may be absent.\n if (typeof result.text === 'string' && result.text) {\n span.setAttribute('neatlogs.llm.output_messages.0.role', 'assistant');\n span.setAttribute('neatlogs.llm.output_messages.0.content', result.text.slice(0, 10000));\n } else if (Array.isArray(result.content)) {\n const text = result.content\n .filter((p: any) => p?.type === 'text' && typeof p.text === 'string')\n .map((p: any) => p.text)\n .join('');\n if (text) {\n span.setAttribute('neatlogs.llm.output_messages.0.role', 'assistant');\n span.setAttribute('neatlogs.llm.output_messages.0.content', text.slice(0, 10000));\n }\n // Tool-call parts → indexed tool_calls\n const toolCalls = result.content.filter((p: any) => p?.type === 'tool-call');\n for (let i = 0; i < toolCalls.length; i++) {\n const tc = toolCalls[i];\n setToolCall(span, i, tc.toolName, tc.input ?? tc.args, tc.toolCallId);\n }\n span.setAttribute('output.value', safeStringify(result.content).slice(0, 10000));\n }\n if (result.usage) recordUsage(span, result.usage);\n span.setAttribute('neatlogs.llm.stop_reason', normalizeFinishReason(result.finishReason));\n}\n\nfunction normalizeFinishReason(fr: any): string {\n if (fr == null) return '';\n if (typeof fr === 'string') return fr;\n // AI SDK v5 raw model returns { unified: 'tool-calls', ... }\n return String(fr.unified ?? fr.reason ?? fr.type ?? safeStringify(fr));\n}\n\n/** Read a possibly-nested token count: 42, or { total: 42 }. */\nfunction tokenValue(v: any): number | undefined {\n if (v == null) return undefined;\n if (typeof v === 'number') return v;\n if (typeof v === 'object' && typeof v.total === 'number') return v.total;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n}\n\n/**\n * Capture LLM sampling/invocation parameters from the model call options onto\n * the span, using only canonical neatlogs.* keys. Present-only — absent params\n * are skipped. Mirrors AI SDK LanguageModelV2CallOptions field names.\n */\nfunction captureInvocationParams(attrs: Record<string, any>, callOpts: any): void {\n if (!callOpts) return;\n const map: Array<[string, string]> = [\n ['temperature', 'neatlogs.llm.temperature'],\n ['maxOutputTokens', 'neatlogs.llm.max_tokens'],\n ['maxTokens', 'neatlogs.llm.max_tokens'],\n ['topP', 'neatlogs.llm.top_p'],\n ['topK', 'neatlogs.llm.top_k'],\n ['frequencyPenalty', 'neatlogs.llm.frequency_penalty'],\n ['presencePenalty', 'neatlogs.llm.presence_penalty'],\n ];\n const invocation: Record<string, any> = {};\n for (const [src, target] of map) {\n const v = callOpts[src];\n if (v != null) {\n attrs[target] = v;\n invocation[src] = v;\n }\n }\n if (Array.isArray(callOpts.stopSequences) && callOpts.stopSequences.length) {\n attrs['neatlogs.llm.stop_sequences'] = safeStringify(callOpts.stopSequences);\n invocation.stopSequences = callOpts.stopSequences;\n }\n // Tool definitions advertised to the model → neatlogs.llm.tools.{i}\n if (Array.isArray(callOpts.tools)) {\n for (let i = 0; i < callOpts.tools.length; i++) {\n attrs[`neatlogs.llm.tools.${i}`] = safeStringify(callOpts.tools[i]).slice(0, 4000);\n }\n invocation.toolChoice = callOpts.toolChoice;\n }\n if (Object.keys(invocation).length) {\n attrs['neatlogs.llm.invocation_parameters'] = safeStringify(invocation).slice(0, 4000);\n }\n}\n\n/**\n * Emit an indexed tool call directly in the neatlogs target namespace\n * `neatlogs.llm.tool_calls.{i}.{id,name,arguments}` — matching how the validated\n * openai/anthropic wrappers (src/openai.ts) emit them. The backend's\n * tool_calls.{i} target is an indexed object with these sub-fields.\n */\nfunction setToolCall(span: Span, i: number, name: any, args: any, id: any): void {\n span.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, name ?? '');\n span.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, safeStringify(args ?? {}));\n if (id) span.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, id);\n}\n\nfunction recordUsage(span: Span, usage: any): void {\n if (!usage) return;\n // Shapes seen:\n // - AISDK v5 raw model: { inputTokens: {total}, outputTokens: {total} }\n // - Mastra result: { inputTokens, outputTokens, totalTokens }\n // - AISDK v3: { promptTokens, completionTokens, totalTokens }\n const prompt = tokenValue(usage.promptTokens ?? usage.inputTokens ?? usage.input_tokens);\n const completion = tokenValue(usage.completionTokens ?? usage.outputTokens ?? usage.output_tokens);\n const total = tokenValue(usage.totalTokens);\n if (prompt != null) span.setAttribute('neatlogs.llm.token_count.prompt', prompt);\n if (completion != null) span.setAttribute('neatlogs.llm.token_count.completion', completion);\n if (total != null) span.setAttribute('neatlogs.llm.token_count.total', total);\n else if (prompt != null && completion != null) {\n span.setAttribute('neatlogs.llm.token_count.total', prompt + completion);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Span helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Open a span as the ACTIVE span for the duration of `fn`, so any spans created\n * inside `fn` (model calls, tool executions, workflow steps) nest under it.\n */\nfunction withActiveSpan<T>(name: string, attrs: Record<string, any>, fn: (span: Span) => Promise<T>): Promise<T> {\n const tracer = trace.getTracer(TRACER_NAME);\n const span = tracer.startSpan(name, { attributes: attrs }, otelContext.active());\n const ctx = trace.setSpan(otelContext.active(), span);\n return otelContext.with(ctx, async () => {\n try {\n const result = await fn(span);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (err) {\n recordError(span, err);\n throw err;\n } finally {\n // Stream wrappers end the span themselves once the stream drains; guard\n // against double-end via the OTel SDK (ending twice is a no-op there).\n span.end();\n }\n });\n}\n\n/** Like withActiveSpan but for non-async-context-sensitive leaf operations. */\nfunction withSpan<T>(name: string, attrs: Record<string, any>, fn: (span: Span) => Promise<T> | T): Promise<T> {\n const tracer = trace.getTracer(TRACER_NAME);\n const span = tracer.startSpan(name, { attributes: attrs }, otelContext.active());\n return Promise.resolve()\n .then(() => fn(span))\n .then((result) => {\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n return result;\n })\n .catch((err) => {\n recordError(span, err);\n span.end();\n throw err;\n });\n}\n\n// ---------------------------------------------------------------------------\n// Utilities\n// ---------------------------------------------------------------------------\n\nfunction markPatched(e: any): void {\n try {\n Object.defineProperty(e, PATCH_FLAG, { value: true, enumerable: false, configurable: true });\n } catch {\n e[PATCH_FLAG] = true;\n }\n}\n\nfunction extractModelId(model: any): string {\n if (!model) return '';\n if (typeof model === 'string') return model;\n return model.modelId ?? model.name ?? '';\n}\n\nfunction toInputValue(input: any): string {\n return (typeof input === 'string' ? input : safeStringify(input)).slice(0, 10000);\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value) ?? '';\n } catch {\n return '';\n }\n}\n\nfunction recordError(span: Span, err: unknown): void {\n if (err instanceof Error) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });\n span.recordException(err);\n } else {\n span.setStatus({ code: SpanStatusCode.ERROR, message: String(err) });\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/openai-agents.ts
21
+ var openai_agents_exports = {};
22
+ __export(openai_agents_exports, {
23
+ openaiAgentsProcessor: () => openaiAgentsProcessor
24
+ });
25
+ module.exports = __toCommonJS(openai_agents_exports);
26
+ var import_api = require("@opentelemetry/api");
27
+ var TRACER_NAME = "neatlogs.openai_agents";
28
+ function openaiAgentsProcessor() {
29
+ return new NeatlogsTraceProcessor();
30
+ }
31
+ var NeatlogsTraceProcessor = class {
32
+ _spans = /* @__PURE__ */ new Map();
33
+ _startTimes = /* @__PURE__ */ new Map();
34
+ // The @openai/agents SDK passes a Trace object: { traceId, name, groupId, metadata }.
35
+ onTraceStart(traceData) {
36
+ const tracer = import_api.trace.getTracer(TRACER_NAME);
37
+ const attrs = { "neatlogs.span.kind": "WORKFLOW" };
38
+ const workflowName = traceData?.name ?? traceData?.workflow_name;
39
+ if (workflowName) attrs["neatlogs.workflow.name"] = workflowName;
40
+ const traceId = traceData?.traceId ?? traceData?.trace_id;
41
+ if (traceId) attrs["neatlogs.agent.trace_id"] = String(traceId);
42
+ const span = tracer.startSpan("openai_agents.trace", { attributes: attrs }, import_api.context.active());
43
+ const key = String(traceId ?? `trace_${Date.now()}`);
44
+ this._spans.set(key, span);
45
+ this._startTimes.set(key, Date.now());
46
+ }
47
+ onTraceEnd(traceData) {
48
+ const key = String(traceData?.traceId ?? traceData?.trace_id ?? "");
49
+ const span = this._spans.get(key);
50
+ if (!span) return;
51
+ const startTime = this._startTimes.get(key);
52
+ if (startTime) {
53
+ span.setAttribute("neatlogs.metrics.duration_ms", Date.now() - startTime);
54
+ }
55
+ span.setStatus({ code: import_api.SpanStatusCode.OK });
56
+ span.end();
57
+ this._spans.delete(key);
58
+ this._startTimes.delete(key);
59
+ }
60
+ // The SDK passes a Span object: { type, spanId, traceId, parentId?, spanData: {...} }.
61
+ // The meaningful payload (type, name, input, output, usage, ...) lives in `spanData`.
62
+ onSpanStart(span) {
63
+ const tracer = import_api.trace.getTracer(TRACER_NAME);
64
+ const data = span?.spanData ?? span ?? {};
65
+ const spanType = data?.type ?? data?.span_type ?? span?.type ?? "";
66
+ const spanId = String(span?.spanId ?? span?.span_id ?? data?.span_id ?? `span_${Date.now()}`);
67
+ const parentKey = String(span?.parentId ?? span?.traceId ?? span?.trace_id ?? "");
68
+ const parentSpan = this._spans.get(parentKey);
69
+ const parentCtx = parentSpan ? import_api.trace.setSpan(import_api.context.active(), parentSpan) : import_api.context.active();
70
+ let otelSpan;
71
+ if (spanType === "agent" || spanType === "agent_run") {
72
+ const agentName = data?.name ?? data?.agent_name ?? "agent";
73
+ const attrs = {
74
+ "neatlogs.span.kind": "AGENT",
75
+ "neatlogs.agent.name": agentName
76
+ };
77
+ if (Array.isArray(data?.tools) && data.tools.length) {
78
+ attrs["neatlogs.agent.available_tools"] = data.tools.join(",");
79
+ }
80
+ otelSpan = tracer.startSpan(`openai_agents.agent.${agentName}`, { attributes: attrs }, parentCtx);
81
+ } else if (spanType === "response" || spanType === "generation" || spanType === "llm") {
82
+ const attrs = {
83
+ "neatlogs.span.kind": "LLM",
84
+ "neatlogs.llm.provider": "openai"
85
+ };
86
+ const model = data?.model;
87
+ if (model) attrs["neatlogs.llm.model_name"] = model;
88
+ const inputMsgs = data?.input ?? data?.messages;
89
+ if (inputMsgs && Array.isArray(inputMsgs)) {
90
+ for (let i = 0; i < inputMsgs.length; i++) {
91
+ const msg = inputMsgs[i];
92
+ const role = typeof msg === "object" ? msg.role ?? "" : "";
93
+ const content = typeof msg === "object" ? msg.content ?? "" : String(msg);
94
+ if (role) attrs[`neatlogs.llm.input_messages.${i}.role`] = role;
95
+ if (content) attrs[`neatlogs.llm.input_messages.${i}.content`] = (typeof content === "string" ? content : safeStringify(content)).slice(0, 1e4);
96
+ }
97
+ }
98
+ otelSpan = tracer.startSpan("openai_agents.generation", { attributes: attrs }, parentCtx);
99
+ } else if (spanType === "function" || spanType === "tool" || spanType === "tool_call") {
100
+ const toolName = data?.name ?? data?.function_name ?? "tool";
101
+ const attrs = {
102
+ "neatlogs.span.kind": "TOOL",
103
+ "neatlogs.tool.name": toolName
104
+ };
105
+ const toolInput = data?.input ?? data?.arguments;
106
+ if (toolInput !== void 0) {
107
+ attrs["input.value"] = (typeof toolInput === "string" ? toolInput : safeStringify(toolInput)).slice(0, 1e4);
108
+ }
109
+ otelSpan = tracer.startSpan(`openai_agents.tool.${toolName}`, { attributes: attrs }, parentCtx);
110
+ } else if (spanType === "handoff") {
111
+ const attrs = { "neatlogs.span.kind": "AGENT" };
112
+ if (data?.from_agent) attrs["neatlogs.agent.handoff_from"] = String(data.from_agent);
113
+ if (data?.to_agent) attrs["neatlogs.agent.name"] = String(data.to_agent);
114
+ otelSpan = tracer.startSpan("openai_agents.handoff", { attributes: attrs }, parentCtx);
115
+ } else {
116
+ const attrs = { "neatlogs.span.kind": "CHAIN" };
117
+ otelSpan = tracer.startSpan(`openai_agents.${spanType || "span"}`, { attributes: attrs }, parentCtx);
118
+ }
119
+ this._spans.set(spanId, otelSpan);
120
+ this._startTimes.set(spanId, Date.now());
121
+ }
122
+ onSpanEnd(span) {
123
+ const data = span?.spanData ?? span ?? {};
124
+ const spanId = String(span?.spanId ?? span?.span_id ?? data?.span_id ?? "");
125
+ const otelSpan = this._spans.get(spanId);
126
+ if (!otelSpan) return;
127
+ const spanType = data?.type ?? data?.span_type ?? span?.type ?? "";
128
+ const startTime = this._startTimes.get(spanId);
129
+ if (spanType === "response" || spanType === "generation" || spanType === "llm") {
130
+ const resp = data?._response ?? data?.response ?? {};
131
+ const model = data?.model ?? resp?.model;
132
+ if (model) otelSpan.setAttribute("neatlogs.llm.model_name", model);
133
+ const outputItems = data?.output ?? resp?.output;
134
+ if (Array.isArray(outputItems)) {
135
+ const text = outputItems.filter((o) => o?.type === "message" || o?.role === "assistant").flatMap((o) => Array.isArray(o.content) ? o.content : [o.content]).map((c) => typeof c === "string" ? c : c?.text ?? "").join("");
136
+ if (text) {
137
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
138
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.content", text.slice(0, 1e4));
139
+ }
140
+ const toolCalls = outputItems.filter((o) => o?.type === "function_call");
141
+ for (let i = 0; i < toolCalls.length; i++) {
142
+ const tc = toolCalls[i];
143
+ otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, tc.name ?? "");
144
+ otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, typeof tc.arguments === "string" ? tc.arguments : safeStringify(tc.arguments ?? {}));
145
+ if (tc.callId ?? tc.id) otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, tc.callId ?? tc.id);
146
+ }
147
+ } else if (outputItems?.content) {
148
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
149
+ const c = outputItems.content;
150
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.content", (typeof c === "string" ? c : safeStringify(c)).slice(0, 1e4));
151
+ }
152
+ const usage = data?.usage ?? resp?.usage;
153
+ if (usage) {
154
+ const inputTokens = usage.input_tokens ?? usage.prompt_tokens ?? usage.inputTokens;
155
+ const outputTokens = usage.output_tokens ?? usage.completion_tokens ?? usage.outputTokens;
156
+ const totalTokens = usage.total_tokens ?? usage.totalTokens;
157
+ if (inputTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.prompt", inputTokens);
158
+ if (outputTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.completion", outputTokens);
159
+ if (totalTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.total", totalTokens);
160
+ else if (inputTokens != null && outputTokens != null) {
161
+ otelSpan.setAttribute("neatlogs.llm.token_count.total", inputTokens + outputTokens);
162
+ }
163
+ }
164
+ } else if (spanType === "function" || spanType === "tool" || spanType === "tool_call") {
165
+ const output = data?.output ?? data?.result;
166
+ if (output != null) {
167
+ otelSpan.setAttribute("output.value", (typeof output === "string" ? output : safeStringify(output)).slice(0, 1e4));
168
+ }
169
+ } else if (spanType === "agent" || spanType === "agent_run") {
170
+ const output = data?.output;
171
+ if (output != null) {
172
+ otelSpan.setAttribute("output.value", (typeof output === "string" ? output : safeStringify(output)).slice(0, 1e4));
173
+ }
174
+ }
175
+ const error = data?.error ?? span?.error;
176
+ if (error) {
177
+ if (error instanceof Error) {
178
+ otelSpan.setStatus({ code: import_api.SpanStatusCode.ERROR, message: error.message });
179
+ otelSpan.recordException(error);
180
+ } else {
181
+ otelSpan.setStatus({ code: import_api.SpanStatusCode.ERROR, message: String(error) });
182
+ }
183
+ } else {
184
+ otelSpan.setStatus({ code: import_api.SpanStatusCode.OK });
185
+ }
186
+ if (startTime) {
187
+ otelSpan.setAttribute("neatlogs.llm.metrics.duration_ms", Date.now() - startTime);
188
+ }
189
+ otelSpan.end();
190
+ this._spans.delete(spanId);
191
+ this._startTimes.delete(spanId);
192
+ }
193
+ shutdown() {
194
+ for (const [, span] of this._spans) {
195
+ span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: "Processor shutdown before span completed" });
196
+ span.end();
197
+ }
198
+ this._spans.clear();
199
+ this._startTimes.clear();
200
+ }
201
+ forceFlush() {
202
+ }
203
+ };
204
+ function safeStringify(value) {
205
+ try {
206
+ return typeof value === "string" ? value : JSON.stringify(value);
207
+ } catch {
208
+ return "";
209
+ }
210
+ }
211
+ // Annotate the CommonJS export names for ESM import in node:
212
+ 0 && (module.exports = {
213
+ openaiAgentsProcessor
214
+ });
215
+ //# sourceMappingURL=openai-agents.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/openai-agents.ts"],"sourcesContent":["/**\n * Neatlogs OpenAI Agents SDK trace processor.\n *\n * Usage:\n * import { openaiAgentsProcessor } from 'neatlogs/openai-agents';\n * import { addTraceProcessor } from '@openai/agents';\n * addTraceProcessor(openaiAgentsProcessor());\n *\n * Creates spans: WORKFLOW (traces), AGENT (agent runs), LLM (generations), TOOL (function calls).\n */\n\nimport { trace, context as otelContext, SpanStatusCode, type Span } from '@opentelemetry/api';\n\nconst TRACER_NAME = 'neatlogs.openai_agents';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport function openaiAgentsProcessor(): any {\n return new NeatlogsTraceProcessor();\n}\n\n// ---------------------------------------------------------------------------\n// Trace Processor (implements OpenAI Agents SDK TracingProcessor protocol)\n// ---------------------------------------------------------------------------\n\nclass NeatlogsTraceProcessor {\n private _spans: Map<string, Span> = new Map();\n private _startTimes: Map<string, number> = new Map();\n\n // The @openai/agents SDK passes a Trace object: { traceId, name, groupId, metadata }.\n onTraceStart(traceData: any): void {\n const tracer = trace.getTracer(TRACER_NAME);\n const attrs: Record<string, any> = { 'neatlogs.span.kind': 'WORKFLOW' };\n\n const workflowName = traceData?.name ?? traceData?.workflow_name;\n if (workflowName) attrs['neatlogs.workflow.name'] = workflowName;\n\n const traceId = traceData?.traceId ?? traceData?.trace_id;\n if (traceId) attrs['neatlogs.agent.trace_id'] = String(traceId);\n\n const span = tracer.startSpan('openai_agents.trace', { attributes: attrs }, otelContext.active());\n const key = String(traceId ?? `trace_${Date.now()}`);\n this._spans.set(key, span);\n this._startTimes.set(key, Date.now());\n }\n\n onTraceEnd(traceData: any): void {\n const key = String(traceData?.traceId ?? traceData?.trace_id ?? '');\n const span = this._spans.get(key);\n if (!span) return;\n\n const startTime = this._startTimes.get(key);\n if (startTime) {\n span.setAttribute('neatlogs.metrics.duration_ms', Date.now() - startTime);\n }\n\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n this._spans.delete(key);\n this._startTimes.delete(key);\n }\n\n // The SDK passes a Span object: { type, spanId, traceId, parentId?, spanData: {...} }.\n // The meaningful payload (type, name, input, output, usage, ...) lives in `spanData`.\n onSpanStart(span: any): void {\n const tracer = trace.getTracer(TRACER_NAME);\n const data = span?.spanData ?? span ?? {};\n const spanType = data?.type ?? data?.span_type ?? span?.type ?? '';\n const spanId = String(span?.spanId ?? span?.span_id ?? data?.span_id ?? `span_${Date.now()}`);\n\n // Parent context: nest under the trace span (or a parent span) so the tree forms.\n const parentKey = String(span?.parentId ?? span?.traceId ?? span?.trace_id ?? '');\n const parentSpan = this._spans.get(parentKey);\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n let otelSpan: Span;\n\n if (spanType === 'agent' || spanType === 'agent_run') {\n const agentName = data?.name ?? data?.agent_name ?? 'agent';\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'AGENT',\n 'neatlogs.agent.name': agentName,\n };\n if (Array.isArray(data?.tools) && data.tools.length) {\n attrs['neatlogs.agent.available_tools'] = data.tools.join(',');\n }\n otelSpan = tracer.startSpan(`openai_agents.agent.${agentName}`, { attributes: attrs }, parentCtx);\n\n } else if (spanType === 'response' || spanType === 'generation' || spanType === 'llm') {\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'LLM',\n 'neatlogs.llm.provider': 'openai',\n };\n\n const model = data?.model;\n if (model) attrs['neatlogs.llm.model_name'] = model;\n\n const inputMsgs = data?.input ?? data?.messages;\n if (inputMsgs && Array.isArray(inputMsgs)) {\n for (let i = 0; i < inputMsgs.length; i++) {\n const msg = inputMsgs[i];\n const role = typeof msg === 'object' ? (msg.role ?? '') : '';\n const content = typeof msg === 'object' ? (msg.content ?? '') : String(msg);\n if (role) attrs[`neatlogs.llm.input_messages.${i}.role`] = role;\n if (content) attrs[`neatlogs.llm.input_messages.${i}.content`] = (typeof content === 'string' ? content : safeStringify(content)).slice(0, 10000);\n }\n }\n\n otelSpan = tracer.startSpan('openai_agents.generation', { attributes: attrs }, parentCtx);\n\n } else if (spanType === 'function' || spanType === 'tool' || spanType === 'tool_call') {\n const toolName = data?.name ?? data?.function_name ?? 'tool';\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'TOOL',\n 'neatlogs.tool.name': toolName,\n };\n\n const toolInput = data?.input ?? data?.arguments;\n if (toolInput !== undefined) {\n attrs['input.value'] = (typeof toolInput === 'string' ? toolInput : safeStringify(toolInput)).slice(0, 10000);\n }\n\n otelSpan = tracer.startSpan(`openai_agents.tool.${toolName}`, { attributes: attrs }, parentCtx);\n\n } else if (spanType === 'handoff') {\n const attrs: Record<string, any> = { 'neatlogs.span.kind': 'AGENT' };\n if (data?.from_agent) attrs['neatlogs.agent.handoff_from'] = String(data.from_agent);\n if (data?.to_agent) attrs['neatlogs.agent.name'] = String(data.to_agent);\n\n otelSpan = tracer.startSpan('openai_agents.handoff', { attributes: attrs }, parentCtx);\n\n } else {\n const attrs: Record<string, any> = { 'neatlogs.span.kind': 'CHAIN' };\n otelSpan = tracer.startSpan(`openai_agents.${spanType || 'span'}`, { attributes: attrs }, parentCtx);\n }\n\n this._spans.set(spanId, otelSpan);\n this._startTimes.set(spanId, Date.now());\n }\n\n onSpanEnd(span: any): void {\n const data = span?.spanData ?? span ?? {};\n const spanId = String(span?.spanId ?? span?.span_id ?? data?.span_id ?? '');\n const otelSpan = this._spans.get(spanId);\n if (!otelSpan) return;\n\n const spanType = data?.type ?? data?.span_type ?? span?.type ?? '';\n const startTime = this._startTimes.get(spanId);\n\n if (spanType === 'response' || spanType === 'generation' || spanType === 'llm') {\n // @openai/agents 'response' span nests the full Responses API object under\n // `_response` and the request under `_input`. Older shapes use output/usage/model directly.\n const resp = data?._response ?? data?.response ?? {};\n const model = data?.model ?? resp?.model;\n if (model) otelSpan.setAttribute('neatlogs.llm.model_name', model);\n\n // Output text: Responses API output[] has message items with content[].text\n const outputItems = data?.output ?? resp?.output;\n if (Array.isArray(outputItems)) {\n const text = outputItems\n .filter((o: any) => o?.type === 'message' || o?.role === 'assistant')\n .flatMap((o: any) => (Array.isArray(o.content) ? o.content : [o.content]))\n .map((c: any) => (typeof c === 'string' ? c : c?.text ?? ''))\n .join('');\n if (text) {\n otelSpan.setAttribute('neatlogs.llm.output_messages.0.role', 'assistant');\n otelSpan.setAttribute('neatlogs.llm.output_messages.0.content', text.slice(0, 10000));\n }\n // Tool-call items advertised in the response output\n const toolCalls = outputItems.filter((o: any) => o?.type === 'function_call');\n for (let i = 0; i < toolCalls.length; i++) {\n const tc = toolCalls[i];\n otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, tc.name ?? '');\n otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, typeof tc.arguments === 'string' ? tc.arguments : safeStringify(tc.arguments ?? {}));\n if (tc.callId ?? tc.id) otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, tc.callId ?? tc.id);\n }\n } else if (outputItems?.content) {\n otelSpan.setAttribute('neatlogs.llm.output_messages.0.role', 'assistant');\n const c = outputItems.content;\n otelSpan.setAttribute('neatlogs.llm.output_messages.0.content', (typeof c === 'string' ? c : safeStringify(c)).slice(0, 10000));\n }\n\n const usage = data?.usage ?? resp?.usage;\n if (usage) {\n const inputTokens = usage.input_tokens ?? usage.prompt_tokens ?? usage.inputTokens;\n const outputTokens = usage.output_tokens ?? usage.completion_tokens ?? usage.outputTokens;\n const totalTokens = usage.total_tokens ?? usage.totalTokens;\n if (inputTokens != null) otelSpan.setAttribute('neatlogs.llm.token_count.prompt', inputTokens);\n if (outputTokens != null) otelSpan.setAttribute('neatlogs.llm.token_count.completion', outputTokens);\n if (totalTokens != null) otelSpan.setAttribute('neatlogs.llm.token_count.total', totalTokens);\n else if (inputTokens != null && outputTokens != null) {\n otelSpan.setAttribute('neatlogs.llm.token_count.total', inputTokens + outputTokens);\n }\n }\n\n } else if (spanType === 'function' || spanType === 'tool' || spanType === 'tool_call') {\n const output = data?.output ?? data?.result;\n if (output != null) {\n otelSpan.setAttribute('output.value', (typeof output === 'string' ? output : safeStringify(output)).slice(0, 10000));\n }\n\n } else if (spanType === 'agent' || spanType === 'agent_run') {\n const output = data?.output;\n if (output != null) {\n otelSpan.setAttribute('output.value', (typeof output === 'string' ? output : safeStringify(output)).slice(0, 10000));\n }\n }\n\n const error = data?.error ?? span?.error;\n if (error) {\n if (error instanceof Error) {\n otelSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n otelSpan.recordException(error);\n } else {\n otelSpan.setStatus({ code: SpanStatusCode.ERROR, message: String(error) });\n }\n } else {\n otelSpan.setStatus({ code: SpanStatusCode.OK });\n }\n\n if (startTime) {\n otelSpan.setAttribute('neatlogs.llm.metrics.duration_ms', Date.now() - startTime);\n }\n\n otelSpan.end();\n this._spans.delete(spanId);\n this._startTimes.delete(spanId);\n }\n\n shutdown(): void {\n for (const [, span] of this._spans) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: 'Processor shutdown before span completed' });\n span.end();\n }\n this._spans.clear();\n this._startTimes.clear();\n }\n\n forceFlush(): void {}\n}\n\n// ---------------------------------------------------------------------------\n// Utilities\n// ---------------------------------------------------------------------------\n\nfunction safeStringify(value: unknown): string {\n try {\n return typeof value === 'string' ? value : JSON.stringify(value);\n } catch {\n return '';\n }\n}\n"],"mappings":"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","names":["otelContext"]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Neatlogs OpenAI Agents SDK trace processor.
3
+ *
4
+ * Usage:
5
+ * import { openaiAgentsProcessor } from 'neatlogs/openai-agents';
6
+ * import { addTraceProcessor } from '@openai/agents';
7
+ * addTraceProcessor(openaiAgentsProcessor());
8
+ *
9
+ * Creates spans: WORKFLOW (traces), AGENT (agent runs), LLM (generations), TOOL (function calls).
10
+ */
11
+ declare function openaiAgentsProcessor(): any;
12
+
13
+ export { openaiAgentsProcessor };
@@ -0,0 +1,190 @@
1
+ // src/openai-agents.ts
2
+ import { trace, context as otelContext, SpanStatusCode } from "@opentelemetry/api";
3
+ var TRACER_NAME = "neatlogs.openai_agents";
4
+ function openaiAgentsProcessor() {
5
+ return new NeatlogsTraceProcessor();
6
+ }
7
+ var NeatlogsTraceProcessor = class {
8
+ _spans = /* @__PURE__ */ new Map();
9
+ _startTimes = /* @__PURE__ */ new Map();
10
+ // The @openai/agents SDK passes a Trace object: { traceId, name, groupId, metadata }.
11
+ onTraceStart(traceData) {
12
+ const tracer = trace.getTracer(TRACER_NAME);
13
+ const attrs = { "neatlogs.span.kind": "WORKFLOW" };
14
+ const workflowName = traceData?.name ?? traceData?.workflow_name;
15
+ if (workflowName) attrs["neatlogs.workflow.name"] = workflowName;
16
+ const traceId = traceData?.traceId ?? traceData?.trace_id;
17
+ if (traceId) attrs["neatlogs.agent.trace_id"] = String(traceId);
18
+ const span = tracer.startSpan("openai_agents.trace", { attributes: attrs }, otelContext.active());
19
+ const key = String(traceId ?? `trace_${Date.now()}`);
20
+ this._spans.set(key, span);
21
+ this._startTimes.set(key, Date.now());
22
+ }
23
+ onTraceEnd(traceData) {
24
+ const key = String(traceData?.traceId ?? traceData?.trace_id ?? "");
25
+ const span = this._spans.get(key);
26
+ if (!span) return;
27
+ const startTime = this._startTimes.get(key);
28
+ if (startTime) {
29
+ span.setAttribute("neatlogs.metrics.duration_ms", Date.now() - startTime);
30
+ }
31
+ span.setStatus({ code: SpanStatusCode.OK });
32
+ span.end();
33
+ this._spans.delete(key);
34
+ this._startTimes.delete(key);
35
+ }
36
+ // The SDK passes a Span object: { type, spanId, traceId, parentId?, spanData: {...} }.
37
+ // The meaningful payload (type, name, input, output, usage, ...) lives in `spanData`.
38
+ onSpanStart(span) {
39
+ const tracer = trace.getTracer(TRACER_NAME);
40
+ const data = span?.spanData ?? span ?? {};
41
+ const spanType = data?.type ?? data?.span_type ?? span?.type ?? "";
42
+ const spanId = String(span?.spanId ?? span?.span_id ?? data?.span_id ?? `span_${Date.now()}`);
43
+ const parentKey = String(span?.parentId ?? span?.traceId ?? span?.trace_id ?? "");
44
+ const parentSpan = this._spans.get(parentKey);
45
+ const parentCtx = parentSpan ? trace.setSpan(otelContext.active(), parentSpan) : otelContext.active();
46
+ let otelSpan;
47
+ if (spanType === "agent" || spanType === "agent_run") {
48
+ const agentName = data?.name ?? data?.agent_name ?? "agent";
49
+ const attrs = {
50
+ "neatlogs.span.kind": "AGENT",
51
+ "neatlogs.agent.name": agentName
52
+ };
53
+ if (Array.isArray(data?.tools) && data.tools.length) {
54
+ attrs["neatlogs.agent.available_tools"] = data.tools.join(",");
55
+ }
56
+ otelSpan = tracer.startSpan(`openai_agents.agent.${agentName}`, { attributes: attrs }, parentCtx);
57
+ } else if (spanType === "response" || spanType === "generation" || spanType === "llm") {
58
+ const attrs = {
59
+ "neatlogs.span.kind": "LLM",
60
+ "neatlogs.llm.provider": "openai"
61
+ };
62
+ const model = data?.model;
63
+ if (model) attrs["neatlogs.llm.model_name"] = model;
64
+ const inputMsgs = data?.input ?? data?.messages;
65
+ if (inputMsgs && Array.isArray(inputMsgs)) {
66
+ for (let i = 0; i < inputMsgs.length; i++) {
67
+ const msg = inputMsgs[i];
68
+ const role = typeof msg === "object" ? msg.role ?? "" : "";
69
+ const content = typeof msg === "object" ? msg.content ?? "" : String(msg);
70
+ if (role) attrs[`neatlogs.llm.input_messages.${i}.role`] = role;
71
+ if (content) attrs[`neatlogs.llm.input_messages.${i}.content`] = (typeof content === "string" ? content : safeStringify(content)).slice(0, 1e4);
72
+ }
73
+ }
74
+ otelSpan = tracer.startSpan("openai_agents.generation", { attributes: attrs }, parentCtx);
75
+ } else if (spanType === "function" || spanType === "tool" || spanType === "tool_call") {
76
+ const toolName = data?.name ?? data?.function_name ?? "tool";
77
+ const attrs = {
78
+ "neatlogs.span.kind": "TOOL",
79
+ "neatlogs.tool.name": toolName
80
+ };
81
+ const toolInput = data?.input ?? data?.arguments;
82
+ if (toolInput !== void 0) {
83
+ attrs["input.value"] = (typeof toolInput === "string" ? toolInput : safeStringify(toolInput)).slice(0, 1e4);
84
+ }
85
+ otelSpan = tracer.startSpan(`openai_agents.tool.${toolName}`, { attributes: attrs }, parentCtx);
86
+ } else if (spanType === "handoff") {
87
+ const attrs = { "neatlogs.span.kind": "AGENT" };
88
+ if (data?.from_agent) attrs["neatlogs.agent.handoff_from"] = String(data.from_agent);
89
+ if (data?.to_agent) attrs["neatlogs.agent.name"] = String(data.to_agent);
90
+ otelSpan = tracer.startSpan("openai_agents.handoff", { attributes: attrs }, parentCtx);
91
+ } else {
92
+ const attrs = { "neatlogs.span.kind": "CHAIN" };
93
+ otelSpan = tracer.startSpan(`openai_agents.${spanType || "span"}`, { attributes: attrs }, parentCtx);
94
+ }
95
+ this._spans.set(spanId, otelSpan);
96
+ this._startTimes.set(spanId, Date.now());
97
+ }
98
+ onSpanEnd(span) {
99
+ const data = span?.spanData ?? span ?? {};
100
+ const spanId = String(span?.spanId ?? span?.span_id ?? data?.span_id ?? "");
101
+ const otelSpan = this._spans.get(spanId);
102
+ if (!otelSpan) return;
103
+ const spanType = data?.type ?? data?.span_type ?? span?.type ?? "";
104
+ const startTime = this._startTimes.get(spanId);
105
+ if (spanType === "response" || spanType === "generation" || spanType === "llm") {
106
+ const resp = data?._response ?? data?.response ?? {};
107
+ const model = data?.model ?? resp?.model;
108
+ if (model) otelSpan.setAttribute("neatlogs.llm.model_name", model);
109
+ const outputItems = data?.output ?? resp?.output;
110
+ if (Array.isArray(outputItems)) {
111
+ const text = outputItems.filter((o) => o?.type === "message" || o?.role === "assistant").flatMap((o) => Array.isArray(o.content) ? o.content : [o.content]).map((c) => typeof c === "string" ? c : c?.text ?? "").join("");
112
+ if (text) {
113
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
114
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.content", text.slice(0, 1e4));
115
+ }
116
+ const toolCalls = outputItems.filter((o) => o?.type === "function_call");
117
+ for (let i = 0; i < toolCalls.length; i++) {
118
+ const tc = toolCalls[i];
119
+ otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, tc.name ?? "");
120
+ otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, typeof tc.arguments === "string" ? tc.arguments : safeStringify(tc.arguments ?? {}));
121
+ if (tc.callId ?? tc.id) otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, tc.callId ?? tc.id);
122
+ }
123
+ } else if (outputItems?.content) {
124
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
125
+ const c = outputItems.content;
126
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.content", (typeof c === "string" ? c : safeStringify(c)).slice(0, 1e4));
127
+ }
128
+ const usage = data?.usage ?? resp?.usage;
129
+ if (usage) {
130
+ const inputTokens = usage.input_tokens ?? usage.prompt_tokens ?? usage.inputTokens;
131
+ const outputTokens = usage.output_tokens ?? usage.completion_tokens ?? usage.outputTokens;
132
+ const totalTokens = usage.total_tokens ?? usage.totalTokens;
133
+ if (inputTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.prompt", inputTokens);
134
+ if (outputTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.completion", outputTokens);
135
+ if (totalTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.total", totalTokens);
136
+ else if (inputTokens != null && outputTokens != null) {
137
+ otelSpan.setAttribute("neatlogs.llm.token_count.total", inputTokens + outputTokens);
138
+ }
139
+ }
140
+ } else if (spanType === "function" || spanType === "tool" || spanType === "tool_call") {
141
+ const output = data?.output ?? data?.result;
142
+ if (output != null) {
143
+ otelSpan.setAttribute("output.value", (typeof output === "string" ? output : safeStringify(output)).slice(0, 1e4));
144
+ }
145
+ } else if (spanType === "agent" || spanType === "agent_run") {
146
+ const output = data?.output;
147
+ if (output != null) {
148
+ otelSpan.setAttribute("output.value", (typeof output === "string" ? output : safeStringify(output)).slice(0, 1e4));
149
+ }
150
+ }
151
+ const error = data?.error ?? span?.error;
152
+ if (error) {
153
+ if (error instanceof Error) {
154
+ otelSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
155
+ otelSpan.recordException(error);
156
+ } else {
157
+ otelSpan.setStatus({ code: SpanStatusCode.ERROR, message: String(error) });
158
+ }
159
+ } else {
160
+ otelSpan.setStatus({ code: SpanStatusCode.OK });
161
+ }
162
+ if (startTime) {
163
+ otelSpan.setAttribute("neatlogs.llm.metrics.duration_ms", Date.now() - startTime);
164
+ }
165
+ otelSpan.end();
166
+ this._spans.delete(spanId);
167
+ this._startTimes.delete(spanId);
168
+ }
169
+ shutdown() {
170
+ for (const [, span] of this._spans) {
171
+ span.setStatus({ code: SpanStatusCode.ERROR, message: "Processor shutdown before span completed" });
172
+ span.end();
173
+ }
174
+ this._spans.clear();
175
+ this._startTimes.clear();
176
+ }
177
+ forceFlush() {
178
+ }
179
+ };
180
+ function safeStringify(value) {
181
+ try {
182
+ return typeof value === "string" ? value : JSON.stringify(value);
183
+ } catch {
184
+ return "";
185
+ }
186
+ }
187
+ export {
188
+ openaiAgentsProcessor
189
+ };
190
+ //# sourceMappingURL=openai-agents.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/openai-agents.ts"],"sourcesContent":["/**\n * Neatlogs OpenAI Agents SDK trace processor.\n *\n * Usage:\n * import { openaiAgentsProcessor } from 'neatlogs/openai-agents';\n * import { addTraceProcessor } from '@openai/agents';\n * addTraceProcessor(openaiAgentsProcessor());\n *\n * Creates spans: WORKFLOW (traces), AGENT (agent runs), LLM (generations), TOOL (function calls).\n */\n\nimport { trace, context as otelContext, SpanStatusCode, type Span } from '@opentelemetry/api';\n\nconst TRACER_NAME = 'neatlogs.openai_agents';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport function openaiAgentsProcessor(): any {\n return new NeatlogsTraceProcessor();\n}\n\n// ---------------------------------------------------------------------------\n// Trace Processor (implements OpenAI Agents SDK TracingProcessor protocol)\n// ---------------------------------------------------------------------------\n\nclass NeatlogsTraceProcessor {\n private _spans: Map<string, Span> = new Map();\n private _startTimes: Map<string, number> = new Map();\n\n // The @openai/agents SDK passes a Trace object: { traceId, name, groupId, metadata }.\n onTraceStart(traceData: any): void {\n const tracer = trace.getTracer(TRACER_NAME);\n const attrs: Record<string, any> = { 'neatlogs.span.kind': 'WORKFLOW' };\n\n const workflowName = traceData?.name ?? traceData?.workflow_name;\n if (workflowName) attrs['neatlogs.workflow.name'] = workflowName;\n\n const traceId = traceData?.traceId ?? traceData?.trace_id;\n if (traceId) attrs['neatlogs.agent.trace_id'] = String(traceId);\n\n const span = tracer.startSpan('openai_agents.trace', { attributes: attrs }, otelContext.active());\n const key = String(traceId ?? `trace_${Date.now()}`);\n this._spans.set(key, span);\n this._startTimes.set(key, Date.now());\n }\n\n onTraceEnd(traceData: any): void {\n const key = String(traceData?.traceId ?? traceData?.trace_id ?? '');\n const span = this._spans.get(key);\n if (!span) return;\n\n const startTime = this._startTimes.get(key);\n if (startTime) {\n span.setAttribute('neatlogs.metrics.duration_ms', Date.now() - startTime);\n }\n\n span.setStatus({ code: SpanStatusCode.OK });\n span.end();\n this._spans.delete(key);\n this._startTimes.delete(key);\n }\n\n // The SDK passes a Span object: { type, spanId, traceId, parentId?, spanData: {...} }.\n // The meaningful payload (type, name, input, output, usage, ...) lives in `spanData`.\n onSpanStart(span: any): void {\n const tracer = trace.getTracer(TRACER_NAME);\n const data = span?.spanData ?? span ?? {};\n const spanType = data?.type ?? data?.span_type ?? span?.type ?? '';\n const spanId = String(span?.spanId ?? span?.span_id ?? data?.span_id ?? `span_${Date.now()}`);\n\n // Parent context: nest under the trace span (or a parent span) so the tree forms.\n const parentKey = String(span?.parentId ?? span?.traceId ?? span?.trace_id ?? '');\n const parentSpan = this._spans.get(parentKey);\n const parentCtx = parentSpan\n ? trace.setSpan(otelContext.active(), parentSpan)\n : otelContext.active();\n\n let otelSpan: Span;\n\n if (spanType === 'agent' || spanType === 'agent_run') {\n const agentName = data?.name ?? data?.agent_name ?? 'agent';\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'AGENT',\n 'neatlogs.agent.name': agentName,\n };\n if (Array.isArray(data?.tools) && data.tools.length) {\n attrs['neatlogs.agent.available_tools'] = data.tools.join(',');\n }\n otelSpan = tracer.startSpan(`openai_agents.agent.${agentName}`, { attributes: attrs }, parentCtx);\n\n } else if (spanType === 'response' || spanType === 'generation' || spanType === 'llm') {\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'LLM',\n 'neatlogs.llm.provider': 'openai',\n };\n\n const model = data?.model;\n if (model) attrs['neatlogs.llm.model_name'] = model;\n\n const inputMsgs = data?.input ?? data?.messages;\n if (inputMsgs && Array.isArray(inputMsgs)) {\n for (let i = 0; i < inputMsgs.length; i++) {\n const msg = inputMsgs[i];\n const role = typeof msg === 'object' ? (msg.role ?? '') : '';\n const content = typeof msg === 'object' ? (msg.content ?? '') : String(msg);\n if (role) attrs[`neatlogs.llm.input_messages.${i}.role`] = role;\n if (content) attrs[`neatlogs.llm.input_messages.${i}.content`] = (typeof content === 'string' ? content : safeStringify(content)).slice(0, 10000);\n }\n }\n\n otelSpan = tracer.startSpan('openai_agents.generation', { attributes: attrs }, parentCtx);\n\n } else if (spanType === 'function' || spanType === 'tool' || spanType === 'tool_call') {\n const toolName = data?.name ?? data?.function_name ?? 'tool';\n const attrs: Record<string, any> = {\n 'neatlogs.span.kind': 'TOOL',\n 'neatlogs.tool.name': toolName,\n };\n\n const toolInput = data?.input ?? data?.arguments;\n if (toolInput !== undefined) {\n attrs['input.value'] = (typeof toolInput === 'string' ? toolInput : safeStringify(toolInput)).slice(0, 10000);\n }\n\n otelSpan = tracer.startSpan(`openai_agents.tool.${toolName}`, { attributes: attrs }, parentCtx);\n\n } else if (spanType === 'handoff') {\n const attrs: Record<string, any> = { 'neatlogs.span.kind': 'AGENT' };\n if (data?.from_agent) attrs['neatlogs.agent.handoff_from'] = String(data.from_agent);\n if (data?.to_agent) attrs['neatlogs.agent.name'] = String(data.to_agent);\n\n otelSpan = tracer.startSpan('openai_agents.handoff', { attributes: attrs }, parentCtx);\n\n } else {\n const attrs: Record<string, any> = { 'neatlogs.span.kind': 'CHAIN' };\n otelSpan = tracer.startSpan(`openai_agents.${spanType || 'span'}`, { attributes: attrs }, parentCtx);\n }\n\n this._spans.set(spanId, otelSpan);\n this._startTimes.set(spanId, Date.now());\n }\n\n onSpanEnd(span: any): void {\n const data = span?.spanData ?? span ?? {};\n const spanId = String(span?.spanId ?? span?.span_id ?? data?.span_id ?? '');\n const otelSpan = this._spans.get(spanId);\n if (!otelSpan) return;\n\n const spanType = data?.type ?? data?.span_type ?? span?.type ?? '';\n const startTime = this._startTimes.get(spanId);\n\n if (spanType === 'response' || spanType === 'generation' || spanType === 'llm') {\n // @openai/agents 'response' span nests the full Responses API object under\n // `_response` and the request under `_input`. Older shapes use output/usage/model directly.\n const resp = data?._response ?? data?.response ?? {};\n const model = data?.model ?? resp?.model;\n if (model) otelSpan.setAttribute('neatlogs.llm.model_name', model);\n\n // Output text: Responses API output[] has message items with content[].text\n const outputItems = data?.output ?? resp?.output;\n if (Array.isArray(outputItems)) {\n const text = outputItems\n .filter((o: any) => o?.type === 'message' || o?.role === 'assistant')\n .flatMap((o: any) => (Array.isArray(o.content) ? o.content : [o.content]))\n .map((c: any) => (typeof c === 'string' ? c : c?.text ?? ''))\n .join('');\n if (text) {\n otelSpan.setAttribute('neatlogs.llm.output_messages.0.role', 'assistant');\n otelSpan.setAttribute('neatlogs.llm.output_messages.0.content', text.slice(0, 10000));\n }\n // Tool-call items advertised in the response output\n const toolCalls = outputItems.filter((o: any) => o?.type === 'function_call');\n for (let i = 0; i < toolCalls.length; i++) {\n const tc = toolCalls[i];\n otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, tc.name ?? '');\n otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, typeof tc.arguments === 'string' ? tc.arguments : safeStringify(tc.arguments ?? {}));\n if (tc.callId ?? tc.id) otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, tc.callId ?? tc.id);\n }\n } else if (outputItems?.content) {\n otelSpan.setAttribute('neatlogs.llm.output_messages.0.role', 'assistant');\n const c = outputItems.content;\n otelSpan.setAttribute('neatlogs.llm.output_messages.0.content', (typeof c === 'string' ? c : safeStringify(c)).slice(0, 10000));\n }\n\n const usage = data?.usage ?? resp?.usage;\n if (usage) {\n const inputTokens = usage.input_tokens ?? usage.prompt_tokens ?? usage.inputTokens;\n const outputTokens = usage.output_tokens ?? usage.completion_tokens ?? usage.outputTokens;\n const totalTokens = usage.total_tokens ?? usage.totalTokens;\n if (inputTokens != null) otelSpan.setAttribute('neatlogs.llm.token_count.prompt', inputTokens);\n if (outputTokens != null) otelSpan.setAttribute('neatlogs.llm.token_count.completion', outputTokens);\n if (totalTokens != null) otelSpan.setAttribute('neatlogs.llm.token_count.total', totalTokens);\n else if (inputTokens != null && outputTokens != null) {\n otelSpan.setAttribute('neatlogs.llm.token_count.total', inputTokens + outputTokens);\n }\n }\n\n } else if (spanType === 'function' || spanType === 'tool' || spanType === 'tool_call') {\n const output = data?.output ?? data?.result;\n if (output != null) {\n otelSpan.setAttribute('output.value', (typeof output === 'string' ? output : safeStringify(output)).slice(0, 10000));\n }\n\n } else if (spanType === 'agent' || spanType === 'agent_run') {\n const output = data?.output;\n if (output != null) {\n otelSpan.setAttribute('output.value', (typeof output === 'string' ? output : safeStringify(output)).slice(0, 10000));\n }\n }\n\n const error = data?.error ?? span?.error;\n if (error) {\n if (error instanceof Error) {\n otelSpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message });\n otelSpan.recordException(error);\n } else {\n otelSpan.setStatus({ code: SpanStatusCode.ERROR, message: String(error) });\n }\n } else {\n otelSpan.setStatus({ code: SpanStatusCode.OK });\n }\n\n if (startTime) {\n otelSpan.setAttribute('neatlogs.llm.metrics.duration_ms', Date.now() - startTime);\n }\n\n otelSpan.end();\n this._spans.delete(spanId);\n this._startTimes.delete(spanId);\n }\n\n shutdown(): void {\n for (const [, span] of this._spans) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: 'Processor shutdown before span completed' });\n span.end();\n }\n this._spans.clear();\n this._startTimes.clear();\n }\n\n forceFlush(): void {}\n}\n\n// ---------------------------------------------------------------------------\n// Utilities\n// ---------------------------------------------------------------------------\n\nfunction safeStringify(value: unknown): string {\n try {\n return typeof value === 'string' ? value : JSON.stringify(value);\n } catch {\n return '';\n }\n}\n"],"mappings":"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","names":[]}