neatlogs 1.1.6 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +16 -27
  2. package/dist/ai-sdk.cjs +142 -54
  3. package/dist/ai-sdk.cjs.map +1 -1
  4. package/dist/ai-sdk.mjs +145 -53
  5. package/dist/ai-sdk.mjs.map +1 -1
  6. package/dist/anthropic.cjs +65 -29
  7. package/dist/anthropic.cjs.map +1 -1
  8. package/dist/anthropic.mjs +73 -36
  9. package/dist/anthropic.mjs.map +1 -1
  10. package/dist/azure-openai.cjs +65 -29
  11. package/dist/azure-openai.cjs.map +1 -1
  12. package/dist/azure-openai.mjs +73 -36
  13. package/dist/azure-openai.mjs.map +1 -1
  14. package/dist/bedrock.cjs +65 -29
  15. package/dist/bedrock.cjs.map +1 -1
  16. package/dist/bedrock.mjs +73 -36
  17. package/dist/bedrock.mjs.map +1 -1
  18. package/dist/claude-agent-sdk.cjs +55 -15
  19. package/dist/claude-agent-sdk.cjs.map +1 -1
  20. package/dist/claude-agent-sdk.mjs +52 -8
  21. package/dist/claude-agent-sdk.mjs.map +1 -1
  22. package/dist/google-genai.cjs +69 -35
  23. package/dist/google-genai.cjs.map +1 -1
  24. package/dist/google-genai.mjs +77 -42
  25. package/dist/google-genai.mjs.map +1 -1
  26. package/dist/index.cjs +963 -682
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.ts +44 -2
  29. package/dist/index.mjs +893 -609
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/langchain.cjs +46 -12
  32. package/dist/langchain.cjs.map +1 -1
  33. package/dist/langchain.mjs +54 -19
  34. package/dist/langchain.mjs.map +1 -1
  35. package/dist/mastra-wrap.cjs +330 -46
  36. package/dist/mastra-wrap.cjs.map +1 -1
  37. package/dist/mastra-wrap.mjs +331 -41
  38. package/dist/mastra-wrap.mjs.map +1 -1
  39. package/dist/openai-agents.cjs +45 -9
  40. package/dist/openai-agents.cjs.map +1 -1
  41. package/dist/openai-agents.mjs +45 -5
  42. package/dist/openai-agents.mjs.map +1 -1
  43. package/dist/openai.cjs +65 -29
  44. package/dist/openai.cjs.map +1 -1
  45. package/dist/openai.mjs +73 -36
  46. package/dist/openai.mjs.map +1 -1
  47. package/dist/opencode-plugin.cjs +1 -1
  48. package/dist/opencode-plugin.cjs.map +1 -1
  49. package/dist/opencode-plugin.mjs +1 -1
  50. package/dist/opencode-plugin.mjs.map +1 -1
  51. package/dist/openrouter-agent.cjs +48 -12
  52. package/dist/openrouter-agent.cjs.map +1 -1
  53. package/dist/openrouter-agent.mjs +56 -19
  54. package/dist/openrouter-agent.mjs.map +1 -1
  55. package/dist/pi-agent.cjs +45 -9
  56. package/dist/pi-agent.cjs.map +1 -1
  57. package/dist/pi-agent.mjs +45 -6
  58. package/dist/pi-agent.mjs.map +1 -1
  59. package/dist/strands.cjs +4 -136
  60. package/dist/strands.cjs.map +1 -1
  61. package/dist/strands.d.ts +5 -24
  62. package/dist/strands.mjs +4 -136
  63. package/dist/strands.mjs.map +1 -1
  64. package/dist/vertex-ai.cjs +69 -35
  65. package/dist/vertex-ai.cjs.map +1 -1
  66. package/dist/vertex-ai.mjs +77 -42
  67. package/dist/vertex-ai.mjs.map +1 -1
  68. package/package.json +2 -7
package/dist/strands.mjs CHANGED
@@ -1,140 +1,8 @@
1
1
  // src/strands.ts
