neatlogs 1.1.12 → 1.1.14
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/index.cjs +703 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +701 -61
- package/dist/index.mjs.map +1 -1
- package/dist/openai.cjs +110 -10
- package/dist/openai.cjs.map +1 -1
- package/dist/openai.mjs +110 -10
- package/dist/openai.mjs.map +1 -1
- package/dist/opencode-plugin.cjs +1 -1
- package/dist/opencode-plugin.cjs.map +1 -1
- package/dist/opencode-plugin.mjs +1 -1
- package/dist/opencode-plugin.mjs.map +1 -1
- package/dist/pi-agent.cjs +578 -48
- package/dist/pi-agent.cjs.map +1 -1
- package/dist/pi-agent.d.ts +69 -7
- package/dist/pi-agent.mjs +575 -47
- package/dist/pi-agent.mjs.map +1 -1
- package/package.json +7 -1
package/dist/index.cjs
CHANGED
|
@@ -66,6 +66,8 @@ __export(index_exports, {
|
|
|
66
66
|
span: () => span,
|
|
67
67
|
strandsHooks: () => strandsHooks,
|
|
68
68
|
trace: () => trace,
|
|
69
|
+
tracePiAgentEvents: () => tracePiAgentEvents,
|
|
70
|
+
tracePiStream: () => tracePiStream,
|
|
69
71
|
traceToolAnthropic: () => traceTool2,
|
|
70
72
|
traceToolAzureOpenAI: () => traceTool3,
|
|
71
73
|
traceToolBedrock: () => traceTool6,
|
|
@@ -4873,6 +4875,8 @@ var NeatlogsSpanProcessor = class {
|
|
|
4873
4875
|
if (!currentModel) return;
|
|
4874
4876
|
const llmOutput = attrs["neatlogs.llm.output"];
|
|
4875
4877
|
if (!llmOutput) return;
|
|
4878
|
+
const trimmed = llmOutput.trimStart();
|
|
4879
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return;
|
|
4876
4880
|
try {
|
|
4877
4881
|
const output = JSON.parse(llmOutput);
|
|
4878
4882
|
const generations = output?.generations;
|
|
@@ -4897,7 +4901,9 @@ var NeatlogsSpanProcessor = class {
|
|
|
4897
4901
|
}
|
|
4898
4902
|
}
|
|
4899
4903
|
} catch (e) {
|
|
4900
|
-
|
|
4904
|
+
if (this.debug) {
|
|
4905
|
+
logger10.debug(`[ModelResolve] Failed to parse LLM output for model extraction: ${e}`);
|
|
4906
|
+
}
|
|
4901
4907
|
}
|
|
4902
4908
|
}
|
|
4903
4909
|
// ── forceFlush / shutdown ─────────────────────────────
|
|
@@ -5058,7 +5064,8 @@ var INSTRUMENTATION_REGISTRY = {
|
|
|
5058
5064
|
"ai_sdk",
|
|
5059
5065
|
"claude_agent_sdk",
|
|
5060
5066
|
"openrouter_agent",
|
|
5061
|
-
"opencode"
|
|
5067
|
+
"opencode",
|
|
5068
|
+
"pi_agent"
|
|
5062
5069
|
],
|
|
5063
5070
|
tool: ["langchain", "llamaindex", "haystack", "mcp"],
|
|
5064
5071
|
http: ["requests", "httpx", "urllib3", "aiohttp"],
|
|
@@ -5433,6 +5440,13 @@ var INSTRUMENTATION_REGISTRY = {
|
|
|
5433
5440
|
neatlogs: "neatlogs/opencode",
|
|
5434
5441
|
default_span_kind: "AGENT",
|
|
5435
5442
|
explicitWrapper: "NeatlogsOpencodePlugin from 'neatlogs/opencode'"
|
|
5443
|
+
},
|
|
5444
|
+
pi_agent: {
|
|
5445
|
+
openinference: null,
|
|
5446
|
+
openllmetry: null,
|
|
5447
|
+
neatlogs: "neatlogs/pi-agent",
|
|
5448
|
+
default_span_kind: "AGENT",
|
|
5449
|
+
explicitWrapper: "piAgentHooks() from 'neatlogs/pi-agent'"
|
|
5436
5450
|
}
|
|
5437
5451
|
}
|
|
5438
5452
|
};
|
|
@@ -6009,7 +6023,7 @@ function _resetMastraCache() {
|
|
|
6009
6023
|
}
|
|
6010
6024
|
|
|
6011
6025
|
// src/version.ts
|
|
6012
|
-
var __version__ = "1.1.
|
|
6026
|
+
var __version__ = "1.1.14";
|
|
6013
6027
|
|
|
6014
6028
|
// src/init.ts
|
|
6015
6029
|
var logger13 = getLogger();
|
|
@@ -6898,29 +6912,25 @@ function tracedResponsesCreate(original) {
|
|
|
6898
6912
|
return function(opts, ...rest) {
|
|
6899
6913
|
const tracer = getProviderTracer(TRACER_NAME3);
|
|
6900
6914
|
const model = opts?.model ?? "";
|
|
6915
|
+
const isStream = opts?.stream === true;
|
|
6901
6916
|
const span2 = tracer.startSpan("openai.responses.create", {
|
|
6902
6917
|
attributes: {
|
|
6903
6918
|
"neatlogs.span.kind": "LLM",
|
|
6904
6919
|
"neatlogs.llm.provider": "openai",
|
|
6905
6920
|
"neatlogs.llm.system": "openai",
|
|
6906
6921
|
"neatlogs.llm.model_name": model,
|
|
6922
|
+
"neatlogs.llm.is_streaming": isStream,
|
|
6907
6923
|
"input.value": safeStringify3(opts?.input ?? "")
|
|
6908
6924
|
}
|
|
6909
6925
|
}, getNeatlogsParentContext());
|
|
6926
|
+
setInvocationParams(span2, opts);
|
|
6910
6927
|
const promise = withNeatlogsSpan(span2, () => original(opts, ...rest));
|
|
6911
6928
|
return promise.then(
|
|
6912
6929
|
(response) => {
|
|
6913
|
-
if (
|
|
6914
|
-
|
|
6915
|
-
span2.setAttribute("neatlogs.llm.output_messages.0.content", response.output_text);
|
|
6916
|
-
}
|
|
6917
|
-
if (response?.model) span2.setAttribute("neatlogs.llm.model_name", response.model);
|
|
6918
|
-
if (response?.usage) {
|
|
6919
|
-
if (response.usage.input_tokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", response.usage.input_tokens);
|
|
6920
|
-
if (response.usage.output_tokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", response.usage.output_tokens);
|
|
6930
|
+
if (isStream) {
|
|
6931
|
+
return wrapResponsesAsyncIterableStream(response, span2);
|
|
6921
6932
|
}
|
|
6922
|
-
span2
|
|
6923
|
-
span2.end();
|
|
6933
|
+
finalizeResponsesResponse(span2, response);
|
|
6924
6934
|
return response;
|
|
6925
6935
|
},
|
|
6926
6936
|
(err) => {
|
|
@@ -6930,6 +6940,110 @@ function tracedResponsesCreate(original) {
|
|
|
6930
6940
|
);
|
|
6931
6941
|
};
|
|
6932
6942
|
}
|
|
6943
|
+
function wrapResponsesAsyncIterableStream(stream, span2) {
|
|
6944
|
+
const originalAsyncIterator = stream?.[Symbol.asyncIterator]?.bind(stream);
|
|
6945
|
+
if (!originalAsyncIterator) {
|
|
6946
|
+
finalizeResponsesResponse(span2, stream);
|
|
6947
|
+
return stream;
|
|
6948
|
+
}
|
|
6949
|
+
const textParts = [];
|
|
6950
|
+
let completedResponse;
|
|
6951
|
+
let finalized = false;
|
|
6952
|
+
const finalize = () => {
|
|
6953
|
+
if (finalized) return;
|
|
6954
|
+
finalized = true;
|
|
6955
|
+
finalizeResponsesResponse(span2, completedResponse, textParts.join(""));
|
|
6956
|
+
};
|
|
6957
|
+
return new Proxy(stream, {
|
|
6958
|
+
get(target, prop) {
|
|
6959
|
+
if (prop === Symbol.asyncIterator) {
|
|
6960
|
+
return () => {
|
|
6961
|
+
const iterator = originalAsyncIterator();
|
|
6962
|
+
return {
|
|
6963
|
+
async next() {
|
|
6964
|
+
try {
|
|
6965
|
+
const result = await iterator.next();
|
|
6966
|
+
if (result.done) {
|
|
6967
|
+
finalize();
|
|
6968
|
+
return result;
|
|
6969
|
+
}
|
|
6970
|
+
const event = result.value;
|
|
6971
|
+
if (event?.type === "response.output_text.delta" && typeof event.delta === "string") {
|
|
6972
|
+
textParts.push(event.delta);
|
|
6973
|
+
} else if (event?.type === "response.completed") {
|
|
6974
|
+
completedResponse = event.response;
|
|
6975
|
+
}
|
|
6976
|
+
return result;
|
|
6977
|
+
} catch (err) {
|
|
6978
|
+
if (!finalized) {
|
|
6979
|
+
finalized = true;
|
|
6980
|
+
recordError(span2, err);
|
|
6981
|
+
}
|
|
6982
|
+
throw err;
|
|
6983
|
+
}
|
|
6984
|
+
},
|
|
6985
|
+
async return(value2) {
|
|
6986
|
+
try {
|
|
6987
|
+
return await (iterator.return?.(value2) ?? { done: true, value: value2 });
|
|
6988
|
+
} finally {
|
|
6989
|
+
finalize();
|
|
6990
|
+
}
|
|
6991
|
+
},
|
|
6992
|
+
async throw(err) {
|
|
6993
|
+
if (!finalized) {
|
|
6994
|
+
finalized = true;
|
|
6995
|
+
recordError(span2, err);
|
|
6996
|
+
}
|
|
6997
|
+
if (iterator.throw) return iterator.throw(err);
|
|
6998
|
+
throw err;
|
|
6999
|
+
}
|
|
7000
|
+
};
|
|
7001
|
+
};
|
|
7002
|
+
}
|
|
7003
|
+
const value = Reflect.get(target, prop, target);
|
|
7004
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
7005
|
+
}
|
|
7006
|
+
});
|
|
7007
|
+
}
|
|
7008
|
+
function finalizeResponsesResponse(span2, response, streamedText = "") {
|
|
7009
|
+
const text = response?.output_text || streamedText || extractResponsesOutputText(response?.output);
|
|
7010
|
+
if (text) {
|
|
7011
|
+
span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
|
|
7012
|
+
span2.setAttribute("neatlogs.llm.output_messages.0.content", text);
|
|
7013
|
+
span2.setAttribute("output.value", text);
|
|
7014
|
+
} else if (response?.output) {
|
|
7015
|
+
span2.setAttribute("output.value", safeStringify3(response.output));
|
|
7016
|
+
}
|
|
7017
|
+
if (response?.model) span2.setAttribute("neatlogs.llm.model_name", response.model);
|
|
7018
|
+
if (response?.status) span2.setAttribute("neatlogs.llm.finish_reason", response.status);
|
|
7019
|
+
const usage = response?.usage;
|
|
7020
|
+
if (usage) {
|
|
7021
|
+
if (usage.input_tokens != null) span2.setAttribute("neatlogs.llm.token_count.prompt", usage.input_tokens);
|
|
7022
|
+
if (usage.output_tokens != null) span2.setAttribute("neatlogs.llm.token_count.completion", usage.output_tokens);
|
|
7023
|
+
if (usage.total_tokens != null) span2.setAttribute("neatlogs.llm.token_count.total", usage.total_tokens);
|
|
7024
|
+
if (usage.input_tokens_details?.cached_tokens != null) {
|
|
7025
|
+
span2.setAttribute("neatlogs.llm.token_count.cache_read", usage.input_tokens_details.cached_tokens);
|
|
7026
|
+
}
|
|
7027
|
+
if (usage.output_tokens_details?.reasoning_tokens != null) {
|
|
7028
|
+
span2.setAttribute("neatlogs.llm.token_count.reasoning", usage.output_tokens_details.reasoning_tokens);
|
|
7029
|
+
}
|
|
7030
|
+
}
|
|
7031
|
+
span2.setStatus({ code: import_api10.SpanStatusCode.OK });
|
|
7032
|
+
span2.end();
|
|
7033
|
+
}
|
|
7034
|
+
function extractResponsesOutputText(output) {
|
|
7035
|
+
if (!Array.isArray(output)) return "";
|
|
7036
|
+
const parts = [];
|
|
7037
|
+
for (const item of output) {
|
|
7038
|
+
if (item?.type !== "message" || !Array.isArray(item.content)) continue;
|
|
7039
|
+
for (const content of item.content) {
|
|
7040
|
+
if (content?.type === "output_text" && typeof content.text === "string") {
|
|
7041
|
+
parts.push(content.text);
|
|
7042
|
+
}
|
|
7043
|
+
}
|
|
7044
|
+
}
|
|
7045
|
+
return parts.join("");
|
|
7046
|
+
}
|
|
6933
7047
|
function wrapAsyncIterableStream(stream, span2) {
|
|
6934
7048
|
const chunks = [];
|
|
6935
7049
|
const originalAsyncIterator = stream[Symbol.asyncIterator]?.bind(stream);
|
|
@@ -10273,22 +10387,342 @@ function recordError7(span2, err) {
|
|
|
10273
10387
|
var import_api19 = require("@opentelemetry/api");
|
|
10274
10388
|
var TRACER_NAME12 = "neatlogs.pi-agent";
|
|
10275
10389
|
var PATCH_FLAG2 = "_neatlogs_patched";
|
|
10390
|
+
var HARNESS_METHOD_FLAG = "_neatlogs_harness_methods_patched";
|
|
10276
10391
|
function piAgentHooks(agent) {
|
|
10277
10392
|
if (!agent || agent[PATCH_FLAG2]) return agent;
|
|
10278
10393
|
const a = agent;
|
|
10279
10394
|
if (typeof a.subscribe !== "function") return agent;
|
|
10280
|
-
const
|
|
10395
|
+
const listener = tracePiAgentEvents(() => a.state?.messages);
|
|
10396
|
+
a.subscribe((event) => listener(event));
|
|
10397
|
+
wrapHarnessModelOperations(a);
|
|
10398
|
+
markPatched2(a);
|
|
10399
|
+
return agent;
|
|
10400
|
+
}
|
|
10401
|
+
function wrapHarnessModelOperations(harness) {
|
|
10402
|
+
if (harness[HARNESS_METHOD_FLAG]) return;
|
|
10403
|
+
const isHarness = typeof harness.compact === "function" && typeof harness.navigateTree === "function" && typeof harness.getModel === "function";
|
|
10404
|
+
if (!isHarness) return;
|
|
10405
|
+
patchHarnessMethod(harness, "compact", (args) => ({ customInstructions: args[0] }));
|
|
10406
|
+
patchHarnessMethod(harness, "navigateTree", (args) => ({ targetId: args[0], options: args[1] }));
|
|
10407
|
+
try {
|
|
10408
|
+
Object.defineProperty(harness, HARNESS_METHOD_FLAG, { value: true });
|
|
10409
|
+
} catch {
|
|
10410
|
+
harness[HARNESS_METHOD_FLAG] = true;
|
|
10411
|
+
}
|
|
10412
|
+
}
|
|
10413
|
+
function patchHarnessMethod(harness, method, inputOf) {
|
|
10414
|
+
const original = harness[method].bind(harness);
|
|
10415
|
+
harness[method] = async (...args) => {
|
|
10416
|
+
const startedAt = Date.now();
|
|
10417
|
+
const parent = getNeatlogsParentContext();
|
|
10418
|
+
const input = inputOf(args);
|
|
10419
|
+
let observedModelCall;
|
|
10420
|
+
let stopObserving;
|
|
10421
|
+
try {
|
|
10422
|
+
stopObserving = harness.subscribe((event) => {
|
|
10423
|
+
if (method === "compact" && event?.type === "session_compact") {
|
|
10424
|
+
observedModelCall = !event.fromHook;
|
|
10425
|
+
} else if (method === "navigateTree" && event?.type === "session_tree") {
|
|
10426
|
+
observedModelCall = Boolean(event.summaryEntry) && !event.fromHook;
|
|
10427
|
+
}
|
|
10428
|
+
});
|
|
10429
|
+
} catch {
|
|
10430
|
+
}
|
|
10431
|
+
let result;
|
|
10432
|
+
let failure;
|
|
10433
|
+
try {
|
|
10434
|
+
result = await original(...args);
|
|
10435
|
+
return result;
|
|
10436
|
+
} catch (err) {
|
|
10437
|
+
failure = err;
|
|
10438
|
+
throw err;
|
|
10439
|
+
} finally {
|
|
10440
|
+
stopObserving?.();
|
|
10441
|
+
try {
|
|
10442
|
+
emitHarnessOperation(
|
|
10443
|
+
method,
|
|
10444
|
+
input,
|
|
10445
|
+
result,
|
|
10446
|
+
failure,
|
|
10447
|
+
harness.getModel?.(),
|
|
10448
|
+
parent,
|
|
10449
|
+
startedAt,
|
|
10450
|
+
Date.now(),
|
|
10451
|
+
observedModelCall
|
|
10452
|
+
);
|
|
10453
|
+
} catch {
|
|
10454
|
+
}
|
|
10455
|
+
}
|
|
10456
|
+
};
|
|
10457
|
+
}
|
|
10458
|
+
function emitHarnessOperation(method, input, result, failure, model, capturedParent, startedAt, endedAt, observedModelCall) {
|
|
10459
|
+
const tracer = getNeatlogsTracer(TRACER_NAME12);
|
|
10460
|
+
let parent = capturedParent;
|
|
10461
|
+
let root;
|
|
10462
|
+
const inputText = safeStringify12(input ?? {});
|
|
10463
|
+
const outputText = failure ? `[error] ${failure instanceof Error ? failure.message : String(failure)}` : harnessOperationOutput(method, result);
|
|
10464
|
+
if (!import_api19.trace.getSpan(parent)?.isRecording()) {
|
|
10465
|
+
root = tracer.startSpan(
|
|
10466
|
+
`pi_agent.harness.${method}`,
|
|
10467
|
+
{
|
|
10468
|
+
startTime: startedAt,
|
|
10469
|
+
attributes: {
|
|
10470
|
+
"neatlogs.span.kind": "WORKFLOW",
|
|
10471
|
+
"input.value": inputText
|
|
10472
|
+
}
|
|
10473
|
+
},
|
|
10474
|
+
parent
|
|
10475
|
+
);
|
|
10476
|
+
parent = import_api19.trace.setSpan(parent, root);
|
|
10477
|
+
}
|
|
10478
|
+
const chain = tracer.startSpan(
|
|
10479
|
+
`pi_agent.harness.${method}`,
|
|
10480
|
+
{
|
|
10481
|
+
startTime: startedAt,
|
|
10482
|
+
attributes: {
|
|
10483
|
+
"neatlogs.span.kind": "CHAIN",
|
|
10484
|
+
"neatlogs.pi.operation": method,
|
|
10485
|
+
"input.value": inputText
|
|
10486
|
+
}
|
|
10487
|
+
},
|
|
10488
|
+
parent
|
|
10489
|
+
);
|
|
10490
|
+
const chainCtx = import_api19.trace.setSpan(parent, chain);
|
|
10491
|
+
const usage = harnessOperationUsage(method, result);
|
|
10492
|
+
const madeModelCall = observedModelCall ?? (failure ? isHarnessSummarizationFailure(failure) : method === "compact" ? Boolean(result?.usage) : Boolean(result?.summaryEntry) && result.summaryEntry.fromHook !== true);
|
|
10493
|
+
if (madeModelCall || failure) {
|
|
10494
|
+
const llm = openLlmSpan(
|
|
10495
|
+
tracer,
|
|
10496
|
+
{
|
|
10497
|
+
toolSpans: /* @__PURE__ */ new Map(),
|
|
10498
|
+
inputMessages: [{ role: "user", content: inputText }],
|
|
10499
|
+
turnIndex: 0,
|
|
10500
|
+
turnCtx: chainCtx,
|
|
10501
|
+
turnStartEpochMs: startedAt
|
|
10502
|
+
},
|
|
10503
|
+
{
|
|
10504
|
+
role: "assistant",
|
|
10505
|
+
model: model?.id ?? model?.model,
|
|
10506
|
+
provider: model?.provider,
|
|
10507
|
+
timestamp: startedAt
|
|
10508
|
+
}
|
|
10509
|
+
);
|
|
10510
|
+
if (failure) {
|
|
10511
|
+
closeLlmFailure(llm, failure, endedAt);
|
|
10512
|
+
} else {
|
|
10513
|
+
finishLlmSpan(
|
|
10514
|
+
llm,
|
|
10515
|
+
{
|
|
10516
|
+
role: "assistant",
|
|
10517
|
+
model: model?.id ?? model?.model,
|
|
10518
|
+
provider: model?.provider,
|
|
10519
|
+
content: outputText ? [{ type: "text", text: outputText }] : [],
|
|
10520
|
+
usage,
|
|
10521
|
+
stopReason: "stop"
|
|
10522
|
+
},
|
|
10523
|
+
endedAt
|
|
10524
|
+
);
|
|
10525
|
+
}
|
|
10526
|
+
}
|
|
10527
|
+
if (outputText) chain.setAttribute("output.value", outputText);
|
|
10528
|
+
if (failure) {
|
|
10529
|
+
const message = failure instanceof Error ? failure.message : String(failure);
|
|
10530
|
+
chain.setAttribute("neatlogs.error.message", message);
|
|
10531
|
+
chain.setStatus({ code: import_api19.SpanStatusCode.ERROR, message });
|
|
10532
|
+
} else {
|
|
10533
|
+
chain.setStatus({ code: import_api19.SpanStatusCode.OK });
|
|
10534
|
+
}
|
|
10535
|
+
chain.end(endedAt);
|
|
10536
|
+
if (root) {
|
|
10537
|
+
if (outputText) root.setAttribute("output.value", outputText);
|
|
10538
|
+
if (failure) {
|
|
10539
|
+
const message = failure instanceof Error ? failure.message : String(failure);
|
|
10540
|
+
root.setAttribute("neatlogs.error.message", message);
|
|
10541
|
+
root.setStatus({ code: import_api19.SpanStatusCode.ERROR, message });
|
|
10542
|
+
} else {
|
|
10543
|
+
root.setStatus({ code: import_api19.SpanStatusCode.OK });
|
|
10544
|
+
}
|
|
10545
|
+
root.end(endedAt);
|
|
10546
|
+
}
|
|
10547
|
+
}
|
|
10548
|
+
function isHarnessSummarizationFailure(failure) {
|
|
10549
|
+
let current = failure;
|
|
10550
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10551
|
+
while (current && !seen.has(current)) {
|
|
10552
|
+
seen.add(current);
|
|
10553
|
+
if (current.code === "summarization_failed") return true;
|
|
10554
|
+
current = current.cause;
|
|
10555
|
+
}
|
|
10556
|
+
return false;
|
|
10557
|
+
}
|
|
10558
|
+
function harnessOperationOutput(method, result) {
|
|
10559
|
+
if (method === "compact") return typeof result?.summary === "string" ? result.summary : safeStringify12(result ?? {});
|
|
10560
|
+
const summary = result?.summaryEntry?.summary;
|
|
10561
|
+
return typeof summary === "string" ? summary : safeStringify12(result ?? {});
|
|
10562
|
+
}
|
|
10563
|
+
function harnessOperationUsage(method, result) {
|
|
10564
|
+
return method === "compact" ? result?.usage : result?.summaryEntry?.usage;
|
|
10565
|
+
}
|
|
10566
|
+
function closeLlmFailure(llm, failure, endedAt) {
|
|
10567
|
+
const message = failure instanceof Error ? failure.message : String(failure);
|
|
10568
|
+
llm.span.setAttribute("output.value", `[error] ${message}`);
|
|
10569
|
+
llm.span.setAttribute("neatlogs.error.message", message);
|
|
10570
|
+
llm.span.setStatus({ code: import_api19.SpanStatusCode.ERROR, message });
|
|
10571
|
+
llm.span.end(endedAt);
|
|
10572
|
+
}
|
|
10573
|
+
function tracePiAgentEvents(getTranscript) {
|
|
10574
|
+
const state = { toolSpans: /* @__PURE__ */ new Map(), inputMessages: [], turnIndex: 0 };
|
|
10281
10575
|
const tracer = getNeatlogsTracer(TRACER_NAME12);
|
|
10282
|
-
|
|
10576
|
+
return (event) => {
|
|
10283
10577
|
try {
|
|
10284
|
-
handleEvent(tracer, state, event);
|
|
10578
|
+
handleEvent(tracer, state, event, getTranscript);
|
|
10285
10579
|
} catch {
|
|
10286
10580
|
}
|
|
10581
|
+
};
|
|
10582
|
+
}
|
|
10583
|
+
function tracePiStream(streamFn) {
|
|
10584
|
+
const tracer = getNeatlogsTracer(TRACER_NAME12);
|
|
10585
|
+
return ((model, context2, options) => {
|
|
10586
|
+
let llm;
|
|
10587
|
+
let root;
|
|
10588
|
+
try {
|
|
10589
|
+
const state = { toolSpans: /* @__PURE__ */ new Map(), inputMessages: [], turnIndex: 0 };
|
|
10590
|
+
state.inputMessages = promptMessagesOf(context2);
|
|
10591
|
+
let parent = getNeatlogsParentContext();
|
|
10592
|
+
if (!import_api19.trace.getSpan(parent)?.isRecording()) {
|
|
10593
|
+
root = tracer.startSpan(
|
|
10594
|
+
"pi_agent.stream",
|
|
10595
|
+
{ attributes: { "neatlogs.span.kind": "WORKFLOW" } },
|
|
10596
|
+
parent
|
|
10597
|
+
);
|
|
10598
|
+
parent = import_api19.trace.setSpan(parent, root);
|
|
10599
|
+
const rootInput = state.inputMessages.length ? safeStringify12({ messages: state.inputMessages }) : void 0;
|
|
10600
|
+
if (rootInput) root.setAttribute("input.value", rootInput);
|
|
10601
|
+
}
|
|
10602
|
+
state.turnCtx = parent;
|
|
10603
|
+
llm = openLlmSpan(tracer, state, {
|
|
10604
|
+
role: "assistant",
|
|
10605
|
+
model: model?.id ?? model?.model,
|
|
10606
|
+
provider: model?.provider
|
|
10607
|
+
});
|
|
10608
|
+
} catch {
|
|
10609
|
+
}
|
|
10610
|
+
let returned;
|
|
10611
|
+
try {
|
|
10612
|
+
returned = streamFn(model, context2, options);
|
|
10613
|
+
} catch (err) {
|
|
10614
|
+
closeStreamFailure(llm, root, err);
|
|
10615
|
+
throw err;
|
|
10616
|
+
}
|
|
10617
|
+
if (isThenable(returned)) {
|
|
10618
|
+
return returned.then(
|
|
10619
|
+
(stream) => attachStreamResult(stream, llm, root),
|
|
10620
|
+
(err) => {
|
|
10621
|
+
closeStreamFailure(llm, root, err);
|
|
10622
|
+
throw err;
|
|
10623
|
+
}
|
|
10624
|
+
);
|
|
10625
|
+
}
|
|
10626
|
+
return attachStreamResult(returned, llm, root);
|
|
10287
10627
|
});
|
|
10288
|
-
markPatched2(a);
|
|
10289
|
-
return agent;
|
|
10290
10628
|
}
|
|
10291
|
-
function
|
|
10629
|
+
function attachStreamResult(stream, llm, root) {
|
|
10630
|
+
if (!llm || !stream || typeof stream.result !== "function") {
|
|
10631
|
+
closeStreamRoot(root);
|
|
10632
|
+
return stream;
|
|
10633
|
+
}
|
|
10634
|
+
observeStreamDeltas(stream, llm);
|
|
10635
|
+
stream.result().then(
|
|
10636
|
+
(msg) => {
|
|
10637
|
+
const message = msg ?? { role: "assistant" };
|
|
10638
|
+
finishLlmSpan(llm, message);
|
|
10639
|
+
closeStreamRoot(root, message);
|
|
10640
|
+
},
|
|
10641
|
+
(err) => closeStreamFailure(llm, root, err)
|
|
10642
|
+
);
|
|
10643
|
+
return stream;
|
|
10644
|
+
}
|
|
10645
|
+
function observeStreamDeltas(stream, llm) {
|
|
10646
|
+
const original = stream?.[Symbol.asyncIterator];
|
|
10647
|
+
if (typeof original !== "function" || original.__neatlogsObserved) return;
|
|
10648
|
+
const observed = function() {
|
|
10649
|
+
const iterator = original.call(this);
|
|
10650
|
+
return {
|
|
10651
|
+
next: async (...args) => {
|
|
10652
|
+
const item = await iterator.next(...args);
|
|
10653
|
+
if (!item.done && isContentDelta(item.value?.type)) markFirstStreamDelta(llm);
|
|
10654
|
+
return item;
|
|
10655
|
+
},
|
|
10656
|
+
return: iterator.return?.bind(iterator),
|
|
10657
|
+
throw: iterator.throw?.bind(iterator)
|
|
10658
|
+
};
|
|
10659
|
+
};
|
|
10660
|
+
Object.defineProperty(observed, "__neatlogsObserved", { value: true });
|
|
10661
|
+
try {
|
|
10662
|
+
stream[Symbol.asyncIterator] = observed;
|
|
10663
|
+
} catch {
|
|
10664
|
+
}
|
|
10665
|
+
}
|
|
10666
|
+
function markFirstStreamDelta(llm) {
|
|
10667
|
+
llm.span.setAttribute("neatlogs.llm.is_streaming", true);
|
|
10668
|
+
if (llm.ttftMs !== void 0) return;
|
|
10669
|
+
llm.ttftMs = llm.callStartEpochMs !== void 0 ? Date.now() - llm.callStartEpochMs : nowMs() - llm.startHr;
|
|
10670
|
+
}
|
|
10671
|
+
function closeStreamFailure(llm, root, err) {
|
|
10672
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
10673
|
+
try {
|
|
10674
|
+
llm?.span.setAttribute("output.value", `[error] ${message}`);
|
|
10675
|
+
llm?.span.setAttribute("neatlogs.error.message", message);
|
|
10676
|
+
llm?.span.setStatus({ code: import_api19.SpanStatusCode.ERROR, message });
|
|
10677
|
+
llm?.span.end();
|
|
10678
|
+
} catch {
|
|
10679
|
+
}
|
|
10680
|
+
closeStreamRoot(root, void 0, message);
|
|
10681
|
+
}
|
|
10682
|
+
function isThenable(value) {
|
|
10683
|
+
return value != null && typeof value.then === "function";
|
|
10684
|
+
}
|
|
10685
|
+
function closeStreamRoot(root, msg, error) {
|
|
10686
|
+
if (!root) return;
|
|
10687
|
+
try {
|
|
10688
|
+
if (msg) {
|
|
10689
|
+
const { text, toolCalls } = splitAssistantContent(msg.content);
|
|
10690
|
+
const out = text || toolCalls.map((tc) => `${tc.name}(${safeStringify12(tc.arguments)})`).join("\n") || terminalSummary(msg);
|
|
10691
|
+
if (out) root.setAttribute("output.value", out);
|
|
10692
|
+
applyStopReasonStatus(root, msg);
|
|
10693
|
+
} else if (error) {
|
|
10694
|
+
root.setAttribute("output.value", `[error] ${error}`);
|
|
10695
|
+
root.setAttribute("neatlogs.error.message", error);
|
|
10696
|
+
root.setStatus({ code: import_api19.SpanStatusCode.ERROR, message: error });
|
|
10697
|
+
}
|
|
10698
|
+
root.end();
|
|
10699
|
+
} catch {
|
|
10700
|
+
}
|
|
10701
|
+
}
|
|
10702
|
+
function transcriptRows(messages) {
|
|
10703
|
+
if (!Array.isArray(messages)) return [];
|
|
10704
|
+
const rows = [];
|
|
10705
|
+
for (const m of messages) {
|
|
10706
|
+
const content = messageText(m);
|
|
10707
|
+
if (!content) continue;
|
|
10708
|
+
rows.push({ role: m?.role === "toolResult" ? "tool" : String(m?.role ?? "user"), content });
|
|
10709
|
+
}
|
|
10710
|
+
return rows;
|
|
10711
|
+
}
|
|
10712
|
+
function promptMessagesOf(context2) {
|
|
10713
|
+
const rows = [];
|
|
10714
|
+
if (typeof context2?.systemPrompt === "string" && context2.systemPrompt) {
|
|
10715
|
+
rows.push({ role: "system", content: context2.systemPrompt });
|
|
10716
|
+
}
|
|
10717
|
+
if (Array.isArray(context2?.messages)) {
|
|
10718
|
+
for (const m of context2.messages) {
|
|
10719
|
+
const content = messageText(m);
|
|
10720
|
+
if (content) rows.push({ role: String(m?.role ?? "user"), content });
|
|
10721
|
+
}
|
|
10722
|
+
}
|
|
10723
|
+
return rows;
|
|
10724
|
+
}
|
|
10725
|
+
function handleEvent(tracer, state, event, getTranscript) {
|
|
10292
10726
|
switch (event.type) {
|
|
10293
10727
|
case "agent_start": {
|
|
10294
10728
|
const base = getNeatlogsParentContext();
|
|
@@ -10299,31 +10733,98 @@ function handleEvent(tracer, state, event) {
|
|
|
10299
10733
|
);
|
|
10300
10734
|
state.agentSpan = span2;
|
|
10301
10735
|
state.agentCtx = import_api19.trace.setSpan(base, span2);
|
|
10302
|
-
state.inputMessages =
|
|
10736
|
+
state.inputMessages = transcriptRows(getTranscript?.());
|
|
10737
|
+
state.turnIndex = 0;
|
|
10738
|
+
state.runInput = void 0;
|
|
10739
|
+
state.runError = void 0;
|
|
10740
|
+
break;
|
|
10741
|
+
}
|
|
10742
|
+
case "turn_start": {
|
|
10743
|
+
const parent = state.agentCtx ?? getNeatlogsParentContext();
|
|
10744
|
+
state.turnIndex += 1;
|
|
10745
|
+
const pending = state.inputMessages[state.inputMessages.length - 1];
|
|
10746
|
+
const priorInput = pending && (pending.role === "user" || pending.role === "tool") ? pending.content : void 0;
|
|
10747
|
+
const span2 = tracer.startSpan(
|
|
10748
|
+
`pi_agent.turn.${state.turnIndex}`,
|
|
10749
|
+
{
|
|
10750
|
+
attributes: {
|
|
10751
|
+
"neatlogs.span.kind": "CHAIN",
|
|
10752
|
+
"neatlogs.chain.turn_index": state.turnIndex,
|
|
10753
|
+
...priorInput ? { "input.value": priorInput } : {}
|
|
10754
|
+
}
|
|
10755
|
+
},
|
|
10756
|
+
parent
|
|
10757
|
+
);
|
|
10758
|
+
state.turnSpan = span2;
|
|
10759
|
+
state.turnCtx = import_api19.trace.setSpan(parent, span2);
|
|
10760
|
+
state.turnHasInput = !!priorInput;
|
|
10761
|
+
state.turnStartEpochMs = Date.now();
|
|
10762
|
+
break;
|
|
10763
|
+
}
|
|
10764
|
+
case "turn_end": {
|
|
10765
|
+
if (!state.turnSpan) break;
|
|
10766
|
+
const msg = event.message;
|
|
10767
|
+
const { text, toolCalls } = splitAssistantContent(msg?.content);
|
|
10768
|
+
const out = text || toolCalls.map((tc) => `${tc.name}(${safeStringify12(tc.arguments)})`).join("\n") || terminalSummary(msg);
|
|
10769
|
+
if (out) state.turnSpan.setAttribute("output.value", out);
|
|
10770
|
+
if (Array.isArray(event.toolResults) && event.toolResults.length) {
|
|
10771
|
+
state.turnSpan.setAttribute("neatlogs.chain.tool_result_count", event.toolResults.length);
|
|
10772
|
+
}
|
|
10773
|
+
applyStopReasonStatus(state.turnSpan, msg);
|
|
10774
|
+
state.turnSpan.end();
|
|
10775
|
+
state.turnSpan = void 0;
|
|
10776
|
+
state.turnCtx = void 0;
|
|
10777
|
+
state.turnHasInput = false;
|
|
10778
|
+
state.turnStartEpochMs = void 0;
|
|
10779
|
+
break;
|
|
10780
|
+
}
|
|
10781
|
+
case "message_start": {
|
|
10782
|
+
const msg = event.message;
|
|
10783
|
+
if (!msg || msg.role !== "assistant") break;
|
|
10784
|
+
state.llm = openLlmSpan(tracer, state, msg);
|
|
10785
|
+
break;
|
|
10786
|
+
}
|
|
10787
|
+
case "message_update": {
|
|
10788
|
+
const llm = state.llm;
|
|
10789
|
+
if (!llm) break;
|
|
10790
|
+
llm.span.setAttribute("neatlogs.llm.is_streaming", true);
|
|
10791
|
+
if (llm.ttftMs === void 0 && isContentDelta(event.assistantMessageEvent?.type)) {
|
|
10792
|
+
llm.ttftMs = llm.callStartEpochMs !== void 0 ? Date.now() - llm.callStartEpochMs : nowMs() - llm.startHr;
|
|
10793
|
+
}
|
|
10303
10794
|
break;
|
|
10304
10795
|
}
|
|
10305
10796
|
case "message_end": {
|
|
10306
10797
|
const msg = event.message;
|
|
10307
10798
|
if (!msg) return;
|
|
10308
10799
|
if (msg.role === "assistant") {
|
|
10309
|
-
|
|
10800
|
+
const llm = state.llm ?? openLlmSpan(tracer, state, msg);
|
|
10801
|
+
state.llm = void 0;
|
|
10802
|
+
state.runError = finishLlmSpan(llm, msg) ?? state.runError;
|
|
10310
10803
|
const { text } = splitAssistantContent(msg.content);
|
|
10311
10804
|
if (text) state.inputMessages.push({ role: "assistant", content: text });
|
|
10312
10805
|
} else {
|
|
10313
10806
|
const role = msg.role === "toolResult" ? "tool" : String(msg.role || "user");
|
|
10314
10807
|
const content = messageText(msg);
|
|
10315
|
-
if (content)
|
|
10808
|
+
if (content) {
|
|
10809
|
+
state.inputMessages.push({ role, content });
|
|
10810
|
+
if (role === "user" && state.runInput === void 0) state.runInput = content;
|
|
10811
|
+
if (state.turnSpan && !state.turnHasInput) {
|
|
10812
|
+
state.turnSpan.setAttribute("input.value", content);
|
|
10813
|
+
state.turnHasInput = true;
|
|
10814
|
+
}
|
|
10815
|
+
}
|
|
10316
10816
|
}
|
|
10317
10817
|
break;
|
|
10318
10818
|
}
|
|
10319
10819
|
case "tool_execution_start": {
|
|
10320
|
-
const parent = state.agentCtx ?? getNeatlogsParentContext();
|
|
10820
|
+
const parent = state.turnCtx ?? state.agentCtx ?? getNeatlogsParentContext();
|
|
10321
10821
|
const span2 = tracer.startSpan(
|
|
10322
10822
|
`pi_agent.tool.${event.toolName ?? "tool"}`,
|
|
10323
10823
|
{
|
|
10324
10824
|
attributes: {
|
|
10325
10825
|
"neatlogs.span.kind": "TOOL",
|
|
10326
10826
|
...event.toolName ? { "neatlogs.tool.name": String(event.toolName) } : {},
|
|
10827
|
+
...event.toolCallId ? { "neatlogs.tool.call_id": String(event.toolCallId) } : {},
|
|
10327
10828
|
...event.args !== void 0 ? { "input.value": safeStringify12(event.args) } : {}
|
|
10328
10829
|
}
|
|
10329
10830
|
},
|
|
@@ -10332,6 +10833,12 @@ function handleEvent(tracer, state, event) {
|
|
|
10332
10833
|
if (event.toolCallId) state.toolSpans.set(event.toolCallId, span2);
|
|
10333
10834
|
break;
|
|
10334
10835
|
}
|
|
10836
|
+
case "tool_execution_update": {
|
|
10837
|
+
const span2 = event.toolCallId ? state.toolSpans.get(event.toolCallId) : void 0;
|
|
10838
|
+
if (!span2) break;
|
|
10839
|
+
span2.setAttribute("neatlogs.tool.is_streaming", true);
|
|
10840
|
+
break;
|
|
10841
|
+
}
|
|
10335
10842
|
case "tool_execution_end": {
|
|
10336
10843
|
const span2 = event.toolCallId ? state.toolSpans.get(event.toolCallId) : void 0;
|
|
10337
10844
|
if (!span2) return;
|
|
@@ -10339,7 +10846,7 @@ function handleEvent(tracer, state, event) {
|
|
|
10339
10846
|
span2.setAttribute("output.value", safeStringify12(event.result));
|
|
10340
10847
|
}
|
|
10341
10848
|
if (event.isError) {
|
|
10342
|
-
span2.setStatus({ code: import_api19.SpanStatusCode.ERROR });
|
|
10849
|
+
span2.setStatus({ code: import_api19.SpanStatusCode.ERROR, message: toolErrorText(event.result) });
|
|
10343
10850
|
span2.setAttribute("neatlogs.tool.is_error", true);
|
|
10344
10851
|
} else {
|
|
10345
10852
|
span2.setStatus({ code: import_api19.SpanStatusCode.OK });
|
|
@@ -10351,17 +10858,47 @@ function handleEvent(tracer, state, event) {
|
|
|
10351
10858
|
case "agent_end": {
|
|
10352
10859
|
for (const ts of state.toolSpans.values()) {
|
|
10353
10860
|
try {
|
|
10861
|
+
ts.setStatus({ code: import_api19.SpanStatusCode.ERROR, message: "run ended before tool completed" });
|
|
10354
10862
|
ts.end();
|
|
10355
10863
|
} catch {
|
|
10356
10864
|
}
|
|
10357
10865
|
}
|
|
10358
10866
|
state.toolSpans.clear();
|
|
10867
|
+
if (state.llm) {
|
|
10868
|
+
try {
|
|
10869
|
+
state.llm.span.setAttribute("output.value", "[incomplete] run ended mid-stream");
|
|
10870
|
+
state.llm.span.setStatus({ code: import_api19.SpanStatusCode.ERROR, message: "run ended mid-stream" });
|
|
10871
|
+
state.llm.span.end();
|
|
10872
|
+
} catch {
|
|
10873
|
+
}
|
|
10874
|
+
state.llm = void 0;
|
|
10875
|
+
}
|
|
10876
|
+
if (state.turnSpan) {
|
|
10877
|
+
try {
|
|
10878
|
+
state.turnSpan.end();
|
|
10879
|
+
} catch {
|
|
10880
|
+
}
|
|
10881
|
+
state.turnSpan = void 0;
|
|
10882
|
+
state.turnCtx = void 0;
|
|
10883
|
+
state.turnStartEpochMs = void 0;
|
|
10884
|
+
}
|
|
10359
10885
|
if (state.agentSpan) {
|
|
10360
|
-
const
|
|
10361
|
-
if (
|
|
10886
|
+
const input = state.runInput ?? lastUserTextFrom(event.messages) ?? lastUserTextFrom(getTranscript?.());
|
|
10887
|
+
if (input) state.agentSpan.setAttribute("input.value", input);
|
|
10362
10888
|
const finalText = lastAssistantText(event.messages);
|
|
10363
|
-
|
|
10364
|
-
|
|
10889
|
+
const err = state.runError ?? terminalErrorFrom(event.messages);
|
|
10890
|
+
if (finalText) {
|
|
10891
|
+
state.agentSpan.setAttribute("output.value", finalText);
|
|
10892
|
+
} else if (err) {
|
|
10893
|
+
state.agentSpan.setAttribute("output.value", `[${err.stopReason}]${err.message ? ` ${err.message}` : ""}`);
|
|
10894
|
+
}
|
|
10895
|
+
if (err) {
|
|
10896
|
+
state.agentSpan.setAttribute("neatlogs.agent.stop_reason", err.stopReason);
|
|
10897
|
+
if (err.message) state.agentSpan.setAttribute("neatlogs.error.message", err.message);
|
|
10898
|
+
state.agentSpan.setStatus({ code: import_api19.SpanStatusCode.ERROR, message: err.message ?? err.stopReason });
|
|
10899
|
+
} else {
|
|
10900
|
+
state.agentSpan.setStatus({ code: import_api19.SpanStatusCode.OK });
|
|
10901
|
+
}
|
|
10365
10902
|
state.agentSpan.end();
|
|
10366
10903
|
state.agentSpan = void 0;
|
|
10367
10904
|
state.agentCtx = void 0;
|
|
@@ -10372,55 +10909,158 @@ function handleEvent(tracer, state, event) {
|
|
|
10372
10909
|
break;
|
|
10373
10910
|
}
|
|
10374
10911
|
}
|
|
10375
|
-
function
|
|
10376
|
-
const
|
|
10377
|
-
|
|
10378
|
-
|
|
10379
|
-
|
|
10380
|
-
|
|
10912
|
+
function openLlmSpan(tracer, state, msg) {
|
|
10913
|
+
const parent = state.turnCtx ?? state.agentCtx ?? getNeatlogsParentContext();
|
|
10914
|
+
const startTime = callStartFrom(msg, state.turnStartEpochMs);
|
|
10915
|
+
const span2 = tracer.startSpan(
|
|
10916
|
+
`pi_agent.llm.${msg.model || "model"}`,
|
|
10917
|
+
{
|
|
10918
|
+
...startTime !== void 0 ? { startTime } : {},
|
|
10919
|
+
attributes: {
|
|
10920
|
+
"neatlogs.span.kind": "LLM",
|
|
10921
|
+
// Pi streams by default; message_update deltas confirm it per call.
|
|
10922
|
+
"neatlogs.llm.is_streaming": false,
|
|
10923
|
+
...msg.model ? { "neatlogs.llm.model_name": String(msg.model) } : {},
|
|
10924
|
+
...msg.provider ? { "neatlogs.llm.provider": String(msg.provider) } : {}
|
|
10925
|
+
}
|
|
10926
|
+
},
|
|
10927
|
+
parent
|
|
10928
|
+
);
|
|
10929
|
+
return {
|
|
10930
|
+
span: span2,
|
|
10931
|
+
startHr: nowMs(),
|
|
10932
|
+
callStartEpochMs: startTime,
|
|
10933
|
+
inputMessages: state.inputMessages.slice()
|
|
10934
|
+
};
|
|
10935
|
+
}
|
|
10936
|
+
function callStartFrom(msg, turnStart) {
|
|
10937
|
+
const ts = msg.timestamp;
|
|
10938
|
+
if (typeof ts !== "number" || !Number.isFinite(ts)) return void 0;
|
|
10939
|
+
const now = Date.now();
|
|
10940
|
+
const age = now - ts;
|
|
10941
|
+
if (age < 0 || age > MAX_CALL_AGE_MS) return void 0;
|
|
10942
|
+
return turnStart !== void 0 ? Math.max(ts, turnStart) : ts;
|
|
10943
|
+
}
|
|
10944
|
+
var MAX_CALL_AGE_MS = 30 * 6e4;
|
|
10945
|
+
function terminalSummary(msg) {
|
|
10946
|
+
const reason = msg?.stopReason;
|
|
10947
|
+
if (reason !== "aborted" && reason !== "error") return "";
|
|
10948
|
+
return `[${reason}]${msg?.errorMessage ? ` ${msg.errorMessage}` : ""}`;
|
|
10949
|
+
}
|
|
10950
|
+
function applyStopReasonStatus(span2, msg) {
|
|
10951
|
+
const reason = msg?.stopReason;
|
|
10952
|
+
if (reason === "aborted" || reason === "error") {
|
|
10953
|
+
span2.setStatus({ code: import_api19.SpanStatusCode.ERROR, message: msg?.errorMessage ?? reason });
|
|
10954
|
+
} else {
|
|
10955
|
+
span2.setStatus({ code: import_api19.SpanStatusCode.OK });
|
|
10956
|
+
}
|
|
10957
|
+
}
|
|
10958
|
+
function isContentDelta(type) {
|
|
10959
|
+
return type === "text_delta" || type === "thinking_delta" || type === "toolcall_delta";
|
|
10960
|
+
}
|
|
10961
|
+
function nowMs() {
|
|
10962
|
+
const p = globalThis.performance;
|
|
10963
|
+
return typeof p?.now === "function" ? p.now() : Date.now();
|
|
10964
|
+
}
|
|
10965
|
+
function toolErrorText(result) {
|
|
10966
|
+
if (!result || typeof result !== "object") return "tool error";
|
|
10967
|
+
const content = result.content;
|
|
10968
|
+
if (Array.isArray(content)) {
|
|
10969
|
+
const text = content.map((b) => typeof b?.text === "string" ? b.text : "").filter(Boolean).join(" ").trim();
|
|
10970
|
+
if (text) return text;
|
|
10971
|
+
}
|
|
10972
|
+
return "tool error";
|
|
10973
|
+
}
|
|
10974
|
+
function lastUserTextFrom(messages) {
|
|
10975
|
+
if (!Array.isArray(messages)) return void 0;
|
|
10976
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
10977
|
+
const m = messages[i];
|
|
10978
|
+
if (m && m.role === "user") {
|
|
10979
|
+
const text = messageText(m);
|
|
10980
|
+
if (text) return text;
|
|
10981
|
+
}
|
|
10982
|
+
}
|
|
10983
|
+
return void 0;
|
|
10984
|
+
}
|
|
10985
|
+
function terminalErrorFrom(messages) {
|
|
10986
|
+
if (!Array.isArray(messages)) return void 0;
|
|
10987
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
10988
|
+
const m = messages[i];
|
|
10989
|
+
if (m && m.role === "assistant") {
|
|
10990
|
+
if (m.stopReason === "aborted" || m.stopReason === "error") {
|
|
10991
|
+
return { stopReason: m.stopReason, message: m.errorMessage };
|
|
10992
|
+
}
|
|
10993
|
+
return void 0;
|
|
10994
|
+
}
|
|
10995
|
+
}
|
|
10996
|
+
return void 0;
|
|
10997
|
+
}
|
|
10998
|
+
function finishLlmSpan(llm, msg, endTime) {
|
|
10999
|
+
const span2 = llm.span;
|
|
11000
|
+
if (msg.model) span2.setAttribute("neatlogs.llm.model_name", String(msg.model));
|
|
11001
|
+
if (msg.provider) span2.setAttribute("neatlogs.llm.provider", String(msg.provider));
|
|
11002
|
+
if (msg.responseModel) span2.setAttribute("neatlogs.llm.response_model", String(msg.responseModel));
|
|
11003
|
+
if (msg.api) span2.setAttribute("neatlogs.llm.api", String(msg.api));
|
|
11004
|
+
if (msg.stopReason) span2.setAttribute("neatlogs.llm.stop_reason", String(msg.stopReason));
|
|
11005
|
+
const inMsgs = llm.inputMessages;
|
|
10381
11006
|
if (inMsgs.length) {
|
|
10382
11007
|
inMsgs.forEach((m, i) => {
|
|
10383
|
-
|
|
10384
|
-
|
|
11008
|
+
span2.setAttribute(`neatlogs.llm.input_messages.${i}.role`, m.role);
|
|
11009
|
+
span2.setAttribute(`neatlogs.llm.input_messages.${i}.content`, m.content);
|
|
10385
11010
|
});
|
|
10386
|
-
|
|
10387
|
-
|
|
11011
|
+
const inBlob = safeStringify12({ messages: inMsgs });
|
|
11012
|
+
span2.setAttribute("neatlogs.llm.input", inBlob);
|
|
11013
|
+
span2.setAttribute("input.value", inBlob);
|
|
10388
11014
|
}
|
|
10389
11015
|
const { text, toolCalls } = splitAssistantContent(msg.content);
|
|
10390
|
-
const outText = text || toolCalls.map((tc) => `${tc.name}(${safeStringify12(tc.arguments)})`).join("\n");
|
|
11016
|
+
const outText = text || toolCalls.map((tc) => `${tc.name}(${safeStringify12(tc.arguments)})`).join("\n") || terminalSummary(msg);
|
|
10391
11017
|
if (outText || toolCalls.length) {
|
|
10392
|
-
|
|
10393
|
-
|
|
11018
|
+
span2.setAttribute("neatlogs.llm.output_messages.0.role", "assistant");
|
|
11019
|
+
span2.setAttribute("neatlogs.llm.output_messages.0.content", outText || "");
|
|
10394
11020
|
const outBlob = { role: "assistant", content: outText || "" };
|
|
10395
11021
|
if (toolCalls.length) {
|
|
10396
11022
|
outBlob.tool_calls = toolCalls.map((tc) => ({ name: tc.name, arguments: tc.arguments }));
|
|
10397
11023
|
toolCalls.forEach((tc, j) => {
|
|
10398
|
-
if (tc.name)
|
|
11024
|
+
if (tc.name) span2.setAttribute(`neatlogs.llm.tool_calls.${j}.name`, tc.name);
|
|
10399
11025
|
if (tc.arguments !== void 0)
|
|
10400
|
-
|
|
10401
|
-
if (tc.id)
|
|
11026
|
+
span2.setAttribute(`neatlogs.llm.tool_calls.${j}.arguments`, safeStringify12(tc.arguments));
|
|
11027
|
+
if (tc.id) span2.setAttribute(`neatlogs.llm.tool_calls.${j}.id`, String(tc.id));
|
|
10402
11028
|
});
|
|
10403
11029
|
}
|
|
10404
|
-
|
|
10405
|
-
|
|
11030
|
+
span2.setAttribute("neatlogs.llm.output", safeStringify12(outBlob));
|
|
11031
|
+
span2.setAttribute("output.value", outText || "");
|
|
10406
11032
|
}
|
|
10407
11033
|
const usage = msg.usage;
|
|
10408
11034
|
if (usage) {
|
|
10409
|
-
if (usage.input != null)
|
|
10410
|
-
if (usage.output != null)
|
|
11035
|
+
if (usage.input != null) span2.setAttribute("neatlogs.llm.token_count.prompt", usage.input);
|
|
11036
|
+
if (usage.output != null) span2.setAttribute("neatlogs.llm.token_count.completion", usage.output);
|
|
10411
11037
|
const total = usage.totalTokens ?? (usage.input ?? 0) + (usage.output ?? 0);
|
|
10412
|
-
if (total)
|
|
10413
|
-
if (usage.cacheRead)
|
|
10414
|
-
if (usage.cacheWrite)
|
|
11038
|
+
if (total) span2.setAttribute("neatlogs.llm.token_count.total", total);
|
|
11039
|
+
if (usage.cacheRead) span2.setAttribute("neatlogs.llm.token_count.cache_read", usage.cacheRead);
|
|
11040
|
+
if (usage.cacheWrite) span2.setAttribute("neatlogs.llm.token_count.cache_write", usage.cacheWrite);
|
|
11041
|
+
const cost = usage.cost;
|
|
11042
|
+
if (cost) {
|
|
11043
|
+
const totalCost = cost.total ?? [cost.input, cost.output, cacheReadOf(cost), cost.cacheWrite].reduce(
|
|
11044
|
+
(sum, v) => sum + (typeof v === "number" ? v : 0),
|
|
11045
|
+
0
|
|
11046
|
+
);
|
|
11047
|
+
if (typeof totalCost === "number" && totalCost > 0) {
|
|
11048
|
+
span2.setAttribute("neatlogs.llm.cost_usd", totalCost);
|
|
11049
|
+
}
|
|
11050
|
+
if (typeof cost.input === "number") span2.setAttribute("neatlogs.llm.cost.prompt", cost.input);
|
|
11051
|
+
if (typeof cost.output === "number") span2.setAttribute("neatlogs.llm.cost.completion", cost.output);
|
|
11052
|
+
}
|
|
10415
11053
|
}
|
|
10416
|
-
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
|
|
10420
|
-
|
|
10421
|
-
);
|
|
10422
|
-
|
|
10423
|
-
|
|
11054
|
+
if (llm.ttftMs !== void 0) {
|
|
11055
|
+
span2.setAttribute("neatlogs.llm.metrics.ttft_ms", Math.round(llm.ttftMs));
|
|
11056
|
+
}
|
|
11057
|
+
if (msg.errorMessage) span2.setAttribute("neatlogs.error.message", String(msg.errorMessage));
|
|
11058
|
+
applyStopReasonStatus(span2, msg);
|
|
11059
|
+
span2.end(endTime);
|
|
11060
|
+
return msg.stopReason === "aborted" || msg.stopReason === "error" ? { stopReason: msg.stopReason, message: msg.errorMessage } : void 0;
|
|
11061
|
+
}
|
|
11062
|
+
function cacheReadOf(cost) {
|
|
11063
|
+
return typeof cost.cacheRead === "number" ? cost.cacheRead : cost.cacheReads;
|
|
10424
11064
|
}
|
|
10425
11065
|
function splitAssistantContent(content) {
|
|
10426
11066
|
const texts = [];
|
|
@@ -11652,7 +12292,7 @@ function handleEvent2(shipper, sessions, stateFor, startRoot, closeAndFlush, eve
|
|
|
11652
12292
|
if (st.processed.has(id)) return void 0;
|
|
11653
12293
|
st.processed.add(id);
|
|
11654
12294
|
startRoot(st, String(sessionID));
|
|
11655
|
-
|
|
12295
|
+
emitLlmSpan(shipper, st, info, String(sessionID));
|
|
11656
12296
|
return shipper.flush().catch(() => void 0);
|
|
11657
12297
|
}
|
|
11658
12298
|
if (type === "session.idle" || type === "session.deleted") {
|
|
@@ -11667,7 +12307,7 @@ function handleEvent2(shipper, sessions, stateFor, startRoot, closeAndFlush, eve
|
|
|
11667
12307
|
}
|
|
11668
12308
|
return void 0;
|
|
11669
12309
|
}
|
|
11670
|
-
function
|
|
12310
|
+
function emitLlmSpan(shipper, st, info, sessionID) {
|
|
11671
12311
|
if (!st.traceId) return;
|
|
11672
12312
|
const model = info?.modelID ?? info?.model ?? "";
|
|
11673
12313
|
const provider = info?.providerID ?? info?.provider ?? "";
|
|
@@ -11864,6 +12504,8 @@ function bindTemplates(llm, systemTpl, userTpl, compiledVars) {
|
|
|
11864
12504
|
span,
|
|
11865
12505
|
strandsHooks,
|
|
11866
12506
|
trace,
|
|
12507
|
+
tracePiAgentEvents,
|
|
12508
|
+
tracePiStream,
|
|
11867
12509
|
traceToolAnthropic,
|
|
11868
12510
|
traceToolAzureOpenAI,
|
|
11869
12511
|
traceToolBedrock,
|