neatlogs 1.0.5 → 1.0.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 (63) hide show
  1. package/dist/azure-openai.cjs +344 -0
  2. package/dist/azure-openai.cjs.map +1 -0
  3. package/dist/azure-openai.d.ts +30 -0
  4. package/dist/azure-openai.mjs +318 -0
  5. package/dist/azure-openai.mjs.map +1 -0
  6. package/dist/bedrock.cjs +540 -0
  7. package/dist/bedrock.cjs.map +1 -0
  8. package/dist/bedrock.d.ts +29 -0
  9. package/dist/bedrock.mjs +514 -0
  10. package/dist/bedrock.mjs.map +1 -0
  11. package/dist/browser.cjs +121 -0
  12. package/dist/browser.cjs.map +1 -0
  13. package/dist/browser.d.ts +143 -0
  14. package/dist/browser.mjs +96 -0
  15. package/dist/browser.mjs.map +1 -0
  16. package/dist/claude-agent-sdk.cjs +406 -0
  17. package/dist/claude-agent-sdk.cjs.map +1 -0
  18. package/dist/claude-agent-sdk.d.ts +49 -0
  19. package/dist/claude-agent-sdk.mjs +381 -0
  20. package/dist/claude-agent-sdk.mjs.map +1 -0
  21. package/dist/index.cjs +3263 -839
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.ts +10 -2
  24. package/dist/index.mjs +3254 -838
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/langchain.cjs +9 -9
  27. package/dist/langchain.cjs.map +1 -1
  28. package/dist/langchain.mjs +9 -9
  29. package/dist/langchain.mjs.map +1 -1
  30. package/dist/mastra-wrap.cjs +25 -25
  31. package/dist/mastra-wrap.cjs.map +1 -1
  32. package/dist/mastra-wrap.mjs +25 -25
  33. package/dist/mastra-wrap.mjs.map +1 -1
  34. package/dist/openai-agents.cjs +6 -6
  35. package/dist/openai-agents.cjs.map +1 -1
  36. package/dist/openai-agents.mjs +6 -6
  37. package/dist/openai-agents.mjs.map +1 -1
  38. package/dist/opencode-plugin.cjs +5879 -0
  39. package/dist/opencode-plugin.cjs.map +1 -0
  40. package/dist/opencode-plugin.d.ts +38 -0
  41. package/dist/opencode-plugin.mjs +5854 -0
  42. package/dist/opencode-plugin.mjs.map +1 -0
  43. package/dist/openrouter-agent.cjs +273 -0
  44. package/dist/openrouter-agent.cjs.map +1 -0
  45. package/dist/openrouter-agent.d.ts +34 -0
  46. package/dist/openrouter-agent.mjs +247 -0
  47. package/dist/openrouter-agent.mjs.map +1 -0
  48. package/dist/pi-agent.cjs +237 -0
  49. package/dist/pi-agent.cjs.map +1 -0
  50. package/dist/pi-agent.d.ts +31 -0
  51. package/dist/pi-agent.mjs +216 -0
  52. package/dist/pi-agent.mjs.map +1 -0
  53. package/dist/strands.cjs +125 -2
  54. package/dist/strands.cjs.map +1 -1
  55. package/dist/strands.d.ts +13 -12
  56. package/dist/strands.mjs +125 -2
  57. package/dist/strands.mjs.map +1 -1
  58. package/dist/vertex-ai.cjs +424 -0
  59. package/dist/vertex-ai.cjs.map +1 -0
  60. package/dist/vertex-ai.d.ts +39 -0
  61. package/dist/vertex-ai.mjs +397 -0
  62. package/dist/vertex-ai.mjs.map +1 -0
  63. package/package.json +88 -1
package/dist/index.cjs CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ NeatlogsOpencodePlugin: () => NeatlogsOpencodePlugin,
33
34
  PromptApiError: () => PromptApiError,
34
35
  PromptClient: () => PromptClient,
35
36
  PromptClientError: () => PromptClientError,