2
- var PATCH_FLAG = "_neatlogs_patched";
3
- function strandsHooks(agent) {
4
- installEventHookFromAgent(agent);
5
- if (agent && typeof agent === "object") {
6
- try {
7
- Object.defineProperty(agent, PATCH_FLAG, {
8
- value: true,
9
- enumerable: false,
10
- configurable: true
11
- });
12
- } catch {
13
- agent[PATCH_FLAG] = true;
14
- }
15
- }
16
- return agent;
17
- }
18
- function installEventHookFromAgent(agent) {
19
- const tracer = agent?._tracer;
20
- const proto = tracer ? Object.getPrototypeOf(tracer) : void 0;
21
- if (!proto || typeof proto._addEvent !== "function") return;
22
- if (proto._addEvent[PATCH_FLAG]) return;
23
- const orig = proto._addEvent;
24
- function patchedAddEvent(span, eventName, eventAttributes) {
25
- const result = orig.call(this, span, eventName, eventAttributes);
26
- try {
27
- enrichSpanFromEvent(span, eventName, eventAttributes || {});
28
- } catch {
29
- }
30
- return result;
31
- }
32
- patchedAddEvent[PATCH_FLAG] = true;
33
- proto._addEvent = patchedAddEvent;
34
- }
35
- function enrichSpanFromEvent(span, eventName, attrs) {
36
- if (!span || typeof span.setAttribute !== "function") return;
37
- if (typeof span.isRecording === "function" && !span.isRecording()) return;
38
- const isTool = readSpanOp(span) === "execute_tool";
39
- if (eventName.startsWith("gen_ai.") && eventName.endsWith(".message")) {
40
- const role = eventName.slice("gen_ai.".length, -".message".length);
41
- const content = flattenStrandsContent(attrs.content);
42
- if (content) {
43
- if (isTool) {
44
- span.setAttribute("input.value", content);
45
- span.setAttribute("neatlogs.tool.input", content);
46
- } else {
47
- appendInputMessage(span, role, content);
48
- }
49
- }
50
- return;
51
- }
52
- if (eventName === "gen_ai.choice") {
53
- const out = flattenStrandsContent(attrs.message);
54
- if (out) setOutput(span, isTool, out);
55
- return;
56
- }
57
- if (eventName === "gen_ai.client.inference.operation.details") {
58
- const out = flattenStrandsContent(attrs["gen_ai.output.messages"]);
59
- if (out) setOutput(span, isTool, out);
60
- }
61
- }
62
- function setOutput(span, isTool, out) {
63
- span.setAttribute("output.value", out);
64
- if (isTool) {
65
- span.setAttribute("neatlogs.tool.output", out);
66
- } else {
67
- span.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
68
- span.setAttribute("neatlogs.llm.output_messages.0.content", out);
69
- span.setAttribute("neatlogs.llm.output", safeStringify({ role: "assistant", content: out }));
70
- }
71
- }
72
- function appendInputMessage(span, role, content) {
73
- const idx = span.__neatlogs_in_idx ?? 0;
74
- span.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, role);
75
- span.setAttribute(`neatlogs.llm.input_messages.${idx}.content`, content);
76
- span.__neatlogs_in_idx = idx + 1;
77
- const existing = span.__neatlogs_in_msgs ?? [];
78
- existing.push({ role, content });
79
- span.__neatlogs_in_msgs = existing;
80
- const blob = safeStringify({ messages: existing });
81
- span.setAttribute("input.value", blob);
82
- span.setAttribute("neatlogs.llm.input", blob);
83
- }
84
- function readSpanOp(span) {
85
- try {
86
- const a = span.attributes;
87
- if (!a) return "";
88
- const v = typeof a.get === "function" ? a.get("gen_ai.operation.name") : a["gen_ai.operation.name"];
89
- return typeof v === "string" ? v.toLowerCase() : "";
90
- } catch {
91
- return "";
92
- }
93
- }
94
- function flattenStrandsContent(content) {
95
- if (content == null) return "";
96
- let val = content;
97
- if (typeof val === "string") {
98
- const s = val.trim();
99
- if (!(s.startsWith("[") || s.startsWith("{"))) return val;
100
- try {
101
- val = JSON.parse(s);
102
- } catch {
103
- return val;
104
- }
105
- }
106
- return flattenBlocks(val);
107
- }
108
- function flattenBlocks(val) {
109
- const items = Array.isArray(val) ? val : [val];
110
- const out = [];
111
- for (const item of items) {
112
- if (typeof item === "string") {
113
- out.push(item);
114
- continue;
115
- }
116
- if (!item || typeof item !== "object") {
117
- if (item != null) out.push(String(item));
118
- continue;
119
- }
120
- const o = item;
121
- if (typeof o.text === "string") out.push(o.text);
122
- else if (typeof o.content === "string") out.push(o.content);
123
- else if (o.toolUse) out.push(`${o.toolUse.name ?? "tool"}(${safeStringify(o.toolUse.input ?? {})})`);
124
- else if (o.toolResult) out.push(flattenBlocks(o.toolResult.content ?? o.toolResult));
125
- else if (Array.isArray(o.parts)) out.push(flattenBlocks(o.parts));
126
- else if (Array.isArray(o.content)) out.push(flattenBlocks(o.content));
127
- else out.push(safeStringify(o));
128
- }
129
- return out.filter(Boolean).join("\n");
130
- }
131
- function safeStringify(value) {
132
- if (typeof value === "string") return value;
133
- try {
134
- return JSON.stringify(value) ?? "";
135
- } catch {
136
- return "";
137
- }
2
+ function strandsHooks(_agent) {
3
+ throw new Error(
4
+ "strandsHooks() is not supported because the Strands Agents tracer creates and activates spans on the global OpenTelemetry context (context.active() / context.with()), which cannot be isolated from other tracing SDKs (Datadog, etc.)."
5
+ );
138
6
  }
139
7
  export {
140
8
  strandsHooks
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/strands.ts"],"sourcesContent":["/**\n * Neatlogs Strands Agents integration.\n *\n * Usage:\n * import { init } from 'neatlogs';\n * import { strandsHooks } from 'neatlogs/strands';\n * import { Agent } from '@strands-agents/sdk';\n *\n * await init({ apiKey, workflowName });\n * const agent = strandsHooks(new Agent({ model }));\n *\n * Strands self-instruments via native OpenTelemetry (gen_ai.* spans for agent /\n * model / tool calls), which `init()` captures and the attribute mapper classifies\n * (kind, model, token counts).\n *\n * BUT Strands records prompt/response CONTENT as OTel span EVENTS\n * (gen_ai.user.message, gen_ai.system.message, gen_ai.choice, gen_ai.tool.message,\n * gen_ai.client.inference.operation.details) — not as span attributes. neatlogs\n * renders I/O from attributes, so without help those spans show tokens but EMPTY\n * input/output. `strandsHooks()` installs a single class-level hook on Strands'\n * own `Tracer._addEvent` chokepoint: after Strands records a message/choice event,\n * we also copy its content onto the span as input.value / output.value (+ the LLM\n * message attributes). We do NOT create spans — Strands' native tracing stays the\n * source of truth; we only enrich it. Mirrors the Python SDK's strands hook.\n */\n\nconst PATCH_FLAG = '_neatlogs_patched';\n\nexport function strandsHooks<T extends object>(agent: T): T {\n // Each Strands Agent constructs its OWN private Tracer (`agent._tracer = new\n // Tracer(...)`), and the Tracer class is NOT publicly exported — so we reach it\n // through the agent instance and patch its `_addEvent` chokepoint. Patching the\n // PROTOTYPE (reached via the instance) covers every agent sharing that class and\n // is idempotent. This is the only access path: the package's exports map blocks\n // deep imports and the top-level index doesn't export Tracer.\n installEventHookFromAgent(agent);\n\n if (agent && typeof agent === 'object') {\n try {\n Object.defineProperty(agent, PATCH_FLAG, {\n value: true,\n enumerable: false,\n configurable: true,\n });\n } catch {\n (agent as any)[PATCH_FLAG] = true;\n }\n }\n return agent;\n}\n\nfunction installEventHookFromAgent(agent: any): void {\n const tracer = agent?._tracer;\n const proto = tracer ? Object.getPrototypeOf(tracer) : undefined;\n if (!proto || typeof proto._addEvent !== 'function') return;\n if (proto._addEvent[PATCH_FLAG]) return;\n\n const orig = proto._addEvent;\n function patchedAddEvent(this: any, span: any, eventName: string, eventAttributes?: Record<string, unknown>) {\n const result = orig.call(this, span, eventName, eventAttributes);\n try {\n enrichSpanFromEvent(span, eventName, eventAttributes || {});\n } catch {\n // never break the agent run over tracing\n }\n return result;\n }\n (patchedAddEvent as any)[PATCH_FLAG] = true;\n proto._addEvent = patchedAddEvent;\n}\n\nfunction enrichSpanFromEvent(\n span: any,\n eventName: string,\n attrs: Record<string, unknown>,\n): void {\n if (!span || typeof span.setAttribute !== 'function') return;\n if (typeof span.isRecording === 'function' && !span.isRecording()) return;\n\n // Classify from the span's own gen_ai.operation.name (set at creation): the same\n // message/choice events fire on chat (LLM), execute_tool (TOOL) and agent spans.\n // We don't set neatlogs.span.kind (the mapper does, from the span name); we only\n // route I/O to the correct namespace so a {span_kind}-templated key isn't needed.\n const isTool = readSpanOp(span) === 'execute_tool';\n\n // Input-side messages: gen_ai.{system,user,assistant,tool}.message\n if (eventName.startsWith('gen_ai.') && eventName.endsWith('.message')) {\n const role = eventName.slice('gen_ai.'.length, -'.message'.length);\n const content = flattenStrandsContent(attrs.content);\n if (content) {\n if (isTool) {\n span.setAttribute('input.value', content);\n span.setAttribute('neatlogs.tool.input', content);\n } else {\n appendInputMessage(span, role, content);\n }\n }\n return;\n }\n\n // Output: legacy gen_ai.choice or the latest-convention details event.\n if (eventName === 'gen_ai.choice') {\n const out = flattenStrandsContent(attrs.message);\n if (out) setOutput(span, isTool, out);\n return;\n }\n if (eventName === 'gen_ai.client.inference.operation.details') {\n const out = flattenStrandsContent(attrs['gen_ai.output.messages']);\n if (out) setOutput(span, isTool, out);\n }\n}\n\nfunction setOutput(span: any, isTool: boolean, out: string): void {\n span.setAttribute('output.value', out);\n if (isTool) {\n span.setAttribute('neatlogs.tool.output', out);\n } else {\n span.setAttribute('neatlogs.llm.output_messages.0.role', 'assistant');\n span.setAttribute('neatlogs.llm.output_messages.0.content', out);\n span.setAttribute('neatlogs.llm.output', safeStringify({ role: 'assistant', content: out }));\n }\n}\n\nfunction appendInputMessage(span: any, role: string, content: string): void {\n const idx = (span.__neatlogs_in_idx as number) ?? 0;\n span.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, role);\n span.setAttribute(`neatlogs.llm.input_messages.${idx}.content`, content);\n span.__neatlogs_in_idx = idx + 1;\n const existing: Array<{ role: string; content: string }> = span.__neatlogs_in_msgs ?? [];\n existing.push({ role, content });\n span.__neatlogs_in_msgs = existing;\n const blob = safeStringify({ messages: existing });\n span.setAttribute('input.value', blob);\n // Flat LLM input the backend reads directly (no reliance on {span_kind} mapping).\n span.setAttribute('neatlogs.llm.input', blob);\n}\n\nfunction readSpanOp(span: any): string {\n // OTel spans don't expose attributes publicly; Strands' span objects carry them\n // on `.attributes`. Best-effort read of gen_ai.operation.name.\n try {\n const a = span.attributes;\n if (!a) return '';\n const v = typeof a.get === 'function' ? a.get('gen_ai.operation.name') : a['gen_ai.operation.name'];\n return typeof v === 'string' ? v.toLowerCase() : '';\n } catch {\n return '';\n }\n}\n\n/**\n * Strands event content arrives as a JSON string of content blocks\n * ([{text}], [{toolUse|toolResult}], or {role,parts,...}) or a plain string.\n */\nfunction flattenStrandsContent(content: unknown): string {\n if (content == null) return '';\n let val: unknown = content;\n if (typeof val === 'string') {\n const s = val.trim();\n if (!(s.startsWith('[') || s.startsWith('{'))) return val; // already plain text\n try {\n val = JSON.parse(s);\n } catch {\n return val as string;\n }\n }\n return flattenBlocks(val);\n}\n\nfunction flattenBlocks(val: unknown): string {\n const items = Array.isArray(val) ? val : [val];\n const out: string[] = [];\n for (const item of items) {\n if (typeof item === 'string') {\n out.push(item);\n continue;\n }\n if (!item || typeof item !== 'object') {\n if (item != null) out.push(String(item));\n continue;\n }\n const o = item as Record<string, any>;\n if (typeof o.text === 'string') out.push(o.text);\n else if (typeof o.content === 'string') out.push(o.content);\n else if (o.toolUse) out.push(`${o.toolUse.name ?? 'tool'}(${safeStringify(o.toolUse.input ?? {})})`);\n else if (o.toolResult) out.push(flattenBlocks(o.toolResult.content ?? o.toolResult));\n else if (Array.isArray(o.parts)) out.push(flattenBlocks(o.parts));\n else if (Array.isArray(o.content)) out.push(flattenBlocks(o.content));\n else out.push(safeStringify(o));\n }\n return out.filter(Boolean).join('\\n');\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"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/strands.ts"],"sourcesContent":["/**\n * Strands currently creates and activates spans through the process-global\n * OpenTelemetry context. Neatlogs always uses a private provider, so this\n * integration is rejected until Strands can accept an injected private-context\n * runtime or Neatlogs ships an explicit wrapper that owns span creation.\n */\nexport function strandsHooks<T extends object>(_agent: T): T {\n throw new Error(\n 'strandsHooks() is not supported because the Strands Agents tracer creates ' +\n 'and activates spans on the global OpenTelemetry context ' +\n '(context.active() / context.with()), which cannot be isolated from other ' +\n 'tracing SDKs (Datadog, etc.).',\n );\n}\n"],"mappings":";AAMO,SAAS,aAA+B,QAAc;AAC3D,QAAM,IAAI;AAAA,IACR;AAAA,EAIF;AACF;","names":[]}
@@ -84,9 +84,6 @@ function getLogger() {
84
84
  // src/core/mask.ts
85
85
  var logger = getLogger();
86
86
 
87
- // src/core/end-user.ts
88
- var import_api = require("@opentelemetry/api");
89
-
90
87
  // src/core/identity.ts
91
88
  var import_node_async_hooks2 = require("async_hooks");
92
89
  var _GLOBAL_KEY = /* @__PURE__ */ Symbol.for("neatlogs.identity.storage");
@@ -102,6 +99,47 @@ function currentEndUserMetadata() {
102
99
  return _storage.getStore()?.endUserMetadata;
103
100
  }
104
101
 
102
+ // src/core/provider.ts
103
+ var import_node_async_hooks3 = require("async_hooks");
104
+ var import_api = require("@opentelemetry/api");
105
+ var PRIVATE_SPAN_STORAGE_KEY = /* @__PURE__ */ Symbol.for(
106
+ "neatlogs.private_span_async_local_storage"
107
+ );
108
+ var PRIVATE_PROVIDER_STATE_KEY = /* @__PURE__ */ Symbol.for(
109
+ "neatlogs.private_provider_state"
110
+ );
111
+ var neatlogsGlobal = globalThis;
112
+ var privateContextStorage = neatlogsGlobal[PRIVATE_SPAN_STORAGE_KEY] ?? (neatlogsGlobal[PRIVATE_SPAN_STORAGE_KEY] = new import_node_async_hooks3.AsyncLocalStorage());
113
+ var providerState = neatlogsGlobal[PRIVATE_PROVIDER_STATE_KEY] ?? (neatlogsGlobal[PRIVATE_PROVIDER_STATE_KEY] = {
114
+ provider: null
115
+ });
116
+ var preInitTracer = {
117
+ startSpan() {
118
+ return import_api.trace.wrapSpanContext(import_api.INVALID_SPAN_CONTEXT);
119
+ },
120
+ startActiveSpan(_name, arg2, arg3, arg4) {
121
+ const fn = typeof arg2 === "function" ? arg2 : typeof arg3 === "function" ? arg3 : arg4;
122
+ return fn(import_api.trace.wrapSpanContext(import_api.INVALID_SPAN_CONTEXT));
123
+ }
124
+ };
125
+ function getNeatlogsTracer(name) {
126
+ return providerState.provider?.getTracer(name) ?? preInitTracer;
127
+ }
128
+ function getNeatlogsActiveContext() {
129
+ return privateContextStorage.getStore() ?? import_api.ROOT_CONTEXT;
130
+ }
131
+ function getActiveNeatlogsSpan() {
132
+ return import_api.trace.getSpan(getNeatlogsActiveContext());
133
+ }
134
+ function getNeatlogsParentContext(baseContext) {
135
+ return baseContext ?? getNeatlogsActiveContext();
136
+ }
137
+ function withNeatlogsSpan(span, fn, baseContext) {
138
+ const base = baseContext ?? getNeatlogsActiveContext();
139
+ const ctx = import_api.trace.setSpan(base, span);
140
+ return privateContextStorage.run(ctx, fn);
141
+ }
142
+
105
143
  // src/core/end-user.ts
106
144
  var logger2 = getLogger();
107
145
  var END_USER_ID_KEY = "neatlogs.end_user.id";
@@ -215,11 +253,11 @@ var AutoRootTracer = class {
215
253
  const kind = String(
216
254
  options?.attributes?.["neatlogs.span.kind"] ?? ""
217
255
  ).toLowerCase();
218
- const ctx = context ?? import_api4.context.active();
219
- const parent = import_api4.trace.getSpan(ctx);
256
+ const ctx = context ?? getNeatlogsParentContext();
257
+ const parent = getActiveNeatlogsSpan();
220
258
  const needsRoot = autoRootEnabled() && !ROOT_KINDS.has(kind) && !(parent !== void 0 && parent.isRecording());
221
259
  if (!needsRoot) {
222
- return this._tracer.startSpan(name, options, context);
260
+ return this._tracer.startSpan(name, options, ctx);
223
261
  }
224
262
  const root = this._tracer.startSpan(
225
263
  resolveRootWorkflowName(),
@@ -238,7 +276,7 @@ var AutoRootTracer = class {
238
276
  ));
239
277
  };
240
278
  function getProviderTracer(name) {
241
- return new AutoRootTracer(import_api4.trace.getTracer(name));
279
+ return new AutoRootTracer(getNeatlogsTracer(name));
242
280
  }
243
281
 
244
282
  // src/vertex-ai.ts
@@ -250,8 +288,8 @@ function wrapVertexAI(client) {
250
288
  }
251
289
  function traceTool(name, fn) {
252
290
  return async function tracedTool(args) {
253
- const tracer = getProviderTracer(TRACER_NAME);
254
- return tracer.startActiveSpan(
291
+ const tracer = getNeatlogsTracer(TRACER_NAME);
292
+ const span = tracer.startSpan(
255
293
  `tool.${name}`,
256
294
  {
257
295
  attributes: {
@@ -260,21 +298,21 @@ function traceTool(name, fn) {
260
298
  "input.value": safeStringify(args)
261
299
  }
262
300
  },
263
- import_api5.context.active(),
264
- async (span) => {
265
- try {
266
- const result = await fn(args);
267
- span.setAttribute("output.value", safeStringify(result));
268
- span.setStatus({ code: import_api5.SpanStatusCode.OK });
269
- return result;
270
- } catch (err) {
271
- recordError(span, err);
272
- throw err;
273
- } finally {
274
- span.end();
275
- }
276
- }
301
+ getNeatlogsParentContext()
277
302
  );
303
+ return withNeatlogsSpan(span, async () => {
304
+ try {
305
+ const result = await fn(args);
306
+ span.setAttribute("output.value", safeStringify(result));
307
+ span.setStatus({ code: import_api5.SpanStatusCode.OK });
308
+ return result;
309
+ } catch (err) {
310
+ recordError(span, err);
311
+ throw err;
312
+ } finally {
313
+ span.end();
314
+ }
315
+ });
278
316
  };
279
317
  }
280
318
  function wrapNamespace(target, path) {
@@ -336,15 +374,14 @@ function tracedChatSend(original, chat, params, rest, isStream) {
336
374
  "neatlogs.llm.model_name": model,
337
375
  "neatlogs.llm.is_streaming": isStream
338
376
  }
339
- }, import_api5.context.active());
377
+ }, getNeatlogsParentContext());
340
378
  const message = params?.message ?? params;
341
379
  span.setAttribute("neatlogs.llm.input_messages.0.role", "user");
342
380
  span.setAttribute(
343
381
  "neatlogs.llm.input_messages.0.content",
344
382
  typeof message === "string" ? message : safeStringify(message)
345
383
  );
346
- const ctx = import_api5.trace.setSpan(import_api5.context.active(), span);
347
- const result = import_api5.context.with(ctx, () => original(params, ...rest));
384
+ const result = withNeatlogsSpan(span, () => original(params, ...rest));
348
385
  return Promise.resolve(result).then(
349
386
  (response) => {
350
387
  if (isStream) return wrapStream(response, span);
@@ -367,9 +404,8 @@ function tracedEmbedContent(original) {
367
404
  "neatlogs.embedding.model_name": opts?.model ?? "",
368
405
  "neatlogs.embedding.text": safeStringify(opts?.contents ?? "")
369
406
  }
370
- }, import_api5.context.active());
371
- const ctx = import_api5.trace.setSpan(import_api5.context.active(), span);
372
- const result = import_api5.context.with(ctx, () => original(opts, ...rest));
407
+ }, getNeatlogsParentContext());
408
+ const result = withNeatlogsSpan(span, () => original(opts, ...rest));
373
409
  return Promise.resolve(result).then(
374
410
  (response) => {
375
411
  const embeddings = response?.embeddings;
@@ -399,9 +435,8 @@ function tracedCountTokens(original) {
399
435
  "neatlogs.llm.task": "count_tokens",
400
436
  "neatlogs.llm.model_name": opts?.model ?? ""
401
437
  }
402
- }, import_api5.context.active());
403
- const ctx = import_api5.trace.setSpan(import_api5.context.active(), span);
404
- const result = import_api5.context.with(ctx, () => original(opts, ...rest));
438
+ }, getNeatlogsParentContext());
439
+ const result = withNeatlogsSpan(span, () => original(opts, ...rest));
405
440
  return Promise.resolve(result).then(
406
441
  (response) => {
407
442
  if (response?.totalTokens != null) span.setAttribute("neatlogs.llm.token_count.prompt", response.totalTokens);
@@ -428,10 +463,9 @@ function tracedGenerateContent(original, isStream) {
428
463
  "neatlogs.llm.model_name": model,
429
464
  "neatlogs.llm.is_streaming": isStream
430
465
  }
431
- }, import_api5.context.active());
466
+ }, getNeatlogsParentContext());
432
467
  setInputAttributes(span, opts);
433
- const ctx = import_api5.trace.setSpan(import_api5.context.active(), span);
434
- const result = import_api5.context.with(ctx, () => original(opts, ...rest));
468
+ const result = withNeatlogsSpan(span, () => original(opts, ...rest));
435
469
  return Promise.resolve(result).then(
436
470
  (response) => {
437
471
  if (isStream) {