@pasko70/pibo 1.16.5 → 2.0.0

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 (146) hide show
  1. package/dist/agent-runtime/auth.js +28 -0
  2. package/dist/agent-runtime/capabilities.js +221 -0
  3. package/dist/agent-runtime/context-build.js +313 -0
  4. package/dist/agent-runtime/contract.js +45 -0
  5. package/dist/agent-runtime/errors.js +57 -0
  6. package/dist/agent-runtime/events.js +1 -0
  7. package/dist/agent-runtime/history.js +1 -0
  8. package/dist/agent-runtime/profile-validation.js +109 -0
  9. package/dist/agent-runtime/registry.js +608 -0
  10. package/dist/agent-runtime/resource-files.js +87 -0
  11. package/dist/agent-runtime/resource-service.js +635 -0
  12. package/dist/agent-runtime/resources.js +1 -0
  13. package/dist/agent-runtime/routed-session.js +931 -0
  14. package/dist/agent-runtime/testing/contract.js +51 -0
  15. package/dist/agent-runtime/testing/fake-adapter.js +192 -0
  16. package/dist/agent-runtime/types.js +3 -0
  17. package/dist/agent-runtimes/codex-native/adapter.js +905 -0
  18. package/dist/agent-runtimes/codex-native/auth.js +476 -0
  19. package/dist/agent-runtimes/codex-native/client.js +734 -0
  20. package/dist/agent-runtimes/codex-native/config.js +152 -0
  21. package/dist/agent-runtimes/codex-native/history.js +283 -0
  22. package/dist/agent-runtimes/codex-native/mcp-stdio-launcher.js +89 -0
  23. package/dist/agent-runtimes/codex-native/models.js +581 -0
  24. package/dist/agent-runtimes/codex-native/process.js +459 -0
  25. package/dist/agent-runtimes/codex-native/protocol-types.js +1 -0
  26. package/dist/agent-runtimes/codex-native/protocol-version.js +7 -0
  27. package/dist/agent-runtimes/codex-native/redaction.js +31 -0
  28. package/dist/agent-runtimes/codex-native/requests.js +378 -0
  29. package/dist/agent-runtimes/codex-native/resource-delivery.js +445 -0
  30. package/dist/agent-runtimes/codex-native/thread.js +388 -0
  31. package/dist/agent-runtimes/codex-native/turn.js +849 -0
  32. package/dist/agent-runtimes/pi/adapter.js +653 -0
  33. package/dist/agent-runtimes/pi/auth.js +455 -0
  34. package/dist/agent-runtimes/pi/history.js +640 -0
  35. package/dist/agent-runtimes/pi/model-catalog.js +87 -0
  36. package/dist/agent-runtimes/pi/routed-session.js +1464 -0
  37. package/dist/agent-runtimes/pi/runtime.js +534 -0
  38. package/dist/agent-runtimes/pi/tool-compiler.js +69 -0
  39. package/dist/apps/chat/agent-profiles.js +40 -23
  40. package/dist/apps/chat/agent-store.js +111 -64
  41. package/dist/apps/chat/chat-api-routes.js +1 -1
  42. package/dist/apps/chat/chat-request-normalizers.js +47 -0
  43. package/dist/apps/chat/data/chat-data-mappers.js +25 -9
  44. package/dist/apps/chat/data/history-query-service.js +108 -0
  45. package/dist/apps/chat/data/session-query-service.js +24 -3
  46. package/dist/apps/chat/data/timeline-query-service.js +3 -3
  47. package/dist/apps/chat/model-catalog.js +1 -55
  48. package/dist/apps/chat/provider-auth-actions.js +171 -23
  49. package/dist/apps/chat/stream.js +12 -0
  50. package/dist/apps/chat/trace-v2.js +1 -0
  51. package/dist/apps/chat/trace.js +126 -415
  52. package/dist/apps/chat/web-app.js +582 -157
  53. package/dist/apps/chat-ui/assets/{dist-QXwINWYY.js → dist-9v2ZXT6V.js} +1 -1
  54. package/dist/apps/chat-ui/assets/{dist-CvZNkkOi.js → dist-B1LVAytl.js} +1 -1
  55. package/dist/apps/chat-ui/assets/{dist-_SP-MjLq.js → dist-C6LPDFXU.js} +1 -1
  56. package/dist/apps/chat-ui/assets/{dist-Bad4Yz4P.js → dist-DVtXxfHc.js} +1 -1
  57. package/dist/apps/chat-ui/assets/{dist-xy-zomwl.js → dist-DW4Qrfbd.js} +1 -1
  58. package/dist/apps/chat-ui/assets/{dist-DI4i80O2.js → dist-DmbsHdMC.js} +1 -1
  59. package/dist/apps/chat-ui/assets/{dist-D17yAUqp.js → dist-DyvwuSFO.js} +1 -1
  60. package/dist/apps/chat-ui/assets/{dist-Bc3Vbgjh.js → dist-I26VB0QO.js} +1 -1
  61. package/dist/apps/chat-ui/assets/{dist-BzqH7w58.js → dist-RtHbJRPV.js} +1 -1
  62. package/dist/apps/chat-ui/assets/{dist-CMDJ-WZm.js → dist-sZgJkWZb.js} +1 -1
  63. package/dist/apps/chat-ui/assets/index-BPbNvcZe.css +1 -0
  64. package/dist/apps/chat-ui/assets/index-CIOf2uL2.js +237 -0
  65. package/dist/apps/chat-ui/index.html +2 -2
  66. package/dist/apps/chat-vscode-web/assets/index-1ivRyjFs.js +41 -0
  67. package/dist/apps/chat-vscode-web/index.html +1 -1
  68. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  69. package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.0.0.vsix +0 -0
  70. package/dist/auth/login-actions.js +5 -251
  71. package/dist/cli-session/localSessionSource.js +8 -1
  72. package/dist/core/context-build.js +124 -20
  73. package/dist/core/default-profile.js +8 -0
  74. package/dist/core/profiles.js +30 -3
  75. package/dist/core/routed-session.js +5 -1446
  76. package/dist/core/runtime.js +5 -561
  77. package/dist/core/session-router.js +637 -83
  78. package/dist/data/cli.js +20 -3
  79. package/dist/data/schema.js +104 -1
  80. package/dist/data/session-store.js +24 -1
  81. package/dist/debug/events.js +25 -10
  82. package/dist/debug/failures.js +23 -3
  83. package/dist/debug/index.js +24 -6
  84. package/dist/debug/messages.js +87 -7
  85. package/dist/debug/persisted-payloads.js +31 -0
  86. package/dist/debug/pty.js +7 -6
  87. package/dist/debug/runtime-binding.js +29 -0
  88. package/dist/debug/session.js +137 -0
  89. package/dist/debug/summary.js +12 -0
  90. package/dist/debug/telemetry.js +28 -0
  91. package/dist/debug/tools.js +12 -2
  92. package/dist/debug/trace.js +154 -76
  93. package/dist/gateway/server.js +87 -2
  94. package/dist/gateway/tool.js +5 -5
  95. package/dist/index.js +21 -2
  96. package/dist/loops/tools.js +13 -12
  97. package/dist/mcp/agent-context.js +13 -4
  98. package/dist/mcp/client.js +10 -6
  99. package/dist/mcp/config.js +5 -2
  100. package/dist/mcp/runtime-session.js +166 -0
  101. package/dist/plugins/builtin.js +191 -53
  102. package/dist/plugins/codex-native.js +29 -0
  103. package/dist/plugins/registry.js +66 -2
  104. package/dist/runs/tools.js +26 -25
  105. package/dist/session-ui/terminalRows.js +2 -2
  106. package/dist/sessions/pibo-data-store.js +125 -16
  107. package/dist/sessions/runtime-binding.js +107 -0
  108. package/dist/sessions/sqlite-store.js +239 -18
  109. package/dist/sessions/store.js +86 -7
  110. package/dist/shared/trace-engine.js +18 -9
  111. package/dist/shared/trace-event-projection.js +29 -11
  112. package/dist/shared/{trace-transcript.js → trace-history.js} +193 -195
  113. package/dist/shared/trace-order.js +9 -4
  114. package/dist/shared/trace-page-merge.js +1 -1
  115. package/dist/signals/projector.js +20 -2
  116. package/dist/signals/registry.js +11 -0
  117. package/dist/subagents/tool.js +8 -6
  118. package/dist/tools/codex-browser.js +20 -19
  119. package/dist/tools/codex-compat.js +10 -9
  120. package/dist/tools/codex-image-generation.js +8 -6
  121. package/dist/tools/contract.js +45 -0
  122. package/dist/tools/credential-registry.js +182 -0
  123. package/dist/tools/mcp-bridge.js +511 -0
  124. package/dist/tools/payload-writer.js +17 -0
  125. package/dist/tools/runtime/tool.js +10 -9
  126. package/dist/tools/schema.js +9 -0
  127. package/dist/tools/session-service.js +193 -0
  128. package/dist/tools/session-tool-set.js +85 -0
  129. package/dist/web-annotations/tools.js +17 -16
  130. package/docs/README.md +11 -0
  131. package/package.json +3 -2
  132. package/skills/builtin/pibo-agent-runtime-adapter/SKILL.md +183 -0
  133. package/skills/builtin/pibo-agent-runtime-adapter/evals/README.md +10 -0
  134. package/skills/builtin/pibo-agent-runtime-adapter/evals/evals.json +45 -0
  135. package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/orion-full-harness.md +60 -0
  136. package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/relay-partial-harness.md +52 -0
  137. package/skills/builtin/pibo-agent-runtime-adapter/references/capabilities-and-designer.md +194 -0
  138. package/skills/builtin/pibo-agent-runtime-adapter/references/history-debug-and-security.md +213 -0
  139. package/skills/builtin/pibo-agent-runtime-adapter/references/interfaces-and-registration.md +214 -0
  140. package/skills/builtin/pibo-agent-runtime-adapter/references/lifecycle-bindings-and-events.md +193 -0
  141. package/skills/builtin/pibo-agent-runtime-adapter/references/portable-delivery-and-native-behavior.md +226 -0
  142. package/skills/builtin/pibo-agent-runtime-adapter/references/testing-migration-and-validation.md +256 -0
  143. package/dist/apps/chat-ui/assets/index-C45B0rw7.js +0 -237
  144. package/dist/apps/chat-ui/assets/index-E0RmuCkY.css +0 -1
  145. package/dist/apps/chat-vscode-web/assets/index-D-tSsXLG.js +0 -41
  146. package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.16.5.vsix +0 -0
