@ramarivera/coding-agent-langfuse 0.1.19 → 0.1.20

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 +87 -20
  2. package/package.json +1 -1
package/dist/backfill.js CHANGED
@@ -7,8 +7,11 @@ import { dirname, join } from "node:path";
7
7
  const allAgents = ["claude", "codex", "grok", "opencode", "pi"];
8
8
  const importIdentityVersion = "v8-cached-input-token-split";
9
9
  const importIdentityVersions = {
10
+ claude: "v11-tool-results",
10
11
  codex: "v9-codex-conversation-events",
12
+ grok: "v11-chat-history-only",
11
13
  opencode: "v10-opencode-message-parts",
14
+ pi: "v11-tool-results",
12
15
  };
13
16
  const defaultEndpoint = "https://langfuse.ai.roxasroot.net/otel/v1/traces";
14
17
  const deadRemoteEndpoint = "http://langfuse.ai.roxasroot.net:14318/v1/traces";
@@ -590,33 +593,56 @@ function piEvents(homeDir) {
590
593
  continue;
591
594
  const message = asRecord(row.message);
592
595
  const usage = normalizeUsage(message.usage);
596
+ const role = asString(message.role);
597
+ const messageId = asString(row.id) ?? `message-${index}`;
598
+ const toolCallId = asString(message.toolCallId);
593
599
  events.push({
594
600
  agent: "pi",
595
601
  sourcePath: path,
596
602
  sessionId,
597
- recordId: asString(row.id) ?? `message-${index}`,
598
- name: `pi ${asString(message.role) ?? "message"}`,
599
- role: asString(message.role),
603
+ recordId: messageId,
604
+ name: role === "toolResult"
605
+ ? `pi toolResult ${asString(message.toolName) ?? "call"}`
606
+ : `pi ${role ?? "message"}`,
607
+ role,
600
608
  model: asString(message.model) ?? asString(row.model),
601
609
  provider: asString(message.provider),
602
610
  cwd,
603
611
  startMs: getTimestampMs(row.timestamp ?? message.timestamp, startMs + index),
604
612
  endMs: getTimestampMs(message.completed, startMs + index + 1),
605
- parentRecordId: asString(row.parentId) ?? "session",
606
- input: message.role === "user"
613
+ parentRecordId: toolCallId
614
+ ? `tool-${toolCallId}`
615
+ : asString(row.parentId) ?? "session",
616
+ input: role === "user"
607
617
  ? extractText(message.content)
608
618
  : undefined,
609
- output: message.role === "assistant"
619
+ output: role === "assistant" || role === "toolResult"
610
620
  ? extractText(message.content)
611
621
  : undefined,
612
622
  usage,
623
+ metadata: pick(message, ["toolCallId", "toolName", "isError", "stopReason"]),
613
624
  });
625
+ for (const reasoning of reasoningFromContent(message.content)) {
626
+ events.push({
627
+ agent: "pi",
628
+ sourcePath: path,
629
+ sessionId,
630
+ recordId: `reasoning-${messageId}-${reasoning.index}`,
631
+ name: "pi reasoning",
632
+ cwd,
633
+ model: asString(message.model),
634
+ startMs: getTimestampMs(row.timestamp, startMs + index),
635
+ parentRecordId: messageId,
636
+ output: reasoning.text,
637
+ metadata: { has_signature: reasoning.hasSignature },
638
+ });
639
+ }
614
640
  for (const tool of toolCallsFromContent(message.content)) {
615
641
  events.push({
616
642
  agent: "pi",
617
643
  sourcePath: path,
618
644
  sessionId,
619
- recordId: tool.id,
645
+ recordId: `tool-${tool.id}`,
620
646
  name: `pi tool ${tool.name}`,
621
647
  cwd,
622
648
  model: asString(message.model),
@@ -630,7 +656,7 @@ function piEvents(homeDir) {
630
656
  });
631
657
  }
632
658
  function grokEvents(homeDir) {
633
- const files = listFiles(join(homeDir, ".grok/sessions"), (path) => path.endsWith(".jsonl"));
659
+ const files = listFiles(join(homeDir, ".grok/sessions"), (path) => path.endsWith("chat_history.jsonl"));
634
660
  return genericJsonlEvents("grok", files, "grok session");
635
661
  }
636
662
  function opencodeEvents(homeDir, rowLimit) {
@@ -866,6 +892,12 @@ function genericJsonlEvents(agent, files, sessionName) {
866
892
  for (const [index, row] of rows.entries()) {
867
893
  const message = asRecord(row.message);
868
894
  const role = asString(message.role) ?? asString(row.type);
895
+ const recordId = asString(row.uuid) ??
896
+ asString(row.id) ??
897
+ asString(row.toolUseID) ??
898
+ `row-${index}`;
899
+ const toolUseId = asString(row.toolUseID) ?? asString(row.tool_use_id);
900
+ const content = message.content ?? row.content;
869
901
  const timestamp = getTimestampMs(row.timestamp ?? row.time_created, startMs + index);
870
902
  const usage = normalizeUsage(message.usage ?? row.usage);
871
903
  events.push({
@@ -873,22 +905,23 @@ function genericJsonlEvents(agent, files, sessionName) {
873
905
  sourcePath: path,
874
906
  sessionId: asString(row.sessionId) ?? asString(row.session_id) ??
875
907
  sessionId,
876
- recordId: asString(row.uuid) ??
877
- asString(row.id) ??
878
- asString(row.toolUseID) ??
879
- `row-${index}`,
880
- name: `${agent} ${role ?? "event"}`,
908
+ recordId,
909
+ name: role === "tool_result" || role === "toolResult"
910
+ ? `${agent} toolResult ${asString(row.toolName) ?? "call"}`
911
+ : `${agent} ${role ?? "event"}`,
881
912
  role,
882
913
  model: asString(getPath(message, ["model"])) ?? asString(row.model),
883
914
  cwd: asString(row.cwd) ?? cwd,
884
915
  startMs: timestamp,
885
- parentRecordId: asString(row.parentUuid) ?? asString(row.parentId) ??
886
- "session",
916
+ parentRecordId: toolUseId
917
+ ? `tool-${toolUseId}`
918
+ : asString(row.parentUuid) ?? asString(row.parentId) ?? "session",
887
919
  input: role === "user"
888
- ? extractText(message.content ?? row.content)
920
+ ? extractText(content)
889
921
  : undefined,
890
- output: role === "assistant"
891
- ? extractText(message.content ?? row.content)
922
+ output: role === "assistant" || role === "tool_result" ||
923
+ role === "toolResult"
924
+ ? extractText(content)
892
925
  : undefined,
893
926
  usage,
894
927
  metadata: pick(row, [
@@ -899,12 +932,26 @@ function genericJsonlEvents(agent, files, sessionName) {
899
932
  "error",
900
933
  ]),
901
934
  });
902
- for (const tool of toolCallsFromContent(message.content)) {
935
+ for (const reasoning of reasoningFromContent(content)) {
936
+ events.push({
937
+ agent,
938
+ sourcePath: path,
939
+ sessionId,
940
+ recordId: `reasoning-${recordId}-${reasoning.index}`,
941
+ name: `${agent} reasoning`,
942
+ cwd,
943
+ startMs: timestamp,
944
+ parentRecordId: recordId,
945
+ output: reasoning.text,
946
+ metadata: { has_signature: reasoning.hasSignature },
947
+ });
948
+ }
949
+ for (const tool of toolCallsFromContent(content)) {
903
950
  events.push({
904
951
  agent,
905
952
  sourcePath: path,
906
953
  sessionId,
907
- recordId: tool.id,
954
+ recordId: `tool-${tool.id}`,
908
955
  name: `${agent} tool ${tool.name}`,
909
956
  cwd,
910
957
  startMs: timestamp,
@@ -934,6 +981,26 @@ function toolCallsFromContent(content) {
934
981
  ];
935
982
  });
936
983
  }
984
+ function reasoningFromContent(content) {
985
+ if (!Array.isArray(content))
986
+ return [];
987
+ return content.flatMap((item, index) => {
988
+ const record = asRecord(item);
989
+ const type = asString(record.type);
990
+ if (type !== "thinking" && type !== "reasoning")
991
+ return [];
992
+ const text = extractText(record.thinking ?? record.text, 8000);
993
+ if (!text)
994
+ return [];
995
+ return [
996
+ {
997
+ index,
998
+ text,
999
+ hasSignature: record.thinkingSignature !== undefined || record.signature !== undefined,
1000
+ },
1001
+ ];
1002
+ });
1003
+ }
937
1004
  function pick(source, keys) {
938
1005
  const out = {};
939
1006
  for (const key of keys) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramarivera/coding-agent-langfuse",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "Universal coding-agent Langfuse backfiller and live OTLP helpers",
5
5
  "type": "module",
6
6
  "license": "MIT",