neatlogs 1.0.6 → 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.
- package/dist/azure-openai.cjs +344 -0
- package/dist/azure-openai.cjs.map +1 -0
- package/dist/azure-openai.d.ts +30 -0
- package/dist/azure-openai.mjs +318 -0
- package/dist/azure-openai.mjs.map +1 -0
- package/dist/bedrock.cjs +540 -0
- package/dist/bedrock.cjs.map +1 -0
- package/dist/bedrock.d.ts +29 -0
- package/dist/bedrock.mjs +514 -0
- package/dist/bedrock.mjs.map +1 -0
- package/dist/browser.cjs +121 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.ts +143 -0
- package/dist/browser.mjs +96 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/claude-agent-sdk.cjs +406 -0
- package/dist/claude-agent-sdk.cjs.map +1 -0
- package/dist/claude-agent-sdk.d.ts +49 -0
- package/dist/claude-agent-sdk.mjs +381 -0
- package/dist/claude-agent-sdk.mjs.map +1 -0
- package/dist/index.cjs +3219 -1129
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.mjs +3210 -1131
- package/dist/index.mjs.map +1 -1
- package/dist/langchain.cjs +9 -9
- package/dist/langchain.cjs.map +1 -1
- package/dist/langchain.mjs +9 -9
- package/dist/langchain.mjs.map +1 -1
- package/dist/mastra-wrap.cjs +25 -25
- package/dist/mastra-wrap.cjs.map +1 -1
- package/dist/mastra-wrap.mjs +25 -25
- package/dist/mastra-wrap.mjs.map +1 -1
- package/dist/openai-agents.cjs +6 -6
- package/dist/openai-agents.cjs.map +1 -1
- package/dist/openai-agents.mjs +6 -6
- package/dist/openai-agents.mjs.map +1 -1
- package/dist/opencode-plugin.cjs +5879 -0
- package/dist/opencode-plugin.cjs.map +1 -0
- package/dist/opencode-plugin.d.ts +38 -0
- package/dist/opencode-plugin.mjs +5854 -0
- package/dist/opencode-plugin.mjs.map +1 -0
- package/dist/openrouter-agent.cjs +273 -0
- package/dist/openrouter-agent.cjs.map +1 -0
- package/dist/openrouter-agent.d.ts +34 -0
- package/dist/openrouter-agent.mjs +247 -0
- package/dist/openrouter-agent.mjs.map +1 -0
- package/dist/pi-agent.cjs +10 -10
- package/dist/pi-agent.cjs.map +1 -1
- package/dist/pi-agent.mjs +10 -10
- package/dist/pi-agent.mjs.map +1 -1
- package/dist/vertex-ai.cjs +424 -0
- package/dist/vertex-ai.cjs.map +1 -0
- package/dist/vertex-ai.d.ts +39 -0
- package/dist/vertex-ai.mjs +397 -0
- package/dist/vertex-ai.mjs.map +1 -0
- package/package.json +76 -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,
|
|
@@ -63,12 +64,22 @@ __export(index_exports, {
|
|
|
63
64
|
strandsHooks: () => strandsHooks,
|
|
64
65
|
trace: () => trace2,
|
|
65
66
|
traceToolAnthropic: () => traceTool2,
|
|
67
|
+
traceToolAzureOpenAI: () => traceTool3,
|
|
68
|
+
traceToolBedrock: () => traceTool5,
|
|
66
69
|
traceToolOpenAI: () => traceTool,
|
|
70
|
+
traceToolVertexAI: () => traceTool4,
|
|
67
71
|
updatePrompt: () => updatePrompt,
|
|
68
72
|
wrapAISDK: () => wrapAISDK,
|
|
69
73
|
wrapAnthropic: () => wrapAnthropic,
|
|
74
|
+
wrapAzureOpenAI: () => wrapAzureOpenAI,
|
|
75
|
+
wrapBedrock: () => wrapBedrock,
|
|
76
|
+
wrapCallModel: () => wrapCallModel,
|
|
77
|
+
wrapClaudeAgentSDK: () => wrapClaudeAgentSDK,
|
|
70
78
|
wrapMastra: () => wrapMastra,
|
|
71
|
-
wrapOpenAI: () => wrapOpenAI
|
|
79
|
+
wrapOpenAI: () => wrapOpenAI,
|
|
80
|
+
wrapOpenRouterAgent: () => wrapOpenRouterAgent,
|
|
81
|
+
wrapVertexAI: () => wrapVertexAI,
|
|
82
|
+
wrapVertexAIChat: () => wrapVertexAIChat
|
|
72
83
|
});
|
|
73
84
|
module.exports = __toCommonJS(index_exports);
|
|
74
85
|
|
|
@@ -1440,7 +1451,7 @@ var UnifiedAttributeProcessor = class {
|
|
|
1440
1451
|
attrs["mcp.server.version"] = info.version ?? "";
|
|
1441
1452
|
}
|
|
1442
1453
|
if ("capabilities" in output) {
|
|
1443
|
-
attrs["mcp.server.capabilities"] = JSON.stringify(output.capabilities)
|
|
1454
|
+
attrs["mcp.server.capabilities"] = JSON.stringify(output.capabilities);
|
|
1444
1455
|
}
|
|
1445
1456
|
}
|
|
1446
1457
|
} catch {
|
|
@@ -2046,7 +2057,7 @@ var UnifiedAttributeProcessor = class {
|
|
|
2046
2057
|
if (typeof r !== "string" || r.toLowerCase() !== role) continue;
|
|
2047
2058
|
const c = unified[`${prefix}.${i}.content`];
|
|
2048
2059
|
if (typeof c === "string" && c.toLowerCase().includes("thought:")) {
|
|
2049
|
-
texts.push(c
|
|
2060
|
+
texts.push(c);
|
|
2050
2061
|
}
|
|
2051
2062
|
}
|
|
2052
2063
|
return texts;
|
|
@@ -4970,6 +4981,7 @@ var INSTRUMENTATION_REGISTRY = {
|
|
|
4970
4981
|
tags: {
|
|
4971
4982
|
llm: [
|
|
4972
4983
|
"azure_ai_inference",
|
|
4984
|
+
"azure_openai",
|
|
4973
4985
|
"openai",
|
|
4974
4986
|
"anthropic",
|
|
4975
4987
|
"cohere",
|
|
@@ -5018,7 +5030,10 @@ var INSTRUMENTATION_REGISTRY = {
|
|
|
5018
5030
|
"smolagents",
|
|
5019
5031
|
"strands",
|
|
5020
5032
|
"pipecat",
|
|
5021
|
-
"ai_sdk"
|
|
5033
|
+
"ai_sdk",
|
|
5034
|
+
"claude_agent_sdk",
|
|
5035
|
+
"openrouter_agent",
|
|
5036
|
+
"opencode"
|
|
5022
5037
|
],
|
|
5023
5038
|
tool: ["langchain", "llamaindex", "haystack", "mcp"],
|
|
5024
5039
|
http: ["requests", "httpx", "urllib3", "aiohttp"],
|
|
@@ -5063,7 +5078,15 @@ var INSTRUMENTATION_REGISTRY = {
|
|
|
5063
5078
|
bedrock: {
|
|
5064
5079
|
openinference: "@arizeai/openinference-instrumentation-bedrock",
|
|
5065
5080
|
openllmetry: null,
|
|
5066
|
-
|
|
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",
|
|
5067
5090
|
default_span_kind: "LLM"
|
|
5068
5091
|
},
|
|
5069
5092
|
groq: {
|
|
@@ -5081,7 +5104,7 @@ var INSTRUMENTATION_REGISTRY = {
|
|
|
5081
5104
|
vertexai: {
|
|
5082
5105
|
openinference: null,
|
|
5083
5106
|
openllmetry: null,
|
|
5084
|
-
neatlogs:
|
|
5107
|
+
neatlogs: "neatlogs/vertex-ai",
|
|
5085
5108
|
default_span_kind: "LLM"
|
|
5086
5109
|
},
|
|
5087
5110
|
google_generativeai: {
|
|
@@ -5354,7 +5377,20 @@ var INSTRUMENTATION_REGISTRY = {
|
|
|
5354
5377
|
claude_agent_sdk: {
|
|
5355
5378
|
openinference: "@arizeai/openinference-instrumentation-claude-agent-sdk",
|
|
5356
5379
|
openllmetry: null,
|
|
5357
|
-
|
|
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",
|
|
5358
5394
|
default_span_kind: "AGENT"
|
|
5359
5395
|
}
|
|
5360
5396
|
}
|
|
@@ -5863,7 +5899,7 @@ async function removeTag(name, tag) {
|
|
|
5863
5899
|
}
|
|
5864
5900
|
|
|
5865
5901
|
// src/version.ts
|
|
5866
|
-
var __version__ = "1.0.
|
|
5902
|
+
var __version__ = "1.0.8";
|
|
5867
5903
|
|
|
5868
5904
|
// src/init.ts
|
|
5869
5905
|
var logger13 = getLogger();
|
|
@@ -7150,238 +7186,302 @@ function recordError2(span2, err) {
|
|
|
7150
7186
|
span2.end();
|
|
7151
7187
|
}
|
|
7152
7188
|
|
|
7153
|
-
// src/
|
|
7189
|
+
// src/azure-openai.ts
|
|
7154
7190
|
var import_api11 = require("@opentelemetry/api");
|
|
7155
|
-
var TRACER_NAME5 = "neatlogs.
|
|
7156
|
-
|
|
7157
|
-
|
|
7191
|
+
var TRACER_NAME5 = "neatlogs.azure_openai";
|
|
7192
|
+
var PROVIDER = "azure";
|
|
7193
|
+
var SYSTEM = "azure";
|
|
7194
|
+
function wrapAzureOpenAI(client) {
|
|
7195
|
+
return wrapNamespace3(client, []);
|
|
7158
7196
|
}
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
_spans = /* @__PURE__ */ new Map();
|
|
7162
|
-
_workflowName;
|
|
7163
|
-
constructor(opts) {
|
|
7164
|
-
this._workflowName = opts?.workflowName;
|
|
7165
|
-
}
|
|
7166
|
-
// --- Chain/Graph callbacks ---
|
|
7167
|
-
async handleChainStart(serialized, inputs, runId, parentRunId, tags, metadata) {
|
|
7168
|
-
const tracer = import_api11.trace.getTracer(TRACER_NAME5);
|
|
7169
|
-
const name = serialized?.name ?? serialized?.id?.at(-1) ?? "chain";
|
|
7170
|
-
const parentSpan = parentRunId ? this._spans.get(parentRunId) : void 0;
|
|
7171
|
-
const parentCtx = parentSpan ? import_api11.trace.setSpan(import_api11.context.active(), parentSpan) : import_api11.context.active();
|
|
7172
|
-
const attrs = {
|
|
7173
|
-
"neatlogs.span.kind": "CHAIN",
|
|
7174
|
-
"neatlogs.chain.name": name
|
|
7175
|
-
};
|
|
7176
|
-
if (this._workflowName) attrs["neatlogs.workflow.name"] = this._workflowName;
|
|
7177
|
-
if (inputs) attrs["input.value"] = safeStringify5(inputs).slice(0, 1e4);
|
|
7178
|
-
if (tags?.length) attrs["neatlogs.tags"] = tags.join(",");
|
|
7179
|
-
const span2 = tracer.startSpan(`langchain.chain.${name}`, { attributes: attrs }, parentCtx);
|
|
7180
|
-
this._spans.set(runId, span2);
|
|
7181
|
-
}
|
|
7182
|
-
async handleChainEnd(outputs, runId) {
|
|
7183
|
-
const span2 = this._spans.get(runId);
|
|
7184
|
-
if (!span2) return;
|
|
7185
|
-
if (outputs) span2.setAttribute("output.value", safeStringify5(outputs).slice(0, 1e4));
|
|
7186
|
-
span2.setStatus({ code: import_api11.SpanStatusCode.OK });
|
|
7187
|
-
span2.end();
|
|
7188
|
-
this._spans.delete(runId);
|
|
7189
|
-
}
|
|
7190
|
-
async handleChainError(error, runId) {
|
|
7191
|
-
const span2 = this._spans.get(runId);
|
|
7192
|
-
if (!span2) return;
|
|
7193
|
-
span2.setStatus({ code: import_api11.SpanStatusCode.ERROR, message: error.message });
|
|
7194
|
-
span2.recordException(error);
|
|
7195
|
-
span2.end();
|
|
7196
|
-
this._spans.delete(runId);
|
|
7197
|
-
}
|
|
7198
|
-
// --- LLM callbacks ---
|
|
7199
|
-
async handleLLMStart(serialized, prompts, runId, parentRunId, extraParams) {
|
|
7197
|
+
function traceTool3(name, fn) {
|
|
7198
|
+
return async function tracedTool(args) {
|
|
7200
7199
|
const tracer = import_api11.trace.getTracer(TRACER_NAME5);
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
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;
|
|
7218
7243
|
}
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
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) {
|
|
7223
7253
|
const tracer = import_api11.trace.getTracer(TRACER_NAME5);
|
|
7224
|
-
const model =
|
|
7225
|
-
const
|
|
7226
|
-
const
|
|
7227
|
-
const
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
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
|
+
}
|
|
7239
7277
|
}
|
|
7240
|
-
if (
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
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
|
+
}
|
|
7245
7285
|
}
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
const generations = output?.generations ?? [];
|
|
7253
|
-
for (let i = 0; i < generations.length; i++) {
|
|
7254
|
-
const gen = generations[i];
|
|
7255
|
-
if (!Array.isArray(gen)) continue;
|
|
7256
|
-
for (let j = 0; j < gen.length; j++) {
|
|
7257
|
-
const msg = gen[j]?.message ?? gen[j];
|
|
7258
|
-
const content = msg?.content ?? msg?.text ?? "";
|
|
7259
|
-
span2.setAttribute(`neatlogs.llm.output_messages.${i}.role`, "assistant");
|
|
7260
|
-
span2.setAttribute(`neatlogs.llm.output_messages.${i}.content`, String(content).slice(0, 1e4));
|
|
7261
|
-
const toolCalls = msg?.tool_calls ?? msg?.additional_kwargs?.tool_calls;
|
|
7262
|
-
if (toolCalls && Array.isArray(toolCalls)) {
|
|
7263
|
-
for (let k = 0; k < toolCalls.length; k++) {
|
|
7264
|
-
const tc = toolCalls[k];
|
|
7265
|
-
span2.setAttribute(`neatlogs.llm.tool_calls.${k}.id`, tc.id ?? "");
|
|
7266
|
-
span2.setAttribute(`neatlogs.llm.tool_calls.${k}.name`, tc.name ?? tc.function?.name ?? "");
|
|
7267
|
-
span2.setAttribute(`neatlogs.llm.tool_calls.${k}.arguments`, tc.args ? safeStringify5(tc.args) : tc.function?.arguments ?? "");
|
|
7268
|
-
}
|
|
7269
|
-
}
|
|
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 };
|
|
7270
7292
|
}
|
|
7271
7293
|
}
|
|
7272
|
-
const
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
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;
|
|
7276
7307
|
}
|
|
7277
|
-
|
|
7278
|
-
|
|
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 ?? "")
|
|
7279
7322
|
}
|
|
7280
|
-
|
|
7281
|
-
|
|
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;
|
|
7282
7344
|
}
|
|
7283
|
-
|
|
7345
|
+
);
|
|
7346
|
+
};
|
|
7347
|
+
}
|
|
7348
|
+
function wrapAsyncIterableStream2(stream, span2) {
|
|
7349
|
+
const chunks = [];
|
|
7350
|
+
const originalAsyncIterator = stream?.[Symbol.asyncIterator]?.bind(stream);
|
|
7351
|
+
if (!originalAsyncIterator) {
|
|
7284
7352
|
span2.setStatus({ code: import_api11.SpanStatusCode.OK });
|
|
7285
7353
|
span2.end();
|
|
7286
|
-
|
|
7287
|
-
}
|
|
7288
|
-
async handleLLMNewToken(_token, _idx, _runId) {
|
|
7289
|
-
}
|
|
7290
|
-
async handleLLMError(error, runId) {
|
|
7291
|
-
const span2 = this._spans.get(runId);
|
|
7292
|
-
if (!span2) return;
|
|
7293
|
-
span2.setStatus({ code: import_api11.SpanStatusCode.ERROR, message: error.message });
|
|
7294
|
-
span2.recordException(error);
|
|
7295
|
-
span2.end();
|
|
7296
|
-
this._spans.delete(runId);
|
|
7354
|
+
return stream;
|
|
7297
7355
|
}
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
const
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
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;
|
|
7312
7412
|
}
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
span2.setAttribute("
|
|
7317
|
-
span2.setStatus({ code: import_api11.SpanStatusCode.OK });
|
|
7318
|
-
span2.end();
|
|
7319
|
-
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);
|
|
7320
7417
|
}
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
span2.
|
|
7325
|
-
span2.
|
|
7326
|
-
|
|
7327
|
-
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++;
|
|
7328
7424
|
}
|
|
7329
|
-
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
"neatlogs.
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
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
|
+
}
|
|
7342
7437
|
}
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
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 ?? "");
|
|
7353
7456
|
}
|
|
7354
7457
|
}
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7458
|
+
if (choices[i].finish_reason) {
|
|
7459
|
+
span2.setAttribute("neatlogs.llm.finish_reason", choices[i].finish_reason);
|
|
7460
|
+
}
|
|
7358
7461
|
}
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
if (
|
|
7362
|
-
|
|
7363
|
-
span2.
|
|
7364
|
-
|
|
7365
|
-
|
|
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
|
+
}
|
|
7366
7473
|
}
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
if (m.includes("gpt") || m.includes("o1") || m.includes("o3") || m.includes("o4")) return "openai";
|
|
7371
|
-
if (m.includes("claude")) return "anthropic";
|
|
7372
|
-
if (m.includes("gemini")) return "google";
|
|
7373
|
-
if (m.includes("command")) return "cohere";
|
|
7374
|
-
if (m.includes("llama") || m.includes("mixtral")) return "meta";
|
|
7375
|
-
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();
|
|
7376
7477
|
}
|
|
7377
|
-
function
|
|
7378
|
-
|
|
7379
|
-
if (
|
|
7380
|
-
if (
|
|
7381
|
-
if (
|
|
7382
|
-
if (
|
|
7383
|
-
if (
|
|
7384
|
-
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));
|
|
7385
7485
|
}
|
|
7386
7486
|
function safeStringify5(value) {
|
|
7387
7487
|
try {
|
|
@@ -7390,325 +7490,901 @@ function safeStringify5(value) {
|
|
|
7390
7490
|
return "";
|
|
7391
7491
|
}
|
|
7392
7492
|
}
|
|
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) });
|
|
7499
|
+
}
|
|
7500
|
+
span2.end();
|
|
7501
|
+
}
|
|
7393
7502
|
|
|
7394
|
-
// src/
|
|
7395
|
-
var
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7503
|
+
// src/vertex-ai.ts
|
|
7504
|
+
var import_api12 = require("@opentelemetry/api");
|
|
7505
|
+
var TRACER_NAME6 = "neatlogs.vertex_ai";
|
|
7506
|
+
var PROVIDER2 = "vertex_ai";
|
|
7507
|
+
var SYSTEM2 = "vertexai";
|
|
7508
|
+
function wrapVertexAI(client) {
|
|
7509
|
+
return wrapNamespace4(client, []);
|
|
7510
|
+
}
|
|
7511
|
+
function traceTool4(name, fn) {
|
|
7512
|
+
return async function tracedTool(args) {
|
|
7513
|
+
const tracer = import_api12.trace.getTracer(TRACER_NAME6);
|
|
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;
|
|
7407
7563
|
}
|
|
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);
|
|
7408
7576
|
}
|
|
7409
|
-
|
|
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;
|
|
7410
7587
|
}
|
|
7411
|
-
function
|
|
7412
|
-
const tracer =
|
|
7413
|
-
const
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
}
|
|
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;
|
|
7422
7617
|
}
|
|
7423
|
-
|
|
7424
|
-
}
|
|
7425
|
-
patchedAddEvent[PATCH_FLAG] = true;
|
|
7426
|
-
proto._addEvent = patchedAddEvent;
|
|
7618
|
+
);
|
|
7427
7619
|
}
|
|
7428
|
-
function
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
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;
|
|
7648
|
+
}
|
|
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: {
|
|
7657
|
+
"neatlogs.span.kind": "LLM",
|
|
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;
|
|
7675
|
+
}
|
|
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
|
|
7690
|
+
}
|
|
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);
|
|
7699
|
+
}
|
|
7700
|
+
finalizeResponse(span2, response);
|
|
7701
|
+
return response;
|
|
7702
|
+
},
|
|
7703
|
+
(err) => {
|
|
7704
|
+
recordError4(span2, err);
|
|
7705
|
+
throw err;
|
|
7706
|
+
}
|
|
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);
|
|
7740
|
+
}
|
|
7741
|
+
span2.setAttribute(
|
|
7742
|
+
`neatlogs.llm.input_messages.${idx}.content`,
|
|
7743
|
+
textParts.length ? textParts.join("\n") : safeStringify6(parts)
|
|
7744
|
+
);
|
|
7745
|
+
idx++;
|
|
7441
7746
|
}
|
|
7442
7747
|
}
|
|
7443
|
-
|
|
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));
|
|
7444
7751
|
}
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
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++;
|
|
7762
|
+
}
|
|
7763
|
+
}
|
|
7449
7764
|
}
|
|
7450
|
-
if (
|
|
7451
|
-
|
|
7452
|
-
if (
|
|
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));
|
|
7780
|
+
}
|
|
7453
7781
|
}
|
|
7454
7782
|
}
|
|
7455
|
-
function
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
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;
|
|
7831
|
+
}
|
|
7832
|
+
if (chunk?.usageMetadata) usage = chunk.usageMetadata;
|
|
7833
|
+
}
|
|
7834
|
+
const fullText = textParts.join("");
|
|
7835
|
+
if (fullText) {
|
|
7460
7836
|
span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
|
|
7461
|
-
span2.setAttribute("neatlogs.llm.output_messages.0.content",
|
|
7462
|
-
span2.setAttribute("neatlogs.llm.output", safeStringify6({ role: "assistant", content: out }));
|
|
7837
|
+
span2.setAttribute("neatlogs.llm.output_messages.0.content", fullText);
|
|
7463
7838
|
}
|
|
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();
|
|
7464
7843
|
}
|
|
7465
|
-
function
|
|
7466
|
-
const
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
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();
|
|
7476
7869
|
}
|
|
7477
|
-
function
|
|
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
|
+
}
|
|
7878
|
+
function safeStringify6(value) {
|
|
7478
7879
|
try {
|
|
7479
|
-
|
|
7480
|
-
if (!a) return "";
|
|
7481
|
-
const v = typeof a.get === "function" ? a.get("gen_ai.operation.name") : a["gen_ai.operation.name"];
|
|
7482
|
-
return typeof v === "string" ? v.toLowerCase() : "";
|
|
7880
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
7483
7881
|
} catch {
|
|
7484
7882
|
return "";
|
|
7485
7883
|
}
|
|
7486
7884
|
}
|
|
7487
|
-
function
|
|
7488
|
-
if (
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
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) });
|
|
7891
|
+
}
|
|
7892
|
+
span2.end();
|
|
7893
|
+
}
|
|
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
|
+
};
|
|
7927
|
+
}
|
|
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);
|
|
7497
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;
|
|
7952
|
+
}
|
|
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);
|
|
7498
7957
|
}
|
|
7499
|
-
|
|
7958
|
+
const vendor = tail.includes(".") ? tail.split(".")[0] : "";
|
|
7959
|
+
return vendor || "bedrock";
|
|
7500
7960
|
}
|
|
7501
|
-
function
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
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;
|
|
7508
7992
|
}
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7993
|
+
);
|
|
7994
|
+
}
|
|
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++;
|
|
7512
8003
|
}
|
|
7513
|
-
const o = item;
|
|
7514
|
-
if (typeof o.text === "string") out.push(o.text);
|
|
7515
|
-
else if (typeof o.content === "string") out.push(o.content);
|
|
7516
|
-
else if (o.toolUse) out.push(`${o.toolUse.name ?? "tool"}(${safeStringify6(o.toolUse.input ?? {})})`);
|
|
7517
|
-
else if (o.toolResult) out.push(flattenBlocks(o.toolResult.content ?? o.toolResult));
|
|
7518
|
-
else if (Array.isArray(o.parts)) out.push(flattenBlocks(o.parts));
|
|
7519
|
-
else if (Array.isArray(o.content)) out.push(flattenBlocks(o.content));
|
|
7520
|
-
else out.push(safeStringify6(o));
|
|
7521
8004
|
}
|
|
7522
|
-
|
|
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
|
+
}
|
|
7523
8021
|
}
|
|
7524
|
-
function
|
|
7525
|
-
if (typeof
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
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
|
+
}
|
|
7530
8035
|
}
|
|
8036
|
+
return parts.join("\n");
|
|
7531
8037
|
}
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
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++;
|
|
8052
|
+
}
|
|
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();
|
|
7538
8062
|
}
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
const key = String(traceId ?? `trace_${Date.now()}`);
|
|
7552
|
-
this._spans.set(key, span2);
|
|
7553
|
-
this._startTimes.set(key, Date.now());
|
|
7554
|
-
}
|
|
7555
|
-
onTraceEnd(traceData) {
|
|
7556
|
-
const key = String(traceData?.traceId ?? traceData?.trace_id ?? "");
|
|
7557
|
-
const span2 = this._spans.get(key);
|
|
7558
|
-
if (!span2) return;
|
|
7559
|
-
const startTime = this._startTimes.get(key);
|
|
7560
|
-
if (startTime) {
|
|
7561
|
-
span2.setAttribute("neatlogs.metrics.duration_ms", Date.now() - startTime);
|
|
7562
|
-
}
|
|
7563
|
-
span2.setStatus({ code: import_api12.SpanStatusCode.OK });
|
|
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 });
|
|
7564
8075
|
span2.end();
|
|
7565
|
-
|
|
7566
|
-
this._startTimes.delete(key);
|
|
8076
|
+
return response;
|
|
7567
8077
|
}
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
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 };
|
|
7604
8120
|
}
|
|
7605
|
-
}
|
|
7606
|
-
otelSpan = tracer.startSpan("openai_agents.generation", { attributes: attrs }, parentCtx);
|
|
7607
|
-
} else if (spanType === "function" || spanType === "tool" || spanType === "tool_call") {
|
|
7608
|
-
const toolName = data?.name ?? data?.function_name ?? "tool";
|
|
7609
|
-
const attrs = {
|
|
7610
|
-
"neatlogs.span.kind": "TOOL",
|
|
7611
|
-
"neatlogs.tool.name": toolName
|
|
7612
8121
|
};
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
8122
|
+
}
|
|
8123
|
+
};
|
|
8124
|
+
response.stream = wrappedStream;
|
|
8125
|
+
return response;
|
|
8126
|
+
}
|
|
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 ?? "")
|
|
7616
8159
|
}
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
if (data?.to_agent) attrs["neatlogs.agent.name"] = String(data.to_agent);
|
|
7622
|
-
otelSpan = tracer.startSpan("openai_agents.handoff", { attributes: attrs }, parentCtx);
|
|
7623
|
-
} else {
|
|
7624
|
-
const attrs = { "neatlogs.span.kind": "CHAIN" };
|
|
7625
|
-
otelSpan = tracer.startSpan(`openai_agents.${spanType || "span"}`, { attributes: attrs }, parentCtx);
|
|
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));
|
|
7626
8164
|
}
|
|
7627
|
-
|
|
7628
|
-
|
|
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);
|
|
7629
8172
|
}
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
const startTime = this._startTimes.get(spanId);
|
|
7637
|
-
if (spanType === "response" || spanType === "generation" || spanType === "llm") {
|
|
7638
|
-
const resp = data?._response ?? data?.response ?? {};
|
|
7639
|
-
const model = data?.model ?? resp?.model;
|
|
7640
|
-
if (model) otelSpan.setAttribute("neatlogs.llm.model_name", model);
|
|
7641
|
-
const outputItems = data?.output ?? resp?.output;
|
|
7642
|
-
if (Array.isArray(outputItems)) {
|
|
7643
|
-
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("");
|
|
7644
|
-
if (text) {
|
|
7645
|
-
otelSpan.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
|
|
7646
|
-
otelSpan.setAttribute("neatlogs.llm.output_messages.0.content", text.slice(0, 1e4));
|
|
7647
|
-
}
|
|
7648
|
-
const toolCalls = outputItems.filter((o) => o?.type === "function_call");
|
|
7649
|
-
for (let i = 0; i < toolCalls.length; i++) {
|
|
7650
|
-
const tc = toolCalls[i];
|
|
7651
|
-
otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, tc.name ?? "");
|
|
7652
|
-
otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, typeof tc.arguments === "string" ? tc.arguments : safeStringify7(tc.arguments ?? {}));
|
|
7653
|
-
if (tc.callId ?? tc.id) otelSpan.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, tc.callId ?? tc.id);
|
|
7654
|
-
}
|
|
7655
|
-
} else if (outputItems?.content) {
|
|
7656
|
-
otelSpan.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
|
|
7657
|
-
const c = outputItems.content;
|
|
7658
|
-
otelSpan.setAttribute("neatlogs.llm.output_messages.0.content", (typeof c === "string" ? c : safeStringify7(c)).slice(0, 1e4));
|
|
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);
|
|
7659
8179
|
}
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
if (inputTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.prompt", inputTokens);
|
|
7666
|
-
if (outputTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.completion", outputTokens);
|
|
7667
|
-
if (totalTokens != null) otelSpan.setAttribute("neatlogs.llm.token_count.total", totalTokens);
|
|
7668
|
-
else if (inputTokens != null && outputTokens != null) {
|
|
7669
|
-
otelSpan.setAttribute("neatlogs.llm.token_count.total", inputTokens + outputTokens);
|
|
8180
|
+
try {
|
|
8181
|
+
if (isEmbedding) {
|
|
8182
|
+
finalizeInvokeEmbedding(span2, decodeBody(response?.body));
|
|
8183
|
+
} else {
|
|
8184
|
+
finalizeInvoke(span2, vendor, decodeBody(response?.body));
|
|
7670
8185
|
}
|
|
8186
|
+
} catch {
|
|
8187
|
+
span2.setStatus({ code: import_api13.SpanStatusCode.OK });
|
|
8188
|
+
span2.end();
|
|
7671
8189
|
}
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
} else if (spanType === "agent" || spanType === "agent_run") {
|
|
7678
|
-
const output = data?.output;
|
|
7679
|
-
if (output != null) {
|
|
7680
|
-
otelSpan.setAttribute("output.value", (typeof output === "string" ? output : safeStringify7(output)).slice(0, 1e4));
|
|
7681
|
-
}
|
|
7682
|
-
}
|
|
7683
|
-
const error = data?.error ?? span2?.error;
|
|
7684
|
-
if (error) {
|
|
7685
|
-
if (error instanceof Error) {
|
|
7686
|
-
otelSpan.setStatus({ code: import_api12.SpanStatusCode.ERROR, message: error.message });
|
|
7687
|
-
otelSpan.recordException(error);
|
|
7688
|
-
} else {
|
|
7689
|
-
otelSpan.setStatus({ code: import_api12.SpanStatusCode.ERROR, message: String(error) });
|
|
7690
|
-
}
|
|
7691
|
-
} else {
|
|
7692
|
-
otelSpan.setStatus({ code: import_api12.SpanStatusCode.OK });
|
|
8190
|
+
return response;
|
|
8191
|
+
},
|
|
8192
|
+
(err) => {
|
|
8193
|
+
recordError5(span2, err);
|
|
8194
|
+
throw err;
|
|
7693
8195
|
}
|
|
7694
|
-
|
|
7695
|
-
|
|
8196
|
+
);
|
|
8197
|
+
}
|
|
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));
|
|
7696
8222
|
}
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
this._startTimes.delete(spanId);
|
|
8223
|
+
if (typeof body === "object") return body;
|
|
8224
|
+
} catch {
|
|
7700
8225
|
}
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
8226
|
+
return {};
|
|
8227
|
+
}
|
|
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;
|
|
7705
8306
|
}
|
|
7706
|
-
|
|
7707
|
-
|
|
8307
|
+
} else {
|
|
8308
|
+
text = body?.generation ?? body?.completion ?? body?.outputText;
|
|
7708
8309
|
}
|
|
7709
|
-
|
|
8310
|
+
if (text) {
|
|
8311
|
+
span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
|
|
8312
|
+
span2.setAttribute("neatlogs.llm.output_messages.0.content", String(text));
|
|
7710
8313
|
}
|
|
7711
|
-
|
|
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
|
+
}
|
|
7712
8388
|
function safeStringify7(value) {
|
|
7713
8389
|
try {
|
|
7714
8390
|
return typeof value === "string" ? value : JSON.stringify(value);
|
|
@@ -7716,525 +8392,1687 @@ function safeStringify7(value) {
|
|
|
7716
8392
|
return "";
|
|
7717
8393
|
}
|
|
7718
8394
|
}
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
if (!entity || entity[PATCH_FLAG2]) return entity;
|
|
7726
|
-
const e = entity;
|
|
7727
|
-
const className = entity.constructor?.name ?? "";
|
|
7728
|
-
if (isRootMastra(e)) {
|
|
7729
|
-
const proxied = wrapRootMastra(e);
|
|
7730
|
-
markPatched(proxied);
|
|
7731
|
-
return proxied;
|
|
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) });
|
|
7732
8401
|
}
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
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));
|
|
7743
9362
|
}
|
|
7744
|
-
|
|
7745
|
-
|
|
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);
|
|
7746
9373
|
}
|
|
7747
|
-
function
|
|
7748
|
-
|
|
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));
|
|
7749
9394
|
}
|
|
7750
|
-
function
|
|
7751
|
-
|
|
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));
|
|
7752
9399
|
}
|
|
7753
|
-
function
|
|
7754
|
-
|
|
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;
|
|
7755
9406
|
}
|
|
7756
|
-
function
|
|
7757
|
-
|
|
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
|
+
}
|
|
7758
9439
|
}
|
|
7759
|
-
function
|
|
7760
|
-
|
|
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);
|
|
7761
9444
|
}
|
|
7762
|
-
function
|
|
7763
|
-
|
|
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
|
+
}
|
|
7764
9456
|
}
|
|
7765
|
-
function
|
|
7766
|
-
|
|
7767
|
-
|
|
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
|
+
});
|
|
7768
9473
|
}
|
|
7769
|
-
function
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
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 {
|
|
7785
9520
|
}
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
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 });
|
|
7798
9549
|
}
|
|
9550
|
+
break;
|
|
7799
9551
|
}
|
|
7800
|
-
|
|
7801
|
-
const
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
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;
|
|
7818
9601
|
}
|
|
7819
|
-
|
|
7820
|
-
}
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
function patchModelInPlace(model) {
|
|
7824
|
-
if (!model || model.__neatlogs_model_patched) return;
|
|
7825
|
-
model.__neatlogs_model_patched = true;
|
|
7826
|
-
const modelId = model.modelId ?? model.modelName ?? "";
|
|
7827
|
-
const provider = model.provider ?? "";
|
|
7828
|
-
for (const fn of ["doGenerate", "doStream"]) {
|
|
7829
|
-
if (typeof model[fn] !== "function") continue;
|
|
7830
|
-
const orig = model[fn].bind(model);
|
|
7831
|
-
const isStream = fn === "doStream";
|
|
7832
|
-
model[fn] = function tracedModelCall(callOpts) {
|
|
7833
|
-
const attrs = { "neatlogs.span.kind": "LLM" };
|
|
7834
|
-
if (modelId) attrs["neatlogs.llm.model_name"] = modelId;
|
|
7835
|
-
if (provider) attrs["neatlogs.llm.provider"] = provider;
|
|
7836
|
-
if (isStream) attrs["neatlogs.llm.is_streaming"] = true;
|
|
7837
|
-
const promptInput = callOpts?.prompt ?? callOpts?.messages;
|
|
7838
|
-
if (promptInput !== void 0) attrs["input.value"] = safeStringify8(promptInput).slice(0, 1e4);
|
|
7839
|
-
captureInvocationParams(attrs, callOpts);
|
|
7840
|
-
return withActiveSpan(`mastra.llm.${modelId || "model"}.${fn}`, attrs, async (span2) => {
|
|
7841
|
-
const result = await orig(callOpts);
|
|
7842
|
-
if (!isStream) finalizeModelResult(span2, result);
|
|
7843
|
-
else if (result?.usage) recordUsage(span2, result.usage);
|
|
7844
|
-
return result;
|
|
7845
|
-
});
|
|
7846
|
-
};
|
|
9602
|
+
break;
|
|
9603
|
+
}
|
|
9604
|
+
default:
|
|
9605
|
+
break;
|
|
7847
9606
|
}
|
|
7848
9607
|
}
|
|
7849
|
-
function
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
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;
|
|
9618
|
+
});
|
|
9619
|
+
attrs["neatlogs.llm.input"] = safeStringify12({ messages: inMsgs });
|
|
9620
|
+
attrs["input.value"] = safeStringify12({ messages: inMsgs });
|
|
7856
9621
|
}
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
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 || "";
|
|
7861
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();
|
|
7862
9657
|
}
|
|
7863
|
-
function
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
span2.setAttribute("output.value", safeStringify8(result).slice(0, 1e4));
|
|
7878
|
-
return result;
|
|
7879
|
-
});
|
|
7880
|
-
};
|
|
7881
|
-
}
|
|
7882
|
-
function patchWorkflow(workflow) {
|
|
7883
|
-
if (typeof workflow.createRun !== "function") return;
|
|
7884
|
-
const origCreateRun = workflow.createRun.bind(workflow);
|
|
7885
|
-
const workflowName = workflow.name ?? workflow.id ?? "mastra_workflow";
|
|
7886
|
-
workflow.createRun = async function tracedCreateRun(...args) {
|
|
7887
|
-
const run = await origCreateRun(...args);
|
|
7888
|
-
if (!run) return run;
|
|
7889
|
-
patchRunMethod(run, "start", workflowName);
|
|
7890
|
-
patchRunMethod(run, "resume", workflowName);
|
|
7891
|
-
return run;
|
|
7892
|
-
};
|
|
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 };
|
|
7893
9672
|
}
|
|
7894
|
-
function
|
|
7895
|
-
if (
|
|
7896
|
-
const
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
if (
|
|
7903
|
-
|
|
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)})`);
|
|
7904
9684
|
}
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
if (result?.status) span2.setAttribute("neatlogs.metadata", safeStringify8({ status: result.status }));
|
|
7908
|
-
if (result?.result !== void 0) {
|
|
7909
|
-
span2.setAttribute("output.value", safeStringify8(result.result).slice(0, 1e4));
|
|
7910
|
-
}
|
|
7911
|
-
return result;
|
|
7912
|
-
});
|
|
7913
|
-
};
|
|
9685
|
+
}
|
|
9686
|
+
return parts.join("");
|
|
7914
9687
|
}
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
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 "";
|
|
7920
9698
|
}
|
|
7921
|
-
function
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
|
|
7926
|
-
|
|
7927
|
-
"neatlogs.span.kind": kind,
|
|
7928
|
-
"neatlogs.db.system": dbName,
|
|
7929
|
-
"neatlogs.db.operation": op,
|
|
7930
|
-
"input.value": safeStringify8(params).slice(0, 1e4)
|
|
7931
|
-
};
|
|
7932
|
-
const indexName = params?.indexName;
|
|
7933
|
-
if (indexName) attrs["neatlogs.vectordb.index_name"] = String(indexName);
|
|
7934
|
-
if (kind === "RETRIEVER" && params?.topK != null) attrs["neatlogs.retriever.top_k"] = params.topK;
|
|
7935
|
-
return withActiveSpan(`mastra.vector.${op}`, attrs, async (span2) => {
|
|
7936
|
-
const result = await orig(params);
|
|
7937
|
-
span2.setAttribute("output.value", safeStringify8(result).slice(0, 1e4));
|
|
7938
|
-
return result;
|
|
7939
|
-
});
|
|
7940
|
-
};
|
|
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
|
+
}
|
|
7941
9705
|
}
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
const attrs = {
|
|
7949
|
-
"neatlogs.span.kind": "CHAIN",
|
|
7950
|
-
"neatlogs.db.operation": op,
|
|
7951
|
-
"input.value": safeStringify8(args?.[0]).slice(0, 1e4)
|
|
7952
|
-
};
|
|
7953
|
-
return withActiveSpan(`mastra.memory.${op}`, attrs, async (span2) => {
|
|
7954
|
-
const result = await orig(...args);
|
|
7955
|
-
span2.setAttribute("output.value", safeStringify8(result).slice(0, 8e3));
|
|
7956
|
-
return result;
|
|
7957
|
-
});
|
|
7958
|
-
};
|
|
9706
|
+
function safeStringify12(value) {
|
|
9707
|
+
if (typeof value === "string") return value;
|
|
9708
|
+
try {
|
|
9709
|
+
return JSON.stringify(value) ?? "";
|
|
9710
|
+
} catch {
|
|
9711
|
+
return "";
|
|
7959
9712
|
}
|
|
7960
9713
|
}
|
|
7961
|
-
|
|
7962
|
-
|
|
7963
|
-
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
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
|
|
7973
9729
|
});
|
|
7974
|
-
}
|
|
7975
|
-
|
|
7976
|
-
function wrapRootMastra(mastra) {
|
|
7977
|
-
const AGENT_GETTERS = /* @__PURE__ */ new Set(["getAgent", "getAgentById"]);
|
|
7978
|
-
const WORKFLOW_GETTERS = /* @__PURE__ */ new Set(["getWorkflow", "getWorkflowById"]);
|
|
7979
|
-
return new Proxy(mastra, {
|
|
7980
|
-
get(target, prop, receiver) {
|
|
7981
|
-
const value = Reflect.get(target, prop, receiver);
|
|
7982
|
-
if (typeof value !== "function") return value;
|
|
7983
|
-
const name = String(prop);
|
|
7984
|
-
if (AGENT_GETTERS.has(name) || WORKFLOW_GETTERS.has(name)) {
|
|
7985
|
-
return (...args) => {
|
|
7986
|
-
const entity = value.apply(target, args);
|
|
7987
|
-
return entity && typeof entity === "object" ? wrapMastra(entity) : entity;
|
|
7988
|
-
};
|
|
7989
|
-
}
|
|
7990
|
-
return value.bind(target);
|
|
7991
|
-
}
|
|
7992
|
-
});
|
|
7993
|
-
}
|
|
7994
|
-
function wrapStreamingOutput(output, span2, ctx) {
|
|
7995
|
-
if (!output) {
|
|
7996
|
-
span2.setStatus({ code: import_api13.SpanStatusCode.OK });
|
|
7997
|
-
span2.end();
|
|
7998
|
-
return output;
|
|
9730
|
+
} catch {
|
|
9731
|
+
wrapped._neatlogsWrapped = true;
|
|
7999
9732
|
}
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
|
|
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);
|
|
9755
|
+
};
|
|
9756
|
+
}
|
|
9757
|
+
function isAsyncIterable(v) {
|
|
9758
|
+
return Boolean(v) && typeof v[Symbol.asyncIterator] === "function";
|
|
9759
|
+
}
|
|
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;
|
|
9767
|
+
}
|
|
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)
|
|
8007
9783
|
};
|
|
8008
|
-
|
|
8009
|
-
|
|
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()) {
|
|
8010
9795
|
try {
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
Promise.resolve(output.usage).catch(() => void 0),
|
|
8014
|
-
Promise.resolve(output.finishReason).catch(() => void 0)
|
|
8015
|
-
]);
|
|
8016
|
-
if (typeof text === "string" && text) {
|
|
8017
|
-
span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
|
|
8018
|
-
span2.setAttribute("neatlogs.llm.output_messages.0.content", text.slice(0, 1e4));
|
|
8019
|
-
}
|
|
8020
|
-
if (usage) recordUsage(span2, usage);
|
|
8021
|
-
if (finishReason) span2.setAttribute("neatlogs.llm.stop_reason", normalizeFinishReason(finishReason));
|
|
8022
|
-
endOnce();
|
|
8023
|
-
} catch (err) {
|
|
8024
|
-
endOnce(err);
|
|
9796
|
+
ts.end();
|
|
9797
|
+
} catch {
|
|
8025
9798
|
}
|
|
8026
|
-
}
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
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
|
+
}
|
|
8046
9825
|
try {
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
finish();
|
|
8050
|
-
return r;
|
|
8051
|
-
}
|
|
8052
|
-
const chunk = r.value;
|
|
8053
|
-
if (typeof chunk === "string") textParts.push(chunk);
|
|
8054
|
-
else if (chunk?.text) textParts.push(chunk.text);
|
|
8055
|
-
else if (chunk?.delta) textParts.push(chunk.delta);
|
|
8056
|
-
return r;
|
|
8057
|
-
} catch (err) {
|
|
8058
|
-
endOnce(err);
|
|
8059
|
-
throw err;
|
|
9826
|
+
handleMessage(tracer, state, result.value, finalizeAgent);
|
|
9827
|
+
} catch {
|
|
8060
9828
|
}
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
},
|
|
8066
|
-
async throw(err) {
|
|
8067
|
-
endOnce(err);
|
|
8068
|
-
return iterator.throw?.(err) ?? { done: true, value: void 0 };
|
|
9829
|
+
return result;
|
|
9830
|
+
} catch (err) {
|
|
9831
|
+
finalizeAgent("error", err);
|
|
9832
|
+
throw err;
|
|
8069
9833
|
}
|
|
8070
|
-
}
|
|
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
|
+
}
|
|
8071
9844
|
};
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
throw err;
|
|
8082
|
-
});
|
|
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 {
|
|
8083
9854
|
}
|
|
8084
|
-
endOnce();
|
|
8085
|
-
return output;
|
|
8086
9855
|
}
|
|
8087
|
-
function
|
|
8088
|
-
const
|
|
8089
|
-
return
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
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));
|
|
8099
9901
|
}
|
|
8100
|
-
|
|
8101
|
-
return value;
|
|
9902
|
+
break;
|
|
8102
9903
|
}
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
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;
|
|
8116
9917
|
}
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
}
|
|
8122
|
-
function finalizeModelResult(span2, result) {
|
|
8123
|
-
if (!result) return;
|
|
8124
|
-
if (typeof result.text === "string" && result.text) {
|
|
8125
|
-
span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
|
|
8126
|
-
span2.setAttribute("neatlogs.llm.output_messages.0.content", result.text.slice(0, 1e4));
|
|
8127
|
-
} else if (Array.isArray(result.content)) {
|
|
8128
|
-
const text = result.content.filter((p) => p?.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
|
|
8129
|
-
if (text) {
|
|
8130
|
-
span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
|
|
8131
|
-
span2.setAttribute("neatlogs.llm.output_messages.0.content", text.slice(0, 1e4));
|
|
9918
|
+
case "assistant": {
|
|
9919
|
+
const scope = getScope(tracer, state, msg);
|
|
9920
|
+
bufferAssistantMessage(scope, msg);
|
|
9921
|
+
break;
|
|
8132
9922
|
}
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
const
|
|
8136
|
-
|
|
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;
|
|
8137
9937
|
}
|
|
8138
|
-
|
|
9938
|
+
default:
|
|
9939
|
+
break;
|
|
8139
9940
|
}
|
|
8140
|
-
if (result.usage) recordUsage(span2, result.usage);
|
|
8141
|
-
span2.setAttribute("neatlogs.llm.stop_reason", normalizeFinishReason(result.finishReason));
|
|
8142
9941
|
}
|
|
8143
|
-
function
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
}
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
if (
|
|
8151
|
-
if (
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
["maxOutputTokens", "neatlogs.llm.max_tokens"],
|
|
8160
|
-
["maxTokens", "neatlogs.llm.max_tokens"],
|
|
8161
|
-
["topP", "neatlogs.llm.top_p"],
|
|
8162
|
-
["topK", "neatlogs.llm.top_k"],
|
|
8163
|
-
["frequencyPenalty", "neatlogs.llm.frequency_penalty"],
|
|
8164
|
-
["presencePenalty", "neatlogs.llm.presence_penalty"]
|
|
8165
|
-
];
|
|
8166
|
-
const invocation = {};
|
|
8167
|
-
for (const [src, target] of map) {
|
|
8168
|
-
const v = callOpts[src];
|
|
8169
|
-
if (v != null) {
|
|
8170
|
-
attrs[target] = v;
|
|
8171
|
-
invocation[src] = v;
|
|
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 });
|
|
8172
9958
|
}
|
|
8173
9959
|
}
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
|
|
9960
|
+
}
|
|
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 });
|
|
8177
9974
|
}
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
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 });
|
|
8183
9981
|
}
|
|
8184
|
-
|
|
8185
|
-
|
|
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;
|
|
8186
9988
|
}
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
span2.setAttribute(`neatlogs.llm.tool_calls.${i}.name`, name ?? "");
|
|
8190
|
-
span2.setAttribute(`neatlogs.llm.tool_calls.${i}.arguments`, safeStringify8(args ?? {}));
|
|
8191
|
-
if (id) span2.setAttribute(`neatlogs.llm.tool_calls.${i}.id`, id);
|
|
8192
|
-
}
|
|
8193
|
-
function recordUsage(span2, usage) {
|
|
8194
|
-
if (!usage) return;
|
|
8195
|
-
const prompt = tokenValue(usage.promptTokens ?? usage.inputTokens ?? usage.input_tokens);
|
|
8196
|
-
const completion = tokenValue(usage.completionTokens ?? usage.outputTokens ?? usage.output_tokens);
|
|
8197
|
-
const total = tokenValue(usage.totalTokens);
|
|
8198
|
-
if (prompt != null) span2.setAttribute("neatlogs.llm.token_count.prompt", prompt);
|
|
8199
|
-
if (completion != null) span2.setAttribute("neatlogs.llm.token_count.completion", completion);
|
|
8200
|
-
if (total != null) span2.setAttribute("neatlogs.llm.token_count.total", total);
|
|
8201
|
-
else if (prompt != null && completion != null) {
|
|
8202
|
-
span2.setAttribute("neatlogs.llm.token_count.total", prompt + completion);
|
|
9989
|
+
if (buf.thinkingParts.length) {
|
|
9990
|
+
attrs["neatlogs.llm.output_messages.0.thinking"] = buf.thinkingParts.join("");
|
|
8203
9991
|
}
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
const ctx = import_api13.trace.setSpan(import_api13.context.active(), span2);
|
|
8209
|
-
return import_api13.context.with(ctx, async () => {
|
|
8210
|
-
try {
|
|
8211
|
-
const result = await fn(span2);
|
|
8212
|
-
span2.setStatus({ code: import_api13.SpanStatusCode.OK });
|
|
8213
|
-
return result;
|
|
8214
|
-
} catch (err) {
|
|
8215
|
-
recordError3(span2, err);
|
|
8216
|
-
throw err;
|
|
8217
|
-
} finally {
|
|
8218
|
-
span2.end();
|
|
8219
|
-
}
|
|
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 ?? {});
|
|
8220
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 });
|
|
10039
|
+
}
|
|
10040
|
+
span2.end();
|
|
10041
|
+
state.toolSpans.delete(id);
|
|
10042
|
+
}
|
|
8221
10043
|
}
|
|
8222
|
-
function
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
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);
|
|
10053
|
+
}
|
|
8227
10054
|
}
|
|
10055
|
+
return parts.join("\n");
|
|
8228
10056
|
}
|
|
8229
|
-
function
|
|
8230
|
-
if (!
|
|
8231
|
-
if (
|
|
8232
|
-
|
|
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
|
+
}
|
|
8233
10070
|
}
|
|
8234
|
-
function
|
|
8235
|
-
|
|
10071
|
+
function extractPromptText(prompt) {
|
|
10072
|
+
if (typeof prompt === "string") return prompt;
|
|
10073
|
+
return "";
|
|
8236
10074
|
}
|
|
8237
|
-
function
|
|
10075
|
+
function safeStringify13(value) {
|
|
8238
10076
|
if (typeof value === "string") return value;
|
|
8239
10077
|
try {
|
|
8240
10078
|
return JSON.stringify(value) ?? "";
|
|
@@ -8242,216 +10080,457 @@ function safeStringify8(value) {
|
|
|
8242
10080
|
return "";
|
|
8243
10081
|
}
|
|
8244
10082
|
}
|
|
8245
|
-
function
|
|
10083
|
+
function recordError7(span2, err) {
|
|
8246
10084
|
if (err instanceof Error) {
|
|
8247
|
-
span2.setStatus({ code:
|
|
10085
|
+
span2.setStatus({ code: import_api18.SpanStatusCode.ERROR, message: err.message });
|
|
8248
10086
|
span2.recordException(err);
|
|
8249
10087
|
} else {
|
|
8250
|
-
span2.setStatus({ code:
|
|
10088
|
+
span2.setStatus({ code: import_api18.SpanStatusCode.ERROR, message: String(err) });
|
|
8251
10089
|
}
|
|
10090
|
+
span2.end();
|
|
8252
10091
|
}
|
|
8253
10092
|
|
|
8254
|
-
// src/
|
|
8255
|
-
var
|
|
8256
|
-
var
|
|
8257
|
-
var
|
|
8258
|
-
function
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
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;
|
|
8268
10107
|
}
|
|
8269
10108
|
});
|
|
8270
|
-
markPatched2(a);
|
|
8271
|
-
return agent;
|
|
8272
10109
|
}
|
|
8273
|
-
function
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
8290
|
-
|
|
8291
|
-
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
break;
|
|
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
|
+
};
|
|
10117
|
+
}
|
|
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
|
+
};
|
|
10125
|
+
}
|
|
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
|
|
8299
10135
|
}
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
}
|
|
8310
|
-
},
|
|
8311
|
-
parent
|
|
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)
|
|
8312
10145
|
);
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
}
|
|
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;
|
|
10196
|
+
try {
|
|
10197
|
+
finalizeLlm(span2, resolved);
|
|
10198
|
+
} catch {
|
|
10199
|
+
span2.setStatus({ code: import_api19.SpanStatusCode.OK });
|
|
8328
10200
|
span2.end();
|
|
8329
|
-
if (event.toolCallId) state.toolSpans.delete(event.toolCallId);
|
|
8330
|
-
break;
|
|
8331
10201
|
}
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
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
|
+
};
|
|
8338
10224
|
}
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
|
|
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
|
+
};
|
|
8349
10246
|
}
|
|
8350
|
-
|
|
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;
|
|
8351
10263
|
}
|
|
8352
|
-
|
|
8353
|
-
break;
|
|
8354
|
-
}
|
|
10264
|
+
});
|
|
8355
10265
|
}
|
|
8356
|
-
function
|
|
8357
|
-
const
|
|
8358
|
-
if (
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
const
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
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);
|
|
10278
|
+
}
|
|
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 ?? {}));
|
|
8366
10293
|
});
|
|
8367
|
-
attrs["neatlogs.llm.input"] = safeStringify9({ messages: inMsgs }).slice(0, 2e4);
|
|
8368
|
-
attrs["input.value"] = safeStringify9({ messages: inMsgs }).slice(0, 1e4);
|
|
8369
10294
|
}
|
|
8370
|
-
const
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
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();
|
|
10304
|
+
}
|
|
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
|
+
}
|
|
8384
10314
|
}
|
|
8385
|
-
attrs["neatlogs.llm.output"] = safeStringify9(outBlob).slice(0, 2e4);
|
|
8386
|
-
attrs["output.value"] = (outText || "").slice(0, 1e4);
|
|
8387
10315
|
}
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
10316
|
+
return parts.length ? parts.join("") : void 0;
|
|
10317
|
+
}
|
|
10318
|
+
function safeStringify14(value) {
|
|
10319
|
+
if (typeof value === "string") return value;
|
|
10320
|
+
try {
|
|
10321
|
+
return JSON.stringify(value) ?? "";
|
|
10322
|
+
} catch {
|
|
10323
|
+
return "";
|
|
10324
|
+
}
|
|
10325
|
+
}
|
|
10326
|
+
function recordError8(span2, err) {
|
|
10327
|
+
if (err instanceof Error) {
|
|
10328
|
+
span2.setStatus({ code: import_api19.SpanStatusCode.ERROR, message: err.message });
|
|
10329
|
+
span2.recordException(err);
|
|
10330
|
+
} else {
|
|
10331
|
+
span2.setStatus({ code: import_api19.SpanStatusCode.ERROR, message: String(err) });
|
|
8396
10332
|
}
|
|
8397
|
-
const parent = state.agentCtx ?? import_api14.context.active();
|
|
8398
|
-
const span2 = tracer.startSpan(
|
|
8399
|
-
`pi_agent.llm.${msg.model || "model"}`,
|
|
8400
|
-
{ attributes: attrs },
|
|
8401
|
-
parent
|
|
8402
|
-
);
|
|
8403
|
-
span2.setStatus({ code: import_api14.SpanStatusCode.OK });
|
|
8404
10333
|
span2.end();
|
|
8405
10334
|
}
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
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 {
|
|
8418
10356
|
}
|
|
8419
|
-
return { text: texts.join(""), toolCalls };
|
|
8420
10357
|
}
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
const
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
if (
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
else if (block.type === "toolCall") parts.push(`${block.name ?? "tool"}(${safeStringify9(block.arguments)})`);
|
|
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);
|
|
8432
10368
|
}
|
|
10369
|
+
return s;
|
|
8433
10370
|
}
|
|
8434
|
-
return
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
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);
|
|
8443
10439
|
}
|
|
10440
|
+
return;
|
|
8444
10441
|
}
|
|
8445
|
-
|
|
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;
|
|
8446
10477
|
}
|
|
8447
|
-
function
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
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);
|
|
8452
10530
|
}
|
|
10531
|
+
return out.join("");
|
|
8453
10532
|
}
|
|
8454
|
-
function
|
|
10533
|
+
function safeStringify15(value) {
|
|
8455
10534
|
if (typeof value === "string") return value;
|
|
8456
10535
|
try {
|
|
8457
10536
|
return JSON.stringify(value) ?? "";
|
|
@@ -8511,6 +10590,7 @@ function bindTemplates(llm, systemTpl, userTpl, compiledVars) {
|
|
|
8511
10590
|
}
|
|
8512
10591
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8513
10592
|
0 && (module.exports = {
|
|
10593
|
+
NeatlogsOpencodePlugin,
|
|
8514
10594
|
PromptApiError,
|
|
8515
10595
|
PromptClient,
|
|
8516
10596
|
PromptClientError,
|
|
@@ -8544,11 +10624,21 @@ function bindTemplates(llm, systemTpl, userTpl, compiledVars) {
|
|
|
8544
10624
|
strandsHooks,
|
|
8545
10625
|
trace,
|
|
8546
10626
|
traceToolAnthropic,
|
|
10627
|
+
traceToolAzureOpenAI,
|
|
10628
|
+
traceToolBedrock,
|
|
8547
10629
|
traceToolOpenAI,
|
|
10630
|
+
traceToolVertexAI,
|
|
8548
10631
|
updatePrompt,
|
|
8549
10632
|
wrapAISDK,
|
|
8550
10633
|
wrapAnthropic,
|
|
10634
|
+
wrapAzureOpenAI,
|
|
10635
|
+
wrapBedrock,
|
|
10636
|
+
wrapCallModel,
|
|
10637
|
+
wrapClaudeAgentSDK,
|
|
8551
10638
|
wrapMastra,
|
|
8552
|
-
wrapOpenAI
|
|
10639
|
+
wrapOpenAI,
|
|
10640
|
+
wrapOpenRouterAgent,
|
|
10641
|
+
wrapVertexAI,
|
|
10642
|
+
wrapVertexAIChat
|
|
8553
10643
|
});
|
|
8554
10644
|
//# sourceMappingURL=index.cjs.map
|