@@ -1,43 +1,42 @@
1
- import { transcriptTraceOrder } from "./trace-order.js";
1
+ import { historyTraceOrder } from "./trace-order.js";
2
2
  import { attachAsyncAgentRunNode, reconcileAsyncAgentRunStatuses } from "./trace-async-agent-runs.js";
3
3
  import { sortTraceNodes } from "./trace-nodes.js";
4
4
  import { createRunNotificationNode, parseRunNotificationText } from "./trace-run-notifications.js";
5
5
  import { isSubagentToolName } from "./trace-subagent-links.js";
6
- import { assistantMessageNodeId, thinkingNodeId } from "./trace-event-projection.js";
7
- export function projectTranscriptEntries(entries, sessionStatus, openTranscriptEventIds, turnTimings = []) {
8
- if (sessionStatus !== "running" || openTranscriptEventIds.size === 0)
9
- return entries;
10
- const userTimingAssignments = assignTranscriptUserTimings(entries, turnTimings);
6
+ import { assistantMessageNodeId, messageTurnNodeId, thinkingNodeId } from "./trace-event-projection.js";
7
+ export function projectHistoryEntries(entries, sessionStatus, openHistoryEventIds, turnTimings = []) {
8
+ if (sessionStatus !== "running" || openHistoryEventIds.size === 0)
9
+ return [...entries];
10
+ const userTimingAssignments = assignHistoryUserTimings(entries, turnTimings);
11
11
  let lastUserMessageIndex = -1;
12
12
  let lastUserEventId;
13
13
  for (let index = 0; index < entries.length; index += 1) {
14
14
  const entry = entries[index];
15
- if (entry.type !== "message" || messageRole(entry) !== "user")
15
+ if (entry.type !== "message" || entry.role !== "user")
16
16
  continue;
17
17
  lastUserMessageIndex = index;
18
- lastUserEventId = openTranscriptEventIds.has(entry.id)
19
- ? entry.id
18
+ lastUserEventId = entry.turnId && openHistoryEventIds.has(entry.turnId)
19
+ ? entry.turnId
20
20
  : userTimingAssignments.get(index)?.eventId;
21
21
  }
22
- return lastUserMessageIndex !== -1 && lastUserEventId && openTranscriptEventIds.has(lastUserEventId)
22
+ return lastUserMessageIndex !== -1 && lastUserEventId && openHistoryEventIds.has(lastUserEventId)
23
23
  ? entries.slice(0, lastUserMessageIndex)
24
- : entries;
24
+ : [...entries];
25
25
  }
26
- export function traceNodesFromEntries(piboSessionId, entries, turnTimings = []) {
26
+ export function traceNodesFromHistoryEntries(piboSessionId, entries, turnTimings = []) {
27
27
  const nodes = [];
28
- const turnTimingAssignments = assignTranscriptTurnTimings(entries, turnTimings);
29
- const userTimingAssignments = assignTranscriptUserTimings(entries, turnTimings);
28
+ const turnTimingAssignments = assignHistoryTurnTimings(entries, turnTimings);
29
+ const userTimingAssignments = assignHistoryUserTimings(entries, turnTimings);
30
30
  let assistantTurnIndex = 0;
31
31
  for (let index = 0; index < entries.length; index += 1) {
32
32
  const entry = entries[index];
33
33
  if (entry.type === "message") {
34
- const role = messageRole(entry);
35
- if (role === "user") {
36
- nodes.push(createUserMessageNode(piboSessionId, entry, messageContent(entry), index, userTimingAssignments.get(index)));
34
+ if (entry.role === "user") {
35
+ nodes.push(createUserMessageNode(piboSessionId, entry, index, userTimingAssignments.get(index)));
37
36
  }
38
- else if (role === "assistant" || role === "toolResult") {
37
+ else if (entry.role === "assistant" || entry.role === "tool") {
39
38
  const turn = collectAssistantTurn(entries, index);
40
- const hasAssistant = turn.entries.some(({ entry: turnEntry }) => messageRole(turnEntry) === "assistant");
39
+ const hasAssistant = turn.entries.some(({ entry: turnEntry }) => turnEntry.role === "assistant");
41
40
  const timing = hasAssistant ? turnTimingAssignments[assistantTurnIndex] : undefined;
42
41
  nodes.push(...createAssistantTurnNodes(piboSessionId, turn.entries, timing));
43
42
  if (hasAssistant)
@@ -46,18 +45,20 @@ export function traceNodesFromEntries(piboSessionId, entries, turnTimings = [])
46
45
  }
47
46
  }
48
47
  else if (entry.type === "session_info" && entry.name) {
48
+ const source = traceSource(entry.source);
49
+ const entryIndex = historyIndex(entry, index);
49
50
  nodes.push({
50
- id: `entry:${entry.id}`,
51
- entryId: entry.id,
51
+ id: historyEntryNodeId(entry),
52
+ entryId: entry.nativeEntryId,
52
53
  piboSessionId,
53
54
  type: "execution.command",
54
55
  title: "Session Info",
55
56
  status: "done",
56
- startedAt: entry.timestamp,
57
+ startedAt: entry.createdAt,
57
58
  output: { name: entry.name },
58
- source: "transcript",
59
- stableKey: `entry:${entry.id}`,
60
- orderKey: transcriptTraceOrder(index, 0, "execution.command"),
59
+ source,
60
+ stableKey: historyEntryStableKey(entry),
61
+ orderKey: historyTraceOrder(entryIndex, 0, "execution.command", source),
61
62
  children: [],
62
63
  });
63
64
  }
@@ -66,67 +67,64 @@ export function traceNodesFromEntries(piboSessionId, entries, turnTimings = [])
66
67
  sortTraceNodes(nodes);
67
68
  return nodes;
68
69
  }
69
- function messageRole(entry) {
70
- return entry.message.role;
71
- }
72
- function messageContent(entry) {
73
- return entry.message.content;
74
- }
75
- function messageParts(entry) {
76
- const content = messageContent(entry);
77
- if (typeof content === "string")
78
- return [{ type: "text", text: content }];
79
- return Array.isArray(content) ? content : [];
80
- }
81
- function collectTranscriptTurnTimingTargets(entries) {
70
+ function collectHistoryTurnTimingTargets(entries) {
82
71
  const targets = [];
83
72
  let latestUserText;
84
73
  let latestUserEntryIndex;
74
+ let latestTurnId;
85
75
  for (let index = 0; index < entries.length; index += 1) {
86
76
  const entry = entries[index];
87
77
  if (entry.type !== "message")
88
78
  continue;
89
- const role = messageRole(entry);
90
- if (role === "user") {
91
- latestUserText = normalizedPrompt(extractText(messageContent(entry)));
79
+ if (entry.role === "user") {
80
+ latestUserText = normalizedPrompt(historyMessageText(entry));
92
81
  latestUserEntryIndex = index;
82
+ latestTurnId = entry.turnId;
93
83
  continue;
94
84
  }
95
- if (role !== "assistant" && role !== "toolResult")
85
+ if (entry.role !== "assistant" && entry.role !== "tool")
96
86
  continue;
97
87
  const turn = collectAssistantTurn(entries, index);
98
- const lastAssistant = [...turn.entries].reverse().find(({ entry: turnEntry }) => messageRole(turnEntry) === "assistant");
88
+ const lastAssistant = [...turn.entries].reverse().find(({ entry: turnEntry }) => turnEntry.role === "assistant");
99
89
  if (lastAssistant) {
100
90
  targets.push({
101
91
  prompt: latestUserText,
102
92
  userEntryIndex: latestUserEntryIndex,
103
- assistantAt: parsedTimestamp(lastAssistant.entry.timestamp),
93
+ assistantAt: parsedTimestamp(lastAssistant.entry.createdAt),
104
94
  settled: isSettledAssistantEntry(lastAssistant.entry),
95
+ turnId: lastAssistant.entry.turnId ?? latestTurnId,
105
96
  });
106
97
  }
107
98
  index = turn.nextIndex - 1;
108
99
  }
109
100
  return targets;
110
101
  }
111
- function assignTranscriptTurnTimings(entries, turnTimings) {
102
+ function assignHistoryTurnTimings(entries, turnTimings) {
112
103
  const messageTurnTimings = turnTimings.filter((timing) => timing.userMessageType !== "message_steered");
113
- const transcriptTurns = collectTranscriptTurnTimingTargets(entries);
114
- const assignments = Array(transcriptTurns.length).fill(undefined);
104
+ const timingByEventId = new Map(messageTurnTimings.map((timing) => [timing.eventId, timing]));
105
+ const historyTurns = collectHistoryTurnTimingTargets(entries);
106
+ const assignments = historyTurns.map((turn) => turn.turnId ? timingByEventId.get(turn.turnId) : undefined);
115
107
  let timingCursor = messageTurnTimings.length - 1;
116
- for (let turnIndex = transcriptTurns.length - 1; turnIndex >= 0; turnIndex -= 1) {
117
- const transcriptTurn = transcriptTurns[turnIndex];
118
- if (!transcriptTurn?.prompt)
108
+ for (let turnIndex = historyTurns.length - 1; turnIndex >= 0; turnIndex -= 1) {
109
+ if (assignments[turnIndex]) {
110
+ const assignedIndex = messageTurnTimings.indexOf(assignments[turnIndex]);
111
+ if (assignedIndex >= 0)
112
+ timingCursor = Math.min(timingCursor, assignedIndex - 1);
113
+ continue;
114
+ }
115
+ const historyTurn = historyTurns[turnIndex];
116
+ if (!historyTurn?.prompt)
119
117
  continue;
120
118
  let matchedIndex;
121
119
  let matchedDistance = Number.POSITIVE_INFINITY;
122
120
  for (let timingIndex = timingCursor; timingIndex >= 0; timingIndex -= 1) {
123
121
  const timing = messageTurnTimings[timingIndex];
124
- if (normalizedPrompt(timing?.userText) !== transcriptTurn.prompt)
122
+ if (normalizedPrompt(timing?.userText) !== historyTurn.prompt)
125
123
  continue;
126
124
  const completedAt = parsedTimestamp(timing?.completedAt);
127
- const distance = completedAt === undefined || transcriptTurn.assistantAt === undefined
125
+ const distance = completedAt === undefined || historyTurn.assistantAt === undefined
128
126
  ? Number.POSITIVE_INFINITY
129
- : Math.abs(completedAt - transcriptTurn.assistantAt);
127
+ : Math.abs(completedAt - historyTurn.assistantAt);
130
128
  if (matchedIndex === undefined || distance < matchedDistance) {
131
129
  matchedIndex = timingIndex;
132
130
  matchedDistance = distance;
@@ -139,18 +137,19 @@ function assignTranscriptTurnTimings(entries, turnTimings) {
139
137
  }
140
138
  return assignments;
141
139
  }
142
- function assignTranscriptUserTimings(entries, turnTimings) {
140
+ function assignHistoryUserTimings(entries, turnTimings) {
143
141
  const users = [];
144
142
  const userPositionByEntryIndex = new Map();
145
143
  for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 1) {
146
144
  const entry = entries[entryIndex];
147
- if (entry.type !== "message" || messageRole(entry) !== "user")
145
+ if (entry.type !== "message" || entry.role !== "user")
148
146
  continue;
149
147
  userPositionByEntryIndex.set(entryIndex, users.length);
150
148
  users.push({
151
149
  entryIndex,
152
- entryId: entry.id,
153
- prompt: normalizedPrompt(extractText(messageContent(entry))),
150
+ entryId: entry.nativeEntryId,
151
+ turnId: entry.turnId,
152
+ prompt: normalizedPrompt(historyMessageText(entry)),
154
153
  });
155
154
  }
156
155
  if (!users.length || !turnTimings.length)
@@ -159,20 +158,21 @@ function assignTranscriptUserTimings(entries, turnTimings) {
159
158
  const anchorByUserPosition = new Map();
160
159
  const assignedTimingIndexes = new Set();
161
160
  for (let userPosition = 0; userPosition < users.length; userPosition += 1) {
162
- const timingIndex = timingIndexByEventId.get(users[userPosition].entryId);
161
+ const user = users[userPosition];
162
+ const timingIndex = timingIndexByEventId.get(user.turnId ?? user.entryId ?? "");
163
163
  if (timingIndex === undefined || assignedTimingIndexes.has(timingIndex))
164
164
  continue;
165
165
  anchorByUserPosition.set(userPosition, timingIndex);
166
166
  assignedTimingIndexes.add(timingIndex);
167
167
  }
168
- const transcriptTurns = collectTranscriptTurnTimingTargets(entries);
168
+ const historyTurns = collectHistoryTurnTimingTargets(entries);
169
169
  let timingUpperBound = turnTimings.length - 1;
170
- for (let turnIndex = transcriptTurns.length - 1; turnIndex >= 0; turnIndex -= 1) {
171
- const transcriptTurn = transcriptTurns[turnIndex];
172
- const userPosition = transcriptTurn?.userEntryIndex === undefined
170
+ for (let turnIndex = historyTurns.length - 1; turnIndex >= 0; turnIndex -= 1) {
171
+ const historyTurn = historyTurns[turnIndex];
172
+ const userPosition = historyTurn?.userEntryIndex === undefined
173
173
  ? undefined
174
- : userPositionByEntryIndex.get(transcriptTurn.userEntryIndex);
175
- if (!transcriptTurn?.prompt || userPosition === undefined)
174
+ : userPositionByEntryIndex.get(historyTurn.userEntryIndex);
175
+ if (!historyTurn?.prompt || userPosition === undefined)
176
176
  continue;
177
177
  const exactAnchor = anchorByUserPosition.get(userPosition);
178
178
  if (exactAnchor !== undefined) {
@@ -184,7 +184,7 @@ function assignTranscriptUserTimings(entries, turnTimings) {
184
184
  const timing = turnTimings[timingIndex];
185
185
  if (assignedTimingIndexes.has(timingIndex) || timing.userMessageType !== "message_steered")
186
186
  continue;
187
- if (normalizedPrompt(timing.userText) !== transcriptTurn.prompt)
187
+ if (normalizedPrompt(timing.userText) !== historyTurn.prompt)
188
188
  continue;
189
189
  steeringTimingIndex = timingIndex;
190
190
  break;
@@ -195,7 +195,7 @@ function assignTranscriptUserTimings(entries, turnTimings) {
195
195
  timingUpperBound = steeringTimingIndex - 1;
196
196
  continue;
197
197
  }
198
- if (!transcriptTurn.settled)
198
+ if (!historyTurn.settled)
199
199
  continue;
200
200
  let matchedTimingIndex;
201
201
  let matchedDistance = Number.POSITIVE_INFINITY;
@@ -203,12 +203,12 @@ function assignTranscriptUserTimings(entries, turnTimings) {
203
203
  const timing = turnTimings[timingIndex];
204
204
  if (assignedTimingIndexes.has(timingIndex) || timing.userMessageType === "message_steered" || !timing.completedAt)
205
205
  continue;
206
- if (normalizedPrompt(timing.userText) !== transcriptTurn.prompt)
206
+ if (normalizedPrompt(timing.userText) !== historyTurn.prompt)
207
207
  continue;
208
208
  const completedAt = parsedTimestamp(timing.completedAt);
209
- const distance = completedAt === undefined || transcriptTurn.assistantAt === undefined
209
+ const distance = completedAt === undefined || historyTurn.assistantAt === undefined
210
210
  ? Number.POSITIVE_INFINITY
211
- : Math.abs(completedAt - transcriptTurn.assistantAt);
211
+ : Math.abs(completedAt - historyTurn.assistantAt);
212
212
  if (matchedTimingIndex === undefined || distance < matchedDistance) {
213
213
  matchedTimingIndex = timingIndex;
214
214
  matchedDistance = distance;
@@ -224,9 +224,8 @@ function assignTranscriptUserTimings(entries, turnTimings) {
224
224
  const anchors = [...anchorByUserPosition.entries()]
225
225
  .map(([userPosition, timingIndex]) => ({ userPosition, timingIndex }))
226
226
  .sort((left, right) => left.userPosition - right.userPosition);
227
- for (const anchor of anchors) {
227
+ for (const anchor of anchors)
228
228
  assignments.set(users[anchor.userPosition].entryIndex, turnTimings[anchor.timingIndex]);
229
- }
230
229
  const boundaries = [
231
230
  { userPosition: -1, timingIndex: -1 },
232
231
  ...anchors,
@@ -255,22 +254,6 @@ function assignTranscriptUserTimings(entries, turnTimings) {
255
254
  }
256
255
  return assignments;
257
256
  }
258
- function isSettledAssistantEntry(entry) {
259
- const message = entry.message;
260
- if (message.stopReason === "toolUse" || message.stopReason === "tool_use")
261
- return false;
262
- return message.status !== "streaming" && message.status !== "in_progress";
263
- }
264
- function normalizedPrompt(value) {
265
- const normalized = value?.replace(/\s+/g, " ").trim();
266
- return normalized || undefined;
267
- }
268
- function parsedTimestamp(value) {
269
- if (!value)
270
- return undefined;
271
- const timestamp = new Date(value).getTime();
272
- return Number.isFinite(timestamp) ? timestamp : undefined;
273
- }
274
257
  function collectAssistantTurn(entries, startIndex) {
275
258
  const turnEntries = [];
276
259
  let index = startIndex;
@@ -278,49 +261,53 @@ function collectAssistantTurn(entries, startIndex) {
278
261
  const entry = entries[index];
279
262
  if (entry.type !== "message")
280
263
  break;
281
- const role = messageRole(entry);
282
- if (role !== "assistant" && role !== "toolResult")
264
+ if (entry.role !== "assistant" && entry.role !== "tool")
283
265
  break;
284
266
  turnEntries.push({ entry, index });
285
267
  index += 1;
286
268
  }
287
269
  return { entries: turnEntries, nextIndex: index };
288
270
  }
289
- function createUserMessageNode(piboSessionId, entry, content, entryIndex, timing) {
290
- const text = extractText(content);
271
+ function createUserMessageNode(piboSessionId, entry, entryIndex, timing) {
272
+ const text = historyMessageText(entry);
291
273
  const notification = parseRunNotificationText(text);
274
+ const source = traceSource(entry.source);
275
+ const orderIndex = historyIndex(entry, entryIndex);
292
276
  if (notification) {
293
277
  return createRunNotificationNode({
294
- id: `entry:${entry.id}`,
295
- entryId: entry.id,
278
+ id: historyEntryNodeId(entry),
279
+ entryId: entry.nativeEntryId,
296
280
  piboSessionId,
297
- startedAt: entry.timestamp,
298
- orderKey: transcriptTraceOrder(entryIndex, 0, "yielded.run"),
299
- source: "transcript",
300
- stableKey: `entry:${entry.id}`,
281
+ startedAt: entry.createdAt,
282
+ orderKey: historyTraceOrder(orderIndex, 0, "yielded.run", source),
283
+ source,
284
+ stableKey: historyEntryStableKey(entry),
301
285
  notification,
302
286
  });
303
287
  }
304
288
  const userMessageType = timing?.userMessageType ?? "message_queued";
305
- const eventIdentity = timing ? `event:${userMessageType}:${timing.eventId}` : undefined;
289
+ const eventId = entry.turnId ?? timing?.eventId;
290
+ const eventIdentity = eventId ? `event:${userMessageType}:${eventId}` : undefined;
306
291
  return {
307
- id: eventIdentity ?? `entry:${entry.id}`,
308
- entryId: entry.id,
292
+ id: eventIdentity ?? historyEntryNodeId(entry),
293
+ entryId: entry.nativeEntryId,
309
294
  piboSessionId,
295
+ eventId,
310
296
  type: "user.message",
311
297
  title: "User Message",
312
- status: "done",
313
- startedAt: entry.timestamp,
298
+ status: entry.status === "running" ? "running" : entry.status === "error" ? "error" : "done",
299
+ startedAt: entry.createdAt,
314
300
  summary: text,
315
301
  output: text,
316
- source: "transcript",
317
- stableKey: eventIdentity ?? `entry:${entry.id}`,
318
- orderKey: transcriptTraceOrder(entryIndex, 0, "user.message"),
302
+ error: entry.error,
303
+ source,
304
+ stableKey: eventIdentity ?? historyEntryStableKey(entry),
305
+ orderKey: historyTraceOrder(orderIndex, 0, "user.message", source),
319
306
  children: [],
320
307
  };
321
308
  }
322
309
  function createAssistantTurnNodes(piboSessionId, entries, timing) {
323
- const firstAssistant = entries.find(({ entry }) => messageRole(entry) === "assistant");
310
+ const firstAssistant = entries.find(({ entry }) => entry.role === "assistant");
324
311
  if (!firstAssistant)
325
312
  return [];
326
313
  const orderedNodes = [];
@@ -328,60 +315,59 @@ function createAssistantTurnNodes(piboSessionId, entries, timing) {
328
315
  let assistantPartOrdinal = 0;
329
316
  let reasoningPartOrdinal = 0;
330
317
  for (const { entry, index: entryIndex } of entries) {
331
- if (messageRole(entry) === "toolResult") {
318
+ if (entry.role === "tool") {
332
319
  mergePersistedToolResult(toolsByCallId, orderedNodes, entry, piboSessionId, entryIndex);
333
320
  continue;
334
321
  }
335
- const responseStatus = messageStatus(entry.message);
336
- const responseError = messageError(entry.message);
322
+ const responseStatus = historyMessageStatus(entry);
337
323
  let responseNode;
338
- for (const [index, part] of messageParts(entry).entries()) {
339
- const typed = part;
340
- if (typed.type === "thinking" && typeof typed.thinking === "string" && hasVisibleText(typed.thinking)) {
324
+ const parts = historyMessageParts(entry);
325
+ for (const [contentPartIndex, part] of parts.entries()) {
326
+ if (part.type === "reasoning" && hasVisibleText(part.text)) {
341
327
  const thinkingIndex = timing?.reasoningIndices?.[reasoningPartOrdinal] ?? reasoningPartOrdinal;
342
328
  orderedNodes.push(createReasoningNode({
343
329
  piboSessionId,
344
330
  entry,
345
331
  entryIndex,
346
- contentPartIndex: index,
332
+ contentPartIndex,
347
333
  thinkingIndex,
348
- eventId: timing?.eventId,
349
- thinking: typed.thinking,
334
+ eventId: entry.turnId ?? timing?.eventId,
335
+ thinking: part.text,
350
336
  }));
351
337
  reasoningPartOrdinal += 1;
352
338
  }
353
- else if (typed.type === "text" && typeof typed.text === "string" && typed.text !== "") {
339
+ else if (part.type === "text" && part.text !== "") {
354
340
  if (!responseNode) {
355
- const assistantIndex = timing?.assistantIndices?.[assistantPartOrdinal] ?? assistantPartOrdinal;
341
+ const assistantIndex = entry.assistantIndex ?? timing?.assistantIndices?.[assistantPartOrdinal] ?? assistantPartOrdinal;
356
342
  responseNode = createAssistantMessageNode({
357
343
  piboSessionId,
358
344
  entry,
359
345
  entryIndex,
360
- contentPartIndex: index,
346
+ contentPartIndex,
361
347
  assistantIndex,
362
- eventId: timing?.eventId,
348
+ eventId: entry.turnId ?? timing?.eventId,
363
349
  status: responseStatus,
364
- text: typed.text,
365
- error: responseError,
350
+ text: part.text,
351
+ error: entry.error,
366
352
  children: [],
367
- startedAt: entry.timestamp,
353
+ startedAt: entry.createdAt,
368
354
  });
369
355
  orderedNodes.push(responseNode);
370
356
  }
371
357
  else {
372
- responseNode.summary = `${typeof responseNode.summary === "string" ? responseNode.summary : ""}${typed.text}`;
373
- responseNode.output = `${typeof responseNode.output === "string" ? responseNode.output : ""}${typed.text}`;
358
+ responseNode.summary = `${typeof responseNode.summary === "string" ? responseNode.summary : ""}${part.text}`;
359
+ responseNode.output = `${typeof responseNode.output === "string" ? responseNode.output : ""}${part.text}`;
374
360
  }
375
361
  }
376
- else if (typed.type === "toolCall" && typeof typed.id === "string" && typeof typed.name === "string") {
377
- const toolNode = createToolCallNode(piboSessionId, entry, entryIndex, index, typed);
362
+ else if (part.type === "tool_call") {
363
+ const toolNode = createToolCallNode(piboSessionId, entry, entryIndex, contentPartIndex, part);
378
364
  orderedNodes.push(toolNode);
379
- toolsByCallId.set(typed.id, toolNode);
365
+ toolsByCallId.set(part.toolCallId, toolNode);
380
366
  }
381
367
  }
382
368
  if (responseNode) {
383
369
  responseNode.status = responseStatus;
384
- responseNode.error = responseError;
370
+ responseNode.error = entry.error;
385
371
  assistantPartOrdinal += 1;
386
372
  }
387
373
  }
@@ -394,44 +380,47 @@ function createAssistantTurnNodes(piboSessionId, entries, timing) {
394
380
  }
395
381
  function createReasoningNode(input) {
396
382
  const eventIdentity = input.eventId ? `${input.eventId}:thinking:${input.thinkingIndex}` : undefined;
383
+ const source = traceSource(input.entry.source);
397
384
  return {
398
- id: eventIdentity ? thinkingNodeId(eventIdentity) : `entry:${input.entry.id}:thinking:${input.contentPartIndex}`,
399
- entryId: input.entry.id,
385
+ id: eventIdentity ? thinkingNodeId(eventIdentity) : `${historyEntryNodeId(input.entry)}:thinking:${input.contentPartIndex}`,
386
+ entryId: input.entry.nativeEntryId,
400
387
  piboSessionId: input.piboSessionId,
388
+ eventId: input.eventId,
389
+ parentId: input.entry.source === "product" && input.eventId ? messageTurnNodeId(input.eventId) : undefined,
401
390
  type: "model.reasoning",
402
391
  title: "Thinking",
403
392
  status: "done",
404
- startedAt: input.entry.timestamp,
393
+ startedAt: input.entry.createdAt,
405
394
  summary: input.thinking,
406
395
  output: input.thinking,
407
- source: "transcript",
408
- stableKey: eventIdentity ? `reasoning:${eventIdentity}` : `entry:${input.entry.id}:thinking:${input.contentPartIndex}`,
409
- orderKey: transcriptTraceOrder(input.entryIndex, input.contentPartIndex, "model.reasoning"),
396
+ source,
397
+ stableKey: eventIdentity ? `reasoning:${eventIdentity}` : `${historyEntryStableKey(input.entry)}:thinking:${input.contentPartIndex}`,
398
+ orderKey: historyTraceOrder(historyIndex(input.entry, input.entryIndex), input.contentPartIndex, "model.reasoning", source),
410
399
  children: [],
411
400
  };
412
401
  }
413
402
  function createToolCallNode(piboSessionId, entry, entryIndex, contentPartIndex, part) {
414
- const name = typeof part.name === "string" ? part.name : "Tool Call";
415
- const toolCallId = typeof part.id === "string" ? part.id : undefined;
403
+ const source = traceSource(entry.source);
416
404
  return {
417
- id: toolCallId ? `tool:${toolCallId}` : `entry:${entry.id}:tool:${contentPartIndex}`,
418
- entryId: entry.id,
405
+ id: `tool:${part.toolCallId}`,
406
+ entryId: entry.nativeEntryId,
419
407
  piboSessionId,
420
- toolCallId,
421
- type: isSubagentToolName(name) ? "agent.delegation" : "tool.call",
422
- title: name,
408
+ eventId: entry.turnId,
409
+ parentId: entry.source === "product" && entry.turnId ? messageTurnNodeId(entry.turnId) : undefined,
410
+ toolCallId: part.toolCallId,
411
+ type: isSubagentToolName(part.toolName) ? "agent.delegation" : "tool.call",
412
+ title: part.toolName,
423
413
  status: "done",
424
- startedAt: entry.timestamp,
425
- input: part.arguments ?? {},
426
- source: "transcript",
427
- stableKey: toolCallId ? `tool:${toolCallId}` : `entry:${entry.id}:tool:${contentPartIndex}`,
428
- orderKey: transcriptTraceOrder(entryIndex, contentPartIndex, isSubagentToolName(name) ? "agent.delegation" : "tool.call"),
414
+ startedAt: entry.createdAt,
415
+ input: part.input ?? {},
416
+ source,
417
+ stableKey: `tool:${part.toolCallId}`,
418
+ orderKey: historyTraceOrder(historyIndex(entry, entryIndex), contentPartIndex, isSubagentToolName(part.toolName) ? "agent.delegation" : "tool.call", source),
429
419
  children: [],
430
420
  };
431
421
  }
432
422
  function mergePersistedToolResult(toolsByCallId, childNodes, entry, piboSessionId, entryIndex) {
433
- const message = entry.message;
434
- const toolCallId = typeof message.toolCallId === "string" ? message.toolCallId : undefined;
423
+ const toolCallId = entry.toolCallId;
435
424
  if (!toolCallId)
436
425
  return;
437
426
  let toolNode = toolsByCallId.get(toolCallId);
@@ -440,87 +429,96 @@ function mergePersistedToolResult(toolsByCallId, childNodes, entry, piboSessionI
440
429
  childNodes.push(toolNode);
441
430
  toolsByCallId.set(toolCallId, toolNode);
442
431
  }
443
- toolNode.status = message.isError === true ? "error" : "done";
444
- toolNode.completedAt = entry.timestamp;
445
- toolNode.output = toolResultOutput(message);
446
- toolNode.error = message.isError === true ? stringifyPreview(toolNode.output) : undefined;
447
- attachAsyncAgentRunNode(toolNode, piboSessionId, entry.timestamp);
432
+ toolNode.status = entry.isError === true || entry.status === "error" ? "error" : "done";
433
+ toolNode.completedAt = entry.createdAt;
434
+ toolNode.output = entry.result ?? { content: entry.content };
435
+ toolNode.error = toolNode.status === "error" ? stringifyPreview(toolNode.output) : undefined;
436
+ attachAsyncAgentRunNode(toolNode, piboSessionId, entry.createdAt);
448
437
  }
449
438
  function createMissingToolResultNode(piboSessionId, entry, entryIndex, toolCallId) {
450
- const message = entry.message;
439
+ const source = traceSource(entry.source);
451
440
  return {
452
441
  id: `tool:${toolCallId}`,
453
- entryId: entry.id,
442
+ entryId: entry.nativeEntryId,
454
443
  piboSessionId,
444
+ eventId: entry.turnId,
455
445
  toolCallId,
456
446
  type: "tool.result",
457
- title: typeof message.toolName === "string" ? message.toolName : "Tool Result",
447
+ title: entry.toolName ?? "Tool Result",
458
448
  status: "done",
459
- startedAt: entry.timestamp,
460
- source: "transcript",
449
+ startedAt: entry.createdAt,
450
+ source,
461
451
  stableKey: `tool:${toolCallId}`,
462
- orderKey: transcriptTraceOrder(entryIndex, 0, "tool.result"),
452
+ orderKey: historyTraceOrder(historyIndex(entry, entryIndex), 0, "tool.result", source),
463
453
  children: [],
464
454
  };
465
455
  }
466
- function toolResultOutput(message) {
467
- if (message.details === undefined)
468
- return { content: message.content };
469
- return { content: message.content, details: message.details };
470
- }
471
456
  function createAssistantMessageNode(input) {
472
457
  const eventIdentity = input.eventId ? `${input.eventId}:assistant:${input.assistantIndex}` : undefined;
458
+ const source = traceSource(input.entry.source);
473
459
  return {
474
- id: eventIdentity ? assistantMessageNodeId(eventIdentity) : `entry:${input.entry.id}:response`,
475
- entryId: input.entry.id,
460
+ id: eventIdentity ? assistantMessageNodeId(eventIdentity) : `${historyEntryNodeId(input.entry)}:response`,
461
+ entryId: input.entry.nativeEntryId,
476
462
  piboSessionId: input.piboSessionId,
477
463
  eventId: input.eventId,
464
+ parentId: input.entry.source === "product" && input.eventId ? messageTurnNodeId(input.eventId) : undefined,
478
465
  type: "assistant.message",
479
466
  title: "Agent Message",
480
467
  status: input.status,
481
- startedAt: input.startedAt ?? input.entry.timestamp,
468
+ startedAt: input.startedAt ?? input.entry.createdAt,
482
469
  completedAt: input.completedAt,
483
470
  summary: input.text,
484
471
  output: input.text,
485
472
  error: input.error,
486
- source: "transcript",
487
- stableKey: eventIdentity ? `assistant:${eventIdentity}` : `entry:${input.entry.id}:response:${input.contentPartIndex}`,
488
- orderKey: transcriptTraceOrder(input.entryIndex, input.contentPartIndex, "assistant.message"),
473
+ source,
474
+ stableKey: eventIdentity ? `assistant:${eventIdentity}` : `${historyEntryStableKey(input.entry)}:response:${input.contentPartIndex}`,
475
+ orderKey: historyTraceOrder(historyIndex(input.entry, input.entryIndex), input.contentPartIndex, "assistant.message", source),
489
476
  children: input.children ?? [],
490
477
  };
491
478
  }
492
- function messageStatus(message) {
493
- if (message && typeof message === "object") {
494
- const stopReason = message.stopReason;
495
- const errorMessage = message.errorMessage;
496
- if (stopReason === "error" || typeof errorMessage === "string")
497
- return "error";
498
- }
479
+ function historyMessageParts(entry) {
480
+ return typeof entry.content === "string" ? [{ type: "text", text: entry.content }] : [...entry.content];
481
+ }
482
+ function historyMessageText(entry) {
483
+ if (typeof entry.content === "string")
484
+ return entry.content;
485
+ return entry.content.map((part) => part.type === "text" ? part.text : "").join("");
486
+ }
487
+ function historyMessageStatus(entry) {
488
+ if (entry.status === "error" || entry.error)
489
+ return "error";
490
+ if (entry.status === "running")
491
+ return "running";
499
492
  return "done";
500
493
  }
501
- function messageError(message) {
502
- if (!message || typeof message !== "object")
494
+ function isSettledAssistantEntry(entry) {
495
+ return entry.status !== "running" && entry.metadata?.stopReason !== "toolUse" && entry.metadata?.stopReason !== "tool_use";
496
+ }
497
+ function historyEntryNodeId(entry) {
498
+ return entry.source === "native" && entry.nativeEntryId ? `entry:${entry.nativeEntryId}` : `history:${entry.id}`;
499
+ }
500
+ function historyEntryStableKey(entry) {
501
+ return historyEntryNodeId(entry);
502
+ }
503
+ function historyIndex(entry, fallback) {
504
+ return entry.sequence ?? fallback;
505
+ }
506
+ function traceSource(source) {
507
+ return source === "native" ? "transcript" : "product-history";
508
+ }
509
+ function normalizedPrompt(value) {
510
+ const normalized = value?.replace(/\s+/g, " ").trim();
511
+ return normalized || undefined;
512
+ }
513
+ function parsedTimestamp(value) {
514
+ if (!value)
503
515
  return undefined;
504
- const errorMessage = message.errorMessage;
505
- return typeof errorMessage === "string" ? errorMessage : undefined;
516
+ const timestamp = new Date(value).getTime();
517
+ return Number.isFinite(timestamp) ? timestamp : undefined;
506
518
  }
507
519
  function hasVisibleText(value) {
508
520
  return typeof value === "string" && value.trim().length > 0;
509
521
  }
510
- function extractText(content) {
511
- if (typeof content === "string")
512
- return content;
513
- if (!Array.isArray(content))
514
- return "";
515
- return content
516
- .map((part) => {
517
- const typed = part;
518
- if (typed.type === "text" && typeof typed.text === "string")
519
- return typed.text;
520
- return "";
521
- })
522
- .join("");
523
- }
524
522
  function stringifyPreview(value) {
525
523
  if (typeof value === "string")
526
524
  return value;