@meridianlabs/log-viewer 0.3.199 → 0.3.201

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 (42) hide show
  1. package/lib/app/log-view/title-view/PrimaryBar.d.ts.map +1 -1
  2. package/lib/app/samples/InlineSampleDisplay.d.ts.map +1 -1
  3. package/lib/app/samples/SampleDisplay.d.ts +1 -0
  4. package/lib/app/samples/SampleDisplay.d.ts.map +1 -1
  5. package/lib/app/samples/chat/ChatViewVirtualList.d.ts.map +1 -1
  6. package/lib/app/samples/chat/MessageContent.d.ts.map +1 -1
  7. package/lib/app/samples/transcript/TranscriptPanel.d.ts.map +1 -1
  8. package/lib/app/types.d.ts +6 -0
  9. package/lib/app/types.d.ts.map +1 -1
  10. package/lib/client/api/client-api.d.ts.map +1 -1
  11. package/lib/client/api/static-http/api-static-http.d.ts +1 -1
  12. package/lib/client/api/static-http/api-static-http.d.ts.map +1 -1
  13. package/lib/client/api/types.d.ts +8 -2
  14. package/lib/client/api/types.d.ts.map +1 -1
  15. package/lib/client/api/view-server/api-view-server.d.ts.map +1 -1
  16. package/lib/client/api/vscode/api-vscode.d.ts.map +1 -1
  17. package/lib/client/api/vscode/jsonrpc.d.ts +1 -1
  18. package/lib/client/remote/remoteLogFile.d.ts +2 -2
  19. package/lib/client/remote/remoteLogFile.d.ts.map +1 -1
  20. package/lib/client/remote/remoteZipFile.d.ts +7 -6
  21. package/lib/client/remote/remoteZipFile.d.ts.map +1 -1
  22. package/lib/components/ActivityBar.d.ts +1 -0
  23. package/lib/components/ActivityBar.d.ts.map +1 -1
  24. package/lib/components/LiveVirtualList.d.ts.map +1 -1
  25. package/lib/components/MarkdownDiv.d.ts.map +1 -1
  26. package/lib/components/markdownRendering.d.ts +14 -0
  27. package/lib/components/markdownRendering.d.ts.map +1 -0
  28. package/lib/index.js +504 -285
  29. package/lib/index.js.map +1 -1
  30. package/lib/state/hooks.d.ts +1 -0
  31. package/lib/state/hooks.d.ts.map +1 -1
  32. package/lib/state/logsSlice.d.ts.map +1 -1
  33. package/lib/state/sampleSlice.d.ts +2 -1
  34. package/lib/state/sampleSlice.d.ts.map +1 -1
  35. package/lib/state/sampleUtils.d.ts.map +1 -1
  36. package/lib/state/useLoadSample.d.ts.map +1 -1
  37. package/lib/styles/index.css +53 -29
  38. package/lib/utils/expandEvents.d.ts +11 -0
  39. package/lib/utils/expandEvents.d.ts.map +1 -0
  40. package/lib/utils/json-worker.d.ts +10 -0
  41. package/lib/utils/json-worker.d.ts.map +1 -1
  42. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -16509,19 +16509,27 @@ const createLogsSlice = (set3, get2, _store) => {
16509
16509
  console.error("API not initialized in LogsStore");
16510
16510
  return void 0;
16511
16511
  }
16512
- const loadLogDir = async () => {
16512
+ const loadLogInfo = async () => {
16513
16513
  try {
16514
- return await api2.get_log_dir();
16514
+ const root2 = await api2.get_log_root();
16515
+ return { logDir: root2.log_dir, absLogDir: root2.abs_log_dir };
16515
16516
  } catch (e) {
16516
16517
  console.log(e);
16517
16518
  get2().appActions.setLoading(false, e);
16518
16519
  return void 0;
16519
16520
  }
16520
16521
  };
16521
- const logDir2 = await loadLogDir();
16522
+ const info = await loadLogInfo();
16523
+ const logDir2 = info?.logDir;
16522
16524
  if (get2().logs.logDir !== logDir2) {
16523
16525
  get2().logsActions.setLogDir(logDir2);
16524
16526
  }
16527
+ const absLogDir = info?.absLogDir;
16528
+ if (get2().logs.absLogDir !== absLogDir) {
16529
+ set3((state) => {
16530
+ state.logs.absLogDir = absLogDir;
16531
+ });
16532
+ }
16525
16533
  return logDir2;
16526
16534
  },
16527
16535
  ensureReplication: async () => {
@@ -16820,54 +16828,48 @@ const resolveAttachments = (value2, attachments, onFailedResolve) => {
16820
16828
  }
16821
16829
  return value2;
16822
16830
  };
16823
- const expandRefs = (refs, pool) => refs.flatMap(([start2, end_exclusive]) => pool.slice(start2, end_exclusive));
16824
- const resolveEventRefs = (events, msgPool, callPool) => {
16831
+ const expandRefs = (refs, pool) => refs.flatMap(([start2, end2]) => pool.slice(start2, end2));
16832
+ const isModelEvent = (event) => event.event === "model";
16833
+ function expandEvents(events, eventsData) {
16834
+ if (!eventsData) return events;
16835
+ const { messages: messages2, calls } = eventsData;
16836
+ const hasMessages = messages2.length > 0;
16837
+ const hasCalls = calls.length > 0;
16838
+ if (!hasMessages && !hasCalls) return events;
16825
16839
  return events.map((event) => {
16826
- if (event.event !== "model") return event;
16827
- const resolved = Array.isArray(event.input_refs) ? {
16828
- ...event,
16829
- input: expandRefs(
16830
- event.input_refs,
16831
- msgPool
16832
- ),
16833
- input_refs: null
16834
- } : event;
16835
- if (!resolved.call || !Array.isArray(resolved.call.call_refs))
16836
- return resolved;
16837
- return {
16838
- ...resolved,
16839
- call: {
16840
- ...resolved.call,
16841
- request: {
16842
- ...resolved.call.request,
16843
- [resolved.call.call_key || "messages"]: expandRefs(
16844
- resolved.call.call_refs,
16845
- callPool
16846
- )
16847
- },
16840
+ if (!isModelEvent(event)) return event;
16841
+ let changed = false;
16842
+ let input2 = event.input;
16843
+ let call = event.call;
16844
+ if (event.input_refs != null && hasMessages) {
16845
+ input2 = expandRefs(event.input_refs, messages2);
16846
+ changed = true;
16847
+ }
16848
+ if (call?.call_refs != null && hasCalls) {
16849
+ const key2 = call.call_key ?? "messages";
16850
+ const expandedMsgs = expandRefs(
16851
+ call.call_refs,
16852
+ calls
16853
+ );
16854
+ call = {
16855
+ ...call,
16856
+ request: { ...call.request, [key2]: expandedMsgs },
16848
16857
  call_refs: null,
16849
16858
  call_key: null
16850
- }
16851
- };
16859
+ };
16860
+ changed = true;
16861
+ }
16862
+ return changed ? { ...event, input: input2, input_refs: null, call } : event;
16852
16863
  });
16853
- };
16854
- const resolvePools = (sample2) => {
16855
- const { message_pool, call_pool } = sample2;
16856
- if (!message_pool?.length && !call_pool?.length) return sample2;
16857
- return {
16858
- ...sample2,
16859
- events: resolveEventRefs(sample2.events, message_pool, call_pool),
16860
- message_pool: [],
16861
- call_pool: []
16862
- };
16863
- };
16864
+ }
16864
16865
  const resolveSample$1 = (sample2) => {
16865
16866
  sample2 = { ...sample2 };
16866
16867
  if (sample2.transcript) {
16867
16868
  sample2.events = sample2.transcript.events;
16868
16869
  sample2.attachments = sample2.transcript.content;
16869
16870
  }
16870
- sample2 = resolvePools(sample2);
16871
+ sample2.events = expandEvents(sample2.events, sample2.events_data ?? null);
16872
+ sample2.events_data = null;
16871
16873
  sample2.attachments = sample2.attachments || {};
16872
16874
  sample2.input = resolveAttachments(sample2.input, sample2.attachments);
16873
16875
  sample2.messages = resolveAttachments(sample2.messages, sample2.attachments);
@@ -17252,6 +17254,7 @@ const initialState = {
17252
17254
  sampleStatus: "ok",
17253
17255
  sampleError: void 0,
17254
17256
  eventsCleared: false,
17257
+ downloadProgress: void 0,
17255
17258
  visiblePopover: void 0,
17256
17259
  // signals that the sample needs to be reloaded
17257
17260
  sampleNeedsReload: 0,
@@ -17306,6 +17309,7 @@ const createSampleSlice = (set3, get2, _store) => {
17306
17309
  state.sample.sampleInState = false;
17307
17310
  state.sample.runningEvents = [];
17308
17311
  state.sample.sampleStatus = "ok";
17312
+ state.sample.downloadProgress = void 0;
17309
17313
  state.log.selectedSampleHandle = void 0;
17310
17314
  });
17311
17315
  },
