@meridianlabs/log-viewer 0.3.237 → 0.3.239

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React$1 from "react";
2
- import React, { Children, Component, Fragment, Suspense, createContext, createElement, forwardRef, isValidElement, lazy, memo, startTransition, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
2
+ import React, { Children, Component, Fragment, Suspense, createContext, createElement, forwardRef, isValidElement, lazy, memo, startTransition, useCallback, useContext, useDeferredValue, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
3
3
  import * as ReactDOM$1 from "react-dom";
4
4
  import ReactDOM, { createPortal, flushSync } from "react-dom";
5
5
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -36338,18 +36338,28 @@ var MarkdownRenderQueue = class {
36338
36338
  };
36339
36339
  var renderQueue = new MarkdownRenderQueue(10);
36340
36340
  var NoContentsPanel_module_default = {
36341
- panel: "_panel_twp3v_1",
36342
- container: "_container_twp3v_7"
36341
+ panel: "_panel_tison_1",
36342
+ container: "_container_tison_7",
36343
+ ellipsis: "_ellipsis_tison_14",
36344
+ "ncp-ellipsis": "_ncp-ellipsis_tison_1"
36343
36345
  };
36344
36346
  //#endregion
36345
36347
  //#region ../../packages/react/src/components/NoContentsPanel.tsx
36346
- var NoContentsPanel = ({ text, icon }) => {
36348
+ var NoContentsPanel = ({ text, icon, busy }) => {
36347
36349
  const icons = useComponentIcons();
36348
36350
  return /* @__PURE__ */ jsx("div", {
36349
36351
  className: clsx(NoContentsPanel_module_default.panel),
36350
36352
  children: /* @__PURE__ */ jsxs("div", {
36351
36353
  className: clsx(NoContentsPanel_module_default.container, "text-size-smaller"),
36352
- children: [/* @__PURE__ */ jsx("i", { className: icon ?? icons.noSamples }), /* @__PURE__ */ jsx("div", { children: text })]
36354
+ children: [!busy && /* @__PURE__ */ jsx("i", { className: icon ?? icons.noSamples }), /* @__PURE__ */ jsxs("div", { children: [text, busy && /* @__PURE__ */ jsxs("span", {
36355
+ className: clsx(NoContentsPanel_module_default.ellipsis),
36356
+ "aria-hidden": "true",
36357
+ children: [
36358
+ /* @__PURE__ */ jsx("i", { children: "." }),
36359
+ /* @__PURE__ */ jsx("i", { children: "." }),
36360
+ /* @__PURE__ */ jsx("i", { children: "." })
36361
+ ]
36362
+ })] })]
36353
36363
  })
36354
36364
  });
36355
36365
  };
@@ -47196,8 +47206,8 @@ var ReplicationService = class {
47196
47206
  constructor() {
47197
47207
  this._processingCount = 0;
47198
47208
  this._throttledUpdateDbStats = throttle(() => this.updateDbStats(), 1e3);
47199
- this._throttledFlushPreviewBatch = throttle(() => this.flushPreviewBatch(), 100);
47200
- this._throttledFlushDetailBatch = throttle(() => this.flushDetailBatch(), 100);
47209
+ this._throttledFlushPreviewBatch = throttle(() => this.flushPreviewBatch(), 250);
47210
+ this._throttledFlushDetailBatch = throttle(() => this.flushDetailBatch(), 250);
47201
47211
  this._previewQueue = new WorkQueue({
47202
47212
  name: "Log-Preview-Queue",
47203
47213
  concurrency: 2,
@@ -103596,6 +103606,50 @@ var FindBandUI = ({ onClose, onNext, onPrevious, onKeyDown, onChange, onBeforeIn
103596
103606
  });
103597
103607
  };
103598
103608
  //#endregion
103609
+ //#region src/app/shared/useKeyedMemo.ts
103610
+ var shallowEqual = (a, b) => {
103611
+ if (a.length !== b.length) return false;
103612
+ for (let i = 0; i < a.length; i++) if (!Object.is(a[i], b[i])) return false;
103613
+ return true;
103614
+ };
103615
+ /**
103616
+ * Map a list to derived values, reusing the prior output object for any item
103617
+ * whose per-item deps are unchanged.
103618
+ *
103619
+ * `useMemo` is all-or-nothing: any dep change rebuilds every element, handing
103620
+ * a consumer (e.g. AG-Grid) all-new identities and forcing a full refresh.
103621
+ * This keeps a per-key cache so only the items that actually changed get a new
103622
+ * object — the rest keep reference identity. Reuse is gated on `itemDeps`, so
103623
+ * the cache must be pure: same deps must always yield the same value.
103624
+ *
103625
+ * The list is re-walked on every render; reuse keeps that cheap (a shallow dep
103626
+ * compare per item, builds only on change). The returned array keeps the same
103627
+ * reference when nothing changed, so consumers that key off its identity (deps
103628
+ * arrays, AG-Grid's rowData diff) don't re-run on unrelated renders.
103629
+ */
103630
+ function useKeyedMemo(source, getKey, itemDeps, build) {
103631
+ const cacheRef = useRef(/* @__PURE__ */ new Map());
103632
+ const resultRef = useRef([]);
103633
+ const prev = cacheRef.current;
103634
+ const next = /* @__PURE__ */ new Map();
103635
+ let changed = source.length !== resultRef.current.length;
103636
+ const result = source.map((item, i) => {
103637
+ const key = getKey(item);
103638
+ const deps = itemDeps(item);
103639
+ const hit = prev.get(key);
103640
+ const value = hit && shallowEqual(hit.deps, deps) ? hit.value : build(item);
103641
+ next.set(key, {
103642
+ deps,
103643
+ value
103644
+ });
103645
+ if (!changed && resultRef.current[i] !== value) changed = true;
103646
+ return value;
103647
+ });
103648
+ cacheRef.current = next;
103649
+ if (changed) resultRef.current = result;
103650
+ return resultRef.current;
103651
+ }
103652
+ //#endregion
103599
103653
  //#region src/app/shared/agGrid.ts
103600
103654
  ModuleRegistry.registerModules([AllCommunityModule]);
103601
103655
  //#endregion
@@ -103730,6 +103784,72 @@ function useApplyColumnVisibility(gridRef, columnDefs, visibility) {
103730
103784
  }
103731
103785
  //#endregion
103732
103786
  //#region src/app/log-list/grid/LogListGrid.tsx
103787
+ var detailsForItem = (item, logDetails) => item.type === "file" && item.log ? logDetails[item.log.name] : void 0;
103788
+ var buildLogListRow = (item, details) => {
103789
+ const preview = item.type === "file" ? item.logPreview : void 0;
103790
+ let totalTokens;
103791
+ if (details?.stats?.model_usage) {
103792
+ totalTokens = 0;
103793
+ for (const usage of Object.values(details.stats.model_usage)) totalTokens += usage.total_tokens;
103794
+ }
103795
+ let duration;
103796
+ if (details?.stats?.started_at && details?.stats?.completed_at) {
103797
+ const start = new Date(details.stats.started_at).getTime();
103798
+ const end = new Date(details.stats.completed_at).getTime();
103799
+ if (start && end && end > start) duration = (end - start) / 1e3;
103800
+ }
103801
+ const taskArgsSource = details?.eval?.task_args_passed ?? details?.eval?.task_args;
103802
+ let taskArgs;
103803
+ if (taskArgsSource) {
103804
+ const entries = Object.entries(taskArgsSource);
103805
+ if (entries.length > 0) taskArgs = entries.map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(", ");
103806
+ }
103807
+ let percentCompleted;
103808
+ const total = details?.results?.total_samples;
103809
+ const completed = details?.results?.completed_samples;
103810
+ if (total && total > 0 && completed !== void 0) percentCompleted = completed / total * 100;
103811
+ let sampleErrors;
103812
+ if (details?.sampleSummaries) sampleErrors = details.sampleSummaries.filter((s) => s.error).length;
103813
+ let sampleLimits;
103814
+ if (details?.sampleSummaries) {
103815
+ const limits = /* @__PURE__ */ new Set();
103816
+ for (const s of details.sampleSummaries) if (s.limit) limits.add(s.limit);
103817
+ if (limits.size > 0) sampleLimits = Array.from(limits).sort().join(", ");
103818
+ }
103819
+ const row = {
103820
+ id: item.id,
103821
+ name: item.name,
103822
+ displayIndex: item.type === "file" || item.type === "pending-task" ? item.displayIndex : void 0,
103823
+ type: item.type,
103824
+ url: item.url,
103825
+ task: item.type === "file" ? preview?.task : item.name,
103826
+ model: item.type === "file" ? preview?.model : item.type === "pending-task" ? item.model : void 0,
103827
+ modelRoles: item.type === "file" ? preview?.model_roles ?? void 0 : void 0,
103828
+ score: preview?.primary_metric?.value,
103829
+ status: preview?.status,
103830
+ completedAt: preview?.completed_at,
103831
+ itemCount: item.type === "folder" ? item.itemCount : void 0,
103832
+ log: item.type === "file" ? item.log : void 0,
103833
+ path: item.type === "file" ? item.name : void 0,
103834
+ totalSamples: details?.results?.total_samples,
103835
+ completedSamples: details?.results?.completed_samples,
103836
+ sandbox: details?.eval?.sandbox?.type,
103837
+ totalTokens,
103838
+ duration,
103839
+ taskFile: details?.eval?.task_file ?? void 0,
103840
+ taskArgs,
103841
+ taskArgsRaw: taskArgsSource ?? void 0,
103842
+ tags: details?.tags,
103843
+ percentCompleted,
103844
+ sampleErrors,
103845
+ sampleLimits,
103846
+ errorMessage: details?.error?.message
103847
+ };
103848
+ if (details?.results?.scores) {
103849
+ for (const evalScore of details.results.scores) if (evalScore.metrics) for (const [metricName, metric] of Object.entries(evalScore.metrics)) row[`score_${evalScore.name}/${metricName}`] = metric.value;
103850
+ }
103851
+ return row;
103852
+ };
103733
103853
  var LogListGrid = ({ items, currentPath, scopeKey, gridRef: externalGridRef, mode = "logs" }) => {
103734
103854
  const { gridStateByScope, setGridState, setFilteredCount } = useLogsListing();
103735
103855
  const gridState = scopeKey ? gridStateByScope[scopeKey] : void 0;
@@ -103737,7 +103857,7 @@ var LogListGrid = ({ items, currentPath, scopeKey, gridRef: externalGridRef, mod
103737
103857
  const loading = useStore((state) => state.app.status.loading);
103738
103858
  const syncing = useStore((state) => state.app.status.syncing);
103739
103859
  const setWatchedLogs = useStore((state) => state.logsActions.setWatchedLogs);
103740
- const logDetails = useStore((state) => state.logs.logDetails);
103860
+ const deferredLogDetails = useDeferredValue(useStore((state) => state.logs.logDetails));
103741
103861
  const navigate = useNavigate();
103742
103862
  const internalGridRef = useRef(null);
103743
103863
  const gridRef = externalGridRef ?? internalGridRef;
@@ -103763,74 +103883,17 @@ var LogListGrid = ({ items, currentPath, scopeKey, gridRef: externalGridRef, mod
103763
103883
  useEffect(() => {
103764
103884
  gridContainerRef.current?.focus();
103765
103885
  }, []);
103766
- const data = useMemo(() => {
103767
- return items.map((item) => {
103768
- const preview = item.type === "file" ? item.logPreview : void 0;
103769
- const details = item.type === "file" && item.log ? logDetails[item.log.name] : void 0;
103770
- let totalTokens;
103771
- if (details?.stats?.model_usage) {
103772
- totalTokens = 0;
103773
- for (const usage of Object.values(details.stats.model_usage)) totalTokens += usage.total_tokens;
103774
- }
103775
- let duration;
103776
- if (details?.stats?.started_at && details?.stats?.completed_at) {
103777
- const start = new Date(details.stats.started_at).getTime();
103778
- const end = new Date(details.stats.completed_at).getTime();
103779
- if (start && end && end > start) duration = (end - start) / 1e3;
103780
- }
103781
- const taskArgsSource = details?.eval?.task_args_passed ?? details?.eval?.task_args;
103782
- let taskArgs;
103783
- if (taskArgsSource) {
103784
- const entries = Object.entries(taskArgsSource);
103785
- if (entries.length > 0) taskArgs = entries.map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(", ");
103786
- }
103787
- let percentCompleted;
103788
- const total = details?.results?.total_samples;
103789
- const completed = details?.results?.completed_samples;
103790
- if (total && total > 0 && completed !== void 0) percentCompleted = completed / total * 100;
103791
- let sampleErrors;
103792
- if (details?.sampleSummaries) sampleErrors = details.sampleSummaries.filter((s) => s.error).length;
103793
- let sampleLimits;
103794
- if (details?.sampleSummaries) {
103795
- const limits = /* @__PURE__ */ new Set();
103796
- for (const s of details.sampleSummaries) if (s.limit) limits.add(s.limit);
103797
- if (limits.size > 0) sampleLimits = Array.from(limits).sort().join(", ");
103798
- }
103799
- const row = {
103800
- id: item.id,
103801
- name: item.name,
103802
- displayIndex: item.type === "file" || item.type === "pending-task" ? item.displayIndex : void 0,
103803
- type: item.type,
103804
- url: item.url,
103805
- task: item.type === "file" ? preview?.task : item.name,
103806
- model: item.type === "file" ? preview?.model : item.type === "pending-task" ? item.model : void 0,
103807
- modelRoles: item.type === "file" ? preview?.model_roles ?? void 0 : void 0,
103808
- score: preview?.primary_metric?.value,
103809
- status: preview?.status,
103810
- completedAt: preview?.completed_at,
103811
- itemCount: item.type === "folder" ? item.itemCount : void 0,
103812
- log: item.type === "file" ? item.log : void 0,
103813
- path: item.type === "file" ? item.name : void 0,
103814
- totalSamples: details?.results?.total_samples,
103815
- completedSamples: details?.results?.completed_samples,
103816
- sandbox: details?.eval?.sandbox?.type,
103817
- totalTokens,
103818
- duration,
103819
- taskFile: details?.eval?.task_file ?? void 0,
103820
- taskArgs,
103821
- taskArgsRaw: taskArgsSource ?? void 0,
103822
- tags: details?.tags,
103823
- percentCompleted,
103824
- sampleErrors,
103825
- sampleLimits,
103826
- errorMessage: details?.error?.message
103827
- };
103828
- if (details?.results?.scores) {
103829
- for (const evalScore of details.results.scores) if (evalScore.metrics) for (const [metricName, metric] of Object.entries(evalScore.metrics)) row[`score_${evalScore.name}/${metricName}`] = metric.value;
103830
- }
103831
- return row;
103832
- });
103833
- }, [items, logDetails]);
103886
+ const data = useKeyedMemo(items, (item) => item.id, (item) => [
103887
+ item.id,
103888
+ item.type,
103889
+ item.url,
103890
+ item.name,
103891
+ item.displayIndex,
103892
+ item.type === "file" ? item.logPreview : void 0,
103893
+ item.type === "folder" ? item.itemCount : void 0,
103894
+ item.type === "pending-task" ? item.model : void 0,
103895
+ detailsForItem(item, deferredLogDetails)
103896
+ ], (item) => buildLogListRow(item, detailsForItem(item, deferredLogDetails)));
103834
103897
  const handleRowClick = useCallback((e) => {
103835
103898
  if (e.data && e.node && gridRef.current?.api) {
103836
103899
  gridRef.current.api.deselectAll();
@@ -104125,7 +104188,7 @@ var LogsPanel = ({ maybeShowSingleLog, mode = "logs" }) => {
104125
104188
  const logDir = useStore((state) => state.logs.logDir);
104126
104189
  const logFiles = useLogsWithretried();
104127
104190
  const evalSet = useStore((state) => state.logs.evalSet);
104128
- const logPreviews = useStore((state) => state.logs.logPreviews);
104191
+ const deferredLogPreviews = useDeferredValue(useStore((state) => state.logs.logPreviews));
104129
104192
  const { filteredCount } = useLogsListing();
104130
104193
  const syncing = useStore((state) => state.app.status.syncing);
104131
104194
  const watchedLogs = useStore((state) => state.logs.listing.watchedLogs);
@@ -104169,7 +104232,7 @@ var LogsPanel = ({ maybeShowSingleLog, mode = "logs" }) => {
104169
104232
  type: "file",
104170
104233
  url: tasksUrl(decodedPath, logDir),
104171
104234
  log: logFile,
104172
- logPreview: logPreviews[logFile.name]
104235
+ logPreview: deferredLogPreviews[logFile.name]
104173
104236
  });
104174
104237
  }
104175
104238
  }
@@ -104180,6 +104243,18 @@ var LogsPanel = ({ maybeShowSingleLog, mode = "logs" }) => {
104180
104243
  const processedFolders = /* @__PURE__ */ new Set();
104181
104244
  const existingLogTaskIds = /* @__PURE__ */ new Set();
104182
104245
  let _hasRetriedLogs = false;
104246
+ const sortedNames = logFiles.map((f) => f.name).sort();
104247
+ const lowerBound = (target) => {
104248
+ let lo = 0;
104249
+ let hi = sortedNames.length;
104250
+ while (lo < hi) {
104251
+ const mid = lo + hi >> 1;
104252
+ if (sortedNames[mid] < target) lo = mid + 1;
104253
+ else hi = mid;
104254
+ }
104255
+ return lo;
104256
+ };
104257
+ const countWithPrefix = (prefix) => lowerBound(prefix + "￿") - lowerBound(prefix);
104183
104258
  for (const logFile of logFiles) {
104184
104259
  if (logFile.task_id) existingLogTaskIds.add(logFile.task_id);
104185
104260
  const name = logFile.name;
@@ -104197,7 +104272,7 @@ var LogsPanel = ({ maybeShowSingleLog, mode = "logs" }) => {
104197
104272
  type: "file",
104198
104273
  url: logsUrl(path, logDir),
104199
104274
  log: logFile,
104200
- logPreview: logPreviews[logFile.name]
104275
+ logPreview: deferredLogPreviews[logFile.name]
104201
104276
  });
104202
104277
  } else if (name.startsWith(dirWithSlash)) {
104203
104278
  const relativePath = directoryRelativeUrl(name, currentDir);
@@ -104210,7 +104285,7 @@ var LogsPanel = ({ maybeShowSingleLog, mode = "logs" }) => {
104210
104285
  name: dirName,
104211
104286
  type: "folder",
104212
104287
  url: logsUrl(url, logDir),
104213
- itemCount: logFiles.filter((file) => file.name.startsWith(dirname(name))).length
104288
+ itemCount: countWithPrefix(dirname(name))
104214
104289
  });
104215
104290
  processedFolders.add(dirName);
104216
104291
  }
@@ -104223,7 +104298,7 @@ var LogsPanel = ({ maybeShowSingleLog, mode = "logs" }) => {
104223
104298
  logFiles,
104224
104299
  currentDir,
104225
104300
  logDir,
104226
- logPreviews,
104301
+ deferredLogPreviews,
104227
104302
  showRetriedLogs
104228
104303
  ]);
104229
104304
  const scopePrefix = mode === "logs" ? currentDir : void 0;
@@ -106731,7 +106806,7 @@ var MessageLabel = ({ label, mode = "badge", onActivate, className }) => {
106731
106806
  /**
106732
106807
  * Renders the ChatMessage component.
106733
106808
  */
106734
- var ChatMessageRow = ({ index, parentName, resolvedMessage, references, className, display, labels, linking, tools, startNumber }) => {
106809
+ var ChatMessageRow = memo(function ChatMessageRow({ index, parentName, resolvedMessage, references, className, display, labels, linking, tools, startNumber }) {
106735
106810
  const highlightUserMessage = display?.highlightUserMessage ?? true;
106736
106811
  const showLabels = labels?.show ?? true;
106737
106812
  const labelValues = labels?.messageLabels;
@@ -106818,8 +106893,8 @@ var ChatMessageRow = ({ index, parentName, resolvedMessage, references, classNam
106818
106893
  idx++;
106819
106894
  }
106820
106895
  }
106821
- if (useLabels) {
106822
- const hasTools = viewKinds.some((k) => k !== "message");
106896
+ const hasTools = viewKinds.some((k) => k !== "message");
106897
+ if (useLabels || hasTools) {
106823
106898
  const renderPart = (idx, attached) => {
106824
106899
  const kind = viewKinds[idx];
106825
106900
  const isMessage = kind === "message";
@@ -106853,7 +106928,19 @@ var ChatMessageRow = ({ index, parentName, resolvedMessage, references, classNam
106853
106928
  children: view
106854
106929
  }, `chat-message-row-unlabeled-${index}-part-${idx}`);
106855
106930
  });
106856
- };
106931
+ }, chatMessageRowEqual);
106932
+ function chatMessageRowEqual(prev, next) {
106933
+ const keys = Object.keys(prev);
106934
+ if (keys.length !== Object.keys(next).length) return false;
106935
+ for (const key of keys) if (key === "resolvedMessage") {
106936
+ const a = prev.resolvedMessage;
106937
+ const b = next.resolvedMessage;
106938
+ if (a.message !== b.message) return false;
106939
+ if (a.toolMessages.length !== b.toolMessages.length) return false;
106940
+ if (!a.toolMessages.every((t, i) => t === b.toolMessages[i])) return false;
106941
+ } else if (prev[key] !== next[key]) return false;
106942
+ return true;
106943
+ }
106857
106944
  var resolveToolMessage = (toolMessage) => {
106858
106945
  if (!toolMessage || toolMessage.error) return [];
106859
106946
  const content = toolMessage.content;
@@ -108260,10 +108347,12 @@ function VirtualList({ persistenceKey, ref, className, scrollRef: externalScroll
108260
108347
  const lastAutoScrollTopRef = useRef(null);
108261
108348
  const lastInitialKeyRef = useRef(null);
108262
108349
  const lastInitialIndexRef = useRef(void 0);
108350
+ const hasResetTopRef = useRef(false);
108263
108351
  useEffect(() => {
108264
108352
  if (lastInitialKeyRef.current !== persistenceKey || lastInitialIndexRef.current !== initialIndex) {
108265
108353
  hasInitialScrolledRef.current = false;
108266
108354
  userScrolledRef.current = false;
108355
+ hasResetTopRef.current = false;
108267
108356
  lastInitialKeyRef.current = persistenceKey;
108268
108357
  lastInitialIndexRef.current = initialIndex ?? void 0;
108269
108358
  }
@@ -108297,8 +108386,9 @@ function VirtualList({ persistenceKey, ref, className, scrollRef: externalScroll
108297
108386
  el.scrollTop = toSpacerScroll(snapshot.totalCount === data.length ? snapshot.scrollOffset : Math.min(snapshot.scrollOffset, maxScroll));
108298
108387
  }
108299
108388
  release();
108300
- } else if (!userScrolledRef.current) {
108389
+ } else if (!userScrolledRef.current && !hasResetTopRef.current) {
108301
108390
  el.scrollTop = 0;
108391
+ hasResetTopRef.current = true;
108302
108392
  release();
108303
108393
  } else release();
108304
108394
  });
@@ -108718,6 +108808,10 @@ var ChatViewVirtualList = memo(function ChatViewVirtualList({ id, messages, init
108718
108808
  maxLabelLength,
108719
108809
  rowStartNumbers
108720
108810
  ]);
108811
+ if (collapsedMessages.length === 0) return running ? /* @__PURE__ */ jsx(NoContentsPanel, {
108812
+ text: "Waiting for messages",
108813
+ busy: true
108814
+ }) : /* @__PURE__ */ jsx(NoContentsPanel, { text: "No messages" });
108721
108815
  return /* @__PURE__ */ jsx(VirtualList, {
108722
108816
  persistenceKey: `chat-${id}`,
108723
108817
  ref: listHandle,
@@ -108757,7 +108851,11 @@ var kCollapsibleEventTypes = [
108757
108851
  TYPE_SUBTASK
108758
108852
  ];
108759
108853
  /** Event types whose *content* can be collapsed (panel-level collapse). */
108760
- var kContentCollapsibleEventTypes = ["state", "store"];
108854
+ var kContentCollapsibleEventTypes = [
108855
+ "model",
108856
+ "state",
108857
+ "store"
108858
+ ];
108761
108859
  var EventNode = class {
108762
108860
  id;
108763
108861
  event;
@@ -116572,6 +116670,7 @@ function useTimelinesArray(events, serverTimelines, options) {
116572
116670
  * Always runs through collectRawEvents so that sourceSpans (used for
116573
116671
  * agent card rendering) are populated for the selected row.
116574
116672
  */
116673
+ var PHASE_SPAN_TYPES = new Set(["init", "scorers"]);
116575
116674
  var emptySourceSpans = /* @__PURE__ */ new Map();
116576
116675
  var emptyHighlightedKeys = /* @__PURE__ */ new Map();
116577
116676
  function useTranscriptTimeline(options) {
@@ -116706,6 +116805,13 @@ function useTranscriptTimeline(options) {
116706
116805
  sourceSpans,
116707
116806
  minimapSelection,
116708
116807
  hasTimeline: timeline.root.content.length > 0 && (timeline.root.content.some((item) => item.type === "span" || item.type === "event" && item.event.event === "span_begin") || timeline.root.branches.length > 0),
116808
+ hasAgentTimeline: visibleRows.some((row) => {
116809
+ if (row.depth < 1) return false;
116810
+ const rowSpan = row.spans[0];
116811
+ if (!rowSpan) return false;
116812
+ const span = getAgents(rowSpan)[0];
116813
+ return !!span && !PHASE_SPAN_TYPES.has(span.spanType ?? "");
116814
+ }),
116709
116815
  timelines,
116710
116816
  activeTimelineIndex,
116711
116817
  setActiveTimeline,
@@ -118106,21 +118212,86 @@ function formatAttemptDuration(event) {
118106
118212
  const sec = attemptDurationSec(event);
118107
118213
  return sec != null ? formatTime$1(sec) : null;
118108
118214
  }
118215
+ var StopReasonBadge_module_default = {
118216
+ section: "_section_8yqw9_1",
118217
+ header: "_header_8yqw9_5",
118218
+ label: "_label_8yqw9_12",
118219
+ badge: "_badge_8yqw9_16",
118220
+ neutral: "_neutral_8yqw9_31",
118221
+ amber: "_amber_8yqw9_36",
118222
+ blue: "_blue_8yqw9_41",
118223
+ rose: "_rose_8yqw9_46",
118224
+ gray: "_gray_8yqw9_51"
118225
+ };
118226
+ //#endregion
118227
+ //#region ../../packages/inspect-components/src/transcript/event/StopReasonBadge.tsx
118228
+ var STOP_TONE = {
118229
+ stop: "neutral",
118230
+ max_tokens: "amber",
118231
+ model_length: "amber",
118232
+ tool_calls: "blue",
118233
+ content_filter: "rose",
118234
+ unknown: "gray"
118235
+ };
118236
+ var TONE_CLASS = {
118237
+ neutral: StopReasonBadge_module_default.neutral,
118238
+ amber: StopReasonBadge_module_default.amber,
118239
+ blue: StopReasonBadge_module_default.blue,
118240
+ rose: StopReasonBadge_module_default.rose,
118241
+ gray: StopReasonBadge_module_default.gray
118242
+ };
118243
+ var detailEntries = (details) => {
118244
+ if (!details) return {};
118245
+ const scalars = {};
118246
+ for (const [k, v] of Object.entries(details)) {
118247
+ if (k === "categories" || typeof v !== "string" || v === "") continue;
118248
+ scalars[k] = v;
118249
+ }
118250
+ const ordered = {};
118251
+ for (const k of ["category", "type"]) if (k in scalars) {
118252
+ ordered[k] = scalars[k];
118253
+ delete scalars[k];
118254
+ }
118255
+ return {
118256
+ ...ordered,
118257
+ ...scalars
118258
+ };
118259
+ };
118260
+ var StopReasonBadge = ({ reason, details }) => {
118261
+ const toneClass = TONE_CLASS[STOP_TONE[reason] ?? "gray"];
118262
+ const entries = detailEntries(details);
118263
+ return /* @__PURE__ */ jsxs("div", {
118264
+ className: StopReasonBadge_module_default.section,
118265
+ children: [/* @__PURE__ */ jsxs("div", {
118266
+ className: StopReasonBadge_module_default.header,
118267
+ children: [/* @__PURE__ */ jsx("span", {
118268
+ className: clsx("text-size-small", "text-style-label", "text-style-secondary", StopReasonBadge_module_default.label),
118269
+ children: "Stop Reason"
118270
+ }), /* @__PURE__ */ jsx("span", {
118271
+ className: clsx(StopReasonBadge_module_default.badge, toneClass),
118272
+ children: reason
118273
+ })]
118274
+ }), Object.keys(entries).length > 0 && /* @__PURE__ */ jsx(MetaDataGrid, {
118275
+ entries,
118276
+ options: { plain: true }
118277
+ })]
118278
+ });
118279
+ };
118109
118280
  var ModelEventView_module_default = {
118110
- container: "_container_v2zov_1",
118111
- all: "_all_v2zov_6",
118112
- tableSelection: "_tableSelection_v2zov_12",
118113
- config: "_config_v2zov_18",
118114
- tools: "_tools_v2zov_22",
118115
- codePre: "_codePre_v2zov_26",
118116
- code: "_code_v2zov_26",
118117
- progress: "_progress_v2zov_38",
118118
- error: "_error_v2zov_42",
118119
- cancelled: "_cancelled_v2zov_53",
118120
- showAllLink: "_showAllLink_v2zov_66",
118121
- showAllIcon: "_showAllIcon_v2zov_77",
118122
- toolConfig: "_toolConfig_v2zov_86",
118123
- toolChoice: "_toolChoice_v2zov_95"
118281
+ container: "_container_2vo8f_1",
118282
+ all: "_all_2vo8f_6",
118283
+ tableSelection: "_tableSelection_2vo8f_12",
118284
+ config: "_config_2vo8f_18",
118285
+ tools: "_tools_2vo8f_22",
118286
+ codePre: "_codePre_2vo8f_26",
118287
+ code: "_code_2vo8f_26",
118288
+ progress: "_progress_2vo8f_38",
118289
+ error: "_error_2vo8f_42",
118290
+ cancelled: "_cancelled_2vo8f_53",
118291
+ showAllLink: "_showAllLink_2vo8f_66",
118292
+ showAllIcon: "_showAllIcon_2vo8f_77",
118293
+ toolConfig: "_toolConfig_2vo8f_86",
118294
+ toolChoice: "_toolChoice_2vo8f_90"
118124
118295
  };
118125
118296
  //#endregion
118126
118297
  //#region ../../packages/inspect-components/src/transcript/ModelEventView.tsx
@@ -118142,12 +118313,6 @@ var ModelEventView = ({ eventNode, showToolCalls, className, context, eventCallb
118142
118313
  const firstChoice = event.output?.choices?.[0];
118143
118314
  const stopDetails = firstChoice?.stop_details;
118144
118315
  const showStopReason = !!firstChoice && (!!stopDetails || firstChoice.stop_reason !== "stop");
118145
- const stopEntries = {};
118146
- if (showStopReason) {
118147
- stopEntries["stop reason"] = firstChoice.stop_reason;
118148
- if (stopDetails?.category) stopEntries["category"] = stopDetails.category;
118149
- if (stopDetails?.explanation) stopEntries["explanation"] = stopDetails.explanation;
118150
- }
118151
118316
  const userMessages = useMemo(() => {
118152
118317
  const result = [];
118153
118318
  if (!!!event.agentResultsFiltered) {
@@ -118239,10 +118404,10 @@ var ModelEventView = ({ eventNode, showToolCalls, className, context, eventCallb
118239
118404
  }) : void 0
118240
118405
  ]
118241
118406
  }),
118242
- /* @__PURE__ */ jsxs("div", {
118243
- "data-name": "All",
118407
+ /* @__PURE__ */ jsx("div", {
118408
+ "data-name": "Info",
118244
118409
  className: ModelEventView_module_default.container,
118245
- children: [/* @__PURE__ */ jsxs("div", {
118410
+ children: /* @__PURE__ */ jsxs("div", {
118246
118411
  className: ModelEventView_module_default.all,
118247
118412
  children: [
118248
118413
  event.output.usage ? /* @__PURE__ */ jsx(ModelUsagePanel, {
@@ -118253,13 +118418,9 @@ var ModelEventView = ({ eventNode, showToolCalls, className, context, eventCallb
118253
118418
  working_time: event.working_time
118254
118419
  }
118255
118420
  }) : void 0,
118256
- Object.keys(stopEntries).length > 0 && /* @__PURE__ */ jsx(EventSection, {
118257
- title: "Stop Reason",
118258
- className: clsx(ModelEventView_module_default.tableSelection, ModelEventView_module_default.config),
118259
- children: /* @__PURE__ */ jsx(MetaDataGrid, {
118260
- entries: stopEntries,
118261
- options: { plain: true }
118262
- })
118421
+ showStopReason && /* @__PURE__ */ jsx(StopReasonBadge, {
118422
+ reason: firstChoice.stop_reason,
118423
+ details: stopDetails
118263
118424
  }),
118264
118425
  Object.keys(entries).length > 0 && /* @__PURE__ */ jsx(EventSection, {
118265
118426
  title: "Configuration",
@@ -118270,15 +118431,17 @@ var ModelEventView = ({ eventNode, showToolCalls, className, context, eventCallb
118270
118431
  })
118271
118432
  })
118272
118433
  ]
118273
- }), /* @__PURE__ */ jsx(EventSection, {
118274
- title: "Messages",
118275
- children: /* @__PURE__ */ jsx(ChatView, {
118276
- id: `${eventNode.id}-model-input-full`,
118277
- messages: [...event.input, ...outputMessages || []],
118278
- tools: { collapseToolMessages: context?.hasToolEvents !== false },
118279
- labels: { show: false }
118280
- })
118281
- })]
118434
+ })
118435
+ }),
118436
+ /* @__PURE__ */ jsx("div", {
118437
+ "data-name": "Messages",
118438
+ className: ModelEventView_module_default.container,
118439
+ children: /* @__PURE__ */ jsx(ChatView, {
118440
+ id: `${eventNode.id}-model-input-full`,
118441
+ messages: [...event.input, ...outputMessages || []],
118442
+ tools: { collapseToolMessages: context?.hasToolEvents !== false },
118443
+ labels: { show: false }
118444
+ })
118282
118445
  }),
118283
118446
  event.tools.length > 1 && /* @__PURE__ */ jsx("div", {
118284
118447
  "data-name": "Tools",
@@ -118338,19 +118501,17 @@ var APICodeCell = ({ id, sourceCode }) => {
118338
118501
  });
118339
118502
  };
118340
118503
  var ToolsConfig = ({ tools, toolChoice }) => {
118341
- const toolEls = tools.map((tool, idx) => {
118342
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
118343
- className: clsx("text-style-label", "text-style-secondary"),
118344
- children: tool.name
118345
- }), /* @__PURE__ */ jsx(ExpandablePanel, {
118346
- id: `config-${tool.name}-${idx}`,
118347
- collapse: true,
118348
- children: /* @__PURE__ */ jsx(MarkdownDiv, { markdown: tool.description })
118349
- })] }, `${tool.name}-${idx}`);
118350
- });
118351
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
118352
- className: clsx(ModelEventView_module_default.toolConfig, "text-size-small"),
118353
- children: toolEls
118504
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(MetaDataGrid, {
118505
+ entries: useMemo(() => {
118506
+ const entries = {};
118507
+ tools.forEach((tool, idx) => {
118508
+ const key = entries[tool.name] === void 0 ? tool.name : `${tool.name} (${idx})`;
118509
+ entries[key] = tool.description;
118510
+ });
118511
+ return entries;
118512
+ }, [tools]),
118513
+ options: { plain: true },
118514
+ className: ModelEventView_module_default.toolConfig
118354
118515
  }), /* @__PURE__ */ jsxs("div", {
118355
118516
  className: clsx(ModelEventView_module_default.toolChoice, "text-size-small"),
118356
118517
  children: [/* @__PURE__ */ jsx("div", {
@@ -120025,14 +120186,14 @@ var scopeMessageLabels = (events, messageLabels) => {
120025
120186
  for (const [id, label] of Object.entries(messageLabels)) if (present.has(id)) scoped[id] = label;
120026
120187
  return Object.keys(scoped).length > 0 ? scoped : void 0;
120027
120188
  };
120028
- var TranscriptLayout = ({ events, hiddenEventTypes, running = false, scrollRef, offsetTop = 0, 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, rightPane, rightPaneScrollRef, eventNodeContext, emptyText = "No events match the current filter", className }) => {
120189
+ var TranscriptLayout = ({ events, hiddenEventTypes, running = false, scrollRef, offsetTop = 0, 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, rightPane, rightPaneScrollRef, eventNodeContext, emptyText = "No events match the current filter", emptyBusy, className }) => {
120029
120190
  const eventsForTimeline = useMemo(() => {
120030
120191
  if (!hiddenEventTypes || hiddenEventTypes.length === 0) return events;
120031
120192
  return events.filter((e) => e.event === "anchor" || !hiddenEventTypes.includes(e.event));
120032
120193
  }, [events, hiddenEventTypes]);
120033
120194
  const timelinesForBranchDetection = useTimelinesArray(eventsForTimeline, serverTimelines);
120034
120195
  const timelineConfig = useTimelineConfig({ branchesPresent: useMemo(() => timelinesForBranchDetection.some((tl) => spanHasBranches(tl.root)), [timelinesForBranchDetection]) });
120035
- const { timeline: timelineData, state: timelineState, layouts: timelineLayouts, rootTimeMapping, selectedEvents, sourceSpans, minimapSelection, hasTimeline, timelines, activeTimelineIndex, setActiveTimeline, regionCounts, branchScrollTarget, highlightedKeys, selectedRowName, viewStack, pushView, popView } = useTranscriptTimeline({
120196
+ const { timeline: timelineData, state: timelineState, layouts: timelineLayouts, rootTimeMapping, selectedEvents, sourceSpans, minimapSelection, hasTimeline, hasAgentTimeline, timelines, activeTimelineIndex, setActiveTimeline, regionCounts, branchScrollTarget, highlightedKeys, selectedRowName, viewStack, pushView, popView } = useTranscriptTimeline({
120036
120197
  events: eventsForTimeline,
120037
120198
  markerConfig: markerConfigOverride ?? timelineConfig.markerConfig,
120038
120199
  timelineOptions: agentConfigOverride ?? timelineConfig.agentConfig,
@@ -120051,10 +120212,11 @@ var TranscriptLayout = ({ events, hiddenEventTypes, running = false, scrollRef,
120051
120212
  ]);
120052
120213
  const swimlanesDefaultCollapsed = useMemo(() => {
120053
120214
  if (showSwimlanesOption === "auto" && !hasTimeline && regionCounts.size === 0) return true;
120054
- return hasTimeline ? false : void 0;
120215
+ if (hasTimeline) return hasAgentTimeline ? false : true;
120055
120216
  }, [
120056
120217
  showSwimlanesOption,
120057
120218
  hasTimeline,
120219
+ hasAgentTimeline,
120058
120220
  regionCounts
120059
120221
  ]);
120060
120222
  const rawEventsForNodes = showSwimlanes ? selectedEvents : events;
@@ -120459,7 +120621,10 @@ var TranscriptLayout = ({ events, hiddenEventTypes, running = false, scrollRef,
120459
120621
  collapsedOutline: collapseState?.outline,
120460
120622
  onCollapseTranscript,
120461
120623
  eventNodeContext: mergedEventNodeContext
120462
- }, effectiveListId) : emptyText !== null ? /* @__PURE__ */ jsx(NoContentsPanel, { text: emptyText }) : null,
120624
+ }, effectiveListId) : emptyText !== null ? /* @__PURE__ */ jsx(NoContentsPanel, {
120625
+ text: emptyText,
120626
+ busy: emptyBusy
120627
+ }) : null,
120463
120628
  rightPane && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", { className: TranscriptLayout_module_default.rightSeparator }), /* @__PURE__ */ jsx(StickyScroll, {
120464
120629
  ref: rightPaneScrollRef,
120465
120630
  scrollRef,
@@ -124983,6 +125148,7 @@ var TranscriptPanel = memo((props) => {
124983
125148
  sampleEpoch
124984
125149
  });
124985
125150
  const filteredEventTypes = useStore((state) => state.sample.eventFilter.filteredTypes);
125151
+ const { isDefaultFilter } = useTranscriptFilter();
124986
125152
  const timelineSelected = useStore((state) => state.sample.timelineSelected);
124987
125153
  const setTimelineSelectedStore = useStore((state) => state.sampleActions.setTimelineSelected);
124988
125154
  const activeTimelineIndex = useStore((state) => state.sample.activeTimelineIndex);
@@ -125181,7 +125347,8 @@ var TranscriptPanel = memo((props) => {
125181
125347
  onSelectedChange: setSelectedScanner
125182
125348
  })
125183
125349
  } : void 0,
125184
- emptyText: filteredEventTypes.length > 0 ? "The currently applied filter hides all events." : void 0
125350
+ emptyText: running && isDefaultFilter ? "Sample is starting" : filteredEventTypes.length > 0 ? "The currently applied filter hides all events." : void 0,
125351
+ emptyBusy: running && isDefaultFilter
125185
125352
  });
125186
125353
  });
125187
125354
  //#endregion
@@ -125285,6 +125452,15 @@ var SampleDisplay = ({ id, scrollRef, showActivity, progress, focusOnLoad }) =>
125285
125452
  urlSampleId,
125286
125453
  urlEpoch
125287
125454
  ]);
125455
+ const chatDisplay = useMemo(() => ({
125456
+ indented: true,
125457
+ formatDateTime
125458
+ }), []);
125459
+ const chatLinking = useMemo(() => ({
125460
+ enabled: isHostedEnvironment(),
125461
+ getMessageUrl
125462
+ }), [getMessageUrl]);
125463
+ const chatTools = useMemo(() => ({ callStyle: "complete" }), []);
125288
125464
  const sampleUsages = usageViewsForSample(`${baseId}-${id}`, sample, evalSpec);
125289
125465
  const sampleMetadatas = metadataViewsForSample(`${baseId}-${id}`, scrollRef, sample);
125290
125466
  const tabsetId = `task-sample-details-tab-${id}`;
@@ -125535,17 +125711,11 @@ var SampleDisplay = ({ id, scrollRef, showActivity, progress, focusOnLoad }) =>
125535
125711
  messages: sampleMessages,
125536
125712
  initialMessageId: sampleDetailNavigation.message,
125537
125713
  offsetTop: stickyOffsetTop,
125538
- display: {
125539
- indented: true,
125540
- formatDateTime
125541
- },
125542
- linking: {
125543
- enabled: isHostedEnvironment(),
125544
- getMessageUrl
125545
- },
125714
+ display: chatDisplay,
125715
+ linking: chatLinking,
125546
125716
  onNativeFindChanged: setNativeFind,
125547
125717
  scrollRef,
125548
- tools: { callStyle: "complete" },
125718
+ tools: chatTools,
125549
125719
  running,
125550
125720
  className: SampleDisplay_module_default.fullWidth
125551
125721
  }, `${baseId}-chat-${id}`)