@meridianlabs/log-viewer 0.3.243 → 0.3.245

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 (90) hide show
  1. package/lib/e2e/viewer-xss.spec.d.ts +2 -0
  2. package/lib/e2e/viewer-xss.spec.d.ts.map +1 -0
  3. package/lib/index.js +872 -421
  4. package/lib/index.js.map +1 -1
  5. package/lib/src/app/log-list/LogsPanel.d.ts.map +1 -1
  6. package/lib/src/app/log-list/grid/LogListGrid.d.ts.map +1 -1
  7. package/lib/src/app/log-list/grid/columns/hooks.d.ts.map +1 -1
  8. package/lib/src/app/log-list/grid/columns/scorerMap.d.ts.map +1 -1
  9. package/lib/src/app/log-view/LogSampleDetailView.d.ts.map +1 -1
  10. package/lib/src/app/log-view/LogView.d.ts.map +1 -1
  11. package/lib/src/app/log-view/LogViewContainer.d.ts.map +1 -1
  12. package/lib/src/app/log-view/tabs/InfoTab.d.ts +1 -0
  13. package/lib/src/app/log-view/tabs/InfoTab.d.ts.map +1 -1
  14. package/lib/src/app/log-view/tabs/ModelsTab.d.ts +2 -1
  15. package/lib/src/app/log-view/tabs/ModelsTab.d.ts.map +1 -1
  16. package/lib/src/app/log-view/tabs/SamplesTab.d.ts.map +1 -1
  17. package/lib/src/app/log-view/tabs/TaskTab.d.ts +2 -1
  18. package/lib/src/app/log-view/tabs/TaskTab.d.ts.map +1 -1
  19. package/lib/src/app/log-view/title-view/ResultsPanel.d.ts.map +1 -1
  20. package/lib/src/app/log-view/title-view/StatusPanel.d.ts +1 -1
  21. package/lib/src/app/log-view/title-view/StatusPanel.d.ts.map +1 -1
  22. package/lib/src/app/plan/ModelCard.d.ts.map +1 -1
  23. package/lib/src/app/plan/PlanDetailView.d.ts.map +1 -1
  24. package/lib/src/app/routing/sampleNavigation.d.ts.map +1 -1
  25. package/lib/src/app/routing/url.d.ts.map +1 -1
  26. package/lib/src/app/samples/SampleDisplay.d.ts.map +1 -1
  27. package/lib/src/app/samples/descriptor/samplesDescriptor.d.ts.map +1 -1
  28. package/lib/src/app/samples/list/SampleList.d.ts.map +1 -1
  29. package/lib/src/app/samples/list/samplesView.converters.d.ts.map +1 -1
  30. package/lib/src/app/samples/list/useSamplesView.d.ts.map +1 -1
  31. package/lib/src/app/samples/print/PrintHeading.d.ts +8 -0
  32. package/lib/src/app/samples/print/PrintHeading.d.ts.map +1 -0
  33. package/lib/src/app/samples/print/SamplePrintView.d.ts.map +1 -1
  34. package/lib/src/app/samples/retry-display/RetryAttemptCard.d.ts.map +1 -1
  35. package/lib/src/app/samples/retry-display/RetryTerminalAnchor.d.ts.map +1 -1
  36. package/lib/src/app/samples/retry-display/retryAttempt.d.ts +4 -4
  37. package/lib/src/app/samples/retry-display/retryAttempt.d.ts.map +1 -1
  38. package/lib/src/app/samples/sample-tools/SelectScorer.d.ts.map +1 -1
  39. package/lib/src/app/samples/sample-tools/astToFilterModel.d.ts.map +1 -1
  40. package/lib/src/app/samples/sample-tools/sample-filter/completions.d.ts.map +1 -1
  41. package/lib/src/app/samples/scores/SampleScoresGrid.d.ts.map +1 -1
  42. package/lib/src/app/samples/transcript/TranscriptPanel.d.ts +1 -0
  43. package/lib/src/app/samples/transcript/TranscriptPanel.d.ts.map +1 -1
  44. package/lib/src/app/samples/transcript/hooks.d.ts.map +1 -1
  45. package/lib/src/app/samples-panel/SampleDetailView.d.ts.map +1 -1
  46. package/lib/src/app/shared/gridKeyboardNavigation.d.ts.map +1 -1
  47. package/lib/src/app/shared/openInNewTab.d.ts.map +1 -1
  48. package/lib/src/app/shared/sample.d.ts +9 -0
  49. package/lib/src/app/shared/sample.d.ts.map +1 -1
  50. package/lib/src/app/types.d.ts +1 -0
  51. package/lib/src/app/types.d.ts.map +1 -1
  52. package/lib/src/client/api/client-api.d.ts.map +1 -1
  53. package/lib/src/client/api/index.d.ts.map +1 -1
  54. package/lib/src/client/api/static-http/fetch.d.ts.map +1 -1
  55. package/lib/src/client/api/view-server/api-view-server.d.ts +1 -0
  56. package/lib/src/client/api/view-server/api-view-server.d.ts.map +1 -1
  57. package/lib/src/client/api/view-server/request.d.ts +1 -1
  58. package/lib/src/client/api/view-server/request.d.ts.map +1 -1
  59. package/lib/src/client/api/vscode/api-vscode-http.d.ts +9 -0
  60. package/lib/src/client/api/vscode/api-vscode-http.d.ts.map +1 -0
  61. package/lib/src/client/api/vscode/api-vscode.d.ts.map +1 -1
  62. package/lib/src/client/api/vscode/host-capabilities.d.ts +7 -0
  63. package/lib/src/client/api/vscode/host-capabilities.d.ts.map +1 -0
  64. package/lib/src/client/api/vscode/jsonrpc.d.ts +3 -30
  65. package/lib/src/client/api/vscode/jsonrpc.d.ts.map +1 -1
  66. package/lib/src/client/database/service.d.ts.map +1 -1
  67. package/lib/src/client/remote/remoteLogFile.d.ts.map +1 -1
  68. package/lib/src/client/remote/remotePendingSampleData.d.ts +6 -0
  69. package/lib/src/client/remote/remotePendingSampleData.d.ts.map +1 -1
  70. package/lib/src/client/remote/remoteZipFile.d.ts.map +1 -1
  71. package/lib/src/client/remote/zstd-worker.d.ts.map +1 -1
  72. package/lib/src/scoring/metrics.d.ts.map +1 -1
  73. package/lib/src/state/appSlice.d.ts.map +1 -1
  74. package/lib/src/state/hooks.d.ts +4 -0
  75. package/lib/src/state/hooks.d.ts.map +1 -1
  76. package/lib/src/state/log.d.ts +6 -0
  77. package/lib/src/state/log.d.ts.map +1 -1
  78. package/lib/src/state/samplePolling.d.ts +5 -0
  79. package/lib/src/state/samplePolling.d.ts.map +1 -1
  80. package/lib/src/state/sampleSlice.d.ts +1 -0
  81. package/lib/src/state/sampleSlice.d.ts.map +1 -1
  82. package/lib/src/state/useLoadSample.d.ts +19 -0
  83. package/lib/src/state/useLoadSample.d.ts.map +1 -1
  84. package/lib/src/utils/dom.d.ts.map +1 -1
  85. package/lib/src/utils/evallog.d.ts.map +1 -1
  86. package/lib/src/utils/markdown.d.ts.map +1 -1
  87. package/lib/styles/index.css +245 -49
  88. package/package.json +2 -1
  89. package/lib/src/app/utils/print.d.ts +0 -22
  90. package/lib/src/app/utils/print.d.ts.map +0 -1
