@ramarivera/coding-agent-langfuse 0.1.39 → 0.1.40
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/README.md +4 -4
- package/bin/coding-agent-langfuse.mjs +0 -0
- package/dist/backfill.js +2 -65
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
Universal coding-agent Langfuse backfiller and OTLP exporter helpers.
|
|
4
4
|
|
|
5
5
|
It imports local histories from Codex, Claude Code, Grok, OpenCode, and Pi into
|
|
6
|
-
Langfuse as session traces with child observations. LLM usage records are
|
|
7
|
-
as
|
|
8
|
-
|
|
6
|
+
Langfuse as session traces with child observations. LLM usage records are kept
|
|
7
|
+
as observation metadata so historical imports do not create Langfuse billing or
|
|
8
|
+
cost rows. Tool calls remain child spans under the same session.
|
|
9
9
|
|
|
10
10
|
```sh
|
|
11
11
|
coding-agent-langfuse-backfill --agents codex,claude,grok,pi,opencode
|
|
@@ -112,7 +112,7 @@ npm run test:e2e
|
|
|
112
112
|
The e2e suite verifies:
|
|
113
113
|
|
|
114
114
|
- Codex full session traces with messages, reasoning, tool calls, tool results,
|
|
115
|
-
usage
|
|
115
|
+
and usage metadata
|
|
116
116
|
- Follow mode picking up newly written Codex events
|
|
117
117
|
- One CLI run posting reconstructable traces for Claude Code, Codex, Grok,
|
|
118
118
|
OpenCode, and Pi
|
|
File without changes
|
package/dist/backfill.js
CHANGED
|
@@ -374,53 +374,6 @@ function usageDetails(usage) {
|
|
|
374
374
|
details.total = usage.total;
|
|
375
375
|
return Object.keys(details).length > 0 ? details : undefined;
|
|
376
376
|
}
|
|
377
|
-
function pricingForModel(model) {
|
|
378
|
-
if (!model)
|
|
379
|
-
return undefined;
|
|
380
|
-
const normalized = normalizeModelName(model) ?? model;
|
|
381
|
-
if (normalized === "kimi-for-coding") {
|
|
382
|
-
return { input: 0.95, output: 4.0, cacheRead: 0.16, cacheWrite: 0 };
|
|
383
|
-
}
|
|
384
|
-
if (normalized.includes("accounts/fireworks/routers/kimi-k2p6-turbo")) {
|
|
385
|
-
return { input: 2.0, output: 8.0, cacheRead: 0.30, cacheWrite: 0 };
|
|
386
|
-
}
|
|
387
|
-
if (normalized.includes("accounts/fireworks/models/deepseek-v4-pro")) {
|
|
388
|
-
return { input: 1.74, output: 3.48, cacheRead: 0.15, cacheWrite: 0 };
|
|
389
|
-
}
|
|
390
|
-
if (normalized.includes("DeepSeek-V4-Pro")) {
|
|
391
|
-
return { input: 2.1, output: 4.4, cacheRead: 0.2, cacheWrite: 0 };
|
|
392
|
-
}
|
|
393
|
-
if (normalized.includes("Kimi-K2.6")) {
|
|
394
|
-
return { input: 1.2, output: 4.5, cacheRead: 0.2, cacheWrite: 0 };
|
|
395
|
-
}
|
|
396
|
-
if (normalized.includes("MiniMax-M2.7")) {
|
|
397
|
-
return { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 };
|
|
398
|
-
}
|
|
399
|
-
return undefined;
|
|
400
|
-
}
|
|
401
|
-
function costDetails(usage, model) {
|
|
402
|
-
if (!usage)
|
|
403
|
-
return undefined;
|
|
404
|
-
const rates = pricingForModel(model);
|
|
405
|
-
if (rates) {
|
|
406
|
-
const cachedInput = usage.cacheRead ?? 0;
|
|
407
|
-
const cacheWriteTokens = usage.cacheWrite ?? 0;
|
|
408
|
-
const regularInput = Math.max((usage.input ?? 0) - cachedInput - cacheWriteTokens, 0);
|
|
409
|
-
const input = (regularInput * rates.input) / 1_000_000;
|
|
410
|
-
const output = (((usage.output ?? 0) + (usage.reasoning ?? 0)) * rates.output) /
|
|
411
|
-
1_000_000;
|
|
412
|
-
const cache_read = (cachedInput * rates.cacheRead) / 1_000_000;
|
|
413
|
-
const cache_write = (cacheWriteTokens * rates.cacheWrite) / 1_000_000;
|
|
414
|
-
const total = input + output + cache_read + cache_write;
|
|
415
|
-
if (total > 0) {
|
|
416
|
-
return { input, output, cache_read, cache_write, total, source: "estimated" };
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
if (usage.cost !== undefined && usage.cost > 0) {
|
|
420
|
-
return { total: usage.cost, source: "recorded" };
|
|
421
|
-
}
|
|
422
|
-
return undefined;
|
|
423
|
-
}
|
|
424
377
|
function isGenerationEvent(event) {
|
|
425
378
|
return event.usage !== undefined && event.role !== "user" &&
|
|
426
379
|
event.role !== "developer" && event.role !== "system";
|
|
@@ -1271,17 +1224,7 @@ function toOtlp(events, options = {}) {
|
|
|
1271
1224
|
const modelName = normalizeModelName(event.model);
|
|
1272
1225
|
const generation = isGenerationEvent(event);
|
|
1273
1226
|
const usage = usageDetails(event.usage);
|
|
1274
|
-
const cost = costDetails(event.usage, modelName);
|
|
1275
1227
|
const eventProject = projectMetadata(event.cwd);
|
|
1276
|
-
const costForLangfuse = cost === undefined
|
|
1277
|
-
? undefined
|
|
1278
|
-
: {
|
|
1279
|
-
...(cost.input !== undefined ? { input: cost.input } : {}),
|
|
1280
|
-
...(cost.output !== undefined ? { output: cost.output } : {}),
|
|
1281
|
-
...(cost.cache_read !== undefined ? { cache_read: cost.cache_read } : {}),
|
|
1282
|
-
...(cost.cache_write !== undefined ? { cache_write: cost.cache_write } : {}),
|
|
1283
|
-
total: cost.total,
|
|
1284
|
-
};
|
|
1285
1228
|
const attributes = [
|
|
1286
1229
|
attr("service.name", `agent.${event.agent}`),
|
|
1287
1230
|
attr("deployment.environment", "local"),
|
|
@@ -1290,13 +1233,6 @@ function toOtlp(events, options = {}) {
|
|
|
1290
1233
|
attr("session.id", event.sessionId),
|
|
1291
1234
|
attr("langfuse.observation.type", generation ? "generation" : "span"),
|
|
1292
1235
|
attr("langfuse.observation.model.name", generation ? modelName : undefined),
|
|
1293
|
-
attr("langfuse.observation.usage_details", usage),
|
|
1294
|
-
attr("langfuse.observation.cost_details", costForLangfuse),
|
|
1295
|
-
attr("gen_ai.response.model", generation ? modelName : undefined),
|
|
1296
|
-
attr("gen_ai.usage.input_tokens", usage?.input),
|
|
1297
|
-
attr("gen_ai.usage.output_tokens", usage?.output),
|
|
1298
|
-
attr("gen_ai.usage.total_tokens", usage?.total),
|
|
1299
|
-
attr("gen_ai.usage.cost", cost?.total),
|
|
1300
1236
|
attr("agent.name", event.agent),
|
|
1301
1237
|
attr("host.name", currentHost),
|
|
1302
1238
|
attr("agent.session_id", event.sessionId),
|
|
@@ -1315,7 +1251,8 @@ function toOtlp(events, options = {}) {
|
|
|
1315
1251
|
attr("langfuse.observation.metadata.project_folder", eventProject.projectFolder),
|
|
1316
1252
|
attr("langfuse.observation.metadata.model", modelName ?? event.model),
|
|
1317
1253
|
attr("langfuse.observation.metadata.provider", event.provider),
|
|
1318
|
-
attr("langfuse.observation.metadata.
|
|
1254
|
+
attr("langfuse.observation.metadata.usage_details", usage),
|
|
1255
|
+
attr("langfuse.observation.metadata.recorded_cost", event.usage?.cost),
|
|
1319
1256
|
attr("langfuse.observation.input", event.input),
|
|
1320
1257
|
attr("langfuse.observation.output", event.output),
|
|
1321
1258
|
attr("source.path", event.sourcePath),
|