@@ -17327,6 +17331,9 @@ const createSampleSlice = (set3, get2, _store) => {
17327
17331
  setSampleError: (error2) => set3((state) => {
17328
17332
  state.sample.sampleError = error2;
17329
17333
  }),
17334
+ setDownloadProgress: (progress2) => set3((state) => {
17335
+ state.sample.downloadProgress = progress2;
17336
+ }),
17330
17337
  setCollapsedEvents: (scope, collapsed2) => {
17331
17338
  set3((state) => {
17332
17339
  if (state.sample.collapsedEvents === null) {
@@ -24836,16 +24843,16 @@ const supportsLinking = () => {
24836
24843
  const toFullUrl = (path) => {
24837
24844
  return `${window.location.origin}${window.location.pathname}${window.location.search}#${path}`;
24838
24845
  };
24839
- const message$3 = "_message_1k527_1";
24840
- const systemRole = "_systemRole_1k527_8";
24841
- const timestamp = "_timestamp_1k527_12";
24842
- const messageGrid = "_messageGrid_1k527_18";
24843
- const toolMessageGrid = "_toolMessageGrid_1k527_28";
24844
- const messageContents = "_messageContents_1k527_32";
24845
- const indented = "_indented_1k527_37";
24846
- const copyLink$1 = "_copyLink_1k527_41";
24847
- const metadataLabel = "_metadataLabel_1k527_52";
24848
- const hover$1 = "_hover_1k527_56";
24846
+ const message$3 = "_message_1kuwu_1";
24847
+ const systemRole = "_systemRole_1kuwu_9";
24848
+ const timestamp = "_timestamp_1kuwu_13";
24849
+ const messageGrid = "_messageGrid_1kuwu_19";
24850
+ const toolMessageGrid = "_toolMessageGrid_1kuwu_29";
24851
+ const messageContents = "_messageContents_1kuwu_33";
24852
+ const indented = "_indented_1kuwu_38";
24853
+ const copyLink$1 = "_copyLink_1kuwu_42";
24854
+ const metadataLabel = "_metadataLabel_1kuwu_53";
24855
+ const hover$1 = "_hover_1kuwu_57";
24849
24856
  const styles$1C = {
24850
24857
  message: message$3,
24851
24858
  systemRole,
@@ -24935,6 +24942,23 @@ class JsonWorkerPool {
24935
24942
  );
24936
24943
  });
24937
24944
  }
24945
+ async parseBytes(data) {
24946
+ this.ensureWorkers();
24947
+ const requestId = this.nextRequestId++;
24948
+ const ownedData = data.byteOffset === 0 && data.byteLength === data.buffer.byteLength ? data : data.slice();
24949
+ return new Promise((resolve, reject) => {
24950
+ this.pendingRequests.set(requestId, { resolve, reject });
24951
+ const worker = this.workers[requestId % this.workers.length];
24952
+ worker?.postMessage(
24953
+ {
24954
+ type: "parse",
24955
+ requestId,
24956
+ encodedText: ownedData
24957
+ },
24958
+ [ownedData.buffer]
24959
+ );
24960
+ });
24961
+ }
24938
24962
  terminate() {
24939
24963
  this.workers.forEach((w) => w.terminate());
24940
24964
  this.workers = [];
@@ -24959,6 +24983,14 @@ const asyncJsonParse = async (text2) => {
24959
24983
  return workerPool.parse(text2);
24960
24984
  }
24961
24985
  };
24986
+ const asyncJsonParseBytes = async (data) => {
24987
+ if (data.length < 5e4) {
24988
+ const text2 = new TextDecoder("utf-8").decode(data);
24989
+ return jsonParse(text2);
24990
+ } else {
24991
+ return workerPool.parseBytes(data);
24992
+ }
24993
+ };
24962
24994
  const jsonParse = (text2) => {
24963
24995
  try {
24964
24996
  return JSON.parse(text2);
@@ -95421,16 +95453,163 @@ function requireMarkdownItMathjax3() {
95421
95453
  }
95422
95454
  var markdownItMathjax3Exports = requireMarkdownItMathjax3();
95423
95455
  const markdownitMathjax3 = /* @__PURE__ */ getDefaultExportFromCjs(markdownItMathjax3Exports);
95456
+ const mdInstanceCache = {};
95457
+ const getOptionsKey = (omitMedia, omitMath) => `${omitMedia ? "1" : "0"}:${omitMath ? "1" : "0"}`;
95458
+ const unescapeHtmlForMath = (content2) => {
95459
+ return content2.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").replace(/&apos;/g, "'").replace(/&quot;/g, '"');
95460
+ };
95461
+ const getMarkdownInstance = (omitMedia, omitMath) => {
95462
+ const key2 = getOptionsKey(omitMedia, omitMath);
95463
+ if (!mdInstanceCache[key2]) {
95464
+ const md = new MarkdownIt({ breaks: true, html: true });
95465
+ if (!omitMath) {
95466
+ md.use(markdownitMathjax3);
95467
+ const origInline = md.renderer.rules.math_inline;
95468
+ const origBlock = md.renderer.rules.math_block;
95469
+ if (origInline) {
95470
+ md.renderer.rules.math_inline = (tokens, idx, options2, env, self2) => {
95471
+ tokens[idx].content = unescapeHtmlForMath(tokens[idx].content);
95472
+ return origInline(tokens, idx, options2, env, self2);
95473
+ };
95474
+ }
95475
+ if (origBlock) {
95476
+ md.renderer.rules.math_block = (tokens, idx, options2, env, self2) => {
95477
+ tokens[idx].content = unescapeHtmlForMath(tokens[idx].content);
95478
+ return origBlock(tokens, idx, options2, env, self2);
95479
+ };
95480
+ }
95481
+ }
95482
+ if (omitMedia) {
95483
+ md.disable(["image"]);
95484
+ }
95485
+ mdInstanceCache[key2] = md;
95486
+ }
95487
+ return mdInstanceCache[key2];
95488
+ };
95489
+ const escapeHtmlCharacters = (content2) => {
95490
+ if (!content2) return content2;
95491
+ return content2.replace(/[<>&'"]/g, (c2) => {
95492
+ switch (c2) {
95493
+ case "<":
95494
+ return "&lt;";
95495
+ case ">":
95496
+ return "&gt;";
95497
+ case "&":
95498
+ return "&amp;";
95499
+ case "'":
95500
+ return "&apos;";
95501
+ case '"':
95502
+ return "&quot;";
95503
+ default:
95504
+ throw new Error("Matched a value that isn't replaceable");
95505
+ }
95506
+ });
95507
+ };
95508
+ const protectBackslashesInLatex = (content2) => {
95509
+ if (!content2) return content2;
95510
+ try {
95511
+ const inlineRegex = /\$(.*?)\$/g;
95512
+ const blockRegex = /\$\$([\s\S]*?)\$\$/g;
95513
+ let result2 = content2.replace(inlineRegex, (_match, latex) => {
95514
+ const protectedTex = latex.replace(/\\/g, "___LATEX_BACKSLASH___");
95515
+ return `$${protectedTex}$`;
95516
+ });
95517
+ result2 = result2.replace(blockRegex, (_match, latex) => {
95518
+ const protectedTex = latex.replace(/\\/g, "___LATEX_BACKSLASH___");
95519
+ return `$$${protectedTex}$$`;
95520
+ });
95521
+ return result2;
95522
+ } catch (error2) {
95523
+ console.error("Error protecting LaTeX content:", error2);
95524
+ return content2;
95525
+ }
95526
+ };
95527
+ const restoreBackslashesForLatex = (content2) => {
95528
+ if (!content2) {
95529
+ return content2;
95530
+ }
95531
+ try {
95532
+ let result2 = content2.replace(/___LATEX_BACKSLASH___/g, "\\");
95533
+ result2 = fixDotsNotation(result2);
95534
+ return result2;
95535
+ } catch (error2) {
95536
+ console.error("Error restoring LaTeX content:", error2);
95537
+ return content2;
95538
+ }
95539
+ };
95540
+ const fixDotsNotation = (content2) => {
95541
+ if (!content2) return content2;
95542
+ try {
95543
+ let result2 = content2.replace(/(\$[^$]*?)\\dots([^$]*?\$)/g, "$1\\ldots$2");
95544
+ result2 = result2.replace(/(\$\$[^$]*?)\\dots([^$]*?\$\$)/g, "$1\\ldots$2");
95545
+ return result2;
95546
+ } catch (error2) {
95547
+ console.error("Error fixing dots notation:", error2);
95548
+ return content2;
95549
+ }
95550
+ };
95551
+ const kLetterListPattern = /^([a-zA-Z][).]\s.*?)$/gm;
95552
+ const kCommonmarkReferenceLinkPattern = /\[([^\]]*)\]: (?!http)(.*)/g;
95553
+ const preRenderText = (txt) => {
95554
+ if (!txt) return txt;
95555
+ txt = txt.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/, "");
95556
+ return txt.replaceAll(
95557
+ kLetterListPattern,
95558
+ "<p class='markdown-ordered-list-item'>$1</p>"
95559
+ );
95560
+ };
95561
+ const protectMarkdown = (txt) => {
95562
+ if (!txt) return txt;
95563
+ return txt.replaceAll(
95564
+ kCommonmarkReferenceLinkPattern,
95565
+ "(open:767A125E)$1(close:767A125E) $2 "
95566
+ );
95567
+ };
95568
+ const unprotectMarkdown = (txt) => {
95569
+ if (!txt) return txt;
95570
+ txt = txt.replaceAll("(open:767A125E)", "[");
95571
+ txt = txt.replaceAll("(close:767A125E)", "]");
95572
+ return txt;
95573
+ };
95574
+ function unescapeSupHtmlEntities(str2) {
95575
+ if (!str2) {
95576
+ return str2;
95577
+ }
95578
+ return str2.replace(/&lt;sup&gt;/g, "<sup>").replace(/&lt;\/sup&gt;/g, "</sup>");
95579
+ }
95580
+ function unescapeCodeHtmlEntities(str2) {
95581
+ if (!str2) return str2;
95582
+ const htmlEntities = {
95583
+ "&lt;": "<",
95584
+ "&gt;": ">",
95585
+ "&amp;": "&",
95586
+ "&#x5C;": "\\",
95587
+ "&quot;": '"'
95588
+ };
95589
+ return str2.replace(
95590
+ /(<code[^>]*>)([\s\S]*?)(<\/code>)/gi,
95591
+ (_match, starttag, content2, endtag) => {
95592
+ return starttag + content2.replace(
95593
+ /&(?:amp|lt|gt|quot|#39|#x2F|#x5C|#96);/g,
95594
+ (entity2) => htmlEntities[entity2] || entity2
95595
+ ) + endtag;
95596
+ }
95597
+ );
95598
+ }
95424
95599
  const MarkdownDivComponent = forwardRef(
95425
95600
  ({ markdown, omitMedia, omitMath, style: style2, className: className2 }, ref) => {
95426
- const optionsKey = getOptionsKey(omitMedia, omitMath);
95601
+ const optionsKey = `${omitMedia ? "1" : "0"}:${omitMath ? "1" : "0"}`;
95427
95602
  const cacheKey = `${markdown}:${optionsKey}`;
95428
95603
  const cachedHtml = renderCache.get(cacheKey);
95604
+ const sanitizeMarkdown = (md) => {
95605
+ const escapedBr = md.replace(/\n/g, "<br/>");
95606
+ return escapeHtmlCharacters(escapedBr);
95607
+ };
95429
95608
  const [renderedHtml, setRenderedHtml] = useState(() => {
95430
95609
  if (cachedHtml) {
95431
95610
  return cachedHtml;
95432
95611
  }
95433
- return markdown.replace(/\n/g, "<br/>");
95612
+ return sanitizeMarkdown(markdown);
95434
95613
  });
95435
95614
  useEffect(() => {
95436
95615
  if (cachedHtml) {
@@ -95441,7 +95620,7 @@ const MarkdownDivComponent = forwardRef(
95441
95620
  }
95442
95621
  return;
95443
95622
  }
95444
- setRenderedHtml(markdown.replace(/\n/g, "<br/>"));
95623
+ setRenderedHtml(sanitizeMarkdown(markdown));
95445
95624
  const { promise, cancel } = renderQueue.enqueue(async () => {
95446
95625
  const protectedContent = protectBackslashesInLatex(markdown);
95447
95626
  const escaped = escapeHtmlCharacters(protectedContent);
@@ -95493,22 +95672,6 @@ const MarkdownDivComponent = forwardRef(
95493
95672
  const MarkdownDiv = memo(MarkdownDivComponent);
95494
95673
  const renderCache = /* @__PURE__ */ new Map();
95495
95674
  const MAX_CACHE_SIZE = 500;
95496
- const mdInstanceCache = {};
95497
- const getOptionsKey = (omitMedia, omitMath) => `${omitMedia ? "1" : "0"}:${omitMath ? "1" : "0"}`;
95498
- const getMarkdownInstance = (omitMedia, omitMath) => {
95499
- const key2 = getOptionsKey(omitMedia, omitMath);
95500
- if (!mdInstanceCache[key2]) {
95501
- const md = new MarkdownIt({ breaks: true, html: true });
95502
- if (!omitMath) {
95503
- md.use(markdownitMathjax3);
95504
- }
95505
- if (omitMedia) {
95506
- md.disable(["image"]);
95507
- }
95508
- mdInstanceCache[key2] = md;
95509
- }
95510
- return mdInstanceCache[key2];
95511
- };
95512
95675
  class MarkdownRenderQueue {
95513
95676
  queue = [];
95514
95677
  activeCount = 0;
@@ -95575,116 +95738,6 @@ class MarkdownRenderQueue {
95575
95738
  }
95576
95739
  }
95577
95740
  const renderQueue = new MarkdownRenderQueue(10);
95578
- const kLetterListPattern = /^([a-zA-Z][).]\s.*?)$/gm;
95579
- const kCommonmarkReferenceLinkPattern = /\[([^\]]*)\]: (?!http)(.*)/g;
95580
- const protectBackslashesInLatex = (content2) => {
95581
- if (!content2) return content2;
95582
- try {
95583
- const inlineRegex = /\$(.*?)\$/g;
95584
- const blockRegex = /\$\$([\s\S]*?)\$\$/g;
95585
- let result2 = content2.replace(inlineRegex, (_match, latex) => {
95586
- const protectedTex = latex.replace(/\\/g, "___LATEX_BACKSLASH___").replace(/</g, "___LATEX_LT___").replace(/>/g, "___LATEX_GT___").replace(/&/g, "___LATEX_AMP___").replace(/'/g, "___LATEX_APOS___").replace(/"/g, "___LATEX_QUOT___");
95587
- return `$${protectedTex}$`;
95588
- });
95589
- result2 = result2.replace(blockRegex, (_match, latex) => {
95590
- const protectedTex = latex.replace(/\\/g, "___LATEX_BACKSLASH___").replace(/</g, "___LATEX_LT___").replace(/>/g, "___LATEX_GT___").replace(/&/g, "___LATEX_AMP___").replace(/'/g, "___LATEX_APOS___").replace(/"/g, "___LATEX_QUOT___");
95591
- return `$$${protectedTex}$$`;
95592
- });
95593
- return result2;
95594
- } catch (error2) {
95595
- console.error("Error protecting LaTeX content:", error2);
95596
- return content2;
95597
- }
95598
- };
95599
- const restoreBackslashesForLatex = (content2) => {
95600
- if (!content2) {
95601
- return content2;
95602
- }
95603
- try {
95604
- let result2 = content2.replace(/___LATEX_BACKSLASH___/g, "\\").replace(/___LATEX_LT___/g, "<").replace(/___LATEX_GT___/g, ">").replace(/___LATEX_AMP___/g, "&").replace(/___LATEX_APOS___/g, "'").replace(/___LATEX_QUOT___/g, '"');
95605
- result2 = fixDotsNotation(result2);
95606
- return result2;
95607
- } catch (error2) {
95608
- console.error("Error restoring LaTeX content:", error2);
95609
- return content2;
95610
- }
95611
- };
95612
- const fixDotsNotation = (content2) => {
95613
- if (!content2) return content2;
95614
- try {
95615
- let result2 = content2.replace(/(\$[^$]*?)\\dots([^$]*?\$)/g, "$1\\ldots$2");
95616
- result2 = result2.replace(/(\$\$[^$]*?)\\dots([^$]*?\$\$)/g, "$1\\ldots$2");
95617
- return result2;
95618
- } catch (error2) {
95619
- console.error("Error fixing dots notation:", error2);
95620
- return content2;
95621
- }
95622
- };
95623
- const escapeHtmlCharacters = (content2) => {
95624
- if (!content2) return content2;
95625
- return content2.replace(/[<>&'"]/g, (c2) => {
95626
- switch (c2) {
95627
- case "<":
95628
- return "&lt;";
95629
- case ">":
95630
- return "&gt;";
95631
- case "&":
95632
- return "&amp;";
95633
- case "'":
95634
- return "&apos;";
95635
- case '"':
95636
- return "&quot;";
95637
- default:
95638
- throw new Error("Matched a value that isn't replaceable");
95639
- }
95640
- });
95641
- };
95642
- const preRenderText = (txt) => {
95643
- if (!txt) return txt;
95644
- txt = txt.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/, "");
95645
- return txt.replaceAll(
95646
- kLetterListPattern,
95647
- "<p class='markdown-ordered-list-item'>$1</p>"
95648
- );
95649
- };
95650
- const protectMarkdown = (txt) => {
95651
- if (!txt) return txt;
95652
- return txt.replaceAll(
95653
- kCommonmarkReferenceLinkPattern,
95654
- "(open:767A125E)$1(close:767A125E) $2 "
95655
- );
95656
- };
95657
- const unprotectMarkdown = (txt) => {
95658
- if (!txt) return txt;
95659
- txt = txt.replaceAll("(open:767A125E)", "[");
95660
- txt = txt.replaceAll("(close:767A125E)", "]");
95661
- return txt;
95662
- };
95663
- function unescapeSupHtmlEntities(str2) {
95664
- if (!str2) {
95665
- return str2;
95666
- }
95667
- return str2.replace(/&lt;sup&gt;/g, "<sup>").replace(/&lt;\/sup&gt;/g, "</sup>");
95668
- }
95669
- function unescapeCodeHtmlEntities(str2) {
95670
- if (!str2) return str2;
95671
- const htmlEntities = {
95672
- "&lt;": "<",
95673
- "&gt;": ">",
95674
- "&amp;": "&",
95675
- "&#x5C;": "\\",
95676
- "&quot;": '"'
95677
- };
95678
- return str2.replace(
95679
- /(<code[^>]*>)([\s\S]*?)(<\/code>)/gi,
95680
- (_match, starttag, content2, endtag) => {
95681
- return starttag + content2.replace(
95682
- /&(?:amp|lt|gt|quot|#39|#x2F|#x5C|#96);/g,
95683
- (entity2) => htmlEntities[entity2] || entity2
95684
- ) + endtag;
95685
- }
95686
- );
95687
- }
95688
95741
  const content$3 = "_content_13ihw_1";
95689
95742
  const styles$1A = {
95690
95743
  content: content$3
@@ -96086,6 +96139,13 @@ function clearLargeEventsArray(data) {
96086
96139
  result2.set(after, offset2);
96087
96140
  return result2;
96088
96141
  }
96142
+ const fetchRange = async (url, start2, end2) => {
96143
+ const response = await fetch(url, {
96144
+ headers: { Range: `bytes=${start2}-${end2}` }
96145
+ });
96146
+ const arrayBuffer = await response.arrayBuffer();
96147
+ return new Uint8Array(arrayBuffer);
96148
+ };
96089
96149
  class AsyncQueue {
96090
96150
  constructor(concurrentLimit = 6) {
96091
96151
  this.concurrentLimit = concurrentLimit;
@@ -97490,8 +97550,50 @@ class FileSizeLimitError extends Error {
97490
97550
  Object.setPrototypeOf(this, FileSizeLimitError.prototype);
97491
97551
  }
97492
97552
  }
97493
- const openRemoteZipFile = async (url, fetchContentLength = fetchSize, fetchBytes = fetchRange) => {
97494
- const contentLength = await fetchContentLength(url);
97553
+ const PARALLEL_CHUNK_THRESHOLD = 8 * 1024 * 1024;
97554
+ const PARALLEL_CHUNK_SIZE = 8 * 1024 * 1024;
97555
+ const MAX_PARALLEL_CHUNKS = 10;
97556
+ const fetchBytesParallel = async (fetchFn, url, start2, end2, onProgress) => {
97557
+ const totalSize = end2 - start2 + 1;
97558
+ if (totalSize <= PARALLEL_CHUNK_THRESHOLD) {
97559
+ return fetchFn(url, start2, end2);
97560
+ }
97561
+ const chunks = [];
97562
+ let offset2 = start2;
97563
+ while (offset2 <= end2) {
97564
+ const chunkEnd = Math.min(offset2 + PARALLEL_CHUNK_SIZE - 1, end2);
97565
+ chunks.push({ start: offset2, end: chunkEnd, index: chunks.length });
97566
+ offset2 = chunkEnd + 1;
97567
+ }
97568
+ const concurrency = Math.min(chunks.length, MAX_PARALLEL_CHUNKS);
97569
+ const results = new Array(chunks.length);
97570
+ let nextChunk = 0;
97571
+ let bytesLoaded = 0;
97572
+ if (onProgress) {
97573
+ onProgress(0, totalSize);
97574
+ }
97575
+ const worker = async () => {
97576
+ while (nextChunk < chunks.length) {
97577
+ const idx = nextChunk++;
97578
+ const chunk = chunks[idx];
97579
+ results[idx] = await fetchFn(url, chunk.start, chunk.end);
97580
+ if (onProgress) {
97581
+ bytesLoaded += results[idx].length;
97582
+ onProgress(bytesLoaded, totalSize);
97583
+ }
97584
+ }
97585
+ };
97586
+ await Promise.all(Array.from({ length: concurrency }, () => worker()));
97587
+ const combined = new Uint8Array(totalSize);
97588
+ let pos2 = 0;
97589
+ for (const chunk of results) {
97590
+ combined.set(chunk, pos2);
97591
+ pos2 += chunk.length;
97592
+ }
97593
+ return combined;
97594
+ };
97595
+ const openRemoteZipFile = async (url, contentLength, fetchBytes = fetchRange) => {
97596
+ contentLength = contentLength ?? await fetchSize(url);
97495
97597
  const eocdrBuffer = await fetchBytes(
97496
97598
  url,
97497
97599
  contentLength - 22,
@@ -97533,7 +97635,8 @@ const openRemoteZipFile = async (url, fetchContentLength = fetchSize, fetchBytes
97533
97635
  centralDirSize = Number(zip64EOCDView.getBigUint64(40, true));
97534
97636
  centralDirOffset = Number(zip64EOCDView.getBigUint64(48, true));
97535
97637
  }
97536
- const centralDirBuffer = await fetchBytes(
97638
+ const centralDirBuffer = await fetchBytesParallel(
97639
+ fetchBytes,
97537
97640
  url,
97538
97641
  centralDirOffset,
97539
97642
  centralDirOffset + centralDirSize - 1
@@ -97541,28 +97644,40 @@ const openRemoteZipFile = async (url, fetchContentLength = fetchSize, fetchBytes
97541
97644
  const centralDirectory = parseCentralDirectory(centralDirBuffer);
97542
97645
  return {
97543
97646
  centralDirectory,
97544
- readFile: async (file, maxBytes) => {
97647
+ readFile: async (file, maxBytes, onProgress) => {
97545
97648
  const entry = centralDirectory.get(file);
97546
97649
  if (!entry) {
97547
97650
  throw new Error(`File not found: ${file}`);
97548
97651
  }
97549
97652
  const headerSize = 30;
97550
- const headerData = await fetchBytes(
97551
- url,
97552
- entry.fileOffset,
97553
- entry.fileOffset + headerSize - 1
97554
- );
97555
- const filenameLength = headerData[26] + (headerData[27] << 8);
97556
- const extraFieldLength = headerData[28] + (headerData[29] << 8);
97557
- const totalSizeToFetch = headerSize + filenameLength + extraFieldLength + entry.compressedSize;
97558
- if (maxBytes && totalSizeToFetch > maxBytes) {
97653
+ const extraFieldPadding = 256;
97654
+ const estimatedSize = headerSize + entry.filenameLength + extraFieldPadding + entry.compressedSize;
97655
+ if (maxBytes && headerSize + entry.filenameLength + entry.compressedSize > maxBytes) {
97559
97656
  throw new FileSizeLimitError(file, maxBytes);
97560
97657
  }
97561
- const fileData = await fetchBytes(
97658
+ let fileData = await fetchBytesParallel(
97659
+ fetchBytes,
97562
97660
  url,
97563
97661
  entry.fileOffset,
97564
- entry.fileOffset + totalSizeToFetch - 1
97662
+ entry.fileOffset + estimatedSize - 1,
97663
+ onProgress
97565
97664
  );
97665
+ if (fileData.length < headerSize) {
97666
+ throw new Error(`File entry header is truncated for ${file}`);
97667
+ }
97668
+ const actualExtraFieldLength = fileData[28] + (fileData[29] << 8);
97669
+ const actualTotal = headerSize + entry.filenameLength + actualExtraFieldLength + entry.compressedSize;
97670
+ if (maxBytes && actualTotal > maxBytes) {
97671
+ throw new FileSizeLimitError(file, maxBytes);
97672
+ }
97673
+ if (actualTotal > estimatedSize) {
97674
+ fileData = await fetchBytesParallel(
97675
+ fetchBytes,
97676
+ url,
97677
+ entry.fileOffset,
97678
+ entry.fileOffset + actualTotal - 1
97679
+ );
97680
+ }
97566
97681
  const zipFileEntry = await parseZipFileEntry(file, fileData);
97567
97682
  return decompressData(
97568
97683
  zipFileEntry.data,
@@ -97597,13 +97712,6 @@ const fetchSize = async (url) => {
97597
97712
  }
97598
97713
  throw new Error(`Could not determine content length for ${url}`);
97599
97714
  };
97600
- const fetchRange = async (url, start2, end2) => {
97601
- const response = await fetch(`${url}`, {
97602
- headers: { Range: `bytes=${start2}-${end2}` }
97603
- });
97604
- const arrayBuffer = await response.arrayBuffer();
97605
- return new Uint8Array(arrayBuffer);
97606
- };
97607
97715
  const parseZipFileEntry = async (file, rawData) => {
97608
97716
  const view = new DataView(rawData.buffer);
97609
97717
  let offset2 = 0;
@@ -97715,7 +97823,8 @@ const parseCentralDirectory = (buffer2) => {
97715
97823
  compressionMethod: view.getUint16(offset2 + 10, true),
97716
97824
  compressedSize,
97717
97825
  uncompressedSize,
97718
- fileOffset
97826
+ fileOffset,
97827
+ filenameLength
97719
97828
  };
97720
97829
  entries.set(filename2, entry);
97721
97830
  offset2 += kFileHeaderSize + filenameLength + extraFieldLength + fileCommentLength;
@@ -97733,15 +97842,23 @@ class SampleNotFoundError extends Error {
97733
97842
  }
97734
97843
  const openRemoteLogFile = async (api2, url, concurrency) => {
97735
97844
  const queue = new AsyncQueue(concurrency);
97845
+ const logInfo = await api2.get_log_info(url);
97846
+ const directUrl = logInfo.direct_url;
97847
+ const fetchBytes = async (_url, start2, end2) => {
97848
+ if (directUrl) {
97849
+ try {
97850
+ return await fetchRange(directUrl, start2, end2);
97851
+ } catch (e) {
97852
+ console.warn("Direct URL fetch failed, falling back to proxy", e);
97853
+ }
97854
+ }
97855
+ return api2.get_log_bytes(url, start2, end2);
97856
+ };
97736
97857
  let remoteZipFile = void 0;
97737
97858
  let retryCount = 0;
97738
97859
  while (!remoteZipFile && retryCount < OPEN_RETRY_LIMIT) {
97739
97860
  try {
97740
- remoteZipFile = await openRemoteZipFile(
97741
- url,
97742
- api2.get_log_size,
97743
- api2.get_log_bytes
97744
- );
97861
+ remoteZipFile = await openRemoteZipFile(url, logInfo.size, fetchBytes);
97745
97862
  } catch {
97746
97863
  retryCount++;
97747
97864
  console.warn(
@@ -97757,20 +97874,13 @@ const openRemoteLogFile = async (api2, url, concurrency) => {
97757
97874
  `Failed to open remote log file at ${url} after ${OPEN_RETRY_LIMIT} attempts.`
97758
97875
  );
97759
97876
  }
97760
- const readJSONFile = async (file, maxBytes, preprocessor2) => {
97877
+ const readJSONFile = async (file, maxBytes, preprocessor2, onProgress) => {
97761
97878
  try {
97762
- let data = await remoteZipFile.readFile(file, maxBytes);
97879
+ let data = await remoteZipFile.readFile(file, maxBytes, onProgress);
97763
97880
  if (preprocessor2) {
97764
97881
  data = preprocessor2.preprocess(data);
97765
97882
  }
97766
- const textDecoder = new TextDecoder("utf-8");
97767
- const jsonString = textDecoder.decode(data);
97768
- if (data.length > 0 && jsonString.length === 0) {
97769
- throw new Error(
97770
- `Failed to decode ${file} (${(data.length / 1024 / 1024).toFixed(0)}MB). The file may be corrupted or contain invalid UTF-8 sequences.`
97771
- );
97772
- }
97773
- return asyncJsonParse(jsonString);
97883
+ return asyncJsonParseBytes(data);
97774
97884
  } catch (error2) {
97775
97885
  if (error2 instanceof FileSizeLimitError) {
97776
97886
  throw error2;
@@ -97796,7 +97906,7 @@ const openRemoteLogFile = async (api2, url, concurrency) => {
97796
97906
  };
97797
97907
  });
97798
97908
  };
97799
- const readSample = async (sampleId, epoch) => {
97909
+ const readSample = async (sampleId, epoch, onProgress) => {
97800
97910
  const sampleFile = `samples/${sampleId}_epoch_${epoch}.json`;
97801
97911
  if (!remoteZipFile.centralDirectory.has(sampleFile)) {
97802
97912
  throw new SampleNotFoundError(
@@ -97813,7 +97923,8 @@ const openRemoteLogFile = async (api2, url, concurrency) => {
97813
97923
  return await readJSONFile(
97814
97924
  sampleFile,
97815
97925
  void 0,
97816
- eventsPreprocessor
97926
+ eventsPreprocessor,
97927
+ onProgress
97817
97928
  );
97818
97929
  };
97819
97930
  const readHeader = async () => {
@@ -97982,7 +98093,7 @@ const clientApi = (api2, log_file, debug2 = false) => {
97982
98093
  let pending_log_promise = null;
97983
98094
  const get_log_details = async (log_file2) => {
97984
98095
  if (isEvalFile(log_file2)) {
97985
- const remoteLogFile = await remoteEvalFile(log_file2);
98096
+ const remoteLogFile = await remoteEvalFile(log_file2, true);
97986
98097
  if (remoteLogFile) {
97987
98098
  return await remoteLogFile.readLogSummary();
97988
98099
  } else {
@@ -98017,7 +98128,7 @@ const clientApi = (api2, log_file, debug2 = false) => {
98017
98128
  };
98018
98129
  }
98019
98130
  };
98020
- const get_log_sample = async (log_file2, id, epoch) => {
98131
+ const get_log_sample = async (log_file2, id, epoch, onProgress) => {
98021
98132
  if (isEvalFile(log_file2)) {
98022
98133
  let handleError2 = function(error2) {
98023
98134
  if (error2 instanceof FileSizeLimitError) {
@@ -98030,7 +98141,7 @@ const clientApi = (api2, log_file, debug2 = false) => {
98030
98141
  if (!remoteLogFile) {
98031
98142
  throw new Error(`Unable to read remote eval file ${log_file2}`);
98032
98143
  }
98033
- return await remoteLogFile.readSample(String(id), epoch);
98144
+ return await remoteLogFile.readSample(String(id), epoch, onProgress);
98034
98145
  }
98035
98146
  try {
98036
98147
  return await fetchSample(true);
@@ -98333,15 +98444,17 @@ const fetchJsonFile = async (file, handleError2) => {
98333
98444
  function joinURI(...segments2) {
98334
98445
  return segments2.map((segment2) => segment2.replace(/(^\/+|\/+$)/g, "")).join("/");
98335
98446
  }
98336
- function staticHttpApi(log_dir, log_file) {
98447
+ function staticHttpApi(log_dir, log_file, abs_log_dir) {
98337
98448
  const resolved_log_dir = log_dir?.replace(" ", "+");
98338
98449
  log_file ? log_file.replace(" ", "+") : void 0;
98339
98450
  return staticHttpApiForLog({
98340
- log_dir: resolved_log_dir
98451
+ log_dir: resolved_log_dir,
98452
+ abs_log_dir
98341
98453
  });
98342
98454
  }
98343
98455
  function staticHttpApiForLog(logInfo) {
98344
98456
  const log_dir = logInfo.log_dir;
98457
+ const abs_log_dir = logInfo.abs_log_dir;
98345
98458
  let manifest = void 0;
98346
98459
  let manifestPromise = void 0;
98347
98460
  const getManifest = async () => {
@@ -98375,7 +98488,8 @@ function staticHttpApiForLog(logInfo) {
98375
98488
  });
98376
98489
  return Promise.resolve({
98377
98490
  logs,
98378
- log_dir
98491
+ log_dir,
98492
+ abs_log_dir
98379
98493
  });
98380
98494
  }
98381
98495
  }
@@ -98435,8 +98549,9 @@ function staticHttpApiForLog(logInfo) {
98435
98549
  throw new Error(`"Unable to load eval log ${log_file}`);
98436
98550
  }
98437
98551
  },
98438
- get_log_size: async (log_file) => {
98439
- return await fetchSize(log_file);
98552
+ get_log_info: async (log_file) => {
98553
+ const size = await fetchSize(log_file);
98554
+ return { size };
98440
98555
  },
98441
98556
  get_log_bytes: async (log_file, start2, end2) => {
98442
98557
  return await fetchRange(log_file, start2, end2);
@@ -98708,10 +98823,10 @@ function viewServerApi(options2 = {}) {
98708
98823
  );
98709
98824
  return result2;
98710
98825
  };
98711
- const get_log_size2 = async (file) => {
98826
+ const get_log_info2 = async (file) => {
98712
98827
  const result2 = await requestApi.fetchString(
98713
98828
  "GET",
98714
- `/log-size/${encodeURIComponent(file)}`
98829
+ `/log-info/${encodeURIComponent(file)}`
98715
98830
  );
98716
98831
  return result2.parsed;
98717
98832
  };
@@ -98866,7 +98981,7 @@ function viewServerApi(options2 = {}) {
98866
98981
  get_eval_set: get_eval_set2,
98867
98982
  get_flow: get_flow2,
98868
98983
  get_log_contents: get_log_contents2,
98869
- get_log_size: get_log_size2,
98984
+ get_log_info: get_log_info2,
98870
98985
  get_log_bytes: get_log_bytes2,
98871
98986
  get_log_summaries: get_log_summaries2,
98872
98987
  log_message: log_message2,
@@ -98882,12 +98997,13 @@ const kMethodEvalLogDir = "eval_log_dir";
98882
98997
  const kMethodEvalLogs = "eval_logs";
98883
98998
  const kMethodEvalLogFiles = "eval_log_files";
98884
98999
  const kMethodEvalLog = "eval_log";
98885
- const kMethodEvalLogSize = "eval_log_size";
99000
+ const kMethodEvalLogInfo = "eval_log_info";
98886
99001
  const kMethodEvalLogBytes = "eval_log_bytes";
98887
99002
  const kMethodEvalLogHeaders = "eval_log_headers";
98888
99003
  const kMethodPendingSamples = "eval_log_pending_samples";
98889
99004
  const kMethodSampleData = "eval_log_sample_data";
98890
99005
  const kMethodLogMessage = "log_message";
99006
+ const kJsonRpcMethodNotFound = -32601;
98891
99007
  const kJsonRpcVersion = "2.0";
98892
99008
  function webViewJsonRpcClient(vscode) {
98893
99009
  const target2 = {
@@ -99020,8 +99136,16 @@ async function get_log_contents(log_file, headerOnly, capabilities) {
99020
99136
  throw new Error(`Unable to load eval log ${log_file}.`);
99021
99137
  }
99022
99138
  }
99023
- async function get_log_size(log_file) {
99024
- return await vscodeClient(kMethodEvalLogSize, [log_file]);
99139
+ async function get_log_info(log_file) {
99140
+ try {
99141
+ return await vscodeClient(kMethodEvalLogInfo, [log_file]);
99142
+ } catch (e) {
99143
+ if (e?.code === kJsonRpcMethodNotFound) {
99144
+ const size = await vscodeClient("eval_log_size", [log_file]);
99145
+ return { size };
99146
+ }
99147
+ throw e;
99148
+ }
99025
99149
  }
99026
99150
  async function get_log_bytes(log_file, start2, end2) {
99027
99151
  return await vscodeClient(kMethodEvalLogBytes, [log_file, start2, end2]);
@@ -99104,7 +99228,7 @@ const api$1 = {
99104
99228
  get_eval_set,
99105
99229
  get_flow,
99106
99230
  get_log_contents,
99107
- get_log_size,
99231
+ get_log_info,
99108
99232
  get_log_bytes,
99109
99233
  get_log_summaries,
99110
99234
  log_message,
@@ -99125,7 +99249,7 @@ const resolveApi = () => {
99125
99249
  const data = lib$d.parse(context);
99126
99250
  if (data.log_dir || data.log_file) {
99127
99251
  const log_dir2 = data.log_dir || dirname(data.log_file);
99128
- const api2 = staticHttpApi(log_dir2, data.log_file);
99252
+ const api2 = staticHttpApi(log_dir2, data.log_file, data.abs_log_dir);
99129
99253
  return clientApi(api2, data.log_file, debug2);
99130
99254
  }
99131
99255
  }
@@ -99287,11 +99411,13 @@ ${citation.url}` : citation.url,
99287
99411
  }
99288
99412
  );
99289
99413
  const OtherCitation = ({ children: children2 }) => /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: children2 });
99290
- const contentImage = "_contentImage_srbm0_1";
99291
- const reasoning = "_reasoning_srbm0_6";
99414
+ const contentImage = "_contentImage_16eyd_1";
99415
+ const reasoning = "_reasoning_16eyd_6";
99416
+ const breakable = "_breakable_16eyd_21";
99292
99417
  const styles$1r = {
99293
99418
  contentImage,
99294
- reasoning
99419
+ reasoning,
99420
+ breakable
99295
99421
  };
99296
99422
  const mcpToolUse = "_mcpToolUse_1792k_1";
99297
99423
  const title$2 = "_title_1792k_9";
@@ -99607,7 +99733,10 @@ const messageRenderers = {
99607
99733
  RenderedText,
99608
99734
  {
99609
99735
  markdown: purgeInternalContainers(c2.text) || "",
99610
- className: isLast ? "no-last-para-padding" : ""
99736
+ className: clsx(
99737
+ isLast ? "no-last-para-padding" : "",
99738
+ styles$1r.breakable
99739
+ )
99611
99740
  }
99612
99741
  ),
99613
99742
  c2.citations ? /* @__PURE__ */ jsxRuntimeExports.jsx(MessageCitations, { citations: c2.citations }) : void 0
@@ -99905,7 +100034,7 @@ const extractInput = (args2, inputDescriptor) => {
99905
100034
  };
99906
100035
  }
99907
100036
  };
99908
- const toolCallView = "_toolCallView_l6wae_1";
100037
+ const toolCallView = "_toolCallView_10z2l_1";
99909
100038
  const styles$1o = {
99910
100039
  toolCallView
99911
100040
  };
@@ -104163,6 +104292,7 @@ const useSampleData = () => {
104163
104292
  const runningEvents = useStore(
104164
104293
  (state) => state.sample.runningEvents
104165
104294
  );
104295
+ const downloadProgress = useStore((state) => state.sample.downloadProgress);
104166
104296
  return useMemo(() => {
104167
104297
  return {
104168
104298
  selectedSampleIdentifier,
@@ -104171,7 +104301,8 @@ const useSampleData = () => {
104171
104301
  error: sampleError,
104172
104302
  getSelectedSample,
104173
104303
  eventsCleared,
104174
- running: runningEvents
104304
+ running: runningEvents,
104305
+ downloadProgress
104175
104306
  };
104176
104307
  }, [
104177
104308
  sampleStatus2,
@@ -104180,7 +104311,8 @@ const useSampleData = () => {
104180
104311
  selectedSampleIdentifier,
104181
104312
  sampleNeedsReload,
104182
104313
  eventsCleared,
104183
- runningEvents
104314
+ runningEvents,
104315
+ downloadProgress
104184
104316
  ]);
104185
104317
  };
104186
104318
  const useSampleInvalidation = () => {
@@ -104612,25 +104744,33 @@ const useFlowServerData = (dir) => {
104612
104744
  }
104613
104745
  }, [dir, flowDir, api2, updateFlowData]);
104614
104746
  };
104615
- const wrapper$3 = "_wrapper_1tajk_1";
104616
- const container$j = "_container_1tajk_12";
104617
- const animate = "_animate_1tajk_21";
104747
+ const wrapper$3 = "_wrapper_44dmw_1";
104748
+ const container$j = "_container_44dmw_12";
104749
+ const animate = "_animate_44dmw_21";
104750
+ const determinate = "_determinate_44dmw_31";
104618
104751
  const styles$1f = {
104619
104752
  wrapper: wrapper$3,
104620
104753
  container: container$j,
104621
- animate
104754
+ animate,
104755
+ determinate
104622
104756
  };
104623
- const ActivityBar = ({ animating }) => {
104757
+ const ActivityBar = ({ animating, progress: progress2 }) => {
104624
104758
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(styles$1f.wrapper), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
104625
104759
  "div",
104626
104760
  {
104627
104761
  className: clsx(styles$1f.container),
104628
104762
  role: "progressbar",
104629
104763
  "aria-label": "Progress bar",
104630
- "aria-valuenow": 25,
104764
+ "aria-valuenow": progress2 !== void 0 ? Math.round(progress2 * 100) : void 0,
104631
104765
  "aria-valuemin": 0,
104632
104766
  "aria-valuemax": 100,
104633
- children: animating && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$1f.animate })
104767
+ children: animating && (progress2 !== void 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(
104768
+ "div",
104769
+ {
104770
+ className: styles$1f.determinate,
104771
+ style: { width: `${progress2 * 100}%` }
104772
+ }
104773
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$1f.animate }))
104634
104774
  }
104635
104775
  ) });
104636
104776
  };
@@ -106610,7 +106750,7 @@ const ViewerOptionsPopover = ({
106610
106750
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(styles$1d.fullWidth, styles$1d.fullWidthPadded), children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: styles$1d.logDir, children: logDir2 }) }),
106611
106751
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(styles$1d.spacer) }),
106612
106752
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx("text-style-label", "text-style-secondary"), children: "Version" }),
106613
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(), children: "0.3.199-0-gffdb82c59" }),
106753
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(), children: "0.3.201-0-gbc38245cb" }),
106614
106754
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx("text-style-label", "text-style-secondary"), children: "Schema" }),
106615
106755
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(), children: DB_VERSION }),
106616
106756
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(styles$1d.spacer) }),
@@ -165171,7 +165311,20 @@ function useLoadSample() {
165171
165311
  if (completed !== false) {
165172
165312
  log$1.debug(`LOADING COMPLETED SAMPLE: ${id}-${epoch}`);
165173
165313
  getSamplePolling().stopPolling();
165174
- const sample2 = await api2?.get_log_sample(logFile, id, epoch);
165314
+ sampleActions.setDownloadProgress(void 0);
165315
+ const onProgress = (bytesLoaded, bytesTotal) => {
165316
+ sampleActions.setDownloadProgress({
165317
+ complete: bytesLoaded,
165318
+ total: bytesTotal
165319
+ });
165320
+ };
165321
+ const sample2 = await api2?.get_log_sample(
165322
+ logFile,
165323
+ id,
165324
+ epoch,
165325
+ onProgress
165326
+ );
165327
+ sampleActions.setDownloadProgress(void 0);
165175
165328
  log$1.debug(`LOADED COMPLETED SAMPLE: ${id}-${epoch}`);
165176
165329
  if (thisGeneration !== loadGeneration) {
165177
165330
  log$1.debug(`Discarding stale sample response: ${id}-${epoch}`);
@@ -165197,6 +165350,7 @@ function useLoadSample() {
165197
165350
  getSamplePolling().stopPolling();
165198
165351
  }
165199
165352
  } catch (e) {
165353
+ sampleActions.setDownloadProgress(void 0);
165200
165354
  sampleActions.setSampleError(e);
165201
165355
  sampleActions.setSampleStatus("error");
165202
165356
  }
@@ -165860,6 +166014,7 @@ async function findExtendedInDOM(searchTerm, back, lastFoundItem, extendedFindTe
165860
166014
  );
165861
166015
  if (foundInVirtual) {
165862
166016
  extendedSearchSucceeded = true;
166017
+ await waitForTextInDOM(searchTerm);
165863
166018
  continue;
165864
166019
  }
165865
166020
  }
@@ -165894,6 +166049,7 @@ async function findExtendedInDOM(searchTerm, back, lastFoundItem, extendedFindTe
165894
166049
  );
165895
166050
  if (foundInVirtual) {
165896
166051
  extendedSearchSucceeded = true;
166052
+ await waitForTextInDOM(searchTerm);
165897
166053
  continue;
165898
166054
  }
165899
166055
  positionSelectionForWrap(back);
@@ -165954,6 +166110,50 @@ function selectionParentElement(range2) {
165954
166110
  }
165955
166111
  return element;
165956
166112
  }
166113
+ function waitForTextInDOM(searchTerm, timeoutMs = 2e3) {
166114
+ const lowerTerm = searchTerm.toLowerCase();
166115
+ const isTextInSearchableDOM = () => {
166116
+ const walker = document.createTreeWalker(
166117
+ document.body,
166118
+ NodeFilter.SHOW_TEXT,
166119
+ {
166120
+ acceptNode: (node2) => {
166121
+ let el2 = node2.parentElement;
166122
+ while (el2) {
166123
+ if (el2.hasAttribute("data-unsearchable")) {
166124
+ return NodeFilter.FILTER_REJECT;
166125
+ }
166126
+ el2 = el2.parentElement;
166127
+ }
166128
+ return NodeFilter.FILTER_ACCEPT;
166129
+ }
166130
+ }
166131
+ );
166132
+ while (walker.nextNode()) {
166133
+ if (walker.currentNode.textContent?.toLowerCase().includes(lowerTerm)) {
166134
+ return true;
166135
+ }
166136
+ }
166137
+ return false;
166138
+ };
166139
+ return new Promise((resolve) => {
166140
+ const interval = 50;
166141
+ let elapsed = 0;
166142
+ const check2 = () => {
166143
+ if (isTextInSearchableDOM()) {
166144
+ resolve(true);
166145
+ return;
166146
+ }
166147
+ elapsed += interval;
166148
+ if (elapsed >= timeoutMs) {
166149
+ resolve(false);
166150
+ return;
166151
+ }
166152
+ setTimeout(check2, interval);
166153
+ };
166154
+ check2();
166155
+ });
166156
+ }
165957
166157
  const tabs$1 = "_tabs_1rv6h_1";
165958
166158
  const tabContents = "_tabContents_1rv6h_5";
165959
166159
  const scrollable = "_scrollable_1rv6h_11";
@@ -166590,6 +166790,7 @@ const LiveVirtualList = ({
166590
166790
  }, 100);
166591
166791
  }
166592
166792
  }, [live, followOutput, prevLive, scrollRef, setFollowOutput]);
166793
+ const isNearBottomRef = useRef(false);
166593
166794
  const handleScroll = useRafThrottle(() => {
166594
166795
  if (isAutoScrollingRef.current) return;
166595
166796
  if (!live) return;
@@ -166603,10 +166804,25 @@ const LiveVirtualList = ({
166603
166804
  }
166604
166805
  }
166605
166806
  }, [setFollowOutput, followOutput, live]);
166807
+ const handleScrollSync = useCallback(() => {
166808
+ if (isAutoScrollingRef.current) return;
166809
+ if (!scrollRef?.current) return;
166810
+ const parent = scrollRef.current;
166811
+ isNearBottomRef.current = parent.scrollHeight - parent.scrollTop <= parent.clientHeight + 50;
166812
+ }, [scrollRef]);
166606
166813
  const heightChanged = useCallback(
166607
166814
  (height) => {
166608
166815
  requestAnimationFrame(() => {
166609
- if (followOutput && live && scrollRef?.current) {
166816
+ if (!scrollRef?.current) return;
166817
+ if (followOutput && live) {
166818
+ isAutoScrollingRef.current = true;
166819
+ listHandle.current?.scrollTo({ top: height });
166820
+ requestAnimationFrame(() => {
166821
+ isAutoScrollingRef.current = false;
166822
+ });
166823
+ return;
166824
+ }
166825
+ if (isNearBottomRef.current) {
166610
166826
  isAutoScrollingRef.current = true;
166611
166827
  listHandle.current?.scrollTo({ top: height });
166612
166828
  requestAnimationFrame(() => {
@@ -166743,9 +166959,13 @@ const LiveVirtualList = ({
166743
166959
  const parent = scrollRef?.current;
166744
166960
  if (parent) {
166745
166961
  parent.addEventListener("scroll", handleScroll);
166746
- return () => parent.removeEventListener("scroll", handleScroll);
166962
+ parent.addEventListener("scroll", handleScrollSync);
166963
+ return () => {
166964
+ parent.removeEventListener("scroll", handleScroll);
166965
+ parent.removeEventListener("scroll", handleScrollSync);
166966
+ };
166747
166967
  }
166748
- }, [scrollRef, handleScroll]);
166968
+ }, [scrollRef, handleScroll, handleScrollSync]);
166749
166969
  const hasScrolled = useRef(false);
166750
166970
  useEffect(() => {
166751
166971
  if (initialTopMostItemIndex !== void 0 && listHandle.current) {
@@ -166907,7 +167127,7 @@ const ChatViewVirtualList = memo(
166907
167127
  } else if (event.key === "ArrowDown") {
166908
167128
  if (useVirtuoso) {
166909
167129
  listHandle.current?.scrollToIndex({
166910
- index: Math.min(messages2.length - 5, 0),
167130
+ index: Math.max(messages2.length - 5, 0),
166911
167131
  align: "center"
166912
167132
  });
166913
167133
  setTimeout(() => {
@@ -166926,16 +167146,10 @@ const ChatViewVirtualList = memo(
166926
167146
  }
166927
167147
  }
166928
167148
  };
166929
- const scrollElement = scrollRef?.current;
166930
- if (scrollElement) {
166931
- scrollElement.addEventListener("keydown", handleKeyDown);
166932
- if (!scrollElement.hasAttribute("tabIndex")) {
166933
- scrollElement.setAttribute("tabIndex", "0");
166934
- }
166935
- return () => {
166936
- scrollElement.removeEventListener("keydown", handleKeyDown);
166937
- };
166938
- }
167149
+ document.addEventListener("keydown", handleKeyDown);
167150
+ return () => {
167151
+ document.removeEventListener("keydown", handleKeyDown);
167152
+ };
166939
167153
  }, [scrollRef, messages2, useVirtuoso]);
166940
167154
  if (!useVirtuoso) {
166941
167155
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -168888,12 +169102,12 @@ const TranscriptOutline = ({
168888
169102
  }
168889
169103
  );
168890
169104
  };
168891
- const container$e = "_container_17sux_1";
168892
- const collapsed = "_collapsed_17sux_9";
168893
- const treeContainer = "_treeContainer_17sux_13";
168894
- const listContainer = "_listContainer_17sux_25";
168895
- const outline = "_outline_17sux_29";
168896
- const outlineToggle = "_outlineToggle_17sux_33";
169105
+ const container$e = "_container_n37ko_1";
169106
+ const collapsed = "_collapsed_n37ko_13";
169107
+ const treeContainer = "_treeContainer_n37ko_17";
169108
+ const listContainer = "_listContainer_n37ko_29";
169109
+ const outline = "_outline_n37ko_33";
169110
+ const outlineToggle = "_outlineToggle_n37ko_37";
168897
169111
  const styles$R = {
168898
169112
  container: container$e,
168899
169113
  collapsed,
@@ -180413,17 +180627,11 @@ const TranscriptPanel = memo((props) => {
180413
180627
  }
180414
180628
  }
180415
180629
  };
180416
- const scrollElement = scrollRef.current;
180417
- if (scrollElement) {
180418
- scrollElement.addEventListener("keydown", handleKeyDown);
180419
- if (!scrollElement.hasAttribute("tabIndex")) {
180420
- scrollElement.setAttribute("tabIndex", "0");
180421
- }
180422
- return () => {
180423
- scrollElement.removeEventListener("keydown", handleKeyDown);
180424
- };
180425
- }
180426
- }, [scrollRef, flattenedNodes]);
180630
+ document.addEventListener("keydown", handleKeyDown);
180631
+ return () => {
180632
+ document.removeEventListener("keydown", handleKeyDown);
180633
+ };
180634
+ }, [flattenedNodes]);
180427
180635
  if (sampleStatus2 === "loading" && flattenedNodes.length === 0) {
180428
180636
  return void 0;
180429
180637
  }
@@ -180529,6 +180737,7 @@ const SampleDisplay = ({
180529
180737
  id,
180530
180738
  scrollRef,
180531
180739
  showActivity,
180740
+ progress: progress2,
180532
180741
  focusOnLoad
180533
180742
  }) => {
180534
180743
  const baseId = `sample-display`;
@@ -180760,7 +180969,7 @@ const SampleDisplay = ({
180760
180969
  const sampleDetailNavigation = useSampleDetailNavigation();
180761
180970
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(Fragment, { children: [
180762
180971
  selectedSampleSummary ? /* @__PURE__ */ jsxRuntimeExports.jsx(SampleSummaryView, { parent_id: id, sample: selectedSampleSummary }) : void 0,
180763
- /* @__PURE__ */ jsxRuntimeExports.jsx(ActivityBar, { animating: showActivity }),
180972
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ActivityBar, { animating: showActivity, progress: progress2 }),
180764
180973
  hasSampleData && /* @__PURE__ */ jsxRuntimeExports.jsxs(
180765
180974
  TabSet,
180766
180975
  {
@@ -181126,6 +181335,7 @@ const InlineSampleComponent = ({
181126
181335
  className: className2
181127
181336
  }) => {
181128
181337
  const sampleData = useSampleData();
181338
+ const sampleProgress = sampleData.status === "loading" && sampleData.downloadProgress && sampleData.downloadProgress.total > 0 ? sampleData.downloadProgress.complete / sampleData.downloadProgress.total : void 0;
181129
181339
  const scrollRef = useRef(null);
181130
181340
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(className2, styles$w.container), children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx(styles$w.scroller), ref: scrollRef, children: /* @__PURE__ */ jsxRuntimeExports.jsx(StickyScrollProvider, { value: scrollRef, children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: styles$w.body, children: sampleData.error ? /* @__PURE__ */ jsxRuntimeExports.jsx(
181131
181341
  ErrorPanel,
@@ -181138,6 +181348,7 @@ const InlineSampleComponent = ({
181138
181348
  {
181139
181349
  id: "inline-sample-display",
181140
181350
  showActivity: !!showActivity,
181351
+ progress: sampleProgress,
181141
181352
  scrollRef
181142
181353
  }
181143
181354
  ) }) }) }) });
@@ -204848,9 +205059,17 @@ const PrimaryBar = ({
204848
205059
  }) => {
204849
205060
  const streamSamples = useStore((state) => state.capabilities.streamSamples);
204850
205061
  const downloadLogs = useStore((state) => state.capabilities.downloadLogs);
205062
+ const absLogDir = useStore((state) => state.logs.absLogDir);
204851
205063
  const selectedLogFile = useStore((state) => state.logs.selectedLogFile);
205064
+ const logDir2 = useStore((state) => state.logs.logDir);
204852
205065
  const logFileName = selectedLogFile ? filename(selectedLogFile) : "";
204853
205066
  const isEvalFile2 = selectedLogFile?.endsWith(".eval");
205067
+ const copyValue = (() => {
205068
+ if (!absLogDir || !selectedLogFile || !logDir2) return selectedLogFile;
205069
+ const prefix = logDir2 + "/";
205070
+ const relFile = selectedLogFile.startsWith(prefix) ? selectedLogFile.slice(prefix.length) : selectedLogFile;
205071
+ return absLogDir.replace(/\/?$/, "/") + relFile;
205072
+ })();
204854
205073
  const hasRunningMetrics = runningMetrics && runningMetrics.length > 0;
204855
205074
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: clsx(styles$b.wrapper), children: [
204856
205075
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -204892,7 +205111,7 @@ const PrimaryBar = ({
204892
205111
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: clsx("text-size-small", styles$b.secondaryContainer), children: [
204893
205112
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx("navbar-secondary-text", "text-truncate"), children: logFileName }),
204894
205113
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: styles$b.buttonGroup, children: [
204895
- selectedLogFile ? /* @__PURE__ */ jsxRuntimeExports.jsx(CopyButton, { value: selectedLogFile }) : "",
205114
+ copyValue ? /* @__PURE__ */ jsxRuntimeExports.jsx(CopyButton, { value: copyValue }) : "",
204896
205115
  downloadLogs && selectedLogFile && isEvalFile2 ? /* @__PURE__ */ jsxRuntimeExports.jsx(DownloadLogButton, { log_file: selectedLogFile }) : null
204897
205116
  ] })
204898
205117
  ] })