package/lib/index.js CHANGED
@@ -24829,7 +24829,7 @@ function isValid(value) {
24829
24829
  //#endregion
24830
24830
  //#region ../../node_modules/.pnpm/arquero@8.0.3/node_modules/arquero/src/op/functions/array.js
24831
24831
  var array_exports = /* @__PURE__ */ __exportAll({
24832
- compact: () => compact$1,
24832
+ compact: () => compact$2,
24833
24833
  concat: () => concat,
24834
24834
  includes: () => includes,
24835
24835
  indexof: () => indexof,
@@ -24848,7 +24848,7 @@ var isSeq = (seq) => isArrayType(seq) || isString$2(seq);
24848
24848
  * @param {T[]} array The input array.
24849
24849
  * @return {T[]} A compacted array.
24850
24850
  */
24851
- function compact$1(array) {
24851
+ function compact$2(array) {
24852
24852
  return isArrayType(array) ? array.filter((v) => isValid(v)) : array;
24853
24853
  }
24854
24854
  /**
@@ -25007,7 +25007,7 @@ var date_exports = /* @__PURE__ */ __exportAll({
25007
25007
  now: () => now,
25008
25008
  quarter: () => quarter,
25009
25009
  seconds: () => seconds,
25010
- timestamp: () => timestamp$1,
25010
+ timestamp: () => timestamp$2,
25011
25011
  utcdate: () => utcdate,
25012
25012
  utcdatetime: () => utcdatetime,
25013
25013
  utcdayofweek: () => utcdayofweek,
@@ -25072,7 +25072,7 @@ function now() {
25072
25072
  * @param {Date | number} date The input Date value.
25073
25073
  * @return {number} The timestamp value.
25074
25074
  */
25075
- function timestamp$1(date) {
25075
+ function timestamp$2(date) {
25076
25076
  return +t$1(date);
25077
25077
  }
25078
25078
  /**
@@ -33131,6 +33131,36 @@ var createLogger = (namespace) => {
33131
33131
  };
33132
33132
  };
33133
33133
  //#endregion
33134
+ //#region ../../packages/util/src/media.ts
33135
+ var parseDataUri = (value) => {
33136
+ let uri;
33137
+ try {
33138
+ uri = new URL(value);
33139
+ } catch {
33140
+ return;
33141
+ }
33142
+ if (uri.protocol.toLowerCase() !== "data:") return;
33143
+ const comma = uri.pathname.indexOf(",");
33144
+ if (comma < 0) return;
33145
+ const [rawMimeType = "", ...parameters] = uri.pathname.slice(0, comma).split(";");
33146
+ const mimeType = rawMimeType.trim().toLowerCase();
33147
+ if (!mimeType) return;
33148
+ return {
33149
+ mimeType,
33150
+ base64: parameters.some((parameter) => parameter.trim().toLowerCase() === "base64")
33151
+ };
33152
+ };
33153
+ var parseAbsoluteHttpUrl = (value) => {
33154
+ let url;
33155
+ try {
33156
+ url = new URL(value);
33157
+ } catch {
33158
+ return;
33159
+ }
33160
+ if (url.protocol !== "http:" && url.protocol !== "https:" || !url.hostname) return;
33161
+ return url.href;
33162
+ };
33163
+ //#endregion
33134
33164
  //#region ../../packages/util/src/numeric.ts
33135
33165
  function compareWithNan(a, b) {
33136
33166
  const aIsNaN = Number.isNaN(a);
@@ -33143,7 +33173,7 @@ function compareWithNan(a, b) {
33143
33173
  //#endregion
33144
33174
  //#region ../../packages/util/src/mime.ts
33145
33175
  var isImage = (mimeType) => {
33146
- return mimeType.startsWith("image/");
33176
+ return mimeType.trim().toLowerCase().startsWith("image/");
33147
33177
  };
33148
33178
  //#endregion
33149
33179
  //#region ../../packages/util/src/object.ts
@@ -36220,7 +36250,7 @@ function list$3(state, startLine, endLine, silent) {
36220
36250
  }
36221
36251
  //#endregion
36222
36252
  //#region ../../node_modules/.pnpm/markdown-it@14.2.0/node_modules/markdown-it/lib/rules_block/reference.mjs
36223
- function reference$1(state, startLine, _endLine, silent) {
36253
+ function reference$2(state, startLine, _endLine, silent) {
36224
36254
  let pos = state.bMarks[startLine] + state.tShift[startLine];
36225
36255
  let max = state.eMarks[startLine];
36226
36256
  let nextLine = startLine + 1;
@@ -36496,7 +36526,7 @@ function html_block(state, startLine, endLine, silent) {
36496
36526
  }
36497
36527
  //#endregion
36498
36528
  //#region ../../node_modules/.pnpm/markdown-it@14.2.0/node_modules/markdown-it/lib/rules_block/heading.mjs
36499
- function heading$2(state, startLine, endLine, silent) {
36529
+ function heading$3(state, startLine, endLine, silent) {
36500
36530
  let pos = state.bMarks[startLine] + state.tShift[startLine];
36501
36531
  let max = state.eMarks[startLine];
36502
36532
  if (state.sCount[startLine] - state.blkIndent >= 4) return false;
@@ -36660,7 +36690,7 @@ var _rules$1 = [
36660
36690
  "blockquote"
36661
36691
  ]
36662
36692
  ],
36663
- ["reference", reference$1],
36693
+ ["reference", reference$2],
36664
36694
  [
36665
36695
  "html_block",
36666
36696
  html_block,
@@ -36672,7 +36702,7 @@ var _rules$1 = [
36672
36702
  ],
36673
36703
  [
36674
36704
  "heading",
36675
- heading$2,
36705
+ heading$3,
36676
36706
  [
36677
36707
  "paragraph",
36678
36708
  "reference",
@@ -38984,6 +39014,19 @@ var getMarkdownInstance = (renderer) => {
38984
39014
  breaks: true,
38985
39015
  html: true
38986
39016
  });
39017
+ md.renderer.rules.image = (tokens, idx) => {
39018
+ const token = tokens[idx];
39019
+ if (!token) return "";
39020
+ const source = token.attrGet("src") ?? "";
39021
+ const href = parseAbsoluteHttpUrl(source);
39022
+ const dataUri = parseDataUri(source);
39023
+ const visibleSource = href ?? (dataUri ? `data:${dataUri.mimeType}${dataUri.base64 ? ";base64" : ""},...` : source);
39024
+ const alt = token.content.trim();
39025
+ const label = alt ? `${alt} (${visibleSource})` : visibleSource;
39026
+ const escapedLabel = md.utils.escapeHtml(label);
39027
+ if (!href) return escapedLabel;
39028
+ return `<a href="${md.utils.escapeHtml(href)}" target="_blank" rel="noopener noreferrer">${escapedLabel}</a>`;
39029
+ };
38987
39030
  if (renderer === "full" || renderer === "fragment") {
38988
39031
  md.use(markdownitMathjax3);
38989
39032
  const origInline = md.renderer.rules.math_inline;
@@ -38999,7 +39042,6 @@ var getMarkdownInstance = (renderer) => {
38999
39042
  return origBlock(tokens, idx, options, env, self);
39000
39043
  };
39001
39044
  }
39002
- if (renderer === "fragment") md.disable(["image"]);
39003
39045
  mdInstanceCache[renderer] = md;
39004
39046
  return md;
39005
39047
  };
@@ -41239,11 +41281,14 @@ var FORBIDDEN_TAGS = [
41239
41281
  "foreignobject",
41240
41282
  "form",
41241
41283
  "iframe",
41284
+ "image",
41285
+ "img",
41242
41286
  "input",
41243
41287
  "link",
41244
41288
  "meta",
41245
41289
  "mpath",
41246
41290
  "object",
41291
+ "picture",
41247
41292
  "script",
41248
41293
  "select",
41249
41294
  "set",
@@ -41317,8 +41362,7 @@ var SAFE_STYLE_PROPERTIES = new Set([
41317
41362
  ]);
41318
41363
  var UNSAFE_CSS_PATTERN = /@import|behavior\s*:|binding\s*:|expression\s*\(|javascript\s*:|vbscript\s*:|url\s*\(/i;
41319
41364
  var PURIFY_CONFIG = {
41320
- ADD_ATTR: MATHJAX_ATTRS,
41321
- ADD_DATA_URI_TAGS: ["img", "image"],
41365
+ ADD_ATTR: [...MATHJAX_ATTRS, "target"],
41322
41366
  ADD_TAGS: MATHJAX_TAGS,
41323
41367
  ALLOW_DATA_ATTR: true,
41324
41368
  ALLOW_UNKNOWN_PROTOCOLS: false,
@@ -41362,11 +41406,14 @@ var installHooks = (purify) => {
41362
41406
  });
41363
41407
  purify.addHook("uponSanitizeAttribute", (node, hookEvent) => {
41364
41408
  if (hookEvent.attrName === "style") sanitizeStyleAttributeHook(node, hookEvent);
41365
- else if (URL_ATTRIBUTES.has(hookEvent.attrName) && !isSafeUrlAttribute(node, hookEvent.attrValue)) {
41409
+ else if (URL_ATTRIBUTES.has(hookEvent.attrName) && !isSafeUrlAttribute(hookEvent.attrValue)) {
41366
41410
  hookEvent.keepAttr = false;
41367
41411
  node.removeAttribute(hookEvent.attrName);
41368
41412
  }
41369
41413
  });
41414
+ purify.addHook("afterSanitizeAttributes", (node) => {
41415
+ if (node instanceof Element && node.tagName.toLowerCase() === "a" && node.getAttribute("target")?.toLowerCase() === "_blank") node.setAttribute("rel", "noopener noreferrer");
41416
+ });
41370
41417
  };
41371
41418
  var sanitizeStyleAttributeHook = (node, hookEvent) => {
41372
41419
  const safeStyle = sanitizeStyleAttribute(hookEvent.attrValue);
@@ -41376,7 +41423,7 @@ var sanitizeStyleAttributeHook = (node, hookEvent) => {
41376
41423
  node.removeAttribute(hookEvent.attrName);
41377
41424
  }
41378
41425
  };
41379
- var isSafeUrlAttribute = (node, value) => {
41426
+ var isSafeUrlAttribute = (value) => {
41380
41427
  const trimmed = value.trim();
41381
41428
  if (!trimmed) return true;
41382
41429
  if (/[<>"'`]/.test(trimmed)) return false;
@@ -41384,7 +41431,7 @@ var isSafeUrlAttribute = (node, value) => {
41384
41431
  const charCode = char.charCodeAt(0);
41385
41432
  return charCode > 31 && charCode !== 127 && !/\s/.test(char);
41386
41433
  }).join("");
41387
- if (/^data:/i.test(normalized)) return ["img", "image"].includes(node.tagName.toLowerCase()) && /^data:image\//i.test(normalized);
41434
+ if (/^data:/i.test(normalized)) return false;
41388
41435
  return !/^(?:javascript|vbscript):/i.test(normalized);
41389
41436
  };
41390
41437
  var sanitizeStyleAttribute = (style) => {
@@ -41585,7 +41632,7 @@ var start = "start";
41585
41632
  var clippingParents = "clippingParents";
41586
41633
  var viewport = "viewport";
41587
41634
  var popper = "popper";
41588
- var reference = "reference";
41635
+ var reference$1 = "reference";
41589
41636
  var variationPlacements = /*#__PURE__*/ basePlacements.reduce(function(acc, placement) {
41590
41637
  return acc.concat([placement + "-" + start, placement + "-end"]);
41591
41638
  }, []);
@@ -42276,7 +42323,7 @@ function detectOverflow(state, options) {
42276
42323
  if (options === void 0) options = {};
42277
42324
  var _options = options, _options$placement = _options.placement, placement = _options$placement === void 0 ? state.placement : _options$placement, _options$strategy = _options.strategy, strategy = _options$strategy === void 0 ? state.strategy : _options$strategy, _options$boundary = _options.boundary, boundary = _options$boundary === void 0 ? clippingParents : _options$boundary, _options$rootBoundary = _options.rootBoundary, rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary, _options$elementConte = _options.elementContext, elementContext = _options$elementConte === void 0 ? popper : _options$elementConte, _options$altBoundary = _options.altBoundary, altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary, _options$padding = _options.padding, padding = _options$padding === void 0 ? 0 : _options$padding;
42278
42325
  var paddingObject = mergePaddingObject(typeof padding !== "number" ? padding : expandToHashMap(padding, basePlacements));
42279
- var altContext = elementContext === "popper" ? reference : popper;
42326
+ var altContext = elementContext === "popper" ? reference$1 : popper;
42280
42327
  var popperRect = state.rects.popper;
42281
42328
  var element = state.elements[altBoundary ? altContext : elementContext];
42282
42329
  var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);
@@ -44364,6 +44411,15 @@ function useListKeyboardNavigation({ listHandle, scrollRef, itemCount }) {
44364
44411
  }
44365
44412
  //#endregion
44366
44413
  //#region ../../packages/react/src/hooks/useBreadcrumbTruncation.ts
44414
+ var replaceMeasurementItems = (element, labels) => {
44415
+ const items = labels.map((label) => {
44416
+ const item = document.createElement("li");
44417
+ item.className = "breadcrumb-item";
44418
+ item.textContent = label;
44419
+ return item;
44420
+ });
44421
+ element.replaceChildren(...items);
44422
+ };
44367
44423
  var useBreadcrumbTruncation = (segments, containerRef) => {
44368
44424
  const [truncatedData, setTruncatedData] = useState({
44369
44425
  visibleSegments: segments,
@@ -44390,7 +44446,7 @@ var useBreadcrumbTruncation = (segments, containerRef) => {
44390
44446
  testElement.style.margin = "0";
44391
44447
  testElement.style.padding = "0";
44392
44448
  container.appendChild(testElement);
44393
- testElement.innerHTML = segments.map((segment) => `<li class="breadcrumb-item">${segment.text}</li>`).join("");
44449
+ replaceMeasurementItems(testElement, segments.map((segment) => segment.text));
44394
44450
  if (testElement.scrollWidth <= containerWidth) {
44395
44451
  container.removeChild(testElement);
44396
44452
  setTruncatedData({
@@ -44413,12 +44469,12 @@ var useBreadcrumbTruncation = (segments, containerRef) => {
44413
44469
  ...segments.slice(segments.length - 1 - endCount, -1),
44414
44470
  lastSegment
44415
44471
  ];
44416
- testElement.innerHTML = [
44417
- `<li class="breadcrumb-item">${firstSegment.text}</li>`,
44418
- `<li class="breadcrumb-item">...</li>`,
44419
- ...segments.slice(segments.length - 1 - endCount, -1).map((s) => `<li class="breadcrumb-item">${s.text}</li>`),
44420
- `<li class="breadcrumb-item">${lastSegment.text}</li>`
44421
- ].join("");
44472
+ replaceMeasurementItems(testElement, [
44473
+ firstSegment.text,
44474
+ "...",
44475
+ ...segments.slice(segments.length - 1 - endCount, -1).map((segment) => segment.text),
44476
+ lastSegment.text
44477
+ ]);
44422
44478
  if (testElement.scrollWidth <= containerWidth) {
44423
44479
  maxVisible = candidateSegments.length;
44424
44480
  setTruncatedData({
@@ -50816,7 +50872,7 @@ var initialState$3 = {
50816
50872
  };
50817
50873
  var createAppSlice = (set, get, _store) => {
50818
50874
  const getBoolRecord = (record, name, defaultValue) => {
50819
- if (Object.keys(record).includes(name)) return record[name];
50875
+ if (Object.hasOwn(record, name)) return record[name] ?? false;
50820
50876
  else return defaultValue || false;
50821
50877
  };
50822
50878
  const slice = {
@@ -50915,7 +50971,11 @@ var createAppSlice = (set, get, _store) => {
50915
50971
  },
50916
50972
  getVisibleRange: (name) => {
50917
50973
  const state = get();
50918
- if (Object.keys(state.app.visibleRanges).includes(name)) return state.app.visibleRanges[name];
50974
+ if (Object.hasOwn(state.app.visibleRanges, name)) return state.app.visibleRanges[name] ?? {
50975
+ startIndex: 0,
50976
+ endIndex: 0,
50977
+ totalCount: 0
50978
+ };
50919
50979
  else return {
50920
50980
  startIndex: 0,
50921
50981
  endIndex: 0,
@@ -51036,6 +51096,14 @@ var sampleIdsEqual = (id, otherId) => {
51036
51096
  if (id === void 0 || otherId === void 0) return false;
51037
51097
  return String(id) === String(otherId);
51038
51098
  };
51099
+ /**
51100
+ * Whether a row is the sample currently open in the detail route.
51101
+ *
51102
+ * Keyed off the route (undefined id/epoch means the log list is showing), not
51103
+ * the persisted selectedSampleHandle — that lingers after navigating back to
51104
+ * the log, so using it would wrongly skip re-opening the same sample.
51105
+ */
51106
+ var isSampleOpenInRoute = (routeSampleId, routeEpoch, rowSampleId, rowEpoch) => routeSampleId !== void 0 && routeEpoch !== void 0 && sampleIdsEqual(routeSampleId, rowSampleId) && Number(routeEpoch) === rowEpoch;
51039
51107
  var sampleHandlesEqual = (sample1, sample2) => {
51040
51108
  if (!sample1 && !sample2) return true;
51041
51109
  if (!sample1 || !sample2) return false;
@@ -51062,9 +51130,9 @@ var toLogPreview = (header) => {
51062
51130
  };
51063
51131
  };
51064
51132
  var primaryMetric = (evalResults) => {
51065
- if (evalResults?.scores && evalResults?.scores.length > 0) {
51066
- const evalMetrics = evalResults.scores[0].metrics;
51067
- const metrics = Object.values(evalMetrics);
51133
+ const firstScore = evalResults?.scores?.[0];
51134
+ if (firstScore) {
51135
+ const metrics = Object.values(firstScore.metrics);
51068
51136
  if (metrics.length > 0) return metrics[0];
51069
51137
  }
51070
51138
  };
@@ -51802,7 +51870,12 @@ var displaySamplesEqual = (a, b) => {
51802
51870
  if (!a && !b) return true;
51803
51871
  if (!a || !b) return false;
51804
51872
  if (a.length !== b.length) return false;
51805
- for (let i = 0; i < a.length; i++) if (a[i].logFile !== b[i].logFile || a[i].sampleId !== b[i].sampleId || a[i].epoch !== b[i].epoch) return false;
51873
+ for (let i = 0; i < a.length; i++) {
51874
+ const sampleA = a[i];
51875
+ const sampleB = b[i];
51876
+ if (sampleA === void 0 || sampleB === void 0) return false;
51877
+ if (sampleA.logFile !== sampleB.logFile || sampleA.sampleId !== sampleB.sampleId || sampleA.epoch !== sampleB.epoch) return false;
51878
+ }
51806
51879
  return true;
51807
51880
  };
51808
51881
  //#endregion
@@ -52031,7 +52104,8 @@ function createSamplePolling(store, api) {
52031
52104
  callPool: [],
52032
52105
  messagePoolEntryIds: /* @__PURE__ */ new Set(),
52033
52106
  callPoolEntryIds: /* @__PURE__ */ new Set(),
52034
- events: []
52107
+ events: [],
52108
+ reachedLive: false
52035
52109
  };
52036
52110
  const startPolling = (logFile, summary) => {
52037
52111
  const pollingId = `${logFile}:${summary.id}-${summary.epoch}`;
@@ -52063,6 +52137,7 @@ function createSamplePolling(store, api) {
52063
52137
  sampleActions.setSampleError(error);
52064
52138
  sampleActions.setSampleStatus("error");
52065
52139
  sampleActions.setRunningEvents([]);
52140
+ sampleActions.setBackfilling(false);
52066
52141
  return false;
52067
52142
  };
52068
52143
  try {
@@ -52078,6 +52153,7 @@ function createSamplePolling(store, api) {
52078
52153
  sampleActions.setSelectedSample(migratedSample, logFile);
52079
52154
  sampleActions.setSampleStatus("ok");
52080
52155
  sampleActions.setRunningEvents([]);
52156
+ sampleActions.setBackfilling(false);
52081
52157
  return false;
52082
52158
  }
52083
52159
  if (!options.missingSampleIsError) return keepStreaming();
@@ -52102,6 +52178,9 @@ function createSamplePolling(store, api) {
52102
52178
  if (sampleDataResponse?.status === "OK" && sampleDataResponse.sampleData) {
52103
52179
  if (localAbort.signal.aborted) return false;
52104
52180
  sampleActions.setSampleStatus("streaming");
52181
+ const backfill = computeBackfilling(sampleDataResponse.has_more, pollingState.reachedLive);
52182
+ pollingState.reachedLive = backfill.reachedLive;
52183
+ sampleActions.setBackfilling(backfill.backfilling);
52105
52184
  processAttachments(sampleDataResponse.sampleData, pollingState);
52106
52185
  processMessagePool(sampleDataResponse.sampleData, pollingState);
52107
52186
  processCallPool(sampleDataResponse.sampleData, pollingState);
@@ -52156,6 +52235,16 @@ var hasCompletedLogSummary = (state, sampleId, sampleEpoch) => {
52156
52235
  var findLiveSummary = (state, sampleId, sampleEpoch) => {
52157
52236
  return mergeSampleSummaries(state.log.selectedLogDetails?.sampleSummaries ?? [], state.log.pendingSampleSummaries?.samples ?? []).find((s) => sampleIdsEqual(s.id, sampleId) && s.epoch === sampleEpoch);
52158
52237
  };
52238
+ var computeBackfilling = (hasMore, reachedLive) => {
52239
+ if (reachedLive || hasMore !== true) return {
52240
+ backfilling: false,
52241
+ reachedLive: true
52242
+ };
52243
+ return {
52244
+ backfilling: true,
52245
+ reachedLive: false
52246
+ };
52247
+ };
52159
52248
  var hasSampleDataUpdates = (sampleData) => {
52160
52249
  if (!sampleData) return false;
52161
52250
  return sampleData.events.length > 0 || sampleData.attachments.length > 0 || sampleData.message_pool.length > 0 || sampleData.call_pool.length > 0;
@@ -52180,6 +52269,7 @@ var resetPollingState = (state) => {
52180
52269
  state.messagePoolEntryIds.clear();
52181
52270
  state.callPoolEntryIds.clear();
52182
52271
  state.events = [];
52272
+ state.reachedLive = false;
52183
52273
  };
52184
52274
  function processAttachments(sampleData, pollingState) {
52185
52275
  log$7.debug(`Processing ${sampleData.attachments.length} attachments`);
@@ -52358,6 +52448,7 @@ var initialState = {
52358
52448
  sampleError: void 0,
52359
52449
  eventsCleared: false,
52360
52450
  downloadProgress: void 0,
52451
+ backfilling: false,
52361
52452
  visiblePopover: void 0,
52362
52453
  sampleNeedsReload: 0,
52363
52454
  runningEvents: [],
@@ -52406,6 +52497,7 @@ var createSampleSlice = (set, get, _store) => {
52406
52497
  state.sample.selectedSampleObject = void 0;
52407
52498
  state.sample.sampleInState = false;
52408
52499
  state.sample.runningEvents = [];
52500
+ state.sample.backfilling = false;
52409
52501
  state.sample.sampleStatus = "ok";
52410
52502
  state.sample.downloadProgress = void 0;
52411
52503
  state.sample.timelineSelected = null;
@@ -52422,6 +52514,7 @@ var createSampleSlice = (set, get, _store) => {
52422
52514
  state.sample.selectedSampleObject = void 0;
52423
52515
  state.sample.sampleInState = false;
52424
52516
  state.sample.runningEvents = [];
52517
+ state.sample.backfilling = false;
52425
52518
  state.sample.sampleStatus = "loading";
52426
52519
  state.sample.sampleError = void 0;
52427
52520
  state.sample.timelineSelected = null;
@@ -52527,6 +52620,7 @@ var createSampleSlice = (set, get, _store) => {
52527
52620
  state.sample.selectedSampleObject = void 0;
52528
52621
  state.sample.sampleInState = false;
52529
52622
  state.sample.runningEvents = [];
52623
+ state.sample.backfilling = false;
52530
52624
  state.sample.sample_identifier = {
52531
52625
  id,
52532
52626
  epoch,
@@ -52547,6 +52641,11 @@ var createSampleSlice = (set, get, _store) => {
52547
52641
  set((state) => {
52548
52642
  state.sample.runningEvents = events;
52549
52643
  });
52644
+ },
52645
+ setBackfilling: (backfilling) => {
52646
+ set((state) => {
52647
+ state.sample.backfilling = backfilling;
52648
+ });
52550
52649
  }
52551
52650
  }
52552
52651
  };
@@ -54220,7 +54319,7 @@ function formatDuration(start, end) {
54220
54319
  */
54221
54320
  var errorType = (message) => {
54222
54321
  if (!message) return "Error";
54223
- if (message.includes("(")) return message.split("(")[0];
54322
+ if (message.includes("(")) return message.split("(")[0] ?? "Error";
54224
54323
  return "Error";
54225
54324
  };
54226
54325
  var BooleanScoreDescriptor_module_default = {
@@ -54431,6 +54530,70 @@ var MetadataGrid_module_default = {
54431
54530
  toggleContainer: "_toggleContainer_25rj7_178",
54432
54531
  toggleButton: "_toggleButton_25rj7_189"
54433
54532
  };
54533
+ //#endregion
54534
+ //#region ../../packages/inspect-components/src/media/mediaSource.ts
54535
+ var rasterImageMimeTypes = new Set([
54536
+ "image/avif",
54537
+ "image/bmp",
54538
+ "image/gif",
54539
+ "image/jpeg",
54540
+ "image/png",
54541
+ "image/webp",
54542
+ "image/x-icon"
54543
+ ]);
54544
+ var imageMimeAliases = new Map([["image/jpg", "image/jpeg"], ["image/vnd.microsoft.icon", "image/x-icon"]]);
54545
+ var primaryAudioMimeTypes = {
54546
+ mp3: "audio/mpeg",
54547
+ wav: "audio/wav"
54548
+ };
54549
+ var audioMimeTypes = {
54550
+ mp3: new Set(["audio/mp3", "audio/mpeg"]),
54551
+ wav: new Set([
54552
+ "audio/vnd.wave",
54553
+ "audio/wav",
54554
+ "audio/wave",
54555
+ "audio/x-wav"
54556
+ ])
54557
+ };
54558
+ var primaryVideoMimeTypes = {
54559
+ mov: "video/quicktime",
54560
+ mp4: "video/mp4",
54561
+ mpeg: "video/mpeg"
54562
+ };
54563
+ var videoMimeTypes = {
54564
+ mov: new Set(["video/quicktime"]),
54565
+ mp4: new Set(["video/mp4"]),
54566
+ mpeg: new Set(["video/mpeg"])
54567
+ };
54568
+ var normalizedImageMimeType = (mimeType) => {
54569
+ const normalized = mimeType.trim().toLowerCase();
54570
+ return imageMimeAliases.get(normalized) ?? normalized;
54571
+ };
54572
+ var base64DataUriMimeType = (source) => {
54573
+ const dataUri = parseDataUri(source);
54574
+ return dataUri?.base64 ? dataUri.mimeType : void 0;
54575
+ };
54576
+ var isRenderableImageSource = (source) => {
54577
+ const mimeType = base64DataUriMimeType(source);
54578
+ return mimeType !== void 0 && rasterImageMimeTypes.has(normalizedImageMimeType(mimeType));
54579
+ };
54580
+ var isRenderableAudioSource = (source, format) => {
54581
+ const mimeType = base64DataUriMimeType(source);
54582
+ return mimeType !== void 0 && audioMimeTypes[format].has(mimeType);
54583
+ };
54584
+ var isRenderableVideoSource = (source, format) => {
54585
+ const mimeType = base64DataUriMimeType(source);
54586
+ return mimeType !== void 0 && videoMimeTypes[format].has(mimeType);
54587
+ };
54588
+ var audioMimeTypeForFormat = (format) => primaryAudioMimeTypes[format];
54589
+ var videoMimeTypeForFormat = (format) => primaryVideoMimeTypes[format];
54590
+ var isRenderableImageDocument = (source, declaredMimeType) => {
54591
+ const sourceMimeType = base64DataUriMimeType(source);
54592
+ if (sourceMimeType === void 0) return false;
54593
+ const normalizedSource = normalizedImageMimeType(sourceMimeType);
54594
+ const normalizedDeclared = normalizedImageMimeType(declaredMimeType);
54595
+ return rasterImageMimeTypes.has(normalizedSource) && normalizedSource === normalizedDeclared;
54596
+ };
54434
54597
  var RenderedContent_module_default = {
54435
54598
  query: "_query_seqs2_1",
54436
54599
  summary: "_summary_seqs2_6",
@@ -54682,7 +54845,7 @@ var contentRenderers = (icons, renderObject, externalRenderers) => {
54682
54845
  Image: {
54683
54846
  bucket: Buckets.intermediate,
54684
54847
  canRender: (entry) => {
54685
- return typeof entry.value === "string" && entry.value.startsWith("data:image/");
54848
+ return typeof entry.value === "string" && isRenderableImageSource(entry.value);
54686
54849
  },
54687
54850
  render: (_id, entry, _options) => {
54688
54851
  return { rendered: /* @__PURE__ */ jsx("img", { src: entry.value }) };
@@ -61040,6 +61203,17 @@ var useSampleDescriptor = () => {
61040
61203
  selectedScores
61041
61204
  ]);
61042
61205
  };
61206
+ var compareSamples = (a, b) => {
61207
+ let idCompare;
61208
+ if (typeof a.id === "number" && typeof b.id === "number") idCompare = a.id - b.id;
61209
+ else idCompare = String(a.id).localeCompare(String(b.id));
61210
+ if (idCompare !== 0) return idCompare;
61211
+ return a.epoch - b.epoch;
61212
+ };
61213
+ var samplesAreSorted = (samples) => samples.every((curr, i) => {
61214
+ const prev = samples[i - 1];
61215
+ return prev === void 0 || compareSamples(prev, curr) <= 0;
61216
+ });
61043
61217
  var useFilteredSamples = () => {
61044
61218
  const samplesDescriptor = useSampleDescriptor();
61045
61219
  const sampleSummaries = useSampleSummaries();
@@ -61054,13 +61228,9 @@ var useFilteredSamples = () => {
61054
61228
  };
61055
61229
  if (error && allErrors) setFilterError(error);
61056
61230
  else clearFilterError();
61057
- return [...error === void 0 || !allErrors ? result : sampleSummaries].sort((a, b) => {
61058
- let idCompare;
61059
- if (typeof a.id === "number" && typeof b.id === "number") idCompare = a.id - b.id;
61060
- else idCompare = String(a.id).localeCompare(String(b.id));
61061
- if (idCompare !== 0) return idCompare;
61062
- return a.epoch - b.epoch;
61063
- });
61231
+ const filtered = error === void 0 || !allErrors ? result : sampleSummaries;
61232
+ if (filtered.length < 2 || samplesAreSorted(filtered)) return filtered;
61233
+ return [...filtered].sort(compareSamples);
61064
61234
  }, [
61065
61235
  samplesDescriptor,
61066
61236
  sampleSummaries,
@@ -61086,6 +61256,7 @@ var useSampleData = () => {
61086
61256
  const sampleNeedsReload = useStore((state) => state.sample.sampleNeedsReload);
61087
61257
  const eventsCleared = useStore((state) => state.sample.eventsCleared);
61088
61258
  const runningEvents = useStore((state) => state.sample.runningEvents);
61259
+ const backfilling = useStore((state) => state.sample.backfilling);
61089
61260
  const downloadProgress = useStore((state) => state.sample.downloadProgress);
61090
61261
  return useMemo(() => {
61091
61262
  return {
@@ -61096,6 +61267,7 @@ var useSampleData = () => {
61096
61267
  getSelectedSample,
61097
61268
  eventsCleared,
61098
61269
  running: runningEvents,
61270
+ backfilling,
61099
61271
  downloadProgress
61100
61272
  };
61101
61273
  }, [
@@ -61106,6 +61278,7 @@ var useSampleData = () => {
61106
61278
  sampleNeedsReload,
61107
61279
  eventsCleared,
61108
61280
  runningEvents,
61281
+ backfilling,
61109
61282
  downloadProgress
61110
61283
  ]);
61111
61284
  };
@@ -61321,8 +61494,7 @@ var useLogOrSampleRouteParams = () => {
61321
61494
  var useLogRouteParams = () => {
61322
61495
  const location = useLocation();
61323
61496
  return useMemo(() => {
61324
- const logsMatch = location.pathname.match(/^\/(logs|tasks)\/(.*)$/);
61325
- const splatPath = logsMatch ? logsMatch[2] : "";
61497
+ const splatPath = location.pathname.match(/^\/(logs|tasks)\/(.*)$/)?.[2] ?? "";
61326
61498
  const sampleUuidMatch = splatPath.match(/^(.+?)\/samples\/sample_uuid\/([^/]+)(?:\/(.+?))?\/?\s*$/);
61327
61499
  if (sampleUuidMatch) {
61328
61500
  const [, logPath, sampleUuid, sampleTabId] = sampleUuidMatch;
@@ -61384,6 +61556,7 @@ var useLogRouteParams = () => {
61384
61556
  let foundTabId = void 0;
61385
61557
  for (let i = pathSegments.length - 1; i >= 0; i--) {
61386
61558
  const segment = pathSegments[i];
61559
+ if (segment === void 0) continue;
61387
61560
  const decodedSegment = decodeUrlParam(segment) || segment;
61388
61561
  if (validTabIds.has(decodedSegment)) {
61389
61562
  tabIdIndex = i;
@@ -61422,8 +61595,7 @@ var useLogRouteParams = () => {
61422
61595
  var useSamplesRouteParams = () => {
61423
61596
  const location = useLocation();
61424
61597
  return useMemo(() => {
61425
- const samplesMatch = location.pathname.match(/^\/samples\/(.*)$/);
61426
- const splatPath = samplesMatch ? samplesMatch[1] : "";
61598
+ const splatPath = location.pathname.match(/^\/samples\/(.*)$/)?.[1] ?? "";
61427
61599
  const sampleMatch = splatPath.match(/^(.+?)\/sample\/([^/]+)\/([^/]+)(?:\/([^/]+))?\/?$/);
61428
61600
  if (sampleMatch) {
61429
61601
  const [, logPath, sampleId, epoch, tabId] = sampleMatch;
@@ -61499,8 +61671,7 @@ var tasksUrl = (log_file, log_dir) => {
61499
61671
  var useTasksRouteParams = () => {
61500
61672
  const location = useLocation();
61501
61673
  return useMemo(() => {
61502
- const tasksMatch = location.pathname.match(/^\/tasks\/(.*)$/);
61503
- const splatPath = tasksMatch ? tasksMatch[1] : "";
61674
+ const splatPath = location.pathname.match(/^\/tasks\/(.*)$/)?.[1] ?? "";
61504
61675
  const sampleMatch = splatPath.match(/^(.+?)\/sample\/([^/]+)\/([^/]+)(?:\/([^/]+))?\/?$/);
61505
61676
  if (sampleMatch) {
61506
61677
  const [, logPath, sampleId, epoch, tabId] = sampleMatch;
@@ -110164,7 +110335,8 @@ var createGridKeyboardHandler = ({ gridRef, onOpenRow, pageJump = 10 }) => {
110164
110335
  const selectedRows = api.getSelectedNodes();
110165
110336
  const totalRows = api.getDisplayedRowCount();
110166
110337
  let currentRowIndex = -1;
110167
- if (selectedRows.length > 0 && selectedRows[0].rowIndex !== null) currentRowIndex = selectedRows[0].rowIndex;
110338
+ const firstSelected = selectedRows[0];
110339
+ if (firstSelected && firstSelected.rowIndex !== null) currentRowIndex = firstSelected.rowIndex;
110168
110340
  let targetRowIndex = null;
110169
110341
  switch (e.key) {
110170
110342
  case "ArrowUp":
@@ -110226,7 +110398,8 @@ var createGridKeyboardHandler = ({ gridRef, onOpenRow, pageJump = 10 }) => {
110226
110398
  * so the new tab doesn't steal focus.
110227
110399
  */
110228
110400
  function openInNewTab(hashRoute) {
110229
- const newWin = window.open(`${window.location.pathname}#${hashRoute}`, "_blank");
110401
+ const hash = hashRoute.startsWith("#") ? hashRoute : `#${hashRoute}`;
110402
+ const newWin = window.open(`${window.location.pathname}${hash}`, "_blank", "noopener,noreferrer");
110230
110403
  if (newWin) newWin.blur();
110231
110404
  window.focus();
110232
110405
  }
@@ -110704,9 +110877,7 @@ var LogsPanel_module_default = {
110704
110877
  //#endregion
110705
110878
  //#region src/app/log-list/LogsPanel.tsx
110706
110879
  var rootName = (relativePath) => {
110707
- const parts = relativePath.split("/");
110708
- if (parts.length === 0) return "";
110709
- return parts[0];
110880
+ return relativePath.split("/")[0] ?? "";
110710
110881
  };
110711
110882
  var LogsPanel = ({ maybeShowSingleLog, mode = "logs" }) => {
110712
110883
  const { loadLogs } = useLogs();
@@ -110780,7 +110951,8 @@ var LogsPanel = ({ maybeShowSingleLog, mode = "logs" }) => {
110780
110951
  let hi = sortedNames.length;
110781
110952
  while (lo < hi) {
110782
110953
  const mid = lo + hi >> 1;
110783
- if (sortedNames[mid] < target) lo = mid + 1;
110954
+ const name = sortedNames[mid];
110955
+ if (name !== void 0 && name < target) lo = mid + 1;
110784
110956
  else hi = mid;
110785
110957
  }
110786
110958
  return lo;
@@ -110873,10 +111045,8 @@ var LogsPanel = ({ maybeShowSingleLog, mode = "logs" }) => {
110873
111045
  const filteredFields = Object.keys(scopeGridState?.filter?.filterModel ?? {});
110874
111046
  const hasFilter = filteredFields.length > 0;
110875
111047
  useEffect(() => {
110876
- if (maybeShowSingleLog && logItems.length === 1) {
110877
- const onlyItem = logItems[0];
110878
- if (onlyItem.url) navigate(onlyItem.url);
110879
- }
111048
+ const onlyItem = logItems.length === 1 ? logItems[0] : void 0;
111049
+ if (maybeShowSingleLog && onlyItem?.url) navigate(onlyItem.url);
110880
111050
  }, [
110881
111051
  logItems,
110882
111052
  maybeShowSingleLog,
@@ -110972,11 +111142,70 @@ var appendPendingItems = (evalSet, tasksWithLogFiles, collapsedLogItems) => {
110972
111142
  return collapsedLogItems;
110973
111143
  };
110974
111144
  //#endregion
111145
+ //#region src/state/log.ts
111146
+ var useUnloadLog = () => {
111147
+ const clearSelectedLogDetails = useStore((state) => state.logActions.clearSelectedLogDetails);
111148
+ const clearSelectedLogFile = useStore((state) => state.logsActions.clearSelectedLogFile);
111149
+ const clearLog = useStore((state) => state.logActions.clearLog);
111150
+ const clearPendingSampleSummaries = useStore((state) => state.logActions.clearPendingSampleSummaries);
111151
+ return { unloadLog: useCallback(() => {
111152
+ clearSelectedLogDetails();
111153
+ clearSelectedLogFile();
111154
+ clearLog();
111155
+ clearPendingSampleSummaries();
111156
+ }, [
111157
+ clearLog,
111158
+ clearSelectedLogDetails,
111159
+ clearSelectedLogFile,
111160
+ clearPendingSampleSummaries
111161
+ ]) };
111162
+ };
111163
+ /**
111164
+ * Clear log-bound state before paint when routing to another log. Pending
111165
+ * summaries live outside selectedLogDetails but are merged into sample lists,
111166
+ * so they must be reset with the selected sample/details.
111167
+ */
111168
+ var useClearStaleLogStateOnNav = (logPath) => {
111169
+ const clearSelectedSample = useStore((state) => state.sampleActions.clearSelectedSample);
111170
+ const clearSelectedLogDetails = useStore((state) => state.logActions.clearSelectedLogDetails);
111171
+ const clearPendingSampleSummaries = useStore((state) => state.logActions.clearPendingSampleSummaries);
111172
+ const prevLogPathRef = useRef(void 0);
111173
+ useLayoutEffect(() => {
111174
+ const prevLogPath = prevLogPathRef.current;
111175
+ prevLogPathRef.current = logPath;
111176
+ if (prevLogPath && logPath && logPath !== prevLogPath) {
111177
+ clearSelectedSample();
111178
+ clearSelectedLogDetails();
111179
+ clearPendingSampleSummaries();
111180
+ }
111181
+ }, [
111182
+ logPath,
111183
+ clearSelectedSample,
111184
+ clearSelectedLogDetails,
111185
+ clearPendingSampleSummaries
111186
+ ]);
111187
+ };
111188
+ //#endregion
110975
111189
  //#region src/state/useLoadSample.ts
110976
111190
  var SAMPLE_LIST_KEYS = ["transcript-tree"];
110977
111191
  var log$1 = createLogger("useSampleLoader");
110978
111192
  var loadGeneration = 0;
110979
111193
  /**
111194
+ * Decide whether the loader should (re)load the selected sample.
111195
+ *
111196
+ * A "loading"/"error" status left over from a previously viewed sample must
111197
+ * not block loading a newly selected one, so those only suppress a load when
111198
+ * they pertain to the selected sample itself (identifier matches). Without
111199
+ * this, navigating away from a still-"streaming" running sample leaves the
111200
+ * new sample unloaded and the tabs showing the previous sample's events.
111201
+ */
111202
+ var shouldLoadSample = (opts) => {
111203
+ const isCurrentSampleLoaded = opts.identifierMatches && opts.hasSampleData;
111204
+ const loadingSelected = opts.identifierMatches && opts.isLoading;
111205
+ const errorSelected = opts.identifierMatches && opts.isError;
111206
+ return !isCurrentSampleLoaded && !loadingSelected && !errorSelected || opts.logFileChanged || opts.sampleIdChanged || opts.completedChanged || opts.needsReloadChanged;
111207
+ };
111208
+ /**
110980
111209
  * Hook that handles loading samples based on the current log selection.
110981
111210
  * Contains the full sample loading logic that was previously in sampleSlice.loadSample.
110982
111211
  */
@@ -111053,16 +111282,16 @@ function useLoadSample() {
111053
111282
  sampleNeedsReload: sampleData.sampleNeedsReload
111054
111283
  };
111055
111284
  if (logSelection.logFile && sampleId !== void 0 && sampleEpoch !== void 0) {
111056
- const identifierMatches = sampleData.selectedSampleIdentifier?.id === sampleId && sampleData.selectedSampleIdentifier?.epoch === sampleEpoch && sampleData.selectedSampleIdentifier?.logFile === logSelection.logFile;
111057
- const hasSampleData = getSelectedSample() !== void 0;
111058
- const isCurrentSampleLoaded = identifierMatches && hasSampleData;
111059
- const isLoading = sampleData.status === "loading" || sampleData.status === "streaming";
111060
- const isError = sampleData.status === "error";
111061
- const logFileChanged = prev.logFile !== void 0 && prev.logFile !== logSelection.logFile;
111062
- const sampleIdChanged = prev.sampleId !== void 0 && prev.sampleId !== sampleId;
111063
- const completedChanged = prev.completed !== void 0 && currentSampleCompleted !== prev.completed;
111064
- const needsReloadChanged = prev.sampleNeedsReload !== void 0 && prev.sampleNeedsReload !== sampleData.sampleNeedsReload;
111065
- if (!isCurrentSampleLoaded && !isLoading && !isError || logFileChanged || sampleIdChanged || completedChanged || needsReloadChanged) loadSample(logSelection.logFile, sampleId, sampleEpoch, sampleCompleted, logSelection.sample);
111285
+ if (shouldLoadSample({
111286
+ identifierMatches: sampleData.selectedSampleIdentifier?.id === sampleId && sampleData.selectedSampleIdentifier?.epoch === sampleEpoch && sampleData.selectedSampleIdentifier?.logFile === logSelection.logFile,
111287
+ hasSampleData: getSelectedSample() !== void 0,
111288
+ isLoading: sampleData.status === "loading" || sampleData.status === "streaming",
111289
+ isError: sampleData.status === "error",
111290
+ logFileChanged: prev.logFile !== void 0 && prev.logFile !== logSelection.logFile,
111291
+ sampleIdChanged: prev.sampleId !== void 0 && prev.sampleId !== sampleId,
111292
+ completedChanged: prev.completed !== void 0 && currentSampleCompleted !== prev.completed,
111293
+ needsReloadChanged: prev.sampleNeedsReload !== void 0 && prev.sampleNeedsReload !== sampleData.sampleNeedsReload
111294
+ })) loadSample(logSelection.logFile, sampleId, sampleEpoch, sampleCompleted, logSelection.sample);
111066
111295
  }
111067
111296
  }, [
111068
111297
  logSelection.logFile,
@@ -111331,6 +111560,7 @@ function scrollRangeToCenter(range, options) {
111331
111560
  const rects = range.getClientRects();
111332
111561
  if (rects.length === 0) return;
111333
111562
  const selectionRect = rects[0];
111563
+ if (selectionRect === void 0) return;
111334
111564
  const scrollableParent = findScrollableParent(range.startContainer.parentElement);
111335
111565
  if (scrollableParent) {
111336
111566
  const parentRect = scrollableParent.getBoundingClientRect();
@@ -111491,7 +111721,7 @@ var FindBand = () => {
111491
111721
  }, [handleSearch]);
111492
111722
  const debouncedSearchRef = useRef(null);
111493
111723
  useEffect(() => {
111494
- debouncedSearchRef.current = debounce$2(() => void runDebouncedSearch(), 300);
111724
+ debouncedSearchRef.current = debounce$2(() => void runDebouncedSearch(), 100);
111495
111725
  }, [runDebouncedSearch]);
111496
111726
  const handleInputChange = useCallback(() => {
111497
111727
  debouncedSearchRef.current?.();
@@ -112234,7 +112464,20 @@ var extractCodexAgentAnswers = (output) => {
112234
112464
  const nonEmpty = answers.filter((answer) => answer.length > 0);
112235
112465
  return nonEmpty.length > 0 ? nonEmpty.join("\n\n---\n\n") : void 0;
112236
112466
  };
112237
- var cleanCodexAnswer = (text) => text.replace(/<content-internal>[\s\S]*?<\/content-internal>/g, "").trimEnd();
112467
+ var cleanCodexAnswer = (text) => {
112468
+ const match = /<content-internal>([A-Za-z0-9+/]+={0,2})<\/content-internal>\s*$/.exec(text);
112469
+ const payload = match?.[1];
112470
+ if (!match || payload === void 0) return text;
112471
+ const visibleAnswer = text.slice(0, match.index);
112472
+ if (visibleAnswer.includes("<content-internal>") || visibleAnswer.includes("</content-internal>")) return text;
112473
+ try {
112474
+ const decoded = Uint8Array.from(atob(payload), (char) => char.charCodeAt(0));
112475
+ JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(decoded));
112476
+ } catch {
112477
+ return text;
112478
+ }
112479
+ return visibleAnswer.trimEnd();
112480
+ };
112238
112481
  /**
112239
112482
  * Substitutes `{{param_name}}` placeholders in tool call content
112240
112483
  * with actual values from the tool call arguments.
@@ -112281,6 +112524,25 @@ var extractInput = (args, inputDescriptor) => {
112281
112524
  return formatArg(key, args[key]);
112282
112525
  }) };
112283
112526
  };
112527
+ var MediaReference_module_default = { reference: "_reference_7p4hu_1" };
112528
+ //#endregion
112529
+ //#region ../../packages/inspect-components/src/media/MediaReference.tsx
112530
+ var MediaReference = ({ source, className }) => {
112531
+ const href = parseAbsoluteHttpUrl(source);
112532
+ const dataUri = parseDataUri(source);
112533
+ const label = dataUri ? `data:${dataUri.mimeType}${dataUri.base64 ? ";base64" : ""},...` : source;
112534
+ const classes = clsx(MediaReference_module_default.reference, className);
112535
+ return href ? /* @__PURE__ */ jsx("a", {
112536
+ className: classes,
112537
+ href,
112538
+ target: "_blank",
112539
+ rel: "noopener noreferrer",
112540
+ children: href
112541
+ }) : /* @__PURE__ */ jsx("code", {
112542
+ className: classes,
112543
+ children: label
112544
+ });
112545
+ };
112284
112546
  var CompactionData_module_default = {
112285
112547
  title: "_title_1pwo3_1",
112286
112548
  content: "_content_1pwo3_11",
@@ -112465,12 +112727,12 @@ var ContentDocumentView = ({ id, document, onDownloadFile }) => {
112465
112727
  if (isImage(document.mime_type || "")) return /* @__PURE__ */ jsx(ContentDocumentFrame, {
112466
112728
  document,
112467
112729
  onDownloadFile,
112468
- children: /* @__PURE__ */ jsx("img", {
112730
+ children: isRenderableImageDocument(document.document, document.mime_type || "") ? /* @__PURE__ */ jsx("img", {
112469
112731
  className: clsx(ContentDocumentView_module_default.imageDocument),
112470
112732
  src: document.document,
112471
112733
  alt: document.filename,
112472
112734
  id
112473
- })
112735
+ }) : /* @__PURE__ */ jsx(MediaReference, { source: document.document })
112474
112736
  });
112475
112737
  else return /* @__PURE__ */ jsx(ContentDocumentFrame, {
112476
112738
  document,
@@ -112903,11 +113165,11 @@ var ToolOutput = ({ output, className, onDownloadFile }) => {
112903
113165
  document: out,
112904
113166
  onDownloadFile
112905
113167
  }, key));
112906
- else if (out.type === "image") if (out.image.startsWith("data:")) outputs.push(/* @__PURE__ */ jsx("img", {
113168
+ else if (out.type === "image") if (isRenderableImageSource(out.image)) outputs.push(/* @__PURE__ */ jsx("img", {
112907
113169
  className: clsx(ToolOutput_module_default.toolImage),
112908
113170
  src: out.image
112909
113171
  }, key));
112910
- else outputs.push(/* @__PURE__ */ jsx(ToolTextOutput, { text: String(out.image) }, key));
113172
+ else outputs.push(/* @__PURE__ */ jsx(MediaReference, { source: out.image }, key));
112911
113173
  else if (out.type === "reasoning") {
112912
113174
  if (out.reasoning) outputs.push(/* @__PURE__ */ jsx(ToolTextOutput, { text: out.reasoning }, key));
112913
113175
  } else if (out.type === "data" && out.data) outputs.push(/* @__PURE__ */ jsx(ToolTextOutput, { text: JSON.stringify(out.data) }, key));
@@ -112922,11 +113184,12 @@ var ToolOutput = ({ output, className, onDownloadFile }) => {
112922
113184
  * Renders the ToolTextOutput component.
112923
113185
  */
112924
113186
  var ToolTextOutput = ({ text }) => {
112925
- if (isJson(text)) return /* @__PURE__ */ jsx(JsonMessageContent, {
113187
+ const displayMode = useDisplayMode();
113188
+ if (displayMode === "rendered" && isJson(text)) return /* @__PURE__ */ jsx(JsonMessageContent, {
112926
113189
  id: `1-json`,
112927
113190
  json: JSON.parse(text)
112928
113191
  });
112929
- if (isAnsiOutput(text)) return /* @__PURE__ */ jsx(ANSIDisplay, {
113192
+ if (displayMode === "rendered" && isAnsiOutput(text)) return /* @__PURE__ */ jsx(ANSIDisplay, {
112930
113193
  className: ToolOutput_module_default.ansiOutput,
112931
113194
  output: text,
112932
113195
  style: { fontSize: "clamp(0.4rem, 1.15vw, 0.9rem)" }
@@ -112936,7 +113199,7 @@ var ToolTextOutput = ({ text }) => {
112936
113199
  className: clsx(ToolOutput_module_default.textOutput, "tool-output"),
112937
113200
  children: /* @__PURE__ */ jsx("code", {
112938
113201
  className: clsx("sourceCode", ToolOutput_module_default.textCode),
112939
- children: capped.trim()
113202
+ children: displayMode === "raw" ? capped : capped.trim()
112940
113203
  })
112941
113204
  }), notice] });
112942
113205
  };
@@ -112947,7 +113210,8 @@ var ToolTextOutput = ({ text }) => {
112947
113210
  * Supports rendering strings, images, and tools using specific renderers.
112948
113211
  */
112949
113212
  var MessageContent = ({ contents, context, references }) => {
112950
- const normalized = normalizeContent$1(contents);
113213
+ const displayMode = useDisplayMode();
113214
+ const normalized = normalizeContent$1(contents, displayMode);
112951
113215
  if (Array.isArray(normalized)) return normalized.map((content, index) => {
112952
113216
  if (typeof content === "string") return messageRenderers["text"]?.render(`text-content-${index}`, {
112953
113217
  type: "text",
@@ -112955,10 +113219,10 @@ var MessageContent = ({ contents, context, references }) => {
112955
113219
  refusal: null,
112956
113220
  internal: null,
112957
113221
  citations: null
112958
- }, index === contents.length - 1, context, references);
113222
+ }, index === contents.length - 1, context, displayMode, references);
112959
113223
  else if (content) {
112960
113224
  const renderer = messageRenderers[content.type];
112961
- if (renderer) return renderer.render(`text-${content.type}-${index}`, content, index === contents.length - 1, context, references);
113225
+ if (renderer) return renderer.render(`text-${content.type}-${index}`, content, index === contents.length - 1, context, displayMode, references);
112962
113226
  else console.error(`Unknown message content type '${content.type}'`);
112963
113227
  }
112964
113228
  });
@@ -112970,33 +113234,22 @@ var MessageContent = ({ contents, context, references }) => {
112970
113234
  internal: null,
112971
113235
  citations: null
112972
113236
  };
112973
- return messageRenderers["text"]?.render("text-message-content", contentText, true, context, references);
113237
+ return messageRenderers["text"]?.render("text-message-content", contentText, true, context, displayMode, references);
112974
113238
  }
112975
113239
  };
112976
113240
  var messageRenderers = {
112977
- text: { render: (key, content, isLast, _context, references) => {
113241
+ text: { render: (key, content, isLast, _context, displayMode, references) => {
112978
113242
  const c = content;
112979
113243
  const cites = c.citations ?? [];
112980
113244
  if (!c.text && !cites.length) return;
112981
- const purgeInternalContainers = (text) => {
112982
- [
112983
- "internal",
112984
- "content-internal",
112985
- "think"
112986
- ].forEach((tag) => {
112987
- const regex = new RegExp(`<${tag}[^>]*>[\\s\\S]*?<\\/${tag}>`, "gm");
112988
- text = text.replace(regex, "");
112989
- });
112990
- return text.trim();
112991
- };
112992
- if (isJson(c.text)) {
113245
+ if (displayMode === "rendered" && isJson(c.text)) {
112993
113246
  const obj = JSON.parse(c.text);
112994
113247
  return /* @__PURE__ */ jsx(JsonMessageContent, {
112995
113248
  id: `${key}-json`,
112996
113249
  json: obj
112997
113250
  });
112998
113251
  } else return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(RenderedText, {
112999
- markdown: purgeInternalContainers(c.text) || "",
113252
+ markdown: c.text,
113000
113253
  className: clsx(isLast ? "no-last-para-padding" : "", MessageContent_module_default.breakable),
113001
113254
  references
113002
113255
  }), c.citations && c.citations.length > 0 ? /* @__PURE__ */ jsx(MessageCitations, { citations: c.citations }) : void 0] }, key);
@@ -113032,31 +113285,33 @@ var messageRenderers = {
113032
113285
  } },
113033
113286
  image: { render: (key, content) => {
113034
113287
  const c = content;
113035
- if (c.image.startsWith("data:")) return /* @__PURE__ */ jsx("img", {
113288
+ if (isRenderableImageSource(c.image)) return /* @__PURE__ */ jsx("img", {
113036
113289
  src: c.image,
113037
113290
  className: MessageContent_module_default.contentImage
113038
113291
  }, key);
113039
- else return /* @__PURE__ */ jsx("code", { children: c.image }, key);
113292
+ else return /* @__PURE__ */ jsx(MediaReference, { source: c.image }, key);
113040
113293
  } },
113041
113294
  audio: { render: (key, content) => {
113042
113295
  const c = content;
113296
+ if (!isRenderableAudioSource(c.audio, c.format)) return /* @__PURE__ */ jsx(MediaReference, { source: c.audio }, key);
113043
113297
  return /* @__PURE__ */ jsx("audio", {
113044
113298
  controls: true,
113045
113299
  children: /* @__PURE__ */ jsx("source", {
113046
113300
  src: c.audio,
113047
- type: mimeTypeForFormat(c.format)
113301
+ type: audioMimeTypeForFormat(c.format)
113048
113302
  })
113049
113303
  }, key);
113050
113304
  } },
113051
113305
  video: { render: (key, content) => {
113052
113306
  const c = content;
113307
+ if (!isRenderableVideoSource(c.video, c.format)) return /* @__PURE__ */ jsx(MediaReference, { source: c.video }, key);
113053
113308
  return /* @__PURE__ */ jsx("video", {
113054
113309
  width: "500",
113055
113310
  height: "375",
113056
113311
  controls: true,
113057
113312
  children: /* @__PURE__ */ jsx("source", {
113058
113313
  src: c.video,
113059
- type: mimeTypeForFormat(c.format)
113314
+ type: videoMimeTypeForFormat(c.format)
113060
113315
  })
113061
113316
  }, key);
113062
113317
  } },
@@ -113087,17 +113342,8 @@ var messageRenderers = {
113087
113342
  * Renders message content based on its type.
113088
113343
  * Supports rendering strings, images, and tools using specific renderers.
113089
113344
  */
113090
- var mimeTypeForFormat = (format) => {
113091
- switch (format) {
113092
- case "mov": return "video/quicktime";
113093
- case "wav": return "audio/wav";
113094
- case "mp3": return "audio/mpeg";
113095
- case "mp4": return "video/mp4";
113096
- case "mpeg": return "video/mpeg";
113097
- default: return "video/mp4";
113098
- }
113099
- };
113100
- var normalizeContent$1 = (contents) => {
113345
+ var normalizeContent$1 = (contents, displayMode) => {
113346
+ if (displayMode === "raw") return contents;
113101
113347
  if (typeof contents === "string") return contents;
113102
113348
  if (contents.length > 0 && typeof contents[0] === "string") return contents;
113103
113349
  const result = [];
@@ -113308,6 +113554,7 @@ var ToolCallView_module_default = { toolCallView: "_toolCallView_x6cus_1" };
113308
113554
  * Renders the ToolCallView component.
113309
113555
  */
113310
113556
  var ToolCallView = ({ id, tool, functionCall, input, description, contentType, view, output, mode, collapsible = true, section = "all", getCustomToolView }) => {
113557
+ const displayMode = useDisplayMode();
113311
113558
  function isContentImage(value) {
113312
113559
  if (value && typeof value === "object") {
113313
113560
  if (value.type === "image") return true;
@@ -113319,9 +113566,13 @@ var ToolCallView = ({ id, tool, functionCall, input, description, contentType, v
113319
113566
  }
113320
113567
  const collapse = Array.isArray(output) ? output.every((item) => !isContentImage(item)) : !isContentImage(output);
113321
113568
  const normalizedContent = useMemo(() => {
113322
- const markdown = codexToolMarkdown(tool, output);
113569
+ const markdown = displayMode === "rendered" ? codexToolMarkdown(tool, output) : void 0;
113323
113570
  return normalizeContent(markdown !== void 0 ? markdown : output);
113324
- }, [tool, output]);
113571
+ }, [
113572
+ displayMode,
113573
+ tool,
113574
+ output
113575
+ ]);
113325
113576
  const hasContent = normalizedContent.find((c) => {
113326
113577
  if (c.type === "tool") {
113327
113578
  for (const t of c.content) if (t.type === "text") {
@@ -113340,7 +113591,7 @@ var ToolCallView = ({ id, tool, functionCall, input, description, contentType, v
113340
113591
  output,
113341
113592
  mode
113342
113593
  };
113343
- const customView = getCustomToolView?.(props) ?? getDefaultCustomToolView(props);
113594
+ const customView = displayMode === "rendered" ? getCustomToolView?.(props) ?? getDefaultCustomToolView(props) : void 0;
113344
113595
  if (customView) return section === "output" ? null : customView;
113345
113596
  const contents = mode !== "compact" ? input : input || functionCall;
113346
113597
  const context = defaultContext();
@@ -113359,7 +113610,7 @@ var ToolCallView = ({ id, tool, functionCall, input, description, contentType, v
113359
113610
  toolCallView: view
113360
113611
  })
113361
113612
  })] });
113362
- const outputSection = contentType === "markdown" && hasContent ? /* @__PURE__ */ jsx(ExpandablePanel, {
113613
+ const outputSection = displayMode === "rendered" && contentType === "markdown" && hasContent ? /* @__PURE__ */ jsx(ExpandablePanel, {
113363
113614
  id: `${id}-tool-content`,
113364
113615
  collapse,
113365
113616
  border: false,
@@ -113423,6 +113674,7 @@ var ClientToolCall_module_default = { custom: "_custom_v2cay_4" };
113423
113674
  * (e.g. code) and the output well stacked beneath.
113424
113675
  */
113425
113676
  var ClientToolCall = ({ id, tool, title, functionCall, input, description, contentType, view, output, error, className, getCustomToolView }) => {
113677
+ const displayMode = useDisplayMode();
113426
113678
  const viewProps = {
113427
113679
  id,
113428
113680
  tool,
@@ -113433,7 +113685,7 @@ var ClientToolCall = ({ id, tool, title, functionCall, input, description, conte
113433
113685
  view,
113434
113686
  output
113435
113687
  };
113436
- const customView = getCustomToolView?.(viewProps) ?? getDefaultCustomToolView(viewProps);
113688
+ const customView = displayMode === "rendered" ? getCustomToolView?.(viewProps) ?? getDefaultCustomToolView(viewProps) : void 0;
113437
113689
  if (customView) return /* @__PURE__ */ jsx("div", {
113438
113690
  className: clsx(ClientToolCall_module_default.custom, className),
113439
113691
  children: customView
@@ -113508,6 +113760,7 @@ var ChatMessage = memo(function ChatMessage({ id, message, display, linking, ref
113508
113760
  const linkingEnabled = linking?.enabled ?? false;
113509
113761
  const getMessageUrl = linking?.getMessageUrl;
113510
113762
  const linkIcon = linking?.icon ?? "bi bi-link-45deg";
113763
+ const displayMode = useDisplayMode();
113511
113764
  const messageUrl = getMessageUrl?.(message.id || "");
113512
113765
  const [mouseOver, setMouseOver] = useState(false);
113513
113766
  const isNonSubagentTool = message.role === "tool" && message.function !== "Task" && message.function !== "task" && message.function !== "Agent" && message.function !== "agent";
@@ -113515,9 +113768,9 @@ var ChatMessage = memo(function ChatMessage({ id, message, display, linking, ref
113515
113768
  const hideRole = unlabeledRoles?.includes(message.role) ?? false;
113516
113769
  let toolSearchNamespaces;
113517
113770
  let toolMarkdown;
113518
- if (isNonSubagentTool && message.role === "tool" && message.function) if (message.function === "tool_search") toolSearchNamespaces = parseToolSearchCatalog(message.content);
113771
+ if (displayMode === "rendered" && isNonSubagentTool && message.role === "tool" && message.function) if (message.function === "tool_search") toolSearchNamespaces = parseToolSearchCatalog(message.content);
113519
113772
  else toolMarkdown = codexToolMarkdown(message.function, message.content);
113520
- const subagentNotifications = message.role === "user" ? formatSubagentNotifications(message.content) : void 0;
113773
+ const subagentNotifications = displayMode === "rendered" && message.role === "user" ? formatSubagentNotifications(message.content) : void 0;
113521
113774
  if (hideRole) {
113522
113775
  const content = message.content;
113523
113776
  const hasVisibleContent = typeof content === "string" ? content.trim().length > 0 : Array.isArray(content) && content.length > 0;
@@ -115182,6 +115435,18 @@ function PaddingChunks({ height, prefix }) {
115182
115435
  }
115183
115436
  return /* @__PURE__ */ jsx(Fragment$1, { children: chunks });
115184
115437
  }
115438
+ var countMatchesInTexts = (lowerTextsByItem, lowerTerm) => {
115439
+ if (lowerTerm.length === 0) return 0;
115440
+ let total = 0;
115441
+ for (const texts of lowerTextsByItem) for (const lowerText of texts) {
115442
+ let pos = 0;
115443
+ while ((pos = lowerText.indexOf(lowerTerm, pos)) !== -1) {
115444
+ total++;
115445
+ pos += lowerTerm.length;
115446
+ }
115447
+ }
115448
+ return total;
115449
+ };
115185
115450
  function VirtualList({ persistenceKey, ref, className, scrollRef: externalScrollRef, data, renderRow, live, showProgress, initialIndex, stickyHeaderOffset, components, smoothScroll = true, itemSearchText, findScope = "local", scrollToTopOnFinish = false, onVisibleRangeChange }) {
115186
115451
  const internalScrollRef = useRef(null);
115187
115452
  const [scrollParent, setScrollParent] = useState(null);
@@ -115504,25 +115769,17 @@ function VirtualList({ persistenceKey, ref, className, scrollRef: externalScroll
115504
115769
  itemSearchText,
115505
115770
  virtualizer
115506
115771
  ]);
115507
- const countMatchesInData = useCallback((term) => {
115508
- if (!term || data.length === 0) return 0;
115772
+ const precomputedSearchTexts = useMemo(() => {
115509
115773
  const getText = itemSearchText ?? ((item) => JSON.stringify(item));
115510
- const lower = term.toLowerCase();
115511
- let total = 0;
115512
- for (const item of data) {
115774
+ return data.map((item) => {
115513
115775
  const texts = getText(item);
115514
- const textArray = Array.isArray(texts) ? texts : [texts];
115515
- for (const text of textArray) {
115516
- const lowerText = text.toLowerCase();
115517
- let pos = 0;
115518
- while ((pos = lowerText.indexOf(lower, pos)) !== -1) {
115519
- total++;
115520
- pos += lower.length;
115521
- }
115522
- }
115523
- }
115524
- return total;
115776
+ return (Array.isArray(texts) ? texts : [texts]).map((t) => t.toLowerCase());
115777
+ });
115525
115778
  }, [data, itemSearchText]);
115779
+ const countMatchesInData = useCallback((term) => {
115780
+ if (!term || precomputedSearchTexts.length === 0) return 0;
115781
+ return countMatchesInTexts(precomputedSearchTexts, term.toLowerCase());
115782
+ }, [precomputedSearchTexts]);
115526
115783
  useEffect(() => {
115527
115784
  if (findScope === "none") return;
115528
115785
  const u1 = registerVirtualList(persistenceKey, searchInData);
@@ -115689,6 +115946,40 @@ function messageHasVisibleContent(message) {
115689
115946
  return true;
115690
115947
  });
115691
115948
  }
115949
+ var LoadingEventsIndicator_module_default = {
115950
+ bar: "_bar_q6epo_1",
115951
+ "le-sweep": "_le-sweep_q6epo_1",
115952
+ compact: "_compact_q6epo_33",
115953
+ spinner: "_spinner_q6epo_44",
115954
+ "le-spin": "_le-spin_q6epo_1",
115955
+ label: "_label_q6epo_55",
115956
+ ell: "_ell_q6epo_68",
115957
+ "le-ell": "_le-ell_q6epo_1"
115958
+ };
115959
+ //#endregion
115960
+ //#region ../../packages/inspect-components/src/indicators/LoadingEventsIndicator.tsx
115961
+ var LoadingEventsIndicator = ({ label, compact = false, className }) => {
115962
+ return /* @__PURE__ */ jsxs("div", {
115963
+ role: "status",
115964
+ "aria-live": "polite",
115965
+ className: clsx(LoadingEventsIndicator_module_default.bar, compact && LoadingEventsIndicator_module_default.compact, className),
115966
+ children: [/* @__PURE__ */ jsx("span", {
115967
+ className: LoadingEventsIndicator_module_default.spinner,
115968
+ "aria-hidden": "true"
115969
+ }), /* @__PURE__ */ jsxs("span", {
115970
+ className: LoadingEventsIndicator_module_default.label,
115971
+ children: [label, /* @__PURE__ */ jsxs("span", {
115972
+ className: LoadingEventsIndicator_module_default.ell,
115973
+ "aria-hidden": "true",
115974
+ children: [
115975
+ /* @__PURE__ */ jsx("i", { children: "." }),
115976
+ /* @__PURE__ */ jsx("i", { children: "." }),
115977
+ /* @__PURE__ */ jsx("i", { children: "." })
115978
+ ]
115979
+ })]
115980
+ })]
115981
+ });
115982
+ };
115692
115983
  var ChatViewVirtualList_module_default = {
115693
115984
  list: "_list_zuqui_1",
115694
115985
  generatingRow: "_generatingRow_zuqui_7"
@@ -115706,7 +115997,7 @@ var ChatItem = ({ children, ...props }) => {
115706
115997
  });
115707
115998
  };
115708
115999
  var chatComponents = { Item: ChatItem };
115709
- var ChatViewVirtualList = memo(function ChatViewVirtualList({ id, messages, initialMessageId, offsetTop, className, scrollRef, running, onNativeFindChanged, display, labels, linking, tools }) {
116000
+ var ChatViewVirtualList = memo(function ChatViewVirtualList({ id, messages, initialMessageId, offsetTop, className, scrollRef, running, backfilling, onNativeFindChanged, display, labels, linking, tools }) {
115710
116001
  const listHandle = useRef(null);
115711
116002
  useEffect(() => {
115712
116003
  onNativeFindChanged?.(false);
@@ -115746,7 +116037,7 @@ var ChatViewVirtualList = memo(function ChatViewVirtualList({ id, messages, init
115746
116037
  const renderRow = useCallback((index, item) => {
115747
116038
  if (running && index === lastIndex && isLivePlaceholderMessage(item.message)) return /* @__PURE__ */ jsx("div", {
115748
116039
  className: ChatViewVirtualList_module_default.generatingRow,
115749
- children: /* @__PURE__ */ jsx(GeneratingIndicator, {})
116040
+ children: backfilling ? /* @__PURE__ */ jsx(LoadingEventsIndicator, { label: "Loading messages" }) : /* @__PURE__ */ jsx(GeneratingIndicator, {})
115750
116041
  });
115751
116042
  const toolExecuting = running && index === lastIndex && isToolExecutingMessage(item.message, item.toolMessages.length);
115752
116043
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ChatMessageRow, {
@@ -115761,11 +116052,12 @@ var ChatViewVirtualList = memo(function ChatViewVirtualList({ id, messages, init
115761
116052
  startNumber: rowStartNumbers[index]
115762
116053
  }), toolExecuting ? /* @__PURE__ */ jsx("div", {
115763
116054
  className: ChatViewVirtualList_module_default.generatingRow,
115764
- children: /* @__PURE__ */ jsx(GeneratingIndicator, { label: "running" })
116055
+ children: backfilling ? /* @__PURE__ */ jsx(LoadingEventsIndicator, { label: "Loading messages" }) : /* @__PURE__ */ jsx(GeneratingIndicator, { label: "running" })
115765
116056
  }) : null] });
115766
116057
  }, [
115767
116058
  id,
115768
116059
  running,
116060
+ backfilling,
115769
116061
  lastIndex,
115770
116062
  display,
115771
116063
  labels,
@@ -115774,10 +116066,13 @@ var ChatViewVirtualList = memo(function ChatViewVirtualList({ id, messages, init
115774
116066
  maxLabelLength,
115775
116067
  rowStartNumbers
115776
116068
  ]);
115777
- if (collapsedMessages.length === 0) return running ? /* @__PURE__ */ jsx(NoContentsPanel, {
115778
- text: "Waiting for messages",
115779
- busy: true
115780
- }) : /* @__PURE__ */ jsx(NoContentsPanel, { text: "No messages" });
116069
+ if (collapsedMessages.length === 0) {
116070
+ if (backfilling) return /* @__PURE__ */ jsx(LoadingEventsIndicator, { label: "Loading messages" });
116071
+ return running ? /* @__PURE__ */ jsx(NoContentsPanel, {
116072
+ text: "Waiting for messages",
116073
+ busy: true
116074
+ }) : /* @__PURE__ */ jsx(NoContentsPanel, { text: "No messages" });
116075
+ }
115781
116076
  return /* @__PURE__ */ jsx(VirtualList, {
115782
116077
  persistenceKey: `chat-${id}`,
115783
116078
  ref: listHandle,
@@ -116376,6 +116671,8 @@ var extractEventFields = (event) => {
116376
116671
  if (modelEvent.input) {
116377
116672
  for (const msg of modelEvent.input) if (msg.role === "user" || msg.role === "system") for (const text of extractContentText(msg.content)) fields.push([msg.role, text]);
116378
116673
  }
116674
+ if (modelEvent.error) fields.push(["error", modelEvent.error]);
116675
+ if (modelEvent.traceback) fields.push(["traceback", modelEvent.traceback]);
116379
116676
  break;
116380
116677
  }
116381
116678
  case "tool": {
@@ -116391,7 +116688,7 @@ var extractEventFields = (event) => {
116391
116688
  if (toolEvent.function) fields.push(["function", toolEvent.function]);
116392
116689
  if (toolEvent.arguments) fields.push(["arguments", JSON.stringify(toolEvent.arguments)]);
116393
116690
  if (toolEvent.result) if (typeof toolEvent.result === "string") fields.push(["result", toolEvent.result]);
116394
- else fields.push(["result", sanitizeStringify(toolEvent.result)]);
116691
+ else for (const text of extractToolResultText(toolEvent.result)) fields.push(["result", text]);
116395
116692
  if (toolEvent.error?.message) fields.push(["error", toolEvent.error.message]);
116396
116693
  break;
116397
116694
  }
@@ -116573,6 +116870,27 @@ var extractContentText = (content) => {
116573
116870
  }
116574
116871
  return texts;
116575
116872
  };
116873
+ var extractToolResultText = (value) => {
116874
+ if (Array.isArray(value)) return value.flatMap((item) => extractToolResultItemText(item));
116875
+ return [sanitizeStringify(value)];
116876
+ };
116877
+ var extractToolResultItemText = (item) => {
116878
+ if (typeof item === "string") return [item];
116879
+ if (item == null) return [];
116880
+ if (typeof item === "number" || typeof item === "boolean" || typeof item === "bigint") return [item.toString()];
116881
+ if (typeof item === "symbol") return [String(item)];
116882
+ if (typeof item !== "object") return [];
116883
+ if (!("type" in item)) return [sanitizeStringify(item)];
116884
+ switch (item.type) {
116885
+ case "text": return "text" in item && typeof item.text === "string" ? [item.text] : [];
116886
+ case "image": return "image" in item && typeof item.image === "string" && !item.image.startsWith("data:") ? [item.image] : [];
116887
+ case "document": return "filename" in item && typeof item.filename === "string" ? [item.filename] : [];
116888
+ case "audio":
116889
+ case "video": return [];
116890
+ case "tool": return "content" in item && Array.isArray(item.content) ? item.content.flatMap((inner) => extractToolResultItemText(inner)) : [sanitizeStringify(item)];
116891
+ default: return [sanitizeStringify(item)];
116892
+ }
116893
+ };
116576
116894
  //#endregion
116577
116895
  //#region ../../packages/inspect-components/src/transcript/timeline/core.ts
116578
116896
  function isSpanNode(item) {
@@ -120375,14 +120693,17 @@ var TranscriptIcons = {
120375
120693
  solvers: { use_tools: "bi bi-tools" }
120376
120694
  };
120377
120695
  var OutlineRow_module_default = {
120378
- eventRow: "_eventRow_moh1w_1",
120379
- selected: "_selected_moh1w_9",
120380
- toggle: "_toggle_moh1w_13",
120381
- eventLink: "_eventLink_moh1w_18",
120382
- label: "_label_moh1w_31",
120383
- iconSlot: "_iconSlot_moh1w_37",
120384
- progress: "_progress_moh1w_49",
120385
- popover: "_popover_moh1w_53"
120696
+ eventRow: "_eventRow_lpuxs_1",
120697
+ selected: "_selected_lpuxs_9",
120698
+ toggle: "_toggle_lpuxs_13",
120699
+ eventLink: "_eventLink_lpuxs_18",
120700
+ label: "_label_lpuxs_31",
120701
+ iconSlot: "_iconSlot_lpuxs_37",
120702
+ progress: "_progress_lpuxs_49",
120703
+ loadingRow: "_loadingRow_lpuxs_53",
120704
+ spinner: "_spinner_lpuxs_57",
120705
+ "outline-spin": "_outline-spin_lpuxs_1",
120706
+ popover: "_popover_lpuxs_78"
120386
120707
  };
120387
120708
  //#endregion
120388
120709
  //#region ../../packages/inspect-components/src/transcript/outline/OutlineRow.tsx
@@ -120432,6 +120753,24 @@ var OutlineRow = ({ node, running, selected, getEventUrl, onSelect, onNavigateTo
120432
120753
  })]
120433
120754
  }) });
120434
120755
  };
120756
+ /** A row rendered below the last outline item while events are still loading. */
120757
+ var OutlineLoadingRow = () => /* @__PURE__ */ jsxs("div", {
120758
+ className: clsx(OutlineRow_module_default.eventRow, OutlineRow_module_default.loadingRow, "text-size-smaller"),
120759
+ style: { paddingLeft: 0 },
120760
+ "data-unsearchable": true,
120761
+ children: [/* @__PURE__ */ jsx("div", { className: OutlineRow_module_default.toggle }), /* @__PURE__ */ jsxs("div", {
120762
+ className: clsx(OutlineRow_module_default.label),
120763
+ role: "status",
120764
+ "aria-live": "polite",
120765
+ children: [/* @__PURE__ */ jsx("span", {
120766
+ className: OutlineRow_module_default.iconSlot,
120767
+ children: /* @__PURE__ */ jsx("span", {
120768
+ className: OutlineRow_module_default.spinner,
120769
+ "aria-hidden": "true"
120770
+ })
120771
+ }), /* @__PURE__ */ jsx("span", { children: "loading" })]
120772
+ })]
120773
+ });
120435
120774
  var toggleIcon = (node, collapsed) => {
120436
120775
  if (node.children.length > 0) return collapsed ? "bi bi-chevron-right" : "bi bi-chevron-down";
120437
120776
  };
@@ -120574,6 +120913,7 @@ function labelForOutlineNode(node) {
120574
120913
  //#endregion
120575
120914
  //#region ../../packages/inspect-components/src/transcript/outline/TranscriptOutline.tsx
120576
120915
  var kFramesToStabilize = 10;
120916
+ var outlineNodeRunning = ({ running, backfilling, isLast }) => running && !backfilling && isLast;
120577
120917
  var EventPaddingNode = {
120578
120918
  id: "padding",
120579
120919
  event: {
@@ -120590,7 +120930,11 @@ var EventPaddingNode = {
120590
120930
  depth: 0,
120591
120931
  children: []
120592
120932
  };
120593
- var TranscriptOutline = ({ eventNodes, defaultCollapsedIds, running, className, scrollRef, outlineScrollEl, style, agentName, onHasNodesChange, onWidthChange, onNavigateToEvent, scrollTrackOffset, getEventUrl, getCollapsed, setCollapsed, collapsedEvents, setCollapsedEvents, selectedOutlineId, setSelectedOutlineId, renderLink }) => {
120933
+ var OutlineLoadingNode = {
120934
+ ...EventPaddingNode,
120935
+ id: "loading"
120936
+ };
120937
+ var TranscriptOutline = ({ eventNodes, defaultCollapsedIds, running, backfilling, className, scrollRef, outlineScrollEl, style, agentName, onHasNodesChange, onWidthChange, onNavigateToEvent, scrollTrackOffset, getEventUrl, getCollapsed, setCollapsed, collapsedEvents, setCollapsedEvents, selectedOutlineId, setSelectedOutlineId, renderLink }) => {
120594
120938
  const id = "transcript-tree";
120595
120939
  const listHandle = useRef(null);
120596
120940
  const { getRestoreState } = useVirtuosoState(listHandle, id);
@@ -120694,9 +121038,14 @@ var TranscriptOutline = ({ eventNodes, defaultCollapsedIds, running, className,
120694
121038
  className: clsx(TranscriptOutline_module_default.eventPadding),
120695
121039
  style: { height: "2em" }
120696
121040
  }, node.id);
121041
+ else if (node === OutlineLoadingNode) return /* @__PURE__ */ jsx(OutlineLoadingRow, {}, node.id);
120697
121042
  else return /* @__PURE__ */ jsx(OutlineRow, {
120698
121043
  node,
120699
- running: running && index === outlineNodeList.length - 1,
121044
+ running: outlineNodeRunning({
121045
+ running: running === true,
121046
+ backfilling: backfilling === true,
121047
+ isLast: index === outlineNodeList.length - 1
121048
+ }),
120700
121049
  selected: selectedOutlineId ? selectedOutlineId === node.id : index === 0,
120701
121050
  getEventUrl,
120702
121051
  onSelect: handleOutlineSelect,
@@ -120708,6 +121057,7 @@ var TranscriptOutline = ({ eventNodes, defaultCollapsedIds, running, className,
120708
121057
  }, [
120709
121058
  outlineNodeList,
120710
121059
  running,
121060
+ backfilling,
120711
121061
  selectedOutlineId,
120712
121062
  getEventUrl,
120713
121063
  handleOutlineSelect,
@@ -120726,7 +121076,11 @@ var TranscriptOutline = ({ eventNodes, defaultCollapsedIds, running, className,
120726
121076
  ref: listHandle,
120727
121077
  customScrollParent: outlineScrollEl ?? void 0,
120728
121078
  id,
120729
- data: [...outlineNodeList, EventPaddingNode],
121079
+ data: backfilling ? [
121080
+ ...outlineNodeList,
121081
+ OutlineLoadingNode,
121082
+ EventPaddingNode
121083
+ ] : [...outlineNodeList, EventPaddingNode],
120730
121084
  defaultItemHeight: 50,
120731
121085
  itemContent: renderRow,
120732
121086
  atBottomThreshold: 30,
@@ -126546,6 +126900,52 @@ var ToolEventView = ({ eventNode, childNodes, className, context, eventCallbacks
126546
126900
  })
126547
126901
  });
126548
126902
  };
126903
+ //#endregion
126904
+ //#region ../../packages/inspect-components/src/transcript/hasToolEventsAtDepth.ts
126905
+ /**
126906
+ * For each event node, compute whether a backward scan from that node reaches a
126907
+ * tool event before it reaches any node strictly shallower than itself. This
126908
+ * reproduces, in O(n), the exact result of the former per-index O(n^2) backward
126909
+ * scan (`hasToolEventsAtCurrentDepth`) so callers see no behavior change.
126910
+ *
126911
+ * Semantics (matching the old scan exactly): scanning backward from index i,
126912
+ * return true on the first tool event encountered; otherwise return false on
126913
+ * the first non-tool node shallower than i's depth. The tool check precedes the
126914
+ * depth check, so a node that is both a tool and shallower still returns true.
126915
+ *
126916
+ * O(n) reformulation. The backward scan from i stops at the first index that is
126917
+ * either a tool OR strictly shallower than depth[i]; the result is true iff
126918
+ * that first stop is a tool. Equivalently: let `lastToolIndex` be the most
126919
+ * recent tool at or before i, and `prevShallower` be the nearest preceding
126920
+ * index strictly shallower than depth[i]. The scan hits the tool before any
126921
+ * strictly-shallower node iff `lastToolIndex >= prevShallower` (and a tool
126922
+ * exists at all). We compute `prevShallower` for every i in amortized O(1)
126923
+ * using a monotonic stack whose depths strictly increase from the bottom (a
126924
+ * classic "previous strictly-smaller element" stack); each node is pushed and
126925
+ * popped at most once, so the whole pass is O(n).
126926
+ */
126927
+ function computeHasToolEventsAtDepth(eventNodes) {
126928
+ const result = new Array(eventNodes.length);
126929
+ const shallowerStack = [];
126930
+ let lastToolIndex = -1;
126931
+ for (let i = 0; i < eventNodes.length; i++) {
126932
+ const node = eventNodes[i];
126933
+ if (!node) {
126934
+ result[i] = false;
126935
+ continue;
126936
+ }
126937
+ const depth = node.depth;
126938
+ while (shallowerStack.length > 0 && shallowerStack[shallowerStack.length - 1].depth >= depth) shallowerStack.pop();
126939
+ const prevShallower = shallowerStack.length > 0 ? shallowerStack[shallowerStack.length - 1].index : -1;
126940
+ shallowerStack.push({
126941
+ index: i,
126942
+ depth
126943
+ });
126944
+ if (node.event.event === "tool") lastToolIndex = i;
126945
+ result[i] = lastToolIndex >= 0 && lastToolIndex >= prevShallower;
126946
+ }
126947
+ return result;
126948
+ }
126549
126949
  var TranscriptVirtualListComponent_module_default = {
126550
126950
  node: "_node_t3xlr_1",
126551
126951
  attached: "_attached_t3xlr_5",
@@ -126560,7 +126960,7 @@ var TranscriptVirtualListComponent_module_default = {
126560
126960
  /**
126561
126961
  * Renders the Transcript component.
126562
126962
  */
126563
- var TranscriptVirtualListComponent = ({ id, listHandle, eventNodes, scrollRef, running, initialEventId, offsetTop, className, turnMap, disableVirtualization, onNativeFindChanged, onAutoCollapse, renderAgentCard, eventCallbacks, eventNodeContext, visibleRangeRef }) => {
126963
+ var TranscriptVirtualListComponent = ({ id, listHandle, eventNodes, scrollRef, running, backfilling, initialEventId, offsetTop, className, turnMap, disableVirtualization, onNativeFindChanged, onAutoCollapse, renderAgentCard, eventCallbacks, eventNodeContext, visibleRangeRef }) => {
126564
126964
  const useVirtualization = !disableVirtualization;
126565
126965
  useEffect(() => {
126566
126966
  onNativeFindChanged?.(!useVirtualization);
@@ -126570,17 +126970,7 @@ var TranscriptVirtualListComponent = ({ id, listHandle, eventNodes, scrollRef, r
126570
126970
  const idx = eventNodes.findIndex((e) => e.id === initialEventId);
126571
126971
  return idx === -1 ? void 0 : idx;
126572
126972
  });
126573
- const hasToolEventsAtCurrentDepth = useCallback((startIndex) => {
126574
- const startNode = eventNodes[startIndex];
126575
- if (!startNode) return false;
126576
- for (let i = startIndex; i >= 0; i--) {
126577
- const node = eventNodes[i];
126578
- if (!node) return false;
126579
- if (node.event.event === "tool") return true;
126580
- if (node.depth < startNode.depth) return false;
126581
- }
126582
- return false;
126583
- }, [eventNodes]);
126973
+ const hasToolEventsLookup = useMemo(() => computeHasToolEventsAtDepth(eventNodes), [eventNodes]);
126584
126974
  const nonVirtualGridRef = useRef(null);
126585
126975
  useEffect(() => {
126586
126976
  if (!useVirtualization && initialEventId) (nonVirtualGridRef.current?.querySelector(`[id="${initialEventId}"]`))?.scrollIntoView({ block: "start" });
@@ -126588,7 +126978,7 @@ var TranscriptVirtualListComponent = ({ id, listHandle, eventNodes, scrollRef, r
126588
126978
  const contextMap = useMemo(() => {
126589
126979
  const map = /* @__PURE__ */ new Map();
126590
126980
  for (const [i, node] of eventNodes.entries()) {
126591
- const hasToolEvents = hasToolEventsAtCurrentDepth(i);
126981
+ const hasToolEvents = hasToolEventsLookup[i] ?? false;
126592
126982
  const turnInfo = turnMap?.get(node.id);
126593
126983
  map.set(node.id, {
126594
126984
  hasToolEvents,
@@ -126599,7 +126989,7 @@ var TranscriptVirtualListComponent = ({ id, listHandle, eventNodes, scrollRef, r
126599
126989
  return map;
126600
126990
  }, [
126601
126991
  eventNodes,
126602
- hasToolEventsAtCurrentDepth,
126992
+ hasToolEventsLookup,
126603
126993
  turnMap,
126604
126994
  eventNodeContext
126605
126995
  ]);
@@ -126648,8 +127038,18 @@ var TranscriptVirtualListComponent = ({ id, listHandle, eventNodes, scrollRef, r
126648
127038
  eventCallbacks,
126649
127039
  eventLabels
126650
127040
  ]);
126651
- const toolsRunning = useMemo(() => running === true && transcriptToolsRunning(eventNodes), [running, eventNodes]);
126652
- const components = useMemo(() => ({ Footer: ToolRunningFooter }), []);
127041
+ const isBackfilling = backfilling === true;
127042
+ const toolsRunning = useMemo(() => running === true && !isBackfilling && transcriptToolsRunning(eventNodes), [
127043
+ running,
127044
+ isBackfilling,
127045
+ eventNodes
127046
+ ]);
127047
+ const showFooter = isBackfilling || toolsRunning;
127048
+ const Footer = useCallback(() => renderTranscriptFooter({
127049
+ backfilling: isBackfilling,
127050
+ toolsRunning
127051
+ }), [isBackfilling, toolsRunning]);
127052
+ const components = useMemo(() => ({ Footer }), [Footer]);
126653
127053
  if (useVirtualization) return /* @__PURE__ */ jsx(VirtualList, {
126654
127054
  ref: listHandle,
126655
127055
  className,
@@ -126659,12 +127059,12 @@ var TranscriptVirtualListComponent = ({ id, listHandle, eventNodes, scrollRef, r
126659
127059
  initialIndex: initialEventIndex,
126660
127060
  stickyHeaderOffset: offsetTop,
126661
127061
  renderRow,
126662
- live: running,
126663
- smoothScroll: !!running,
127062
+ live: running === true,
127063
+ smoothScroll: running === true && !isBackfilling,
126664
127064
  scrollToTopOnFinish: true,
126665
127065
  itemSearchText: eventSearchText,
126666
127066
  findScope: "none",
126667
- showProgress: toolsRunning,
127067
+ showProgress: showFooter,
126668
127068
  components,
126669
127069
  onVisibleRangeChange: (range) => {
126670
127070
  if (visibleRangeRef) visibleRangeRef.current = range;
@@ -126674,13 +127074,25 @@ var TranscriptVirtualListComponent = ({ id, listHandle, eventNodes, scrollRef, r
126674
127074
  ref: nonVirtualGridRef,
126675
127075
  children: [eventNodes.map((node, index) => {
126676
127076
  return renderRow(index, node, { scrollMarginTop: offsetTop });
126677
- }), toolsRunning ? /* @__PURE__ */ jsx(ToolRunningFooter, {}) : null]
127077
+ }), renderTranscriptFooter({
127078
+ backfilling: isBackfilling,
127079
+ toolsRunning
127080
+ })]
126678
127081
  });
126679
127082
  };
126680
- var ToolRunningFooter = () => /* @__PURE__ */ jsx("div", {
126681
- className: TranscriptVirtualListComponent_module_default.runningTool,
126682
- children: /* @__PURE__ */ jsx(GeneratingIndicator, { label: "running" })
126683
- });
127083
+ var TranscriptVirtualList = memo(TranscriptVirtualListComponent);
127084
+ TranscriptVirtualList.displayName = "TranscriptVirtualList";
127085
+ var renderTranscriptFooter = ({ backfilling, toolsRunning }) => {
127086
+ if (backfilling) return /* @__PURE__ */ jsx("div", {
127087
+ className: TranscriptVirtualListComponent_module_default.runningTool,
127088
+ children: /* @__PURE__ */ jsx(LoadingEventsIndicator, { label: "Loading events" })
127089
+ });
127090
+ if (toolsRunning) return /* @__PURE__ */ jsx("div", {
127091
+ className: TranscriptVirtualListComponent_module_default.runningTool,
127092
+ children: /* @__PURE__ */ jsx(GeneratingIndicator, { label: "running" })
127093
+ });
127094
+ return null;
127095
+ };
126684
127096
  function transcriptToolsRunning(eventNodes) {
126685
127097
  let lastModelIdx = -1;
126686
127098
  for (let i = eventNodes.length - 1; i >= 0; i--) if (eventNodes[i]?.event.event === "model") {
@@ -126701,8 +127113,6 @@ function transcriptToolsRunning(eventNodes) {
126701
127113
  }
126702
127114
  //#endregion
126703
127115
  //#region ../../packages/inspect-components/src/transcript/TranscriptVirtualList.tsx
126704
- var TranscriptVirtualList = memo(TranscriptVirtualListComponent);
126705
- TranscriptVirtualList.displayName = "TranscriptVirtualList";
126706
127116
  /**
126707
127117
  * Renders the event based on its type.
126708
127118
  */
@@ -126970,7 +127380,7 @@ function scrollToEventTarget({ listHandle, index, container, targetSelector, get
126970
127380
  if (frame !== null) cancelAnimationFrame(frame);
126971
127381
  };
126972
127382
  }
126973
- var TranscriptViewNodes = forwardRef(function TranscriptViewNodes({ id, eventNodes, defaultCollapsedIds, running, scrollRef, initialEventId, initialMessageId, offsetTop = 10, className, renderAgentCard, turnMap, getEventUrl, linkingEnabled, collapsedTranscript, collapsedOutline, onCollapseTranscript, onExpandNodes, eventNodeContext }, ref) {
127383
+ var TranscriptViewNodes = forwardRef(function TranscriptViewNodes({ id, eventNodes, defaultCollapsedIds, running, backfilling, scrollRef, initialEventId, initialMessageId, offsetTop = 10, className, renderAgentCard, turnMap, getEventUrl, linkingEnabled, collapsedTranscript, collapsedOutline, onCollapseTranscript, onExpandNodes, eventNodeContext }, ref) {
126974
127384
  const listHandle = useRef(null);
126975
127385
  const getCollapsed = useCallback((nodeId) => {
126976
127386
  return (collapsedTranscript || defaultCollapsedIds)[nodeId] === true;
@@ -127159,6 +127569,7 @@ var TranscriptViewNodes = forwardRef(function TranscriptViewNodes({ id, eventNod
127159
127569
  eventNodes: flattenedNodes,
127160
127570
  scrollRef,
127161
127571
  running,
127572
+ backfilling,
127162
127573
  offsetTop,
127163
127574
  className: clsx(className),
127164
127575
  initialEventId: scrollEventId,
@@ -127222,7 +127633,7 @@ var scopeMessageLabels = (events, messageLabels) => {
127222
127633
  for (const [id, label] of Object.entries(messageLabels)) if (present.has(id)) scoped[id] = label;
127223
127634
  return Object.keys(scoped).length > 0 ? scoped : void 0;
127224
127635
  };
127225
- var TranscriptLayout = ({ events, hiddenEventTypes, running = false, scrollRef, offsetTop = 0, embedded = false, timelineSelection, activeTimeline, serverTimelines, markerConfig: markerConfigOverride, agentConfig: agentConfigOverride, showSwimlanes: showSwimlanesOption = "auto", onMarkerNavigate, onScrollToTop, headroomHidden, onHeadroomResetAnchor, onHeadroomSetHidden, listId, initialEventId, initialMessageId, eventsListRef, getEventUrl, linkingEnabled, bulkCollapse, collapseState, outline, outlineScrollRef, rightRail, rightRailPanelScrollRef, eventNodeContext, emptyText = "No events match the current filter", emptyBusy, className }) => {
127636
+ var TranscriptLayout = ({ events, hiddenEventTypes, running = false, backfilling = false, scrollRef, offsetTop = 0, embedded = false, timelineSelection, activeTimeline, serverTimelines, markerConfig: markerConfigOverride, agentConfig: agentConfigOverride, showSwimlanes: showSwimlanesOption = "auto", onMarkerNavigate, onScrollToTop, headroomHidden, onHeadroomResetAnchor, onHeadroomSetHidden, listId, initialEventId, initialMessageId, eventsListRef, getEventUrl, linkingEnabled, bulkCollapse, collapseState, outline, outlineScrollRef, rightRail, rightRailPanelScrollRef, eventNodeContext, emptyText = "No events match the current filter", emptyBusy, className }) => {
127226
127637
  const eventsForTimeline = useMemo(() => {
127227
127638
  if (!hiddenEventTypes || hiddenEventTypes.length === 0) return events;
127228
127639
  return events.filter((e) => e.event === "anchor" || !hiddenEventTypes.includes(e.event));
@@ -127665,6 +128076,7 @@ var TranscriptLayout = ({ events, hiddenEventTypes, running = false, scrollRef,
127665
128076
  scrollRef,
127666
128077
  outlineScrollEl,
127667
128078
  running,
128079
+ backfilling,
127668
128080
  agentName: outline.name ?? (showSwimlanes ? selectedRowName : void 0),
127669
128081
  scrollTrackOffset: effectiveOffsetTop,
127670
128082
  getCollapsed: collapseState?.outline ? (nodeId) => collapseState.outline?.[nodeId] === true : void 0,
@@ -127693,6 +128105,7 @@ var TranscriptLayout = ({ events, hiddenEventTypes, running = false, scrollRef,
127693
128105
  eventNodes,
127694
128106
  defaultCollapsedIds,
127695
128107
  running,
128108
+ backfilling,
127696
128109
  initialEventId: effectiveInitialEventId,
127697
128110
  initialMessageId,
127698
128111
  offsetTop: effectiveOffsetTop,
@@ -127741,7 +128154,7 @@ var createState = () => ({
127741
128154
  var insertAt = (state, index, m) => {
127742
128155
  state.messages.splice(index, 0, m);
127743
128156
  for (let i = index; i < state.messages.length; i++) {
127744
- const id = state.messages[i].id;
128157
+ const id = state.messages[i]?.id;
127745
128158
  if (id) state.positions.set(id, i);
127746
128159
  }
127747
128160
  };
@@ -127794,7 +128207,7 @@ var messagesFromEvents = (events, stateRef) => {
127794
128207
  const priorLen = state.messages.length;
127795
128208
  for (let i = startFrom; i < events.length; i++) {
127796
128209
  const e = events[i];
127797
- if (isSuccessfulModelEvent(e)) processEvent(state, e);
128210
+ if (e !== void 0 && isSuccessfulModelEvent(e)) processEvent(state, e);
127798
128211
  }
127799
128212
  state.events = events;
127800
128213
  if (!canReuse || state.messages.length !== priorLen) state.lastResult = state.messages.slice();
@@ -127846,33 +128259,34 @@ function deriveErrorType(retry) {
127846
128259
  return /^[A-Za-z_]\w*$/.test(cls) ? cls : null;
127847
128260
  }
127848
128261
  /**
127849
- * Best-effort attempt duration in seconds, derived ONLY from the event
127850
- * timestamps. `EvalRetryError` carries no top-level duration; never fabricate
127851
- * one. Returns null when it can't be computed.
128262
+ * Best-effort attempt start time the earliest event timestamp. `EvalRetryError`
128263
+ * carries no top-level timing, so the events are the only source; never
128264
+ * fabricate one. Returns null when no event carries a parseable timestamp.
127852
128265
  */
127853
- function attemptDuration(retry) {
128266
+ function attemptStartTime(retry) {
127854
128267
  const events = retry.events;
127855
128268
  if (!events || events.length === 0) return null;
127856
128269
  const times = events.map((e) => "timestamp" in e ? e.timestamp : void 0).filter((t) => typeof t === "string").map((t) => Date.parse(t)).filter((n) => Number.isFinite(n));
127857
- if (times.length < 2) return null;
127858
- const span = (Math.max(...times) - Math.min(...times)) / 1e3;
127859
- return span >= 0 ? span : null;
128270
+ if (times.length === 0) return null;
128271
+ return new Date(Math.min(...times));
127860
128272
  }
127861
128273
  var RetryAttemptCard_module_default = {
127862
- card: "_card_zuaa2_1",
127863
- cardCollapsed: "_cardCollapsed_zuaa2_11",
127864
- cardOpen: "_cardOpen_zuaa2_15",
127865
- header: "_header_zuaa2_19",
127866
- attemptLabel: "_attemptLabel_zuaa2_27",
127867
- errorChip: "_errorChip_zuaa2_34",
127868
- message: "_message_zuaa2_48",
127869
- headerRight: "_headerRight_zuaa2_59",
127870
- headerToggle: "_headerToggle_zuaa2_66",
127871
- duration: "_duration_zuaa2_70",
127872
- chevron: "_chevron_zuaa2_77",
127873
- body: "_body_zuaa2_84",
127874
- errorPanel: "_errorPanel_zuaa2_89",
127875
- ansi: "_ansi_zuaa2_93"
128274
+ card: "_card_wikv3_1",
128275
+ cardCollapsed: "_cardCollapsed_wikv3_11",
128276
+ cardOpen: "_cardOpen_wikv3_15",
128277
+ header: "_header_wikv3_19",
128278
+ attemptLabel: "_attemptLabel_wikv3_27",
128279
+ timestamp: "_timestamp_wikv3_37",
128280
+ errorChip: "_errorChip_wikv3_47",
128281
+ message: "_message_wikv3_62",
128282
+ chevron: "_chevron_wikv3_71",
128283
+ body: "_body_wikv3_80",
128284
+ dividerBand: "_dividerBand_wikv3_86",
128285
+ hairline: "_hairline_wikv3_93",
128286
+ toggle: "_toggle_wikv3_99",
128287
+ content: "_content_wikv3_104",
128288
+ errorPanel: "_errorPanel_wikv3_108",
128289
+ ansi: "_ansi_wikv3_112"
127876
128290
  };
127877
128291
  //#endregion
127878
128292
  //#region src/app/samples/retry-display/RetryAttemptCard.tsx
@@ -127887,7 +128301,7 @@ var kViewSegments = [{
127887
128301
  }];
127888
128302
  var RetryAttemptCard = ({ retry, attemptNumber, isOpen, onToggleOpen, listId, scrollRef }) => {
127889
128303
  const errorType = useMemo(() => deriveErrorType(retry), [retry]);
127890
- const durationSec = useMemo(() => attemptDuration(retry), [retry]);
128304
+ const startTime = useMemo(() => attemptStartTime(retry), [retry]);
127891
128305
  const hasEvents = !!retry.events?.length;
127892
128306
  const [view, setView] = useState("error");
127893
128307
  return /* @__PURE__ */ jsxs("div", {
@@ -127917,44 +128331,53 @@ var RetryAttemptCard = ({ retry, attemptNumber, isOpen, onToggleOpen, listId, sc
127917
128331
  className: RetryAttemptCard_module_default.message,
127918
128332
  children: retry.message
127919
128333
  }),
127920
- /* @__PURE__ */ jsxs("div", {
127921
- className: RetryAttemptCard_module_default.headerRight,
127922
- children: [
127923
- isOpen && hasEvents && /* @__PURE__ */ jsx("div", {
127924
- className: RetryAttemptCard_module_default.headerToggle,
127925
- onClick: (e) => e.stopPropagation(),
127926
- children: /* @__PURE__ */ jsx(SegmentedControl, {
127927
- segments: kViewSegments,
127928
- selectedId: view,
127929
- onSegmentChange: (id) => setView(id)
127930
- })
127931
- }),
127932
- durationSec != null && /* @__PURE__ */ jsx("span", {
127933
- className: RetryAttemptCard_module_default.duration,
127934
- children: formatTime$1(durationSec)
127935
- }),
127936
- /* @__PURE__ */ jsx("i", {
127937
- className: clsx("bi", isOpen ? "bi-chevron-down" : "bi-chevron-right", RetryAttemptCard_module_default.chevron),
127938
- "aria-hidden": "true"
127939
- })
127940
- ]
128334
+ startTime && /* @__PURE__ */ jsx("span", {
128335
+ className: RetryAttemptCard_module_default.timestamp,
128336
+ children: formatDateTime$1(startTime)
128337
+ }),
128338
+ /* @__PURE__ */ jsx("i", {
128339
+ className: clsx("bi", isOpen ? "bi-chevron-down" : "bi-chevron-right", RetryAttemptCard_module_default.chevron),
128340
+ "aria-hidden": "true"
127941
128341
  })
127942
128342
  ]
127943
- }), isOpen && /* @__PURE__ */ jsx("div", {
128343
+ }), isOpen && /* @__PURE__ */ jsxs("div", {
127944
128344
  className: RetryAttemptCard_module_default.body,
127945
- children: view === "error" || !hasEvents ? /* @__PURE__ */ jsx(ExpandablePanel, {
127946
- id: `retry-error-${listId}`,
127947
- collapse: true,
127948
- className: RetryAttemptCard_module_default.errorPanel,
127949
- children: /* @__PURE__ */ jsx(ANSIDisplay, {
127950
- output: retry.traceback_ansi,
127951
- className: RetryAttemptCard_module_default.ansi
128345
+ children: [hasEvents && /* @__PURE__ */ jsxs("div", {
128346
+ className: RetryAttemptCard_module_default.dividerBand,
128347
+ children: [
128348
+ /* @__PURE__ */ jsx("span", {
128349
+ className: RetryAttemptCard_module_default.hairline,
128350
+ "aria-hidden": "true"
128351
+ }),
128352
+ /* @__PURE__ */ jsx("div", {
128353
+ className: RetryAttemptCard_module_default.toggle,
128354
+ children: /* @__PURE__ */ jsx(SegmentedControl, {
128355
+ segments: kViewSegments,
128356
+ selectedId: view,
128357
+ onSegmentChange: (id) => setView(id)
128358
+ })
128359
+ }),
128360
+ /* @__PURE__ */ jsx("span", {
128361
+ className: RetryAttemptCard_module_default.hairline,
128362
+ "aria-hidden": "true"
128363
+ })
128364
+ ]
128365
+ }), /* @__PURE__ */ jsx("div", {
128366
+ className: RetryAttemptCard_module_default.content,
128367
+ children: view === "error" || !hasEvents ? /* @__PURE__ */ jsx(ExpandablePanel, {
128368
+ id: `retry-error-${listId}`,
128369
+ collapse: true,
128370
+ className: RetryAttemptCard_module_default.errorPanel,
128371
+ children: /* @__PURE__ */ jsx(ANSIDisplay, {
128372
+ output: retry.traceback_ansi,
128373
+ className: RetryAttemptCard_module_default.ansi
128374
+ })
128375
+ }) : /* @__PURE__ */ jsx(RetryEventsView, {
128376
+ retry,
128377
+ listId,
128378
+ scrollRef
127952
128379
  })
127953
- }) : /* @__PURE__ */ jsx(RetryEventsView, {
127954
- retry,
127955
- listId,
127956
- scrollRef
127957
- })
128380
+ })]
127958
128381
  })]
127959
128382
  });
127960
128383
  };
@@ -128019,7 +128442,7 @@ var RetryTerminalAnchor = ({ retryCount }) => {
128019
128442
  children: "This run succeeded"
128020
128443
  }), /* @__PURE__ */ jsx("span", {
128021
128444
  className: RetryTerminalAnchor_module_default.detail,
128022
- children: `after ${retriesLabel}`
128445
+ children: `after ${retriesLabel} — the sample you're viewing`
128023
128446
  })]
128024
128447
  })]
128025
128448
  });
@@ -128183,12 +128606,18 @@ function isCompleteSyntax(token) {
128183
128606
  function truncateAtWordBoundary(text, maxLength) {
128184
128607
  if (text.length <= maxLength) return text;
128185
128608
  let lastSpace = -1;
128186
- for (let i = maxLength - 1; i >= 0; i--) if (/\s/.test(text[i])) {
128187
- lastSpace = i;
128188
- break;
128609
+ for (let i = maxLength - 1; i >= 0; i--) {
128610
+ const char = text[i];
128611
+ if (char !== void 0 && /\s/.test(char)) {
128612
+ lastSpace = i;
128613
+ break;
128614
+ }
128189
128615
  }
128190
128616
  if (lastSpace > 0) return text.slice(0, lastSpace);
128191
- for (let i = maxLength - 1; i >= 0; i--) if (/[.!?,;:\-—]/.test(text[i])) return text.slice(0, i + 1);
128617
+ for (let i = maxLength - 1; i >= 0; i--) {
128618
+ const char = text[i];
128619
+ if (char !== void 0 && /[.!?,;:\-—]/.test(char)) return text.slice(0, i + 1);
128620
+ }
128192
128621
  const substr = text.slice(0, maxLength);
128193
128622
  for (const pattern of [
128194
128623
  /\[([^\]]*)?$/,
@@ -128716,9 +129145,10 @@ function useSamplesView(allColumns, options) {
128716
129145
  const seen = /* @__PURE__ */ new Set();
128717
129146
  const nextColumns = [];
128718
129147
  for (const c of view.columns) {
128719
- nextColumns.push(c.id in visibility ? {
129148
+ const nextVisible = visibility[c.id];
129149
+ nextColumns.push(nextVisible !== void 0 ? {
128720
129150
  id: c.id,
128721
- visible: visibility[c.id]
129151
+ visible: nextVisible
128722
129152
  } : c);
128723
129153
  seen.add(c.id);
128724
129154
  }
@@ -132381,7 +132811,10 @@ var useTranscriptFilter = () => {
132381
132811
  }
132382
132812
  const arrangedKeys = [];
132383
132813
  const maxItemsInColumn = Math.max(...columnArrays.map((col) => col.length));
132384
- for (let row = 0; row < maxItemsInColumn; row++) for (let col = 0; col < columns; col++) if (row < columnArrays[col].length) arrangedKeys.push(columnArrays[col][row]);
132814
+ for (let row = 0; row < maxItemsInColumn; row++) for (let col = 0; col < columns; col++) {
132815
+ const item = columnArrays[col]?.[row];
132816
+ if (item !== void 0) arrangedKeys.push(item);
132817
+ }
132385
132818
  return arrangedKeys;
132386
132819
  }, [])
132387
132820
  };
@@ -132688,7 +133121,7 @@ var TranscriptFilterPopover = ({ showing, positionEl, setShowing }) => {
132688
133121
  * when the sample provides timeline data.
132689
133122
  */
132690
133123
  var TranscriptPanel = memo((props) => {
132691
- const { id, scrollRef, events, running, initialEventId, initialMessageId, offsetTop, timelines: serverTimelines, eventNodeContext, rightRail, rightRailPanelScrollRef } = props;
133124
+ const { id, scrollRef, events, running, backfilling, initialEventId, initialMessageId, offsetTop, timelines: serverTimelines, eventNodeContext, rightRail, rightRailPanelScrollRef } = props;
132692
133125
  const filteredEventTypes = useStore((state) => state.sample.eventFilter.filteredTypes);
132693
133126
  const { isDefaultFilter } = useTranscriptFilter();
132694
133127
  const timelineSelected = useStore((state) => state.sample.timelineSelected);
@@ -132802,6 +133235,7 @@ var TranscriptPanel = memo((props) => {
132802
133235
  events,
132803
133236
  hiddenEventTypes: filteredEventTypes,
132804
133237
  running,
133238
+ backfilling,
132805
133239
  scrollRef,
132806
133240
  offsetTop,
132807
133241
  timelineSelection,
@@ -132834,8 +133268,8 @@ var TranscriptPanel = memo((props) => {
132834
133268
  selectedId: selectedOutlineId,
132835
133269
  setSelectedId: setSelectedOutlineId
132836
133270
  },
132837
- emptyText: running && isDefaultFilter ? "Sample is starting" : filteredEventTypes.length > 0 ? "The currently applied filter hides all events." : void 0,
132838
- emptyBusy: running && isDefaultFilter
133271
+ emptyText: backfilling && isDefaultFilter ? "Loading events" : running && isDefaultFilter ? "Sample is starting" : filteredEventTypes.length > 0 ? "The currently applied filter hides all events." : void 0,
133272
+ emptyBusy: (running || backfilling) && isDefaultFilter
132839
133273
  });
132840
133274
  });
132841
133275
  TranscriptPanel.displayName = "TranscriptPanel";
@@ -132853,6 +133287,7 @@ var SampleDisplay = ({ id, scrollRef, showActivity, progress, focusOnLoad }) =>
132853
133287
  }, [sampleData]);
132854
133288
  const eventsCleared = sampleData.eventsCleared;
132855
133289
  const runningSampleData = sampleData.running;
133290
+ const backfilling = sampleData.backfilling;
132856
133291
  const evalSpec = useStore((state) => state.log.selectedLogDetails?.eval);
132857
133292
  const { setDocumentTitle } = useDocumentTitle();
132858
133293
  useEffect(() => {
@@ -133264,6 +133699,7 @@ var SampleDisplay = ({ id, scrollRef, showActivity, progress, focusOnLoad }) =>
133264
133699
  scrollRef,
133265
133700
  offsetTop: stickyOffsetTop,
133266
133701
  running,
133702
+ backfilling,
133267
133703
  events: sampleEvents,
133268
133704
  timelines: sample?.timelines ?? void 0,
133269
133705
  eventNodeContext: transcriptEventNodeContext,
@@ -133302,6 +133738,7 @@ var SampleDisplay = ({ id, scrollRef, showActivity, progress, focusOnLoad }) =>
133302
133738
  scrollRef,
133303
133739
  tools: chatTools,
133304
133740
  running,
133741
+ backfilling,
133305
133742
  className: SampleDisplay_module_default.fullWidth
133306
133743
  }, `${baseId}-chat-${id}`)
133307
133744
  })
@@ -133735,6 +134172,7 @@ var SampleDetailComponent = ({ sampleId, epoch, tabId, navigation, navbarConfig
133735
134172
  */
133736
134173
  var LogSampleDetailView = () => {
133737
134174
  const { logPath: routeLogPath, sampleId: routeSampleId, epoch: routeEpoch, sampleTabId, sampleUuid } = useLogRouteParams();
134175
+ useClearStaleLogStateOnNav(routeLogPath);
133738
134176
  useLoadSample();
133739
134177
  usePollSample();
133740
134178
  const navigate = useNavigate();
@@ -133809,22 +134247,6 @@ var LogSampleDetailView = () => {
133809
134247
  });
133810
134248
  };
133811
134249
  //#endregion
133812
- //#region src/state/log.ts
133813
- var useUnloadLog = () => {
133814
- const clearSelectedLogDetails = useStore((state) => state.logActions.clearSelectedLogDetails);
133815
- const clearSelectedLogFile = useStore((state) => state.logsActions.clearSelectedLogFile);
133816
- const clearLog = useStore((state) => state.logActions.clearLog);
133817
- return { unloadLog: useCallback(() => {
133818
- clearSelectedLogDetails();
133819
- clearSelectedLogFile();
133820
- clearLog();
133821
- }, [
133822
- clearLog,
133823
- clearSelectedLogDetails,
133824
- clearSelectedLogFile
133825
- ]) };
133826
- };
133827
- //#endregion
133828
134250
  //#region src/app/routing/logNavigation.ts
133829
134251
  var useLogNavigation = () => {
133830
134252
  const navigate = useNavigate();
@@ -134273,7 +134695,8 @@ function unwrapFastapiDetail(body) {
134273
134695
  } catch {}
134274
134696
  return body;
134275
134697
  }
134276
- function serverRequestApi(baseUrl, getHeaders) {
134698
+ function serverRequestApi(baseUrl, getHeaders, customFetch) {
134699
+ const fetchFn = customFetch ?? fetch;
134277
134700
  const apiUrl = baseUrl || "";
134278
134701
  function addViewRequestHeader(method, headers) {
134279
134702
  if (method !== "GET") headers[VIEW_REQUEST_HEADER] = VIEW_REQUEST_HEADER_VALUE;
@@ -134304,7 +134727,7 @@ function serverRequestApi(baseUrl, getHeaders) {
134304
134727
  }
134305
134728
  if (request.body) responseHeaders["Content-Type"] = "application/json";
134306
134729
  addViewRequestHeader(method, responseHeaders);
134307
- const response = await fetch(url, {
134730
+ const response = await fetchFn(url, {
134308
134731
  method,
134309
134732
  headers: responseHeaders,
134310
134733
  body: request.body,
@@ -134340,7 +134763,7 @@ function serverRequestApi(baseUrl, getHeaders) {
134340
134763
  }
134341
134764
  if (body) requestHeaders["Content-Type"] = "application/json";
134342
134765
  addViewRequestHeader(method, requestHeaders);
134343
- const response = await fetch(url, {
134766
+ const response = await fetchFn(url, {
134344
134767
  method,
134345
134768
  headers: requestHeaders,
134346
134769
  body,
@@ -134369,7 +134792,7 @@ function serverRequestApi(baseUrl, getHeaders) {
134369
134792
  Object.assign(headers, globalHeaders);
134370
134793
  }
134371
134794
  addViewRequestHeader(method, headers);
134372
- const response = await fetch(url, {
134795
+ const response = await fetchFn(url, {
134373
134796
  method,
134374
134797
  headers,
134375
134798
  credentials: isApiCrossOrigin() ? "include" : "same-origin"
@@ -134934,20 +135357,23 @@ var PlanDetailView = ({ evaluation, plan, scores }) => {
134934
135357
  });
134935
135358
  if (scores) {
134936
135359
  const scorers = scores.reduce((accum, score) => {
134937
- if (!accum[score.scorer]) accum[score.scorer] = {
135360
+ const existing = accum[score.scorer];
135361
+ if (existing === void 0) accum[score.scorer] = {
134938
135362
  scores: [score.name],
134939
135363
  params: score.params
134940
135364
  };
134941
- else accum[score.scorer].scores.push(score.name);
135365
+ else existing.scores.push(score.name);
134942
135366
  return accum;
134943
135367
  }, {});
134944
135368
  if (Object.keys(scorers).length > 0) {
134945
135369
  const label = Object.keys(scorers).length === 1 ? "Scorer" : "Scorers";
134946
135370
  const scorerPanels = Object.keys(scorers).map((key) => {
135371
+ const scorer = scorers[key];
135372
+ if (scorer === void 0) return null;
134947
135373
  return /* @__PURE__ */ jsx(ScorerDetailView, {
134948
135374
  name: key,
134949
- scores: scorers[key].scores,
134950
- params: scorers[key].params
135375
+ scores: scorer.scores,
135376
+ params: scorer.params
134951
135377
  }, key);
134952
135378
  });
134953
135379
  taskColumns.push({
@@ -135514,6 +135940,7 @@ var SampleList = memo((props) => {
135514
135940
  listHandle.current?.api?.ensureIndexVisible(0, "top");
135515
135941
  }, [listHandle, useStore((state) => state.logs.selectedLogFile)]);
135516
135942
  const sampleNavigation = useSampleNavigation();
135943
+ const { sampleId: routeSampleId, epoch: routeEpoch } = useLogRouteParams();
135517
135944
  const selectedSampleHandle = useStore((state) => state.log.selectedSampleHandle);
135518
135945
  const evalSpec = useStore((state) => state.log.selectedLogDetails)?.eval;
135519
135946
  const { setDocumentTitle } = useDocumentTitle();
@@ -135523,9 +135950,16 @@ var SampleList = memo((props) => {
135523
135950
  const handleRowOpen = useCallback((row, opts) => {
135524
135951
  if (opts.newWindow) {
135525
135952
  const url = sampleNavigation.getSampleUrl(row.sampleId, row.epoch);
135526
- if (url) window.open(url, "_blank");
135527
- } else sampleNavigation.showSample(row.sampleId, row.epoch);
135528
- }, [sampleNavigation]);
135953
+ if (url) openInNewTab(url);
135954
+ } else {
135955
+ if (isSampleOpenInRoute(routeSampleId, routeEpoch, row.sampleId, row.epoch)) return;
135956
+ sampleNavigation.showSample(row.sampleId, row.epoch);
135957
+ }
135958
+ }, [
135959
+ sampleNavigation,
135960
+ routeSampleId,
135961
+ routeEpoch
135962
+ ]);
135529
135963
  const getRowId = useCallback((params) => makeSampleRowId(params.data.sampleId, params.data.epoch), []);
135530
135964
  const selectedRowId = selectedSampleHandle ? makeSampleRowId(selectedSampleHandle.id, selectedSampleHandle.epoch) : void 0;
135531
135965
  const handleStateUpdated = useCallback((state) => {
@@ -135536,8 +135970,12 @@ var SampleList = memo((props) => {
135536
135970
  }, [onFilterChanged]);
135537
135971
  const sampleCount = items.length;
135538
135972
  const warnings = useMemo(() => {
135539
- const errorCount = items.reduce((prev, item) => item.error || item.data?.error ? prev + 1 : prev, 0);
135540
- const limitCount = items.reduce((prev, item) => item.limit || item.data?.limit ? prev + 1 : prev, 0);
135973
+ let errorCount = 0;
135974
+ let limitCount = 0;
135975
+ for (const item of items) {
135976
+ if (item.error || item.data?.error) errorCount += 1;
135977
+ if (item.limit || item.data?.limit) limitCount += 1;
135978
+ }
135541
135979
  const percentError = sampleCount > 0 ? errorCount / sampleCount * 100 : 0;
135542
135980
  const percentLimit = sampleCount > 0 ? limitCount / sampleCount * 100 : 0;
135543
135981
  const result = [];
@@ -135562,11 +136000,11 @@ var SampleList = memo((props) => {
135562
136000
  return /* @__PURE__ */ jsxs("div", {
135563
136001
  className: SampleList_module_default.mainLayout,
135564
136002
  children: [
135565
- warnings.map((warning, index) => /* @__PURE__ */ jsx(MessageBand, {
135566
- id: `sample-warning-message-${index}`,
136003
+ warnings.map((warning) => /* @__PURE__ */ jsx(MessageBand, {
136004
+ id: `sample-warning-message-${warning.type}-${warning.msg}`,
135567
136005
  message: warning.msg,
135568
136006
  type: warning.type
135569
- }, `sample-warning-message-${index}`)),
136007
+ }, `sample-warning-message-${warning.type}-${warning.msg}`)),
135570
136008
  /* @__PURE__ */ jsx(SamplesGrid, {
135571
136009
  rowData: items,
135572
136010
  columnDefs: columns,
@@ -150106,7 +150544,7 @@ function getStyleTags(node) {
150106
150544
  return rule || null;
150107
150545
  }
150108
150546
  var t = Tag.define;
150109
- var comment = t(), name = t(), typeName = t(name), propertyName = t(name), literal = t(), string = t(literal), number = t(literal), content = t(), heading = t(content), keyword = t(), operator = t(), punctuation = t(), bracket = t(punctuation), meta = t();
150547
+ var comment = t(), name = t(), typeName = t(name), propertyName = t(name), literal = t(), string = t(literal), number = t(literal), content = t(), heading$1 = t(content), keyword = t(), operator = t(), punctuation = t(), bracket = t(punctuation), meta = t();
150110
150548
  /**
150111
150549
  The default set of highlighting [tags](#highlight.Tag).
150112
150550
 
@@ -150359,31 +150797,31 @@ var tags = {
150359
150797
  /**
150360
150798
  [Content](#highlight.tags.content) that represents a heading.
150361
150799
  */
150362
- heading,
150800
+ heading: heading$1,
150363
150801
  /**
150364
150802
  A level 1 [heading](#highlight.tags.heading).
150365
150803
  */
150366
- heading1: t(heading),
150804
+ heading1: t(heading$1),
150367
150805
  /**
150368
150806
  A level 2 [heading](#highlight.tags.heading).
150369
150807
  */
150370
- heading2: t(heading),
150808
+ heading2: t(heading$1),
150371
150809
  /**
150372
150810
  A level 3 [heading](#highlight.tags.heading).
150373
150811
  */
150374
- heading3: t(heading),
150812
+ heading3: t(heading$1),
150375
150813
  /**
150376
150814
  A level 4 [heading](#highlight.tags.heading).
150377
150815
  */
150378
- heading4: t(heading),
150816
+ heading4: t(heading$1),
150379
150817
  /**
150380
150818
  A level 5 [heading](#highlight.tags.heading).
150381
150819
  */
150382
- heading5: t(heading),
150820
+ heading5: t(heading$1),
150383
150821
  /**
150384
150822
  A level 6 [heading](#highlight.tags.heading).
150385
150823
  */
150386
- heading6: t(heading),
150824
+ heading6: t(heading$1),
150387
150825
  /**
150388
150826
  A prose [content](#highlight.tags.content) separator (such as a horizontal rule).
150389
150827
  */
@@ -157840,7 +158278,8 @@ var SelectScorer = ({ scores, selectedScores, setSelectedScores }) => {
157840
158278
  /* @__PURE__ */ jsx("a", {
157841
158279
  className: clsx(SelectScorer_module_default.link, !allScoresSelected ? SelectScorer_module_default.selected : void 0),
157842
158280
  onClick: () => {
157843
- if (scores.length > 0) setSelectedScores([scores[0]]);
158281
+ const firstScore = scores[0];
158282
+ if (firstScore !== void 0) setSelectedScores([firstScore]);
157844
158283
  },
157845
158284
  children: "Default"
157846
158285
  }),
@@ -158536,7 +158975,7 @@ var columnFilterToFiltrex = (mapping, filter) => {
158536
158975
  if (filter.operator === "OR") return null;
158537
158976
  const parts = conditions.map((c) => conditionToFiltrex(mapping, c)).filter((p) => p !== null);
158538
158977
  if (parts.length === 0) return null;
158539
- if (parts.length === 1) return parts[0];
158978
+ if (parts.length === 1) return parts[0] ?? null;
158540
158979
  return `(${parts.join(" and ")})`;
158541
158980
  }
158542
158981
  return conditionToFiltrex(mapping, filter);
@@ -158568,7 +159007,7 @@ var filterModelToText = (model, registry) => {
158568
159007
  if (text === null) return null;
158569
159008
  parts.push(text);
158570
159009
  }
158571
- if (parts.length === 1) return parts[0];
159010
+ if (parts.length === 1) return parts[0] ?? null;
158572
159011
  return parts.join(" and ");
158573
159012
  };
158574
159013
  //#endregion
@@ -159112,7 +159551,8 @@ function buildScoreColumns(ctx) {
159112
159551
  }
159113
159552
  }
159114
159553
  return Object.keys(types).sort((a, b) => a.localeCompare(b)).map((name) => {
159115
- const isUniformNumber = types[name].size === 1 && types[name].has("number");
159554
+ const nameTypes = types[name];
159555
+ const isUniformNumber = nameTypes?.size === 1 && nameTypes.has("number");
159116
159556
  const compactWidth = isUniformNumber ? 40 : 55;
159117
159557
  const cellStyle = cellStyleFor(name, ranges[name] ?? {});
159118
159558
  const headerCols = compactScores ? {
@@ -159514,10 +159954,8 @@ var SamplesTab = ({ running, scrollRef, showColumnSelector, setShowColumnSelecto
159514
159954
  selectedLogFile
159515
159955
  ]);
159516
159956
  useEffect(() => {
159517
- if (sampleSummaries.length === 1 && selectedLogFile) {
159518
- const sample = sampleSummaries[0];
159519
- selectSample(sample.id, sample.epoch, selectedLogFile);
159520
- }
159957
+ const sample = sampleSummaries.length === 1 ? sampleSummaries[0] : void 0;
159958
+ if (sample && selectedLogFile) selectSample(sample.id, sample.epoch, selectedLogFile);
159521
159959
  }, [
159522
159960
  sampleSummaries,
159523
159961
  selectSample,
@@ -160151,8 +160589,7 @@ var toDisplayScorers = (scores) => {
160151
160589
  return {
160152
160590
  scorer: score.name,
160153
160591
  reducer: score.reducer === null ? void 0 : score.reducer,
160154
- metrics: Object.keys(score.metrics).map((key) => {
160155
- const metric = score.metrics[key];
160592
+ metrics: Object.values(score.metrics).map((metric) => {
160156
160593
  return {
160157
160594
  name: metric.name,
160158
160595
  group: metric.group,
@@ -160501,16 +160938,17 @@ var ResultsPanel = ({ scorers }) => {
160501
160938
  const [showing, setShowing] = useProperty("results-panel-metrics", "modal-showing", { defaultValue: false });
160502
160939
  if (!scorers || scorers.length === 0) return;
160503
160940
  const expandedScorers = expandGroupedMetrics(scorers);
160504
- if (expandedScorers.length === 1) {
160505
- const showReducer = !!expandedScorers[0].reducer;
160506
- const metrics = expandedScorers[0].metrics;
160507
- const unscoredSamples = expandedScorers[0].unscoredSamples || 0;
160508
- const scoredSamples = expandedScorers[0].scoredSamples || 0;
160941
+ const onlyScorer = expandedScorers.length === 1 ? expandedScorers[0] : void 0;
160942
+ if (onlyScorer) {
160943
+ const showReducer = !!onlyScorer.reducer;
160944
+ const metrics = onlyScorer.metrics;
160945
+ const unscoredSamples = onlyScorer.unscoredSamples || 0;
160946
+ const scoredSamples = onlyScorer.scoredSamples || 0;
160509
160947
  return /* @__PURE__ */ jsx("div", {
160510
160948
  className: ResultsPanel_module_default.simpleMetricsRows,
160511
160949
  children: metrics.map((metric, i) => {
160512
160950
  return /* @__PURE__ */ jsx(VerticalMetric, {
160513
- reducer: expandedScorers[0].reducer,
160951
+ reducer: onlyScorer.reducer,
160514
160952
  metric,
160515
160953
  isFirst: i === 0,
160516
160954
  showReducer,
@@ -160787,7 +161225,7 @@ var ModelRolesView = ({ roles }) => {
160787
161225
  const singleLine = Object.keys(modelRoles).length !== 1;
160788
161226
  const modelEls = Object.keys(modelRoles).map((key) => {
160789
161227
  const role = key;
160790
- const model = modelRoles[role].model;
161228
+ const model = modelRoles[role]?.model;
160791
161229
  return /* @__PURE__ */ jsxs("div", {
160792
161230
  className: clsx(singleLine ? ModelRolesView_module_default.grid : void 0, "text-style-secondary", "text-size-smallest"),
160793
161231
  children: [/* @__PURE__ */ jsxs("span", {
@@ -161172,6 +161610,7 @@ var LogView = () => {
161172
161610
  const refreshLog = useRefreshLog();
161173
161611
  const navigation = useLogNavigation();
161174
161612
  const selectedLogDetails = useStore((state) => state.log.selectedLogDetails);
161613
+ const loading = useStore((state) => state.app.status.loading);
161175
161614
  const evalSpec = useEvalSpec();
161176
161615
  const runningMetrics = useStore((state) => state.log.pendingSampleSummaries?.metrics);
161177
161616
  const samplesTabConfig = useSamplesTabConfig(selectedLogDetails?.status, refreshLog);
@@ -161191,7 +161630,7 @@ var LogView = () => {
161191
161630
  const { hidden: titleCollapsed } = useScrollDirection(useMemo(() => {
161192
161631
  const refs = [];
161193
161632
  for (const key of Object.keys(tabs)) {
161194
- const ref = tabs[key].scrollRef;
161633
+ const ref = tabs[key]?.scrollRef;
161195
161634
  if (ref) refs.push(ref);
161196
161635
  }
161197
161636
  return refs;
@@ -161205,11 +161644,12 @@ var LogView = () => {
161205
161644
  navigation.selectTab(id);
161206
161645
  }
161207
161646
  }, [setSelectedTab, navigation]);
161208
- if (evalSpec === void 0) return /* @__PURE__ */ jsx(EmptyPanel, {});
161647
+ if (evalSpec === void 0) return /* @__PURE__ */ jsx(EmptyPanel, { children: loading > 0 ? /* @__PURE__ */ jsx(PulsingDots, {
161648
+ size: "large",
161649
+ text: "Loading log…"
161650
+ }) : null });
161209
161651
  else {
161210
- const tabTools = Object.keys(tabs).map((key) => {
161211
- return tabs[key];
161212
- }).filter((tab) => {
161652
+ const tabTools = Object.values(tabs).filter((tab) => tab !== void 0).filter((tab) => {
161213
161653
  return tab.id === selectedTab;
161214
161654
  }).map((tab) => {
161215
161655
  if (tab.tools) return tab.tools();
@@ -161238,6 +161678,7 @@ var LogView = () => {
161238
161678
  tabPanelsClassName: clsx(LogView_module_default.tabPanels),
161239
161679
  children: Object.keys(tabs).map((key) => {
161240
161680
  const tab = tabs[key];
161681
+ if (tab === void 0) return null;
161241
161682
  return /* @__PURE__ */ jsx(TabPanel, {
161242
161683
  id: tab.id,
161243
161684
  title: tab.label,
@@ -161322,8 +161763,6 @@ var LogViewContainer = () => {
161322
161763
  const evalSpec = useEvalSpec();
161323
161764
  const setWorkspaceTab = useStore((state) => state.appActions.setWorkspaceTab);
161324
161765
  const setSelectedLogFile = useStore((state) => state.logsActions.setSelectedLogFile);
161325
- const clearSelectedLogSummary = useStore((state) => state.logActions.clearSelectedLogDetails);
161326
- const clearSelectedSample = useStore((state) => state.sampleActions.clearSelectedSample);
161327
161766
  const navigate = useNavigate();
161328
161767
  const prefix = useLocation().pathname.startsWith("/tasks/") ? "/tasks" : "/logs";
161329
161768
  const sampleSummaries = useSampleSummaries();
@@ -161365,21 +161804,9 @@ var LogViewContainer = () => {
161365
161804
  navigate,
161366
161805
  prefix
161367
161806
  ]);
161368
- const prevLogPathRef = useRef(void 0);
161369
161807
  const syncLogs = useStore((state) => state.logsActions.syncLogs);
161370
161808
  const initLogDir = useStore((state) => state.logsActions.initLogDir);
161371
- useLayoutEffect(() => {
161372
- const prevLogPath = prevLogPathRef.current;
161373
- prevLogPathRef.current = logPath;
161374
- if (prevLogPath && logPath && logPath !== prevLogPath) {
161375
- clearSelectedSample();
161376
- clearSelectedLogSummary();
161377
- }
161378
- }, [
161379
- logPath,
161380
- clearSelectedSample,
161381
- clearSelectedLogSummary
161382
- ]);
161809
+ useClearStaleLogStateOnNav(logPath);
161383
161810
  useEffect(() => {
161384
161811
  if (!logPath) return;
161385
161812
  setWorkspaceTab(tabId ?? "samples");
@@ -161443,33 +161870,39 @@ var FlowPanel = () => {
161443
161870
  })]
161444
161871
  });
161445
161872
  };
161446
- //#endregion
161447
- //#region src/app/utils/print.ts
161448
- /**
161449
- * Generates an HTML string that displays the task title, model, and creation time in a styled grid layout.
161450
- *
161451
- * The task title, model, and creation time are retrieved from the elements with the IDs 'task-title',
161452
- * 'task-model', and 'task-created', respectively. The generated HTML will display these elements in a
161453
- * three-column grid with custom styling.
161454
- *
161455
- * @example
161456
- * // Example usage:
161457
- * const headingHtml = printHeadingHtml();
161458
- * console.log(headingHtml);
161459
- */
161460
- var printHeadingHtml = (evalSpec) => {
161461
- return `
161462
- <div style="display: grid; grid-template-columns: repeat(3, 1fr); column-gap: 0.5em; margin-bottom: 2em; justify-content: space-between; border-bottom: solid 1px silver;">
161463
- <div style="font-weight: 600">${evalSpec?.task || "Unknown Task"}</div>
161464
- <div style="text-align: center;">${evalSpec?.model || "Unknown Model"}</div>
161465
- <div style="text-align: right;">${evalSpec?.created ? new Date(evalSpec.created).toLocaleString() : "Unknown Time"}</div>
161466
- </div>`;
161467
- };
161468
161873
  var SamplePrintView_module_default = {
161469
- container: "_container_15zex_1",
161470
- loading: "_loading_15zex_5",
161471
- header: "_header_15zex_14",
161472
- sampleInfo: "_sampleInfo_15zex_18"
161874
+ container: "_container_9l9dc_1",
161875
+ loading: "_loading_9l9dc_5",
161876
+ header: "_header_9l9dc_14",
161877
+ heading: "_heading_9l9dc_18",
161878
+ headingTask: "_headingTask_9l9dc_27",
161879
+ headingModel: "_headingModel_9l9dc_31",
161880
+ headingTime: "_headingTime_9l9dc_35",
161881
+ sampleInfo: "_sampleInfo_9l9dc_39"
161882
+ };
161883
+ //#endregion
161884
+ //#region src/app/samples/print/PrintHeading.tsx
161885
+ var PrintHeading = ({ evalSpec }) => {
161886
+ const task = evalSpec?.task || "Unknown Task";
161887
+ const model = evalSpec?.model || "Unknown Model";
161888
+ const time = evalSpec?.created ? new Date(evalSpec.created).toLocaleString() : "Unknown Time";
161889
+ return /* @__PURE__ */ jsxs("div", {
161890
+ className: SamplePrintView_module_default.heading,
161891
+ children: [
161892
+ /* @__PURE__ */ jsx("div", {
161893
+ className: SamplePrintView_module_default.headingTask,
161894
+ children: task
161895
+ }),
161896
+ /* @__PURE__ */ jsx("div", {
161897
+ className: SamplePrintView_module_default.headingModel,
161898
+ children: model
161899
+ }),
161900
+ /* @__PURE__ */ jsx("div", {
161901
+ className: SamplePrintView_module_default.headingTime,
161902
+ children: time
161903
+ })
161904
+ ]
161905
+ });
161473
161906
  };
161474
161907
  //#endregion
161475
161908
  //#region src/app/samples/print/SamplePrintView.tsx
@@ -161554,14 +161987,13 @@ var SamplePrintView = () => {
161554
161987
  })
161555
161988
  });
161556
161989
  const sampleMessages = sample.messages || [];
161557
- const headingHtml = printHeadingHtml(evalSpec);
161558
161990
  return /* @__PURE__ */ jsxs("div", {
161559
161991
  className: SamplePrintView_module_default.container,
161560
161992
  ref: contentRef,
161561
161993
  children: [
161562
161994
  /* @__PURE__ */ jsxs("div", {
161563
161995
  className: SamplePrintView_module_default.header,
161564
- children: [/* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: headingHtml } }), sampleId && epoch && /* @__PURE__ */ jsxs("div", {
161996
+ children: [/* @__PURE__ */ jsx(PrintHeading, { evalSpec }), sampleId && epoch && /* @__PURE__ */ jsxs("div", {
161565
161997
  className: SamplePrintView_module_default.sampleInfo,
161566
161998
  children: [
161567
161999
  "Sample ",
@@ -164180,6 +164612,72 @@ var openRemoteLogFile = async (api, url, concurrency) => {
164180
164612
  }
164181
164613
  };
164182
164614
  };
164615
+ var DirectFetchError = class extends Error {
164616
+ constructor(message, options) {
164617
+ super(message, options);
164618
+ this.name = "DirectFetchError";
164619
+ }
164620
+ };
164621
+ /**
164622
+ * Fetch one chunk of pending-sample data via presigned S3 URLs.
164623
+ * Returns `undefined` when this transport isn't supported (404, or any
164624
+ * segment lacks a presigned URL); all other failures throw.
164625
+ */
164626
+ var fetchPendingSampleDataDirect = async (getUrls, log_file, id, epoch, cursors) => {
164627
+ let urls;
164628
+ try {
164629
+ urls = await getUrls(log_file, id, epoch, cursors.last_event, cursors.last_attachment, cursors.last_message_pool, cursors.last_call_pool, 100);
164630
+ } catch (e) {
164631
+ if (e instanceof ApiError && e.status === 404) return;
164632
+ throw e;
164633
+ }
164634
+ if (urls.segments.length === 0) return {
164635
+ sampleData: {
164636
+ events: [],
164637
+ attachments: [],
164638
+ message_pool: [],
164639
+ call_pool: []
164640
+ },
164641
+ has_more: urls.has_more === true,
164642
+ complete: urls.complete === true
164643
+ };
164644
+ if (!urls.segments.every((s) => s.direct_url != null)) return;
164645
+ const parts = await Promise.all(urls.segments.map((seg) => readSegment(seg)));
164646
+ return {
164647
+ sampleData: applyCursorFilter({
164648
+ events: parts.flatMap((p) => p.events),
164649
+ attachments: parts.flatMap((p) => p.attachments),
164650
+ message_pool: parts.flatMap((p) => p.message_pool),
164651
+ call_pool: parts.flatMap((p) => p.call_pool)
164652
+ }, cursors),
164653
+ has_more: urls.has_more === true,
164654
+ complete: urls.complete === true
164655
+ };
164656
+ };
164657
+ var readSegment = async (seg) => {
164658
+ const url = seg.direct_url;
164659
+ let bytes;
164660
+ try {
164661
+ const resp = await fetch(url);
164662
+ if (!resp.ok) throw new DirectFetchError(`Failed to fetch segment: ${resp.status} ${resp.statusText}`);
164663
+ bytes = new Uint8Array(await resp.arrayBuffer());
164664
+ } catch (e) {
164665
+ if (e instanceof DirectFetchError) throw e;
164666
+ throw new DirectFetchError(`Failed to fetch segment: ${String(e)}`, { cause: e });
164667
+ }
164668
+ return await asyncJsonParseBytes(await (await openZipFileFromBuffer(bytes)).readFile(seg.member_name));
164669
+ };
164670
+ var applyCursorFilter = (out, cursors) => {
164671
+ const lastEvent = cursors.last_event ?? -1;
164672
+ const lastAttachment = cursors.last_attachment ?? -1;
164673
+ const lastMessagePool = cursors.last_message_pool ?? -1;
164674
+ const lastCallPool = cursors.last_call_pool ?? -1;
164675
+ out.events = out.events.filter((e) => e.id > lastEvent);
164676
+ out.attachments = out.attachments.filter((a) => a.id > lastAttachment);
164677
+ out.message_pool = out.message_pool.filter((m) => m.id > lastMessagePool);
164678
+ out.call_pool = out.call_pool.filter((c) => c.id > lastCallPool);
164679
+ return out;
164680
+ };
164183
164681
  //#endregion
164184
164682
  //#region src/client/api/client-api.ts
164185
164683
  var isEvalFile = (file) => {
@@ -164379,24 +164877,34 @@ var clientApi = (api, log_file, debug = false) => {
164379
164877
  const editEtagByLog = /* @__PURE__ */ new Map();
164380
164878
  const get_log_sample_data = async (log_file, id, epoch, last_event, last_attachment, last_message_pool, last_call_pool) => {
164381
164879
  if (!api.eval_log_sample_data) throw new Error("API doesn't supported streamed sample data");
164880
+ const fetchViaProxy = () => api.eval_log_sample_data(log_file, id, epoch, last_event, last_attachment, last_message_pool, last_call_pool);
164881
+ const fallBackToProxy = (e) => {
164882
+ if (!(e instanceof DirectFetchError)) throw e;
164883
+ sampleDataPathByLog.set(log_file, "proxy");
164884
+ return fetchViaProxy();
164885
+ };
164382
164886
  let path = sampleDataPathByLog.get(log_file);
164383
- if (path === void 0 && api.eval_log_sample_data_direct) {
164887
+ if (path === void 0 && api.eval_log_sample_data_direct) try {
164384
164888
  const probe = await api.eval_log_sample_data_direct(log_file, id, epoch, last_event, last_attachment, last_message_pool, last_call_pool);
164385
164889
  if (probe !== void 0) {
164386
164890
  sampleDataPathByLog.set(log_file, "direct");
164387
164891
  return probe;
164388
164892
  }
164893
+ } catch (e) {
164894
+ return fallBackToProxy(e);
164389
164895
  }
164390
164896
  if (path === void 0) {
164391
164897
  path = "proxy";
164392
164898
  sampleDataPathByLog.set(log_file, path);
164393
164899
  }
164394
- if (path === "direct") {
164900
+ if (path === "direct") try {
164395
164901
  const result = await api.eval_log_sample_data_direct(log_file, id, epoch, last_event, last_attachment, last_message_pool, last_call_pool);
164396
164902
  if (result === void 0) throw new Error("Direct pending-sample-data path returned 'not supported' after probe");
164397
164903
  return result;
164904
+ } catch (e) {
164905
+ return fallBackToProxy(e);
164398
164906
  }
164399
- return api.eval_log_sample_data(log_file, id, epoch, last_event, last_attachment, last_message_pool, last_call_pool);
164907
+ return fetchViaProxy();
164400
164908
  };
164401
164909
  const middleware = debug ? createMiddlewareWrapper([debugMiddleware]) : (_name, fn) => fn;
164402
164910
  return {
@@ -164642,11 +165150,11 @@ function staticHttpApiForLog(logInfo) {
164642
165150
  if (log_dir) {
164643
165151
  const manifest = await getManifest();
164644
165152
  if (manifest) {
164645
- const logs = Object.keys(manifest).map((key) => {
165153
+ const logs = Object.entries(manifest).map(([key, preview]) => {
164646
165154
  return {
164647
165155
  name: joinURI(log_dir, key),
164648
- task: manifest[key].task,
164649
- task_id: manifest[key].task_id
165156
+ task: preview.task,
165157
+ task_id: preview.task_id
164650
165158
  };
164651
165159
  });
164652
165160
  return Promise.resolve({
@@ -164697,8 +165205,8 @@ function staticHttpApiForLog(logInfo) {
164697
165205
  const manifest = await getManifest();
164698
165206
  if (manifest) {
164699
165207
  const manifestAbs = {};
164700
- Object.keys(manifest).forEach((key) => {
164701
- manifestAbs[joinURI(log_dir || "", key)] = manifest[key];
165208
+ Object.entries(manifest).forEach(([key, preview]) => {
165209
+ manifestAbs[joinURI(log_dir || "", key)] = preview;
164702
165210
  });
164703
165211
  const header = manifestAbs[log_file];
164704
165212
  if (header) return header;
@@ -164729,62 +165237,6 @@ function staticHttpApiForLog(logInfo) {
164729
165237
  };
164730
165238
  }
164731
165239
  //#endregion
164732
- //#region src/client/remote/remotePendingSampleData.ts
164733
- var SEGMENT_CAP_PER_CALL = 25;
164734
- /**
164735
- * Fetch one chunk of pending-sample data via presigned S3 URLs.
164736
- * Returns `undefined` when this transport isn't supported (404, or any
164737
- * segment lacks a presigned URL); all other failures throw.
164738
- */
164739
- var fetchPendingSampleDataDirect = async (getUrls, log_file, id, epoch, cursors) => {
164740
- let urls;
164741
- try {
164742
- urls = await getUrls(log_file, id, epoch, cursors.last_event, cursors.last_attachment, cursors.last_message_pool, cursors.last_call_pool, SEGMENT_CAP_PER_CALL);
164743
- } catch (e) {
164744
- if (e instanceof ApiError && e.status === 404) return;
164745
- throw e;
164746
- }
164747
- if (urls.segments.length === 0) return {
164748
- sampleData: {
164749
- events: [],
164750
- attachments: [],
164751
- message_pool: [],
164752
- call_pool: []
164753
- },
164754
- has_more: urls.has_more === true,
164755
- complete: urls.complete === true
164756
- };
164757
- if (!urls.segments.every((s) => s.direct_url != null)) return;
164758
- const parts = await Promise.all(urls.segments.map((seg) => readSegment(seg)));
164759
- return {
164760
- sampleData: applyCursorFilter({
164761
- events: parts.flatMap((p) => p.events),
164762
- attachments: parts.flatMap((p) => p.attachments),
164763
- message_pool: parts.flatMap((p) => p.message_pool),
164764
- call_pool: parts.flatMap((p) => p.call_pool)
164765
- }, cursors),
164766
- has_more: urls.has_more === true,
164767
- complete: urls.complete === true
164768
- };
164769
- };
164770
- var readSegment = async (seg) => {
164771
- const url = seg.direct_url;
164772
- const resp = await fetch(url);
164773
- if (!resp.ok) throw new Error(`Failed to fetch segment: ${resp.status} ${resp.statusText}`);
164774
- return await asyncJsonParseBytes(await (await openZipFileFromBuffer(new Uint8Array(await resp.arrayBuffer()))).readFile(seg.member_name));
164775
- };
164776
- var applyCursorFilter = (out, cursors) => {
164777
- const lastEvent = cursors.last_event ?? -1;
164778
- const lastAttachment = cursors.last_attachment ?? -1;
164779
- const lastMessagePool = cursors.last_message_pool ?? -1;
164780
- const lastCallPool = cursors.last_call_pool ?? -1;
164781
- out.events = out.events.filter((e) => e.id > lastEvent);
164782
- out.attachments = out.attachments.filter((a) => a.id > lastAttachment);
164783
- out.message_pool = out.message_pool.filter((m) => m.id > lastMessagePool);
164784
- out.call_pool = out.call_pool.filter((c) => c.id > lastCallPool);
164785
- return out;
164786
- };
164787
- //#endregion
164788
165240
  //#region src/client/api/view-server/api-view-server.ts
164789
165241
  var LOADED_TIME = Date.now();
164790
165242
  var lastEvalTime = 0;
@@ -164792,8 +165244,8 @@ var lastEvalTime = 0;
164792
165244
  * Create a view server API with optional server-side log listing
164793
165245
  */
164794
165246
  function viewServerApi(options = {}) {
164795
- const { apiBaseUrl, logDir, headerProvider } = options;
164796
- const requestApi = serverRequestApi(apiBaseUrl || "/api", headerProvider);
165247
+ const { apiBaseUrl, logDir, headerProvider, customFetch } = options;
165248
+ const requestApi = serverRequestApi(apiBaseUrl || "/api", headerProvider, customFetch);
164797
165249
  const client_events = async () => {
164798
165250
  const params = new URLSearchParams();
164799
165251
  params.append("loaded_time", String(LOADED_TIME.valueOf()));
@@ -164857,8 +165309,7 @@ function viewServerApi(options = {}) {
164857
165309
  return (await requestApi.fetchString("GET", `/log-info/${encodeURIComponent(file)}`)).parsed;
164858
165310
  };
164859
165311
  const toLogPreview = (header) => {
164860
- const scores = Object.values(header.results?.scores || {});
164861
- const metric = scores.length > 0 ? scores[0].metrics : void 0;
165312
+ const metric = Object.values(header.results?.scores || {})[0]?.metrics;
164862
165313
  const evalMetrics = Object.values(metric || {});
164863
165314
  const primary_metric = evalMetrics.length > 0 ? evalMetrics[0] : void 0;
164864
165315
  const model_roles = header.eval.model_roles ? Object.fromEntries(Object.entries(header.eval.model_roles).map(([role, cfg]) => [role, cfg.model])) : void 0;
@@ -164989,7 +165440,7 @@ function viewServerApi(options = {}) {
164989
165440
  return false;
164990
165441
  }
164991
165442
  })());
164992
- const response = await fetch(url, {
165443
+ const response = await (customFetch ?? fetch)(url, {
164993
165444
  method: "POST",
164994
165445
  headers,
164995
165446
  body: JSON.stringify(update),