@@ -54,6 +55,7 @@ __export(index_exports, {
54
55
  listPrompts: () => listPrompts,
55
56
  log: () => log,
56
57
  openaiAgentsProcessor: () => openaiAgentsProcessor,
58
+ piAgentHooks: () => piAgentHooks,
57
59
  registerCrewaiTask: () => registerCrewaiTask,
58
60
  removeTag: () => removeTag,
59
61
  saveAsVersion: () => saveAsVersion,
@@ -62,12 +64,22 @@ __export(index_exports, {
62
64
  strandsHooks: () => strandsHooks,
63
65
  trace: () => trace2,
64
66
  traceToolAnthropic: () => traceTool2,
67
+ traceToolAzureOpenAI: () => traceTool3,
68
+ traceToolBedrock: () => traceTool5,
65
69
  traceToolOpenAI: () => traceTool,
70
+ traceToolVertexAI: () => traceTool4,
66
71
  updatePrompt: () => updatePrompt,
67
72
  wrapAISDK: () => wrapAISDK,
68
73
  wrapAnthropic: () => wrapAnthropic,
74
+ wrapAzureOpenAI: () => wrapAzureOpenAI,
75
+ wrapBedrock: () => wrapBedrock,
76
+ wrapCallModel: () => wrapCallModel,
77
+ wrapClaudeAgentSDK: () => wrapClaudeAgentSDK,
69
78
  wrapMastra: () => wrapMastra,
70
- wrapOpenAI: () => wrapOpenAI
79
+ wrapOpenAI: () => wrapOpenAI,
80
+ wrapOpenRouterAgent: () => wrapOpenRouterAgent,
81
+ wrapVertexAI: () => wrapVertexAI,
82
+ wrapVertexAIChat: () => wrapVertexAIChat
71
83
  });
72
84
  module.exports = __toCommonJS(index_exports);
73
85
 
@@ -1439,7 +1451,7 @@ var UnifiedAttributeProcessor = class {
1439
1451
  attrs["mcp.server.version"] = info.version ?? "";
1440
1452
  }
1441
1453
  if ("capabilities" in output) {
1442
- attrs["mcp.server.capabilities"] = JSON.stringify(output.capabilities).slice(0, 2e3);
1454
+ attrs["mcp.server.capabilities"] = JSON.stringify(output.capabilities);
1443
1455
  }
1444
1456
  }
1445
1457
  } catch {
@@ -2045,7 +2057,7 @@ var UnifiedAttributeProcessor = class {
2045
2057
  if (typeof r !== "string" || r.toLowerCase() !== role) continue;
2046
2058
  const c = unified[`${prefix}.${i}.content`];
2047
2059
  if (typeof c === "string" && c.toLowerCase().includes("thought:")) {
2048
- texts.push(c.slice(0, 2e4));
2060
+ texts.push(c);
2049
2061
  }
2050
2062
  }
2051
2063
  return texts;
@@ -4969,6 +4981,7 @@ var INSTRUMENTATION_REGISTRY = {
4969
4981
  tags: {
4970
4982
  llm: [
4971
4983
  "azure_ai_inference",
4984
+ "azure_openai",
4972
4985
  "openai",
4973
4986
  "anthropic",
4974
4987
  "cohere",
@@ -5017,7 +5030,10 @@ var INSTRUMENTATION_REGISTRY = {
5017
5030
  "smolagents",
5018
5031
  "strands",
5019
5032
  "pipecat",
5020
- "ai_sdk"
5033
+ "ai_sdk",
5034
+ "claude_agent_sdk",
5035
+ "openrouter_agent",
5036
+ "opencode"
5021
5037
  ],
5022
5038
  tool: ["langchain", "llamaindex", "haystack", "mcp"],
5023
5039
  http: ["requests", "httpx", "urllib3", "aiohttp"],
@@ -5062,7 +5078,15 @@ var INSTRUMENTATION_REGISTRY = {
5062
5078
  bedrock: {
5063
5079
  openinference: "@arizeai/openinference-instrumentation-bedrock",
5064
5080
  openllmetry: null,
5065
- neatlogs: null,
5081
+ // The wrapper is opt-in per call site (wrapBedrock); this entry keeps
5082
+ // scope detection and tagging consistent.
5083
+ neatlogs: "neatlogs/bedrock",
5084
+ default_span_kind: "LLM"
5085
+ },
5086
+ azure_openai: {
5087
+ openinference: null,
5088
+ openllmetry: null,
5089
+ neatlogs: "neatlogs/azure-openai",
5066
5090
  default_span_kind: "LLM"
5067
5091
  },
5068
5092
  groq: {
@@ -5080,7 +5104,7 @@ var INSTRUMENTATION_REGISTRY = {
5080
5104
  vertexai: {
5081
5105
  openinference: null,
5082
5106
  openllmetry: null,
5083
- neatlogs: null,
5107
+ neatlogs: "neatlogs/vertex-ai",
5084
5108
  default_span_kind: "LLM"
5085
5109
  },
5086
5110
  google_generativeai: {
@@ -5353,7 +5377,20 @@ var INSTRUMENTATION_REGISTRY = {
5353
5377
  claude_agent_sdk: {
5354
5378
  openinference: "@arizeai/openinference-instrumentation-claude-agent-sdk",
5355
5379
  openllmetry: null,
5356
- neatlogs: null,
5380
+ // Opt-in wrapper (wrapClaudeAgentSDK); entry kept for scope detection/tagging.
5381
+ neatlogs: "neatlogs/claude-agent-sdk",
5382
+ default_span_kind: "AGENT"
5383
+ },
5384
+ openrouter_agent: {
5385
+ openinference: null,
5386
+ openllmetry: null,
5387
+ neatlogs: "neatlogs/openrouter-agent",
5388
+ default_span_kind: "AGENT"
5389
+ },
5390
+ opencode: {
5391
+ openinference: null,
5392
+ openllmetry: null,
5393
+ neatlogs: "neatlogs/opencode",
5357
5394
  default_span_kind: "AGENT"
5358
5395
  }
5359
5396
  }
@@ -5862,7 +5899,7 @@ async function removeTag(name, tag) {
5862
5899
  }
5863
5900
 
5864
5901
  // src/version.ts
5865
- var __version__ = "1.0.0";
5902
+ var __version__ = "1.0.8";
5866
5903
 
5867
5904
  // src/init.ts
5868
5905
  var logger13 = getLogger();
@@ -7149,238 +7186,302 @@ function recordError2(span2, err) {
7149
7186
  span2.end();
7150
7187
  }
7151
7188
 
7152
- // src/langchain.ts
7189
+ // src/azure-openai.ts
7153
7190
  var import_api11 = require("@opentelemetry/api");
7154
- var TRACER_NAME5 = "neatlogs.langchain";
7155
- function langchainHandler(opts) {
7156
- return new NeatlogsCallbackHandler(opts);
7191
+ var TRACER_NAME5 = "neatlogs.azure_openai";
7192
+ var PROVIDER = "azure";
7193
+ var SYSTEM = "azure";
7194
+ function wrapAzureOpenAI(client) {
7195
+ return wrapNamespace3(client, []);
7157
7196
  }
7158
- var NeatlogsCallbackHandler = class {
7159
- name = "neatlogs";
7160
- _spans = /* @__PURE__ */ new Map();
7161
- _workflowName;
7162
- constructor(opts) {
7163
- this._workflowName = opts?.workflowName;
7164
- }
7165
- // --- Chain/Graph callbacks ---
7166
- async handleChainStart(serialized, inputs, runId, parentRunId, tags, metadata) {
7167
- const tracer = import_api11.trace.getTracer(TRACER_NAME5);
7168
- const name = serialized?.name ?? serialized?.id?.at(-1) ?? "chain";
7169
- const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
7170
- const parentCtx = parentSpan ? import_api11.trace.setSpan(import_api11.context.active(), parentSpan) : import_api11.context.active();
7171
- const attrs = {
7172
- "neatlogs.span.kind": "CHAIN",
7173
- "neatlogs.chain.name": name
7174
- };
7175
- if (this._workflowName) attrs["neatlogs.workflow.name"] = this._workflowName;
7176
- if (inputs) attrs["input.value"] = safeStringify5(inputs).slice(0, 1e4);
7177
- if (tags?.length) attrs["neatlogs.tags"] = tags.join(",");
7178
- const span2 = tracer.startSpan(`langchain.chain.${name}`, { attributes: attrs }, parentCtx);
7179
- this._spans.set(runId, span2);
7180
- }
7181
- async handleChainEnd(outputs, runId) {
7182
- const span2 = this._spans.get(runId);
7183
- if (!span2) return;
7184
- if (outputs) span2.setAttribute("output.value", safeStringify5(outputs).slice(0, 1e4));
7185
- span2.setStatus({ code: import_api11.SpanStatusCode.OK });
7186
- span2.end();
7187
- this._spans.delete(runId);
7188
- }
7189
- async handleChainError(error, runId) {
7190
- const span2 = this._spans.get(runId);
7191
- if (!span2) return;
7192
- span2.setStatus({ code: import_api11.SpanStatusCode.ERROR, message: error.message });
7193
- span2.recordException(error);
7194
- span2.end();
7195
- this._spans.delete(runId);
7196
- }
7197
- // --- LLM callbacks ---
7198
- async handleLLMStart(serialized, prompts, runId, parentRunId, extraParams) {
7197
+ function traceTool3(name, fn) {
7198
+ return async function tracedTool(args) {
7199
7199
  const tracer = import_api11.trace.getTracer(TRACER_NAME5);
7200
- const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? "";
7201
- const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
7202
- const parentCtx = parentSpan ? import_api11.trace.setSpan(import_api11.context.active(), parentSpan) : import_api11.context.active();
7203
- const attrs = {
7204
- "neatlogs.span.kind": "LLM",
7205
- "neatlogs.llm.provider": detectProvider(model),
7206
- "neatlogs.llm.model_name": model
7207
- };
7208
- for (let i = 0; i < prompts.length; i++) {
7209
- attrs[`neatlogs.llm.input_messages.${i}.role`] = "user";
7210
- attrs[`neatlogs.llm.input_messages.${i}.content`] = prompts[i].slice(0, 1e4);
7211
- }
7212
- if (extraParams?.invocation_params) {
7213
- const p = extraParams.invocation_params;
7214
- if (p.temperature != null) attrs["neatlogs.llm.temperature"] = p.temperature;
7215
- if (p.max_tokens != null) attrs["neatlogs.llm.max_tokens"] = p.max_tokens;
7216
- if (p.model_name) attrs["neatlogs.llm.model_name"] = p.model_name;
7200
+ return tracer.startActiveSpan(
7201
+ `tool.${name}`,
7202
+ {
7203
+ attributes: {
7204
+ "neatlogs.span.kind": "TOOL",
7205
+ "neatlogs.tool.name": name,
7206
+ "input.value": safeStringify5(args)
7207
+ }
7208
+ },
7209
+ import_api11.context.active(),
7210
+ async (span2) => {
7211
+ try {
7212
+ const result = await fn(args);
7213
+ span2.setAttribute("output.value", safeStringify5(result));
7214
+ span2.setStatus({ code: import_api11.SpanStatusCode.OK });
7215
+ return result;
7216
+ } catch (err) {
7217
+ recordError3(span2, err);
7218
+ throw err;
7219
+ } finally {
7220
+ span2.end();
7221
+ }
7222
+ }
7223
+ );
7224
+ };
7225
+ }
7226
+ function wrapNamespace3(target, path4) {
7227
+ return new Proxy(target, {
7228
+ get(obj, prop, receiver) {
7229
+ const value = Reflect.get(obj, prop, receiver);
7230
+ if (typeof prop === "symbol" || String(prop).startsWith("_")) return value;
7231
+ const currentPath = [...path4, String(prop)];
7232
+ const pathStr = currentPath.join(".");
7233
+ if (pathStr === "chat.completions.create" && typeof value === "function") {
7234
+ return tracedChatCompletionsCreate2(value.bind(obj));
7235
+ }
7236
+ if (pathStr === "responses.create" && typeof value === "function") {
7237
+ return tracedResponsesCreate2(value.bind(obj));
7238
+ }
7239
+ if (value && typeof value === "object" && !Array.isArray(value) && isNamespace3(currentPath)) {
7240
+ return wrapNamespace3(value, currentPath);
7241
+ }
7242
+ return value;
7217
7243
  }
7218
- const span2 = tracer.startSpan("langchain.llm", { attributes: attrs }, parentCtx);
7219
- this._spans.set(runId, span2);
7220
- }
7221
- async handleChatModelStart(serialized, messages, runId, parentRunId, extraParams) {
7244
+ });
7245
+ }
7246
+ function isNamespace3(path4) {
7247
+ if (path4.length > 3) return false;
7248
+ const key = path4[path4.length - 1];
7249
+ return ["chat", "completions", "responses", "beta"].includes(key);
7250
+ }
7251
+ function tracedChatCompletionsCreate2(original) {
7252
+ return function(opts, ...rest) {
7222
7253
  const tracer = import_api11.trace.getTracer(TRACER_NAME5);
7223
- const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? "";
7224
- const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
7225
- const parentCtx = parentSpan ? import_api11.trace.setSpan(import_api11.context.active(), parentSpan) : import_api11.context.active();
7226
- const attrs = {
7227
- "neatlogs.span.kind": "LLM",
7228
- "neatlogs.llm.provider": detectProvider(model),
7229
- "neatlogs.llm.model_name": model
7230
- };
7231
- const flatMessages = messages.flat();
7232
- for (let i = 0; i < flatMessages.length; i++) {
7233
- const msg = flatMessages[i];
7234
- const role = msg?.role ?? msg?._getType?.() ?? msg?.constructor?.name ?? "unknown";
7235
- const content = typeof msg?.content === "string" ? msg.content : safeStringify5(msg?.content);
7236
- attrs[`neatlogs.llm.input_messages.${i}.role`] = mapRole(role);
7237
- attrs[`neatlogs.llm.input_messages.${i}.content`] = content.slice(0, 1e4);
7254
+ const model = opts?.model ?? "";
7255
+ const messages = opts?.messages ?? [];
7256
+ const isStream = opts?.stream === true;
7257
+ const span2 = tracer.startSpan("azure_openai.chat.completions.create", {
7258
+ attributes: {
7259
+ "neatlogs.span.kind": "LLM",
7260
+ "neatlogs.llm.provider": PROVIDER,
7261
+ "neatlogs.llm.system": SYSTEM,
7262
+ "neatlogs.llm.model_name": model,
7263
+ "neatlogs.llm.is_streaming": isStream
7264
+ }
7265
+ }, import_api11.context.active());
7266
+ for (let i = 0; i < messages.length; i++) {
7267
+ const msg = messages[i];
7268
+ span2.setAttribute(`neatlogs.llm.input_messages.${i}.role`, msg.role ?? "");
7269
+ if (typeof msg.content === "string") {
7270
+ span2.setAttribute(`neatlogs.llm.input_messages.${i}.content`, msg.content);
7271
+ } else if (msg.content) {
7272
+ span2.setAttribute(`neatlogs.llm.input_messages.${i}.content`, safeStringify5(msg.content));
7273
+ }
7274
+ if (msg.tool_call_id) {
7275
+ span2.setAttribute(`neatlogs.llm.input_messages.${i}.tool_call_id`, msg.tool_call_id);
7276
+ }
7238
7277
  }
7239
- if (extraParams?.invocation_params) {
7240
- const p = extraParams.invocation_params;
7241
- if (p.temperature != null) attrs["neatlogs.llm.temperature"] = p.temperature;
7242
- if (p.max_tokens != null) attrs["neatlogs.llm.max_tokens"] = p.max_tokens;
7243
- if (p.model_name) attrs["neatlogs.llm.model_name"] = p.model_name;
7278
+ if (opts?.tools) {
7279
+ for (let i = 0; i < opts.tools.length; i++) {
7280
+ const fn = opts.tools[i]?.function ?? {};
7281
+ span2.setAttribute(`neatlogs.llm.tools.${i}.name`, fn.name ?? "");
7282
+ if (fn.description) span2.setAttribute(`neatlogs.llm.tools.${i}.description`, fn.description);
7283
+ if (fn.parameters) span2.setAttribute(`neatlogs.llm.tools.${i}.input_schema`, safeStringify5(fn.parameters));
7284
+ }
7244
7285
  }
7245
- const span2 = tracer.startSpan("langchain.chat_model", { attributes: attrs }, parentCtx);
7246
- this._spans.set(runId, span2);
7247
- }
7248
- async handleLLMEnd(output, runId) {
7249
- const span2 = this._spans.get(runId);
7250
- if (!span2) return;
7251
- const generations = output?.generations ?? [];
7252
- for (let i = 0; i < generations.length; i++) {
7253
- const gen = generations[i];
7254
- if (!Array.isArray(gen)) continue;
7255
- for (let j = 0; j < gen.length; j++) {
7256
- const msg = gen[j]?.message ?? gen[j];
7257
- const content = msg?.content ?? msg?.text ?? "";
7258
- span2.setAttribute(`neatlogs.llm.output_messages.${i}.role`, "assistant");
7259
- span2.setAttribute(`neatlogs.llm.output_messages.${i}.content`, String(content).slice(0, 1e4));
7260
- const toolCalls = msg?.tool_calls ?? msg?.additional_kwargs?.tool_calls;
7261
- if (toolCalls && Array.isArray(toolCalls)) {
7262
- for (let k = 0; k < toolCalls.length; k++) {
7263
- const tc = toolCalls[k];
7264
- span2.setAttribute(`neatlogs.llm.tool_calls.${k}.id`, tc.id ?? "");
7265
- span2.setAttribute(`neatlogs.llm.tool_calls.${k}.name`, tc.name ?? tc.function?.name ?? "");
7266
- span2.setAttribute(`neatlogs.llm.tool_calls.${k}.arguments`, tc.args ? safeStringify5(tc.args) : tc.function?.arguments ?? "");
7267
- }
7268
- }
7286
+ setInvocationParams3(span2, opts);
7287
+ if (isStream) {
7288
+ opts = { ...opts };
7289
+ const streamOpts = opts.stream_options ?? {};
7290
+ if (!streamOpts.include_usage) {
7291
+ opts.stream_options = { ...streamOpts, include_usage: true };
7269
7292
  }
7270
7293
  }
7271
- const usage = output?.llmOutput?.tokenUsage ?? output?.llmOutput?.usage;
7272
- if (usage) {
7273
- if (usage.promptTokens != null || usage.prompt_tokens != null) {
7274
- span2.setAttribute("neatlogs.llm.token_count.prompt", usage.promptTokens ?? usage.prompt_tokens);
7294
+ const ctx = import_api11.trace.setSpan(import_api11.context.active(), span2);
7295
+ const promise = import_api11.context.with(ctx, () => original(opts, ...rest));
7296
+ return promise.then(
7297
+ (response) => {
7298
+ if (isStream) {
7299
+ return wrapAsyncIterableStream2(response, span2);
7300
+ }
7301
+ finalizeChatResponse2(span2, response);
7302
+ return response;
7303
+ },
7304
+ (err) => {
7305
+ recordError3(span2, err);
7306
+ throw err;
7275
7307
  }
7276
- if (usage.completionTokens != null || usage.completion_tokens != null) {
7277
- span2.setAttribute("neatlogs.llm.token_count.completion", usage.completionTokens ?? usage.completion_tokens);
7308
+ );
7309
+ };
7310
+ }
7311
+ function tracedResponsesCreate2(original) {
7312
+ return function(opts, ...rest) {
7313
+ const tracer = import_api11.trace.getTracer(TRACER_NAME5);
7314
+ const model = opts?.model ?? "";
7315
+ const span2 = tracer.startSpan("azure_openai.responses.create", {
7316
+ attributes: {
7317
+ "neatlogs.span.kind": "LLM",
7318
+ "neatlogs.llm.provider": PROVIDER,
7319
+ "neatlogs.llm.system": SYSTEM,
7320
+ "neatlogs.llm.model_name": model,
7321
+ "input.value": safeStringify5(opts?.input ?? "")
7278
7322
  }
7279
- if (usage.totalTokens != null || usage.total_tokens != null) {
7280
- span2.setAttribute("neatlogs.llm.token_count.total", usage.totalTokens ?? usage.total_tokens);
7323
+ }, import_api11.context.active());
7324
+ const ctx = import_api11.trace.setSpan(import_api11.context.active(), span2);
7325
+ const promise = import_api11.context.with(ctx, () => original(opts, ...rest));
7326
+ return promise.then(
7327
+ (response) => {
7328
+ if (response?.output_text) {
7329
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7330
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", response.output_text);
7331
+ }
7332
+ if (response?.model) span2.setAttribute("neatlogs.llm.model_name", response.model);
7333
+ if (response?.usage) {
7334
+ if (response.usage.input_tokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", response.usage.input_tokens);
7335
+ if (response.usage.output_tokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", response.usage.output_tokens);
7336
+ }
7337
+ span2.setStatus({ code: import_api11.SpanStatusCode.OK });
7338
+ span2.end();
7339
+ return response;
7340
+ },
7341
+ (err) => {
7342
+ recordError3(span2, err);
7343
+ throw err;
7281
7344
  }
7282
- }
7345
+ );
7346
+ };
7347
+ }
7348
+ function wrapAsyncIterableStream2(stream, span2) {
7349
+ const chunks = [];
7350
+ const originalAsyncIterator = stream?.[Symbol.asyncIterator]?.bind(stream);
7351
+ if (!originalAsyncIterator) {
7283
7352
  span2.setStatus({ code: import_api11.SpanStatusCode.OK });
7284
7353
  span2.end();
7285
- this._spans.delete(runId);
7286
- }
7287
- async handleLLMNewToken(_token, _idx, _runId) {
7288
- }
7289
- async handleLLMError(error, runId) {
7290
- const span2 = this._spans.get(runId);
7291
- if (!span2) return;
7292
- span2.setStatus({ code: import_api11.SpanStatusCode.ERROR, message: error.message });
7293
- span2.recordException(error);
7294
- span2.end();
7295
- this._spans.delete(runId);
7354
+ return stream;
7296
7355
  }
7297
- // --- Tool callbacks ---
7298
- async handleToolStart(serialized, input, runId, parentRunId, _tags, _metadata, runName, toolCallId) {
7299
- const tracer = import_api11.trace.getTracer(TRACER_NAME5);
7300
- const name = serialized?.name || runName || (Array.isArray(serialized?.id) ? serialized.id[serialized.id.length - 1] : void 0) || "tool";
7301
- const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
7302
- const parentCtx = parentSpan ? import_api11.trace.setSpan(import_api11.context.active(), parentSpan) : import_api11.context.active();
7303
- const attrs = {
7304
- "neatlogs.span.kind": "TOOL",
7305
- "neatlogs.tool.name": name,
7306
- "input.value": String(input).slice(0, 1e4)
7307
- };
7308
- if (toolCallId) attrs["neatlogs.tool_call.id"] = toolCallId;
7309
- const span2 = tracer.startSpan(`langchain.tool.${name}`, { attributes: attrs }, parentCtx);
7310
- this._spans.set(runId, span2);
7356
+ const wrapped = Object.create(Object.getPrototypeOf(stream));
7357
+ Object.assign(wrapped, stream);
7358
+ wrapped[Symbol.asyncIterator] = function() {
7359
+ const iterator = originalAsyncIterator();
7360
+ return {
7361
+ async next() {
7362
+ try {
7363
+ const result = await iterator.next();
7364
+ if (result.done) {
7365
+ finalizeStreamChunks2(span2, chunks);
7366
+ return result;
7367
+ }
7368
+ chunks.push(result.value);
7369
+ return result;
7370
+ } catch (err) {
7371
+ recordError3(span2, err);
7372
+ throw err;
7373
+ }
7374
+ },
7375
+ async return(value) {
7376
+ finalizeStreamChunks2(span2, chunks);
7377
+ return iterator.return?.(value) ?? { done: true, value: void 0 };
7378
+ },
7379
+ async throw(err) {
7380
+ recordError3(span2, err);
7381
+ return iterator.throw?.(err) ?? { done: true, value: void 0 };
7382
+ }
7383
+ };
7384
+ };
7385
+ return wrapped;
7386
+ }
7387
+ function finalizeStreamChunks2(span2, chunks) {
7388
+ const textParts = [];
7389
+ const toolCallsAcc = {};
7390
+ let finishReason = "";
7391
+ let model = "";
7392
+ let usage = null;
7393
+ for (const chunk of chunks) {
7394
+ if (!chunk?.choices?.length) {
7395
+ if (chunk?.usage) usage = chunk.usage;
7396
+ continue;
7397
+ }
7398
+ const choice = chunk.choices[0];
7399
+ const delta = choice?.delta;
7400
+ if (delta?.content) textParts.push(delta.content);
7401
+ if (delta?.tool_calls) {
7402
+ for (const tc of delta.tool_calls) {
7403
+ const idx = tc.index ?? 0;
7404
+ if (!toolCallsAcc[idx]) toolCallsAcc[idx] = { id: "", name: "", arguments: "" };
7405
+ if (tc.id) toolCallsAcc[idx].id = tc.id;
7406
+ if (tc.function?.name) toolCallsAcc[idx].name = tc.function.name;
7407
+ if (tc.function?.arguments) toolCallsAcc[idx].arguments += tc.function.arguments;
7408
+ }
7409
+ }
7410
+ if (choice?.finish_reason) finishReason = choice.finish_reason;
7411
+ if (chunk?.model) model = chunk.model;
7311
7412
  }
7312
- async handleToolEnd(output, runId) {
7313
- const span2 = this._spans.get(runId);
7314
- if (!span2) return;
7315
- span2.setAttribute("output.value", String(output).slice(0, 1e4));
7316
- span2.setStatus({ code: import_api11.SpanStatusCode.OK });
7317
- span2.end();
7318
- this._spans.delete(runId);
7413
+ const fullText = textParts.join("");
7414
+ if (fullText) {
7415
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7416
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", fullText);
7319
7417
  }
7320
- async handleToolError(error, runId) {
7321
- const span2 = this._spans.get(runId);
7322
- if (!span2) return;
7323
- span2.setStatus({ code: import_api11.SpanStatusCode.ERROR, message: error.message });
7324
- span2.recordException(error);
7325
- span2.end();
7326
- this._spans.delete(runId);
7418
+ let j = 0;
7419
+ for (const tc of Object.values(toolCallsAcc)) {
7420
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.id`, tc.id);
7421
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.name`, tc.name);
7422
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.arguments`, tc.arguments);
7423
+ j++;
7327
7424
  }
7328
- // --- Retriever callbacks ---
7329
- async handleRetrieverStart(serialized, query, runId, parentRunId) {
7330
- const tracer = import_api11.trace.getTracer(TRACER_NAME5);
7331
- const name = serialized?.name ?? "retriever";
7332
- const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
7333
- const parentCtx = parentSpan ? import_api11.trace.setSpan(import_api11.context.active(), parentSpan) : import_api11.context.active();
7334
- const attrs = {
7335
- "neatlogs.span.kind": "RETRIEVER",
7336
- "neatlogs.retriever.name": name,
7337
- "input.value": query.slice(0, 1e4)
7338
- };
7339
- const span2 = tracer.startSpan(`langchain.retriever.${name}`, { attributes: attrs }, parentCtx);
7340
- this._spans.set(runId, span2);
7425
+ if (model) span2.setAttribute("neatlogs.llm.model_name", model);
7426
+ if (finishReason) span2.setAttribute("neatlogs.llm.finish_reason", finishReason);
7427
+ if (usage) {
7428
+ if (usage.prompt_tokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", usage.prompt_tokens);
7429
+ if (usage.completion_tokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", usage.completion_tokens);
7430
+ if (usage.total_tokens != null) span2.setAttribute("neatlogs.llm.token_count.total", usage.total_tokens);
7431
+ if (usage.prompt_tokens_details?.cached_tokens != null) {
7432
+ span2.setAttribute("neatlogs.llm.token_count.cache_read", usage.prompt_tokens_details.cached_tokens);
7433
+ }
7434
+ if (usage.completion_tokens_details?.reasoning_tokens != null) {
7435
+ span2.setAttribute("neatlogs.llm.token_count.reasoning", usage.completion_tokens_details.reasoning_tokens);
7436
+ }
7341
7437
  }
7342
- async handleRetrieverEnd(documents, runId) {
7343
- const span2 = this._spans.get(runId);
7344
- if (!span2) return;
7345
- if (documents?.length) {
7346
- span2.setAttribute("neatlogs.retriever.document_count", documents.length);
7347
- for (let i = 0; i < Math.min(documents.length, 10); i++) {
7348
- const doc = documents[i];
7349
- if (doc?.pageContent) {
7350
- span2.setAttribute(`neatlogs.retriever.documents.${i}.content`, doc.pageContent.slice(0, 2e3));
7351
- }
7438
+ span2.setStatus({ code: import_api11.SpanStatusCode.OK });
7439
+ span2.end();
7440
+ }
7441
+ function finalizeChatResponse2(span2, response) {
7442
+ const choices = response?.choices ?? [];
7443
+ for (let i = 0; i < choices.length; i++) {
7444
+ const message = choices[i]?.message;
7445
+ if (!message) continue;
7446
+ span2.setAttribute(`neatlogs.llm.output_messages.${i}.role`, "assistant");
7447
+ if (message.content) {
7448
+ span2.setAttribute(`neatlogs.llm.output_messages.${i}.content`, message.content);
7449
+ }
7450
+ if (message.tool_calls) {
7451
+ for (let j = 0; j < message.tool_calls.length; j++) {
7452
+ const tc = message.tool_calls[j];
7453
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.id`, tc.id ?? "");
7454
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.name`, tc.function?.name ?? "");
7455
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.arguments`, tc.function?.arguments ?? "");
7352
7456
  }
7353
7457
  }
7354
- span2.setStatus({ code: import_api11.SpanStatusCode.OK });
7355
- span2.end();
7356
- this._spans.delete(runId);
7458
+ if (choices[i].finish_reason) {
7459
+ span2.setAttribute("neatlogs.llm.finish_reason", choices[i].finish_reason);
7460
+ }
7357
7461
  }
7358
- async handleRetrieverError(error, runId) {
7359
- const span2 = this._spans.get(runId);
7360
- if (!span2) return;
7361
- span2.setStatus({ code: import_api11.SpanStatusCode.ERROR, message: error.message });
7362
- span2.recordException(error);
7363
- span2.end();
7364
- this._spans.delete(runId);
7462
+ const usage = response?.usage;
7463
+ if (usage) {
7464
+ if (usage.prompt_tokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", usage.prompt_tokens);
7465
+ if (usage.completion_tokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", usage.completion_tokens);
7466
+ if (usage.total_tokens != null) span2.setAttribute("neatlogs.llm.token_count.total", usage.total_tokens);
7467
+ if (usage.prompt_tokens_details?.cached_tokens != null) {
7468
+ span2.setAttribute("neatlogs.llm.token_count.cache_read", usage.prompt_tokens_details.cached_tokens);
7469
+ }
7470
+ if (usage.completion_tokens_details?.reasoning_tokens != null) {
7471
+ span2.setAttribute("neatlogs.llm.token_count.reasoning", usage.completion_tokens_details.reasoning_tokens);
7472
+ }
7365
7473
  }
7366
- };
7367
- function detectProvider(model) {
7368
- const m = model.toLowerCase();
7369
- if (m.includes("gpt") || m.includes("o1") || m.includes("o3") || m.includes("o4")) return "openai";
7370
- if (m.includes("claude")) return "anthropic";
7371
- if (m.includes("gemini")) return "google";
7372
- if (m.includes("command")) return "cohere";
7373
- if (m.includes("llama") || m.includes("mixtral")) return "meta";
7374
- return "unknown";
7474
+ if (response?.model) span2.setAttribute("neatlogs.llm.model_name", response.model);
7475
+ span2.setStatus({ code: import_api11.SpanStatusCode.OK });
7476
+ span2.end();
7375
7477
  }
7376
- function mapRole(role) {
7377
- const r = role.toLowerCase();
7378
- if (r === "human" || r === "humanmessage") return "user";
7379
- if (r === "ai" || r === "aimessage") return "assistant";
7380
- if (r === "system" || r === "systemmessage") return "system";
7381
- if (r === "function" || r === "functionmessage") return "function";
7382
- if (r === "tool" || r === "toolmessage") return "tool";
7383
- return role;
7478
+ function setInvocationParams3(span2, opts) {
7479
+ if (opts?.temperature != null) span2.setAttribute("neatlogs.llm.temperature", opts.temperature);
7480
+ if (opts?.top_p != null) span2.setAttribute("neatlogs.llm.top_p", opts.top_p);
7481
+ if (opts?.max_tokens != null) span2.setAttribute("neatlogs.llm.max_tokens", opts.max_tokens);
7482
+ if (opts?.frequency_penalty != null) span2.setAttribute("neatlogs.llm.frequency_penalty", opts.frequency_penalty);
7483
+ if (opts?.presence_penalty != null) span2.setAttribute("neatlogs.llm.presence_penalty", opts.presence_penalty);
7484
+ if (opts?.stop) span2.setAttribute("neatlogs.llm.stop_sequences", safeStringify5(opts.stop));
7384
7485
  }
7385
7486
  function safeStringify5(value) {
7386
7487
  try {
@@ -7389,202 +7490,391 @@ function safeStringify5(value) {
7389
7490
  return "";
7390
7491
  }
7391
7492
  }
7392
-
7393
- // src/strands.ts
7394
- function strandsHooks(agent) {
7395
- if (agent && typeof agent === "object") {
7396
- try {
7397
- Object.defineProperty(agent, "_neatlogs_patched", {
7398
- value: true,
7399
- enumerable: false,
7400
- configurable: true
7401
- });
7402
- } catch {
7403
- agent._neatlogs_patched = true;
7404
- }
7493
+ function recordError3(span2, err) {
7494
+ if (err instanceof Error) {
7495
+ span2.setStatus({ code: import_api11.SpanStatusCode.ERROR, message: err.message });
7496
+ span2.recordException(err);
7497
+ } else {
7498
+ span2.setStatus({ code: import_api11.SpanStatusCode.ERROR, message: String(err) });
7405
7499
  }
7406
- return agent;
7500
+ span2.end();
7407
7501
  }
7408
7502
 
7409
- // src/openai-agents.ts
7503
+ // src/vertex-ai.ts
7410
7504
  var import_api12 = require("@opentelemetry/api");
7411
- var TRACER_NAME6 = "neatlogs.openai_agents";
7412
- function openaiAgentsProcessor() {
7413
- return new NeatlogsTraceProcessor();
7505
+ var TRACER_NAME6 = "neatlogs.vertex_ai";
7506
+ var PROVIDER2 = "vertex_ai";
7507
+ var SYSTEM2 = "vertexai";
7508
+ function wrapVertexAI(client) {
7509
+ return wrapNamespace4(client, []);
7414
7510
  }
7415
- var NeatlogsTraceProcessor = class {
7416
- _spans = /* @__PURE__ */ new Map();
7417
- _startTimes = /* @__PURE__ */ new Map();
7418
- // The @openai/agents SDK passes a Trace object: { traceId, name, groupId, metadata }.
7419
- onTraceStart(traceData) {
7511
+ function traceTool4(name, fn) {
7512
+ return async function tracedTool(args) {
7420
7513
  const tracer = import_api12.trace.getTracer(TRACER_NAME6);
7421
- const attrs = { "neatlogs.span.kind": "WORKFLOW" };
7422
- const workflowName = traceData?.name ?? traceData?.workflow_name;
7423
- if (workflowName) attrs["neatlogs.workflow.name"] = workflowName;
7424
- const traceId = traceData?.traceId ?? traceData?.trace_id;
7425
- if (traceId) attrs["neatlogs.agent.trace_id"] = String(traceId);
7426
- const span2 = tracer.startSpan("openai_agents.trace", { attributes: attrs }, import_api12.context.active());
7427
- const key = String(traceId ?? `trace_${Date.now()}`);
7428
- this._spans.set(key, span2);
7429
- this._startTimes.set(key, Date.now());
7430
- }
7431
- onTraceEnd(traceData) {
7432
- const key = String(traceData?.traceId ?? traceData?.trace_id ?? "");
7433
- const span2 = this._spans.get(key);
7434
- if (!span2) return;
7435
- const startTime = this._startTimes.get(key);
7436
- if (startTime) {
7437
- span2.setAttribute("neatlogs.metrics.duration_ms", Date.now() - startTime);
7514
+ return tracer.startActiveSpan(
7515
+ `tool.${name}`,
7516
+ {
7517
+ attributes: {
7518
+ "neatlogs.span.kind": "TOOL",
7519
+ "neatlogs.tool.name": name,
7520
+ "input.value": safeStringify6(args)
7521
+ }
7522
+ },
7523
+ import_api12.context.active(),
7524
+ async (span2) => {
7525
+ try {
7526
+ const result = await fn(args);
7527
+ span2.setAttribute("output.value", safeStringify6(result));
7528
+ span2.setStatus({ code: import_api12.SpanStatusCode.OK });
7529
+ return result;
7530
+ } catch (err) {
7531
+ recordError4(span2, err);
7532
+ throw err;
7533
+ } finally {
7534
+ span2.end();
7535
+ }
7536
+ }
7537
+ );
7538
+ };
7539
+ }
7540
+ function wrapNamespace4(target, path4) {
7541
+ return new Proxy(target, {
7542
+ get(obj, prop, receiver) {
7543
+ const value = Reflect.get(obj, prop, receiver);
7544
+ if (typeof prop === "symbol" || String(prop).startsWith("_")) return value;
7545
+ const currentPath = [...path4, String(prop)];
7546
+ const pathStr = currentPath.join(".");
7547
+ if (pathStr === "models.generateContent" && typeof value === "function") {
7548
+ return tracedGenerateContent(value.bind(obj), false);
7549
+ }
7550
+ if (pathStr === "models.generateContentStream" && typeof value === "function") {
7551
+ return tracedGenerateContent(value.bind(obj), true);
7552
+ }
7553
+ if (pathStr === "models.embedContent" && typeof value === "function") {
7554
+ return tracedEmbedContent(value.bind(obj));
7555
+ }
7556
+ if (pathStr === "models.countTokens" && typeof value === "function") {
7557
+ return tracedCountTokens(value.bind(obj));
7558
+ }
7559
+ if (value && typeof value === "object" && !Array.isArray(value) && isNamespace4(currentPath)) {
7560
+ return wrapNamespace4(value, currentPath);
7561
+ }
7562
+ return value;
7438
7563
  }
7439
- span2.setStatus({ code: import_api12.SpanStatusCode.OK });
7440
- span2.end();
7441
- this._spans.delete(key);
7442
- this._startTimes.delete(key);
7564
+ });
7565
+ }
7566
+ function isNamespace4(path4) {
7567
+ if (path4.length > 2) return false;
7568
+ return ["models", "chats"].includes(path4[path4.length - 1]);
7569
+ }
7570
+ function wrapVertexAIChat(chat) {
7571
+ const c = chat;
7572
+ if (!c || c._neatlogsVertexPatched) return chat;
7573
+ if (typeof c.sendMessage === "function") {
7574
+ const orig = c.sendMessage.bind(c);
7575
+ c.sendMessage = (params, ...rest) => tracedChatSend(orig, c, params, rest, false);
7443
7576
  }
7444
- // The SDK passes a Span object: { type, spanId, traceId, parentId?, spanData: {...} }.
7445
- // The meaningful payload (type, name, input, output, usage, ...) lives in `spanData`.
7446
- onSpanStart(span2) {
7447
- const tracer = import_api12.trace.getTracer(TRACER_NAME6);
7448
- const data = span2?.spanData ?? span2 ?? {};
7449
- const spanType = data?.type ?? data?.span_type ?? span2?.type ?? "";
7450
- const spanId = String(span2?.spanId ?? span2?.span_id ?? data?.span_id ?? `span_${Date.now()}`);
7451
- const parentKey = String(span2?.parentId ?? span2?.traceId ?? span2?.trace_id ?? "");
7452
- const parentSpan = this._spans.get(parentKey);
7453
- const parentCtx = parentSpan ? import_api12.trace.setSpan(import_api12.context.active(), parentSpan) : import_api12.context.active();
7454
- let otelSpan;
7455
- if (spanType === "agent" || spanType === "agent_run") {
7456
- const agentName = data?.name ?? data?.agent_name ?? "agent";
7457
- const attrs = {
7458
- "neatlogs.span.kind": "AGENT",
7459
- "neatlogs.agent.name": agentName
7460
- };
7461
- if (Array.isArray(data?.tools) && data.tools.length) {
7462
- attrs["neatlogs.agent.available_tools"] = data.tools.join(",");
7577
+ if (typeof c.sendMessageStream === "function") {
7578
+ const orig = c.sendMessageStream.bind(c);
7579
+ c.sendMessageStream = (params, ...rest) => tracedChatSend(orig, c, params, rest, true);
7580
+ }
7581
+ try {
7582
+ Object.defineProperty(c, "_neatlogsVertexPatched", { value: true, enumerable: false, configurable: true });
7583
+ } catch {
7584
+ c._neatlogsVertexPatched = true;
7585
+ }
7586
+ return chat;
7587
+ }
7588
+ function tracedChatSend(original, chat, params, rest, isStream) {
7589
+ const tracer = import_api12.trace.getTracer(TRACER_NAME6);
7590
+ const model = chat?.model ?? chat?.modelVersion ?? "";
7591
+ const span2 = tracer.startSpan("vertex_ai.chat.send_message", {
7592
+ attributes: {
7593
+ "neatlogs.span.kind": "LLM",
7594
+ "neatlogs.llm.provider": PROVIDER2,
7595
+ "neatlogs.llm.system": SYSTEM2,
7596
+ "neatlogs.llm.model_name": model,
7597
+ "neatlogs.llm.is_streaming": isStream
7598
+ }
7599
+ }, import_api12.context.active());
7600
+ const message = params?.message ?? params;
7601
+ span2.setAttribute("neatlogs.llm.input_messages.0.role", "user");
7602
+ span2.setAttribute(
7603
+ "neatlogs.llm.input_messages.0.content",
7604
+ typeof message === "string" ? message : safeStringify6(message)
7605
+ );
7606
+ const ctx = import_api12.trace.setSpan(import_api12.context.active(), span2);
7607
+ const result = import_api12.context.with(ctx, () => original(params, ...rest));
7608
+ return Promise.resolve(result).then(
7609
+ (response) => {
7610
+ if (isStream) return wrapStream(response, span2);
7611
+ finalizeResponse(span2, response);
7612
+ return response;
7613
+ },
7614
+ (err) => {
7615
+ recordError4(span2, err);
7616
+ throw err;
7617
+ }
7618
+ );
7619
+ }
7620
+ function tracedEmbedContent(original) {
7621
+ return function(opts, ...rest) {
7622
+ const tracer = import_api12.trace.getTracer(TRACER_NAME6);
7623
+ const span2 = tracer.startSpan("vertex_ai.models.embed_content", {
7624
+ attributes: {
7625
+ "neatlogs.span.kind": "EMBEDDING",
7626
+ "neatlogs.llm.provider": PROVIDER2,
7627
+ "neatlogs.embedding.model_name": opts?.model ?? "",
7628
+ "neatlogs.embedding.text": safeStringify6(opts?.contents ?? "")
7629
+ }
7630
+ }, import_api12.context.active());
7631
+ const ctx = import_api12.trace.setSpan(import_api12.context.active(), span2);
7632
+ const result = import_api12.context.with(ctx, () => original(opts, ...rest));
7633
+ return Promise.resolve(result).then(
7634
+ (response) => {
7635
+ const embeddings = response?.embeddings;
7636
+ if (Array.isArray(embeddings)) {
7637
+ span2.setAttribute("neatlogs.embedding.count", embeddings.length);
7638
+ const vals = embeddings[0]?.values;
7639
+ if (Array.isArray(vals)) span2.setAttribute("neatlogs.embedding.dimensions", vals.length);
7640
+ }
7641
+ span2.setStatus({ code: import_api12.SpanStatusCode.OK });
7642
+ span2.end();
7643
+ return response;
7644
+ },
7645
+ (err) => {
7646
+ recordError4(span2, err);
7647
+ throw err;
7463
7648
  }
7464
- otelSpan = tracer.startSpan(`openai_agents.agent.${agentName}`, { attributes: attrs }, parentCtx);
7465
- } else if (spanType === "response" || spanType === "generation" || spanType === "llm") {
7466
- const attrs = {
7649
+ );
7650
+ };
7651
+ }
7652
+ function tracedCountTokens(original) {
7653
+ return function(opts, ...rest) {
7654
+ const tracer = import_api12.trace.getTracer(TRACER_NAME6);
7655
+ const span2 = tracer.startSpan("vertex_ai.models.count_tokens", {
7656
+ attributes: {
7467
7657
  "neatlogs.span.kind": "LLM",
7468
- "neatlogs.llm.provider": "openai"
7469
- };
7470
- const model = data?.model;
7471
- if (model) attrs["neatlogs.llm.model_name"] = model;
7472
- const inputMsgs = data?.input ?? data?.messages;
7473
- if (inputMsgs && Array.isArray(inputMsgs)) {
7474
- for (let i = 0; i < inputMsgs.length; i++) {
7475
- const msg = inputMsgs[i];
7476
- const role = typeof msg === "object" ? msg.role ?? "" : "";
7477
- const content = typeof msg === "object" ? msg.content ?? "" : String(msg);
7478
- if (role) attrs[`neatlogs.llm.input_messages.${i}.role`] = role;
7479
- if (content) attrs[`neatlogs.llm.input_messages.${i}.content`] = (typeof content === "string" ? content : safeStringify6(content)).slice(0, 1e4);
7480
- }
7658
+ "neatlogs.llm.provider": PROVIDER2,
7659
+ "neatlogs.llm.task": "count_tokens",
7660
+ "neatlogs.llm.model_name": opts?.model ?? ""
7661
+ }
7662
+ }, import_api12.context.active());
7663
+ const ctx = import_api12.trace.setSpan(import_api12.context.active(), span2);
7664
+ const result = import_api12.context.with(ctx, () => original(opts, ...rest));
7665
+ return Promise.resolve(result).then(
7666
+ (response) => {
7667
+ if (response?.totalTokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", response.totalTokens);
7668
+ span2.setStatus({ code: import_api12.SpanStatusCode.OK });
7669
+ span2.end();
7670
+ return response;
7671
+ },
7672
+ (err) => {
7673
+ recordError4(span2, err);
7674
+ throw err;
7481
7675
  }
7482
- otelSpan = tracer.startSpan("openai_agents.generation", { attributes: attrs }, parentCtx);
7483
- } else if (spanType === "function" || spanType === "tool" || spanType === "tool_call") {
7484
- const toolName = data?.name ?? data?.function_name ?? "tool";
7485
- const attrs = {
7486
- "neatlogs.span.kind": "TOOL",
7487
- "neatlogs.tool.name": toolName
7488
- };
7489
- const toolInput = data?.input ?? data?.arguments;
7490
- if (toolInput !== void 0) {
7491
- attrs["input.value"] = (typeof toolInput === "string" ? toolInput : safeStringify6(toolInput)).slice(0, 1e4);
7676
+ );
7677
+ };
7678
+ }
7679
+ function tracedGenerateContent(original, isStream) {
7680
+ return function(opts, ...rest) {
7681
+ const tracer = import_api12.trace.getTracer(TRACER_NAME6);
7682
+ const model = opts?.model ?? "";
7683
+ const span2 = tracer.startSpan("vertex_ai.models.generate_content", {
7684
+ attributes: {
7685
+ "neatlogs.span.kind": "LLM",
7686
+ "neatlogs.llm.provider": PROVIDER2,
7687
+ "neatlogs.llm.system": SYSTEM2,
7688
+ "neatlogs.llm.model_name": model,
7689
+ "neatlogs.llm.is_streaming": isStream
7492
7690
  }
7493
- otelSpan = tracer.startSpan(`openai_agents.tool.${toolName}`, { attributes: attrs }, parentCtx);
7494
- } else if (spanType === "handoff") {
7495
- const attrs = { "neatlogs.span.kind": "AGENT" };
7496
- if (data?.from_agent) attrs["neatlogs.agent.handoff_from"] = String(data.from_agent);
7497
- if (data?.to_agent) attrs["neatlogs.agent.name"] = String(data.to_agent);
7498
- otelSpan = tracer.startSpan("openai_agents.handoff", { attributes: attrs }, parentCtx);
7499
- } else {
7500
- const attrs = { "neatlogs.span.kind": "CHAIN" };
7501
- otelSpan = tracer.startSpan(`openai_agents.${spanType || "span"}`, { attributes: attrs }, parentCtx);
7502
- }
7503
- this._spans.set(spanId, otelSpan);
7504
- this._startTimes.set(spanId, Date.now());
7505
- }
7506
- onSpanEnd(span2) {
7507
- const data = span2?.spanData ?? span2 ?? {};
7508
- const spanId = String(span2?.spanId ?? span2?.span_id ?? data?.span_id ?? "");
7509
- const otelSpan = this._spans.get(spanId);
7510
- if (!otelSpan) return;
7511
- const spanType = data?.type ?? data?.span_type ?? span2?.type ?? "";
7512
- const startTime = this._startTimes.get(spanId);
7513
- if (spanType === "response" || spanType === "generation" || spanType === "llm") {
7514
- const resp = data?._response ?? data?.response ?? {};
7515
- const model = data?.model ?? resp?.model;
7516
- if (model) otelSpan.setAttribute("neatlogs.llm.model_name", model);
7517
- const outputItems = data?.output ?? resp?.output;
7518
- if (Array.isArray(outputItems)) {
7519
- 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("");
7520
- if (text) {
7521
- otelSpan.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7522
- otelSpan.setAttribute("neatlogs.llm.output_messages.0.content", text.slice(0, 1e4));
7523
- }
7524
- const toolCalls = outputItems.filter((o) => o?.type === "function_call");
7525
- for (let i = 0; i < toolCalls.length; i++) {
7526
- const tc = toolCalls[i];
7527
- otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, tc.name ?? "");
7528
- otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, typeof tc.arguments === "string" ? tc.arguments : safeStringify6(tc.arguments ?? {}));
7529
- if (tc.callId ?? tc.id) otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, tc.callId ?? tc.id);
7691
+ }, import_api12.context.active());
7692
+ setInputAttributes(span2, opts);
7693
+ const ctx = import_api12.trace.setSpan(import_api12.context.active(), span2);
7694
+ const result = import_api12.context.with(ctx, () => original(opts, ...rest));
7695
+ return Promise.resolve(result).then(
7696
+ (response) => {
7697
+ if (isStream) {
7698
+ return wrapStream(response, span2);
7530
7699
  }
7531
- } else if (outputItems?.content) {
7532
- otelSpan.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7533
- const c = outputItems.content;
7534
- otelSpan.setAttribute("neatlogs.llm.output_messages.0.content", (typeof c === "string" ? c : safeStringify6(c)).slice(0, 1e4));
7700
+ finalizeResponse(span2, response);
7701
+ return response;
7702
+ },
7703
+ (err) => {
7704
+ recordError4(span2, err);
7705
+ throw err;
7535
7706
  }
7536
- const usage = data?.usage ?? resp?.usage;
7537
- if (usage) {
7538
- const inputTokens = usage.input_tokens ?? usage.prompt_tokens ?? usage.inputTokens;
7539
- const outputTokens = usage.output_tokens ?? usage.completion_tokens ?? usage.outputTokens;
7540
- const totalTokens = usage.total_tokens ?? usage.totalTokens;
7541
- if (inputTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.prompt", inputTokens);
7542
- if (outputTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.completion", outputTokens);
7543
- if (totalTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.total", totalTokens);
7544
- else if (inputTokens != null && outputTokens != null) {
7545
- otelSpan.setAttribute("neatlogs.llm.token_count.total", inputTokens + outputTokens);
7707
+ );
7708
+ };
7709
+ }
7710
+ function setInputAttributes(span2, opts) {
7711
+ let idx = 0;
7712
+ const config = opts?.config;
7713
+ const systemInstruction = config?.systemInstruction ?? config?.system_instruction;
7714
+ if (systemInstruction) {
7715
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, "system");
7716
+ span2.setAttribute(
7717
+ `neatlogs.llm.input_messages.${idx}.content`,
7718
+ typeof systemInstruction === "string" ? systemInstruction : safeStringify6(systemInstruction)
7719
+ );
7720
+ idx++;
7721
+ }
7722
+ const contents = opts?.contents;
7723
+ if (typeof contents === "string") {
7724
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, "user");
7725
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.content`, contents);
7726
+ } else if (Array.isArray(contents)) {
7727
+ for (const item of contents) {
7728
+ if (typeof item === "string") {
7729
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, "user");
7730
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.content`, item);
7731
+ idx++;
7732
+ } else if (item && typeof item === "object") {
7733
+ const role = item.role ?? "user";
7734
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, role);
7735
+ const parts = item.parts ?? [];
7736
+ const textParts = [];
7737
+ for (const part of parts) {
7738
+ if (typeof part === "string") textParts.push(part);
7739
+ else if (part?.text) textParts.push(part.text);
7546
7740
  }
7547
- }
7548
- } else if (spanType === "function" || spanType === "tool" || spanType === "tool_call") {
7549
- const output = data?.output ?? data?.result;
7550
- if (output != null) {
7551
- otelSpan.setAttribute("output.value", (typeof output === "string" ? output : safeStringify6(output)).slice(0, 1e4));
7552
- }
7553
- } else if (spanType === "agent" || spanType === "agent_run") {
7554
- const output = data?.output;
7555
- if (output != null) {
7556
- otelSpan.setAttribute("output.value", (typeof output === "string" ? output : safeStringify6(output)).slice(0, 1e4));
7741
+ span2.setAttribute(
7742
+ `neatlogs.llm.input_messages.${idx}.content`,
7743
+ textParts.length ? textParts.join("\n") : safeStringify6(parts)
7744
+ );
7745
+ idx++;
7557
7746
  }
7558
7747
  }
7559
- const error = data?.error ?? span2?.error;
7560
- if (error) {
7561
- if (error instanceof Error) {
7562
- otelSpan.setStatus({ code: import_api12.SpanStatusCode.ERROR, message: error.message });
7563
- otelSpan.recordException(error);
7564
- } else {
7565
- otelSpan.setStatus({ code: import_api12.SpanStatusCode.ERROR, message: String(error) });
7748
+ } else if (contents) {
7749
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, "user");
7750
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.content`, safeStringify6(contents));
7751
+ }
7752
+ const tools = config?.tools;
7753
+ if (Array.isArray(tools)) {
7754
+ let t = 0;
7755
+ for (const tool of tools) {
7756
+ const decls = tool?.functionDeclarations ?? tool?.function_declarations ?? [];
7757
+ for (const fn of decls) {
7758
+ span2.setAttribute(`neatlogs.llm.tools.${t}.name`, fn?.name ?? "");
7759
+ if (fn?.description) span2.setAttribute(`neatlogs.llm.tools.${t}.description`, fn.description);
7760
+ if (fn?.parameters) span2.setAttribute(`neatlogs.llm.tools.${t}.input_schema`, safeStringify6(fn.parameters));
7761
+ t++;
7566
7762
  }
7567
- } else {
7568
- otelSpan.setStatus({ code: import_api12.SpanStatusCode.OK });
7569
7763
  }
7570
- if (startTime) {
7571
- otelSpan.setAttribute("neatlogs.llm.metrics.duration_ms", Date.now() - startTime);
7764
+ }
7765
+ if (config) {
7766
+ if (config.temperature != null) span2.setAttribute("neatlogs.llm.temperature", config.temperature);
7767
+ if (config.topP != null) span2.setAttribute("neatlogs.llm.top_p", config.topP);
7768
+ if (config.topK != null) span2.setAttribute("neatlogs.llm.top_k", config.topK);
7769
+ const maxTokens = config.maxOutputTokens ?? config.max_output_tokens;
7770
+ if (maxTokens != null) span2.setAttribute("neatlogs.llm.max_tokens", maxTokens);
7771
+ const params = {};
7772
+ if (config.temperature != null) params.temperature = config.temperature;
7773
+ if (config.topP != null) params.top_p = config.topP;
7774
+ if (config.topK != null) params.top_k = config.topK;
7775
+ if (maxTokens != null) params.max_tokens = maxTokens;
7776
+ if (config.frequencyPenalty != null) params.frequency_penalty = config.frequencyPenalty;
7777
+ if (config.presencePenalty != null) params.presence_penalty = config.presencePenalty;
7778
+ if (Object.keys(params).length > 0) {
7779
+ span2.setAttribute("neatlogs.llm.invocation_parameters", JSON.stringify(params));
7572
7780
  }
7573
- otelSpan.end();
7574
- this._spans.delete(spanId);
7575
- this._startTimes.delete(spanId);
7576
7781
  }
7577
- shutdown() {
7578
- for (const [, span2] of this._spans) {
7579
- span2.setStatus({ code: import_api12.SpanStatusCode.ERROR, message: "Processor shutdown before span completed" });
7580
- span2.end();
7782
+ }
7783
+ function wrapStream(stream, span2) {
7784
+ const chunks = [];
7785
+ const originalAsyncIterator = stream?.[Symbol.asyncIterator]?.bind(stream);
7786
+ if (!originalAsyncIterator) {
7787
+ finalizeStreamChunks3(span2, chunks);
7788
+ return stream;
7789
+ }
7790
+ const wrapped = Object.create(Object.getPrototypeOf(stream));
7791
+ Object.assign(wrapped, stream);
7792
+ wrapped[Symbol.asyncIterator] = function() {
7793
+ const iterator = originalAsyncIterator();
7794
+ return {
7795
+ async next() {
7796
+ try {
7797
+ const result = await iterator.next();
7798
+ if (result.done) {
7799
+ finalizeStreamChunks3(span2, chunks);
7800
+ return result;
7801
+ }
7802
+ chunks.push(result.value);
7803
+ return result;
7804
+ } catch (err) {
7805
+ recordError4(span2, err);
7806
+ throw err;
7807
+ }
7808
+ },
7809
+ async return(value) {
7810
+ finalizeStreamChunks3(span2, chunks);
7811
+ return iterator.return?.(value) ?? { done: true, value: void 0 };
7812
+ },
7813
+ async throw(err) {
7814
+ recordError4(span2, err);
7815
+ return iterator.throw?.(err) ?? { done: true, value: void 0 };
7816
+ }
7817
+ };
7818
+ };
7819
+ return wrapped;
7820
+ }
7821
+ function finalizeStreamChunks3(span2, chunks) {
7822
+ const textParts = [];
7823
+ let finishReason = "";
7824
+ let usage = null;
7825
+ for (const chunk of chunks) {
7826
+ for (const candidate of chunk?.candidates ?? []) {
7827
+ for (const part of candidate?.content?.parts ?? []) {
7828
+ if (part?.text && !part?.thought) textParts.push(part.text);
7829
+ }
7830
+ if (candidate?.finishReason) finishReason = candidate.finishReason;
7581
7831
  }
7582
- this._spans.clear();
7583
- this._startTimes.clear();
7832
+ if (chunk?.usageMetadata) usage = chunk.usageMetadata;
7584
7833
  }
7585
- forceFlush() {
7834
+ const fullText = textParts.join("");
7835
+ if (fullText) {
7836
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7837
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", fullText);
7586
7838
  }
7587
- };
7839
+ if (finishReason) span2.setAttribute("neatlogs.llm.finish_reason", String(finishReason));
7840
+ setUsage(span2, usage);
7841
+ span2.setStatus({ code: import_api12.SpanStatusCode.OK });
7842
+ span2.end();
7843
+ }
7844
+ function finalizeResponse(span2, response) {
7845
+ const textParts = [];
7846
+ let toolIdx = 0;
7847
+ for (const candidate of response?.candidates ?? []) {
7848
+ for (const part of candidate?.content?.parts ?? []) {
7849
+ if (part?.text && !part?.thought) {
7850
+ textParts.push(part.text);
7851
+ } else if (part?.thought && part?.text) {
7852
+ span2.setAttribute("neatlogs.llm.output_messages.0.thinking", part.text);
7853
+ } else if (part?.functionCall) {
7854
+ const fc = part.functionCall;
7855
+ span2.setAttribute(`neatlogs.llm.tool_calls.${toolIdx}.name`, fc?.name ?? "");
7856
+ span2.setAttribute(`neatlogs.llm.tool_calls.${toolIdx}.arguments`, safeStringify6(fc?.args ?? {}));
7857
+ toolIdx++;
7858
+ }
7859
+ }
7860
+ if (candidate?.finishReason) span2.setAttribute("neatlogs.llm.finish_reason", String(candidate.finishReason));
7861
+ }
7862
+ if (textParts.length) {
7863
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7864
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", textParts.join(""));
7865
+ }
7866
+ setUsage(span2, response?.usageMetadata);
7867
+ span2.setStatus({ code: import_api12.SpanStatusCode.OK });
7868
+ span2.end();
7869
+ }
7870
+ function setUsage(span2, usage) {
7871
+ if (!usage) return;
7872
+ if (usage.promptTokenCount != null) span2.setAttribute("neatlogs.llm.token_count.prompt", usage.promptTokenCount);
7873
+ if (usage.candidatesTokenCount != null) span2.setAttribute("neatlogs.llm.token_count.completion", usage.candidatesTokenCount);
7874
+ if (usage.totalTokenCount != null) span2.setAttribute("neatlogs.llm.token_count.total", usage.totalTokenCount);
7875
+ if (usage.cachedContentTokenCount != null) span2.setAttribute("neatlogs.llm.token_count.cache_read", usage.cachedContentTokenCount);
7876
+ if (usage.thoughtsTokenCount != null) span2.setAttribute("neatlogs.llm.token_count.reasoning", usage.thoughtsTokenCount);
7877
+ }
7588
7878
  function safeStringify6(value) {
7589
7879
  try {
7590
7880
  return typeof value === "string" ? value : JSON.stringify(value);
@@ -7592,525 +7882,2440 @@ function safeStringify6(value) {
7592
7882
  return "";
7593
7883
  }
7594
7884
  }
7595
-
7596
- // src/mastra-wrap.ts
7597
- var import_api13 = require("@opentelemetry/api");
7598
- var TRACER_NAME7 = "neatlogs.mastra";
7599
- var PATCH_FLAG = "_neatlogs_patched";
7600
- function wrapMastra(entity) {
7601
- if (!entity || entity[PATCH_FLAG]) return entity;
7602
- const e = entity;
7603
- const className = entity.constructor?.name ?? "";
7604
- if (isRootMastra(e)) {
7605
- const proxied = wrapRootMastra(e);
7606
- markPatched(proxied);
7607
- return proxied;
7608
- }
7609
- if (isAgent(e, className)) {
7610
- patchAgent(e);
7611
- } else if (isWorkflow(e, className)) {
7612
- patchWorkflow(e);
7613
- } else if (isVector(e, className)) {
7614
- patchVector(e);
7615
- } else if (isMemory(e, className)) {
7616
- patchMemory(e);
7617
- } else if (isDocument(e, className)) {
7618
- patchDocument(e);
7885
+ function recordError4(span2, err) {
7886
+ if (err instanceof Error) {
7887
+ span2.setStatus({ code: import_api12.SpanStatusCode.ERROR, message: err.message });
7888
+ span2.recordException(err);
7889
+ } else {
7890
+ span2.setStatus({ code: import_api12.SpanStatusCode.ERROR, message: String(err) });
7619
7891
  }
7620
- markPatched(e);
7621
- return entity;
7622
- }
7623
- function isRootMastra(e) {
7624
- return typeof e.getAgent === "function" && typeof e.getWorkflow === "function";
7892
+ span2.end();
7625
7893
  }
7626
- function isAgent(e, className) {
7627
- return className === "Agent" || typeof e.generate === "function" || typeof e.stream === "function";
7894
+
7895
+ // src/bedrock.ts
7896
+ var import_api13 = require("@opentelemetry/api");
7897
+ var TRACER_NAME7 = "neatlogs.bedrock";
7898
+ var PROVIDER3 = "bedrock";
7899
+ function traceTool5(name, fn) {
7900
+ return async function tracedTool(args) {
7901
+ const tracer = import_api13.trace.getTracer(TRACER_NAME7);
7902
+ return tracer.startActiveSpan(
7903
+ `tool.${name}`,
7904
+ {
7905
+ attributes: {
7906
+ "neatlogs.span.kind": "TOOL",
7907
+ "neatlogs.tool.name": name,
7908
+ "input.value": safeStringify7(args)
7909
+ }
7910
+ },
7911
+ import_api13.context.active(),
7912
+ async (span2) => {
7913
+ try {
7914
+ const result = await fn(args);
7915
+ span2.setAttribute("output.value", safeStringify7(result));
7916
+ span2.setStatus({ code: import_api13.SpanStatusCode.OK });
7917
+ return result;
7918
+ } catch (err) {
7919
+ recordError5(span2, err);
7920
+ throw err;
7921
+ } finally {
7922
+ span2.end();
7923
+ }
7924
+ }
7925
+ );
7926
+ };
7628
7927
  }
7629
- function isWorkflow(e, className) {
7630
- return className === "Workflow" || typeof e.createRun === "function";
7928
+ function wrapBedrock(client) {
7929
+ const c = client;
7930
+ if (c._neatlogsBedrockPatched) return client;
7931
+ if (typeof c.send !== "function") return client;
7932
+ const originalSend = c.send.bind(c);
7933
+ c.send = function(command, ...rest) {
7934
+ const name = command?.constructor?.name ?? "";
7935
+ const input = command?.input ?? {};
7936
+ if (name === "ConverseCommand") {
7937
+ return tracedConverse(originalSend, command, input, rest, false);
7938
+ }
7939
+ if (name === "ConverseStreamCommand") {
7940
+ return tracedConverse(originalSend, command, input, rest, true);
7941
+ }
7942
+ if (name === "InvokeModelCommand") {
7943
+ return tracedInvokeModel(originalSend, command, input, rest, false);
7944
+ }
7945
+ if (name === "InvokeModelWithResponseStreamCommand") {
7946
+ return tracedInvokeModel(originalSend, command, input, rest, true);
7947
+ }
7948
+ return originalSend(command, ...rest);
7949
+ };
7950
+ c._neatlogsBedrockPatched = true;
7951
+ return client;
7631
7952
  }
7632
- function isVector(e, className) {
7633
- return /Vector/.test(className) || typeof e.query === "function" && typeof e.upsert === "function";
7953
+ function vendorFromModel(modelId) {
7954
+ let tail = String(modelId ?? "").split("/").pop() ?? "";
7955
+ for (const prefix of ["us.", "eu.", "apac.", "us-gov."]) {
7956
+ if (tail.startsWith(prefix)) tail = tail.slice(prefix.length);
7957
+ }
7958
+ const vendor = tail.includes(".") ? tail.split(".")[0] : "";
7959
+ return vendor || "bedrock";
7634
7960
  }
7635
- function isMemory(e, className) {
7636
- return /Memory/.test(className) || typeof e.recall === "function" && typeof e.saveMessages === "function";
7961
+ function startSpan(name, modelId, isStream) {
7962
+ return import_api13.trace.getTracer(TRACER_NAME7).startSpan(name, {
7963
+ attributes: {
7964
+ "neatlogs.span.kind": "LLM",
7965
+ "neatlogs.llm.provider": PROVIDER3,
7966
+ "neatlogs.llm.system": vendorFromModel(modelId),
7967
+ "neatlogs.llm.model_name": String(modelId ?? ""),
7968
+ "neatlogs.llm.is_streaming": isStream
7969
+ }
7970
+ }, import_api13.context.active());
7971
+ }
7972
+ function tracedConverse(originalSend, command, input, rest, isStream) {
7973
+ const span2 = startSpan(
7974
+ isStream ? "bedrock.converse_stream" : "bedrock.converse",
7975
+ input?.modelId,
7976
+ isStream
7977
+ );
7978
+ setConverseInput(span2, input);
7979
+ const ctx = import_api13.trace.setSpan(import_api13.context.active(), span2);
7980
+ const promise = import_api13.context.with(ctx, () => originalSend(command, ...rest));
7981
+ return promise.then(
7982
+ (response) => {
7983
+ if (isStream) {
7984
+ return wrapConverseStream(response, span2);
7985
+ }
7986
+ finalizeConverse(span2, response);
7987
+ return response;
7988
+ },
7989
+ (err) => {
7990
+ recordError5(span2, err);
7991
+ throw err;
7992
+ }
7993
+ );
7637
7994
  }
7638
- function isDocument(e, className) {
7639
- return className === "MDocument" || typeof e.chunk === "function" && typeof e.getDocs === "function";
7995
+ function setConverseInput(span2, input) {
7996
+ let idx = 0;
7997
+ if (Array.isArray(input?.system)) {
7998
+ const text = input.system.map((b) => b?.text ?? "").join(" ").trim();
7999
+ if (text) {
8000
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, "system");
8001
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.content`, text);
8002
+ idx++;
8003
+ }
8004
+ }
8005
+ for (const msg of input?.messages ?? []) {
8006
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, msg?.role ?? "user");
8007
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.content`, converseBlocksToText(msg?.content));
8008
+ idx++;
8009
+ }
8010
+ const cfg = input?.inferenceConfig ?? {};
8011
+ if (cfg.temperature != null) span2.setAttribute("neatlogs.llm.temperature", cfg.temperature);
8012
+ if (cfg.topP != null) span2.setAttribute("neatlogs.llm.top_p", cfg.topP);
8013
+ if (cfg.maxTokens != null) span2.setAttribute("neatlogs.llm.max_tokens", cfg.maxTokens);
8014
+ const tools = input?.toolConfig?.tools ?? [];
8015
+ for (let i = 0; i < tools.length; i++) {
8016
+ const spec = tools[i]?.toolSpec ?? {};
8017
+ if (spec.name) span2.setAttribute(`neatlogs.llm.tools.${i}.name`, spec.name);
8018
+ if (spec.description) span2.setAttribute(`neatlogs.llm.tools.${i}.description`, spec.description);
8019
+ if (spec.inputSchema) span2.setAttribute(`neatlogs.llm.tools.${i}.input_schema`, safeStringify7(spec.inputSchema));
8020
+ }
7640
8021
  }
7641
- function patchAgent(agent) {
7642
- patchAgentMethod(agent, "generate", false);
7643
- patchAgentMethod(agent, "stream", true);
8022
+ function converseBlocksToText(content) {
8023
+ if (typeof content === "string") return content;
8024
+ if (!Array.isArray(content)) return safeStringify7(content);
8025
+ const parts = [];
8026
+ for (const block of content) {
8027
+ if (block && typeof block === "object") {
8028
+ if ("text" in block) parts.push(String(block.text));
8029
+ else if ("toolResult" in block) parts.push(safeStringify7(block.toolResult));
8030
+ else if ("toolUse" in block) parts.push(safeStringify7(block.toolUse));
8031
+ else parts.push(safeStringify7(block));
8032
+ } else {
8033
+ parts.push(String(block));
8034
+ }
8035
+ }
8036
+ return parts.join("\n");
7644
8037
  }
7645
- function patchAgentMethod(agent, method, streaming) {
7646
- if (typeof agent[method] !== "function") return;
7647
- const orig = agent[method].bind(agent);
7648
- agent[method] = async function tracedAgentMethod(input, opts) {
7649
- const agentName = agent.name ?? agent.id ?? "mastra_agent";
7650
- const model = extractModelId(agent.model);
7651
- installAgentLlmHook(agent);
7652
- installAgentToolHooks(agent);
7653
- const attrs = {
7654
- "neatlogs.span.kind": "AGENT",
7655
- "neatlogs.agent.name": agentName,
7656
- "input.value": toInputValue(input)
7657
- };
7658
- if (model) attrs["neatlogs.llm.model_name"] = model;
7659
- if (agent.instructions && typeof agent.instructions === "string") {
7660
- attrs["neatlogs.llm.system_prompt"] = agent.instructions.slice(0, 5e3);
8038
+ function finalizeConverse(span2, response) {
8039
+ const content = response?.output?.message?.content ?? [];
8040
+ const textParts = [];
8041
+ let toolIdx = 0;
8042
+ for (const block of content) {
8043
+ if (!block || typeof block !== "object") continue;
8044
+ if ("text" in block) {
8045
+ textParts.push(String(block.text));
8046
+ } else if ("toolUse" in block) {
8047
+ const tu = block.toolUse;
8048
+ span2.setAttribute(`neatlogs.llm.tool_calls.${toolIdx}.id`, String(tu?.toolUseId ?? ""));
8049
+ span2.setAttribute(`neatlogs.llm.tool_calls.${toolIdx}.name`, String(tu?.name ?? ""));
8050
+ span2.setAttribute(`neatlogs.llm.tool_calls.${toolIdx}.arguments`, safeStringify7(tu?.input ?? {}));
8051
+ toolIdx++;
7661
8052
  }
7662
- if (streaming) attrs["neatlogs.llm.is_streaming"] = true;
7663
- if (streaming) {
7664
- const tracer = import_api13.trace.getTracer(TRACER_NAME7);
7665
- const span2 = tracer.startSpan(`mastra.agent.${agentName}`, { attributes: attrs }, import_api13.context.active());
7666
- const ctx = import_api13.trace.setSpan(import_api13.context.active(), span2);
7667
- try {
7668
- const result = await import_api13.context.with(ctx, () => orig(input, opts));
7669
- return wrapStreamingOutput(result, span2, ctx);
7670
- } catch (err) {
7671
- recordError3(span2, err);
7672
- span2.end();
7673
- throw err;
7674
- }
8053
+ }
8054
+ if (textParts.length) {
8055
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
8056
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", textParts.join(""));
8057
+ }
8058
+ if (response?.stopReason) span2.setAttribute("neatlogs.llm.finish_reason", String(response.stopReason));
8059
+ setConverseUsage(span2, response?.usage);
8060
+ span2.setStatus({ code: import_api13.SpanStatusCode.OK });
8061
+ span2.end();
8062
+ }
8063
+ function setConverseUsage(span2, usage) {
8064
+ if (!usage) return;
8065
+ if (usage.inputTokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", usage.inputTokens);
8066
+ if (usage.outputTokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", usage.outputTokens);
8067
+ if (usage.totalTokens != null) span2.setAttribute("neatlogs.llm.token_count.total", usage.totalTokens);
8068
+ if (usage.cacheReadInputTokens != null) span2.setAttribute("neatlogs.llm.token_count.cache_read", usage.cacheReadInputTokens);
8069
+ if (usage.cacheWriteInputTokens != null) span2.setAttribute("neatlogs.llm.token_count.cache_write", usage.cacheWriteInputTokens);
8070
+ }
8071
+ function wrapConverseStream(response, span2) {
8072
+ const stream = response?.stream;
8073
+ if (!stream || typeof stream[Symbol.asyncIterator] !== "function") {
8074
+ span2.setStatus({ code: import_api13.SpanStatusCode.OK });
8075
+ span2.end();
8076
+ return response;
8077
+ }
8078
+ const originalIterator = stream[Symbol.asyncIterator].bind(stream);
8079
+ const textParts = [];
8080
+ const toolCalls = {};
8081
+ let finishReason = "";
8082
+ let usage = null;
8083
+ const wrappedStream = {
8084
+ [Symbol.asyncIterator]() {
8085
+ const iterator = originalIterator();
8086
+ return {
8087
+ async next() {
8088
+ try {
8089
+ const result = await iterator.next();
8090
+ if (result.done) {
8091
+ finalizeConverseStream(span2, textParts, toolCalls, finishReason, usage);
8092
+ return result;
8093
+ }
8094
+ const ev = result.value;
8095
+ const delta = ev?.contentBlockDelta?.delta;
8096
+ if (delta?.text) textParts.push(delta.text);
8097
+ if (delta?.toolUse?.input) {
8098
+ const idx = ev.contentBlockDelta.contentBlockIndex ?? 0;
8099
+ toolCalls[idx] = toolCalls[idx] ?? { id: "", name: "", arguments: "" };
8100
+ toolCalls[idx].arguments += delta.toolUse.input;
8101
+ }
8102
+ const startBlk = ev?.contentBlockStart?.start?.toolUse;
8103
+ if (startBlk) {
8104
+ const idx = ev.contentBlockStart.contentBlockIndex ?? 0;
8105
+ toolCalls[idx] = toolCalls[idx] ?? { id: "", name: "", arguments: "" };
8106
+ toolCalls[idx].name = startBlk.name ?? "";
8107
+ toolCalls[idx].id = startBlk.toolUseId ?? "";
8108
+ }
8109
+ if (ev?.messageStop?.stopReason) finishReason = ev.messageStop.stopReason;
8110
+ if (ev?.metadata?.usage) usage = ev.metadata.usage;
8111
+ return result;
8112
+ } catch (err) {
8113
+ recordError5(span2, err);
8114
+ throw err;
8115
+ }
8116
+ },
8117
+ async return(value) {
8118
+ finalizeConverseStream(span2, textParts, toolCalls, finishReason, usage);
8119
+ return iterator.return?.(value) ?? { done: true, value: void 0 };
8120
+ }
8121
+ };
7675
8122
  }
7676
- return withActiveSpan(`mastra.agent.${agentName}`, attrs, async (span2) => {
7677
- const result = await orig(input, opts);
7678
- finalizeAgentResult(span2, result);
7679
- return result;
7680
- });
7681
8123
  };
8124
+ response.stream = wrappedStream;
8125
+ return response;
7682
8126
  }
7683
- function installAgentLlmHook(agent) {
7684
- if (agent.__neatlogs_llm_hook || typeof agent.getLLM !== "function") return;
7685
- agent.__neatlogs_llm_hook = true;
7686
- const origGetLLM = agent.getLLM.bind(agent);
7687
- agent.getLLM = function patchedGetLLM(...args) {
7688
- const out = origGetLLM(...args);
7689
- return Promise.resolve(out).then((llm) => {
8127
+ function finalizeConverseStream(span2, textParts, toolCalls, finishReason, usage) {
8128
+ const full = textParts.join("");
8129
+ if (full) {
8130
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
8131
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", full);
8132
+ }
8133
+ let j = 0;
8134
+ for (const tc of Object.values(toolCalls)) {
8135
+ if (tc.id) span2.setAttribute(`neatlogs.llm.tool_calls.${j}.id`, tc.id);
8136
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.name`, tc.name);
8137
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.arguments`, tc.arguments);
8138
+ j++;
8139
+ }
8140
+ if (finishReason) span2.setAttribute("neatlogs.llm.finish_reason", String(finishReason));
8141
+ setConverseUsage(span2, usage);
8142
+ span2.setStatus({ code: import_api13.SpanStatusCode.OK });
8143
+ span2.end();
8144
+ }
8145
+ function isEmbeddingModel(modelId) {
8146
+ return String(modelId ?? "").toLowerCase().includes("embed");
8147
+ }
8148
+ function tracedInvokeModel(originalSend, command, input, rest, isStream) {
8149
+ const vendor = vendorFromModel(input?.modelId);
8150
+ const isEmbedding = !isStream && isEmbeddingModel(input?.modelId);
8151
+ const bodyIn = decodeBody(input?.body);
8152
+ let span2;
8153
+ if (isEmbedding) {
8154
+ span2 = import_api13.trace.getTracer(TRACER_NAME7).startSpan("bedrock.invoke_model", {
8155
+ attributes: {
8156
+ "neatlogs.span.kind": "EMBEDDING",
8157
+ "neatlogs.llm.provider": PROVIDER3,
8158
+ "neatlogs.embedding.model_name": String(input?.modelId ?? "")
8159
+ }
8160
+ }, import_api13.context.active());
8161
+ const text = bodyIn?.inputText ?? bodyIn?.texts ?? bodyIn?.input_text;
8162
+ if (text) {
8163
+ span2.setAttribute("neatlogs.embedding.text", typeof text === "string" ? text : safeStringify7(text));
8164
+ }
8165
+ } else {
8166
+ span2 = startSpan(
8167
+ isStream ? "bedrock.invoke_model_with_response_stream" : "bedrock.invoke_model",
8168
+ input?.modelId,
8169
+ isStream
8170
+ );
8171
+ setInvokeInput(span2, vendor, bodyIn);
8172
+ }
8173
+ const ctx = import_api13.trace.setSpan(import_api13.context.active(), span2);
8174
+ const promise = import_api13.context.with(ctx, () => originalSend(command, ...rest));
8175
+ return promise.then(
8176
+ (response) => {
8177
+ if (isStream) {
8178
+ return wrapInvokeStream(response, span2, vendor);
8179
+ }
7690
8180
  try {
7691
- const model = typeof llm?.getModel === "function" ? llm.getModel() : llm;
7692
- patchModelInPlace(model);
8181
+ if (isEmbedding) {
8182
+ finalizeInvokeEmbedding(span2, decodeBody(response?.body));
8183
+ } else {
8184
+ finalizeInvoke(span2, vendor, decodeBody(response?.body));
8185
+ }
7693
8186
  } catch {
8187
+ span2.setStatus({ code: import_api13.SpanStatusCode.OK });
8188
+ span2.end();
7694
8189
  }
7695
- return llm;
7696
- });
7697
- };
8190
+ return response;
8191
+ },
8192
+ (err) => {
8193
+ recordError5(span2, err);
8194
+ throw err;
8195
+ }
8196
+ );
7698
8197
  }
7699
- function patchModelInPlace(model) {
7700
- if (!model || model.__neatlogs_model_patched) return;
7701
- model.__neatlogs_model_patched = true;
7702
- const modelId = model.modelId ?? model.modelName ?? "";
7703
- const provider = model.provider ?? "";
7704
- for (const fn of ["doGenerate", "doStream"]) {
7705
- if (typeof model[fn] !== "function") continue;
7706
- const orig = model[fn].bind(model);
7707
- const isStream = fn === "doStream";
7708
- model[fn] = function tracedModelCall(callOpts) {
7709
- const attrs = { "neatlogs.span.kind": "LLM" };
7710
- if (modelId) attrs["neatlogs.llm.model_name"] = modelId;
7711
- if (provider) attrs["neatlogs.llm.provider"] = provider;
7712
- if (isStream) attrs["neatlogs.llm.is_streaming"] = true;
7713
- const promptInput = callOpts?.prompt ?? callOpts?.messages;
7714
- if (promptInput !== void 0) attrs["input.value"] = safeStringify7(promptInput).slice(0, 1e4);
7715
- captureInvocationParams(attrs, callOpts);
7716
- return withActiveSpan(`mastra.llm.${modelId || "model"}.${fn}`, attrs, async (span2) => {
7717
- const result = await orig(callOpts);
7718
- if (!isStream) finalizeModelResult(span2, result);
7719
- else if (result?.usage) recordUsage(span2, result.usage);
7720
- return result;
7721
- });
7722
- };
8198
+ function finalizeInvokeEmbedding(span2, body) {
8199
+ const emb = body?.embedding;
8200
+ const embs = body?.embeddings;
8201
+ if (Array.isArray(emb)) {
8202
+ span2.setAttribute("neatlogs.embedding.count", 1);
8203
+ span2.setAttribute("neatlogs.embedding.dimensions", emb.length);
8204
+ } else if (Array.isArray(embs) && embs.length) {
8205
+ span2.setAttribute("neatlogs.embedding.count", embs.length);
8206
+ if (Array.isArray(embs[0])) span2.setAttribute("neatlogs.embedding.dimensions", embs[0].length);
8207
+ }
8208
+ if (body?.inputTextTokenCount != null) {
8209
+ span2.setAttribute("neatlogs.llm.token_count.prompt", body.inputTextTokenCount);
8210
+ span2.setAttribute("neatlogs.embedding.token_count", body.inputTextTokenCount);
8211
+ }
8212
+ span2.setStatus({ code: import_api13.SpanStatusCode.OK });
8213
+ span2.end();
8214
+ }
8215
+ function decodeBody(body) {
8216
+ try {
8217
+ if (body == null) return {};
8218
+ if (typeof body === "string") return JSON.parse(body);
8219
+ if (body instanceof Uint8Array) return JSON.parse(new TextDecoder().decode(body));
8220
+ if (typeof body === "object" && typeof body.byteLength === "number") {
8221
+ return JSON.parse(new TextDecoder().decode(body));
8222
+ }
8223
+ if (typeof body === "object") return body;
8224
+ } catch {
7723
8225
  }
8226
+ return {};
7724
8227
  }
7725
- function installAgentToolHooks(agent) {
7726
- if (agent.__neatlogs_tool_hook) return;
7727
- let tools;
8228
+ function setInvokeInput(span2, vendor, body) {
8229
+ let idx = 0;
8230
+ if (body?.system) {
8231
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, "system");
8232
+ span2.setAttribute(
8233
+ `neatlogs.llm.input_messages.${idx}.content`,
8234
+ typeof body.system === "string" ? body.system : safeStringify7(body.system)
8235
+ );
8236
+ idx++;
8237
+ }
8238
+ if (Array.isArray(body?.messages)) {
8239
+ for (const msg of body.messages) {
8240
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, msg?.role ?? "user");
8241
+ span2.setAttribute(
8242
+ `neatlogs.llm.input_messages.${idx}.content`,
8243
+ typeof msg?.content === "string" ? msg.content : safeStringify7(msg?.content)
8244
+ );
8245
+ idx++;
8246
+ }
8247
+ } else if (body?.prompt) {
8248
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, "user");
8249
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.content`, String(body.prompt));
8250
+ } else if (body?.inputText) {
8251
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, "user");
8252
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.content`, String(body.inputText));
8253
+ }
8254
+ if (body?.temperature != null) span2.setAttribute("neatlogs.llm.temperature", body.temperature);
8255
+ if (body?.top_p != null) span2.setAttribute("neatlogs.llm.top_p", body.top_p);
8256
+ const maxTokens = body?.max_tokens ?? body?.maxTokens ?? body?.max_tokens_to_sample;
8257
+ if (maxTokens != null) span2.setAttribute("neatlogs.llm.max_tokens", maxTokens);
8258
+ const cfg = body?.textGenerationConfig;
8259
+ if (cfg) {
8260
+ if (cfg.temperature != null) span2.setAttribute("neatlogs.llm.temperature", cfg.temperature);
8261
+ if (cfg.topP != null) span2.setAttribute("neatlogs.llm.top_p", cfg.topP);
8262
+ if (cfg.maxTokenCount != null) span2.setAttribute("neatlogs.llm.max_tokens", cfg.maxTokenCount);
8263
+ }
8264
+ }
8265
+ function finalizeInvoke(span2, vendor, body) {
8266
+ let text;
8267
+ let promptTokens;
8268
+ let completionTokens;
8269
+ let finishReason;
8270
+ if (vendor === "anthropic") {
8271
+ if (Array.isArray(body?.content)) {
8272
+ text = body.content.filter((b) => b?.type === "text").map((b) => b.text).join("");
8273
+ let toolIdx = 0;
8274
+ for (const b of body.content) {
8275
+ if (b?.type === "tool_use") {
8276
+ span2.setAttribute(`neatlogs.llm.tool_calls.${toolIdx}.id`, String(b.id ?? ""));
8277
+ span2.setAttribute(`neatlogs.llm.tool_calls.${toolIdx}.name`, String(b.name ?? ""));
8278
+ span2.setAttribute(`neatlogs.llm.tool_calls.${toolIdx}.arguments`, safeStringify7(b.input ?? {}));
8279
+ toolIdx++;
8280
+ }
8281
+ }
8282
+ } else if (body?.completion != null) {
8283
+ text = body.completion;
8284
+ }
8285
+ promptTokens = body?.usage?.input_tokens;
8286
+ completionTokens = body?.usage?.output_tokens;
8287
+ finishReason = body?.stop_reason;
8288
+ } else if (vendor === "amazon") {
8289
+ const r = Array.isArray(body?.results) ? body.results[0] : void 0;
8290
+ if (r) {
8291
+ text = r.outputText;
8292
+ completionTokens = r.tokenCount;
8293
+ finishReason = r.completionReason;
8294
+ }
8295
+ promptTokens = body?.inputTextTokenCount;
8296
+ } else if (vendor === "meta") {
8297
+ text = body?.generation;
8298
+ promptTokens = body?.prompt_token_count;
8299
+ completionTokens = body?.generation_token_count;
8300
+ finishReason = body?.stop_reason;
8301
+ } else if (vendor === "cohere") {
8302
+ const g = Array.isArray(body?.generations) ? body.generations[0] : void 0;
8303
+ if (g) {
8304
+ text = g.text;
8305
+ finishReason = g.finish_reason;
8306
+ }
8307
+ } else {
8308
+ text = body?.generation ?? body?.completion ?? body?.outputText;
8309
+ }
8310
+ if (text) {
8311
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
8312
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", String(text));
8313
+ }
8314
+ if (promptTokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", promptTokens);
8315
+ if (completionTokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", completionTokens);
8316
+ if (promptTokens != null && completionTokens != null) {
8317
+ span2.setAttribute("neatlogs.llm.token_count.total", promptTokens + completionTokens);
8318
+ }
8319
+ if (finishReason) span2.setAttribute("neatlogs.llm.finish_reason", String(finishReason));
8320
+ span2.setStatus({ code: import_api13.SpanStatusCode.OK });
8321
+ span2.end();
8322
+ }
8323
+ function wrapInvokeStream(response, span2, vendor) {
8324
+ const body = response?.body;
8325
+ if (!body || typeof body[Symbol.asyncIterator] !== "function") {
8326
+ span2.setStatus({ code: import_api13.SpanStatusCode.OK });
8327
+ span2.end();
8328
+ return response;
8329
+ }
8330
+ const originalIterator = body[Symbol.asyncIterator].bind(body);
8331
+ const textParts = [];
8332
+ let promptTokens;
8333
+ let completionTokens;
8334
+ let finishReason;
8335
+ const finalize = () => {
8336
+ const full = textParts.join("");
8337
+ if (full) {
8338
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
8339
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", full);
8340
+ }
8341
+ if (promptTokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", promptTokens);
8342
+ if (completionTokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", completionTokens);
8343
+ if (finishReason) span2.setAttribute("neatlogs.llm.finish_reason", String(finishReason));
8344
+ span2.setStatus({ code: import_api13.SpanStatusCode.OK });
8345
+ span2.end();
8346
+ };
8347
+ const wrappedBody = {
8348
+ [Symbol.asyncIterator]() {
8349
+ const iterator = originalIterator();
8350
+ return {
8351
+ async next() {
8352
+ try {
8353
+ const result = await iterator.next();
8354
+ if (result.done) {
8355
+ finalize();
8356
+ return result;
8357
+ }
8358
+ const data = decodeBody(result.value?.chunk?.bytes);
8359
+ if (data?.type === "content_block_delta") {
8360
+ textParts.push(data?.delta?.text ?? "");
8361
+ } else if (data?.type === "message_delta") {
8362
+ if (data?.delta?.stop_reason) finishReason = data.delta.stop_reason;
8363
+ if (data?.usage?.output_tokens != null) completionTokens = data.usage.output_tokens;
8364
+ }
8365
+ if (data?.outputText) textParts.push(data.outputText);
8366
+ if (data?.generation) textParts.push(data.generation);
8367
+ const metrics2 = data?.["amazon-bedrock-invocationMetrics"];
8368
+ if (metrics2) {
8369
+ promptTokens = metrics2.inputTokenCount ?? promptTokens;
8370
+ completionTokens = metrics2.outputTokenCount ?? completionTokens;
8371
+ }
8372
+ return result;
8373
+ } catch (err) {
8374
+ recordError5(span2, err);
8375
+ throw err;
8376
+ }
8377
+ },
8378
+ async return(value) {
8379
+ finalize();
8380
+ return iterator.return?.(value) ?? { done: true, value: void 0 };
8381
+ }
8382
+ };
8383
+ }
8384
+ };
8385
+ response.body = wrappedBody;
8386
+ return response;
8387
+ }
8388
+ function safeStringify7(value) {
7728
8389
  try {
7729
- tools = typeof agent.listTools === "function" ? agent.listTools() : void 0;
8390
+ return typeof value === "string" ? value : JSON.stringify(value);
7730
8391
  } catch {
7731
- tools = void 0;
8392
+ return "";
7732
8393
  }
7733
- if (!tools || typeof tools !== "object") return;
7734
- agent.__neatlogs_tool_hook = true;
7735
- for (const [key, tool] of Object.entries(tools)) {
7736
- patchToolExecute(tool, key);
8394
+ }
8395
+ function recordError5(span2, err) {
8396
+ if (err instanceof Error) {
8397
+ span2.setStatus({ code: import_api13.SpanStatusCode.ERROR, message: err.message });
8398
+ span2.recordException(err);
8399
+ } else {
8400
+ span2.setStatus({ code: import_api13.SpanStatusCode.ERROR, message: String(err) });
8401
+ }
8402
+ span2.end();
8403
+ }
8404
+
8405
+ // src/langchain.ts
8406
+ var import_api14 = require("@opentelemetry/api");
8407
+ var TRACER_NAME8 = "neatlogs.langchain";
8408
+ function langchainHandler(opts) {
8409
+ return new NeatlogsCallbackHandler(opts);
8410
+ }
8411
+ var NeatlogsCallbackHandler = class {
8412
+ name = "neatlogs";
8413
+ _spans = /* @__PURE__ */ new Map();
8414
+ _workflowName;
8415
+ constructor(opts) {
8416
+ this._workflowName = opts?.workflowName;
8417
+ }
8418
+ // --- Chain/Graph callbacks ---
8419
+ async handleChainStart(serialized, inputs, runId, parentRunId, tags, metadata) {
8420
+ const tracer = import_api14.trace.getTracer(TRACER_NAME8);
8421
+ const name = serialized?.name ?? serialized?.id?.at(-1) ?? "chain";
8422
+ const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
8423
+ const parentCtx = parentSpan ? import_api14.trace.setSpan(import_api14.context.active(), parentSpan) : import_api14.context.active();
8424
+ const attrs = {
8425
+ "neatlogs.span.kind": "CHAIN",
8426
+ "neatlogs.chain.name": name
8427
+ };
8428
+ if (this._workflowName) attrs["neatlogs.workflow.name"] = this._workflowName;
8429
+ if (inputs) attrs["input.value"] = safeStringify8(inputs);
8430
+ if (tags?.length) attrs["neatlogs.tags"] = tags.join(",");
8431
+ const span2 = tracer.startSpan(`langchain.chain.${name}`, { attributes: attrs }, parentCtx);
8432
+ this._spans.set(runId, span2);
8433
+ }
8434
+ async handleChainEnd(outputs, runId) {
8435
+ const span2 = this._spans.get(runId);
8436
+ if (!span2) return;
8437
+ if (outputs) span2.setAttribute("output.value", safeStringify8(outputs));
8438
+ span2.setStatus({ code: import_api14.SpanStatusCode.OK });
8439
+ span2.end();
8440
+ this._spans.delete(runId);
8441
+ }
8442
+ async handleChainError(error, runId) {
8443
+ const span2 = this._spans.get(runId);
8444
+ if (!span2) return;
8445
+ span2.setStatus({ code: import_api14.SpanStatusCode.ERROR, message: error.message });
8446
+ span2.recordException(error);
8447
+ span2.end();
8448
+ this._spans.delete(runId);
8449
+ }
8450
+ // --- LLM callbacks ---
8451
+ async handleLLMStart(serialized, prompts, runId, parentRunId, extraParams) {
8452
+ const tracer = import_api14.trace.getTracer(TRACER_NAME8);
8453
+ const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? "";
8454
+ const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
8455
+ const parentCtx = parentSpan ? import_api14.trace.setSpan(import_api14.context.active(), parentSpan) : import_api14.context.active();
8456
+ const attrs = {
8457
+ "neatlogs.span.kind": "LLM",
8458
+ "neatlogs.llm.provider": detectProvider(model),
8459
+ "neatlogs.llm.model_name": model
8460
+ };
8461
+ for (let i = 0; i < prompts.length; i++) {
8462
+ attrs[`neatlogs.llm.input_messages.${i}.role`] = "user";
8463
+ attrs[`neatlogs.llm.input_messages.${i}.content`] = prompts[i];
8464
+ }
8465
+ if (extraParams?.invocation_params) {
8466
+ const p = extraParams.invocation_params;
8467
+ if (p.temperature != null) attrs["neatlogs.llm.temperature"] = p.temperature;
8468
+ if (p.max_tokens != null) attrs["neatlogs.llm.max_tokens"] = p.max_tokens;
8469
+ if (p.model_name) attrs["neatlogs.llm.model_name"] = p.model_name;
8470
+ }
8471
+ const span2 = tracer.startSpan("langchain.llm", { attributes: attrs }, parentCtx);
8472
+ this._spans.set(runId, span2);
8473
+ }
8474
+ async handleChatModelStart(serialized, messages, runId, parentRunId, extraParams) {
8475
+ const tracer = import_api14.trace.getTracer(TRACER_NAME8);
8476
+ const model = serialized?.kwargs?.model_name ?? serialized?.kwargs?.model ?? serialized?.name ?? "";
8477
+ const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
8478
+ const parentCtx = parentSpan ? import_api14.trace.setSpan(import_api14.context.active(), parentSpan) : import_api14.context.active();
8479
+ const attrs = {
8480
+ "neatlogs.span.kind": "LLM",
8481
+ "neatlogs.llm.provider": detectProvider(model),
8482
+ "neatlogs.llm.model_name": model
8483
+ };
8484
+ const flatMessages = messages.flat();
8485
+ for (let i = 0; i < flatMessages.length; i++) {
8486
+ const msg = flatMessages[i];
8487
+ const role = msg?.role ?? msg?._getType?.() ?? msg?.constructor?.name ?? "unknown";
8488
+ const content = typeof msg?.content === "string" ? msg.content : safeStringify8(msg?.content);
8489
+ attrs[`neatlogs.llm.input_messages.${i}.role`] = mapRole(role);
8490
+ attrs[`neatlogs.llm.input_messages.${i}.content`] = content;
8491
+ }
8492
+ if (extraParams?.invocation_params) {
8493
+ const p = extraParams.invocation_params;
8494
+ if (p.temperature != null) attrs["neatlogs.llm.temperature"] = p.temperature;
8495
+ if (p.max_tokens != null) attrs["neatlogs.llm.max_tokens"] = p.max_tokens;
8496
+ if (p.model_name) attrs["neatlogs.llm.model_name"] = p.model_name;
8497
+ }
8498
+ const span2 = tracer.startSpan("langchain.chat_model", { attributes: attrs }, parentCtx);
8499
+ this._spans.set(runId, span2);
8500
+ }
8501
+ async handleLLMEnd(output, runId) {
8502
+ const span2 = this._spans.get(runId);
8503
+ if (!span2) return;
8504
+ const generations = output?.generations ?? [];
8505
+ for (let i = 0; i < generations.length; i++) {
8506
+ const gen = generations[i];
8507
+ if (!Array.isArray(gen)) continue;
8508
+ for (let j = 0; j < gen.length; j++) {
8509
+ const msg = gen[j]?.message ?? gen[j];
8510
+ const content = msg?.content ?? msg?.text ?? "";
8511
+ span2.setAttribute(`neatlogs.llm.output_messages.${i}.role`, "assistant");
8512
+ span2.setAttribute(`neatlogs.llm.output_messages.${i}.content`, String(content));
8513
+ const toolCalls = msg?.tool_calls ?? msg?.additional_kwargs?.tool_calls;
8514
+ if (toolCalls && Array.isArray(toolCalls)) {
8515
+ for (let k = 0; k < toolCalls.length; k++) {
8516
+ const tc = toolCalls[k];
8517
+ span2.setAttribute(`neatlogs.llm.tool_calls.${k}.id`, tc.id ?? "");
8518
+ span2.setAttribute(`neatlogs.llm.tool_calls.${k}.name`, tc.name ?? tc.function?.name ?? "");
8519
+ span2.setAttribute(`neatlogs.llm.tool_calls.${k}.arguments`, tc.args ? safeStringify8(tc.args) : tc.function?.arguments ?? "");
8520
+ }
8521
+ }
8522
+ }
8523
+ }
8524
+ const usage = output?.llmOutput?.tokenUsage ?? output?.llmOutput?.usage;
8525
+ if (usage) {
8526
+ if (usage.promptTokens != null || usage.prompt_tokens != null) {
8527
+ span2.setAttribute("neatlogs.llm.token_count.prompt", usage.promptTokens ?? usage.prompt_tokens);
8528
+ }
8529
+ if (usage.completionTokens != null || usage.completion_tokens != null) {
8530
+ span2.setAttribute("neatlogs.llm.token_count.completion", usage.completionTokens ?? usage.completion_tokens);
8531
+ }
8532
+ if (usage.totalTokens != null || usage.total_tokens != null) {
8533
+ span2.setAttribute("neatlogs.llm.token_count.total", usage.totalTokens ?? usage.total_tokens);
8534
+ }
8535
+ }
8536
+ span2.setStatus({ code: import_api14.SpanStatusCode.OK });
8537
+ span2.end();
8538
+ this._spans.delete(runId);
8539
+ }
8540
+ async handleLLMNewToken(_token, _idx, _runId) {
8541
+ }
8542
+ async handleLLMError(error, runId) {
8543
+ const span2 = this._spans.get(runId);
8544
+ if (!span2) return;
8545
+ span2.setStatus({ code: import_api14.SpanStatusCode.ERROR, message: error.message });
8546
+ span2.recordException(error);
8547
+ span2.end();
8548
+ this._spans.delete(runId);
8549
+ }
8550
+ // --- Tool callbacks ---
8551
+ async handleToolStart(serialized, input, runId, parentRunId, _tags, _metadata, runName, toolCallId) {
8552
+ const tracer = import_api14.trace.getTracer(TRACER_NAME8);
8553
+ const name = serialized?.name || runName || (Array.isArray(serialized?.id) ? serialized.id[serialized.id.length - 1] : void 0) || "tool";
8554
+ const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
8555
+ const parentCtx = parentSpan ? import_api14.trace.setSpan(import_api14.context.active(), parentSpan) : import_api14.context.active();
8556
+ const attrs = {
8557
+ "neatlogs.span.kind": "TOOL",
8558
+ "neatlogs.tool.name": name,
8559
+ "input.value": String(input)
8560
+ };
8561
+ if (toolCallId) attrs["neatlogs.tool_call.id"] = toolCallId;
8562
+ const span2 = tracer.startSpan(`langchain.tool.${name}`, { attributes: attrs }, parentCtx);
8563
+ this._spans.set(runId, span2);
8564
+ }
8565
+ async handleToolEnd(output, runId) {
8566
+ const span2 = this._spans.get(runId);
8567
+ if (!span2) return;
8568
+ span2.setAttribute("output.value", String(output));
8569
+ span2.setStatus({ code: import_api14.SpanStatusCode.OK });
8570
+ span2.end();
8571
+ this._spans.delete(runId);
8572
+ }
8573
+ async handleToolError(error, runId) {
8574
+ const span2 = this._spans.get(runId);
8575
+ if (!span2) return;
8576
+ span2.setStatus({ code: import_api14.SpanStatusCode.ERROR, message: error.message });
8577
+ span2.recordException(error);
8578
+ span2.end();
8579
+ this._spans.delete(runId);
8580
+ }
8581
+ // --- Retriever callbacks ---
8582
+ async handleRetrieverStart(serialized, query, runId, parentRunId) {
8583
+ const tracer = import_api14.trace.getTracer(TRACER_NAME8);
8584
+ const name = serialized?.name ?? "retriever";
8585
+ const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
8586
+ const parentCtx = parentSpan ? import_api14.trace.setSpan(import_api14.context.active(), parentSpan) : import_api14.context.active();
8587
+ const attrs = {
8588
+ "neatlogs.span.kind": "RETRIEVER",
8589
+ "neatlogs.retriever.name": name,
8590
+ "input.value": query
8591
+ };
8592
+ const span2 = tracer.startSpan(`langchain.retriever.${name}`, { attributes: attrs }, parentCtx);
8593
+ this._spans.set(runId, span2);
8594
+ }
8595
+ async handleRetrieverEnd(documents, runId) {
8596
+ const span2 = this._spans.get(runId);
8597
+ if (!span2) return;
8598
+ if (documents?.length) {
8599
+ span2.setAttribute("neatlogs.retriever.document_count", documents.length);
8600
+ for (let i = 0; i < Math.min(documents.length, 10); i++) {
8601
+ const doc = documents[i];
8602
+ if (doc?.pageContent) {
8603
+ span2.setAttribute(`neatlogs.retriever.documents.${i}.content`, doc.pageContent);
8604
+ }
8605
+ }
8606
+ }
8607
+ span2.setStatus({ code: import_api14.SpanStatusCode.OK });
8608
+ span2.end();
8609
+ this._spans.delete(runId);
8610
+ }
8611
+ async handleRetrieverError(error, runId) {
8612
+ const span2 = this._spans.get(runId);
8613
+ if (!span2) return;
8614
+ span2.setStatus({ code: import_api14.SpanStatusCode.ERROR, message: error.message });
8615
+ span2.recordException(error);
8616
+ span2.end();
8617
+ this._spans.delete(runId);
8618
+ }
8619
+ };
8620
+ function detectProvider(model) {
8621
+ const m = model.toLowerCase();
8622
+ if (m.includes("gpt") || m.includes("o1") || m.includes("o3") || m.includes("o4")) return "openai";
8623
+ if (m.includes("claude")) return "anthropic";
8624
+ if (m.includes("gemini")) return "google";
8625
+ if (m.includes("command")) return "cohere";
8626
+ if (m.includes("llama") || m.includes("mixtral")) return "meta";
8627
+ return "unknown";
8628
+ }
8629
+ function mapRole(role) {
8630
+ const r = role.toLowerCase();
8631
+ if (r === "human" || r === "humanmessage") return "user";
8632
+ if (r === "ai" || r === "aimessage") return "assistant";
8633
+ if (r === "system" || r === "systemmessage") return "system";
8634
+ if (r === "function" || r === "functionmessage") return "function";
8635
+ if (r === "tool" || r === "toolmessage") return "tool";
8636
+ return role;
8637
+ }
8638
+ function safeStringify8(value) {
8639
+ try {
8640
+ return typeof value === "string" ? value : JSON.stringify(value);
8641
+ } catch {
8642
+ return "";
8643
+ }
8644
+ }
8645
+
8646
+ // src/strands.ts
8647
+ var PATCH_FLAG = "_neatlogs_patched";
8648
+ function strandsHooks(agent) {
8649
+ installEventHookFromAgent(agent);
8650
+ if (agent && typeof agent === "object") {
8651
+ try {
8652
+ Object.defineProperty(agent, PATCH_FLAG, {
8653
+ value: true,
8654
+ enumerable: false,
8655
+ configurable: true
8656
+ });
8657
+ } catch {
8658
+ agent[PATCH_FLAG] = true;
8659
+ }
8660
+ }
8661
+ return agent;
8662
+ }
8663
+ function installEventHookFromAgent(agent) {
8664
+ const tracer = agent?._tracer;
8665
+ const proto = tracer ? Object.getPrototypeOf(tracer) : void 0;
8666
+ if (!proto || typeof proto._addEvent !== "function") return;
8667
+ if (proto._addEvent[PATCH_FLAG]) return;
8668
+ const orig = proto._addEvent;
8669
+ function patchedAddEvent(span2, eventName, eventAttributes) {
8670
+ const result = orig.call(this, span2, eventName, eventAttributes);
8671
+ try {
8672
+ enrichSpanFromEvent(span2, eventName, eventAttributes || {});
8673
+ } catch {
8674
+ }
8675
+ return result;
8676
+ }
8677
+ patchedAddEvent[PATCH_FLAG] = true;
8678
+ proto._addEvent = patchedAddEvent;
8679
+ }
8680
+ function enrichSpanFromEvent(span2, eventName, attrs) {
8681
+ if (!span2 || typeof span2.setAttribute !== "function") return;
8682
+ if (typeof span2.isRecording === "function" && !span2.isRecording()) return;
8683
+ const isTool = readSpanOp(span2) === "execute_tool";
8684
+ if (eventName.startsWith("gen_ai.") && eventName.endsWith(".message")) {
8685
+ const role = eventName.slice("gen_ai.".length, -".message".length);
8686
+ const content = flattenStrandsContent(attrs.content);
8687
+ if (content) {
8688
+ if (isTool) {
8689
+ span2.setAttribute("input.value", content);
8690
+ span2.setAttribute("neatlogs.tool.input", content);
8691
+ } else {
8692
+ appendInputMessage(span2, role, content);
8693
+ }
8694
+ }
8695
+ return;
8696
+ }
8697
+ if (eventName === "gen_ai.choice") {
8698
+ const out = flattenStrandsContent(attrs.message);
8699
+ if (out) setOutput(span2, isTool, out);
8700
+ return;
8701
+ }
8702
+ if (eventName === "gen_ai.client.inference.operation.details") {
8703
+ const out = flattenStrandsContent(attrs["gen_ai.output.messages"]);
8704
+ if (out) setOutput(span2, isTool, out);
8705
+ }
8706
+ }
8707
+ function setOutput(span2, isTool, out) {
8708
+ span2.setAttribute("output.value", out);
8709
+ if (isTool) {
8710
+ span2.setAttribute("neatlogs.tool.output", out);
8711
+ } else {
8712
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
8713
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", out);
8714
+ span2.setAttribute("neatlogs.llm.output", safeStringify9({ role: "assistant", content: out }));
8715
+ }
8716
+ }
8717
+ function appendInputMessage(span2, role, content) {
8718
+ const idx = span2.__neatlogs_in_idx ?? 0;
8719
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.role`, role);
8720
+ span2.setAttribute(`neatlogs.llm.input_messages.${idx}.content`, content);
8721
+ span2.__neatlogs_in_idx = idx + 1;
8722
+ const existing = span2.__neatlogs_in_msgs ?? [];
8723
+ existing.push({ role, content });
8724
+ span2.__neatlogs_in_msgs = existing;
8725
+ const blob = safeStringify9({ messages: existing });
8726
+ span2.setAttribute("input.value", blob);
8727
+ span2.setAttribute("neatlogs.llm.input", blob);
8728
+ }
8729
+ function readSpanOp(span2) {
8730
+ try {
8731
+ const a = span2.attributes;
8732
+ if (!a) return "";
8733
+ const v = typeof a.get === "function" ? a.get("gen_ai.operation.name") : a["gen_ai.operation.name"];
8734
+ return typeof v === "string" ? v.toLowerCase() : "";
8735
+ } catch {
8736
+ return "";
8737
+ }
8738
+ }
8739
+ function flattenStrandsContent(content) {
8740
+ if (content == null) return "";
8741
+ let val = content;
8742
+ if (typeof val === "string") {
8743
+ const s = val.trim();
8744
+ if (!(s.startsWith("[") || s.startsWith("{"))) return val;
8745
+ try {
8746
+ val = JSON.parse(s);
8747
+ } catch {
8748
+ return val;
8749
+ }
8750
+ }
8751
+ return flattenBlocks(val);
8752
+ }
8753
+ function flattenBlocks(val) {
8754
+ const items = Array.isArray(val) ? val : [val];
8755
+ const out = [];
8756
+ for (const item of items) {
8757
+ if (typeof item === "string") {
8758
+ out.push(item);
8759
+ continue;
8760
+ }
8761
+ if (!item || typeof item !== "object") {
8762
+ if (item != null) out.push(String(item));
8763
+ continue;
8764
+ }
8765
+ const o = item;
8766
+ if (typeof o.text === "string") out.push(o.text);
8767
+ else if (typeof o.content === "string") out.push(o.content);
8768
+ else if (o.toolUse) out.push(`${o.toolUse.name ?? "tool"}(${safeStringify9(o.toolUse.input ?? {})})`);
8769
+ else if (o.toolResult) out.push(flattenBlocks(o.toolResult.content ?? o.toolResult));
8770
+ else if (Array.isArray(o.parts)) out.push(flattenBlocks(o.parts));
8771
+ else if (Array.isArray(o.content)) out.push(flattenBlocks(o.content));
8772
+ else out.push(safeStringify9(o));
8773
+ }
8774
+ return out.filter(Boolean).join("\n");
8775
+ }
8776
+ function safeStringify9(value) {
8777
+ if (typeof value === "string") return value;
8778
+ try {
8779
+ return JSON.stringify(value) ?? "";
8780
+ } catch {
8781
+ return "";
8782
+ }
8783
+ }
8784
+
8785
+ // src/openai-agents.ts
8786
+ var import_api15 = require("@opentelemetry/api");
8787
+ var TRACER_NAME9 = "neatlogs.openai_agents";
8788
+ function openaiAgentsProcessor() {
8789
+ return new NeatlogsTraceProcessor();
8790
+ }
8791
+ var NeatlogsTraceProcessor = class {
8792
+ _spans = /* @__PURE__ */ new Map();
8793
+ _startTimes = /* @__PURE__ */ new Map();
8794
+ // The @openai/agents SDK passes a Trace object: { traceId, name, groupId, metadata }.
8795
+ onTraceStart(traceData) {
8796
+ const tracer = import_api15.trace.getTracer(TRACER_NAME9);
8797
+ const attrs = { "neatlogs.span.kind": "WORKFLOW" };
8798
+ const workflowName = traceData?.name ?? traceData?.workflow_name;
8799
+ if (workflowName) attrs["neatlogs.workflow.name"] = workflowName;
8800
+ const traceId = traceData?.traceId ?? traceData?.trace_id;
8801
+ if (traceId) attrs["neatlogs.agent.trace_id"] = String(traceId);
8802
+ const span2 = tracer.startSpan("openai_agents.trace", { attributes: attrs }, import_api15.context.active());
8803
+ const key = String(traceId ?? `trace_${Date.now()}`);
8804
+ this._spans.set(key, span2);
8805
+ this._startTimes.set(key, Date.now());
8806
+ }
8807
+ onTraceEnd(traceData) {
8808
+ const key = String(traceData?.traceId ?? traceData?.trace_id ?? "");
8809
+ const span2 = this._spans.get(key);
8810
+ if (!span2) return;
8811
+ const startTime = this._startTimes.get(key);
8812
+ if (startTime) {
8813
+ span2.setAttribute("neatlogs.metrics.duration_ms", Date.now() - startTime);
8814
+ }
8815
+ span2.setStatus({ code: import_api15.SpanStatusCode.OK });
8816
+ span2.end();
8817
+ this._spans.delete(key);
8818
+ this._startTimes.delete(key);
8819
+ }
8820
+ // The SDK passes a Span object: { type, spanId, traceId, parentId?, spanData: {...} }.
8821
+ // The meaningful payload (type, name, input, output, usage, ...) lives in `spanData`.
8822
+ onSpanStart(span2) {
8823
+ const tracer = import_api15.trace.getTracer(TRACER_NAME9);
8824
+ const data = span2?.spanData ?? span2 ?? {};
8825
+ const spanType = data?.type ?? data?.span_type ?? span2?.type ?? "";
8826
+ const spanId = String(span2?.spanId ?? span2?.span_id ?? data?.span_id ?? `span_${Date.now()}`);
8827
+ const parentKey = String(span2?.parentId ?? span2?.traceId ?? span2?.trace_id ?? "");
8828
+ const parentSpan = this._spans.get(parentKey);
8829
+ const parentCtx = parentSpan ? import_api15.trace.setSpan(import_api15.context.active(), parentSpan) : import_api15.context.active();
8830
+ let otelSpan;
8831
+ if (spanType === "agent" || spanType === "agent_run") {
8832
+ const agentName = data?.name ?? data?.agent_name ?? "agent";
8833
+ const attrs = {
8834
+ "neatlogs.span.kind": "AGENT",
8835
+ "neatlogs.agent.name": agentName
8836
+ };
8837
+ if (Array.isArray(data?.tools) && data.tools.length) {
8838
+ attrs["neatlogs.agent.available_tools"] = data.tools.join(",");
8839
+ }
8840
+ otelSpan = tracer.startSpan(`openai_agents.agent.${agentName}`, { attributes: attrs }, parentCtx);
8841
+ } else if (spanType === "response" || spanType === "generation" || spanType === "llm") {
8842
+ const attrs = {
8843
+ "neatlogs.span.kind": "LLM",
8844
+ "neatlogs.llm.provider": "openai"
8845
+ };
8846
+ const model = data?.model;
8847
+ if (model) attrs["neatlogs.llm.model_name"] = model;
8848
+ const inputMsgs = data?.input ?? data?.messages;
8849
+ if (inputMsgs && Array.isArray(inputMsgs)) {
8850
+ for (let i = 0; i < inputMsgs.length; i++) {
8851
+ const msg = inputMsgs[i];
8852
+ const role = typeof msg === "object" ? msg.role ?? "" : "";
8853
+ const content = typeof msg === "object" ? msg.content ?? "" : String(msg);
8854
+ if (role) attrs[`neatlogs.llm.input_messages.${i}.role`] = role;
8855
+ if (content) attrs[`neatlogs.llm.input_messages.${i}.content`] = typeof content === "string" ? content : safeStringify10(content);
8856
+ }
8857
+ }
8858
+ otelSpan = tracer.startSpan("openai_agents.generation", { attributes: attrs }, parentCtx);
8859
+ } else if (spanType === "function" || spanType === "tool" || spanType === "tool_call") {
8860
+ const toolName = data?.name ?? data?.function_name ?? "tool";
8861
+ const attrs = {
8862
+ "neatlogs.span.kind": "TOOL",
8863
+ "neatlogs.tool.name": toolName
8864
+ };
8865
+ const toolInput = data?.input ?? data?.arguments;
8866
+ if (toolInput !== void 0) {
8867
+ attrs["input.value"] = typeof toolInput === "string" ? toolInput : safeStringify10(toolInput);
8868
+ }
8869
+ otelSpan = tracer.startSpan(`openai_agents.tool.${toolName}`, { attributes: attrs }, parentCtx);
8870
+ } else if (spanType === "handoff") {
8871
+ const attrs = { "neatlogs.span.kind": "AGENT" };
8872
+ if (data?.from_agent) attrs["neatlogs.agent.handoff_from"] = String(data.from_agent);
8873
+ if (data?.to_agent) attrs["neatlogs.agent.name"] = String(data.to_agent);
8874
+ otelSpan = tracer.startSpan("openai_agents.handoff", { attributes: attrs }, parentCtx);
8875
+ } else {
8876
+ const attrs = { "neatlogs.span.kind": "CHAIN" };
8877
+ otelSpan = tracer.startSpan(`openai_agents.${spanType || "span"}`, { attributes: attrs }, parentCtx);
8878
+ }
8879
+ this._spans.set(spanId, otelSpan);
8880
+ this._startTimes.set(spanId, Date.now());
8881
+ }
8882
+ onSpanEnd(span2) {
8883
+ const data = span2?.spanData ?? span2 ?? {};
8884
+ const spanId = String(span2?.spanId ?? span2?.span_id ?? data?.span_id ?? "");
8885
+ const otelSpan = this._spans.get(spanId);
8886
+ if (!otelSpan) return;
8887
+ const spanType = data?.type ?? data?.span_type ?? span2?.type ?? "";
8888
+ const startTime = this._startTimes.get(spanId);
8889
+ if (spanType === "response" || spanType === "generation" || spanType === "llm") {
8890
+ const resp = data?._response ?? data?.response ?? {};
8891
+ const model = data?.model ?? resp?.model;
8892
+ if (model) otelSpan.setAttribute("neatlogs.llm.model_name", model);
8893
+ const outputItems = data?.output ?? resp?.output;
8894
+ if (Array.isArray(outputItems)) {
8895
+ 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("");
8896
+ if (text) {
8897
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
8898
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.content", text);
8899
+ }
8900
+ const toolCalls = outputItems.filter((o) => o?.type === "function_call");
8901
+ for (let i = 0; i < toolCalls.length; i++) {
8902
+ const tc = toolCalls[i];
8903
+ otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, tc.name ?? "");
8904
+ otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, typeof tc.arguments === "string" ? tc.arguments : safeStringify10(tc.arguments ?? {}));
8905
+ if (tc.callId ?? tc.id) otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, tc.callId ?? tc.id);
8906
+ }
8907
+ } else if (outputItems?.content) {
8908
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
8909
+ const c = outputItems.content;
8910
+ otelSpan.setAttribute("neatlogs.llm.output_messages.0.content", typeof c === "string" ? c : safeStringify10(c));
8911
+ }
8912
+ const usage = data?.usage ?? resp?.usage;
8913
+ if (usage) {
8914
+ const inputTokens = usage.input_tokens ?? usage.prompt_tokens ?? usage.inputTokens;
8915
+ const outputTokens = usage.output_tokens ?? usage.completion_tokens ?? usage.outputTokens;
8916
+ const totalTokens = usage.total_tokens ?? usage.totalTokens;
8917
+ if (inputTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.prompt", inputTokens);
8918
+ if (outputTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.completion", outputTokens);
8919
+ if (totalTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.total", totalTokens);
8920
+ else if (inputTokens != null && outputTokens != null) {
8921
+ otelSpan.setAttribute("neatlogs.llm.token_count.total", inputTokens + outputTokens);
8922
+ }
8923
+ }
8924
+ } else if (spanType === "function" || spanType === "tool" || spanType === "tool_call") {
8925
+ const output = data?.output ?? data?.result;
8926
+ if (output != null) {
8927
+ otelSpan.setAttribute("output.value", typeof output === "string" ? output : safeStringify10(output));
8928
+ }
8929
+ } else if (spanType === "agent" || spanType === "agent_run") {
8930
+ const output = data?.output;
8931
+ if (output != null) {
8932
+ otelSpan.setAttribute("output.value", typeof output === "string" ? output : safeStringify10(output));
8933
+ }
8934
+ }
8935
+ const error = data?.error ?? span2?.error;
8936
+ if (error) {
8937
+ if (error instanceof Error) {
8938
+ otelSpan.setStatus({ code: import_api15.SpanStatusCode.ERROR, message: error.message });
8939
+ otelSpan.recordException(error);
8940
+ } else {
8941
+ otelSpan.setStatus({ code: import_api15.SpanStatusCode.ERROR, message: String(error) });
8942
+ }
8943
+ } else {
8944
+ otelSpan.setStatus({ code: import_api15.SpanStatusCode.OK });
8945
+ }
8946
+ if (startTime) {
8947
+ otelSpan.setAttribute("neatlogs.llm.metrics.duration_ms", Date.now() - startTime);
8948
+ }
8949
+ otelSpan.end();
8950
+ this._spans.delete(spanId);
8951
+ this._startTimes.delete(spanId);
8952
+ }
8953
+ shutdown() {
8954
+ for (const [, span2] of this._spans) {
8955
+ span2.setStatus({ code: import_api15.SpanStatusCode.ERROR, message: "Processor shutdown before span completed" });
8956
+ span2.end();
8957
+ }
8958
+ this._spans.clear();
8959
+ this._startTimes.clear();
8960
+ }
8961
+ forceFlush() {
8962
+ }
8963
+ };
8964
+ function safeStringify10(value) {
8965
+ try {
8966
+ return typeof value === "string" ? value : JSON.stringify(value);
8967
+ } catch {
8968
+ return "";
8969
+ }
8970
+ }
8971
+
8972
+ // src/mastra-wrap.ts
8973
+ var import_api16 = require("@opentelemetry/api");
8974
+ var TRACER_NAME10 = "neatlogs.mastra";
8975
+ var PATCH_FLAG2 = "_neatlogs_patched";
8976
+ function wrapMastra(entity) {
8977
+ if (!entity || entity[PATCH_FLAG2]) return entity;
8978
+ const e = entity;
8979
+ const className = entity.constructor?.name ?? "";
8980
+ if (isRootMastra(e)) {
8981
+ const proxied = wrapRootMastra(e);
8982
+ markPatched(proxied);
8983
+ return proxied;
8984
+ }
8985
+ if (isAgent(e, className)) {
8986
+ patchAgent(e);
8987
+ } else if (isWorkflow(e, className)) {
8988
+ patchWorkflow(e);
8989
+ } else if (isVector(e, className)) {
8990
+ patchVector(e);
8991
+ } else if (isMemory(e, className)) {
8992
+ patchMemory(e);
8993
+ } else if (isDocument(e, className)) {
8994
+ patchDocument(e);
8995
+ }
8996
+ markPatched(e);
8997
+ return entity;
8998
+ }
8999
+ function isRootMastra(e) {
9000
+ return typeof e.getAgent === "function" && typeof e.getWorkflow === "function";
9001
+ }
9002
+ function isAgent(e, className) {
9003
+ return className === "Agent" || typeof e.generate === "function" || typeof e.stream === "function";
9004
+ }
9005
+ function isWorkflow(e, className) {
9006
+ return className === "Workflow" || typeof e.createRun === "function";
9007
+ }
9008
+ function isVector(e, className) {
9009
+ return /Vector/.test(className) || typeof e.query === "function" && typeof e.upsert === "function";
9010
+ }
9011
+ function isMemory(e, className) {
9012
+ return /Memory/.test(className) || typeof e.recall === "function" && typeof e.saveMessages === "function";
9013
+ }
9014
+ function isDocument(e, className) {
9015
+ return className === "MDocument" || typeof e.chunk === "function" && typeof e.getDocs === "function";
9016
+ }
9017
+ function patchAgent(agent) {
9018
+ patchAgentMethod(agent, "generate", false);
9019
+ patchAgentMethod(agent, "stream", true);
9020
+ }
9021
+ function patchAgentMethod(agent, method, streaming) {
9022
+ if (typeof agent[method] !== "function") return;
9023
+ const orig = agent[method].bind(agent);
9024
+ agent[method] = async function tracedAgentMethod(input, opts) {
9025
+ const agentName = agent.name ?? agent.id ?? "mastra_agent";
9026
+ const model = extractModelId(agent.model);
9027
+ installAgentLlmHook(agent);
9028
+ installAgentToolHooks(agent);
9029
+ const attrs = {
9030
+ "neatlogs.span.kind": "AGENT",
9031
+ "neatlogs.agent.name": agentName,
9032
+ "input.value": toInputValue(input)
9033
+ };
9034
+ if (model) attrs["neatlogs.llm.model_name"] = model;
9035
+ if (agent.instructions && typeof agent.instructions === "string") {
9036
+ attrs["neatlogs.llm.system_prompt"] = agent.instructions;
9037
+ }
9038
+ if (streaming) attrs["neatlogs.llm.is_streaming"] = true;
9039
+ if (streaming) {
9040
+ const tracer = import_api16.trace.getTracer(TRACER_NAME10);
9041
+ const span2 = tracer.startSpan(`mastra.agent.${agentName}`, { attributes: attrs }, import_api16.context.active());
9042
+ const ctx = import_api16.trace.setSpan(import_api16.context.active(), span2);
9043
+ try {
9044
+ const result = await import_api16.context.with(ctx, () => orig(input, opts));
9045
+ return wrapStreamingOutput(result, span2, ctx);
9046
+ } catch (err) {
9047
+ recordError6(span2, err);
9048
+ span2.end();
9049
+ throw err;
9050
+ }
9051
+ }
9052
+ return withActiveSpan(`mastra.agent.${agentName}`, attrs, async (span2) => {
9053
+ const result = await orig(input, opts);
9054
+ finalizeAgentResult(span2, result);
9055
+ return result;
9056
+ });
9057
+ };
9058
+ }
9059
+ function installAgentLlmHook(agent) {
9060
+ if (agent.__neatlogs_llm_hook || typeof agent.getLLM !== "function") return;
9061
+ agent.__neatlogs_llm_hook = true;
9062
+ const origGetLLM = agent.getLLM.bind(agent);
9063
+ agent.getLLM = function patchedGetLLM(...args) {
9064
+ const out = origGetLLM(...args);
9065
+ return Promise.resolve(out).then((llm) => {
9066
+ try {
9067
+ const model = typeof llm?.getModel === "function" ? llm.getModel() : llm;
9068
+ patchModelInPlace(model);
9069
+ } catch {
9070
+ }
9071
+ return llm;
9072
+ });
9073
+ };
9074
+ }
9075
+ function patchModelInPlace(model) {
9076
+ if (!model || model.__neatlogs_model_patched) return;
9077
+ model.__neatlogs_model_patched = true;
9078
+ const modelId = model.modelId ?? model.modelName ?? "";
9079
+ const provider = model.provider ?? "";
9080
+ for (const fn of ["doGenerate", "doStream"]) {
9081
+ if (typeof model[fn] !== "function") continue;
9082
+ const orig = model[fn].bind(model);
9083
+ const isStream = fn === "doStream";
9084
+ model[fn] = function tracedModelCall(callOpts) {
9085
+ const attrs = { "neatlogs.span.kind": "LLM" };
9086
+ if (modelId) attrs["neatlogs.llm.model_name"] = modelId;
9087
+ if (provider) attrs["neatlogs.llm.provider"] = provider;
9088
+ if (isStream) attrs["neatlogs.llm.is_streaming"] = true;
9089
+ const promptInput = callOpts?.prompt ?? callOpts?.messages;
9090
+ if (promptInput !== void 0) attrs["input.value"] = safeStringify11(promptInput);
9091
+ captureInvocationParams(attrs, callOpts);
9092
+ return withActiveSpan(`mastra.llm.${modelId || "model"}.${fn}`, attrs, async (span2) => {
9093
+ const result = await orig(callOpts);
9094
+ if (!isStream) finalizeModelResult(span2, result);
9095
+ else if (result?.usage) recordUsage(span2, result.usage);
9096
+ return result;
9097
+ });
9098
+ };
9099
+ }
9100
+ }
9101
+ function installAgentToolHooks(agent) {
9102
+ if (agent.__neatlogs_tool_hook) return;
9103
+ let tools;
9104
+ try {
9105
+ tools = typeof agent.listTools === "function" ? agent.listTools() : void 0;
9106
+ } catch {
9107
+ tools = void 0;
9108
+ }
9109
+ if (!tools || typeof tools !== "object") return;
9110
+ agent.__neatlogs_tool_hook = true;
9111
+ for (const [key, tool] of Object.entries(tools)) {
9112
+ patchToolExecute(tool, key);
9113
+ }
9114
+ }
9115
+ function patchToolExecute(tool, key) {
9116
+ if (!tool || typeof tool.execute !== "function" || tool.__neatlogs_tool_patched) return;
9117
+ tool.__neatlogs_tool_patched = true;
9118
+ const toolName = tool.id ?? key;
9119
+ const orig = tool.execute.bind(tool);
9120
+ tool.execute = function tracedToolExecute(params, options) {
9121
+ const attrs = {
9122
+ "neatlogs.span.kind": "TOOL",
9123
+ "neatlogs.tool.name": toolName,
9124
+ "input.value": safeStringify11(params)
9125
+ };
9126
+ if (tool.description) attrs["neatlogs.tool.description"] = String(tool.description);
9127
+ return withActiveSpan(`mastra.tool.${toolName}`, attrs, async (span2) => {
9128
+ const result = await orig(params, options);
9129
+ span2.setAttribute("output.value", safeStringify11(result));
9130
+ return result;
9131
+ });
9132
+ };
9133
+ }
9134
+ function patchWorkflow(workflow) {
9135
+ if (typeof workflow.createRun !== "function") return;
9136
+ const origCreateRun = workflow.createRun.bind(workflow);
9137
+ const workflowName = workflow.name ?? workflow.id ?? "mastra_workflow";
9138
+ workflow.createRun = async function tracedCreateRun(...args) {
9139
+ const run = await origCreateRun(...args);
9140
+ if (!run) return run;
9141
+ patchRunMethod(run, "start", workflowName);
9142
+ patchRunMethod(run, "resume", workflowName);
9143
+ return run;
9144
+ };
9145
+ }
9146
+ function patchRunMethod(run, method, workflowName) {
9147
+ if (typeof run[method] !== "function") return;
9148
+ const orig = run[method].bind(run);
9149
+ run[method] = async function tracedRunMethod(startOpts) {
9150
+ const attrs = {
9151
+ "neatlogs.span.kind": "WORKFLOW",
9152
+ "neatlogs.workflow.name": workflowName
9153
+ };
9154
+ if (startOpts?.inputData !== void 0) {
9155
+ attrs["input.value"] = safeStringify11(startOpts.inputData);
9156
+ }
9157
+ return withActiveSpan(`mastra.workflow.${workflowName}`, attrs, async (span2) => {
9158
+ const result = await orig(startOpts);
9159
+ if (result?.status) span2.setAttribute("neatlogs.metadata", safeStringify11({ status: result.status }));
9160
+ if (result?.result !== void 0) {
9161
+ span2.setAttribute("output.value", safeStringify11(result.result));
9162
+ }
9163
+ return result;
9164
+ });
9165
+ };
9166
+ }
9167
+ var VECTOR_READ_OPS = ["query"];
9168
+ var VECTOR_WRITE_OPS = ["upsert", "updateVector", "deleteVector", "createIndex", "deleteIndex"];
9169
+ function patchVector(vector) {
9170
+ for (const op of VECTOR_READ_OPS) patchVectorOp(vector, op, "RETRIEVER");
9171
+ for (const op of VECTOR_WRITE_OPS) patchVectorOp(vector, op, "VECTOR_STORE");
9172
+ }
9173
+ function patchVectorOp(vector, op, kind) {
9174
+ if (typeof vector[op] !== "function") return;
9175
+ const orig = vector[op].bind(vector);
9176
+ const dbName = vector.constructor?.name ?? "vector";
9177
+ vector[op] = async function tracedVectorOp(params) {
9178
+ const attrs = {
9179
+ "neatlogs.span.kind": kind,
9180
+ "neatlogs.db.system": dbName,
9181
+ "neatlogs.db.operation": op,
9182
+ "input.value": safeStringify11(params)
9183
+ };
9184
+ const indexName = params?.indexName;
9185
+ if (indexName) attrs["neatlogs.vectordb.index_name"] = String(indexName);
9186
+ if (kind === "RETRIEVER" && params?.topK != null) attrs["neatlogs.retriever.top_k"] = params.topK;
9187
+ return withActiveSpan(`mastra.vector.${op}`, attrs, async (span2) => {
9188
+ const result = await orig(params);
9189
+ span2.setAttribute("output.value", safeStringify11(result));
9190
+ return result;
9191
+ });
9192
+ };
9193
+ }
9194
+ var MEMORY_OPS = ["recall", "saveMessages", "updateWorkingMemory", "deleteMessages"];
9195
+ function patchMemory(memory) {
9196
+ for (const op of MEMORY_OPS) {
9197
+ if (typeof memory[op] !== "function") continue;
9198
+ const orig = memory[op].bind(memory);
9199
+ memory[op] = async function tracedMemoryOp(...args) {
9200
+ const attrs = {
9201
+ "neatlogs.span.kind": "CHAIN",
9202
+ "neatlogs.db.operation": op,
9203
+ "input.value": safeStringify11(args?.[0])
9204
+ };
9205
+ return withActiveSpan(`mastra.memory.${op}`, attrs, async (span2) => {
9206
+ const result = await orig(...args);
9207
+ span2.setAttribute("output.value", safeStringify11(result));
9208
+ return result;
9209
+ });
9210
+ };
9211
+ }
9212
+ }
9213
+ function patchDocument(doc) {
9214
+ if (typeof doc.chunk !== "function") return;
9215
+ const orig = doc.chunk.bind(doc);
9216
+ doc.chunk = async function tracedChunk(...args) {
9217
+ const attrs = {
9218
+ "neatlogs.span.kind": "CHAIN",
9219
+ "neatlogs.db.operation": "chunk"
9220
+ };
9221
+ return withActiveSpan("mastra.document.chunk", attrs, async (span2) => {
9222
+ const result = await orig(...args);
9223
+ if (Array.isArray(result)) span2.setAttribute("neatlogs.db.documents_count", result.length);
9224
+ return result;
9225
+ });
9226
+ };
9227
+ }
9228
+ function wrapRootMastra(mastra) {
9229
+ const AGENT_GETTERS = /* @__PURE__ */ new Set(["getAgent", "getAgentById"]);
9230
+ const WORKFLOW_GETTERS = /* @__PURE__ */ new Set(["getWorkflow", "getWorkflowById"]);
9231
+ return new Proxy(mastra, {
9232
+ get(target, prop, receiver) {
9233
+ const value = Reflect.get(target, prop, receiver);
9234
+ if (typeof value !== "function") return value;
9235
+ const name = String(prop);
9236
+ if (AGENT_GETTERS.has(name) || WORKFLOW_GETTERS.has(name)) {
9237
+ return (...args) => {
9238
+ const entity = value.apply(target, args);
9239
+ return entity && typeof entity === "object" ? wrapMastra(entity) : entity;
9240
+ };
9241
+ }
9242
+ return value.bind(target);
9243
+ }
9244
+ });
9245
+ }
9246
+ function wrapStreamingOutput(output, span2, ctx) {
9247
+ if (!output) {
9248
+ span2.setStatus({ code: import_api16.SpanStatusCode.OK });
9249
+ span2.end();
9250
+ return output;
9251
+ }
9252
+ let ended = false;
9253
+ const endOnce = (err) => {
9254
+ if (ended) return;
9255
+ ended = true;
9256
+ if (err) recordError6(span2, err);
9257
+ else span2.setStatus({ code: import_api16.SpanStatusCode.OK });
9258
+ span2.end();
9259
+ };
9260
+ if (output.text && typeof output.text.then === "function") {
9261
+ const finalize = async () => {
9262
+ try {
9263
+ const [text, usage, finishReason] = await Promise.all([
9264
+ Promise.resolve(output.text).catch(() => void 0),
9265
+ Promise.resolve(output.usage).catch(() => void 0),
9266
+ Promise.resolve(output.finishReason).catch(() => void 0)
9267
+ ]);
9268
+ if (typeof text === "string" && text) {
9269
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
9270
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", text);
9271
+ }
9272
+ if (usage) recordUsage(span2, usage);
9273
+ if (finishReason) span2.setAttribute("neatlogs.llm.stop_reason", normalizeFinishReason(finishReason));
9274
+ endOnce();
9275
+ } catch (err) {
9276
+ endOnce(err);
9277
+ }
9278
+ };
9279
+ void finalize();
9280
+ return rebindStreamContext(output, ctx);
9281
+ }
9282
+ if (output[Symbol.asyncIterator]) {
9283
+ const origIterator = output[Symbol.asyncIterator].bind(output);
9284
+ const textParts = [];
9285
+ const wrapped = Object.create(Object.getPrototypeOf(output));
9286
+ Object.assign(wrapped, output);
9287
+ wrapped[Symbol.asyncIterator] = function() {
9288
+ const iterator = origIterator();
9289
+ const finish = () => {
9290
+ if (textParts.length) {
9291
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
9292
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", textParts.join(""));
9293
+ }
9294
+ endOnce();
9295
+ };
9296
+ return {
9297
+ async next() {
9298
+ try {
9299
+ const r = await iterator.next();
9300
+ if (r.done) {
9301
+ finish();
9302
+ return r;
9303
+ }
9304
+ const chunk = r.value;
9305
+ if (typeof chunk === "string") textParts.push(chunk);
9306
+ else if (chunk?.text) textParts.push(chunk.text);
9307
+ else if (chunk?.delta) textParts.push(chunk.delta);
9308
+ return r;
9309
+ } catch (err) {
9310
+ endOnce(err);
9311
+ throw err;
9312
+ }
9313
+ },
9314
+ async return(value) {
9315
+ finish();
9316
+ return iterator.return?.(value) ?? { done: true, value: void 0 };
9317
+ },
9318
+ async throw(err) {
9319
+ endOnce(err);
9320
+ return iterator.throw?.(err) ?? { done: true, value: void 0 };
9321
+ }
9322
+ };
9323
+ };
9324
+ return wrapped;
9325
+ }
9326
+ if (typeof output.then === "function") {
9327
+ return output.then((resolved) => {
9328
+ finalizeAgentResult(span2, resolved);
9329
+ endOnce();
9330
+ return resolved;
9331
+ }).catch((err) => {
9332
+ endOnce(err);
9333
+ throw err;
9334
+ });
9335
+ }
9336
+ endOnce();
9337
+ return output;
9338
+ }
9339
+ function rebindStreamContext(output, ctx) {
9340
+ const STREAM_PROPS = /* @__PURE__ */ new Set(["textStream", "fullStream", "objectStream", "elementStream"]);
9341
+ return new Proxy(output, {
9342
+ get(target, prop, receiver) {
9343
+ const value = Reflect.get(target, prop, receiver);
9344
+ if (typeof prop === "string" && STREAM_PROPS.has(prop) && value && value[Symbol.asyncIterator]) {
9345
+ const origIterator = value[Symbol.asyncIterator].bind(value);
9346
+ return {
9347
+ [Symbol.asyncIterator]() {
9348
+ return import_api16.context.with(ctx, () => origIterator());
9349
+ }
9350
+ };
9351
+ }
9352
+ if (typeof value === "function") return value.bind(target);
9353
+ return value;
9354
+ }
9355
+ });
9356
+ }
9357
+ function finalizeAgentResult(span2, result) {
9358
+ if (!result) return;
9359
+ if (result.text) {
9360
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
9361
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", String(result.text));
9362
+ }
9363
+ if (Array.isArray(result.toolCalls)) {
9364
+ for (let i = 0; i < result.toolCalls.length; i++) {
9365
+ const tc = result.toolCalls[i];
9366
+ const p = tc.payload ?? tc;
9367
+ setToolCall(span2, i, p.toolName ?? p.name, p.args ?? p.arguments, p.toolCallId ?? p.id);
9368
+ }
9369
+ }
9370
+ if (result.usage) recordUsage(span2, result.usage);
9371
+ if (result.finishReason) span2.setAttribute("neatlogs.llm.stop_reason", normalizeFinishReason(result.finishReason));
9372
+ if (result.model) span2.setAttribute("neatlogs.llm.model_name", result.model);
9373
+ }
9374
+ function finalizeModelResult(span2, result) {
9375
+ if (!result) return;
9376
+ if (typeof result.text === "string" && result.text) {
9377
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
9378
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", result.text);
9379
+ } else if (Array.isArray(result.content)) {
9380
+ const text = result.content.filter((p) => p?.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
9381
+ if (text) {
9382
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
9383
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", text);
9384
+ }
9385
+ const toolCalls = result.content.filter((p) => p?.type === "tool-call");
9386
+ for (let i = 0; i < toolCalls.length; i++) {
9387
+ const tc = toolCalls[i];
9388
+ setToolCall(span2, i, tc.toolName, tc.input ?? tc.args, tc.toolCallId);
9389
+ }
9390
+ span2.setAttribute("output.value", safeStringify11(result.content));
9391
+ }
9392
+ if (result.usage) recordUsage(span2, result.usage);
9393
+ span2.setAttribute("neatlogs.llm.stop_reason", normalizeFinishReason(result.finishReason));
9394
+ }
9395
+ function normalizeFinishReason(fr) {
9396
+ if (fr == null) return "";
9397
+ if (typeof fr === "string") return fr;
9398
+ return String(fr.unified ?? fr.reason ?? fr.type ?? safeStringify11(fr));
9399
+ }
9400
+ function tokenValue(v) {
9401
+ if (v == null) return void 0;
9402
+ if (typeof v === "number") return v;
9403
+ if (typeof v === "object" && typeof v.total === "number") return v.total;
9404
+ const n = Number(v);
9405
+ return Number.isFinite(n) ? n : void 0;
9406
+ }
9407
+ function captureInvocationParams(attrs, callOpts) {
9408
+ if (!callOpts) return;
9409
+ const map = [
9410
+ ["temperature", "neatlogs.llm.temperature"],
9411
+ ["maxOutputTokens", "neatlogs.llm.max_tokens"],
9412
+ ["maxTokens", "neatlogs.llm.max_tokens"],
9413
+ ["topP", "neatlogs.llm.top_p"],
9414
+ ["topK", "neatlogs.llm.top_k"],
9415
+ ["frequencyPenalty", "neatlogs.llm.frequency_penalty"],
9416
+ ["presencePenalty", "neatlogs.llm.presence_penalty"]
9417
+ ];
9418
+ const invocation = {};
9419
+ for (const [src, target] of map) {
9420
+ const v = callOpts[src];
9421
+ if (v != null) {
9422
+ attrs[target] = v;
9423
+ invocation[src] = v;
9424
+ }
9425
+ }
9426
+ if (Array.isArray(callOpts.stopSequences) && callOpts.stopSequences.length) {
9427
+ attrs["neatlogs.llm.stop_sequences"] = safeStringify11(callOpts.stopSequences);
9428
+ invocation.stopSequences = callOpts.stopSequences;
9429
+ }
9430
+ if (Array.isArray(callOpts.tools)) {
9431
+ for (let i = 0; i < callOpts.tools.length; i++) {
9432
+ attrs[`neatlogs.llm.tools.${i}`] = safeStringify11(callOpts.tools[i]);
9433
+ }
9434
+ invocation.toolChoice = callOpts.toolChoice;
9435
+ }
9436
+ if (Object.keys(invocation).length) {
9437
+ attrs["neatlogs.llm.invocation_parameters"] = safeStringify11(invocation);
9438
+ }
9439
+ }
9440
+ function setToolCall(span2, i, name, args, id) {
9441
+ span2.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, name ?? "");
9442
+ span2.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, safeStringify11(args ?? {}));
9443
+ if (id) span2.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, id);
9444
+ }
9445
+ function recordUsage(span2, usage) {
9446
+ if (!usage) return;
9447
+ const prompt = tokenValue(usage.promptTokens ?? usage.inputTokens ?? usage.input_tokens);
9448
+ const completion = tokenValue(usage.completionTokens ?? usage.outputTokens ?? usage.output_tokens);
9449
+ const total = tokenValue(usage.totalTokens);
9450
+ if (prompt != null) span2.setAttribute("neatlogs.llm.token_count.prompt", prompt);
9451
+ if (completion != null) span2.setAttribute("neatlogs.llm.token_count.completion", completion);
9452
+ if (total != null) span2.setAttribute("neatlogs.llm.token_count.total", total);
9453
+ else if (prompt != null && completion != null) {
9454
+ span2.setAttribute("neatlogs.llm.token_count.total", prompt + completion);
9455
+ }
9456
+ }
9457
+ function withActiveSpan(name, attrs, fn) {
9458
+ const tracer = import_api16.trace.getTracer(TRACER_NAME10);
9459
+ const span2 = tracer.startSpan(name, { attributes: attrs }, import_api16.context.active());
9460
+ const ctx = import_api16.trace.setSpan(import_api16.context.active(), span2);
9461
+ return import_api16.context.with(ctx, async () => {
9462
+ try {
9463
+ const result = await fn(span2);
9464
+ span2.setStatus({ code: import_api16.SpanStatusCode.OK });
9465
+ return result;
9466
+ } catch (err) {
9467
+ recordError6(span2, err);
9468
+ throw err;
9469
+ } finally {
9470
+ span2.end();
9471
+ }
9472
+ });
9473
+ }
9474
+ function markPatched(e) {
9475
+ try {
9476
+ Object.defineProperty(e, PATCH_FLAG2, { value: true, enumerable: false, configurable: true });
9477
+ } catch {
9478
+ e[PATCH_FLAG2] = true;
9479
+ }
9480
+ }
9481
+ function extractModelId(model) {
9482
+ if (!model) return "";
9483
+ if (typeof model === "string") return model;
9484
+ return model.modelId ?? model.name ?? "";
9485
+ }
9486
+ function toInputValue(input) {
9487
+ return typeof input === "string" ? input : safeStringify11(input);
9488
+ }
9489
+ function safeStringify11(value) {
9490
+ if (typeof value === "string") return value;
9491
+ try {
9492
+ return JSON.stringify(value) ?? "";
9493
+ } catch {
9494
+ return "";
9495
+ }
9496
+ }
9497
+ function recordError6(span2, err) {
9498
+ if (err instanceof Error) {
9499
+ span2.setStatus({ code: import_api16.SpanStatusCode.ERROR, message: err.message });
9500
+ span2.recordException(err);
9501
+ } else {
9502
+ span2.setStatus({ code: import_api16.SpanStatusCode.ERROR, message: String(err) });
9503
+ }
9504
+ }
9505
+
9506
+ // src/pi-agent.ts
9507
+ var import_api17 = require("@opentelemetry/api");
9508
+ var TRACER_NAME11 = "neatlogs.pi-agent";
9509
+ var PATCH_FLAG3 = "_neatlogs_patched";
9510
+ function piAgentHooks(agent) {
9511
+ if (!agent || agent[PATCH_FLAG3]) return agent;
9512
+ const a = agent;
9513
+ if (typeof a.subscribe !== "function") return agent;
9514
+ const state = { toolSpans: /* @__PURE__ */ new Map(), inputMessages: [] };
9515
+ const tracer = import_api17.trace.getTracer(TRACER_NAME11);
9516
+ a.subscribe((event) => {
9517
+ try {
9518
+ handleEvent(tracer, state, event);
9519
+ } catch {
9520
+ }
9521
+ });
9522
+ markPatched2(a);
9523
+ return agent;
9524
+ }
9525
+ function handleEvent(tracer, state, event) {
9526
+ switch (event.type) {
9527
+ case "agent_start": {
9528
+ const span2 = tracer.startSpan(
9529
+ "pi_agent.run",
9530
+ { attributes: { "neatlogs.span.kind": "AGENT" } },
9531
+ import_api17.context.active()
9532
+ );
9533
+ state.agentSpan = span2;
9534
+ state.agentCtx = import_api17.trace.setSpan(import_api17.context.active(), span2);
9535
+ state.inputMessages = [];
9536
+ break;
9537
+ }
9538
+ case "message_end": {
9539
+ const msg = event.message;
9540
+ if (!msg) return;
9541
+ if (msg.role === "assistant") {
9542
+ emitLlmSpan(tracer, state, msg);
9543
+ const { text } = splitAssistantContent(msg.content);
9544
+ if (text) state.inputMessages.push({ role: "assistant", content: text });
9545
+ } else {
9546
+ const role = msg.role === "toolResult" ? "tool" : String(msg.role || "user");
9547
+ const content = messageText(msg);
9548
+ if (content) state.inputMessages.push({ role, content });
9549
+ }
9550
+ break;
9551
+ }
9552
+ case "tool_execution_start": {
9553
+ const parent = state.agentCtx ?? import_api17.context.active();
9554
+ const span2 = tracer.startSpan(
9555
+ `pi_agent.tool.${event.toolName ?? "tool"}`,
9556
+ {
9557
+ attributes: {
9558
+ "neatlogs.span.kind": "TOOL",
9559
+ ...event.toolName ? { "neatlogs.tool.name": String(event.toolName) } : {},
9560
+ ...event.args !== void 0 ? { "input.value": safeStringify12(event.args) } : {}
9561
+ }
9562
+ },
9563
+ parent
9564
+ );
9565
+ if (event.toolCallId) state.toolSpans.set(event.toolCallId, span2);
9566
+ break;
9567
+ }
9568
+ case "tool_execution_end": {
9569
+ const span2 = event.toolCallId ? state.toolSpans.get(event.toolCallId) : void 0;
9570
+ if (!span2) return;
9571
+ if (event.result !== void 0) {
9572
+ span2.setAttribute("output.value", safeStringify12(event.result));
9573
+ }
9574
+ if (event.isError) {
9575
+ span2.setStatus({ code: import_api17.SpanStatusCode.ERROR });
9576
+ span2.setAttribute("neatlogs.tool.is_error", true);
9577
+ } else {
9578
+ span2.setStatus({ code: import_api17.SpanStatusCode.OK });
9579
+ }
9580
+ span2.end();
9581
+ if (event.toolCallId) state.toolSpans.delete(event.toolCallId);
9582
+ break;
9583
+ }
9584
+ case "agent_end": {
9585
+ for (const ts of state.toolSpans.values()) {
9586
+ try {
9587
+ ts.end();
9588
+ } catch {
9589
+ }
9590
+ }
9591
+ state.toolSpans.clear();
9592
+ if (state.agentSpan) {
9593
+ const firstUser = state.inputMessages.find((m) => m.role === "user");
9594
+ if (firstUser) state.agentSpan.setAttribute("input.value", firstUser.content);
9595
+ const finalText = lastAssistantText(event.messages);
9596
+ if (finalText) state.agentSpan.setAttribute("output.value", finalText);
9597
+ state.agentSpan.setStatus({ code: import_api17.SpanStatusCode.OK });
9598
+ state.agentSpan.end();
9599
+ state.agentSpan = void 0;
9600
+ state.agentCtx = void 0;
9601
+ }
9602
+ break;
9603
+ }
9604
+ default:
9605
+ break;
7737
9606
  }
7738
9607
  }
7739
- function patchToolExecute(tool, key) {
7740
- if (!tool || typeof tool.execute !== "function" || tool.__neatlogs_tool_patched) return;
7741
- tool.__neatlogs_tool_patched = true;
7742
- const toolName = tool.id ?? key;
7743
- const orig = tool.execute.bind(tool);
7744
- tool.execute = function tracedToolExecute(params, options) {
7745
- const attrs = {
7746
- "neatlogs.span.kind": "TOOL",
7747
- "neatlogs.tool.name": toolName,
7748
- "input.value": safeStringify7(params).slice(0, 1e4)
7749
- };
7750
- if (tool.description) attrs["neatlogs.tool.description"] = String(tool.description).slice(0, 2e3);
7751
- return withActiveSpan(`mastra.tool.${toolName}`, attrs, async (span2) => {
7752
- const result = await orig(params, options);
7753
- span2.setAttribute("output.value", safeStringify7(result).slice(0, 1e4));
7754
- return result;
9608
+ function emitLlmSpan(tracer, state, msg) {
9609
+ const attrs = { "neatlogs.span.kind": "LLM" };
9610
+ if (msg.model) attrs["neatlogs.llm.model_name"] = String(msg.model);
9611
+ if (msg.provider) attrs["neatlogs.llm.provider"] = String(msg.provider);
9612
+ if (msg.stopReason) attrs["neatlogs.llm.stop_reason"] = String(msg.stopReason);
9613
+ const inMsgs = state.inputMessages;
9614
+ if (inMsgs.length) {
9615
+ inMsgs.forEach((m, i) => {
9616
+ attrs[`neatlogs.llm.input_messages.${i}.role`] = m.role;
9617
+ attrs[`neatlogs.llm.input_messages.${i}.content`] = m.content;
7755
9618
  });
7756
- };
9619
+ attrs["neatlogs.llm.input"] = safeStringify12({ messages: inMsgs });
9620
+ attrs["input.value"] = safeStringify12({ messages: inMsgs });
9621
+ }
9622
+ const { text, toolCalls } = splitAssistantContent(msg.content);
9623
+ const outText = text || toolCalls.map((tc) => `${tc.name}(${safeStringify12(tc.arguments)})`).join("\n");
9624
+ if (outText || toolCalls.length) {
9625
+ attrs["neatlogs.llm.output_messages.0.role"] = "assistant";
9626
+ attrs["neatlogs.llm.output_messages.0.content"] = outText || "";
9627
+ const outBlob = { role: "assistant", content: outText || "" };
9628
+ if (toolCalls.length) {
9629
+ outBlob.tool_calls = toolCalls.map((tc) => ({ name: tc.name, arguments: tc.arguments }));
9630
+ toolCalls.forEach((tc, j) => {
9631
+ if (tc.name) attrs[`neatlogs.llm.tool_calls.${j}.name`] = tc.name;
9632
+ if (tc.arguments !== void 0)
9633
+ attrs[`neatlogs.llm.tool_calls.${j}.arguments`] = safeStringify12(tc.arguments);
9634
+ if (tc.id) attrs[`neatlogs.llm.tool_calls.${j}.id`] = String(tc.id);
9635
+ });
9636
+ }
9637
+ attrs["neatlogs.llm.output"] = safeStringify12(outBlob);
9638
+ attrs["output.value"] = outText || "";
9639
+ }
9640
+ const usage = msg.usage;
9641
+ if (usage) {
9642
+ if (usage.input != null) attrs["neatlogs.llm.token_count.prompt"] = usage.input;
9643
+ if (usage.output != null) attrs["neatlogs.llm.token_count.completion"] = usage.output;
9644
+ const total = usage.totalTokens ?? (usage.input ?? 0) + (usage.output ?? 0);
9645
+ if (total) attrs["neatlogs.llm.token_count.total"] = total;
9646
+ if (usage.cacheRead) attrs["neatlogs.llm.token_count.cache_read"] = usage.cacheRead;
9647
+ if (usage.cacheWrite) attrs["neatlogs.llm.token_count.cache_write"] = usage.cacheWrite;
9648
+ }
9649
+ const parent = state.agentCtx ?? import_api17.context.active();
9650
+ const span2 = tracer.startSpan(
9651
+ `pi_agent.llm.${msg.model || "model"}`,
9652
+ { attributes: attrs },
9653
+ parent
9654
+ );
9655
+ span2.setStatus({ code: import_api17.SpanStatusCode.OK });
9656
+ span2.end();
7757
9657
  }
7758
- function patchWorkflow(workflow) {
7759
- if (typeof workflow.createRun !== "function") return;
7760
- const origCreateRun = workflow.createRun.bind(workflow);
7761
- const workflowName = workflow.name ?? workflow.id ?? "mastra_workflow";
7762
- workflow.createRun = async function tracedCreateRun(...args) {
7763
- const run = await origCreateRun(...args);
7764
- if (!run) return run;
7765
- patchRunMethod(run, "start", workflowName);
7766
- patchRunMethod(run, "resume", workflowName);
7767
- return run;
7768
- };
9658
+ function splitAssistantContent(content) {
9659
+ const texts = [];
9660
+ const toolCalls = [];
9661
+ if (Array.isArray(content)) {
9662
+ for (const block of content) {
9663
+ if (!block || typeof block !== "object") continue;
9664
+ if (block.type === "text" && typeof block.text === "string") texts.push(block.text);
9665
+ else if (block.type === "toolCall")
9666
+ toolCalls.push(block);
9667
+ }
9668
+ } else if (typeof content === "string") {
9669
+ texts.push(content);
9670
+ }
9671
+ return { text: texts.join(""), toolCalls };
7769
9672
  }
7770
- function patchRunMethod(run, method, workflowName) {
7771
- if (typeof run[method] !== "function") return;
7772
- const orig = run[method].bind(run);
7773
- run[method] = async function tracedRunMethod(startOpts) {
7774
- const attrs = {
7775
- "neatlogs.span.kind": "WORKFLOW",
7776
- "neatlogs.workflow.name": workflowName
7777
- };
7778
- if (startOpts?.inputData !== void 0) {
7779
- attrs["input.value"] = safeStringify7(startOpts.inputData).slice(0, 1e4);
9673
+ function messageText(msg) {
9674
+ if (!msg) return "";
9675
+ const c = msg.content;
9676
+ if (typeof c === "string") return c;
9677
+ if (!Array.isArray(c)) return "";
9678
+ const parts = [];
9679
+ for (const block of c) {
9680
+ if (typeof block === "string") parts.push(block);
9681
+ else if (block && typeof block === "object") {
9682
+ if (typeof block.text === "string") parts.push(block.text);
9683
+ else if (block.type === "toolCall") parts.push(`${block.name ?? "tool"}(${safeStringify12(block.arguments)})`);
7780
9684
  }
7781
- return withActiveSpan(`mastra.workflow.${workflowName}`, attrs, async (span2) => {
7782
- const result = await orig(startOpts);
7783
- if (result?.status) span2.setAttribute("neatlogs.metadata", safeStringify7({ status: result.status }));
7784
- if (result?.result !== void 0) {
7785
- span2.setAttribute("output.value", safeStringify7(result.result).slice(0, 1e4));
7786
- }
7787
- return result;
7788
- });
7789
- };
9685
+ }
9686
+ return parts.join("");
7790
9687
  }
7791
- var VECTOR_READ_OPS = ["query"];
7792
- var VECTOR_WRITE_OPS = ["upsert", "updateVector", "deleteVector", "createIndex", "deleteIndex"];
7793
- function patchVector(vector) {
7794
- for (const op of VECTOR_READ_OPS) patchVectorOp(vector, op, "RETRIEVER");
7795
- for (const op of VECTOR_WRITE_OPS) patchVectorOp(vector, op, "VECTOR_STORE");
9688
+ function lastAssistantText(messages) {
9689
+ if (!Array.isArray(messages)) return "";
9690
+ for (let i = messages.length - 1; i >= 0; i--) {
9691
+ const m = messages[i];
9692
+ if (m && m.role === "assistant") {
9693
+ const { text } = splitAssistantContent(m.content);
9694
+ if (text) return text;
9695
+ }
9696
+ }
9697
+ return "";
7796
9698
  }
7797
- function patchVectorOp(vector, op, kind) {
7798
- if (typeof vector[op] !== "function") return;
7799
- const orig = vector[op].bind(vector);
7800
- const dbName = vector.constructor?.name ?? "vector";
7801
- vector[op] = async function tracedVectorOp(params) {
7802
- const attrs = {
7803
- "neatlogs.span.kind": kind,
7804
- "neatlogs.db.system": dbName,
7805
- "neatlogs.db.operation": op,
7806
- "input.value": safeStringify7(params).slice(0, 1e4)
7807
- };
7808
- const indexName = params?.indexName;
7809
- if (indexName) attrs["neatlogs.vectordb.index_name"] = String(indexName);
7810
- if (kind === "RETRIEVER" && params?.topK != null) attrs["neatlogs.retriever.top_k"] = params.topK;
7811
- return withActiveSpan(`mastra.vector.${op}`, attrs, async (span2) => {
7812
- const result = await orig(params);
7813
- span2.setAttribute("output.value", safeStringify7(result).slice(0, 1e4));
7814
- return result;
7815
- });
7816
- };
9699
+ function markPatched2(e) {
9700
+ try {
9701
+ Object.defineProperty(e, PATCH_FLAG3, { value: true, enumerable: false, configurable: true });
9702
+ } catch {
9703
+ e[PATCH_FLAG3] = true;
9704
+ }
7817
9705
  }
7818
- var MEMORY_OPS = ["recall", "saveMessages", "updateWorkingMemory", "deleteMessages"];
7819
- function patchMemory(memory) {
7820
- for (const op of MEMORY_OPS) {
7821
- if (typeof memory[op] !== "function") continue;
7822
- const orig = memory[op].bind(memory);
7823
- memory[op] = async function tracedMemoryOp(...args) {
7824
- const attrs = {
7825
- "neatlogs.span.kind": "CHAIN",
7826
- "neatlogs.db.operation": op,
7827
- "input.value": safeStringify7(args?.[0]).slice(0, 1e4)
7828
- };
7829
- return withActiveSpan(`mastra.memory.${op}`, attrs, async (span2) => {
7830
- const result = await orig(...args);
7831
- span2.setAttribute("output.value", safeStringify7(result).slice(0, 8e3));
7832
- return result;
7833
- });
7834
- };
9706
+ function safeStringify12(value) {
9707
+ if (typeof value === "string") return value;
9708
+ try {
9709
+ return JSON.stringify(value) ?? "";
9710
+ } catch {
9711
+ return "";
7835
9712
  }
7836
9713
  }
7837
- function patchDocument(doc) {
7838
- if (typeof doc.chunk !== "function") return;
7839
- const orig = doc.chunk.bind(doc);
7840
- doc.chunk = async function tracedChunk(...args) {
7841
- const attrs = {
7842
- "neatlogs.span.kind": "CHAIN",
7843
- "neatlogs.db.operation": "chunk"
7844
- };
7845
- return withActiveSpan("mastra.document.chunk", attrs, async (span2) => {
7846
- const result = await orig(...args);
7847
- if (Array.isArray(result)) span2.setAttribute("neatlogs.db.documents_count", result.length);
7848
- return result;
9714
+
9715
+ // src/claude-agent-sdk.ts
9716
+ var import_api18 = require("@opentelemetry/api");
9717
+ var TRACER_NAME12 = "neatlogs.claude_agent_sdk";
9718
+ var ROOT_SCOPE = "__root__";
9719
+ function wrapClaudeAgentSDK(sdk, options = {}) {
9720
+ if (!sdk || typeof sdk.query !== "function") return sdk;
9721
+ if (sdk._neatlogsWrapped) return sdk;
9722
+ const wrapped = { ...sdk };
9723
+ wrapped.query = wrapQuery(sdk.query.bind(sdk), options);
9724
+ try {
9725
+ Object.defineProperty(wrapped, "_neatlogsWrapped", {
9726
+ value: true,
9727
+ enumerable: false,
9728
+ configurable: true
7849
9729
  });
9730
+ } catch {
9731
+ wrapped._neatlogsWrapped = true;
9732
+ }
9733
+ return wrapped;
9734
+ }
9735
+ function wrapQuery(original, options) {
9736
+ return function(params, ...rest) {
9737
+ const tracer = import_api18.trace.getTracer(TRACER_NAME12);
9738
+ const workflowName = options.workflowName ?? "claude_agent.query";
9739
+ const promptRef = { text: "" };
9740
+ const agentSpan = tracer.startSpan(
9741
+ "claude_agent.query",
9742
+ { attributes: { "neatlogs.span.kind": "AGENT", "neatlogs.workflow.name": workflowName } },
9743
+ import_api18.context.active()
9744
+ );
9745
+ const promptText = extractPromptText(params?.prompt);
9746
+ if (promptText) {
9747
+ promptRef.text = promptText;
9748
+ agentSpan.setAttribute("input.value", promptText);
9749
+ } else if (params && isAsyncIterable(params.prompt)) {
9750
+ params = { ...params, prompt: tapPromptStream(params.prompt, promptRef) };
9751
+ }
9752
+ const agentCtx = import_api18.trace.setSpan(import_api18.context.active(), agentSpan);
9753
+ const queryObj = import_api18.context.with(agentCtx, () => original(params, ...rest));
9754
+ return instrumentQueryIterable(queryObj, agentSpan, agentCtx, tracer, promptRef);
7850
9755
  };
7851
9756
  }
7852
- function wrapRootMastra(mastra) {
7853
- const AGENT_GETTERS = /* @__PURE__ */ new Set(["getAgent", "getAgentById"]);
7854
- const WORKFLOW_GETTERS = /* @__PURE__ */ new Set(["getWorkflow", "getWorkflowById"]);
7855
- return new Proxy(mastra, {
7856
- get(target, prop, receiver) {
7857
- const value = Reflect.get(target, prop, receiver);
7858
- if (typeof value !== "function") return value;
7859
- const name = String(prop);
7860
- if (AGENT_GETTERS.has(name) || WORKFLOW_GETTERS.has(name)) {
7861
- return (...args) => {
7862
- const entity = value.apply(target, args);
7863
- return entity && typeof entity === "object" ? wrapMastra(entity) : entity;
7864
- };
7865
- }
7866
- return value.bind(target);
7867
- }
7868
- });
9757
+ function isAsyncIterable(v) {
9758
+ return Boolean(v) && typeof v[Symbol.asyncIterator] === "function";
7869
9759
  }
7870
- function wrapStreamingOutput(output, span2, ctx) {
7871
- if (!output) {
7872
- span2.setStatus({ code: import_api13.SpanStatusCode.OK });
7873
- span2.end();
7874
- return output;
9760
+ async function* tapPromptStream(prompt, ref) {
9761
+ for await (const message of prompt) {
9762
+ if (!ref.text) {
9763
+ const text = userMessageText(message);
9764
+ if (text) ref.text = text;
9765
+ }
9766
+ yield message;
7875
9767
  }
7876
- let ended = false;
7877
- const endOnce = (err) => {
7878
- if (ended) return;
7879
- ended = true;
7880
- if (err) recordError3(span2, err);
7881
- else span2.setStatus({ code: import_api13.SpanStatusCode.OK });
7882
- span2.end();
9768
+ }
9769
+ function instrumentQueryIterable(queryObj, agentSpan, agentCtx, tracer, promptRef) {
9770
+ const originalAsyncIterator = queryObj?.[Symbol.asyncIterator]?.bind(queryObj);
9771
+ if (!originalAsyncIterator) {
9772
+ agentSpan.setStatus({ code: import_api18.SpanStatusCode.OK });
9773
+ agentSpan.end();
9774
+ return queryObj;
9775
+ }
9776
+ const rootScope = {
9777
+ span: agentSpan,
9778
+ ctx: agentCtx,
9779
+ inputMessages: promptRef.text ? [{ role: "user", content: promptRef.text }] : [],
9780
+ assistantBuffer: null,
9781
+ finalText: "",
9782
+ inputCaptured: Boolean(promptRef.text)
7883
9783
  };
7884
- if (output.text && typeof output.text.then === "function") {
7885
- const finalize = async () => {
9784
+ const state = {
9785
+ toolSpans: /* @__PURE__ */ new Map(),
9786
+ scopes: /* @__PURE__ */ new Map([[ROOT_SCOPE, rootScope]]),
9787
+ finished: false,
9788
+ promptRef
9789
+ };
9790
+ const finalizeAgent = (status, err) => {
9791
+ if (state.finished) return;
9792
+ state.finished = true;
9793
+ for (const scope of state.scopes.values()) flushAssistantTurn(tracer, scope, state);
9794
+ for (const ts of state.toolSpans.values()) {
7886
9795
  try {
7887
- const [text, usage, finishReason] = await Promise.all([
7888
- Promise.resolve(output.text).catch(() => void 0),
7889
- Promise.resolve(output.usage).catch(() => void 0),
7890
- Promise.resolve(output.finishReason).catch(() => void 0)
7891
- ]);
7892
- if (typeof text === "string" && text) {
7893
- span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7894
- span2.setAttribute("neatlogs.llm.output_messages.0.content", text.slice(0, 1e4));
7895
- }
7896
- if (usage) recordUsage(span2, usage);
7897
- if (finishReason) span2.setAttribute("neatlogs.llm.stop_reason", normalizeFinishReason(finishReason));
7898
- endOnce();
7899
- } catch (err) {
7900
- endOnce(err);
9796
+ ts.end();
9797
+ } catch {
7901
9798
  }
7902
- };
7903
- void finalize();
7904
- return rebindStreamContext(output, ctx);
7905
- }
7906
- if (output[Symbol.asyncIterator]) {
7907
- const origIterator = output[Symbol.asyncIterator].bind(output);
7908
- const textParts = [];
7909
- const wrapped = Object.create(Object.getPrototypeOf(output));
7910
- Object.assign(wrapped, output);
7911
- wrapped[Symbol.asyncIterator] = function() {
7912
- const iterator = origIterator();
7913
- const finish = () => {
7914
- if (textParts.length) {
7915
- span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7916
- span2.setAttribute("neatlogs.llm.output_messages.0.content", textParts.join("").slice(0, 1e4));
7917
- }
7918
- endOnce();
7919
- };
7920
- return {
7921
- async next() {
9799
+ }
9800
+ state.toolSpans.clear();
9801
+ for (const [key, scope] of state.scopes) {
9802
+ if (key === ROOT_SCOPE) continue;
9803
+ closeScope(scope, "ok");
9804
+ }
9805
+ if (rootScope.finalText) agentSpan.setAttribute("output.value", rootScope.finalText);
9806
+ if (status === "error") {
9807
+ recordError7(agentSpan, err);
9808
+ } else {
9809
+ agentSpan.setStatus({ code: import_api18.SpanStatusCode.OK });
9810
+ agentSpan.end();
9811
+ }
9812
+ };
9813
+ const wrapped = Object.create(Object.getPrototypeOf(queryObj));
9814
+ Object.assign(wrapped, queryObj);
9815
+ wrapped[Symbol.asyncIterator] = function() {
9816
+ const iterator = originalAsyncIterator();
9817
+ return {
9818
+ async next() {
9819
+ try {
9820
+ const result = await import_api18.context.with(agentCtx, () => iterator.next());
9821
+ if (result.done) {
9822
+ finalizeAgent("ok");
9823
+ return result;
9824
+ }
7922
9825
  try {
7923
- const r = await iterator.next();
7924
- if (r.done) {
7925
- finish();
7926
- return r;
7927
- }
7928
- const chunk = r.value;
7929
- if (typeof chunk === "string") textParts.push(chunk);
7930
- else if (chunk?.text) textParts.push(chunk.text);
7931
- else if (chunk?.delta) textParts.push(chunk.delta);
7932
- return r;
7933
- } catch (err) {
7934
- endOnce(err);
7935
- throw err;
9826
+ handleMessage(tracer, state, result.value, finalizeAgent);
9827
+ } catch {
7936
9828
  }
7937
- },
7938
- async return(value) {
7939
- finish();
7940
- return iterator.return?.(value) ?? { done: true, value: void 0 };
7941
- },
7942
- async throw(err) {
7943
- endOnce(err);
7944
- return iterator.throw?.(err) ?? { done: true, value: void 0 };
9829
+ return result;
9830
+ } catch (err) {
9831
+ finalizeAgent("error", err);
9832
+ throw err;
7945
9833
  }
7946
- };
9834
+ },
9835
+ async return(value) {
9836
+ finalizeAgent("ok");
9837
+ return iterator.return?.(value) ?? { done: true, value: void 0 };
9838
+ },
9839
+ async throw(err) {
9840
+ finalizeAgent("error", err);
9841
+ if (iterator.throw) return iterator.throw(err);
9842
+ throw err;
9843
+ }
7947
9844
  };
7948
- return wrapped;
9845
+ };
9846
+ return wrapped;
9847
+ }
9848
+ function closeScope(scope, status) {
9849
+ try {
9850
+ if (scope.finalText) scope.span.setAttribute("output.value", scope.finalText);
9851
+ scope.span.setStatus({ code: status === "ok" ? import_api18.SpanStatusCode.OK : import_api18.SpanStatusCode.ERROR });
9852
+ scope.span.end();
9853
+ } catch {
7949
9854
  }
7950
- if (typeof output.then === "function") {
7951
- return output.then((resolved) => {
7952
- finalizeAgentResult(span2, resolved);
7953
- endOnce();
7954
- return resolved;
7955
- }).catch((err) => {
7956
- endOnce(err);
7957
- throw err;
7958
- });
9855
+ }
9856
+ function getScope(tracer, state, msg) {
9857
+ const parentId = msg?.parent_tool_use_id ?? null;
9858
+ if (!parentId) return state.scopes.get(ROOT_SCOPE);
9859
+ const existing = state.scopes.get(parentId);
9860
+ if (existing) return existing;
9861
+ const root = state.scopes.get(ROOT_SCOPE);
9862
+ if (!state.toolSpans.has(parentId) && root.assistantBuffer) {
9863
+ flushAssistantTurn(tracer, root, state);
9864
+ }
9865
+ const parentToolSpan = state.toolSpans.get(parentId);
9866
+ const parentCtx = parentToolSpan ? import_api18.trace.setSpan(import_api18.context.active(), parentToolSpan) : state.scopes.get(ROOT_SCOPE).ctx;
9867
+ const subType = msg?.subagent_type ? String(msg.subagent_type) : "subagent";
9868
+ const attrs = {
9869
+ "neatlogs.span.kind": "AGENT",
9870
+ "neatlogs.agent.name": subType
9871
+ };
9872
+ if (msg?.task_description) attrs["input.value"] = String(msg.task_description);
9873
+ const span2 = tracer.startSpan(`claude_agent.subagent.${subType}`, { attributes: attrs }, parentCtx);
9874
+ const scope = {
9875
+ span: span2,
9876
+ ctx: import_api18.trace.setSpan(import_api18.context.active(), span2),
9877
+ inputMessages: msg?.task_description ? [{ role: "user", content: String(msg.task_description) }] : [],
9878
+ assistantBuffer: null,
9879
+ finalText: "",
9880
+ inputCaptured: Boolean(msg?.task_description)
9881
+ };
9882
+ state.scopes.set(parentId, scope);
9883
+ return scope;
9884
+ }
9885
+ function handleMessage(tracer, state, msg, finalizeAgent) {
9886
+ if (!msg || typeof msg !== "object") return;
9887
+ const rootScope = state.scopes.get(ROOT_SCOPE);
9888
+ if (!rootScope.inputCaptured && state.promptRef.text) {
9889
+ rootScope.inputCaptured = true;
9890
+ rootScope.span.setAttribute("input.value", state.promptRef.text);
9891
+ }
9892
+ switch (msg.type) {
9893
+ case "system": {
9894
+ if (msg.session_id) {
9895
+ state.sessionId = msg.session_id;
9896
+ rootScope.span.setAttribute("neatlogs.conversation.id", String(msg.session_id));
9897
+ }
9898
+ if (msg.model) {
9899
+ state.model = msg.model;
9900
+ rootScope.span.setAttribute("neatlogs.agent.model", String(msg.model));
9901
+ }
9902
+ break;
9903
+ }
9904
+ case "user": {
9905
+ const scope = getScope(tracer, state, msg);
9906
+ flushAssistantTurn(tracer, scope, state);
9907
+ const userText = userMessageText(msg);
9908
+ if (userText) {
9909
+ if (!scope.inputCaptured) {
9910
+ scope.inputCaptured = true;
9911
+ scope.span.setAttribute("input.value", userText);
9912
+ }
9913
+ scope.inputMessages.push({ role: "user", content: userText });
9914
+ }
9915
+ closeToolSpansFromUser(state, scope, msg);
9916
+ break;
9917
+ }
9918
+ case "assistant": {
9919
+ const scope = getScope(tracer, state, msg);
9920
+ bufferAssistantMessage(scope, msg);
9921
+ break;
9922
+ }
9923
+ case "result": {
9924
+ flushAssistantTurn(tracer, rootScope, state);
9925
+ const text = typeof msg.result === "string" ? msg.result : "";
9926
+ if (text) rootScope.finalText = text;
9927
+ if (msg.session_id && !state.sessionId) {
9928
+ rootScope.span.setAttribute("neatlogs.conversation.id", String(msg.session_id));
9929
+ }
9930
+ const usage = msg.usage;
9931
+ if (usage) setUsage2(rootScope.span, usage);
9932
+ if (msg.total_cost_usd != null) rootScope.span.setAttribute("neatlogs.agent.cost_usd", msg.total_cost_usd);
9933
+ if (msg.num_turns != null) rootScope.span.setAttribute("neatlogs.agent.num_turns", msg.num_turns);
9934
+ if (msg.is_error) rootScope.span.setAttribute("neatlogs.agent.is_error", true);
9935
+ finalizeAgent(msg.is_error ? "error" : "ok", msg.is_error ? new Error(String(text || "agent run failed")) : void 0);
9936
+ break;
9937
+ }
9938
+ default:
9939
+ break;
7959
9940
  }
7960
- endOnce();
7961
- return output;
7962
9941
  }
7963
- function rebindStreamContext(output, ctx) {
7964
- const STREAM_PROPS = /* @__PURE__ */ new Set(["textStream", "fullStream", "objectStream", "elementStream"]);
7965
- return new Proxy(output, {
7966
- get(target, prop, receiver) {
7967
- const value = Reflect.get(target, prop, receiver);
7968
- if (typeof prop === "string" && STREAM_PROPS.has(prop) && value && value[Symbol.asyncIterator]) {
7969
- const origIterator = value[Symbol.asyncIterator].bind(value);
7970
- return {
7971
- [Symbol.asyncIterator]() {
7972
- return import_api13.context.with(ctx, () => origIterator());
7973
- }
7974
- };
7975
- }
7976
- if (typeof value === "function") return value.bind(target);
7977
- return value;
9942
+ function bufferAssistantMessage(scope, msg) {
9943
+ const message = msg.message ?? msg;
9944
+ const content = message?.content ?? [];
9945
+ if (!scope.assistantBuffer) {
9946
+ scope.assistantBuffer = { textParts: [], thinkingParts: [], toolCalls: [], usage: void 0 };
9947
+ }
9948
+ const buf = scope.assistantBuffer;
9949
+ if (message?.model) buf.model = message.model;
9950
+ if (message?.stop_reason) buf.stopReason = message.stop_reason;
9951
+ if (message?.usage) buf.usage = message.usage;
9952
+ for (const block of Array.isArray(content) ? content : []) {
9953
+ if (!block || typeof block !== "object") continue;
9954
+ if (block.type === "text" && typeof block.text === "string") buf.textParts.push(block.text);
9955
+ else if (block.type === "thinking" && typeof block.thinking === "string") buf.thinkingParts.push(block.thinking);
9956
+ else if (block.type === "tool_use") {
9957
+ buf.toolCalls.push({ id: block.id ?? "", name: block.name ?? "", input: block.input });
7978
9958
  }
7979
- });
9959
+ }
7980
9960
  }
7981
- function finalizeAgentResult(span2, result) {
7982
- if (!result) return;
7983
- if (result.text) {
7984
- span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
7985
- span2.setAttribute("neatlogs.llm.output_messages.0.content", String(result.text).slice(0, 1e4));
9961
+ function flushAssistantTurn(tracer, scope, state) {
9962
+ const buf = scope.assistantBuffer;
9963
+ if (!buf) return;
9964
+ scope.assistantBuffer = null;
9965
+ const model = buf.model ?? state.model ?? "";
9966
+ const attrs = {
9967
+ "neatlogs.span.kind": "LLM",
9968
+ "neatlogs.llm.provider": "anthropic",
9969
+ "neatlogs.llm.system": "anthropic"
9970
+ };
9971
+ if (model) attrs["neatlogs.llm.model_name"] = String(model);
9972
+ if (scope.inputMessages.length === 0 && state.promptRef.text) {
9973
+ scope.inputMessages.push({ role: "user", content: state.promptRef.text });
7986
9974
  }
7987
- if (Array.isArray(result.toolCalls)) {
7988
- for (let i = 0; i < result.toolCalls.length; i++) {
7989
- const tc = result.toolCalls[i];
7990
- const p = tc.payload ?? tc;
7991
- setToolCall(span2, i, p.toolName ?? p.name, p.args ?? p.arguments, p.toolCallId ?? p.id);
9975
+ scope.inputMessages.forEach((m, i) => {
9976
+ attrs[`neatlogs.llm.input_messages.${i}.role`] = m.role;
9977
+ attrs[`neatlogs.llm.input_messages.${i}.content`] = m.content;
9978
+ });
9979
+ if (scope.inputMessages.length) {
9980
+ attrs["input.value"] = safeStringify13({ messages: scope.inputMessages });
9981
+ }
9982
+ const outText = buf.textParts.join("");
9983
+ const outValue = outText || buf.toolCalls.map((tc) => `${tc.name}(${safeStringify13(tc.input ?? {})})`).join("\n");
9984
+ if (outValue) {
9985
+ attrs["neatlogs.llm.output_messages.0.role"] = "assistant";
9986
+ attrs["neatlogs.llm.output_messages.0.content"] = outValue;
9987
+ attrs["output.value"] = outValue;
9988
+ }
9989
+ if (buf.thinkingParts.length) {
9990
+ attrs["neatlogs.llm.output_messages.0.thinking"] = buf.thinkingParts.join("");
9991
+ }
9992
+ buf.toolCalls.forEach((tc, j) => {
9993
+ attrs[`neatlogs.llm.tool_calls.${j}.id`] = tc.id;
9994
+ attrs[`neatlogs.llm.tool_calls.${j}.name`] = tc.name;
9995
+ attrs[`neatlogs.llm.tool_calls.${j}.arguments`] = safeStringify13(tc.input ?? {});
9996
+ });
9997
+ if (buf.stopReason) attrs["neatlogs.llm.finish_reason"] = String(buf.stopReason);
9998
+ const span2 = tracer.startSpan(`claude_agent.llm.${model || "model"}`, { attributes: attrs }, scope.ctx);
9999
+ if (buf.usage) setUsage2(span2, buf.usage);
10000
+ span2.setStatus({ code: import_api18.SpanStatusCode.OK });
10001
+ span2.end();
10002
+ if (outText) scope.finalText = outText;
10003
+ const turnParts = [];
10004
+ if (outText) turnParts.push(outText);
10005
+ for (const tc of buf.toolCalls) turnParts.push(`[tool_call ${tc.name} ${safeStringify13(tc.input ?? {})}]`);
10006
+ if (turnParts.length) scope.inputMessages.push({ role: "assistant", content: turnParts.join("\n") });
10007
+ for (const tc of buf.toolCalls) {
10008
+ const toolSpan = tracer.startSpan(
10009
+ `claude_agent.tool.${tc.name || "tool"}`,
10010
+ {
10011
+ attributes: {
10012
+ "neatlogs.span.kind": "TOOL",
10013
+ "neatlogs.tool.name": String(tc.name ?? ""),
10014
+ ...tc.id ? { "neatlogs.tool_call.id": String(tc.id) } : {},
10015
+ "input.value": safeStringify13(tc.input ?? {})
10016
+ }
10017
+ },
10018
+ scope.ctx
10019
+ );
10020
+ if (tc.id) state.toolSpans.set(tc.id, toolSpan);
10021
+ }
10022
+ }
10023
+ function closeToolSpansFromUser(state, scope, msg) {
10024
+ const content = (msg.message ?? msg)?.content ?? [];
10025
+ for (const block of Array.isArray(content) ? content : []) {
10026
+ if (block?.type !== "tool_result") continue;
10027
+ const id = block.tool_use_id ?? "";
10028
+ const out = block.content;
10029
+ const outText = typeof out === "string" ? out : safeStringify13(out);
10030
+ if (outText) scope.inputMessages.push({ role: "tool", content: outText });
10031
+ const span2 = state.toolSpans.get(id);
10032
+ if (!span2) continue;
10033
+ span2.setAttribute("output.value", outText);
10034
+ if (block.is_error) {
10035
+ span2.setStatus({ code: import_api18.SpanStatusCode.ERROR });
10036
+ span2.setAttribute("neatlogs.tool.is_error", true);
10037
+ } else {
10038
+ span2.setStatus({ code: import_api18.SpanStatusCode.OK });
7992
10039
  }
10040
+ span2.end();
10041
+ state.toolSpans.delete(id);
7993
10042
  }
7994
- if (result.usage) recordUsage(span2, result.usage);
7995
- if (result.finishReason) span2.setAttribute("neatlogs.llm.stop_reason", normalizeFinishReason(result.finishReason));
7996
- if (result.model) span2.setAttribute("neatlogs.llm.model_name", result.model);
7997
10043
  }
7998
- function finalizeModelResult(span2, result) {
7999
- if (!result) return;
8000
- if (typeof result.text === "string" && result.text) {
8001
- span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
8002
- span2.setAttribute("neatlogs.llm.output_messages.0.content", result.text.slice(0, 1e4));
8003
- } else if (Array.isArray(result.content)) {
8004
- const text = result.content.filter((p) => p?.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
8005
- if (text) {
8006
- span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
8007
- span2.setAttribute("neatlogs.llm.output_messages.0.content", text.slice(0, 1e4));
8008
- }
8009
- const toolCalls = result.content.filter((p) => p?.type === "tool-call");
8010
- for (let i = 0; i < toolCalls.length; i++) {
8011
- const tc = toolCalls[i];
8012
- setToolCall(span2, i, tc.toolName, tc.input ?? tc.args, tc.toolCallId);
10044
+ function userMessageText(msg) {
10045
+ const content = (msg.message ?? msg)?.content;
10046
+ if (typeof content === "string") return content;
10047
+ if (!Array.isArray(content)) return "";
10048
+ const parts = [];
10049
+ for (const block of content) {
10050
+ if (typeof block === "string") parts.push(block);
10051
+ else if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
10052
+ parts.push(block.text);
8013
10053
  }
8014
- span2.setAttribute("output.value", safeStringify7(result.content).slice(0, 1e4));
8015
10054
  }
8016
- if (result.usage) recordUsage(span2, result.usage);
8017
- span2.setAttribute("neatlogs.llm.stop_reason", normalizeFinishReason(result.finishReason));
10055
+ return parts.join("\n");
8018
10056
  }
8019
- function normalizeFinishReason(fr) {
8020
- if (fr == null) return "";
8021
- if (typeof fr === "string") return fr;
8022
- return String(fr.unified ?? fr.reason ?? fr.type ?? safeStringify7(fr));
10057
+ function setUsage2(span2, usage) {
10058
+ if (!usage) return;
10059
+ if (usage.input_tokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", usage.input_tokens);
10060
+ if (usage.output_tokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", usage.output_tokens);
10061
+ if (usage.input_tokens != null && usage.output_tokens != null) {
10062
+ span2.setAttribute("neatlogs.llm.token_count.total", usage.input_tokens + usage.output_tokens);
10063
+ }
10064
+ if (usage.cache_read_input_tokens != null) {
10065
+ span2.setAttribute("neatlogs.llm.token_count.cache_read", usage.cache_read_input_tokens);
10066
+ }
10067
+ if (usage.cache_creation_input_tokens != null) {
10068
+ span2.setAttribute("neatlogs.llm.token_count.cache_write", usage.cache_creation_input_tokens);
10069
+ }
8023
10070
  }
8024
- function tokenValue(v) {
8025
- if (v == null) return void 0;
8026
- if (typeof v === "number") return v;
8027
- if (typeof v === "object" && typeof v.total === "number") return v.total;
8028
- const n = Number(v);
8029
- return Number.isFinite(n) ? n : void 0;
10071
+ function extractPromptText(prompt) {
10072
+ if (typeof prompt === "string") return prompt;
10073
+ return "";
8030
10074
  }
8031
- function captureInvocationParams(attrs, callOpts) {
8032
- if (!callOpts) return;
8033
- const map = [
8034
- ["temperature", "neatlogs.llm.temperature"],
8035
- ["maxOutputTokens", "neatlogs.llm.max_tokens"],
8036
- ["maxTokens", "neatlogs.llm.max_tokens"],
8037
- ["topP", "neatlogs.llm.top_p"],
8038
- ["topK", "neatlogs.llm.top_k"],
8039
- ["frequencyPenalty", "neatlogs.llm.frequency_penalty"],
8040
- ["presencePenalty", "neatlogs.llm.presence_penalty"]
8041
- ];
8042
- const invocation = {};
8043
- for (const [src, target] of map) {
8044
- const v = callOpts[src];
8045
- if (v != null) {
8046
- attrs[target] = v;
8047
- invocation[src] = v;
8048
- }
10075
+ function safeStringify13(value) {
10076
+ if (typeof value === "string") return value;
10077
+ try {
10078
+ return JSON.stringify(value) ?? "";
10079
+ } catch {
10080
+ return "";
8049
10081
  }
8050
- if (Array.isArray(callOpts.stopSequences) && callOpts.stopSequences.length) {
8051
- attrs["neatlogs.llm.stop_sequences"] = safeStringify7(callOpts.stopSequences);
8052
- invocation.stopSequences = callOpts.stopSequences;
10082
+ }
10083
+ function recordError7(span2, err) {
10084
+ if (err instanceof Error) {
10085
+ span2.setStatus({ code: import_api18.SpanStatusCode.ERROR, message: err.message });
10086
+ span2.recordException(err);
10087
+ } else {
10088
+ span2.setStatus({ code: import_api18.SpanStatusCode.ERROR, message: String(err) });
8053
10089
  }
8054
- if (Array.isArray(callOpts.tools)) {
8055
- for (let i = 0; i < callOpts.tools.length; i++) {
8056
- attrs[`neatlogs.llm.tools.${i}`] = safeStringify7(callOpts.tools[i]).slice(0, 4e3);
10090
+ span2.end();
10091
+ }
10092
+
10093
+ // src/openrouter-agent.ts
10094
+ var import_api19 = require("@opentelemetry/api");
10095
+ var TRACER_NAME13 = "neatlogs.openrouter_agent";
10096
+ var PROVIDER4 = "openrouter";
10097
+ function wrapOpenRouterAgent(client) {
10098
+ const c = client;
10099
+ if (!c || c._neatlogsWrapped) return client;
10100
+ return new Proxy(client, {
10101
+ get(obj, prop, receiver) {
10102
+ const value = Reflect.get(obj, prop, receiver);
10103
+ if (prop === "callModel" && typeof value === "function") {
10104
+ return tracedCallModel(value.bind(obj));
10105
+ }
10106
+ return value;
8057
10107
  }
8058
- invocation.toolChoice = callOpts.toolChoice;
8059
- }
8060
- if (Object.keys(invocation).length) {
8061
- attrs["neatlogs.llm.invocation_parameters"] = safeStringify7(invocation).slice(0, 4e3);
8062
- }
10108
+ });
8063
10109
  }
8064
- function setToolCall(span2, i, name, args, id) {
8065
- span2.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, name ?? "");
8066
- span2.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, safeStringify7(args ?? {}));
8067
- if (id) span2.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, id);
10110
+ function wrapCallModel(callModel) {
10111
+ return function(clientArg, opts, ...rest) {
10112
+ const span2 = startLlmSpan(opts);
10113
+ const ctx = import_api19.trace.setSpan(import_api19.context.active(), span2);
10114
+ const result = import_api19.context.with(ctx, () => callModel.call(this, clientArg, opts, ...rest));
10115
+ return instrumentModelResult(result, span2);
10116
+ };
8068
10117
  }
8069
- function recordUsage(span2, usage) {
8070
- if (!usage) return;
8071
- const prompt = tokenValue(usage.promptTokens ?? usage.inputTokens ?? usage.input_tokens);
8072
- const completion = tokenValue(usage.completionTokens ?? usage.outputTokens ?? usage.output_tokens);
8073
- const total = tokenValue(usage.totalTokens);
8074
- if (prompt != null) span2.setAttribute("neatlogs.llm.token_count.prompt", prompt);
8075
- if (completion != null) span2.setAttribute("neatlogs.llm.token_count.completion", completion);
8076
- if (total != null) span2.setAttribute("neatlogs.llm.token_count.total", total);
8077
- else if (prompt != null && completion != null) {
8078
- span2.setAttribute("neatlogs.llm.token_count.total", prompt + completion);
8079
- }
10118
+ function tracedCallModel(original) {
10119
+ return function(opts, ...rest) {
10120
+ const span2 = startLlmSpan(opts);
10121
+ const ctx = import_api19.trace.setSpan(import_api19.context.active(), span2);
10122
+ const result = import_api19.context.with(ctx, () => original(opts, ...rest));
10123
+ return instrumentModelResult(result, span2);
10124
+ };
8080
10125
  }
8081
- function withActiveSpan(name, attrs, fn) {
8082
- const tracer = import_api13.trace.getTracer(TRACER_NAME7);
8083
- const span2 = tracer.startSpan(name, { attributes: attrs }, import_api13.context.active());
8084
- const ctx = import_api13.trace.setSpan(import_api13.context.active(), span2);
8085
- return import_api13.context.with(ctx, async () => {
10126
+ function startLlmSpan(opts) {
10127
+ const tracer = import_api19.trace.getTracer(TRACER_NAME13);
10128
+ const model = opts?.model ?? "";
10129
+ const span2 = tracer.startSpan("openrouter.call_model", {
10130
+ attributes: {
10131
+ "neatlogs.span.kind": "LLM",
10132
+ "neatlogs.llm.provider": PROVIDER4,
10133
+ "neatlogs.llm.system": PROVIDER4,
10134
+ "neatlogs.llm.model_name": model
10135
+ }
10136
+ }, import_api19.context.active());
10137
+ const messages = Array.isArray(opts?.messages) ? opts.messages : Array.isArray(opts?.input) ? opts.input : [];
10138
+ if (messages.length) {
10139
+ messages.forEach((msg, i) => {
10140
+ span2.setAttribute(`neatlogs.llm.input_messages.${i}.role`, msg?.role ?? "user");
10141
+ const content = msg?.content;
10142
+ span2.setAttribute(
10143
+ `neatlogs.llm.input_messages.${i}.content`,
10144
+ typeof content === "string" ? content : safeStringify14(content)
10145
+ );
10146
+ });
10147
+ span2.setAttribute("input.value", safeStringify14({ messages }));
10148
+ } else if (typeof opts?.input === "string") {
10149
+ span2.setAttribute("neatlogs.llm.input_messages.0.role", "user");
10150
+ span2.setAttribute("neatlogs.llm.input_messages.0.content", opts.input);
10151
+ span2.setAttribute("input.value", opts.input);
10152
+ }
10153
+ if (typeof opts?.instructions === "string" && opts.instructions) {
10154
+ span2.setAttribute("neatlogs.llm.system_prompt", opts.instructions);
10155
+ }
10156
+ if (Array.isArray(opts?.tools)) {
10157
+ for (let i = 0; i < opts.tools.length; i++) {
10158
+ const t = opts.tools[i] ?? {};
10159
+ const name = t.name ?? t.function?.name;
10160
+ if (name) span2.setAttribute(`neatlogs.llm.tools.${i}.name`, name);
10161
+ const desc = t.description ?? t.function?.description;
10162
+ if (desc) span2.setAttribute(`neatlogs.llm.tools.${i}.description`, desc);
10163
+ }
10164
+ }
10165
+ const temperature = opts?.temperature;
10166
+ const topP = opts?.top_p ?? opts?.topP;
10167
+ const maxTokens = opts?.max_tokens ?? opts?.maxTokens ?? opts?.max_output_tokens ?? opts?.maxOutputTokens;
10168
+ const frequencyPenalty = opts?.frequency_penalty ?? opts?.frequencyPenalty;
10169
+ const presencePenalty = opts?.presence_penalty ?? opts?.presencePenalty;
10170
+ const topK = opts?.top_k ?? opts?.topK;
10171
+ if (temperature != null) span2.setAttribute("neatlogs.llm.temperature", temperature);
10172
+ if (topP != null) span2.setAttribute("neatlogs.llm.top_p", topP);
10173
+ if (maxTokens != null) span2.setAttribute("neatlogs.llm.max_tokens", maxTokens);
10174
+ const params = {};
10175
+ if (temperature != null) params.temperature = temperature;
10176
+ if (topP != null) params.top_p = topP;
10177
+ if (maxTokens != null) params.max_tokens = maxTokens;
10178
+ if (frequencyPenalty != null) params.frequency_penalty = frequencyPenalty;
10179
+ if (presencePenalty != null) params.presence_penalty = presencePenalty;
10180
+ if (topK != null) params.top_k = topK;
10181
+ if (Object.keys(params).length) {
10182
+ span2.setAttribute("neatlogs.llm.invocation_parameters", JSON.stringify(params));
10183
+ }
10184
+ return span2;
10185
+ }
10186
+ function instrumentModelResult(result, span2) {
10187
+ if (!result || typeof result !== "object" && typeof result !== "function") {
10188
+ span2.setStatus({ code: import_api19.SpanStatusCode.OK });
10189
+ span2.end();
10190
+ return result;
10191
+ }
10192
+ let finalized = false;
10193
+ const finalizeFromResult = (resolved) => {
10194
+ if (finalized) return;
10195
+ finalized = true;
8086
10196
  try {
8087
- const result = await fn(span2);
8088
- span2.setStatus({ code: import_api13.SpanStatusCode.OK });
8089
- return result;
8090
- } catch (err) {
8091
- recordError3(span2, err);
8092
- throw err;
8093
- } finally {
10197
+ finalizeLlm(span2, resolved);
10198
+ } catch {
10199
+ span2.setStatus({ code: import_api19.SpanStatusCode.OK });
8094
10200
  span2.end();
8095
10201
  }
10202
+ };
10203
+ const finalizeError = (err) => {
10204
+ if (finalized) return;
10205
+ finalized = true;
10206
+ recordError8(span2, err);
10207
+ };
10208
+ return new Proxy(result, {
10209
+ get(obj, prop, receiver) {
10210
+ const value = Reflect.get(obj, prop, receiver);
10211
+ if (prop === "getResponse" && typeof value === "function") {
10212
+ return function(...args) {
10213
+ return Promise.resolve(value.apply(obj, args)).then(
10214
+ (resp) => {
10215
+ finalizeFromResult(resp);
10216
+ return resp;
10217
+ },
10218
+ (err) => {
10219
+ finalizeError(err);
10220
+ throw err;
10221
+ }
10222
+ );
10223
+ };
10224
+ }
10225
+ if (prop === "getText" && typeof value === "function") {
10226
+ return function(...args) {
10227
+ return Promise.resolve(value.apply(obj, args)).then(
10228
+ async (textStr) => {
10229
+ let resp;
10230
+ if (typeof obj?.getResponse === "function") {
10231
+ try {
10232
+ resp = await obj.getResponse();
10233
+ } catch {
10234
+ resp = void 0;
10235
+ }
10236
+ }
10237
+ finalizeFromResult(resp ? { ...resp, text: textStr } : { text: textStr });
10238
+ return textStr;
10239
+ },
10240
+ (err) => {
10241
+ finalizeError(err);
10242
+ throw err;
10243
+ }
10244
+ );
10245
+ };
10246
+ }
10247
+ if (prop === "then" && typeof value === "function") {
10248
+ return function(onFulfilled, onRejected) {
10249
+ return value.call(
10250
+ obj,
10251
+ (resolved) => {
10252
+ finalizeFromResult(typeof resolved === "string" ? { text: resolved } : resolved ?? obj);
10253
+ return onFulfilled ? onFulfilled(resolved) : resolved;
10254
+ },
10255
+ (err) => {
10256
+ finalizeError(err);
10257
+ return onRejected ? onRejected(err) : Promise.reject(err);
10258
+ }
10259
+ );
10260
+ };
10261
+ }
10262
+ return value;
10263
+ }
8096
10264
  });
8097
10265
  }
8098
- function markPatched(e) {
8099
- try {
8100
- Object.defineProperty(e, PATCH_FLAG, { value: true, enumerable: false, configurable: true });
8101
- } catch {
8102
- e[PATCH_FLAG] = true;
8103
- }
10266
+ function setOpenResponsesUsage(span2, resp) {
10267
+ const u = resp?.usage ?? resp;
10268
+ if (!u) return;
10269
+ const input = u.inputTokens ?? u.input_tokens ?? u.prompt_tokens;
10270
+ const output = u.outputTokens ?? u.output_tokens ?? u.completion_tokens;
10271
+ const total = u.totalTokens ?? u.total_tokens;
10272
+ const cached = u.cachedTokens ?? u.cached_tokens;
10273
+ if (input != null) span2.setAttribute("neatlogs.llm.token_count.prompt", input);
10274
+ if (output != null) span2.setAttribute("neatlogs.llm.token_count.completion", output);
10275
+ if (total != null) span2.setAttribute("neatlogs.llm.token_count.total", total);
10276
+ else if (input != null && output != null) span2.setAttribute("neatlogs.llm.token_count.total", input + output);
10277
+ if (cached != null) span2.setAttribute("neatlogs.llm.token_count.cache_read", cached);
8104
10278
  }
8105
- function extractModelId(model) {
8106
- if (!model) return "";
8107
- if (typeof model === "string") return model;
8108
- return model.modelId ?? model.name ?? "";
10279
+ function finalizeLlm(span2, result) {
10280
+ const text = result?.text ?? result?.output_text ?? result?.content ?? extractOpenResponsesText(result) ?? result?.choices?.[0]?.message?.content ?? result?.message?.content;
10281
+ if (text) {
10282
+ span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
10283
+ span2.setAttribute("neatlogs.llm.output_messages.0.content", String(text));
10284
+ span2.setAttribute("output.value", String(text));
10285
+ }
10286
+ const toolCalls = result?.toolCalls ?? result?.tool_calls ?? result?.choices?.[0]?.message?.tool_calls ?? result?.message?.tool_calls;
10287
+ if (Array.isArray(toolCalls)) {
10288
+ toolCalls.forEach((tc, j) => {
10289
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.id`, tc?.id ?? "");
10290
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.name`, tc?.function?.name ?? tc?.name ?? "");
10291
+ const args = tc?.function?.arguments ?? tc?.arguments;
10292
+ span2.setAttribute(`neatlogs.llm.tool_calls.${j}.arguments`, typeof args === "string" ? args : safeStringify14(args ?? {}));
10293
+ });
10294
+ }
10295
+ const model = result?.model ?? result?.response?.model;
10296
+ if (model) span2.setAttribute("neatlogs.llm.model_name", String(model));
10297
+ const responseId = result?.id ?? result?.response?.id;
10298
+ if (responseId) span2.setAttribute("neatlogs.llm.response_id", String(responseId));
10299
+ const finishReason = result?.finishReason ?? result?.finish_reason ?? result?.choices?.[0]?.finish_reason;
10300
+ if (finishReason) span2.setAttribute("neatlogs.llm.finish_reason", String(finishReason));
10301
+ setOpenResponsesUsage(span2, result);
10302
+ span2.setStatus({ code: import_api19.SpanStatusCode.OK });
10303
+ span2.end();
8109
10304
  }
8110
- function toInputValue(input) {
8111
- return (typeof input === "string" ? input : safeStringify7(input)).slice(0, 1e4);
10305
+ function extractOpenResponsesText(result) {
10306
+ const output = result?.output;
10307
+ if (!Array.isArray(output)) return void 0;
10308
+ const parts = [];
10309
+ for (const item of output) {
10310
+ if (item?.type === "message" && Array.isArray(item.content)) {
10311
+ for (const c of item.content) {
10312
+ if ((c?.type === "output_text" || c?.type === "text") && typeof c.text === "string") parts.push(c.text);
10313
+ }
10314
+ }
10315
+ }
10316
+ return parts.length ? parts.join("") : void 0;
8112
10317
  }
8113
- function safeStringify7(value) {
10318
+ function safeStringify14(value) {
8114
10319
  if (typeof value === "string") return value;
8115
10320
  try {
8116
10321
  return JSON.stringify(value) ?? "";
@@ -8118,12 +10323,219 @@ function safeStringify7(value) {
8118
10323
  return "";
8119
10324
  }
8120
10325
  }
8121
- function recordError3(span2, err) {
10326
+ function recordError8(span2, err) {
8122
10327
  if (err instanceof Error) {
8123
- span2.setStatus({ code: import_api13.SpanStatusCode.ERROR, message: err.message });
10328
+ span2.setStatus({ code: import_api19.SpanStatusCode.ERROR, message: err.message });
8124
10329
  span2.recordException(err);
8125
10330
  } else {
8126
- span2.setStatus({ code: import_api13.SpanStatusCode.ERROR, message: String(err) });
10331
+ span2.setStatus({ code: import_api19.SpanStatusCode.ERROR, message: String(err) });
10332
+ }
10333
+ span2.end();
10334
+ }
10335
+
10336
+ // src/opencode-plugin.ts
10337
+ var import_api20 = require("@opentelemetry/api");
10338
+ var TRACER_NAME14 = "neatlogs.opencode";
10339
+ var _initialized2 = false;
10340
+ async function ensureInitialized() {
10341
+ if (_initialized2) return;
10342
+ _initialized2 = true;
10343
+ try {
10344
+ await init({
10345
+ apiKey: process.env.NEATLOGS_API_KEY,
10346
+ // The plugin bootstraps itself inside opencode's process — there is no user
10347
+ // init() to pass an endpoint, so honor NEATLOGS_ENDPOINT from the env (e.g.
10348
+ // a local backend). init() otherwise defaults to the hosted cloud.
10349
+ ...process.env.NEATLOGS_ENDPOINT ? { endpoint: process.env.NEATLOGS_ENDPOINT } : {},
10350
+ workflowName: process.env.NEATLOGS_WORKFLOW_NAME || "opencode",
10351
+ // opencode is long-running and event-driven; keep auto session off so each
10352
+ // span's conversation id is the opencode session id we set explicitly.
10353
+ autoSession: false
10354
+ });
10355
+ } catch {
10356
+ }
10357
+ }
10358
+ var NeatlogsOpencodePlugin = async (_ctx) => {
10359
+ await ensureInitialized();
10360
+ const sessions = /* @__PURE__ */ new Map();
10361
+ const tracer = import_api20.trace.getTracer(TRACER_NAME14);
10362
+ const captureSystemPrompt = String(process.env.NEATLOGS_CAPTURE_SYSTEM_PROMPT || "").toLowerCase() === "true";
10363
+ function stateFor(sessionID) {
10364
+ let s = sessions.get(sessionID);
10365
+ if (!s) {
10366
+ s = { toolSpans: /* @__PURE__ */ new Map(), messageText: /* @__PURE__ */ new Map(), emitted: /* @__PURE__ */ new Set(), lastUserText: "" };
10367
+ sessions.set(sessionID, s);
10368
+ }
10369
+ return s;
10370
+ }
10371
+ return {
10372
+ /**
10373
+ * Global event bus. opencode emits message + session lifecycle events here.
10374
+ * We use it to emit an LLM span when an assistant message completes, and to
10375
+ * track user-message text + assistant text from part updates.
10376
+ */
10377
+ event: async ({ event }) => {
10378
+ try {
10379
+ await handleEvent2(tracer, sessions, stateFor, captureSystemPrompt, event);
10380
+ } catch {
10381
+ }
10382
+ },
10383
+ /** Fired before a tool runs: open a TOOL span keyed by callID. */
10384
+ "tool.execute.before": async (input, output) => {
10385
+ try {
10386
+ const sessionID = input?.sessionID ?? "";
10387
+ const callID = input?.callID ?? input?.tool ?? "";
10388
+ const st = stateFor(sessionID);
10389
+ const span2 = tracer.startSpan(
10390
+ `opencode.tool.${input?.tool ?? "tool"}`,
10391
+ {
10392
+ attributes: {
10393
+ "neatlogs.span.kind": "TOOL",
10394
+ "neatlogs.tool.name": String(input?.tool ?? ""),
10395
+ ...sessionID ? { "neatlogs.conversation.id": String(sessionID) } : {},
10396
+ ...output?.args !== void 0 ? { "input.value": safeStringify15(output.args) } : {}
10397
+ }
10398
+ },
10399
+ import_api20.context.active()
10400
+ );
10401
+ if (callID) st.toolSpans.set(String(callID), span2);
10402
+ } catch {
10403
+ }
10404
+ },
10405
+ /** Fired after a tool runs: close the matching TOOL span. */
10406
+ "tool.execute.after": async (input, output) => {
10407
+ try {
10408
+ const sessionID = input?.sessionID ?? "";
10409
+ const callID = String(input?.callID ?? input?.tool ?? "");
10410
+ const st = stateFor(sessionID);
10411
+ const span2 = st.toolSpans.get(callID);
10412
+ if (!span2) return;
10413
+ if (output?.title) span2.setAttribute("neatlogs.tool.title", String(output.title));
10414
+ const out = output?.output ?? output?.result;
10415
+ if (out !== void 0) {
10416
+ span2.setAttribute("output.value", typeof out === "string" ? out : safeStringify15(out));
10417
+ }
10418
+ if (output?.metadata !== void 0) {
10419
+ span2.setAttribute("neatlogs.tool.metadata", safeStringify15(output.metadata));
10420
+ }
10421
+ span2.setStatus({ code: import_api20.SpanStatusCode.OK });
10422
+ span2.end();
10423
+ st.toolSpans.delete(callID);
10424
+ } catch {
10425
+ }
10426
+ }
10427
+ };
10428
+ };
10429
+ function handleEvent2(tracer, sessions, stateFor, captureSystemPrompt, event) {
10430
+ const type = event?.type;
10431
+ const props = event?.properties ?? {};
10432
+ if (type === "message.part.updated" || type === "message.part.completed") {
10433
+ const part = props.part ?? props;
10434
+ const messageID = part?.messageID ?? part?.message_id;
10435
+ const sessionID = part?.sessionID ?? props.sessionID;
10436
+ if (part?.type === "text" && typeof part?.text === "string" && messageID && sessionID) {
10437
+ const st = stateFor(String(sessionID));
10438
+ st.messageText.set(String(messageID), part.text);
10439
+ }
10440
+ return;
10441
+ }
10442
+ if (type === "message.updated" || type === "message.completed") {
10443
+ const info = props.info ?? props.message ?? props;
10444
+ const sessionID = info?.sessionID ?? info?.session_id;
10445
+ if (!sessionID) return;
10446
+ const st = stateFor(String(sessionID));
10447
+ if (info?.role === "user") {
10448
+ const text = messageText2(info) || st.messageText.get(String(info?.id)) || "";
10449
+ if (text) st.lastUserText = text;
10450
+ return;
10451
+ }
10452
+ if (info?.role === "assistant") {
10453
+ const completed = info?.time?.completed ?? info?.completed;
10454
+ const id = String(info?.id ?? "");
10455
+ if (!completed || st.emitted.has(id)) return;
10456
+ st.emitted.add(id);
10457
+ emitLlmSpan2(tracer, st, captureSystemPrompt, info, String(sessionID));
10458
+ }
10459
+ return;
10460
+ }
10461
+ if (type === "session.idle" || type === "session.deleted") {
10462
+ const sessionID = props.sessionID ?? props.info?.id;
10463
+ if (!sessionID) return void 0;
10464
+ const st = sessions.get(String(sessionID));
10465
+ if (!st) return void 0;
10466
+ for (const ts of st.toolSpans.values()) {
10467
+ try {
10468
+ ts.end();
10469
+ } catch {
10470
+ }
10471
+ }
10472
+ st.toolSpans.clear();
10473
+ if (type === "session.deleted") sessions.delete(String(sessionID));
10474
+ return flush().catch(() => false);
10475
+ }
10476
+ return void 0;
10477
+ }
10478
+ function emitLlmSpan2(tracer, st, captureSystemPrompt, info, sessionID) {
10479
+ const model = info?.modelID ?? info?.model ?? "";
10480
+ const provider = info?.providerID ?? info?.provider ?? "";
10481
+ const attrs = {
10482
+ "neatlogs.span.kind": "LLM",
10483
+ "neatlogs.conversation.id": sessionID
10484
+ };
10485
+ if (model) attrs["neatlogs.llm.model_name"] = String(model);
10486
+ if (provider) attrs["neatlogs.llm.provider"] = String(provider);
10487
+ if (captureSystemPrompt && info?.system) {
10488
+ const sys = Array.isArray(info.system) ? info.system.join("\n") : String(info.system);
10489
+ attrs["neatlogs.llm.input_messages.0.role"] = "system";
10490
+ attrs["neatlogs.llm.input_messages.0.content"] = sys;
10491
+ }
10492
+ let inIdx = captureSystemPrompt && info?.system ? 1 : 0;
10493
+ if (st.lastUserText) {
10494
+ attrs[`neatlogs.llm.input_messages.${inIdx}.role`] = "user";
10495
+ attrs[`neatlogs.llm.input_messages.${inIdx}.content`] = st.lastUserText;
10496
+ inIdx++;
10497
+ }
10498
+ const outText = messageText2(info) || st.messageText.get(String(info?.id)) || "";
10499
+ if (outText) {
10500
+ attrs["neatlogs.llm.output_messages.0.role"] = "assistant";
10501
+ attrs["neatlogs.llm.output_messages.0.content"] = outText;
10502
+ }
10503
+ const tokens = info?.tokens;
10504
+ if (tokens) {
10505
+ if (tokens.input != null) attrs["neatlogs.llm.token_count.prompt"] = tokens.input;
10506
+ if (tokens.output != null) attrs["neatlogs.llm.token_count.completion"] = tokens.output;
10507
+ if (tokens.input != null && tokens.output != null) {
10508
+ attrs["neatlogs.llm.token_count.total"] = tokens.input + tokens.output;
10509
+ }
10510
+ if (tokens.reasoning != null) attrs["neatlogs.llm.token_count.reasoning"] = tokens.reasoning;
10511
+ if (tokens.cache?.read != null) attrs["neatlogs.llm.token_count.cache_read"] = tokens.cache.read;
10512
+ if (tokens.cache?.write != null) attrs["neatlogs.llm.token_count.cache_write"] = tokens.cache.write;
10513
+ }
10514
+ if (info?.cost != null) attrs["neatlogs.llm.cost_usd"] = info.cost;
10515
+ const span2 = tracer.startSpan(`opencode.llm.${model || "model"}`, { attributes: attrs }, import_api20.context.active());
10516
+ span2.setStatus({ code: import_api20.SpanStatusCode.OK });
10517
+ span2.end();
10518
+ if (info?.id) st.messageText.delete(String(info.id));
10519
+ }
10520
+ function messageText2(info) {
10521
+ if (!info) return "";
10522
+ if (typeof info.text === "string") return info.text;
10523
+ const parts = info.parts ?? info.content;
10524
+ if (typeof parts === "string") return parts;
10525
+ if (!Array.isArray(parts)) return "";
10526
+ const out = [];
10527
+ for (const p of parts) {
10528
+ if (typeof p === "string") out.push(p);
10529
+ else if (p && typeof p === "object" && typeof p.text === "string") out.push(p.text);
10530
+ }
10531
+ return out.join("");
10532
+ }
10533
+ function safeStringify15(value) {
10534
+ if (typeof value === "string") return value;
10535
+ try {
10536
+ return JSON.stringify(value) ?? "";
10537
+ } catch {
10538
+ return "";
8127
10539
  }
8128
10540
  }
8129
10541
 
@@ -8178,6 +10590,7 @@ function bindTemplates(llm, systemTpl, userTpl, compiledVars) {
8178
10590
  }
8179
10591
  // Annotate the CommonJS export names for ESM import in node:
8180
10592
  0 && (module.exports = {
10593
+ NeatlogsOpencodePlugin,
8181
10594
  PromptApiError,
8182
10595
  PromptClient,
8183
10596
  PromptClientError,
@@ -8202,6 +10615,7 @@ function bindTemplates(llm, systemTpl, userTpl, compiledVars) {
8202
10615
  listPrompts,
8203
10616
  log,
8204
10617
  openaiAgentsProcessor,
10618
+ piAgentHooks,
8205
10619
  registerCrewaiTask,
8206
10620
  removeTag,
8207
10621
  saveAsVersion,
@@ -8210,11 +10624,21 @@ function bindTemplates(llm, systemTpl, userTpl, compiledVars) {
8210
10624
  strandsHooks,
8211
10625
  trace,
8212
10626
  traceToolAnthropic,
10627
+ traceToolAzureOpenAI,
10628
+ traceToolBedrock,
8213
10629
  traceToolOpenAI,
10630
+ traceToolVertexAI,
8214
10631
  updatePrompt,
8215
10632
  wrapAISDK,
8216
10633
  wrapAnthropic,
10634
+ wrapAzureOpenAI,
10635
+ wrapBedrock,
10636
+ wrapCallModel,
10637
+ wrapClaudeAgentSDK,
8217
10638
  wrapMastra,
8218
- wrapOpenAI
10639
+ wrapOpenAI,
10640
+ wrapOpenRouterAgent,
10641
+ wrapVertexAI,
10642
+ wrapVertexAIChat
8219
10643
  });
8220
10644
  //# sourceMappingURL=index.cjs.map