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