@ramarivera/coding-agent-langfuse 0.1.24 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/backfill.js +32 -4
  2. package/package.json +1 -1
package/dist/backfill.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { execFileSync } from "node:child_process";
3
3
  import { createHash } from "node:crypto";
4
- import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync, } from "node:fs";
5
- import { homedir } from "node:os";
4
+ import { existsSync, mkdirSync, renameSync, readdirSync, readFileSync, statSync, writeFileSync, } from "node:fs";
5
+ import { hostname, homedir } from "node:os";
6
6
  import { dirname, join } from "node:path";
7
7
  const allAgents = ["claude", "codex", "grok", "opencode", "pi"];
8
8
  const importIdentityVersion = "v8-cached-input-token-split";
@@ -16,6 +16,7 @@ const importIdentityVersions = {
16
16
  const defaultEndpoint = "https://langfuse.ai.roxasroot.net/otel/v1/traces";
17
17
  const deadRemoteEndpoint = "http://langfuse.ai.roxasroot.net:14318/v1/traces";
18
18
  const defaultStatePath = join(homedir(), ".local/state/coding-agent-langfuse/backfill-v6.json");
19
+ const currentHost = hostname();
19
20
  function usage() {
20
21
  return `Usage: coding-agent-langfuse-backfill [options]
21
22
 
@@ -157,7 +158,9 @@ function loadState(path) {
157
158
  }
158
159
  function saveState(path, state) {
159
160
  mkdirSync(dirname(path), { recursive: true });
160
- writeFileSync(path, `${JSON.stringify(state, null, 2)}\n`);
161
+ const tempPath = `${path}.${process.pid}.tmp`;
162
+ writeFileSync(tempPath, `${JSON.stringify(state, null, 2)}\n`);
163
+ renameSync(tempPath, path);
161
164
  }
162
165
  function listFiles(root, predicate) {
163
166
  if (!existsSync(root))
@@ -566,6 +569,7 @@ function claudeEvents(homeDir) {
566
569
  return genericJsonlEvents("claude", files, "claude session");
567
570
  }
568
571
  function piEvents(homeDir) {
572
+ const seenMessageIds = new Set();
569
573
  const files = [
570
574
  ...listFiles(join(homeDir, ".pi/agent/sessions"), (path) => path.endsWith(".jsonl")),
571
575
  ...listFiles(join(homeDir, ".pi/agent"), (path) => path.endsWith("run-history.jsonl")),
@@ -594,7 +598,14 @@ function piEvents(homeDir) {
594
598
  const message = asRecord(row.message);
595
599
  const usage = normalizeUsage(message.usage);
596
600
  const role = asString(message.role);
597
- const messageId = asString(row.id) ?? `message-${index}`;
601
+ const explicitMessageId = asString(row.id);
602
+ const messageId = explicitMessageId ?? `message-${stableId(path)}-${index}`;
603
+ const dedupeKey = explicitMessageId === undefined
604
+ ? `${path}:${messageId}`
605
+ : explicitMessageId;
606
+ if (seenMessageIds.has(dedupeKey))
607
+ continue;
608
+ seenMessageIds.add(dedupeKey);
598
609
  const toolCallId = asString(message.toolCallId);
599
610
  events.push({
600
611
  agent: "pi",
@@ -1140,16 +1151,24 @@ function toOtlp(events) {
1140
1151
  attr("session.id", first.sessionId),
1141
1152
  attr("langfuse.observation.type", "span"),
1142
1153
  attr("agent.name", first.agent),
1154
+ attr("host.name", currentHost),
1143
1155
  attr("agent.session_id", first.sessionId),
1144
1156
  attr("agent.record_id", "session-root"),
1145
1157
  attr("agent.event_count", sortedEvents.length),
1146
1158
  attr("langfuse.trace.metadata.agent", first.agent),
1159
+ attr("langfuse.trace.metadata.host", currentHost),
1160
+ attr("langfuse.trace.metadata.machine", currentHost),
1147
1161
  attr("langfuse.trace.metadata.source_path", first.sourcePath),
1148
1162
  attr("langfuse.trace.metadata.cwd", first.cwd),
1149
1163
  attr("langfuse.trace.input", firstInputEvent?.input),
1150
1164
  attr("langfuse.trace.output", lastOutputEvent?.output),
1151
1165
  attr("langfuse.observation.metadata.agent", first.agent),
1166
+ attr("langfuse.observation.metadata.host", currentHost),
1167
+ attr("langfuse.observation.metadata.machine", currentHost),
1168
+ attr("langfuse.observation.metadata.session_id", first.sessionId),
1152
1169
  attr("langfuse.observation.metadata.record_id", "session-root"),
1170
+ attr("langfuse.observation.metadata.source_path", first.sourcePath),
1171
+ attr("langfuse.observation.metadata.cwd", first.cwd),
1153
1172
  attr("source.path", first.sourcePath),
1154
1173
  attr("cwd", first.cwd),
1155
1174
  ].filter((item) => Boolean(item));
@@ -1196,16 +1215,25 @@ function toOtlp(events) {
1196
1215
  attr("gen_ai.usage.total_tokens", usage?.total),
1197
1216
  attr("gen_ai.usage.cost", cost?.total),
1198
1217
  attr("agent.name", event.agent),
1218
+ attr("host.name", currentHost),
1199
1219
  attr("agent.session_id", event.sessionId),
1200
1220
  attr("agent.record_id", event.recordId),
1201
1221
  attr("agent.original_start_time", new Date(event.startMs).toISOString()),
1202
1222
  attr("agent.original_end_time", event.endMs === undefined ? undefined : new Date(event.endMs).toISOString()),
1203
1223
  attr("langfuse.trace.metadata.agent", event.agent),
1224
+ attr("langfuse.trace.metadata.host", currentHost),
1225
+ attr("langfuse.trace.metadata.machine", currentHost),
1204
1226
  attr("langfuse.trace.metadata.source_path", event.sourcePath),
1227
+ attr("langfuse.trace.metadata.cwd", event.cwd),
1205
1228
  attr("langfuse.trace.metadata.model", event.model),
1206
1229
  attr("langfuse.trace.metadata.provider", event.provider),
1207
1230
  attr("langfuse.observation.metadata.agent", event.agent),
1231
+ attr("langfuse.observation.metadata.host", currentHost),
1232
+ attr("langfuse.observation.metadata.machine", currentHost),
1233
+ attr("langfuse.observation.metadata.session_id", event.sessionId),
1208
1234
  attr("langfuse.observation.metadata.record_id", event.recordId),
1235
+ attr("langfuse.observation.metadata.source_path", event.sourcePath),
1236
+ attr("langfuse.observation.metadata.cwd", event.cwd),
1209
1237
  attr("langfuse.observation.metadata.model", modelName ?? event.model),
1210
1238
  attr("langfuse.observation.metadata.provider", event.provider),
1211
1239
  attr("langfuse.observation.metadata.cost_source", cost?.source),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramarivera/coding-agent-langfuse",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "Universal coding-agent Langfuse backfiller and live OTLP helpers",
5
5
  "type": "module",
6
6
  "license": "MIT",