@pasko70/pibo 2.5.2 → 3.0.1
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/context/pibo-native-tooling.md +1 -0
- package/dist/agent-runtime/contract.js +2 -1
- package/dist/agent-runtime/history.js +53 -1
- package/dist/agent-runtime/routed-session.js +100 -26
- package/dist/agent-runtimes/codex-native/adapter.js +304 -30
- package/dist/agent-runtimes/codex-native/client.js +22 -3
- package/dist/agent-runtimes/codex-native/first-use.js +294 -0
- package/dist/agent-runtimes/codex-native/history.js +26 -7
- package/dist/agent-runtimes/codex-native/process.js +14 -0
- package/dist/agent-runtimes/codex-native/thread.js +59 -25
- package/dist/agent-runtimes/codex-native/turn.js +27 -0
- package/dist/agent-runtimes/history-proof.js +8 -0
- package/dist/agent-runtimes/omp/adapter.js +61 -14
- package/dist/agent-runtimes/omp/history.js +189 -34
- package/dist/agent-runtimes/omp/thread.js +82 -36
- package/dist/agent-runtimes/pi/adapter.js +30 -3
- package/dist/agent-runtimes/pi/history.js +66 -5
- package/dist/agent-runtimes/pi/openai-response-observer.js +102 -0
- package/dist/agent-runtimes/pi/routed-session.js +344 -37
- package/dist/apps/chat/chat-api-routes.js +1 -1
- package/dist/apps/chat/chat-files.js +130 -9
- package/dist/apps/chat/chat-settings-routes.js +27 -2
- package/dist/apps/chat/chat-speech.js +100 -0
- package/dist/apps/chat/data/chat-data-mappers.js +25 -5
- package/dist/apps/chat/data/timeline-query-service.js +89 -1
- package/dist/apps/chat/trace-v2.js +210 -8
- package/dist/apps/chat/trace.js +3 -0
- package/dist/apps/chat/web-app.js +108 -3
- package/dist/apps/chat-ui/assets/{dist-DTWJf37A.js → dist-BBDMeU5-.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CkYWKnvy.js → dist-BDIATCQt.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DZ8Wpj-H.js → dist-JnW4v8UE.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Dmblz15N.js → dist-lRiLP9rr.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DjcwoyNY.js → dist-mqCviI-c.js} +1 -1
- package/dist/apps/chat-ui/assets/index-0XOOVxLP.js +228 -0
- package/dist/apps/chat-ui/assets/index-DV7_CgsC.css +1 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-Dtw2Z7jz.js +43 -0
- package/dist/apps/chat-vscode-web/assets/{index-CF1-9PKU.css → index-SluZr_-r.css} +1 -1
- package/dist/apps/chat-vscode-web/index.html +2 -2
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-3.0.1.vsix +0 -0
- package/dist/cli.js +49 -5
- package/dist/config/config.js +59 -8
- package/dist/core/preview-server-settings.js +20 -0
- package/dist/core/session-router.js +464 -37
- package/dist/core/user-settings.js +10 -0
- package/dist/data/payload-store.js +57 -1
- package/dist/data/schema.js +18 -1
- package/dist/debug/trace.js +5 -0
- package/dist/gateway/client.js +368 -65
- package/dist/gateway/protocol.js +2 -0
- package/dist/gateway/server.js +8 -0
- package/dist/gateway/web.js +2 -0
- package/dist/index.js +1 -1
- package/dist/loops/store.js +6 -4
- package/dist/mcp/config.js +89 -17
- package/dist/mcp/daemon-client.js +473 -153
- package/dist/mcp/daemon.js +401 -37
- package/dist/plugins/builtin.js +2 -2
- package/dist/plugins/codex-native.js +2 -0
- package/dist/plugins/registry.js +259 -1
- package/dist/previews/cli.js +345 -0
- package/dist/previews/config.js +61 -0
- package/dist/previews/manager.js +644 -0
- package/dist/previews/network.js +198 -0
- package/dist/previews/plugin.js +11 -0
- package/dist/previews/process-supervisor.js +38 -0
- package/dist/previews/proxy.js +387 -0
- package/dist/previews/store.js +750 -0
- package/dist/previews/types.js +1 -0
- package/dist/previews/web-app.js +446 -0
- package/dist/runs/registry.js +22 -0
- package/dist/runs/tools.js +46 -7
- package/dist/session-ui/terminalRows.js +187 -13
- package/dist/sessions/pibo-data-store.js +37 -0
- package/dist/sessions/runtime-binding-persistence.js +34 -0
- package/dist/sessions/runtime-binding.js +6 -0
- package/dist/sessions/sqlite-store.js +37 -0
- package/dist/shared/trace-engine.js +12 -64
- package/dist/shared/trace-event-projection.js +16 -0
- package/dist/shared/trace-history.js +684 -184
- package/dist/shared/trace-limits.js +7 -0
- package/dist/shared/trace-live-patch.js +61 -0
- package/dist/shared/trace-tool-identity.js +43 -0
- package/dist/speech/openai-codex-realtime-call-proxy.js +248 -0
- package/dist/speech/openai-codex.js +407 -0
- package/dist/speech/types.js +8 -0
- package/dist/subagents/context.js +5 -3
- package/dist/subagents/observations.js +94 -6
- package/dist/subagents/tool.js +103 -20
- package/dist/tools/codex-image-artifacts.js +24 -0
- package/dist/tools/codex-image-generation.js +4 -22
- package/dist/web/channel.js +88 -4
- package/dist/web/http.js +2 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/apps/chat-ui/assets/index-0WZI2phJ.css +0 -1
- package/dist/apps/chat-ui/assets/index-DsgTm1Aw.js +0 -228
- package/dist/apps/chat-vscode-web/assets/index-DvTSSvzN.js +0 -43
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.5.2.vsix +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { compareTraceNodes } from "../shared/trace-
|
|
1
|
+
import { compareTraceNodes } from "../shared/trace-nodes.js";
|
|
2
2
|
import { terminalTextValue } from "./terminalValue.js";
|
|
3
|
+
export const MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS = 20;
|
|
3
4
|
export const COMPACT_TERMINAL_OUTPUT_PREVIEW_LINES = 5;
|
|
4
5
|
export const COMPACT_TERMINAL_EXPLORING_PREVIEW_LINES = 6;
|
|
5
6
|
const CODEX_COMPATIBLE_TOOL_LABELS = {
|
|
@@ -218,11 +219,25 @@ function reconcileConceptualRowCandidates(candidates) {
|
|
|
218
219
|
output: candidate.row.output ?? existing.row.output,
|
|
219
220
|
error: candidate.row.error ?? existing.row.error,
|
|
220
221
|
payloadRefs: { ...existing.row.payloadRefs, ...candidate.row.payloadRefs },
|
|
222
|
+
imagePreviews: mergeImagePreviews(existing.row.imagePreviews, candidate.row.imagePreviews),
|
|
221
223
|
},
|
|
222
224
|
};
|
|
223
225
|
}
|
|
224
226
|
return reconciled;
|
|
225
227
|
}
|
|
228
|
+
function mergeImagePreviews(existing, candidate) {
|
|
229
|
+
if (!existing?.length)
|
|
230
|
+
return candidate?.slice(0, MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS);
|
|
231
|
+
if (!candidate?.length)
|
|
232
|
+
return existing.slice(0, MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS);
|
|
233
|
+
const merged = new Map(existing.map((preview) => [preview.id, preview]));
|
|
234
|
+
for (const preview of candidate) {
|
|
235
|
+
merged.set(preview.id, { ...merged.get(preview.id), ...preview });
|
|
236
|
+
if (merged.size >= MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS)
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
return [...merged.values()];
|
|
240
|
+
}
|
|
226
241
|
function applyCompletedTurnTiming(candidates, turnById) {
|
|
227
242
|
for (const turn of turnById.values()) {
|
|
228
243
|
if (!turn.completedAt)
|
|
@@ -343,20 +358,51 @@ function createToolRowCandidate(node, turnId) {
|
|
|
343
358
|
}
|
|
344
359
|
function createWebSearchToolRow(node) {
|
|
345
360
|
const status = mapStatus(node.status);
|
|
361
|
+
const actionType = webSearchActionType(node);
|
|
346
362
|
const query = webSearchQuery(node);
|
|
363
|
+
const queries = webSearchQueries(node);
|
|
364
|
+
const url = webSearchUrl(node);
|
|
365
|
+
const pattern = webSearchPattern(node);
|
|
366
|
+
const sources = webSearchSources(node.output);
|
|
347
367
|
const sourceCount = webSearchSourceCount(node.output);
|
|
348
368
|
const lines = [
|
|
349
369
|
{
|
|
350
370
|
prefix: "bullet",
|
|
351
|
-
tokens: [token(webSearchVerb(node.status), toneForStatus(node.status), node.status === "error" ? "bold" : "semibold")],
|
|
371
|
+
tokens: [token(webSearchVerb(node.status, actionType), toneForStatus(node.status), node.status === "error" ? "bold" : "semibold")],
|
|
352
372
|
},
|
|
353
373
|
];
|
|
354
374
|
if (query) {
|
|
355
375
|
lines.push({ prefix: "detail", tokens: [token(`query: ${JSON.stringify(query)}`, "cyan")] });
|
|
356
376
|
}
|
|
377
|
+
else if (queries?.length) {
|
|
378
|
+
lines.push({ prefix: "detail", tokens: [token(`queries: ${JSON.stringify(queries)}`, "cyan")] });
|
|
379
|
+
}
|
|
380
|
+
if (url) {
|
|
381
|
+
lines.push({
|
|
382
|
+
prefix: "detail",
|
|
383
|
+
tokens: [token("page: ", "dim"), webLinkToken(url, `Open web page: ${url}`)],
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
if (pattern) {
|
|
387
|
+
lines.push({ prefix: "detail", tokens: [token(`find: ${JSON.stringify(pattern)}`, "cyan")] });
|
|
388
|
+
}
|
|
357
389
|
if (node.status === "done" && sourceCount !== undefined) {
|
|
358
390
|
lines.push({ prefix: "detail", tokens: [token(`sources: ${sourceCount}`, "dim")] });
|
|
359
391
|
}
|
|
392
|
+
const visibleSources = sources.slice(0, 3);
|
|
393
|
+
for (const source of visibleSources) {
|
|
394
|
+
lines.push({
|
|
395
|
+
prefix: "detail",
|
|
396
|
+
tokens: [
|
|
397
|
+
...(source.title ? [token(`${source.title}: `, "dim")] : []),
|
|
398
|
+
webLinkToken(source.url, `Open source: ${source.title ?? source.url}`),
|
|
399
|
+
],
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
const hiddenSourceCount = Math.max(0, (sourceCount ?? sources.length) - visibleSources.length);
|
|
403
|
+
if (visibleSources.length > 0 && hiddenSourceCount > 0) {
|
|
404
|
+
lines.push({ prefix: "detail", tokens: [token(`+${hiddenSourceCount} more sources`, "dim")] });
|
|
405
|
+
}
|
|
360
406
|
if (node.status === "error" && node.error) {
|
|
361
407
|
lines.push({ prefix: "detail", tokens: [token(node.error, "red")] });
|
|
362
408
|
}
|
|
@@ -396,6 +442,7 @@ function createImageToolRow(node, image) {
|
|
|
396
442
|
output: image.summary,
|
|
397
443
|
error: node.error,
|
|
398
444
|
expandable: node.input !== undefined || image.summary !== undefined || Boolean(node.error),
|
|
445
|
+
imagePreviews: image.previews,
|
|
399
446
|
};
|
|
400
447
|
}
|
|
401
448
|
function createToolResultRowCandidate(node, turnId) {
|
|
@@ -889,6 +936,7 @@ function createImageGroup(candidates) {
|
|
|
889
936
|
orderStreamFrameIndex: firstRow?.orderStreamFrameIndex,
|
|
890
937
|
detailItems,
|
|
891
938
|
expandable: detailItems.some((item) => item.input !== undefined || item.output !== undefined || Boolean(item.error)),
|
|
939
|
+
imagePreviews: detailItems.flatMap((item) => item.imagePreviews ?? []).slice(0, MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS),
|
|
892
940
|
previewOmission: omittedDetailCount > 0 ? {
|
|
893
941
|
source: "details",
|
|
894
942
|
visibleLineCount: visibleDetailItems.length,
|
|
@@ -911,6 +959,7 @@ function detailItemsForGroup(candidates, kind) {
|
|
|
911
959
|
payloadRefs: candidate.row.payloadRefs,
|
|
912
960
|
linkedPiboSessionId: candidate.row.linkedPiboSessionId,
|
|
913
961
|
previewOmission: candidate.row.previewOmission,
|
|
962
|
+
imagePreviews: candidate.row.imagePreviews,
|
|
914
963
|
};
|
|
915
964
|
});
|
|
916
965
|
}
|
|
@@ -925,14 +974,17 @@ function classifyImageTool(node) {
|
|
|
925
974
|
: previewPath(args) ?? previewPath(details) ?? previewPath(output);
|
|
926
975
|
const artifactId = codexOperation ? stringValue(details?.artifactId) : undefined;
|
|
927
976
|
const query = previewQuery(args);
|
|
928
|
-
const images = collectImagePayloads(node.output);
|
|
929
|
-
const
|
|
930
|
-
|
|
977
|
+
const images = collectImagePayloads(node.output).slice(0, MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS);
|
|
978
|
+
const payloadRef = node.payloadRefs?.output;
|
|
979
|
+
const persistedImageCount = Math.min(payloadRef?.imageCount ?? 0, MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS);
|
|
980
|
+
const isImageTool = matchesTool(normalized, ["view_image", "image", "screenshot"])
|
|
981
|
+
|| (normalized === "read" && isPreviewableImagePath(path));
|
|
982
|
+
if (!images.length && !persistedImageCount && !isImageTool && !codexOperation)
|
|
931
983
|
return undefined;
|
|
932
984
|
const mimeType = images.map((image) => image.mimeType).find((value) => Boolean(value));
|
|
933
|
-
const count = Math.max(1, images.length);
|
|
985
|
+
const count = Math.max(1, images.length, persistedImageCount);
|
|
934
986
|
const summary = {
|
|
935
|
-
type:
|
|
987
|
+
type: count > 1 ? "images" : images.length === 1 ? "image" : "image_reference",
|
|
936
988
|
toolName: codexOperation ? node.title : undefined,
|
|
937
989
|
operation: codexOperation,
|
|
938
990
|
path,
|
|
@@ -943,10 +995,24 @@ function classifyImageTool(node) {
|
|
|
943
995
|
query,
|
|
944
996
|
mimeType,
|
|
945
997
|
count: count > 1 ? count : undefined,
|
|
946
|
-
detail: images.length ? "Image data hidden in terminal view." : "Image path only; binary data is hidden in terminal view.",
|
|
998
|
+
detail: images.length || persistedImageCount ? "Image data hidden in terminal view." : "Image path only; binary data is hidden in terminal view.",
|
|
947
999
|
};
|
|
948
1000
|
const labelTarget = path ?? artifactId ?? query ?? mimeType ?? "image";
|
|
949
1001
|
const verb = codexOperation ? codexImageVerb(node.status, codexOperation) : imageToolVerb(node.status, count);
|
|
1002
|
+
const previewImages = images.length
|
|
1003
|
+
? images
|
|
1004
|
+
: Array.from({ length: Math.max(1, persistedImageCount) }, () => ({ mimeType }));
|
|
1005
|
+
const previews = previewImages.map((image, index) => ({
|
|
1006
|
+
id: `${node.id}:image:${index}`,
|
|
1007
|
+
label: previewImages.length > 1 ? `${labelTarget} (${index + 1}/${previewImages.length})` : labelTarget,
|
|
1008
|
+
path,
|
|
1009
|
+
artifactId,
|
|
1010
|
+
payloadRef: payloadRef?.ref,
|
|
1011
|
+
payloadImageIndex: payloadRef ? index : undefined,
|
|
1012
|
+
traceNodeId: payloadRef ? payloadRef.nodeId ?? node.id : undefined,
|
|
1013
|
+
generatedToolCallId: codexOperation ? node.toolCallId : undefined,
|
|
1014
|
+
mimeType: image.mimeType ?? mimeType,
|
|
1015
|
+
}));
|
|
950
1016
|
return {
|
|
951
1017
|
count,
|
|
952
1018
|
path,
|
|
@@ -956,6 +1022,7 @@ function classifyImageTool(node) {
|
|
|
956
1022
|
verb,
|
|
957
1023
|
groupable: !codexOperation,
|
|
958
1024
|
summary,
|
|
1025
|
+
previews,
|
|
959
1026
|
detail: {
|
|
960
1027
|
id: node.id,
|
|
961
1028
|
label: `${verb} ${labelTarget}`,
|
|
@@ -963,19 +1030,32 @@ function classifyImageTool(node) {
|
|
|
963
1030
|
input: sanitizeImagePayload(node.input),
|
|
964
1031
|
output: summary,
|
|
965
1032
|
error: node.error,
|
|
1033
|
+
imagePreviews: previews,
|
|
966
1034
|
},
|
|
967
1035
|
};
|
|
968
1036
|
}
|
|
1037
|
+
function isPreviewableImagePath(path) {
|
|
1038
|
+
if (!path)
|
|
1039
|
+
return false;
|
|
1040
|
+
return /\.(?:png|jpe?g|gif|webp|bmp|avif)$/i.test(path.split(/[?#]/, 1)[0] ?? "");
|
|
1041
|
+
}
|
|
969
1042
|
function collectImagePayloads(value, depth = 0, seen = new Set()) {
|
|
970
|
-
if (depth > 5 || value === undefined || value === null)
|
|
1043
|
+
if (depth > 5 || seen.size >= 1_000 || value === undefined || value === null)
|
|
971
1044
|
return [];
|
|
972
1045
|
if (typeof value !== "object")
|
|
973
1046
|
return [];
|
|
974
1047
|
if (seen.has(value))
|
|
975
1048
|
return [];
|
|
976
1049
|
seen.add(value);
|
|
977
|
-
if (Array.isArray(value))
|
|
978
|
-
|
|
1050
|
+
if (Array.isArray(value)) {
|
|
1051
|
+
const images = [];
|
|
1052
|
+
for (const item of value) {
|
|
1053
|
+
images.push(...collectImagePayloads(item, depth + 1, seen));
|
|
1054
|
+
if (images.length >= MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS)
|
|
1055
|
+
return images.slice(0, MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS);
|
|
1056
|
+
}
|
|
1057
|
+
return images;
|
|
1058
|
+
}
|
|
979
1059
|
const record = value;
|
|
980
1060
|
const type = typeof record.type === "string" ? record.type.toLowerCase() : undefined;
|
|
981
1061
|
const mimeType = typeof record.mimeType === "string" ? record.mimeType : typeof record.mime_type === "string" ? record.mime_type : undefined;
|
|
@@ -994,7 +1074,13 @@ function collectImagePayloads(value, depth = 0, seen = new Set()) {
|
|
|
994
1074
|
nested.push(record.result);
|
|
995
1075
|
if ("output" in record)
|
|
996
1076
|
nested.push(record.output);
|
|
997
|
-
|
|
1077
|
+
const images = [];
|
|
1078
|
+
for (const item of nested) {
|
|
1079
|
+
images.push(...collectImagePayloads(item, depth + 1, seen));
|
|
1080
|
+
if (images.length >= MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS)
|
|
1081
|
+
break;
|
|
1082
|
+
}
|
|
1083
|
+
return images.slice(0, MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS);
|
|
998
1084
|
}
|
|
999
1085
|
function sanitizeImagePayload(value) {
|
|
1000
1086
|
if (Array.isArray(value))
|
|
@@ -1186,18 +1272,84 @@ function isShellToolName(name) {
|
|
|
1186
1272
|
function isWebSearchToolName(name) {
|
|
1187
1273
|
return (name ?? "").trim().toLowerCase() === "web_search";
|
|
1188
1274
|
}
|
|
1189
|
-
function webSearchVerb(status) {
|
|
1275
|
+
function webSearchVerb(status, actionType) {
|
|
1276
|
+
if (actionType === "open_page") {
|
|
1277
|
+
if (status === "running")
|
|
1278
|
+
return "Opening web page";
|
|
1279
|
+
if (status === "error")
|
|
1280
|
+
return "Opening web page failed";
|
|
1281
|
+
return "Opened web page";
|
|
1282
|
+
}
|
|
1283
|
+
if (actionType === "find_in_page") {
|
|
1284
|
+
if (status === "running")
|
|
1285
|
+
return "Finding in web page";
|
|
1286
|
+
if (status === "error")
|
|
1287
|
+
return "Finding in web page failed";
|
|
1288
|
+
return "Found in web page";
|
|
1289
|
+
}
|
|
1190
1290
|
if (status === "running")
|
|
1191
1291
|
return "Searching web";
|
|
1192
1292
|
if (status === "error")
|
|
1193
1293
|
return "Web search failed";
|
|
1194
1294
|
return "Searched web";
|
|
1195
1295
|
}
|
|
1296
|
+
function webSearchActionType(node) {
|
|
1297
|
+
const input = isRecord(node.input) ? node.input : undefined;
|
|
1298
|
+
const output = isRecord(node.output) ? node.output : undefined;
|
|
1299
|
+
return stringValue(input?.actionType) ?? stringValue(output?.actionType);
|
|
1300
|
+
}
|
|
1196
1301
|
function webSearchQuery(node) {
|
|
1197
1302
|
const input = isRecord(node.input) ? node.input : undefined;
|
|
1198
1303
|
const output = isRecord(node.output) ? node.output : undefined;
|
|
1199
1304
|
return stringValue(input?.query) ?? stringValue(output?.query) ?? stringValue(node.summary);
|
|
1200
1305
|
}
|
|
1306
|
+
function webSearchQueries(node) {
|
|
1307
|
+
const input = isRecord(node.input) ? node.input : undefined;
|
|
1308
|
+
const output = isRecord(node.output) ? node.output : undefined;
|
|
1309
|
+
for (const value of [input?.queries, output?.queries]) {
|
|
1310
|
+
if (!Array.isArray(value))
|
|
1311
|
+
continue;
|
|
1312
|
+
const queries = [...new Set(value.flatMap((candidate) => {
|
|
1313
|
+
const normalized = stringValue(candidate)?.trim();
|
|
1314
|
+
return normalized ? [normalized] : [];
|
|
1315
|
+
}))];
|
|
1316
|
+
if (queries.length)
|
|
1317
|
+
return queries;
|
|
1318
|
+
}
|
|
1319
|
+
return undefined;
|
|
1320
|
+
}
|
|
1321
|
+
function webSearchUrl(node) {
|
|
1322
|
+
const input = isRecord(node.input) ? node.input : undefined;
|
|
1323
|
+
const output = isRecord(node.output) ? node.output : undefined;
|
|
1324
|
+
return stringValue(input?.url) ?? stringValue(output?.url);
|
|
1325
|
+
}
|
|
1326
|
+
function webSearchPattern(node) {
|
|
1327
|
+
const input = isRecord(node.input) ? node.input : undefined;
|
|
1328
|
+
const output = isRecord(node.output) ? node.output : undefined;
|
|
1329
|
+
return stringValue(input?.pattern) ?? stringValue(output?.pattern);
|
|
1330
|
+
}
|
|
1331
|
+
function webSearchSources(output) {
|
|
1332
|
+
if (!isRecord(output))
|
|
1333
|
+
return [];
|
|
1334
|
+
const candidates = output.sources ?? output.citations ?? output.results;
|
|
1335
|
+
if (!Array.isArray(candidates))
|
|
1336
|
+
return [];
|
|
1337
|
+
const sources = new Map();
|
|
1338
|
+
for (const candidate of candidates) {
|
|
1339
|
+
const record = isRecord(candidate) ? candidate : undefined;
|
|
1340
|
+
const rawUrl = typeof candidate === "string"
|
|
1341
|
+
? candidate
|
|
1342
|
+
: stringValue(record?.url) ?? stringValue(record?.href) ?? stringValue(record?.link);
|
|
1343
|
+
const url = safeWebHref(rawUrl, true);
|
|
1344
|
+
if (!url)
|
|
1345
|
+
continue;
|
|
1346
|
+
const title = stringValue(record?.title)?.trim() ?? stringValue(record?.name)?.trim();
|
|
1347
|
+
const existing = sources.get(url);
|
|
1348
|
+
if (!existing || (!existing.title && title))
|
|
1349
|
+
sources.set(url, { url, ...(title ? { title } : {}) });
|
|
1350
|
+
}
|
|
1351
|
+
return [...sources.values()];
|
|
1352
|
+
}
|
|
1201
1353
|
function webSearchSourceCount(output) {
|
|
1202
1354
|
if (!isRecord(output))
|
|
1203
1355
|
return undefined;
|
|
@@ -1207,6 +1359,28 @@ function webSearchSourceCount(output) {
|
|
|
1207
1359
|
const sources = output.sources ?? output.citations ?? output.results;
|
|
1208
1360
|
return Array.isArray(sources) ? sources.length : undefined;
|
|
1209
1361
|
}
|
|
1362
|
+
function safeWebHref(value, stripHash = false) {
|
|
1363
|
+
if (!value)
|
|
1364
|
+
return undefined;
|
|
1365
|
+
try {
|
|
1366
|
+
const url = new URL(value.trim());
|
|
1367
|
+
if ((url.protocol !== "https:" && url.protocol !== "http:") || url.username || url.password)
|
|
1368
|
+
return undefined;
|
|
1369
|
+
if (stripHash)
|
|
1370
|
+
url.hash = "";
|
|
1371
|
+
return url.href;
|
|
1372
|
+
}
|
|
1373
|
+
catch {
|
|
1374
|
+
return undefined;
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
function webLinkToken(value, ariaLabel) {
|
|
1378
|
+
const href = safeWebHref(value);
|
|
1379
|
+
return {
|
|
1380
|
+
...token(value, href ? "blue" : "dim"),
|
|
1381
|
+
...(href ? { href, ariaLabel } : {}),
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1210
1384
|
function shellCommandValue(value) {
|
|
1211
1385
|
if (!isRecord(value))
|
|
1212
1386
|
return undefined;
|
|
@@ -22,10 +22,12 @@ const SESSION_SELECT = `
|
|
|
22
22
|
LEFT JOIN session_runtime_bindings b ON b.pibo_session_id = s.id
|
|
23
23
|
`;
|
|
24
24
|
export class PiboDataSessionStore {
|
|
25
|
+
#concreteRuntimeBindingCasIdentity;
|
|
25
26
|
dataStore;
|
|
26
27
|
db;
|
|
27
28
|
ownsDataStore;
|
|
28
29
|
constructor(dataStore = new PiboDataStore()) {
|
|
30
|
+
this.#concreteRuntimeBindingCasIdentity = new.target === PiboDataSessionStore;
|
|
29
31
|
if (typeof dataStore === "string") {
|
|
30
32
|
this.dataStore = new PiboDataStore(dataStore);
|
|
31
33
|
this.ownsDataStore = true;
|
|
@@ -36,6 +38,13 @@ export class PiboDataSessionStore {
|
|
|
36
38
|
}
|
|
37
39
|
this.db = this.dataStore.db;
|
|
38
40
|
}
|
|
41
|
+
/** @internal Read-only concrete-construction identity; it cannot mint authorization. */
|
|
42
|
+
static hasConcreteRuntimeBindingCasIdentity(store) {
|
|
43
|
+
return typeof store === "object"
|
|
44
|
+
&& store !== null
|
|
45
|
+
&& #concreteRuntimeBindingCasIdentity in store
|
|
46
|
+
&& store.#concreteRuntimeBindingCasIdentity;
|
|
47
|
+
}
|
|
39
48
|
get(id) {
|
|
40
49
|
const row = this.db.prepare(`${SESSION_SELECT} WHERE s.id = ? AND s.deleted_at IS NULL`).get(id);
|
|
41
50
|
return row ? sessionFromRow(row) : undefined;
|
|
@@ -285,6 +294,34 @@ export class PiboDataSessionStore {
|
|
|
285
294
|
`).run(binding.piboSessionId, binding.runtimeInstanceId, binding.adapterId, binding.nativeSessionId ?? null, binding.state, binding.protocol ?? null, binding.protocolVersion ?? null, binding.adapterVersion ?? null, binding.locator ? JSON.stringify(binding.locator) : null, JSON.stringify(binding.metadata ?? {}), binding.revision ?? 1, binding.createdAt ?? new Date().toISOString(), binding.updatedAt ?? binding.createdAt ?? new Date().toISOString());
|
|
286
295
|
}
|
|
287
296
|
}
|
|
297
|
+
const auditedPiboDataGet = PiboDataSessionStore.prototype.get;
|
|
298
|
+
const auditedPiboDataGetRuntimeBinding = PiboDataSessionStore.prototype.getRuntimeBinding;
|
|
299
|
+
const auditedPiboDataRuntimeBindingCas = PiboDataSessionStore.prototype.updateRuntimeBinding;
|
|
300
|
+
const hasConcretePiboDataRuntimeBindingCasIdentity = PiboDataSessionStore.hasConcreteRuntimeBindingCasIdentity;
|
|
301
|
+
/** @internal Resolves only the original CAS of an exact, genuinely constructed built-in store. */
|
|
302
|
+
export function resolvePiboDataRuntimeBindingCas(store) {
|
|
303
|
+
if (!hasConcretePiboDataRuntimeBindingCasIdentity(store)
|
|
304
|
+
|| Object.getPrototypeOf(store) !== PiboDataSessionStore.prototype
|
|
305
|
+
|| Object.prototype.hasOwnProperty.call(store, "get")
|
|
306
|
+
|| Object.prototype.hasOwnProperty.call(store, "getRuntimeBinding")
|
|
307
|
+
|| Object.prototype.hasOwnProperty.call(store, "updateRuntimeBinding")
|
|
308
|
+
|| PiboDataSessionStore.prototype.get !== auditedPiboDataGet
|
|
309
|
+
|| PiboDataSessionStore.prototype.getRuntimeBinding !== auditedPiboDataGetRuntimeBinding
|
|
310
|
+
|| PiboDataSessionStore.prototype.updateRuntimeBinding !== auditedPiboDataRuntimeBindingCas)
|
|
311
|
+
return undefined;
|
|
312
|
+
const auditedStore = new Proxy(store, {
|
|
313
|
+
get(target, property) {
|
|
314
|
+
if (property === "get")
|
|
315
|
+
return auditedPiboDataGet;
|
|
316
|
+
if (property === "getRuntimeBinding")
|
|
317
|
+
return auditedPiboDataGetRuntimeBinding;
|
|
318
|
+
if (property === "updateRuntimeBinding")
|
|
319
|
+
return auditedPiboDataRuntimeBindingCas;
|
|
320
|
+
return Reflect.get(target, property, target);
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
return auditedPiboDataRuntimeBindingCas.bind(auditedStore);
|
|
324
|
+
}
|
|
288
325
|
export function createDefaultPiboDataSessionStore() {
|
|
289
326
|
return new PiboDataSessionStore(new PiboDataStore());
|
|
290
327
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { resolvePiboDataRuntimeBindingCas } from "./pibo-data-store.js";
|
|
2
|
+
import { resolveSqliteRuntimeBindingCas } from "./sqlite-store.js";
|
|
3
|
+
const runtimeBindingPersistenceCapabilities = new WeakSet();
|
|
4
|
+
function auditedRuntimeBindingCas(store) {
|
|
5
|
+
return (resolvePiboDataRuntimeBindingCas(store) ?? resolveSqliteRuntimeBindingCas(store));
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Mints runtime-binding persistence only for exact audited built-in stores.
|
|
9
|
+
* The capability closes over the audited prototype CAS, so mutable instance
|
|
10
|
+
* members and structural look-alikes cannot authorize native first use.
|
|
11
|
+
*/
|
|
12
|
+
export function createAgentRuntimeBindingPersistence(store, options) {
|
|
13
|
+
const compareAndSet = auditedRuntimeBindingCas(store);
|
|
14
|
+
if (!compareAndSet)
|
|
15
|
+
return undefined;
|
|
16
|
+
const piboSessionId = options.piboSessionId;
|
|
17
|
+
const onPersisted = options.onPersisted;
|
|
18
|
+
const capability = Object.freeze({
|
|
19
|
+
async compareAndSet(binding, expectedRevision) {
|
|
20
|
+
const updated = compareAndSet(piboSessionId, { ...structuredClone(binding), piboSessionId }, { expectedRevision });
|
|
21
|
+
if (!updated)
|
|
22
|
+
throw new Error(`Pibo session "${piboSessionId}" no longer exists.`);
|
|
23
|
+
onPersisted?.(structuredClone(updated));
|
|
24
|
+
return updated;
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
runtimeBindingPersistenceCapabilities.add(capability);
|
|
28
|
+
return capability;
|
|
29
|
+
}
|
|
30
|
+
export function isAgentRuntimeBindingPersistence(value) {
|
|
31
|
+
return typeof value === "object"
|
|
32
|
+
&& value !== null
|
|
33
|
+
&& runtimeBindingPersistenceCapabilities.has(value);
|
|
34
|
+
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { DEFAULT_AGENT_RUNTIME_INSTANCE_ID } from "../core/profiles.js";
|
|
2
|
+
export const PENDING_NATIVE_SESSION_METADATA_KEY = "piboPendingNativeSession";
|
|
3
|
+
export function hasPendingNativeSession(binding) {
|
|
4
|
+
return binding.state === "unbound"
|
|
5
|
+
&& Boolean(binding.nativeSessionId)
|
|
6
|
+
&& binding.metadata?.[PENDING_NATIVE_SESSION_METADATA_KEY] === true;
|
|
7
|
+
}
|
|
2
8
|
export class RuntimeSessionBindingConflictError extends Error {
|
|
3
9
|
piboSessionId;
|
|
4
10
|
expectedRevision;
|
|
@@ -24,8 +24,10 @@ const SESSION_SELECT = `
|
|
|
24
24
|
LEFT JOIN pibo_session_runtime_bindings b ON b.pibo_session_id = s.id
|
|
25
25
|
`;
|
|
26
26
|
export class SqlitePiboSessionStore {
|
|
27
|
+
#concreteRuntimeBindingCasIdentity;
|
|
27
28
|
db;
|
|
28
29
|
constructor(path) {
|
|
30
|
+
this.#concreteRuntimeBindingCasIdentity = new.target === SqlitePiboSessionStore;
|
|
29
31
|
const resolvedPath = path === ":memory:" ? path : resolve(path);
|
|
30
32
|
if (resolvedPath !== ":memory:") {
|
|
31
33
|
mkdirSync(dirname(resolvedPath), { recursive: true });
|
|
@@ -41,6 +43,13 @@ export class SqlitePiboSessionStore {
|
|
|
41
43
|
this.applySchema();
|
|
42
44
|
this.applyRuntimeBindingSchema();
|
|
43
45
|
}
|
|
46
|
+
/** @internal Read-only concrete-construction identity; it cannot mint authorization. */
|
|
47
|
+
static hasConcreteRuntimeBindingCasIdentity(store) {
|
|
48
|
+
return typeof store === "object"
|
|
49
|
+
&& store !== null
|
|
50
|
+
&& #concreteRuntimeBindingCasIdentity in store
|
|
51
|
+
&& store.#concreteRuntimeBindingCasIdentity;
|
|
52
|
+
}
|
|
44
53
|
applySchema() {
|
|
45
54
|
this.db.exec(`
|
|
46
55
|
CREATE TABLE IF NOT EXISTS pibo_sessions (
|
|
@@ -364,6 +373,34 @@ export class SqlitePiboSessionStore {
|
|
|
364
373
|
this.db.close();
|
|
365
374
|
}
|
|
366
375
|
}
|
|
376
|
+
const auditedSqliteGet = SqlitePiboSessionStore.prototype.get;
|
|
377
|
+
const auditedSqliteGetRuntimeBinding = SqlitePiboSessionStore.prototype.getRuntimeBinding;
|
|
378
|
+
const auditedSqliteRuntimeBindingCas = SqlitePiboSessionStore.prototype.updateRuntimeBinding;
|
|
379
|
+
const hasConcreteSqliteRuntimeBindingCasIdentity = SqlitePiboSessionStore.hasConcreteRuntimeBindingCasIdentity;
|
|
380
|
+
/** @internal Resolves only the original CAS of an exact, genuinely constructed built-in store. */
|
|
381
|
+
export function resolveSqliteRuntimeBindingCas(store) {
|
|
382
|
+
if (!hasConcreteSqliteRuntimeBindingCasIdentity(store)
|
|
383
|
+
|| Object.getPrototypeOf(store) !== SqlitePiboSessionStore.prototype
|
|
384
|
+
|| Object.prototype.hasOwnProperty.call(store, "get")
|
|
385
|
+
|| Object.prototype.hasOwnProperty.call(store, "getRuntimeBinding")
|
|
386
|
+
|| Object.prototype.hasOwnProperty.call(store, "updateRuntimeBinding")
|
|
387
|
+
|| SqlitePiboSessionStore.prototype.get !== auditedSqliteGet
|
|
388
|
+
|| SqlitePiboSessionStore.prototype.getRuntimeBinding !== auditedSqliteGetRuntimeBinding
|
|
389
|
+
|| SqlitePiboSessionStore.prototype.updateRuntimeBinding !== auditedSqliteRuntimeBindingCas)
|
|
390
|
+
return undefined;
|
|
391
|
+
const auditedStore = new Proxy(store, {
|
|
392
|
+
get(target, property) {
|
|
393
|
+
if (property === "get")
|
|
394
|
+
return auditedSqliteGet;
|
|
395
|
+
if (property === "getRuntimeBinding")
|
|
396
|
+
return auditedSqliteGetRuntimeBinding;
|
|
397
|
+
if (property === "updateRuntimeBinding")
|
|
398
|
+
return auditedSqliteRuntimeBindingCas;
|
|
399
|
+
return Reflect.get(target, property, target);
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
return auditedSqliteRuntimeBindingCas.bind(auditedStore);
|
|
403
|
+
}
|
|
367
404
|
export function createDefaultPiboSessionStore(_cwd) {
|
|
368
405
|
return new SqlitePiboSessionStore(piboHomePath("pibo-sessions.sqlite"));
|
|
369
406
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { reconcileAsyncAgentRunStatuses } from "./trace-async-agent-runs.js";
|
|
2
|
-
import { applySingleEventToNodes,
|
|
2
|
+
import { applySingleEventToNodes, dedupeTraceEvents, findOpenTranscriptEventIds, latestTraceStreamId, mergeMessageTurnTimings, messageTurnTimingsFromEvents, reconcileTranscriptUserMessages, } from "./trace-event-projection.js";
|
|
3
3
|
import { flattenTraceNodes, mapTraceNodesById, nestTraceNodes } from "./trace-nodes.js";
|
|
4
|
-
import { nestMutableCopiedTraceNodes, shareUnchangedTraceNodes } from "./trace-patch-nodes.js";
|
|
5
4
|
import { mapTraceChildSessionsByParent, mapTraceSubagentSessionLinks, } from "./trace-subagent-links.js";
|
|
6
5
|
import { projectHistoryEntries, traceNodesFromHistoryEntries } from "./trace-history.js";
|
|
6
|
+
import { TRACE_RECONCILIATION_TIMING_CAP } from "./trace-limits.js";
|
|
7
7
|
export { isRunStartToolNode } from "./trace-async-agent-runs.js";
|
|
8
|
+
export { patchTraceViewWithEvent, patchTraceViewWithEvents } from "./trace-live-patch.js";
|
|
8
9
|
export { assistantMessageNodeId, dedupeTraceEvents, latestTraceStreamId, messageTurnNodeId, thinkingNodeId, traceEventDedupeKey, } from "./trace-event-projection.js";
|
|
9
10
|
export { traceNodesFromHistoryEntries } from "./trace-history.js";
|
|
10
11
|
export { compareTraceNodes, flattenTraceNodes, mapTraceNodesById, nestTraceNodes, sortTraceNodes, } from "./trace-nodes.js";
|
|
@@ -13,9 +14,15 @@ export function buildTraceViewFromEvents(input) {
|
|
|
13
14
|
const events = dedupeTraceEvents(input.events);
|
|
14
15
|
const allEntries = input.historyEntries ?? [];
|
|
15
16
|
const openHistoryEventIds = findOpenTranscriptEventIds(events, sessionStatus);
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
17
|
+
const suppliedTurnTimings = input.turnTimings ?? [];
|
|
18
|
+
const eventTurnTimings = messageTurnTimingsFromEvents(events);
|
|
19
|
+
const timingOverflow = suppliedTurnTimings.length + eventTurnTimings.length > TRACE_RECONCILIATION_TIMING_CAP;
|
|
20
|
+
const turnTimings = timingOverflow
|
|
21
|
+
? []
|
|
22
|
+
: mergeMessageTurnTimings(suppliedTurnTimings, eventTurnTimings);
|
|
23
|
+
const historyTurnTimings = timingOverflow ? [...suppliedTurnTimings, ...eventTurnTimings] : turnTimings;
|
|
24
|
+
const entries = projectHistoryEntries(allEntries, sessionStatus, openHistoryEventIds, historyTurnTimings, input.historyReconciliationProof, input.historyReconciliationAuthoritative);
|
|
25
|
+
const nodes = traceNodesFromHistoryEntries(input.session.id, entries, historyTurnTimings, input.historyReconciliationProof, input.historyReconciliationAuthoritative);
|
|
19
26
|
reconcileTranscriptUserMessages(nodes, events, turnTimings);
|
|
20
27
|
const byId = mapTraceNodesById(nodes);
|
|
21
28
|
const childByParent = mapTraceChildSessionsByParent(input.sessions ?? []);
|
|
@@ -46,62 +53,3 @@ export function buildTraceViewFromEvents(input) {
|
|
|
46
53
|
: [],
|
|
47
54
|
};
|
|
48
55
|
}
|
|
49
|
-
// ── transcript helpers ───────────────────────────────────────────
|
|
50
|
-
export function patchTraceViewWithEvent(view, event, sessionStatus) {
|
|
51
|
-
return patchTraceViewWithEvents(view, [event], sessionStatus);
|
|
52
|
-
}
|
|
53
|
-
export function patchTraceViewWithEvents(view, events, sessionStatus) {
|
|
54
|
-
if (!events.length)
|
|
55
|
-
return view;
|
|
56
|
-
const seenEventKeys = new Set(view.rawEvents.map((event) => traceEventDedupeKey(event)));
|
|
57
|
-
const candidateEvents = [];
|
|
58
|
-
for (const event of events) {
|
|
59
|
-
const eventKey = traceEventDedupeKey(event);
|
|
60
|
-
if (seenEventKeys.has(eventKey))
|
|
61
|
-
continue;
|
|
62
|
-
seenEventKeys.add(eventKey);
|
|
63
|
-
candidateEvents.push(event);
|
|
64
|
-
}
|
|
65
|
-
if (!candidateEvents.length)
|
|
66
|
-
return view;
|
|
67
|
-
const previousFlatNodes = flattenTraceNodes(view.nodes);
|
|
68
|
-
const allNodes = [];
|
|
69
|
-
const byId = new Map();
|
|
70
|
-
const previousById = new Map();
|
|
71
|
-
for (const previousNode of previousFlatNodes) {
|
|
72
|
-
previousById.set(previousNode.id, previousNode);
|
|
73
|
-
const nextNode = { ...previousNode, children: [] };
|
|
74
|
-
allNodes.push(nextNode);
|
|
75
|
-
byId.set(nextNode.id, nextNode);
|
|
76
|
-
}
|
|
77
|
-
const childByParent = new Map();
|
|
78
|
-
const linkedChildByToolCallId = new Map();
|
|
79
|
-
const openTranscriptEventIds = new Set();
|
|
80
|
-
const emptyHistoryCoverage = { mode: "none", eventIds: new Set(), toolCallIds: new Set() };
|
|
81
|
-
const appliedEvents = [];
|
|
82
|
-
let contentDeltaChangedNodeIds = new Set();
|
|
83
|
-
for (const event of candidateEvents) {
|
|
84
|
-
if (isConfirmedUserMessageEcho(allNodes, event))
|
|
85
|
-
continue;
|
|
86
|
-
appliedEvents.push(event);
|
|
87
|
-
const contentDeltaNodeId = contentDeltaPatchNodeId(event.payload);
|
|
88
|
-
if (contentDeltaChangedNodeIds && contentDeltaNodeId)
|
|
89
|
-
contentDeltaChangedNodeIds.add(contentDeltaNodeId);
|
|
90
|
-
else
|
|
91
|
-
contentDeltaChangedNodeIds = undefined;
|
|
92
|
-
applySingleEventToNodes(allNodes, byId, view.piboSessionId, event, childByParent, linkedChildByToolCallId, emptyHistoryCoverage, openTranscriptEventIds, sessionStatus);
|
|
93
|
-
}
|
|
94
|
-
if (!appliedEvents.length)
|
|
95
|
-
return view;
|
|
96
|
-
const nestedNodes = nestMutableCopiedTraceNodes(allNodes);
|
|
97
|
-
if (eventsCanAffectAsyncAgentRunStatus(appliedEvents)) {
|
|
98
|
-
reconcileAsyncAgentRunStatuses(nestedNodes);
|
|
99
|
-
}
|
|
100
|
-
const sharedNodes = shareUnchangedTraceNodes(previousById, nestedNodes, contentDeltaChangedNodeIds);
|
|
101
|
-
return {
|
|
102
|
-
...view,
|
|
103
|
-
rawEvents: view.rawEvents.length ? [...view.rawEvents, ...appliedEvents] : appliedEvents,
|
|
104
|
-
nodes: sharedNodes,
|
|
105
|
-
latestStreamId: latestTraceStreamId(appliedEvents, view.latestStreamId),
|
|
106
|
-
};
|
|
107
|
-
}
|
|
@@ -43,6 +43,7 @@ export function applySingleEventToNodes(nodes, byId, piboSessionId, storedEvent,
|
|
|
43
43
|
const node = traceNodeFromEvent(piboSessionId, payload, childByParent, linkedChildByToolCallId, sessionStatus, storedEvent.createdAt, storedEvent.eventSequence, storedEvent.streamId, storedEvent.streamFrameIndex, storedEvent.traceSource);
|
|
44
44
|
if (!node)
|
|
45
45
|
return;
|
|
46
|
+
applyStoredPayloadRef(node, payload, storedEvent.storedPayloadRef);
|
|
46
47
|
if (node.type === "user.message" &&
|
|
47
48
|
node.status === "running" &&
|
|
48
49
|
!node.parentId &&
|
|
@@ -124,6 +125,16 @@ export function applySingleEventToNodes(nodes, byId, piboSessionId, storedEvent,
|
|
|
124
125
|
for (const indexed of flattenTraceNodes([node]))
|
|
125
126
|
byId.set(indexed.id, indexed);
|
|
126
127
|
}
|
|
128
|
+
function applyStoredPayloadRef(node, event, storedPayloadRef) {
|
|
129
|
+
if (!storedPayloadRef)
|
|
130
|
+
return;
|
|
131
|
+
if (event.type === "tool_call" || event.type === "tool_execution_started") {
|
|
132
|
+
node.payloadRefs = { ...node.payloadRefs, input: storedPayloadRef };
|
|
133
|
+
}
|
|
134
|
+
if (event.type === "tool_execution_finished" || event.type === "tool_execution_updated") {
|
|
135
|
+
node.payloadRefs = { ...node.payloadRefs, output: storedPayloadRef };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
127
138
|
function assistantMessageNodeFromEvent(piboSessionId, event, createdAt, eventSequence, streamId, streamFrameIndex, traceSource) {
|
|
128
139
|
const eventId = typeof event.eventId === "string" ? event.eventId : undefined;
|
|
129
140
|
const assistantId = assistantEventNodeId(event);
|
|
@@ -704,6 +715,7 @@ export function mergeMessageTurnTimings(...groups) {
|
|
|
704
715
|
eventId: timing.eventId,
|
|
705
716
|
userText: timing.userText ?? existing.userText,
|
|
706
717
|
userMessageType: timing.userMessageType ?? existing.userMessageType,
|
|
718
|
+
activeEventId: timing.activeEventId ?? existing.activeEventId,
|
|
707
719
|
startedAt: timing.startedAt ?? existing.startedAt,
|
|
708
720
|
completedAt: timing.completedAt ?? existing.completedAt,
|
|
709
721
|
durationMs: timing.durationMs ?? existing.durationMs,
|
|
@@ -766,6 +778,8 @@ export function messageTurnTimingsFromEvents(events) {
|
|
|
766
778
|
else if (event.type === "message_steered") {
|
|
767
779
|
timing.userText ??= event.text;
|
|
768
780
|
timing.userMessageType = "message_steered";
|
|
781
|
+
timing.activeEventId ??= event.activeEventId;
|
|
782
|
+
timing.startedAt ??= storedEvent.createdAt;
|
|
769
783
|
}
|
|
770
784
|
else if (event.type === "message_started") {
|
|
771
785
|
timing.userText ??= event.text;
|
|
@@ -797,6 +811,7 @@ export function messageTurnTimingsFromEvents(events) {
|
|
|
797
811
|
userText: timing.userText,
|
|
798
812
|
startedAt: timing.startedAt,
|
|
799
813
|
...(timing.userMessageType ? { userMessageType: timing.userMessageType } : {}),
|
|
814
|
+
...(timing.activeEventId ? { activeEventId: timing.activeEventId } : {}),
|
|
800
815
|
completedAt: timing.completedAt,
|
|
801
816
|
durationMs: startedAtMs === undefined || completedAtMs === undefined
|
|
802
817
|
? undefined
|
|
@@ -926,6 +941,7 @@ function mergeToolEvent(target, update) {
|
|
|
926
941
|
target.output = update.output ?? target.output;
|
|
927
942
|
target.error = update.error ?? target.error;
|
|
928
943
|
target.completedAt = update.completedAt ?? target.completedAt;
|
|
944
|
+
target.payloadRefs = { ...target.payloadRefs, ...update.payloadRefs };
|
|
929
945
|
target.linkedPiboSessionId = update.linkedPiboSessionId ?? target.linkedPiboSessionId;
|
|
930
946
|
}
|
|
931
947
|
function mergeSubagentSessionLink(target, update) {
|