@ramarivera/coding-agent-langfuse 0.1.17 → 0.1.18
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/backfill.js +87 -12
- package/package.json +1 -1
package/dist/backfill.js
CHANGED
|
@@ -5,7 +5,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSy
|
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
const allAgents = ["claude", "codex", "grok", "opencode", "pi"];
|
|
8
|
-
const importIdentityVersion = "
|
|
8
|
+
const importIdentityVersion = "v9-codex-conversation-events";
|
|
9
9
|
const defaultEndpoint = "https://langfuse.ai.roxasroot.net/otel/v1/traces";
|
|
10
10
|
const deadRemoteEndpoint = "http://langfuse.ai.roxasroot.net:14318/v1/traces";
|
|
11
11
|
const defaultStatePath = join(homedir(), ".local/state/coding-agent-langfuse/backfill-v6.json");
|
|
@@ -229,7 +229,10 @@ function extractText(value, maxLength = 4000) {
|
|
|
229
229
|
const text = value
|
|
230
230
|
.map((item) => {
|
|
231
231
|
const record = asRecord(item);
|
|
232
|
-
return asString(record.text) ??
|
|
232
|
+
return asString(record.text) ??
|
|
233
|
+
extractText(record.content, maxLength) ??
|
|
234
|
+
extractText(record.summary, maxLength) ??
|
|
235
|
+
"";
|
|
233
236
|
})
|
|
234
237
|
.filter(Boolean)
|
|
235
238
|
.join("\n");
|
|
@@ -363,7 +366,8 @@ function costDetails(usage, model) {
|
|
|
363
366
|
return undefined;
|
|
364
367
|
}
|
|
365
368
|
function isGenerationEvent(event) {
|
|
366
|
-
return event.usage !== undefined && event.role !== "user"
|
|
369
|
+
return event.usage !== undefined && event.role !== "user" &&
|
|
370
|
+
event.role !== "developer" && event.role !== "system";
|
|
367
371
|
}
|
|
368
372
|
function codexEvents(homeDir) {
|
|
369
373
|
const files = listFiles(join(homeDir, ".codex/sessions"), (path) => path.endsWith(".jsonl"));
|
|
@@ -378,6 +382,7 @@ function codexEvents(homeDir) {
|
|
|
378
382
|
asString(getPath(payload, ["model"]));
|
|
379
383
|
let currentModel = model;
|
|
380
384
|
let currentCwd = cwd;
|
|
385
|
+
let currentTurnRecordId = "session";
|
|
381
386
|
const seenTokenCounts = new Set();
|
|
382
387
|
const events = [
|
|
383
388
|
{
|
|
@@ -406,11 +411,12 @@ function codexEvents(homeDir) {
|
|
|
406
411
|
if (type === "turn_context") {
|
|
407
412
|
currentModel = asString(rowPayload.model) ?? currentModel;
|
|
408
413
|
currentCwd = asString(rowPayload.cwd) ?? currentCwd;
|
|
414
|
+
currentTurnRecordId = `turn-${asString(rowPayload.turn_id) ?? index}`;
|
|
409
415
|
events.push({
|
|
410
416
|
agent: "codex",
|
|
411
417
|
sourcePath: path,
|
|
412
418
|
sessionId,
|
|
413
|
-
recordId:
|
|
419
|
+
recordId: currentTurnRecordId,
|
|
414
420
|
name: "codex turn",
|
|
415
421
|
cwd: currentCwd,
|
|
416
422
|
model: currentModel,
|
|
@@ -420,34 +426,99 @@ function codexEvents(homeDir) {
|
|
|
420
426
|
});
|
|
421
427
|
}
|
|
422
428
|
if (type === "response_item" && itemType === "message") {
|
|
429
|
+
const role = asString(rowPayload.role);
|
|
430
|
+
const text = extractText(rowPayload.content);
|
|
431
|
+
const input = role === "user" || role === "developer" ||
|
|
432
|
+
role === "system"
|
|
433
|
+
? text
|
|
434
|
+
: undefined;
|
|
435
|
+
const output = role === "assistant" ? text : undefined;
|
|
423
436
|
events.push({
|
|
424
437
|
agent: "codex",
|
|
425
438
|
sourcePath: path,
|
|
426
439
|
sessionId,
|
|
427
440
|
recordId: `message-${asString(rowPayload.id) ?? index}`,
|
|
428
|
-
name: `codex ${
|
|
429
|
-
role
|
|
441
|
+
name: `codex ${role ?? "message"}`,
|
|
442
|
+
role,
|
|
430
443
|
model: currentModel,
|
|
431
444
|
cwd: currentCwd,
|
|
432
445
|
startMs: timestamp,
|
|
433
|
-
parentRecordId:
|
|
434
|
-
|
|
446
|
+
parentRecordId: currentTurnRecordId,
|
|
447
|
+
input,
|
|
448
|
+
output,
|
|
435
449
|
usage: normalizeUsage(rowPayload.usage),
|
|
450
|
+
metadata: pick(rowPayload, ["phase"]),
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
if (type === "response_item" && itemType === "reasoning") {
|
|
454
|
+
events.push({
|
|
455
|
+
agent: "codex",
|
|
456
|
+
sourcePath: path,
|
|
457
|
+
sessionId,
|
|
458
|
+
recordId: `reasoning-${index}`,
|
|
459
|
+
name: "codex reasoning",
|
|
460
|
+
model: currentModel,
|
|
461
|
+
cwd: currentCwd,
|
|
462
|
+
startMs: timestamp,
|
|
463
|
+
parentRecordId: currentTurnRecordId,
|
|
464
|
+
output: extractText(rowPayload.content) ??
|
|
465
|
+
extractText(rowPayload.summary),
|
|
466
|
+
metadata: {
|
|
467
|
+
has_encrypted_content: rowPayload.encrypted_content !== undefined,
|
|
468
|
+
},
|
|
436
469
|
});
|
|
437
470
|
}
|
|
438
471
|
if (type === "response_item" && itemType === "function_call") {
|
|
472
|
+
const callId = asString(rowPayload.call_id) ?? `${index}`;
|
|
439
473
|
events.push({
|
|
440
474
|
agent: "codex",
|
|
441
475
|
sourcePath: path,
|
|
442
476
|
sessionId,
|
|
443
|
-
recordId: `tool-${
|
|
477
|
+
recordId: `tool-${callId}`,
|
|
444
478
|
name: `codex tool ${asString(rowPayload.name) ?? "call"}`,
|
|
445
479
|
model: currentModel,
|
|
446
480
|
cwd: currentCwd,
|
|
447
481
|
startMs: timestamp,
|
|
448
|
-
parentRecordId:
|
|
482
|
+
parentRecordId: currentTurnRecordId,
|
|
449
483
|
input: rowPayload.arguments,
|
|
450
|
-
metadata: pick(rowPayload, ["name", "call_id"]),
|
|
484
|
+
metadata: pick(rowPayload, ["name", "namespace", "call_id"]),
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
if (type === "response_item" && itemType === "function_call_output") {
|
|
488
|
+
const callId = asString(rowPayload.call_id) ?? `${index}`;
|
|
489
|
+
events.push({
|
|
490
|
+
agent: "codex",
|
|
491
|
+
sourcePath: path,
|
|
492
|
+
sessionId,
|
|
493
|
+
recordId: `tool-result-${callId}`,
|
|
494
|
+
name: "codex tool result",
|
|
495
|
+
model: currentModel,
|
|
496
|
+
cwd: currentCwd,
|
|
497
|
+
startMs: timestamp,
|
|
498
|
+
parentRecordId: `tool-${callId}`,
|
|
499
|
+
output: rowPayload.output,
|
|
500
|
+
metadata: pick(rowPayload, ["call_id", "status", "execution"]),
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
if (type === "response_item" &&
|
|
504
|
+
(itemType === "tool_search_call" || itemType === "tool_search_output")) {
|
|
505
|
+
const callId = asString(rowPayload.call_id) ?? `${index}`;
|
|
506
|
+
const isOutput = itemType === "tool_search_output";
|
|
507
|
+
events.push({
|
|
508
|
+
agent: "codex",
|
|
509
|
+
sourcePath: path,
|
|
510
|
+
sessionId,
|
|
511
|
+
recordId: `${isOutput ? "tool-search-result" : "tool-search"}-${callId}`,
|
|
512
|
+
name: isOutput ? "codex tool_search result" : "codex tool_search",
|
|
513
|
+
model: currentModel,
|
|
514
|
+
cwd: currentCwd,
|
|
515
|
+
startMs: timestamp,
|
|
516
|
+
parentRecordId: isOutput
|
|
517
|
+
? `tool-search-${callId}`
|
|
518
|
+
: currentTurnRecordId,
|
|
519
|
+
input: isOutput ? undefined : rowPayload.arguments,
|
|
520
|
+
output: isOutput ? rowPayload.tools : undefined,
|
|
521
|
+
metadata: pick(rowPayload, ["call_id", "status", "execution"]),
|
|
451
522
|
});
|
|
452
523
|
}
|
|
453
524
|
if (type === "event_msg" && rowPayload.type === "token_count") {
|
|
@@ -862,6 +933,7 @@ function toOtlp(events) {
|
|
|
862
933
|
attributes: rootAttributes,
|
|
863
934
|
status: { code: 1 },
|
|
864
935
|
};
|
|
936
|
+
const spanIdsByRecordId = new Map(sortedEvents.map((event) => [event.recordId, spanId(event)]));
|
|
865
937
|
const childSpans = sortedEvents.map((event) => {
|
|
866
938
|
const startMs = event.startMs;
|
|
867
939
|
const durationMs = Math.max(1, (event.endMs ?? event.startMs + 1) - event.startMs);
|
|
@@ -923,7 +995,10 @@ function toOtlp(events) {
|
|
|
923
995
|
return {
|
|
924
996
|
traceId: traceId(event),
|
|
925
997
|
spanId: spanId(event),
|
|
926
|
-
parentSpanId:
|
|
998
|
+
parentSpanId: event.parentRecordId &&
|
|
999
|
+
event.parentRecordId !== "session"
|
|
1000
|
+
? spanIdsByRecordId.get(event.parentRecordId) ?? rootSpanId(event)
|
|
1001
|
+
: rootSpanId(event),
|
|
927
1002
|
name: event.name,
|
|
928
1003
|
kind: 1,
|
|
929
1004
|
startTimeUnixNano: ns(startMs),
|