@bolt-foundry/gambit 0.8.5-rc.6 → 0.8.5

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 (53) hide show
  1. package/CHANGELOG.md +57 -2
  2. package/README.md +16 -7
  3. package/esm/_dnt.polyfills.d.ts +7 -7
  4. package/esm/_dnt.polyfills.d.ts.map +1 -1
  5. package/esm/_dnt.polyfills.js +14 -13
  6. package/esm/deps/jsr.io/@std/path/1.1.4/constants.d.ts +1 -1
  7. package/esm/gambit/simulator-ui/dist/bundle.js +2464 -380
  8. package/esm/gambit/simulator-ui/dist/bundle.js.map +4 -4
  9. package/esm/src/providers/codex.d.ts.map +1 -1
  10. package/esm/src/providers/codex.js +5 -1
  11. package/esm/src/providers/ollama.d.ts.map +1 -1
  12. package/esm/src/providers/ollama.js +57 -0
  13. package/esm/src/providers/openrouter.d.ts.map +1 -1
  14. package/esm/src/providers/openrouter.js +75 -1
  15. package/esm/src/server.d.ts.map +1 -1
  16. package/esm/src/server.js +346 -32
  17. package/esm/src/server_session_store.d.ts.map +1 -1
  18. package/esm/src/server_session_store.js +7 -4
  19. package/esm/src/server_types.d.ts +1 -0
  20. package/esm/src/server_types.d.ts.map +1 -1
  21. package/esm/src/server_ui_routes.d.ts.map +1 -1
  22. package/esm/src/server_ui_routes.js +3 -0
  23. package/esm/src/workspace.d.ts.map +1 -1
  24. package/esm/src/workspace.js +0 -2
  25. package/esm/src/workspace_contract.d.ts +1 -1
  26. package/esm/src/workspace_contract.d.ts.map +1 -1
  27. package/esm/src/workspace_contract.js +2 -1
  28. package/package.json +2 -2
  29. package/script/_dnt.polyfills.d.ts +7 -7
  30. package/script/_dnt.polyfills.d.ts.map +1 -1
  31. package/script/_dnt.polyfills.js +14 -13
  32. package/script/deps/jsr.io/@std/path/1.1.4/constants.d.ts +1 -1
  33. package/script/gambit/simulator-ui/dist/bundle.js +2464 -380
  34. package/script/gambit/simulator-ui/dist/bundle.js.map +4 -4
  35. package/script/src/providers/codex.d.ts.map +1 -1
  36. package/script/src/providers/codex.js +5 -1
  37. package/script/src/providers/ollama.d.ts.map +1 -1
  38. package/script/src/providers/ollama.js +57 -0
  39. package/script/src/providers/openrouter.d.ts.map +1 -1
  40. package/script/src/providers/openrouter.js +75 -1
  41. package/script/src/server.d.ts.map +1 -1
  42. package/script/src/server.js +346 -32
  43. package/script/src/server_session_store.d.ts.map +1 -1
  44. package/script/src/server_session_store.js +7 -4
  45. package/script/src/server_types.d.ts +1 -0
  46. package/script/src/server_types.d.ts.map +1 -1
  47. package/script/src/server_ui_routes.d.ts.map +1 -1
  48. package/script/src/server_ui_routes.js +3 -0
  49. package/script/src/workspace.d.ts.map +1 -1
  50. package/script/src/workspace.js +0 -2
  51. package/script/src/workspace_contract.d.ts +1 -1
  52. package/script/src/workspace_contract.d.ts.map +1 -1
  53. package/script/src/workspace_contract.js +2 -1
@@ -1013,17 +1013,17 @@ var require_react_jsx_runtime_development = __commonJS({
1013
1013
  function isValidElement(object) {
1014
1014
  return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE;
1015
1015
  }
1016
- var React40 = require__(), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React40.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
1016
+ var React41 = require__(), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React41.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
1017
1017
  return null;
1018
1018
  };
1019
- React40 = {
1019
+ React41 = {
1020
1020
  react_stack_bottom_frame: function(callStackForError) {
1021
1021
  return callStackForError();
1022
1022
  }
1023
1023
  };
1024
1024
  var specialPropKeyWarningShown;
1025
1025
  var didWarnAboutElementRef = {};
1026
- var unknownOwnerDebugStack = React40.react_stack_bottom_frame.bind(React40, UnknownOwner)();
1026
+ var unknownOwnerDebugStack = React41.react_stack_bottom_frame.bind(React41, UnknownOwner)();
1027
1027
  var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
1028
1028
  var didWarnAboutKeySpread = {};
1029
1029
  exports.Fragment = REACT_FRAGMENT_TYPE;
@@ -1347,7 +1347,7 @@ var require_react_dom_development = __commonJS({
1347
1347
  return dispatcher;
1348
1348
  }
1349
1349
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
1350
- var React40 = require__(), Internals = {
1350
+ var React41 = require__(), Internals = {
1351
1351
  d: {
1352
1352
  f: noop,
1353
1353
  r: function() {
@@ -1363,7 +1363,7 @@ var require_react_dom_development = __commonJS({
1363
1363
  },
1364
1364
  p: 0,
1365
1365
  findDOMNode: null
1366
- }, REACT_PORTAL_TYPE = Symbol.for("react.portal"), ReactSharedInternals = React40.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
1366
+ }, REACT_PORTAL_TYPE = Symbol.for("react.portal"), ReactSharedInternals = React41.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
1367
1367
  "function" === typeof Map && null != Map.prototype && "function" === typeof Map.prototype.forEach && "function" === typeof Set && null != Set.prototype && "function" === typeof Set.prototype.clear && "function" === typeof Set.prototype.forEach || console.error("React depends on Map and Set built-in types. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills");
1368
1368
  exports.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = Internals;
1369
1369
  exports.createPortal = function(children, container) {
@@ -2718,7 +2718,7 @@ var require_react_dom_client_development = __commonJS({
2718
2718
  "number" === type && getActiveElement(node.ownerDocument) === node || node.defaultValue === "" + value || (node.defaultValue = "" + value);
2719
2719
  }
2720
2720
  function validateOptionProps(element, props) {
2721
- null == props.value && ("object" === typeof props.children && null !== props.children ? React40.Children.forEach(props.children, function(child) {
2721
+ null == props.value && ("object" === typeof props.children && null !== props.children ? React41.Children.forEach(props.children, function(child) {
2722
2722
  null == child || "string" === typeof child || "number" === typeof child || "bigint" === typeof child || didWarnInvalidChild || (didWarnInvalidChild = true, console.error("Cannot infer the option value of complex children. Pass a `value` prop or use a plain string as children to <option>."));
2723
2723
  }) : null == props.dangerouslySetInnerHTML || didWarnInvalidInnerHTML || (didWarnInvalidInnerHTML = true, console.error("Pass a `value` prop if you set dangerouslyInnerHTML so React knows which value should be selected.")));
2724
2724
  null == props.selected || didWarnSelectedSetOnOption || (console.error("Use the `defaultValue` or `value` props on <select> instead of setting `selected` on <option>."), didWarnSelectedSetOnOption = true);
@@ -13575,14 +13575,14 @@ var require_react_dom_client_development = __commonJS({
13575
13575
  container[internalContainerInstanceKey] && (container._reactRootContainer ? console.error("You are calling ReactDOMClient.createRoot() on a container that was previously passed to ReactDOM.render(). This is not supported.") : console.error("You are calling ReactDOMClient.createRoot() on a container that has already been passed to createRoot() before. Instead, call root.render() on the existing root instead if you want to update it."));
13576
13576
  }
13577
13577
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
13578
- var Scheduler = require__2(), React40 = require__(), ReactDOM = require__3(), assign = Object.assign, REACT_LEGACY_ELEMENT_TYPE = Symbol.for("react.element"), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy");
13578
+ var Scheduler = require__2(), React41 = require__(), ReactDOM = require__3(), assign = Object.assign, REACT_LEGACY_ELEMENT_TYPE = Symbol.for("react.element"), REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy");
13579
13579
  Symbol.for("react.scope");
13580
13580
  var REACT_ACTIVITY_TYPE = Symbol.for("react.activity");
13581
13581
  Symbol.for("react.legacy_hidden");
13582
13582
  Symbol.for("react.tracing_marker");
13583
13583
  var REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel");
13584
13584
  Symbol.for("react.view_transition");
13585
- var MAYBE_ITERATOR_SYMBOL = Symbol.iterator, REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), isArrayImpl = Array.isArray, ReactSharedInternals = React40.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, ReactDOMSharedInternals = ReactDOM.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, NotPending = Object.freeze({
13585
+ var MAYBE_ITERATOR_SYMBOL = Symbol.iterator, REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), isArrayImpl = Array.isArray, ReactSharedInternals = React41.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, ReactDOMSharedInternals = ReactDOM.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, NotPending = Object.freeze({
13586
13586
  pending: false,
13587
13587
  data: null,
13588
13588
  method: null,
@@ -16555,7 +16555,7 @@ var require_react_dom_client_development = __commonJS({
16555
16555
  }
16556
16556
  };
16557
16557
  (function() {
16558
- var isomorphicReactPackageVersion = React40.version;
16558
+ var isomorphicReactPackageVersion = React41.version;
16559
16559
  if ("19.2.4" !== isomorphicReactPackageVersion) throw Error('Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + "\n - react-dom: 19.2.4\nLearn more: https://react.dev/warnings/version-mismatch"));
16560
16560
  })();
16561
16561
  "function" === typeof Map && null != Map.prototype && "function" === typeof Map.prototype.forEach && "function" === typeof Set && null != Set.prototype && "function" === typeof Set.prototype.clear && "function" === typeof Set.prototype.forEach || console.error("React depends on Map and Set built-in types. Make sure that you load a polyfill in older browsers. https://react.dev/link/react-polyfills");
@@ -16651,8 +16651,8 @@ var require_client = __commonJS({
16651
16651
  });
16652
16652
 
16653
16653
  // simulator-ui/src/main.tsx
16654
- var import_jsx_runtime43 = __toESM(require_jsx_runtime());
16655
- var import_react40 = __toESM(require__());
16654
+ var import_jsx_runtime44 = __toESM(require_jsx_runtime());
16655
+ var import_react41 = __toESM(require__());
16656
16656
  var import_client = __toESM(require_client());
16657
16657
 
16658
16658
  // simulator-ui/src/DocsPage.tsx
@@ -16675,7 +16675,7 @@ var buildWorkspacePath = (tab, workspaceId, opts) => {
16675
16675
  return `${base}/${encodeURIComponent(runId)}`;
16676
16676
  };
16677
16677
  var parseWorkspaceRoute = (pathname) => {
16678
- const match = pathname.match(/^\/workspaces\/([^/]+)\/(debug|build|test|grade)(?:\/([^/]+))?$/);
16678
+ const match = pathname.match(/^\/workspaces\/([^/]+)\/(debug|build|test|grade|verify)(?:\/([^/]+))?$/);
16679
16679
  if (!match) return null;
16680
16680
  const rawId = decodeURIComponent(match[1]);
16681
16681
  const tab = match[2];
@@ -16714,16 +16714,19 @@ var DEFAULT_WORKSPACE_DEBUG_PATH = buildWorkspacePath("debug");
16714
16714
  var DEFAULT_TEST_PATH = buildWorkspacePath("test");
16715
16715
  var DEFAULT_BUILD_PATH = buildWorkspacePath("build");
16716
16716
  var DEFAULT_GRADE_PATH = buildWorkspacePath("grade");
16717
+ var DEFAULT_VERIFY_PATH = buildWorkspacePath("verify");
16717
16718
  var buildGradePath = (workspaceId, gradeRunId) => buildWorkspacePath("grade", workspaceId, {
16718
16719
  runId: gradeRunId
16719
16720
  });
16720
16721
  var buildTestPath = (workspaceId, runId) => buildWorkspacePath("test", workspaceId, {
16721
16722
  runId
16722
16723
  });
16724
+ var buildVerifyPath = (workspaceId) => buildWorkspacePath("verify", workspaceId);
16723
16725
  var DURABLE_STREAM_PREFIX = "/api/durable-streams/stream/";
16724
16726
  var SIMULATOR_STREAM_ID = "gambit-simulator";
16725
16727
  var WORKSPACE_STREAM_ID = "gambit-workspace";
16726
16728
  var buildTabEnabled = Boolean(window.__GAMBIT_BUILD_TAB_ENABLED__);
16729
+ var verifyTabEnabled = Boolean(window.__GAMBIT_VERIFY_TAB_ENABLED__);
16727
16730
  var workspaceOnboardingEnabled = Boolean(window.__GAMBIT_WORKSPACE_ONBOARDING__);
16728
16731
  var workspaceIdFromWindow = window.__GAMBIT_WORKSPACE_ID__ ?? null;
16729
16732
  var chatAccordionEnabled = Boolean(window.__GAMBIT_CHAT_ACCORDION_ENABLED__);
@@ -17484,6 +17487,27 @@ ${normalizedText}`;
17484
17487
  });
17485
17488
  continue;
17486
17489
  }
17490
+ if (itemType.includes(":")) {
17491
+ const extensionData = Object.hasOwn(item, "data") ? item.data : item;
17492
+ const extensionText = (() => {
17493
+ try {
17494
+ return JSON.stringify(extensionData);
17495
+ } catch {
17496
+ return String(extensionData);
17497
+ }
17498
+ })();
17499
+ if (!extensionText || extensionText === "{}") continue;
17500
+ const outputIndex = typeof payload.output_index === "number" ? String(payload.output_index) : "";
17501
+ const actionScope2 = asString(record.actionCallId) || asString(record.runId);
17502
+ const baseExtensionId = asString(item.id) || asString(payload.item_id) || (outputIndex ? `extension-${outputIndex}` : itemType);
17503
+ upsertReasoning({
17504
+ reasoningId: scopedId(actionScope2, `extension:${baseExtensionId}`),
17505
+ text: `${itemType}: ${extensionText}`,
17506
+ raw: item,
17507
+ mode: "replace"
17508
+ });
17509
+ continue;
17510
+ }
17487
17511
  if (itemType !== "reasoning") continue;
17488
17512
  let text = "";
17489
17513
  const summary = item.summary;
@@ -17620,7 +17644,7 @@ function deriveReasoningByAssistant(traces) {
17620
17644
  }
17621
17645
  return buckets;
17622
17646
  }
17623
- var RESPOND_TOOL_NAME = "gambit_respond";
17647
+ var LEGACY_RESPOND_TOOL_NAME = "gambit_respond";
17624
17648
  var stringifyMessageContent = (value) => {
17625
17649
  if (value === null || value === void 0) return "";
17626
17650
  if (typeof value === "string") return value;
@@ -17641,7 +17665,7 @@ var safeParseJson = (text) => {
17641
17665
  var summarizeRespondMessage = (message) => {
17642
17666
  if (!message || message.role !== "tool") return null;
17643
17667
  const name = typeof message.name === "string" ? message.name : void 0;
17644
- if (name !== RESPOND_TOOL_NAME) return null;
17668
+ if (name !== LEGACY_RESPOND_TOOL_NAME) return null;
17645
17669
  const parsed = safeParseJson(typeof message.content === "string" ? message.content : "");
17646
17670
  const payload = parsed && typeof parsed === "object" ? "payload" in parsed ? parsed.payload : parsed : void 0;
17647
17671
  const status = typeof parsed?.status === "number" ? parsed.status : void 0;
@@ -17683,7 +17707,7 @@ function buildConversationEntries(state) {
17683
17707
  message: {
17684
17708
  role: "assistant",
17685
17709
  content: respondSummary.displayText,
17686
- name: RESPOND_TOOL_NAME
17710
+ name: LEGACY_RESPOND_TOOL_NAME
17687
17711
  },
17688
17712
  feedback: ref ? feedbackByRef.get(ref.id) : void 0,
17689
17713
  respond: {
@@ -17736,6 +17760,12 @@ function normalizeAppPath(input) {
17736
17760
  }
17737
17761
  return DEFAULT_GRADE_PATH;
17738
17762
  }
17763
+ if (trimmed === "/verify") {
17764
+ if (window.location.pathname !== DEFAULT_VERIFY_PATH) {
17765
+ window.history.replaceState({}, "", DEFAULT_VERIFY_PATH);
17766
+ }
17767
+ return DEFAULT_VERIFY_PATH;
17768
+ }
17739
17769
  if (trimmed === "/build") {
17740
17770
  if (window.location.pathname !== DEFAULT_BUILD_PATH) {
17741
17771
  window.history.replaceState({}, "", DEFAULT_BUILD_PATH);
@@ -17748,7 +17778,7 @@ function normalizeAppPath(input) {
17748
17778
  }
17749
17779
  return DEFAULT_WORKSPACE_DEBUG_PATH;
17750
17780
  }
17751
- if (/^\/workspaces\/[^/]+\/(debug|build)$/.test(trimmed) || /^\/workspaces\/[^/]+\/(test|grade)(?:\/[^/]+)?$/.test(trimmed)) {
17781
+ if (/^\/workspaces\/[^/]+\/(debug|build|verify)$/.test(trimmed) || /^\/workspaces\/[^/]+\/(test|grade)(?:\/[^/]+)?$/.test(trimmed)) {
17752
17782
  return trimmed;
17753
17783
  }
17754
17784
  if (trimmed.startsWith("/debug/workspaces/")) {
@@ -17758,7 +17788,7 @@ function normalizeAppPath(input) {
17758
17788
  window.history.replaceState({}, "", next);
17759
17789
  return next;
17760
17790
  }
17761
- if (trimmed.startsWith("/workspaces/") && !trimmed.includes("/debug") && !trimmed.includes("/test") && !trimmed.includes("/grade") && !trimmed.includes("/build") && trimmed !== DEFAULT_WORKSPACE_DEBUG_PATH) {
17791
+ if (trimmed.startsWith("/workspaces/") && !trimmed.includes("/debug") && !trimmed.includes("/test") && !trimmed.includes("/grade") && !trimmed.includes("/build") && !trimmed.includes("/verify") && trimmed !== DEFAULT_WORKSPACE_DEBUG_PATH) {
17762
17792
  const remainder = trimmed.slice("/workspaces/".length);
17763
17793
  if (remainder && remainder !== "new") {
17764
17794
  const decoded = decodeURIComponent(remainder);
@@ -18374,6 +18404,11 @@ code:not(pre *) {
18374
18404
  width: 100%;
18375
18405
  min-height: 0;
18376
18406
  }
18407
+ .verify-shell .verify-layout {
18408
+ grid-template-columns: 320px minmax(0, 1fr);
18409
+ width: 100%;
18410
+ min-height: 0;
18411
+ }
18377
18412
  @media (max-width: 1100px) {
18378
18413
  .calibrate-shell .calibrate-layout {
18379
18414
  grid-template-columns: minmax(0, 1fr);
@@ -18382,6 +18417,9 @@ code:not(pre *) {
18382
18417
  position: static;
18383
18418
  max-height: none;
18384
18419
  }
18420
+ .verify-shell .verify-layout {
18421
+ grid-template-columns: minmax(0, 1fr);
18422
+ }
18385
18423
  }
18386
18424
  .calibrate-shell .calibrate-runner {
18387
18425
  flex: 0 0 auto;
@@ -18391,6 +18429,227 @@ code:not(pre *) {
18391
18429
  min-height: 0;
18392
18430
  overflow-y: auto;
18393
18431
  }
18432
+ .verify-controls {
18433
+ display: flex;
18434
+ flex-direction: column;
18435
+ gap: 12px;
18436
+ }
18437
+ .verify-controls-header {
18438
+ display: flex;
18439
+ flex-direction: column;
18440
+ gap: 4px;
18441
+ }
18442
+ .verify-number-grid {
18443
+ display: grid;
18444
+ grid-template-columns: repeat(2, minmax(0, 1fr));
18445
+ gap: 8px;
18446
+ }
18447
+ .verify-number-field {
18448
+ display: flex;
18449
+ flex-direction: column;
18450
+ gap: 6px;
18451
+ font-size: 12px;
18452
+ color: var(--color-text-muted);
18453
+ font-weight: 600;
18454
+ }
18455
+ .verify-number-field input {
18456
+ border: 1px solid var(--color-border-strong);
18457
+ border-radius: calc(10px * var(--corner-radius-scale, 1));
18458
+ corner-shape: squircle;
18459
+ padding: 6px 8px;
18460
+ background: var(--color-surface);
18461
+ color: var(--color-text);
18462
+ font-size: 13px;
18463
+ }
18464
+ .verify-results {
18465
+ display: flex;
18466
+ flex-direction: column;
18467
+ gap: 12px;
18468
+ min-height: 0;
18469
+ overflow-y: auto;
18470
+ }
18471
+ .verify-status-row {
18472
+ display: flex;
18473
+ flex-wrap: wrap;
18474
+ align-items: flex-start;
18475
+ justify-content: flex-start;
18476
+ gap: 10px;
18477
+ }
18478
+ .verify-status-main {
18479
+ display: flex;
18480
+ flex-direction: column;
18481
+ gap: 4px;
18482
+ }
18483
+ .verify-status-meta {
18484
+ font-size: 12px;
18485
+ color: var(--color-text-muted);
18486
+ }
18487
+ .verify-progress-row {
18488
+ display: flex;
18489
+ flex-wrap: wrap;
18490
+ gap: 8px;
18491
+ font-size: 12px;
18492
+ color: var(--color-text-muted);
18493
+ }
18494
+ .verify-verdict-badge {
18495
+ margin-left: auto;
18496
+ border-radius: calc(10px * var(--corner-radius-scale, 1));
18497
+ corner-shape: squircle;
18498
+ border: 1px solid var(--color-border);
18499
+ padding: 4px 8px;
18500
+ font-size: 11px;
18501
+ font-weight: 700;
18502
+ letter-spacing: 0.02em;
18503
+ }
18504
+ .verify-verdict-badge--pass {
18505
+ background: var(--color-success-soft);
18506
+ border-color: var(--color-success-strong);
18507
+ color: var(--color-success-strong);
18508
+ }
18509
+ .verify-verdict-badge--warn {
18510
+ background: var(--color-warning-soft);
18511
+ border-color: var(--color-warning-border);
18512
+ color: var(--color-warning);
18513
+ }
18514
+ .verify-verdict-badge--fail {
18515
+ background: var(--color-danger-soft);
18516
+ border-color: var(--color-danger-strong);
18517
+ color: var(--color-danger-strong);
18518
+ }
18519
+ .verify-metric-grid {
18520
+ display: grid;
18521
+ grid-template-columns: repeat(2, minmax(0, 1fr));
18522
+ gap: 8px;
18523
+ }
18524
+ @media (max-width: 800px) {
18525
+ .verify-metric-grid {
18526
+ grid-template-columns: minmax(0, 1fr);
18527
+ }
18528
+ }
18529
+ .verify-metric-card {
18530
+ border: 1px solid var(--color-border);
18531
+ border-radius: calc(12px * var(--corner-radius-scale, 1));
18532
+ corner-shape: squircle;
18533
+ padding: 8px;
18534
+ background: var(--color-surface-muted);
18535
+ }
18536
+ .verify-metric-label {
18537
+ font-size: 11px;
18538
+ text-transform: uppercase;
18539
+ letter-spacing: 0.02em;
18540
+ color: var(--color-text-muted);
18541
+ }
18542
+ .verify-metric-value {
18543
+ margin-top: 4px;
18544
+ font-size: 20px;
18545
+ font-weight: 700;
18546
+ color: var(--color-text);
18547
+ }
18548
+ .verify-sample-size-row {
18549
+ display: flex;
18550
+ align-items: center;
18551
+ justify-content: space-between;
18552
+ gap: 8px;
18553
+ flex-wrap: wrap;
18554
+ }
18555
+ .verify-sample-size-copy {
18556
+ display: flex;
18557
+ flex-direction: column;
18558
+ }
18559
+ .verify-sample-size-row .verify-metric-value {
18560
+ margin-top: 4px;
18561
+ }
18562
+ .verify-sample-scope-select {
18563
+ min-width: 170px;
18564
+ }
18565
+ .verify-sample-scope-select .gds-listbox-field-label {
18566
+ display: none;
18567
+ }
18568
+ .verify-metric-value--compact {
18569
+ font-size: 14px;
18570
+ }
18571
+ .verify-section {
18572
+ display: flex;
18573
+ flex-direction: column;
18574
+ gap: 8px;
18575
+ }
18576
+ .verify-section-header {
18577
+ display: flex;
18578
+ align-items: center;
18579
+ justify-content: space-between;
18580
+ gap: 8px;
18581
+ flex-wrap: wrap;
18582
+ }
18583
+ .verify-section-controls {
18584
+ display: flex;
18585
+ align-items: center;
18586
+ gap: 8px;
18587
+ flex-wrap: wrap;
18588
+ }
18589
+ .verify-section-sort {
18590
+ min-width: 150px;
18591
+ }
18592
+ .verify-section-sort .gds-listbox-field-label {
18593
+ display: none;
18594
+ }
18595
+ .verify-outlier-list {
18596
+ display: flex;
18597
+ flex-direction: column;
18598
+ gap: 8px;
18599
+ }
18600
+ .verify-outlier-card {
18601
+ border: 1px solid var(--color-border);
18602
+ border-radius: calc(12px * var(--corner-radius-scale, 1));
18603
+ corner-shape: squircle;
18604
+ padding: 8px;
18605
+ background: var(--color-surface-muted);
18606
+ display: flex;
18607
+ flex-direction: column;
18608
+ gap: 6px;
18609
+ }
18610
+ .verify-outlier-header {
18611
+ display: flex;
18612
+ align-items: center;
18613
+ justify-content: space-between;
18614
+ gap: 8px;
18615
+ }
18616
+ .verify-outlier-meta {
18617
+ font-size: 12px;
18618
+ color: var(--color-text-muted);
18619
+ }
18620
+ .verify-outlier-links {
18621
+ display: flex;
18622
+ flex-wrap: wrap;
18623
+ gap: 8px;
18624
+ font-size: 12px;
18625
+ }
18626
+ .verify-request-list {
18627
+ list-style: none;
18628
+ margin: 0;
18629
+ padding: 0;
18630
+ display: flex;
18631
+ flex-direction: column;
18632
+ gap: 6px;
18633
+ }
18634
+ .verify-request-row {
18635
+ border: 1px solid var(--color-border);
18636
+ border-radius: calc(10px * var(--corner-radius-scale, 1));
18637
+ corner-shape: squircle;
18638
+ padding: 6px 8px;
18639
+ background: var(--color-surface-muted);
18640
+ display: flex;
18641
+ align-items: center;
18642
+ gap: 8px;
18643
+ flex-wrap: wrap;
18644
+ font-size: 12px;
18645
+ }
18646
+ .verify-request-index {
18647
+ color: var(--color-text-muted);
18648
+ min-width: 28px;
18649
+ }
18650
+ .verify-request-error {
18651
+ color: var(--color-danger-strong);
18652
+ }
18394
18653
  .calibrate-run-card {
18395
18654
  border: 1px solid var(--color-border);
18396
18655
  border-radius: calc(14px * var(--corner-radius-scale, 1));
@@ -20110,6 +20369,67 @@ code:not(pre *) {
20110
20369
  .workbench-chat-current.is-history {
20111
20370
  transform: translateX(85%);
20112
20371
  }
20372
+ .workbench-chat-readonly-overlay {
20373
+ position: absolute;
20374
+ inset: 0;
20375
+ z-index: 2;
20376
+ background: rgba(248, 250, 252, 0.88);
20377
+ display: flex;
20378
+ align-items: center;
20379
+ justify-content: center;
20380
+ padding: 16px;
20381
+ }
20382
+ .workbench-chat-readonly-card {
20383
+ background: var(--color-surface);
20384
+ border: 1px solid var(--color-border);
20385
+ border-radius: calc(16px * var(--corner-radius-scale, 1));
20386
+ corner-shape: squircle;
20387
+ box-shadow: 0 12px 30px rgba(15, 23, 42, 0.08);
20388
+ width: 100%;
20389
+ max-width: 640px;
20390
+ padding: 16px;
20391
+ display: flex;
20392
+ flex-direction: column;
20393
+ gap: 10px;
20394
+ text-align: left;
20395
+ }
20396
+ .workbench-chat-readonly-title {
20397
+ margin: 0;
20398
+ font-size: 16px;
20399
+ }
20400
+ .workbench-chat-readonly-copy {
20401
+ margin: 0;
20402
+ font-size: 13px;
20403
+ color: var(--color-text-muted);
20404
+ }
20405
+ .workbench-chat-readonly-actions {
20406
+ display: flex;
20407
+ flex-wrap: wrap;
20408
+ align-items: center;
20409
+ gap: 8px;
20410
+ }
20411
+ .workbench-chat-command-row {
20412
+ display: flex;
20413
+ align-items: flex-start;
20414
+ gap: 8px;
20415
+ }
20416
+ .workbench-chat-command-code {
20417
+ margin: 0;
20418
+ flex: 1;
20419
+ max-width: 100%;
20420
+ padding: 10px 12px;
20421
+ border: 1px solid var(--color-border);
20422
+ border-radius: calc(10px * var(--corner-radius-scale, 1));
20423
+ corner-shape: squircle;
20424
+ background: var(--color-surface-muted);
20425
+ overflow-x: auto;
20426
+ }
20427
+ .workbench-chat-command-code code {
20428
+ font-size: 12px;
20429
+ line-height: 1.4;
20430
+ white-space: pre-wrap;
20431
+ word-break: break-all;
20432
+ }
20113
20433
  .gds-accordion .gds-accordion-open-only {
20114
20434
  display: none;
20115
20435
  }
@@ -20334,6 +20654,23 @@ code:not(pre *) {
20334
20654
  opacity: 0.6;
20335
20655
  cursor: not-allowed;
20336
20656
  }
20657
+ .gds-listbox--size-small .gds-listbox-field-label {
20658
+ margin-bottom: 4px;
20659
+ font-size: 12px;
20660
+ }
20661
+ .gds-listbox--size-small .gds-listbox-trigger {
20662
+ padding: 4px 28px 4px 10px;
20663
+ gap: 0;
20664
+ }
20665
+ .gds-listbox--size-small .gds-listbox-label {
20666
+ font-size: 13px;
20667
+ }
20668
+ .gds-listbox--size-small .gds-listbox-meta {
20669
+ display: none;
20670
+ }
20671
+ .gds-listbox--size-small .gds-listbox-caret {
20672
+ right: 9px;
20673
+ }
20337
20674
  .gds-listbox-label {
20338
20675
  font-weight: 600;
20339
20676
  font-size: 14px;
@@ -21655,26 +21992,42 @@ function formatScoreLabel(score) {
21655
21992
  return score > 0 ? `+${score}` : String(score);
21656
21993
  }
21657
21994
  function formatContextLabel(context) {
21658
- if (context.source === "scenario_run_error") return "Error";
21995
+ if (context.source === "scenario_run_error") return "Scenario error";
21996
+ if (context.source === "grader_run_error") return "Grader error";
21659
21997
  if (context.source === "message_rating") {
21660
21998
  return formatScoreLabel(context.score);
21661
21999
  }
22000
+ if (context.source === "verify_outlier") return "Verify";
21662
22001
  return "Flag";
21663
22002
  }
21664
22003
  function formatContextTooltip(context) {
21665
- if (context.source === "scenario_run_error") return context.error;
21666
- if (context.source === "message_rating") {
21667
- return context.reason?.trim() || `Rating ${formatScoreLabel(context.score)}`;
22004
+ switch (context.source) {
22005
+ case "scenario_run_error":
22006
+ case "grader_run_error":
22007
+ return context.error;
22008
+ case "message_rating":
22009
+ return context.reason?.trim() || `Rating ${formatScoreLabel(context.score)}`;
22010
+ case "grading_flag":
22011
+ case "verify_outlier":
22012
+ return context.message;
22013
+ }
22014
+ }
22015
+ function getVerifyOutlierClass(context) {
22016
+ if (typeof context.instability === "boolean") {
22017
+ return getScoreClass(context.instability ? -1 : 1);
21668
22018
  }
21669
- return context.message;
22019
+ if (typeof context.score === "number" && Number.isFinite(context.score)) {
22020
+ return getScoreClass(context.score);
22021
+ }
22022
+ return getScoreClass(0);
21670
22023
  }
21671
22024
  function WorkbenchComposerChip(props) {
21672
22025
  const { className, context, enabled, onEnabledChange, onRemove, testId, ...rest } = props;
21673
22026
  const label = formatContextLabel(context);
21674
22027
  const tooltip = formatContextTooltip(context);
21675
22028
  const score = "score" in context ? context.score : void 0;
21676
- const badgeClassName = classNames("workbench-context-chip", context.source === "scenario_run_error" && "workbench-context-chip--error", context.source === "grading_flag" && "workbench-context-chip--flag", context.source === "grading_flag" && typeof score === "number" && getScoreClass(score), context.source === "message_rating" && "workbench-context-chip--rating", context.source === "message_rating" && typeof score === "number" && getScoreClass(score));
21677
- const testIds = context.source === "scenario_run_error" ? {
22029
+ const badgeClassName = classNames("workbench-context-chip", (context.source === "scenario_run_error" || context.source === "grader_run_error") && "workbench-context-chip--error", context.source === "grading_flag" && "workbench-context-chip--flag", context.source === "grading_flag" && typeof score === "number" && getScoreClass(score), context.source === "verify_outlier" && "workbench-context-chip--flag", context.source === "verify_outlier" && getVerifyOutlierClass(context), context.source === "message_rating" && "workbench-context-chip--rating", context.source === "message_rating" && typeof score === "number" && getScoreClass(score));
22030
+ const testIds = context.source === "scenario_run_error" || context.source === "grader_run_error" ? {
21678
22031
  badge: "workbench-error-chip",
21679
22032
  toggle: "workbench-error-chip-toggle",
21680
22033
  remove: "workbench-error-chip-remove"
@@ -21685,7 +22038,7 @@ function WorkbenchComposerChip(props) {
21685
22038
  const content = context.source === "grading_flag" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Icon, {
21686
22039
  name: "flag",
21687
22040
  size: 10
21688
- }) : label;
22041
+ }) : context.source === "verify_outlier" ? "Verify" : label;
21689
22042
  if (isPassive) {
21690
22043
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Tooltip, {
21691
22044
  content: tooltip,
@@ -23306,6 +23659,12 @@ function WorkspaceProvider(props) {
23306
23659
  ];
23307
23660
  });
23308
23661
  }
23662
+ if (!data.run) {
23663
+ throw new Error(data.error ?? "Calibration response missing run payload");
23664
+ }
23665
+ if (data.run.status !== "completed") {
23666
+ throw new Error(data.run.error ?? `Calibration run ended with status ${data.run.status}`);
23667
+ }
23309
23668
  setGradeError(null);
23310
23669
  return data;
23311
23670
  } catch (err) {
@@ -23500,6 +23859,9 @@ function useBuildChat() {
23500
23859
  }
23501
23860
 
23502
23861
  // simulator-ui/src/Chat.tsx
23862
+ function isWorkbenchErrorChip(chip) {
23863
+ return chip.source === "scenario_run_error" || chip.source === "grader_run_error";
23864
+ }
23503
23865
  var ERROR_CONTEXT_START_MARKER = "[gambit:error-context/v1]";
23504
23866
  var ERROR_CONTEXT_END_MARKER = "[/gambit:error-context/v1]";
23505
23867
  var WORKBENCH_CONTEXT_START_MARKER = "[gambit:workbench-context/v2]";
@@ -23514,12 +23876,12 @@ function parseWorkbenchContext(value) {
23514
23876
  }
23515
23877
  const workspaceId = typeof record.workspaceId === "string" ? record.workspaceId : void 0;
23516
23878
  const runId = typeof record.runId === "string" ? record.runId : void 0;
23517
- if (record.source === "scenario_run_error") {
23879
+ if (record.source === "scenario_run_error" || record.source === "grader_run_error") {
23518
23880
  if (typeof record.error !== "string" || record.error.trim().length === 0) {
23519
23881
  return null;
23520
23882
  }
23521
23883
  return {
23522
- source: "scenario_run_error",
23884
+ source: record.source,
23523
23885
  workspaceId,
23524
23886
  runId,
23525
23887
  capturedAt: record.capturedAt,
@@ -23557,6 +23919,21 @@ function parseWorkbenchContext(value) {
23557
23919
  message: record.message
23558
23920
  };
23559
23921
  }
23922
+ if (record.source === "verify_outlier") {
23923
+ if (typeof record.outlierKey !== "string" || record.outlierKey.trim().length === 0 || typeof record.message !== "string" || record.message.trim().length === 0) {
23924
+ return null;
23925
+ }
23926
+ return {
23927
+ source: "verify_outlier",
23928
+ workspaceId,
23929
+ runId,
23930
+ capturedAt: record.capturedAt,
23931
+ outlierKey: record.outlierKey,
23932
+ instability: typeof record.instability === "boolean" ? record.instability : void 0,
23933
+ score: typeof record.score === "number" && Number.isFinite(record.score) ? record.score : void 0,
23934
+ message: record.message
23935
+ };
23936
+ }
23560
23937
  return null;
23561
23938
  }
23562
23939
  function decodeLegacyWorkbenchErrorContext(content) {
@@ -23648,7 +24025,7 @@ function UserMessageContent(props) {
23648
24025
  children: decoded.contexts.map((context, index) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(WorkbenchComposerChip, {
23649
24026
  className: "workbench-context-chip--transcript",
23650
24027
  context,
23651
- testId: context.source === "scenario_run_error" ? "workbench-transcript-error-chip" : void 0
24028
+ testId: context.source === "scenario_run_error" ? "workbench-transcript-error-chip" : context.source === "grader_run_error" ? "workbench-transcript-error-chip" : void 0
23652
24029
  }, `${context.source}-${index}`))
23653
24030
  }),
23654
24031
  showBody && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", {
@@ -23811,13 +24188,13 @@ function ChatView(props) {
23811
24188
  return;
23812
24189
  }
23813
24190
  if (!onScenarioErrorChipChange) return;
23814
- const errorChip = next.find((chip) => chip.source === "scenario_run_error");
24191
+ const errorChip = next.find(isWorkbenchErrorChip);
23815
24192
  if (!errorChip) {
23816
24193
  onScenarioErrorChipChange(null);
23817
24194
  return;
23818
24195
  }
23819
24196
  onScenarioErrorChipChange({
23820
- source: "scenario_run_error",
24197
+ source: errorChip.source,
23821
24198
  workspaceId: errorChip.workspaceId,
23822
24199
  runId: errorChip.runId,
23823
24200
  capturedAt: errorChip.capturedAt,
@@ -23835,18 +24212,20 @@ function ChatView(props) {
23835
24212
  const message = chatDraft.trim();
23836
24213
  const activeChips = resolvedComposerChips.filter((chip) => chip.enabled);
23837
24214
  const activeChipIds = new Set(activeChips.map((chip) => chip.chipId));
23838
- const activeContexts = activeChips.map((chip) => {
23839
- if (chip.source === "scenario_run_error") {
23840
- return {
23841
- source: "scenario_run_error",
24215
+ const activeContexts = [];
24216
+ for (const chip of activeChips) {
24217
+ if (isWorkbenchErrorChip(chip)) {
24218
+ activeContexts.push({
24219
+ source: chip.source,
23842
24220
  workspaceId: chip.workspaceId,
23843
24221
  runId: chip.runId,
23844
24222
  capturedAt: chip.capturedAt,
23845
24223
  error: chip.error
23846
- };
24224
+ });
24225
+ continue;
23847
24226
  }
23848
24227
  if (chip.source === "message_rating") {
23849
- return {
24228
+ activeContexts.push({
23850
24229
  source: "message_rating",
23851
24230
  workspaceId: chip.workspaceId,
23852
24231
  runId: chip.runId,
@@ -23856,19 +24235,35 @@ function ChatView(props) {
23856
24235
  statePointer: chip.statePointer,
23857
24236
  score: chip.score,
23858
24237
  reason: chip.reason
23859
- };
24238
+ });
24239
+ continue;
23860
24240
  }
23861
- return {
23862
- source: "grading_flag",
23863
- workspaceId: chip.workspaceId,
23864
- runId: chip.runId,
23865
- capturedAt: chip.capturedAt,
23866
- flagId: chip.flagId,
23867
- refId: chip.refId,
23868
- score: chip.score,
23869
- message: chip.message
23870
- };
23871
- });
24241
+ if (chip.source === "grading_flag") {
24242
+ activeContexts.push({
24243
+ source: "grading_flag",
24244
+ workspaceId: chip.workspaceId,
24245
+ runId: chip.runId,
24246
+ capturedAt: chip.capturedAt,
24247
+ flagId: chip.flagId,
24248
+ refId: chip.refId,
24249
+ score: chip.score,
24250
+ message: chip.message
24251
+ });
24252
+ continue;
24253
+ }
24254
+ if (chip.source === "verify_outlier") {
24255
+ activeContexts.push({
24256
+ source: "verify_outlier",
24257
+ workspaceId: chip.workspaceId,
24258
+ runId: chip.runId,
24259
+ capturedAt: chip.capturedAt,
24260
+ outlierKey: chip.outlierKey,
24261
+ instability: chip.instability,
24262
+ score: chip.score,
24263
+ message: chip.message
24264
+ });
24265
+ }
24266
+ }
23872
24267
  if (!message && activeContexts.length === 0) return;
23873
24268
  const outboundMessage = activeContexts.length > 0 ? encodeWorkbenchMessageWithContext(message, activeContexts) : message;
23874
24269
  setOptimisticUser({
@@ -24201,9 +24596,21 @@ function WorkbenchDrawer(props) {
24201
24596
  const [chatHistoryLoading, setChatHistoryLoading] = (0, import_react28.useState)(false);
24202
24597
  const [chatHistoryError, setChatHistoryError] = (0, import_react28.useState)(null);
24203
24598
  const [copiedStatePath, setCopiedStatePath] = (0, import_react28.useState)(false);
24599
+ const [copiedCodexLoginCommand, setCopiedCodexLoginCommand] = (0, import_react28.useState)(false);
24600
+ const [codexTrustPending, setCodexTrustPending] = (0, import_react28.useState)(false);
24601
+ const [codexTrustError, setCodexTrustError] = (0, import_react28.useState)(null);
24602
+ const [codexTrustSuccess, setCodexTrustSuccess] = (0, import_react28.useState)(null);
24603
+ const [codexWorkspaceWriteEnabled, setCodexWorkspaceWriteEnabled] = (0, import_react28.useState)(null);
24604
+ const [codexWorkspaceLoggedIn, setCodexWorkspaceLoggedIn] = (0, import_react28.useState)(null);
24605
+ const [codexLoginStatusText, setCodexLoginStatusText] = (0, import_react28.useState)(null);
24606
+ const [codexTrustedPath, setCodexTrustedPath] = (0, import_react28.useState)(null);
24607
+ const [codexTrustOverlayDismissed, setCodexTrustOverlayDismissed] = (0, import_react28.useState)(false);
24204
24608
  const initializedChipTrackingRef = (0, import_react28.useRef)(false);
24205
24609
  const seenRatingChipIdsRef = (0, import_react28.useRef)(/* @__PURE__ */ new Set());
24206
24610
  const seenFlagChipIdsRef = (0, import_react28.useRef)(/* @__PURE__ */ new Set());
24611
+ const showCodexTrustOverlay = (codexWorkspaceWriteEnabled === false || codexWorkspaceLoggedIn === false) && !codexTrustOverlayDismissed || Boolean(codexTrustError);
24612
+ const workspaceIdForTrust = (sessionId ?? run.id) || void 0;
24613
+ const codexLoginCommand = codexTrustedPath ? `CODEX_HOME="${codexTrustedPath}/.codex" codex login` : 'CODEX_HOME="<workspace>/.codex" codex login';
24207
24614
  const resolvedStatePath = (0, import_react28.useMemo)(() => {
24208
24615
  if (statePath) return statePath;
24209
24616
  const meta = sessionDetail?.meta;
@@ -24421,9 +24828,49 @@ function WorkbenchDrawer(props) {
24421
24828
  initializedChipTrackingRef.current = false;
24422
24829
  seenRatingChipIdsRef.current.clear();
24423
24830
  seenFlagChipIdsRef.current.clear();
24831
+ setCodexTrustPending(false);
24832
+ setCodexTrustError(null);
24833
+ setCodexTrustSuccess(null);
24834
+ setCodexWorkspaceWriteEnabled(null);
24835
+ setCodexWorkspaceLoggedIn(null);
24836
+ setCodexLoginStatusText(null);
24837
+ setCodexTrustedPath(null);
24838
+ setCopiedCodexLoginCommand(false);
24839
+ setCodexTrustOverlayDismissed(false);
24424
24840
  }, [
24425
24841
  sessionId
24426
24842
  ]);
24843
+ (0, import_react28.useEffect)(() => {
24844
+ if (!open) return;
24845
+ if (!workspaceIdForTrust) return;
24846
+ let canceled = false;
24847
+ setCodexTrustError(null);
24848
+ fetch(`/api/codex/trust-workspace?workspaceId=${encodeURIComponent(workspaceIdForTrust)}`).then(async (response) => {
24849
+ const payload = await response.json();
24850
+ if (!response.ok || payload.ok === false) {
24851
+ throw new Error(payload.error || response.statusText);
24852
+ }
24853
+ if (canceled) return;
24854
+ setCodexWorkspaceWriteEnabled(payload.writeEnabled === true);
24855
+ setCodexWorkspaceLoggedIn(payload.codexLoggedIn === true);
24856
+ setCodexLoginStatusText(typeof payload.codexLoginStatus === "string" ? payload.codexLoginStatus : null);
24857
+ setCodexTrustedPath(typeof payload.trustedPath === "string" ? payload.trustedPath : null);
24858
+ }).catch((err) => {
24859
+ if (canceled) return;
24860
+ setCodexWorkspaceWriteEnabled(null);
24861
+ setCodexWorkspaceLoggedIn(null);
24862
+ setCodexLoginStatusText(null);
24863
+ setCodexTrustError(err instanceof Error ? err.message : String(err));
24864
+ }).finally(() => {
24865
+ if (canceled) return;
24866
+ });
24867
+ return () => {
24868
+ canceled = true;
24869
+ };
24870
+ }, [
24871
+ open,
24872
+ workspaceIdForTrust
24873
+ ]);
24427
24874
  (0, import_react28.useEffect)(() => {
24428
24875
  if (loading) return;
24429
24876
  const currentRatingChipIds = new Set(resolvedFeedbackItems.map(({ entry }) => `rating:${entry.messageRefId}:${entry.id}`));
@@ -24460,18 +24907,20 @@ function WorkbenchDrawer(props) {
24460
24907
  let didChange = false;
24461
24908
  const syncedChips = composerChips.filter((chip) => {
24462
24909
  if (chip.source === "message_rating") {
24910
+ if (!chip.chipId.startsWith("rating:")) return true;
24463
24911
  const stillExists = ratingByChipId.has(chip.chipId);
24464
24912
  if (!stillExists) didChange = true;
24465
24913
  return stillExists;
24466
24914
  }
24467
24915
  if (chip.source === "grading_flag") {
24916
+ if (!chip.chipId.startsWith("flag:")) return true;
24468
24917
  const stillExists = flagByChipId.has(chip.chipId);
24469
24918
  if (!stillExists) didChange = true;
24470
24919
  return stillExists;
24471
24920
  }
24472
24921
  return true;
24473
24922
  }).map((chip) => {
24474
- const latest = chip.source === "message_rating" ? ratingByChipId.get(chip.chipId) : chip.source === "grading_flag" ? flagByChipId.get(chip.chipId) : void 0;
24923
+ const latest = chip.source === "message_rating" && chip.chipId.startsWith("rating:") ? ratingByChipId.get(chip.chipId) : chip.source === "grading_flag" && chip.chipId.startsWith("flag:") ? flagByChipId.get(chip.chipId) : void 0;
24475
24924
  if (!latest) return chip;
24476
24925
  const next = {
24477
24926
  ...chip,
@@ -24539,6 +24988,13 @@ function WorkbenchDrawer(props) {
24539
24988
  }, [
24540
24989
  resolvedStatePath
24541
24990
  ]);
24991
+ const handleCopyCodexLoginCommand = (0, import_react28.useCallback)(() => {
24992
+ navigator.clipboard?.writeText(codexLoginCommand);
24993
+ setCopiedCodexLoginCommand(true);
24994
+ window.setTimeout(() => setCopiedCodexLoginCommand(false), 1200);
24995
+ }, [
24996
+ codexLoginCommand
24997
+ ]);
24542
24998
  (0, import_react28.useEffect)(() => {
24543
24999
  if (!open) return;
24544
25000
  if (!onClose) return;
@@ -24553,6 +25009,55 @@ function WorkbenchDrawer(props) {
24553
25009
  onClose,
24554
25010
  open
24555
25011
  ]);
25012
+ const trustWorkspaceInCodex = (0, import_react28.useCallback)(async () => {
25013
+ setCodexTrustPending(true);
25014
+ setCodexTrustError(null);
25015
+ setCodexTrustSuccess(null);
25016
+ try {
25017
+ const statusResponse = await fetch(`/api/codex/trust-workspace?workspaceId=${encodeURIComponent(workspaceIdForTrust ?? "")}`);
25018
+ const statusPayload = await statusResponse.json();
25019
+ if (!statusResponse.ok || statusPayload.ok === false) {
25020
+ throw new Error(statusPayload.error || statusResponse.statusText);
25021
+ }
25022
+ if (statusPayload.writeEnabled === true && statusPayload.codexLoggedIn === true) {
25023
+ setCodexWorkspaceWriteEnabled(true);
25024
+ setCodexWorkspaceLoggedIn(true);
25025
+ setCodexTrustSuccess("Workspace is already configured for Codex writes.");
25026
+ setCodexTrustOverlayDismissed(true);
25027
+ return;
25028
+ }
25029
+ setCodexWorkspaceWriteEnabled(statusPayload.writeEnabled === true);
25030
+ setCodexWorkspaceLoggedIn(statusPayload.codexLoggedIn === true);
25031
+ setCodexLoginStatusText(typeof statusPayload.codexLoginStatus === "string" ? statusPayload.codexLoginStatus : null);
25032
+ setCodexTrustedPath(typeof statusPayload.trustedPath === "string" ? statusPayload.trustedPath : null);
25033
+ const response = await fetch("/api/codex/trust-workspace", {
25034
+ method: "POST",
25035
+ headers: {
25036
+ "content-type": "application/json"
25037
+ },
25038
+ body: JSON.stringify({
25039
+ workspaceId: workspaceIdForTrust
25040
+ })
25041
+ });
25042
+ const payload = await response.json();
25043
+ if (!response.ok || payload.ok === false) {
25044
+ throw new Error(payload.error || response.statusText);
25045
+ }
25046
+ const trustedPath = typeof payload.trustedPath === "string" ? payload.trustedPath : "workspace";
25047
+ setCodexTrustSuccess(`Codex write enabled for: ${trustedPath}`);
25048
+ setCodexWorkspaceWriteEnabled(payload.writeEnabled === true);
25049
+ setCodexWorkspaceLoggedIn(payload.codexLoggedIn === true);
25050
+ setCodexLoginStatusText(typeof payload.codexLoginStatus === "string" ? payload.codexLoginStatus : null);
25051
+ setCodexTrustedPath(typeof payload.trustedPath === "string" ? payload.trustedPath : null);
25052
+ setCodexTrustOverlayDismissed(payload.codexLoggedIn === true);
25053
+ } catch (err) {
25054
+ setCodexTrustError(err instanceof Error ? err.message : String(err));
25055
+ } finally {
25056
+ setCodexTrustPending(false);
25057
+ }
25058
+ }, [
25059
+ workspaceIdForTrust
25060
+ ]);
24556
25061
  if (!open) return null;
24557
25062
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("aside", {
24558
25063
  className: "workbench-drawer-docked",
@@ -24653,12 +25158,87 @@ function WorkbenchDrawer(props) {
24653
25158
  })
24654
25159
  ]
24655
25160
  }),
24656
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", {
25161
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", {
24657
25162
  className: `workbench-chat-current${chatHistoryOpen ? " is-history" : ""}`,
24658
- children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Chat, {
24659
- composerChips,
24660
- onComposerChipsChange
24661
- })
25163
+ children: [
25164
+ showCodexTrustOverlay && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", {
25165
+ className: "workbench-chat-readonly-overlay",
25166
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", {
25167
+ className: "workbench-chat-readonly-card",
25168
+ children: [
25169
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h3", {
25170
+ className: "workbench-chat-readonly-title",
25171
+ children: "Codex setup required"
25172
+ }),
25173
+ codexWorkspaceWriteEnabled === false && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", {
25174
+ className: "workbench-chat-readonly-copy",
25175
+ children: "Codex write access is disabled for this workspace. Trust this workspace to enable file edits."
25176
+ }),
25177
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", {
25178
+ className: "workbench-chat-readonly-actions",
25179
+ children: codexWorkspaceWriteEnabled === false && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Button, {
25180
+ variant: "primary",
25181
+ onClick: () => trustWorkspaceInCodex(),
25182
+ disabled: codexTrustPending,
25183
+ children: codexTrustPending ? "Trusting..." : "Trust workspace"
25184
+ })
25185
+ }),
25186
+ codexWorkspaceLoggedIn === false && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, {
25187
+ children: [
25188
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", {
25189
+ className: "workbench-chat-readonly-copy",
25190
+ children: "Codex login is required for this workspace."
25191
+ }),
25192
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", {
25193
+ className: "workbench-chat-readonly-copy",
25194
+ children: "Run this in this workspace to authenticate Codex, then restart Gambit."
25195
+ }),
25196
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", {
25197
+ className: "workbench-chat-command-row",
25198
+ children: [
25199
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("pre", {
25200
+ className: "workbench-chat-command-code",
25201
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("code", {
25202
+ children: codexLoginCommand
25203
+ })
25204
+ }),
25205
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(Button, {
25206
+ variant: "secondary",
25207
+ size: "small",
25208
+ onClick: handleCopyCodexLoginCommand,
25209
+ children: [
25210
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Icon, {
25211
+ name: copiedCodexLoginCommand ? "copied" : "copy",
25212
+ size: 14
25213
+ }),
25214
+ copiedCodexLoginCommand ? "Copied" : "Copy"
25215
+ ]
25216
+ })
25217
+ ]
25218
+ })
25219
+ ]
25220
+ }),
25221
+ codexLoginStatusText && !/^not logged in$/i.test(codexLoginStatusText.trim()) && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Callout, {
25222
+ children: codexLoginStatusText
25223
+ }),
25224
+ codexTrustError && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", {
25225
+ className: "error",
25226
+ children: codexTrustError
25227
+ }),
25228
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Button, {
25229
+ variant: "secondary",
25230
+ onClick: () => setCodexTrustOverlayDismissed(true),
25231
+ disabled: codexTrustPending,
25232
+ children: "Dismiss"
25233
+ })
25234
+ ]
25235
+ })
25236
+ }),
25237
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Chat, {
25238
+ composerChips,
25239
+ onComposerChipsChange
25240
+ })
25241
+ ]
24662
25242
  })
24663
25243
  ]
24664
25244
  })
@@ -24672,6 +25252,9 @@ function WorkbenchDrawer(props) {
24672
25252
  content: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", {
24673
25253
  className: "workbench-ratings",
24674
25254
  children: [
25255
+ codexTrustSuccess && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Callout, {
25256
+ children: codexTrustSuccess
25257
+ }),
24675
25258
  showCopyStatePath && handleCopyStatePath && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, {
24676
25259
  children: [
24677
25260
  /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(Button, {
@@ -25140,7 +25723,7 @@ function MessageBubble(props) {
25140
25723
  className: "respond-meta",
25141
25724
  children: [
25142
25725
  /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Badge, {
25143
- children: "gambit_respond"
25726
+ children: "legacy respond envelope"
25144
25727
  }),
25145
25728
  typeof entry.respond?.status === "number" && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Badge, {
25146
25729
  variant: "ghost",
@@ -25253,16 +25836,20 @@ function FeedbackControls(props) {
25253
25836
  const [errorMessage, setErrorMessage] = (0, import_react32.useState)(null);
25254
25837
  const requestSeqRef = (0, import_react32.useRef)(0);
25255
25838
  (0, import_react32.useEffect)(() => {
25256
- setReason(feedback?.reason ?? "");
25257
- if (typeof feedback?.score === "number" || feedback?.reason !== void 0) {
25258
- setStatus("saved");
25259
- } else {
25260
- setStatus("idle");
25839
+ const isEditing = status === "unsaved" || status === "saving";
25840
+ if (!isEditing) {
25841
+ setReason(feedback?.reason ?? "");
25842
+ if (typeof feedback?.score === "number" || feedback?.reason !== void 0) {
25843
+ setStatus("saved");
25844
+ } else {
25845
+ setStatus("idle");
25846
+ }
25847
+ setErrorMessage(null);
25261
25848
  }
25262
- setErrorMessage(null);
25263
25849
  }, [
25264
25850
  feedback?.reason,
25265
- feedback?.score
25851
+ feedback?.score,
25852
+ status
25266
25853
  ]);
25267
25854
  (0, import_react32.useEffect)(() => {
25268
25855
  if (typeof feedback?.score === "number") {
@@ -25963,7 +26550,7 @@ var import_jsx_runtime36 = __toESM(require_jsx_runtime());
25963
26550
  var import_react33 = __toESM(require__());
25964
26551
  var import_react_dom2 = __toESM(require__3());
25965
26552
  function Listbox(props) {
25966
- const { value, options, placeholder = "Select", disabled = false, onChange, label, labelClassName, id } = props;
26553
+ const { value, options, placeholder = "Select", disabled = false, onChange, label, labelClassName, id, popoverMatchTriggerWidth = true, popoverMinWidth, popoverAlign = "left", size = "default" } = props;
25967
26554
  const [open, setOpen] = (0, import_react33.useState)(false);
25968
26555
  const rootRef = (0, import_react33.useRef)(null);
25969
26556
  const triggerRef = (0, import_react33.useRef)(null);
@@ -25983,17 +26570,40 @@ function Listbox(props) {
25983
26570
  options,
25984
26571
  value
25985
26572
  ]);
26573
+ const selectedTriggerMeta = (0, import_react33.useMemo)(() => {
26574
+ if (!selected) return null;
26575
+ if ("triggerMeta" in selected) return selected.triggerMeta ?? null;
26576
+ return selected.meta ?? null;
26577
+ }, [
26578
+ selected
26579
+ ]);
25986
26580
  const updatePopover = (0, import_react33.useCallback)(() => {
25987
26581
  const trigger = triggerRef.current;
25988
26582
  if (!trigger) return;
25989
26583
  const rect = trigger.getBoundingClientRect();
25990
- setPopoverStyle({
26584
+ const style = {
25991
26585
  position: "fixed",
25992
- top: rect.bottom + 6,
25993
- left: rect.left,
25994
- width: rect.width
25995
- });
25996
- }, []);
26586
+ top: rect.bottom + 6
26587
+ };
26588
+ if (popoverMatchTriggerWidth) {
26589
+ style.width = rect.width;
26590
+ } else if (typeof popoverMinWidth === "number" && Number.isFinite(popoverMinWidth)) {
26591
+ style.minWidth = popoverMinWidth;
26592
+ }
26593
+ if (popoverAlign === "right") {
26594
+ style.left = popoverMatchTriggerWidth ? rect.right - rect.width : rect.right;
26595
+ if (!popoverMatchTriggerWidth) {
26596
+ style.transform = "translateX(-100%)";
26597
+ }
26598
+ } else {
26599
+ style.left = rect.left;
26600
+ }
26601
+ setPopoverStyle(style);
26602
+ }, [
26603
+ popoverAlign,
26604
+ popoverMatchTriggerWidth,
26605
+ popoverMinWidth
26606
+ ]);
25997
26607
  (0, import_react33.useLayoutEffect)(() => {
25998
26608
  if (!open) return;
25999
26609
  updatePopover();
@@ -26032,8 +26642,9 @@ function Listbox(props) {
26032
26642
  open,
26033
26643
  updatePopover
26034
26644
  ]);
26645
+ const rootClassName = size === "small" ? "gds-listbox gds-listbox--size-small" : "gds-listbox";
26035
26646
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", {
26036
- className: "gds-listbox",
26647
+ className: rootClassName,
26037
26648
  ref: rootRef,
26038
26649
  children: [
26039
26650
  label && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("label", {
@@ -26054,11 +26665,11 @@ function Listbox(props) {
26054
26665
  ref: triggerRef,
26055
26666
  children: [
26056
26667
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ScrollingText, {
26057
- text: selected?.label ?? placeholder,
26668
+ text: selected?.triggerLabel ?? selected?.label ?? placeholder,
26058
26669
  className: "gds-listbox-label"
26059
26670
  }),
26060
- selected?.meta && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ScrollingText, {
26061
- text: selected.meta,
26671
+ selectedTriggerMeta && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ScrollingText, {
26672
+ text: selectedTriggerMeta,
26062
26673
  className: "gds-listbox-meta"
26063
26674
  }),
26064
26675
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", {
@@ -26176,7 +26787,7 @@ var scenarioRunIdFromCalibrationRun = (run) => {
26176
26787
  const scenarioRunId = meta.scenarioRunId;
26177
26788
  return typeof scenarioRunId === "string" && scenarioRunId.trim().length > 0 ? scenarioRunId : null;
26178
26789
  };
26179
- function GradePage({ setNavActions, onAppPathChange, activeWorkspaceId, onFlagsUpdate, onOptimisticToggleFlag, onOptimisticFlagReason, requestedGradeRunId }) {
26790
+ function GradePage({ setNavActions, onAppPathChange, activeWorkspaceId, onFlagsUpdate, onOptimisticToggleFlag, onOptimisticFlagReason, onAddErrorToWorkbench, requestedGradeRunId }) {
26180
26791
  const workspaceGrade = useWorkspaceGrade();
26181
26792
  const { loading, error, running, graders, sessions, sessionDetail, loadData, loadSessionDetail, runGrader: runGrade, toggleFlag: toggleGradeFlag, updateFlagReason: updateGradeFlagReason } = workspaceGrade;
26182
26793
  const workspaceRouting = useWorkspaceRouting();
@@ -26757,8 +27368,23 @@ function GradePage({ setNavActions, onAppPathChange, activeWorkspaceId, onFlagsU
26757
27368
  gap: 12
26758
27369
  },
26759
27370
  children: [
26760
- error && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", {
26761
- className: "error",
27371
+ error && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Callout, {
27372
+ variant: "danger",
27373
+ title: "Grader run failed",
27374
+ actions: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Button, {
27375
+ variant: "secondary",
27376
+ size: "small",
27377
+ onClick: () => onAddErrorToWorkbench?.({
27378
+ source: "grader_run_error",
27379
+ workspaceId: selectedSessionId ?? activeWorkspaceId ?? void 0,
27380
+ runId: routeGradeRunId ?? expandedRunId ?? void 0,
27381
+ error
27382
+ }),
27383
+ disabled: !onAddErrorToWorkbench,
27384
+ "data-testid": "grade-add-error-to-chat",
27385
+ children: "Add to chat"
27386
+ }),
27387
+ "data-testid": "grade-error-callout",
26762
27388
  children: error
26763
27389
  }),
26764
27390
  loading && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", {
@@ -26769,11 +27395,21 @@ function GradePage({ setNavActions, onAppPathChange, activeWorkspaceId, onFlagsU
26769
27395
  children: [
26770
27396
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", {
26771
27397
  className: "flex-column gap-4",
26772
- children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", {
27398
+ children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", {
26773
27399
  className: "flex-row items-center gap-8",
26774
- children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("strong", {
26775
- children: "Grader runs"
26776
- })
27400
+ children: [
27401
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("strong", {
27402
+ children: "Grader runs"
27403
+ }),
27404
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", {
27405
+ className: "secondary-note",
27406
+ children: [
27407
+ "(",
27408
+ filteredSessionRuns.length,
27409
+ ")"
27410
+ ]
27411
+ })
27412
+ ]
26777
27413
  })
26778
27414
  }),
26779
27415
  runItems.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Callout, {
@@ -27052,8 +27688,23 @@ function GradePage({ setNavActions, onAppPathChange, activeWorkspaceId, onFlagsU
27052
27688
  ]
27053
27689
  })
27054
27690
  }),
27055
- item.error && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", {
27056
- className: "error",
27691
+ item.error && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Callout, {
27692
+ variant: "danger",
27693
+ title: "Grade run failed",
27694
+ actions: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Button, {
27695
+ variant: "secondary",
27696
+ size: "small",
27697
+ onClick: () => onAddErrorToWorkbench?.({
27698
+ source: "grader_run_error",
27699
+ workspaceId: selectedSessionId ?? activeWorkspaceId ?? void 0,
27700
+ runId: item.runId,
27701
+ error: item.error
27702
+ }),
27703
+ disabled: !onAddErrorToWorkbench,
27704
+ "data-testid": "grade-run-add-error-to-chat",
27705
+ children: "Add to chat"
27706
+ }),
27707
+ "data-testid": "grade-run-error-callout",
27057
27708
  children: item.error
27058
27709
  }),
27059
27710
  isOpen && /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", {
@@ -27125,7 +27776,7 @@ var import_react38 = __toESM(require__());
27125
27776
  var import_jsx_runtime40 = __toESM(require_jsx_runtime());
27126
27777
  var import_react37 = __toESM(require__());
27127
27778
  function TestBotChatPanel(props) {
27128
- const { run, runWorkspaceId, runStatusLabel, activeWorkspaceId, requestedRunNotFound, canStart, canRunPersona, hasPersonaSelection, botJsonErrorCount, deckJsonErrorCount, missingBotInput, missingDeckInit, lastInitFill, isUserStart, showStartOverlay, canStartAssistant, canSendChat, chatDraft, setChatDraft, chatError, optimisticUser, streamingUser, streamingAssistant, startRun, stopRun, handleNewChat, handleSendChat, handleStartAssistant, onScore, onReasonChange, onAddScenarioErrorToWorkbench } = props;
27779
+ const { run, runWorkspaceId, runStatusLabel, activeWorkspaceId, requestedRunNotFound, canStart, canRunPersona, hasPersonaSelection, botJsonErrorCount, deckJsonErrorCount, missingBotInput, missingDeckInit, lastInitFill, isUserStart, showStartOverlay, canStartAssistant, canSendChat, chatDraft, setChatDraft, chatError, optimisticUser, streamingUser, streamingAssistant, startRun, stopRun, handleNewChat, handleSendChat, handleStartAssistant, onScore, onReasonChange, onAddErrorToWorkbench } = props;
27129
27780
  const transcriptRef = (0, import_react37.useRef)(null);
27130
27781
  const lastRunMessageCountRef = (0, import_react37.useRef)(0);
27131
27782
  (0, import_react37.useEffect)(() => {
@@ -27333,12 +27984,13 @@ function TestBotChatPanel(props) {
27333
27984
  actions: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Button, {
27334
27985
  variant: "secondary",
27335
27986
  size: "small",
27336
- onClick: () => onAddScenarioErrorToWorkbench?.({
27987
+ onClick: () => onAddErrorToWorkbench?.({
27988
+ source: "scenario_run_error",
27337
27989
  workspaceId: runWorkspaceId ?? activeWorkspaceId ?? void 0,
27338
27990
  runId: run.id,
27339
27991
  error: run.error
27340
27992
  }),
27341
- disabled: !onAddScenarioErrorToWorkbench,
27993
+ disabled: !onAddErrorToWorkbench,
27342
27994
  "data-testid": "testbot-add-error-to-chat",
27343
27995
  children: "Add to chat"
27344
27996
  }),
@@ -27416,7 +28068,7 @@ function TestBotChatPanel(props) {
27416
28068
  className: "respond-meta",
27417
28069
  children: [
27418
28070
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Badge, {
27419
- children: "gambit_respond"
28071
+ children: "legacy respond envelope"
27420
28072
  }),
27421
28073
  typeof message.respondStatus === "number" && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Badge, {
27422
28074
  variant: "ghost",
@@ -27624,7 +28276,7 @@ var getScenarioTitle2 = (summary, opts) => {
27624
28276
  return fromDeckCatalogById ?? fromDeckCatalogByPath ?? fromDeckLabel ?? fromDeckId ?? fromPath ?? summary.runId;
27625
28277
  };
27626
28278
  function TestBotPage(props) {
27627
- const { onReplaceTestBotSession, onResetTestBotSession, activeWorkspaceId, requestedRunId, resetToken, setNavActions, onFeedbackPersisted, onAddScenarioErrorToWorkbench } = props;
28279
+ const { onReplaceTestBotSession, onResetTestBotSession, activeWorkspaceId, requestedRunId, resetToken, setNavActions, onFeedbackPersisted, onAddErrorToWorkbench } = props;
27628
28280
  const deckStorageKey = "gambit:test:selected-deck";
27629
28281
  const [testDecks, setTestDecks] = (0, import_react38.useState)([]);
27630
28282
  const [selectedDeckId, setSelectedDeckId] = (0, import_react38.useState)(null);
@@ -28746,7 +29398,7 @@ function TestBotPage(props) {
28746
29398
  handleStartAssistant,
28747
29399
  onScore: handleTestBotScore,
28748
29400
  onReasonChange: handleTestBotReason,
28749
- onAddScenarioErrorToWorkbench
29401
+ onAddErrorToWorkbench
28750
29402
  })
28751
29403
  ]
28752
29404
  })
@@ -29147,103 +29799,1421 @@ function BuildPage(props) {
29147
29799
  });
29148
29800
  }
29149
29801
 
29150
- // simulator-ui/src/main.tsx
29151
- var globalStyleEl = document.createElement("style");
29152
- globalStyleEl.textContent = globalStyles;
29153
- document.head.appendChild(globalStyleEl);
29154
- function useSimulator() {
29155
- const [connectionStatus, setConnectionStatus] = (0, import_react40.useState)("connecting");
29156
- const [savedState, setSavedState] = (0, import_react40.useState)(null);
29157
- const [traceEvents, setTraceEvents] = (0, import_react40.useState)([]);
29158
- const [errors, setErrors] = (0, import_react40.useState)([]);
29159
- const [streamText, setStreamText] = (0, import_react40.useState)("");
29160
- const [isRunning, setIsRunning] = (0, import_react40.useState)(false);
29161
- const [connectSeq, setConnectSeq] = (0, import_react40.useState)(0);
29162
- (0, import_react40.useEffect)(() => {
29163
- const streamId = SIMULATOR_STREAM_ID;
29164
- const streamUrl = buildDurableStreamUrl(streamId, getDurableStreamOffset(streamId));
29165
- const source = new EventSource(streamUrl);
29166
- setConnectionStatus("connecting");
29167
- source.onopen = () => {
29168
- setConnectionStatus("connected");
29169
- setErrors([]);
29802
+ // simulator-ui/src/VerifyPage.tsx
29803
+ var import_jsx_runtime43 = __toESM(require_jsx_runtime());
29804
+ var import_react40 = __toESM(require__());
29805
+
29806
+ // simulator-ui/src/verify_metrics.ts
29807
+ var VERIFY_CONSISTENCY_THRESHOLDS = {
29808
+ minSampleSize: 6,
29809
+ instabilityScoreDelta: 1.5,
29810
+ pass: {
29811
+ agreementMin: 0.9,
29812
+ maxSpread: 1,
29813
+ maxInstabilityCount: 0
29814
+ },
29815
+ warn: {
29816
+ agreementMin: 0.75,
29817
+ maxSpread: 2,
29818
+ maxInstabilityCount: 2
29819
+ }
29820
+ };
29821
+ var pickPayload = (result) => {
29822
+ if (!result || typeof result !== "object") return {};
29823
+ const record = result;
29824
+ if (record.payload && typeof record.payload === "object" && !Array.isArray(record.payload)) {
29825
+ return record.payload;
29826
+ }
29827
+ return record;
29828
+ };
29829
+ var extractScoreReasonPass = (result) => {
29830
+ const payload = pickPayload(result);
29831
+ const score = typeof payload.score === "number" && Number.isFinite(payload.score) ? payload.score : void 0;
29832
+ const reason = typeof payload.reason === "string" ? payload.reason : void 0;
29833
+ if (typeof payload.pass === "boolean") {
29834
+ return {
29835
+ score,
29836
+ reason,
29837
+ pass: payload.pass
29170
29838
  };
29171
- source.onerror = () => {
29172
- setConnectionStatus("error");
29173
- setErrors((prev) => prev.includes("Stream connection error") ? prev : [
29174
- ...prev,
29175
- "Stream connection error"
29176
- ]);
29177
- setIsRunning(false);
29178
- setStreamText("");
29839
+ }
29840
+ if (typeof payload.passed === "boolean") {
29841
+ return {
29842
+ score,
29843
+ reason,
29844
+ pass: payload.passed
29179
29845
  };
29180
- const handleMessage = (event) => {
29181
- let msg = null;
29182
- try {
29183
- msg = JSON.parse(event.data);
29184
- } catch (err) {
29185
- console.error("[sim] failed to parse stream event payload", err);
29186
- return;
29187
- }
29188
- const parsedOffset = Number(event.lastEventId);
29189
- if (Number.isFinite(parsedOffset)) {
29190
- setDurableStreamOffset(streamId, parsedOffset + 1);
29191
- }
29192
- if (!msg || typeof msg !== "object") return;
29193
- if (msg.type === "state") {
29194
- setSavedState(msg.state);
29195
- if (Array.isArray(msg.state.traces)) {
29196
- setTraceEvents(msg.state.traces);
29197
- }
29198
- } else if (msg.type === "stream") {
29199
- if (typeof msg.chunk === "string" && msg.chunk.length > 0) {
29200
- setStreamText((prev) => prev + msg.chunk);
29201
- }
29202
- } else if (msg.type === "result") {
29203
- setIsRunning(false);
29204
- setStreamText("");
29205
- } else if (msg.type === "trace" && msg.event) {
29206
- setTraceEvents((prev) => [
29207
- ...prev,
29208
- msg.event
29209
- ].slice(-200));
29210
- } else if (msg.type === "error") {
29211
- const message = msg.message ?? "Unknown error";
29212
- setErrors((prev) => [
29213
- ...prev,
29214
- message
29215
- ]);
29216
- if (msg.runId || message !== "Run already in progress") {
29217
- setIsRunning(false);
29218
- }
29219
- setStreamText("");
29220
- }
29846
+ }
29847
+ if (typeof payload.verdict === "string") {
29848
+ const verdict = payload.verdict.trim().toLowerCase();
29849
+ if (verdict === "pass") return {
29850
+ score,
29851
+ reason,
29852
+ pass: true
29221
29853
  };
29222
- const simulatorEventTypes = [
29223
- "ready",
29224
- "pong",
29225
- "stream",
29226
- "result",
29227
- "trace",
29228
- "state",
29229
- "error"
29230
- ];
29231
- for (const type of simulatorEventTypes) {
29232
- source.addEventListener(type, handleMessage);
29854
+ if (verdict === "fail") return {
29855
+ score,
29856
+ reason,
29857
+ pass: false
29858
+ };
29859
+ }
29860
+ if (typeof score === "number") {
29861
+ return {
29862
+ score,
29863
+ reason,
29864
+ pass: score >= 0
29865
+ };
29866
+ }
29867
+ return {
29868
+ score,
29869
+ reason
29870
+ };
29871
+ };
29872
+ var flattenRunExamples = (run) => {
29873
+ if (!run.result || typeof run.result !== "object") return [];
29874
+ const record = run.result;
29875
+ if (record.mode === "turns" && Array.isArray(record.turns)) {
29876
+ const buckets = [];
29877
+ record.turns.forEach((turn, fallbackIndex) => {
29878
+ if (!turn || typeof turn !== "object") return;
29879
+ const turnRecord = turn;
29880
+ const index = typeof turnRecord.index === "number" && Number.isFinite(turnRecord.index) ? Math.max(0, Math.round(turnRecord.index)) : fallbackIndex;
29881
+ const messageRefId = typeof turnRecord.messageRefId === "string" && turnRecord.messageRefId.trim().length > 0 ? turnRecord.messageRefId : void 0;
29882
+ const key = messageRefId ? `ref:${messageRefId}` : `turn:${index}`;
29883
+ const label = `Assistant turn ${fallbackIndex + 1}`;
29884
+ const parsed2 = extractScoreReasonPass(turnRecord.result);
29885
+ buckets.push({
29886
+ key,
29887
+ label,
29888
+ points: [
29889
+ {
29890
+ runId: run.id,
29891
+ runAt: run.runAt,
29892
+ score: parsed2.score,
29893
+ pass: parsed2.pass,
29894
+ reason: parsed2.reason,
29895
+ turnIndex: index,
29896
+ messageRefId
29897
+ }
29898
+ ]
29899
+ });
29900
+ });
29901
+ return buckets;
29902
+ }
29903
+ const parsed = extractScoreReasonPass(run.result);
29904
+ return [
29905
+ {
29906
+ key: "conversation",
29907
+ label: "Conversation score",
29908
+ points: [
29909
+ {
29910
+ runId: run.id,
29911
+ runAt: run.runAt,
29912
+ score: parsed.score,
29913
+ pass: parsed.pass,
29914
+ reason: parsed.reason
29915
+ }
29916
+ ]
29233
29917
  }
29234
- return () => {
29235
- for (const type of simulatorEventTypes) {
29236
- source.removeEventListener(type, handleMessage);
29237
- }
29238
- source.close();
29239
- setConnectionStatus("closed");
29240
- setIsRunning(false);
29241
- setStreamText("");
29918
+ ];
29919
+ };
29920
+ var median = (values) => {
29921
+ if (!values.length) return null;
29922
+ const sorted = [
29923
+ ...values
29924
+ ].sort((a, b) => a - b);
29925
+ const mid = Math.floor(sorted.length / 2);
29926
+ if (sorted.length % 2 === 1) return sorted[mid];
29927
+ return (sorted[mid - 1] + sorted[mid]) / 2;
29928
+ };
29929
+ var round2 = (value) => Math.round(value * 100) / 100;
29930
+ var resolveVerdict = (input) => {
29931
+ const t = VERIFY_CONSISTENCY_THRESHOLDS;
29932
+ if (input.sampleSize < t.minSampleSize) {
29933
+ return {
29934
+ verdict: "WARN",
29935
+ reason: `Need at least ${t.minSampleSize} samples before issuing a firm verdict.`
29242
29936
  };
29243
- }, [
29937
+ }
29938
+ if (input.agreementRate === null) {
29939
+ return {
29940
+ verdict: "WARN",
29941
+ reason: "No comparable pass/fail evidence was found in the sampled runs."
29942
+ };
29943
+ }
29944
+ const spreadMax = input.spreadMax ?? 0;
29945
+ if (input.agreementRate >= t.pass.agreementMin && spreadMax <= t.pass.maxSpread && input.instabilityCount <= t.pass.maxInstabilityCount) {
29946
+ return {
29947
+ verdict: "PASS",
29948
+ reason: "Agreement, spread, and instability all meet PASS thresholds."
29949
+ };
29950
+ }
29951
+ if (input.agreementRate >= t.warn.agreementMin && spreadMax <= t.warn.maxSpread && input.instabilityCount <= t.warn.maxInstabilityCount) {
29952
+ return {
29953
+ verdict: "WARN",
29954
+ reason: "Some variation was detected, but results remain within WARN thresholds."
29955
+ };
29956
+ }
29957
+ return {
29958
+ verdict: "FAIL",
29959
+ reason: "Agreement/spread instability exceeds WARN thresholds."
29960
+ };
29961
+ };
29962
+ function buildVerifyConsistencyReport(runs) {
29963
+ const completedRuns = runs.filter((run) => run.status === "completed");
29964
+ const sampleSize = completedRuns.length;
29965
+ const bucketsByKey = /* @__PURE__ */ new Map();
29966
+ completedRuns.forEach((run) => {
29967
+ flattenRunExamples(run).forEach((entry) => {
29968
+ const existing = bucketsByKey.get(entry.key);
29969
+ if (!existing) {
29970
+ bucketsByKey.set(entry.key, {
29971
+ key: entry.key,
29972
+ label: entry.label,
29973
+ points: [
29974
+ ...entry.points
29975
+ ]
29976
+ });
29977
+ return;
29978
+ }
29979
+ existing.points.push(...entry.points);
29980
+ });
29981
+ });
29982
+ const outliers = [];
29983
+ let agreementVotes = 0;
29984
+ let agreementTotal = 0;
29985
+ const scoreDeltas = [];
29986
+ bucketsByKey.forEach((bucket) => {
29987
+ const scores = bucket.points.map((point) => point.score).filter((score) => typeof score === "number" && Number.isFinite(score));
29988
+ const minScore = scores.length ? Math.min(...scores) : null;
29989
+ const maxScore = scores.length ? Math.max(...scores) : null;
29990
+ const scoreDelta = minScore !== null && maxScore !== null ? round2(maxScore - minScore) : null;
29991
+ const passVotes = bucket.points.map((point) => point.pass).filter((pass) => typeof pass === "boolean");
29992
+ const passCount = passVotes.filter((value) => value).length;
29993
+ const failCount = passVotes.length - passCount;
29994
+ const agreementRate2 = passVotes.length > 0 ? round2(Math.max(passCount, failCount) / passVotes.length) : null;
29995
+ if (passVotes.length > 0) {
29996
+ agreementVotes += Math.max(passCount, failCount);
29997
+ agreementTotal += passVotes.length;
29998
+ }
29999
+ if (scoreDelta !== null) {
30000
+ scoreDeltas.push(scoreDelta);
30001
+ }
30002
+ const passFlip = passCount > 0 && failCount > 0;
30003
+ const instability = passFlip || scoreDelta !== null && scoreDelta > VERIFY_CONSISTENCY_THRESHOLDS.instabilityScoreDelta;
30004
+ const minPoint = minScore === null ? void 0 : bucket.points.find((point) => point.score === minScore);
30005
+ const maxPoint = maxScore === null ? void 0 : bucket.points.find((point) => point.score === maxScore);
30006
+ outliers.push({
30007
+ key: bucket.key,
30008
+ label: bucket.label,
30009
+ sampleSize: bucket.points.length,
30010
+ agreementRate: agreementRate2,
30011
+ scoreDelta,
30012
+ passFlip,
30013
+ instability,
30014
+ minScore,
30015
+ maxScore,
30016
+ minRunId: minPoint?.runId,
30017
+ maxRunId: maxPoint?.runId,
30018
+ turnIndex: maxPoint?.turnIndex ?? minPoint?.turnIndex,
30019
+ messageRefId: maxPoint?.messageRefId ?? minPoint?.messageRefId
30020
+ });
30021
+ });
30022
+ outliers.sort((a, b) => {
30023
+ if (a.instability !== b.instability) return a.instability ? -1 : 1;
30024
+ if (a.passFlip !== b.passFlip) return a.passFlip ? -1 : 1;
30025
+ const aDelta = a.scoreDelta ?? -1;
30026
+ const bDelta = b.scoreDelta ?? -1;
30027
+ if (aDelta !== bDelta) return bDelta - aDelta;
30028
+ if (a.sampleSize !== b.sampleSize) return b.sampleSize - a.sampleSize;
30029
+ return a.label.localeCompare(b.label);
30030
+ });
30031
+ const agreementRate = agreementTotal > 0 ? round2(agreementVotes / agreementTotal) : null;
30032
+ const scoreSpreadMin = scoreDeltas.length ? Math.min(...scoreDeltas) : null;
30033
+ const scoreSpreadMax = scoreDeltas.length ? Math.max(...scoreDeltas) : null;
30034
+ const scoreSpreadMedian = median(scoreDeltas);
30035
+ const instabilityCount = outliers.filter((entry) => entry.instability).length;
30036
+ const verdict = resolveVerdict({
30037
+ sampleSize,
30038
+ agreementRate,
30039
+ spreadMax: scoreSpreadMax,
30040
+ instabilityCount
30041
+ });
30042
+ return {
30043
+ sampleSize,
30044
+ comparableExampleCount: outliers.length,
30045
+ agreementRate,
30046
+ scoreSpreadMin: scoreSpreadMin === null ? null : round2(scoreSpreadMin),
30047
+ scoreSpreadMedian: scoreSpreadMedian === null ? null : round2(scoreSpreadMedian),
30048
+ scoreSpreadMax: scoreSpreadMax === null ? null : round2(scoreSpreadMax),
30049
+ instabilityCount,
30050
+ verdict: verdict.verdict,
30051
+ verdictReason: verdict.reason,
30052
+ outliers
30053
+ };
30054
+ }
30055
+
30056
+ // simulator-ui/src/VerifyPage.tsx
30057
+ var MAX_BATCH_SIZE = 24;
30058
+ var MAX_BATCH_CONCURRENCY = 6;
30059
+ var DEFAULT_BATCH_SIZE = 8;
30060
+ var DEFAULT_BATCH_CONCURRENCY = 3;
30061
+ var NO_SCENARIO_RUN_VALUE = "__workspace_context__";
30062
+ var parseScenarioRunSummary2 = (value) => {
30063
+ if (!value || typeof value !== "object") return null;
30064
+ const summary = value;
30065
+ const scenarioRunId = typeof summary.scenarioRunId === "string" ? summary.scenarioRunId : null;
30066
+ if (!scenarioRunId) return null;
30067
+ return {
30068
+ scenarioRunId,
30069
+ lastEventSeq: typeof summary.lastEventSeq === "number" && Number.isFinite(summary.lastEventSeq) ? summary.lastEventSeq : void 0,
30070
+ updatedAt: typeof summary.updatedAt === "string" ? summary.updatedAt : void 0,
30071
+ selectedScenarioDeckId: typeof summary.selectedScenarioDeckId === "string" ? summary.selectedScenarioDeckId : void 0,
30072
+ selectedScenarioDeckLabel: typeof summary.selectedScenarioDeckLabel === "string" ? summary.selectedScenarioDeckLabel : void 0,
30073
+ scenarioConfigPath: typeof summary.scenarioConfigPath === "string" ? summary.scenarioConfigPath : void 0
30074
+ };
30075
+ };
30076
+ var getScenarioTitle3 = (summary) => {
30077
+ const fromDeckLabel = typeof summary.selectedScenarioDeckLabel === "string" && summary.selectedScenarioDeckLabel.trim().length > 0 ? summary.selectedScenarioDeckLabel : null;
30078
+ const fromDeckId = typeof summary.selectedScenarioDeckId === "string" && summary.selectedScenarioDeckId.trim().length > 0 ? scenarioNameFromValue(summary.selectedScenarioDeckId) ?? summary.selectedScenarioDeckId : null;
30079
+ const fromPath = scenarioNameFromValue(summary.scenarioConfigPath ?? null) ?? botFilename(summary.scenarioConfigPath ?? null);
30080
+ return fromDeckLabel ?? fromDeckId ?? fromPath ?? summary.scenarioRunId;
30081
+ };
30082
+ var scenarioRunIdFromCalibrationRun2 = (run) => {
30083
+ if (!run.input || typeof run.input !== "object") return null;
30084
+ const input = run.input;
30085
+ const session = input.session;
30086
+ if (!session || typeof session !== "object") return null;
30087
+ const meta = session.meta;
30088
+ if (!meta || typeof meta !== "object") return null;
30089
+ const scenarioRunId = meta.scenarioRunId;
30090
+ return typeof scenarioRunId === "string" && scenarioRunId.trim().length > 0 ? scenarioRunId : null;
30091
+ };
30092
+ var parseRunAt = (run) => {
30093
+ const parsed = Date.parse(run.runAt ?? "");
30094
+ return Number.isFinite(parsed) ? parsed : -1;
30095
+ };
30096
+ var clampInt = (value, min, max) => {
30097
+ const rounded = Number.isFinite(value) ? Math.round(value) : min;
30098
+ return Math.max(min, Math.min(max, rounded));
30099
+ };
30100
+ var formatSignedScore = (value) => {
30101
+ if (typeof value !== "number" || !Number.isFinite(value)) return "\u2014";
30102
+ return `${value > 0 ? "+" : ""}${value}`;
30103
+ };
30104
+ var scoreBadgeVariant = (value) => {
30105
+ if (typeof value !== "number" || !Number.isFinite(value)) return "ghost";
30106
+ if (value < 0) return "error";
30107
+ if (value > 0) return "completed";
30108
+ return "idle";
30109
+ };
30110
+ function VerifyPage({ setNavActions, onAppPathChange, activeWorkspaceId, composerChips, onComposerChipsChange }) {
30111
+ const { loading, error, graders, sessions, sessionDetail, loadData, loadSessionDetail } = useWorkspaceGrade();
30112
+ const workspaceRouting = useWorkspaceRouting();
30113
+ const [selectedSessionId, setSelectedSessionId] = (0, import_react40.useState)(activeWorkspaceId ?? null);
30114
+ const [selectedGraderId, setSelectedGraderId] = (0, import_react40.useState)(null);
30115
+ const [selectedScenarioRunId, setSelectedScenarioRunId] = (0, import_react40.useState)(null);
30116
+ const [batchSize, setBatchSize] = (0, import_react40.useState)(DEFAULT_BATCH_SIZE);
30117
+ const [batchConcurrency, setBatchConcurrency] = (0, import_react40.useState)(DEFAULT_BATCH_CONCURRENCY);
30118
+ const [batchState, setBatchState] = (0, import_react40.useState)({
30119
+ batchId: 0,
30120
+ status: "idle",
30121
+ requested: 0,
30122
+ concurrency: 0,
30123
+ completed: 0,
30124
+ failed: 0,
30125
+ active: 0,
30126
+ initialRunIds: [],
30127
+ requests: []
30128
+ });
30129
+ const [reportScope, setReportScope] = (0, import_react40.useState)("all_matching");
30130
+ const [inconsistentOnly, setInconsistentOnly] = (0, import_react40.useState)(false);
30131
+ const [exampleSort, setExampleSort] = (0, import_react40.useState)("default");
30132
+ const batchSeqRef = (0, import_react40.useRef)(0);
30133
+ const updateVerifyPath = (0, import_react40.useCallback)((sessionId) => {
30134
+ const targetPath = buildVerifyPath(sessionId);
30135
+ if (window.location.pathname === targetPath) return;
30136
+ window.history.replaceState({}, "", targetPath);
30137
+ onAppPathChange?.(targetPath);
30138
+ }, [
30139
+ onAppPathChange
30140
+ ]);
30141
+ const navigateToAppPath = (0, import_react40.useCallback)((nextPath) => {
30142
+ if (window.location.pathname === nextPath) return;
30143
+ window.history.pushState({}, "", nextPath);
30144
+ onAppPathChange?.(nextPath);
30145
+ }, [
30146
+ onAppPathChange
30147
+ ]);
30148
+ const handleInternalLinkClick = (0, import_react40.useCallback)((event, href) => {
30149
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) {
30150
+ return;
30151
+ }
30152
+ event.preventDefault();
30153
+ navigateToAppPath(href);
30154
+ }, [
30155
+ navigateToAppPath
30156
+ ]);
30157
+ const loadVerifyData = (0, import_react40.useCallback)(async () => {
30158
+ await loadData({
30159
+ workspaceId: activeWorkspaceId ?? null
30160
+ });
30161
+ }, [
30162
+ activeWorkspaceId,
30163
+ loadData
30164
+ ]);
30165
+ (0, import_react40.useEffect)(() => {
30166
+ loadVerifyData();
30167
+ }, [
30168
+ loadVerifyData
30169
+ ]);
30170
+ (0, import_react40.useEffect)(() => {
30171
+ setSelectedSessionId((prev) => {
30172
+ if (activeWorkspaceId) return activeWorkspaceId;
30173
+ if (prev && sessions.some((session) => session.id === prev)) return prev;
30174
+ return sessions[0]?.id ?? null;
30175
+ });
30176
+ }, [
30177
+ activeWorkspaceId,
30178
+ sessions
30179
+ ]);
30180
+ (0, import_react40.useEffect)(() => {
30181
+ setSelectedGraderId((prev) => {
30182
+ if (prev && graders.some((grader) => grader.id === prev)) return prev;
30183
+ return graders[0]?.id ?? null;
30184
+ });
30185
+ }, [
30186
+ graders
30187
+ ]);
30188
+ (0, import_react40.useEffect)(() => {
30189
+ if (!selectedSessionId) return;
30190
+ updateVerifyPath(selectedSessionId);
30191
+ }, [
30192
+ selectedSessionId,
30193
+ updateVerifyPath
30194
+ ]);
30195
+ (0, import_react40.useEffect)(() => {
30196
+ loadSessionDetail(selectedSessionId).catch((err) => {
30197
+ console.error(err);
30198
+ });
30199
+ }, [
30200
+ loadSessionDetail,
30201
+ selectedSessionId
30202
+ ]);
30203
+ const selectedSession = (0, import_react40.useMemo)(() => sessions.find((session) => session.id === selectedSessionId) ?? null, [
30204
+ sessions,
30205
+ selectedSessionId
30206
+ ]);
30207
+ const selectedGrader = (0, import_react40.useMemo)(() => graders.find((grader) => grader.id === selectedGraderId) ?? null, [
30208
+ graders,
30209
+ selectedGraderId
30210
+ ]);
30211
+ const scenarioRunOptions = (0, import_react40.useMemo)(() => {
30212
+ const meta = sessionDetail?.meta && typeof sessionDetail.meta === "object" ? sessionDetail.meta : {};
30213
+ const fromList = Array.isArray(meta.scenarioRunSummaries) ? meta.scenarioRunSummaries.map((entry) => parseScenarioRunSummary2(entry)) : [];
30214
+ const fromCurrent = parseScenarioRunSummary2(meta.scenarioRunSummary);
30215
+ const all = [
30216
+ ...fromList,
30217
+ fromCurrent
30218
+ ].filter((entry) => Boolean(entry));
30219
+ const deduped = /* @__PURE__ */ new Map();
30220
+ all.forEach((entry) => {
30221
+ const existing = deduped.get(entry.scenarioRunId);
30222
+ if (!existing) {
30223
+ deduped.set(entry.scenarioRunId, entry);
30224
+ return;
30225
+ }
30226
+ const existingSeq = existing.lastEventSeq ?? -1;
30227
+ const nextSeq = entry.lastEventSeq ?? -1;
30228
+ if (nextSeq > existingSeq) {
30229
+ deduped.set(entry.scenarioRunId, entry);
30230
+ return;
30231
+ }
30232
+ if (nextSeq === existingSeq) {
30233
+ const existingStamp = existing.updatedAt ?? "";
30234
+ const nextStamp = entry.updatedAt ?? "";
30235
+ if (nextStamp.localeCompare(existingStamp) > 0) {
30236
+ deduped.set(entry.scenarioRunId, entry);
30237
+ }
30238
+ }
30239
+ });
30240
+ return [
30241
+ ...deduped.values()
30242
+ ].sort((a, b) => {
30243
+ const aTime = Date.parse(a.updatedAt ?? "");
30244
+ const bTime = Date.parse(b.updatedAt ?? "");
30245
+ const aValidTime = Number.isFinite(aTime) ? aTime : -1;
30246
+ const bValidTime = Number.isFinite(bTime) ? bTime : -1;
30247
+ if (aValidTime !== bValidTime) return bValidTime - aValidTime;
30248
+ const aSeq = a.lastEventSeq ?? -1;
30249
+ const bSeq = b.lastEventSeq ?? -1;
30250
+ if (aSeq !== bSeq) return bSeq - aSeq;
30251
+ return b.scenarioRunId.localeCompare(a.scenarioRunId);
30252
+ });
30253
+ }, [
30254
+ sessionDetail?.meta
30255
+ ]);
30256
+ (0, import_react40.useEffect)(() => {
30257
+ const hasOption = (runId) => Boolean(runId && scenarioRunOptions.some((entry) => entry.scenarioRunId === runId));
30258
+ const meta = sessionDetail?.meta && typeof sessionDetail.meta === "object" ? sessionDetail.meta : {};
30259
+ const currentScenarioRunId = typeof meta.scenarioRunId === "string" && meta.scenarioRunId.trim().length > 0 ? meta.scenarioRunId : null;
30260
+ const nextRunId = hasOption(workspaceRouting.testRunId) ? workspaceRouting.testRunId : hasOption(selectedScenarioRunId) ? selectedScenarioRunId : hasOption(currentScenarioRunId) ? currentScenarioRunId : scenarioRunOptions[0]?.scenarioRunId ?? null;
30261
+ if (selectedScenarioRunId !== nextRunId) {
30262
+ setSelectedScenarioRunId(nextRunId);
30263
+ }
30264
+ if (workspaceRouting.testRunId !== nextRunId) {
30265
+ workspaceRouting.setTestRunId(nextRunId);
30266
+ }
30267
+ }, [
30268
+ scenarioRunOptions,
30269
+ selectedScenarioRunId,
30270
+ sessionDetail?.meta,
30271
+ workspaceRouting
30272
+ ]);
30273
+ const sessionRuns = (0, import_react40.useMemo)(() => {
30274
+ if (!selectedSession?.gradingRuns) return [];
30275
+ return [
30276
+ ...selectedSession.gradingRuns
30277
+ ].sort((a, b) => parseRunAt(b) - parseRunAt(a));
30278
+ }, [
30279
+ selectedSession?.gradingRuns
30280
+ ]);
30281
+ const filteredRuns = (0, import_react40.useMemo)(() => {
30282
+ const latestScenarioRunIdFromRuns = sessionRuns.map((run) => scenarioRunIdFromCalibrationRun2(run)).find((runId) => Boolean(runId));
30283
+ const hasOption = (runId) => Boolean(runId && scenarioRunOptions.some((entry) => entry.scenarioRunId === runId));
30284
+ const meta = sessionDetail?.meta && typeof sessionDetail.meta === "object" ? sessionDetail.meta : {};
30285
+ const currentScenarioRunId = typeof meta.scenarioRunId === "string" && meta.scenarioRunId.trim().length > 0 ? meta.scenarioRunId : null;
30286
+ const activeScenarioRunFilterId = hasOption(workspaceRouting.testRunId) ? workspaceRouting.testRunId : hasOption(selectedScenarioRunId) ? selectedScenarioRunId : hasOption(currentScenarioRunId) ? currentScenarioRunId : scenarioRunOptions[0]?.scenarioRunId ?? latestScenarioRunIdFromRuns ?? null;
30287
+ return sessionRuns.filter((run) => {
30288
+ if (selectedGraderId && run.graderId !== selectedGraderId) return false;
30289
+ if (!activeScenarioRunFilterId) return true;
30290
+ return scenarioRunIdFromCalibrationRun2(run) === activeScenarioRunFilterId;
30291
+ });
30292
+ }, [
30293
+ scenarioRunOptions,
30294
+ selectedGraderId,
30295
+ selectedScenarioRunId,
30296
+ sessionDetail?.meta,
30297
+ sessionRuns,
30298
+ workspaceRouting.testRunId
30299
+ ]);
30300
+ const runConsistencySample = (0, import_react40.useCallback)(async (payload) => {
30301
+ const res = await fetch("/api/calibrate/run", {
30302
+ method: "POST",
30303
+ headers: {
30304
+ "content-type": "application/json"
30305
+ },
30306
+ body: JSON.stringify(payload)
30307
+ });
30308
+ const body = await res.json().catch(() => ({}));
30309
+ if (!res.ok) {
30310
+ throw new Error(body.error ?? res.statusText);
30311
+ }
30312
+ if (!body.run) {
30313
+ throw new Error(body.error ?? "Calibration run response missing run payload");
30314
+ }
30315
+ return {
30316
+ run: body.run,
30317
+ error: body.error
30318
+ };
30319
+ }, []);
30320
+ const updateBatchRequest = (0, import_react40.useCallback)((batchId, index, patch) => {
30321
+ setBatchState((prev) => {
30322
+ if (prev.batchId !== batchId) return prev;
30323
+ if (index < 0 || index >= prev.requests.length) return prev;
30324
+ const nextRequests = prev.requests.map((request, requestIndex) => requestIndex === index ? {
30325
+ ...request,
30326
+ ...patch
30327
+ } : request);
30328
+ const completed = nextRequests.filter((request) => request.status === "completed").length;
30329
+ const failed = nextRequests.filter((request) => request.status === "error").length;
30330
+ const active = nextRequests.filter((request) => request.status === "running").length;
30331
+ const terminal = completed + failed === prev.requested && active === 0;
30332
+ const nextStatus = terminal ? failed > 0 ? "error" : "completed" : "running";
30333
+ return {
30334
+ ...prev,
30335
+ requests: nextRequests,
30336
+ completed,
30337
+ failed,
30338
+ active,
30339
+ status: nextStatus,
30340
+ finishedAt: terminal ? (/* @__PURE__ */ new Date()).toISOString() : prev.finishedAt
30341
+ };
30342
+ });
30343
+ }, []);
30344
+ const runConsistencyBatch = (0, import_react40.useCallback)(async () => {
30345
+ if (!selectedSessionId || !selectedGraderId) return;
30346
+ const nextBatchSize = clampInt(batchSize, 1, MAX_BATCH_SIZE);
30347
+ const nextConcurrency = clampInt(batchConcurrency, 1, Math.min(MAX_BATCH_CONCURRENCY, nextBatchSize));
30348
+ const batchId = batchSeqRef.current + 1;
30349
+ batchSeqRef.current = batchId;
30350
+ const now = (/* @__PURE__ */ new Date()).toISOString();
30351
+ const initialRunIds = filteredRuns.map((run) => run.id);
30352
+ const initialRequests = Array.from({
30353
+ length: nextBatchSize
30354
+ }, (_, index) => ({
30355
+ requestId: `${batchId}:${index + 1}`,
30356
+ status: "queued"
30357
+ }));
30358
+ setBatchState({
30359
+ batchId,
30360
+ status: "running",
30361
+ startedAt: now,
30362
+ finishedAt: void 0,
30363
+ requested: nextBatchSize,
30364
+ concurrency: nextConcurrency,
30365
+ completed: 0,
30366
+ failed: 0,
30367
+ active: 0,
30368
+ initialRunIds,
30369
+ requests: initialRequests
30370
+ });
30371
+ let cursor = 0;
30372
+ const workers = Array.from({
30373
+ length: nextConcurrency
30374
+ }, () => (async () => {
30375
+ while (true) {
30376
+ const nextIndex = cursor;
30377
+ cursor += 1;
30378
+ if (nextIndex >= nextBatchSize) return;
30379
+ if (batchSeqRef.current !== batchId) return;
30380
+ updateBatchRequest(batchId, nextIndex, {
30381
+ status: "running"
30382
+ });
30383
+ try {
30384
+ const response = await runConsistencySample({
30385
+ workspaceId: selectedSessionId,
30386
+ graderId: selectedGraderId,
30387
+ scenarioRunId: selectedScenarioRunId ?? void 0
30388
+ });
30389
+ if (batchSeqRef.current !== batchId) return;
30390
+ if (response.run.status !== "completed") {
30391
+ updateBatchRequest(batchId, nextIndex, {
30392
+ status: "error",
30393
+ runId: response.run.id,
30394
+ error: response.run.error ?? `Calibration run ended with status ${response.run.status}`
30395
+ });
30396
+ continue;
30397
+ }
30398
+ updateBatchRequest(batchId, nextIndex, {
30399
+ status: "completed",
30400
+ runId: response.run.id
30401
+ });
30402
+ } catch (err) {
30403
+ if (batchSeqRef.current !== batchId) return;
30404
+ updateBatchRequest(batchId, nextIndex, {
30405
+ status: "error",
30406
+ error: err instanceof Error ? err.message : String(err)
30407
+ });
30408
+ }
30409
+ }
30410
+ })());
30411
+ await Promise.all(workers);
30412
+ if (batchSeqRef.current !== batchId) return;
30413
+ await loadData({
30414
+ workspaceId: selectedSessionId
30415
+ }).catch(() => {
30416
+ });
30417
+ }, [
30418
+ batchConcurrency,
30419
+ batchSize,
30420
+ filteredRuns,
30421
+ loadData,
30422
+ runConsistencySample,
30423
+ selectedGraderId,
30424
+ selectedScenarioRunId,
30425
+ selectedSessionId,
30426
+ updateBatchRequest
30427
+ ]);
30428
+ const batchInitialRunIdSet = (0, import_react40.useMemo)(() => new Set(batchState.initialRunIds), [
30429
+ batchState.initialRunIds
30430
+ ]);
30431
+ const activeBatchRuns = (0, import_react40.useMemo)(() => {
30432
+ if (!batchState.startedAt) return [];
30433
+ const startedAt = Date.parse(batchState.startedAt);
30434
+ const hasStartedAt = Number.isFinite(startedAt);
30435
+ return filteredRuns.filter((run) => {
30436
+ if (batchInitialRunIdSet.has(run.id)) return false;
30437
+ if (!hasStartedAt) return true;
30438
+ const runAt = parseRunAt(run);
30439
+ return runAt < 0 || runAt >= startedAt - 2e3;
30440
+ });
30441
+ }, [
30442
+ batchInitialRunIdSet,
30443
+ batchState.startedAt,
30444
+ filteredRuns
30445
+ ]);
30446
+ const completedBatchRuns = (0, import_react40.useMemo)(() => activeBatchRuns.filter((run) => run.status === "completed"), [
30447
+ activeBatchRuns
30448
+ ]);
30449
+ const historicalCompletedRuns = (0, import_react40.useMemo)(() => filteredRuns.filter((run) => run.status === "completed"), [
30450
+ filteredRuns
30451
+ ]);
30452
+ const reportRuns = (0, import_react40.useMemo)(() => reportScope === "current_batch" ? completedBatchRuns : historicalCompletedRuns, [
30453
+ completedBatchRuns,
30454
+ historicalCompletedRuns,
30455
+ reportScope
30456
+ ]);
30457
+ const consistencyReport = (0, import_react40.useMemo)(() => buildVerifyConsistencyReport(reportRuns), [
30458
+ reportRuns
30459
+ ]);
30460
+ const queuedCount = (0, import_react40.useMemo)(() => batchState.requests.filter((request) => request.status === "queued").length, [
30461
+ batchState.requests
30462
+ ]);
30463
+ const canRun = Boolean(selectedSessionId && selectedGraderId && batchState.status !== "running");
30464
+ const displayedOutliers = (0, import_react40.useMemo)(() => {
30465
+ const filtered = inconsistentOnly ? consistencyReport.outliers.filter((outlier) => outlier.instability) : consistencyReport.outliers;
30466
+ if (exampleSort === "default") return filtered;
30467
+ const next = [
30468
+ ...filtered
30469
+ ];
30470
+ if (exampleSort === "delta_desc") {
30471
+ next.sort((a, b) => {
30472
+ const aDelta = a.scoreDelta ?? -1;
30473
+ const bDelta = b.scoreDelta ?? -1;
30474
+ if (aDelta !== bDelta) return bDelta - aDelta;
30475
+ return a.label.localeCompare(b.label);
30476
+ });
30477
+ return next;
30478
+ }
30479
+ if (exampleSort === "agreement_asc") {
30480
+ next.sort((a, b) => {
30481
+ const aAgreement = a.agreementRate ?? Number.POSITIVE_INFINITY;
30482
+ const bAgreement = b.agreementRate ?? Number.POSITIVE_INFINITY;
30483
+ if (aAgreement !== bAgreement) return aAgreement - bAgreement;
30484
+ return a.label.localeCompare(b.label);
30485
+ });
30486
+ return next;
30487
+ }
30488
+ if (exampleSort === "samples_desc") {
30489
+ next.sort((a, b) => {
30490
+ if (a.sampleSize !== b.sampleSize) return b.sampleSize - a.sampleSize;
30491
+ return a.label.localeCompare(b.label);
30492
+ });
30493
+ return next;
30494
+ }
30495
+ next.sort((a, b) => a.label.localeCompare(b.label));
30496
+ return next;
30497
+ }, [
30498
+ consistencyReport.outliers,
30499
+ exampleSort,
30500
+ inconsistentOnly
30501
+ ]);
30502
+ const reportScopeLabel = reportScope === "current_batch" ? "current batch" : "all matching runs";
30503
+ const resolvedComposerChips = (0, import_react40.useMemo)(() => composerChips ?? [], [
30504
+ composerChips
30505
+ ]);
30506
+ const composerChipIds = (0, import_react40.useMemo)(() => new Set(resolvedComposerChips.map((chip) => chip.chipId)), [
30507
+ resolvedComposerChips
30508
+ ]);
30509
+ const mergeComposerChip = (0, import_react40.useCallback)((base, chip) => {
30510
+ const next = [
30511
+ ...base
30512
+ ];
30513
+ const existingIndex = next.findIndex((entry) => entry.chipId === chip.chipId);
30514
+ if (existingIndex >= 0) {
30515
+ next[existingIndex] = {
30516
+ ...next[existingIndex],
30517
+ ...chip,
30518
+ enabled: true
30519
+ };
30520
+ return next;
30521
+ }
30522
+ next.push(chip);
30523
+ return next;
30524
+ }, []);
30525
+ const addComposerChip = (0, import_react40.useCallback)((chip) => {
30526
+ if (!onComposerChipsChange) return;
30527
+ onComposerChipsChange(mergeComposerChip(resolvedComposerChips, chip));
30528
+ }, [
30529
+ mergeComposerChip,
30530
+ onComposerChipsChange,
30531
+ resolvedComposerChips
30532
+ ]);
30533
+ const removeComposerChip = (0, import_react40.useCallback)((chipId) => {
30534
+ if (!onComposerChipsChange) return;
30535
+ onComposerChipsChange(resolvedComposerChips.filter((chip) => chip.chipId !== chipId));
30536
+ }, [
30537
+ onComposerChipsChange,
30538
+ resolvedComposerChips
30539
+ ]);
30540
+ const buildOutlierChip = (0, import_react40.useCallback)((outlier) => {
30541
+ const chipId = `verify:${selectedSessionId ?? ""}:${outlier.key}`;
30542
+ const runId = outlier.maxRunId ?? outlier.minRunId;
30543
+ const score = outlier.maxScore ?? outlier.minScore ?? void 0;
30544
+ const agreementText = outlier.agreementRate === null ? "agreement unavailable" : `agreement ${Math.round(outlier.agreementRate * 100)}%`;
30545
+ const deltaText = outlier.scoreDelta === null ? "delta unavailable" : `delta ${outlier.scoreDelta}`;
30546
+ return {
30547
+ chipId,
30548
+ source: "verify_outlier",
30549
+ workspaceId: selectedSessionId ?? void 0,
30550
+ runId,
30551
+ capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
30552
+ outlierKey: outlier.key,
30553
+ instability: outlier.instability,
30554
+ score,
30555
+ message: `Verify outlier ${outlier.label}: ${agreementText}, ${deltaText}, samples ${outlier.sampleSize}`,
30556
+ enabled: true
30557
+ };
30558
+ }, [
30559
+ selectedSessionId
30560
+ ]);
30561
+ (0, import_react40.useEffect)(() => {
30562
+ if (!setNavActions) return;
30563
+ setNavActions(null);
30564
+ return () => setNavActions(null);
30565
+ }, [
30566
+ setNavActions
30567
+ ]);
30568
+ (0, import_react40.useEffect)(() => {
30569
+ return () => {
30570
+ batchSeqRef.current += 1;
30571
+ };
30572
+ }, []);
30573
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(PageShell, {
30574
+ className: "verify-shell",
30575
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(PageGrid, {
30576
+ as: "main",
30577
+ className: "verify-layout",
30578
+ children: [
30579
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(Panel_default, {
30580
+ className: "verify-controls",
30581
+ children: [
30582
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30583
+ className: "verify-controls-header",
30584
+ children: [
30585
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", {
30586
+ children: "Verify consistency"
30587
+ }),
30588
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", {
30589
+ className: "secondary-note",
30590
+ children: "Run repeated grading checks against one grader and scenario."
30591
+ })
30592
+ ]
30593
+ }),
30594
+ scenarioRunOptions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Listbox, {
30595
+ label: "Scenario run",
30596
+ value: selectedScenarioRunId ?? NO_SCENARIO_RUN_VALUE,
30597
+ onChange: (runId) => {
30598
+ if (runId === NO_SCENARIO_RUN_VALUE) {
30599
+ setSelectedScenarioRunId(null);
30600
+ workspaceRouting.setTestRunId(null);
30601
+ return;
30602
+ }
30603
+ setSelectedScenarioRunId(runId);
30604
+ workspaceRouting.setTestRunId(runId);
30605
+ },
30606
+ options: [
30607
+ {
30608
+ value: NO_SCENARIO_RUN_VALUE,
30609
+ label: "Current workspace context",
30610
+ meta: "Run without a prior scenario run binding"
30611
+ },
30612
+ ...scenarioRunOptions.map((entry) => ({
30613
+ value: entry.scenarioRunId,
30614
+ label: getScenarioTitle3(entry),
30615
+ meta: [
30616
+ entry.updatedAt ? formatTimestampShort(entry.updatedAt) : null,
30617
+ entry.scenarioRunId
30618
+ ].filter(Boolean).join(" \xB7 ")
30619
+ }))
30620
+ ],
30621
+ placeholder: "Select scenario run"
30622
+ }),
30623
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Listbox, {
30624
+ label: "Grader",
30625
+ value: selectedGraderId ?? "",
30626
+ onChange: (value) => setSelectedGraderId(value.length ? value : null),
30627
+ options: graders.map((grader) => ({
30628
+ value: grader.id,
30629
+ label: grader.label,
30630
+ meta: botFilename(grader.path ?? null) ?? void 0
30631
+ })),
30632
+ placeholder: "Select grader",
30633
+ disabled: graders.length === 0
30634
+ }),
30635
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30636
+ className: "verify-number-grid",
30637
+ children: [
30638
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("label", {
30639
+ className: "verify-number-field",
30640
+ children: [
30641
+ "Batch size",
30642
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("input", {
30643
+ type: "number",
30644
+ min: 1,
30645
+ max: MAX_BATCH_SIZE,
30646
+ value: batchSize,
30647
+ onChange: (event) => setBatchSize(clampInt(Number(event.target.value), 1, MAX_BATCH_SIZE))
30648
+ })
30649
+ ]
30650
+ }),
30651
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("label", {
30652
+ className: "verify-number-field",
30653
+ children: [
30654
+ "Concurrency",
30655
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("input", {
30656
+ type: "number",
30657
+ min: 1,
30658
+ max: MAX_BATCH_CONCURRENCY,
30659
+ value: batchConcurrency,
30660
+ onChange: (event) => setBatchConcurrency(clampInt(Number(event.target.value), 1, MAX_BATCH_CONCURRENCY))
30661
+ })
30662
+ ]
30663
+ })
30664
+ ]
30665
+ }),
30666
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, {
30667
+ variant: "primary",
30668
+ onClick: runConsistencyBatch,
30669
+ disabled: !canRun,
30670
+ children: batchState.status === "running" ? "Running consistency batch\u2026" : "Run consistency batch"
30671
+ }),
30672
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Callout, {
30673
+ variant: "emphasis",
30674
+ title: "Build assistant stays available",
30675
+ children: "Use the chat drawer toggle in the top-right corner to investigate and iterate while this page remains open."
30676
+ }),
30677
+ sessions.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Callout, {
30678
+ children: "No workspaces found yet. Run a Test scenario first so Verify has evidence to grade."
30679
+ }),
30680
+ graders.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(Callout, {
30681
+ children: [
30682
+ "No graders are available. Add ",
30683
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("code", {
30684
+ children: "[[graders]]"
30685
+ }),
30686
+ " ",
30687
+ "entries to the active root deck."
30688
+ ]
30689
+ }),
30690
+ selectedGrader?.description && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Callout, {
30691
+ children: selectedGrader.description
30692
+ })
30693
+ ]
30694
+ }),
30695
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(Panel_default, {
30696
+ className: "verify-results",
30697
+ children: [
30698
+ error && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30699
+ className: "error",
30700
+ children: error
30701
+ }),
30702
+ loading && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30703
+ className: "editor-status",
30704
+ children: "Loading verify data\u2026"
30705
+ }),
30706
+ !loading && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, {
30707
+ children: [
30708
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30709
+ className: "verify-status-row",
30710
+ children: [
30711
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30712
+ className: "verify-status-main flex-row items-center gap-8",
30713
+ children: [
30714
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", {
30715
+ children: "Batch status"
30716
+ }),
30717
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, {
30718
+ status: batchState.status,
30719
+ children: batchState.status
30720
+ })
30721
+ ]
30722
+ }),
30723
+ consistencyReport.sampleSize > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", {
30724
+ className: classNames("verify-verdict-badge", `verify-verdict-badge--${consistencyReport.verdict.toLowerCase()}`),
30725
+ children: consistencyReport.verdict
30726
+ })
30727
+ ]
30728
+ }),
30729
+ batchState.status === "idle" && consistencyReport.sampleSize === 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Callout, {
30730
+ children: "Run a consistency batch to compute agreement, spread, and instability for the selected grader."
30731
+ }),
30732
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30733
+ className: "verify-metric-grid",
30734
+ children: [
30735
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30736
+ className: "verify-metric-card",
30737
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30738
+ className: "verify-sample-size-row",
30739
+ children: [
30740
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30741
+ className: "verify-sample-size-copy",
30742
+ children: [
30743
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30744
+ className: "verify-metric-label",
30745
+ children: "Sample size"
30746
+ }),
30747
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30748
+ className: "verify-metric-value",
30749
+ children: consistencyReport.sampleSize
30750
+ })
30751
+ ]
30752
+ }),
30753
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30754
+ className: "verify-sample-scope-select",
30755
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Listbox, {
30756
+ value: reportScope,
30757
+ onChange: (value) => setReportScope(value),
30758
+ size: "small",
30759
+ popoverMatchTriggerWidth: false,
30760
+ popoverMinWidth: 320,
30761
+ popoverAlign: "right",
30762
+ options: [
30763
+ {
30764
+ value: "current_batch",
30765
+ label: `Current batch (${completedBatchRuns.length})`,
30766
+ triggerLabel: "Current batch",
30767
+ triggerMeta: null,
30768
+ meta: "Only runs from the latest batch launch"
30769
+ },
30770
+ {
30771
+ value: "all_matching",
30772
+ label: `All matching runs (${historicalCompletedRuns.length})`,
30773
+ triggerLabel: "All matching runs",
30774
+ triggerMeta: null,
30775
+ meta: "All runs matching selected scenario + grader"
30776
+ }
30777
+ ]
30778
+ })
30779
+ })
30780
+ ]
30781
+ })
30782
+ }),
30783
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30784
+ className: "verify-metric-card",
30785
+ children: [
30786
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30787
+ className: "verify-metric-label",
30788
+ children: "Agreement rate"
30789
+ }),
30790
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30791
+ className: "verify-metric-value",
30792
+ children: consistencyReport.agreementRate === null ? "\u2014" : `${Math.round(consistencyReport.agreementRate * 100)}%`
30793
+ })
30794
+ ]
30795
+ }),
30796
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30797
+ className: "verify-metric-card",
30798
+ children: [
30799
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30800
+ className: "verify-metric-label",
30801
+ children: "Score spread (min/median/max)"
30802
+ }),
30803
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30804
+ className: "verify-metric-value verify-metric-value--compact",
30805
+ children: consistencyReport.scoreSpreadMin === null ? "\u2014" : `${consistencyReport.scoreSpreadMin} / ${consistencyReport.scoreSpreadMedian ?? "\u2014"} / ${consistencyReport.scoreSpreadMax ?? "\u2014"}`
30806
+ })
30807
+ ]
30808
+ }),
30809
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30810
+ className: "verify-metric-card",
30811
+ children: [
30812
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30813
+ className: "verify-metric-label",
30814
+ children: "Instability count"
30815
+ }),
30816
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30817
+ className: "verify-metric-value",
30818
+ children: consistencyReport.instabilityCount
30819
+ })
30820
+ ]
30821
+ })
30822
+ ]
30823
+ }),
30824
+ consistencyReport.sampleSize > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Callout, {
30825
+ variant: consistencyReport.verdict === "FAIL" ? "danger" : consistencyReport.verdict === "WARN" ? "emphasis" : "muted",
30826
+ title: `Verdict: ${consistencyReport.verdict}`,
30827
+ children: consistencyReport.verdictReason
30828
+ }),
30829
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(Callout, {
30830
+ title: "Thresholds in code",
30831
+ children: [
30832
+ "Min sample size: ",
30833
+ VERIFY_CONSISTENCY_THRESHOLDS.minSampleSize,
30834
+ " ",
30835
+ "\xB7 PASS requires agreement \u2265 ",
30836
+ Math.round(VERIFY_CONSISTENCY_THRESHOLDS.pass.agreementMin * 100),
30837
+ "%, spread \u2264",
30838
+ " ",
30839
+ VERIFY_CONSISTENCY_THRESHOLDS.pass.maxSpread,
30840
+ ", instability \u2264",
30841
+ " ",
30842
+ VERIFY_CONSISTENCY_THRESHOLDS.pass.maxInstabilityCount,
30843
+ " ",
30844
+ "\xB7 WARN allows agreement \u2265 ",
30845
+ Math.round(VERIFY_CONSISTENCY_THRESHOLDS.warn.agreementMin * 100),
30846
+ "%, spread \u2264",
30847
+ " ",
30848
+ VERIFY_CONSISTENCY_THRESHOLDS.warn.maxSpread,
30849
+ ", instability \u2264",
30850
+ " ",
30851
+ VERIFY_CONSISTENCY_THRESHOLDS.warn.maxInstabilityCount,
30852
+ "."
30853
+ ]
30854
+ }),
30855
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30856
+ className: "verify-section",
30857
+ children: [
30858
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30859
+ className: "verify-section-header",
30860
+ children: [
30861
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", {
30862
+ children: "Examples"
30863
+ }),
30864
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30865
+ className: "verify-section-controls",
30866
+ children: [
30867
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, {
30868
+ variant: inconsistentOnly ? "primary-deemph" : "secondary",
30869
+ size: "small",
30870
+ onClick: () => setInconsistentOnly((prev) => !prev),
30871
+ children: "Inconsistent"
30872
+ }),
30873
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30874
+ className: "verify-section-sort",
30875
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Listbox, {
30876
+ value: exampleSort,
30877
+ onChange: (value) => setExampleSort(value),
30878
+ size: "small",
30879
+ options: [
30880
+ {
30881
+ value: "default",
30882
+ label: "Sort: default"
30883
+ },
30884
+ {
30885
+ value: "delta_desc",
30886
+ label: "Sort: score delta"
30887
+ },
30888
+ {
30889
+ value: "agreement_asc",
30890
+ label: "Sort: agreement"
30891
+ },
30892
+ {
30893
+ value: "samples_desc",
30894
+ label: "Sort: sample size"
30895
+ },
30896
+ {
30897
+ value: "label_asc",
30898
+ label: "Sort: label"
30899
+ }
30900
+ ]
30901
+ })
30902
+ })
30903
+ ]
30904
+ })
30905
+ ]
30906
+ }),
30907
+ displayedOutliers.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Callout, {
30908
+ children: consistencyReport.outliers.length === 0 ? `Examples will appear here as soon as at least one completed run is available in ${reportScopeLabel}.` : `No examples match the current filters in ${reportScopeLabel}.`
30909
+ }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30910
+ className: "verify-outlier-list",
30911
+ children: displayedOutliers.map((outlier) => {
30912
+ const runLinks = (() => {
30913
+ if (!selectedSessionId) return [];
30914
+ const ids = [
30915
+ outlier.maxRunId,
30916
+ outlier.minRunId
30917
+ ].filter((value) => Boolean(value));
30918
+ return [
30919
+ ...new Set(ids)
30920
+ ];
30921
+ })();
30922
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30923
+ className: "verify-outlier-card",
30924
+ children: [
30925
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30926
+ className: "verify-outlier-header",
30927
+ children: [
30928
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", {
30929
+ children: outlier.label
30930
+ }),
30931
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30932
+ style: {
30933
+ display: "flex",
30934
+ alignItems: "center",
30935
+ gap: "8px"
30936
+ },
30937
+ children: [
30938
+ outlier.minScore === outlier.maxScore ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, {
30939
+ variant: scoreBadgeVariant(outlier.minScore),
30940
+ children: formatSignedScore(outlier.minScore)
30941
+ }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30942
+ style: {
30943
+ display: "flex",
30944
+ alignItems: "center"
30945
+ },
30946
+ children: [
30947
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, {
30948
+ variant: scoreBadgeVariant(outlier.minScore),
30949
+ style: {
30950
+ borderTopRightRadius: 0,
30951
+ borderBottomRightRadius: 0
30952
+ },
30953
+ children: formatSignedScore(outlier.minScore)
30954
+ }),
30955
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, {
30956
+ variant: scoreBadgeVariant(outlier.maxScore),
30957
+ style: {
30958
+ marginLeft: "-1px",
30959
+ borderTopLeftRadius: 0,
30960
+ borderBottomLeftRadius: 0
30961
+ },
30962
+ children: formatSignedScore(outlier.maxScore)
30963
+ })
30964
+ ]
30965
+ }),
30966
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, {
30967
+ variant: outlier.instability ? "error" : "completed",
30968
+ children: outlier.instability ? "Unstable" : "Stable"
30969
+ })
30970
+ ]
30971
+ })
30972
+ ]
30973
+ }),
30974
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30975
+ className: "flex-row items-center",
30976
+ children: [
30977
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30978
+ className: "flex-1 flex-column",
30979
+ children: [
30980
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
30981
+ className: "verify-outlier-meta",
30982
+ children: [
30983
+ "agreement ",
30984
+ outlier.agreementRate === null ? "\u2014" : `${Math.round(outlier.agreementRate * 100)}%`,
30985
+ " \xB7 delta ",
30986
+ outlier.scoreDelta ?? "\u2014",
30987
+ " ",
30988
+ "\xB7 samples ",
30989
+ outlier.sampleSize,
30990
+ outlier.passFlip ? " \xB7 pass/fail flip" : "",
30991
+ outlier.messageRefId ? ` \xB7 ref ${outlier.messageRefId}` : ""
30992
+ ]
30993
+ }),
30994
+ runLinks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
30995
+ className: "verify-outlier-links",
30996
+ children: runLinks.map((runId) => {
30997
+ if (!selectedSessionId) return null;
30998
+ const href = buildGradePath(selectedSessionId, runId);
30999
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("a", {
31000
+ href,
31001
+ onClick: (event) => handleInternalLinkClick(event, href),
31002
+ children: [
31003
+ "Open grade run ",
31004
+ runId
31005
+ ]
31006
+ }, runId);
31007
+ })
31008
+ })
31009
+ ]
31010
+ }),
31011
+ (() => {
31012
+ const outlierChip = buildOutlierChip(outlier);
31013
+ const inChat = composerChipIds.has(outlierChip.chipId);
31014
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
31015
+ className: "workbench-summary-actions",
31016
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, {
31017
+ variant: "secondary",
31018
+ size: "small",
31019
+ onClick: () => inChat ? removeComposerChip(outlierChip.chipId) : addComposerChip(outlierChip),
31020
+ disabled: !onComposerChipsChange,
31021
+ children: inChat ? "Remove from chat" : "Add to chat"
31022
+ })
31023
+ });
31024
+ })()
31025
+ ]
31026
+ })
31027
+ ]
31028
+ }, outlier.key);
31029
+ })
31030
+ })
31031
+ ]
31032
+ }),
31033
+ batchState.requests.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
31034
+ className: "verify-section",
31035
+ children: [
31036
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", {
31037
+ children: "Batch requests"
31038
+ }),
31039
+ (batchState.startedAt || batchState.finishedAt) && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
31040
+ className: "verify-status-meta",
31041
+ children: [
31042
+ batchState.startedAt ? `started ${formatTimestampShort(batchState.startedAt)}` : "",
31043
+ batchState.finishedAt ? ` \xB7 finished ${formatTimestampShort(batchState.finishedAt)}` : ""
31044
+ ]
31045
+ }),
31046
+ batchState.requested > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
31047
+ className: "verify-progress-row",
31048
+ children: [
31049
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", {
31050
+ children: [
31051
+ "Queued: ",
31052
+ queuedCount
31053
+ ]
31054
+ }),
31055
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", {
31056
+ children: [
31057
+ "Running: ",
31058
+ batchState.active
31059
+ ]
31060
+ }),
31061
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", {
31062
+ children: [
31063
+ "Completed: ",
31064
+ batchState.completed
31065
+ ]
31066
+ }),
31067
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", {
31068
+ children: [
31069
+ "Failed: ",
31070
+ batchState.failed
31071
+ ]
31072
+ })
31073
+ ]
31074
+ }),
31075
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", {
31076
+ className: "verify-request-list",
31077
+ children: batchState.requests.map((request, index) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("li", {
31078
+ className: "verify-request-row",
31079
+ children: [
31080
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", {
31081
+ className: "verify-request-index",
31082
+ children: [
31083
+ "#",
31084
+ index + 1
31085
+ ]
31086
+ }),
31087
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, {
31088
+ status: request.status === "queued" ? "idle" : request.status,
31089
+ children: request.status
31090
+ }),
31091
+ selectedSessionId && request.runId ? (() => {
31092
+ const href = buildGradePath(selectedSessionId, request.runId);
31093
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", {
31094
+ href,
31095
+ onClick: (event) => handleInternalLinkClick(event, href),
31096
+ children: request.runId
31097
+ });
31098
+ })() : request.runId ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("code", {
31099
+ children: request.runId
31100
+ }) : null,
31101
+ request.error && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", {
31102
+ className: "verify-request-error",
31103
+ children: request.error
31104
+ })
31105
+ ]
31106
+ }, request.requestId))
31107
+ })
31108
+ ]
31109
+ })
31110
+ ]
31111
+ })
31112
+ ]
31113
+ })
31114
+ ]
31115
+ })
31116
+ });
31117
+ }
31118
+ var VerifyPage_default = VerifyPage;
31119
+
31120
+ // simulator-ui/src/main.tsx
31121
+ var globalStyleEl = document.createElement("style");
31122
+ globalStyleEl.textContent = globalStyles;
31123
+ document.head.appendChild(globalStyleEl);
31124
+ function useSimulator() {
31125
+ const [connectionStatus, setConnectionStatus] = (0, import_react41.useState)("connecting");
31126
+ const [savedState, setSavedState] = (0, import_react41.useState)(null);
31127
+ const [traceEvents, setTraceEvents] = (0, import_react41.useState)([]);
31128
+ const [errors, setErrors] = (0, import_react41.useState)([]);
31129
+ const [streamText, setStreamText] = (0, import_react41.useState)("");
31130
+ const [isRunning, setIsRunning] = (0, import_react41.useState)(false);
31131
+ const [connectSeq, setConnectSeq] = (0, import_react41.useState)(0);
31132
+ (0, import_react41.useEffect)(() => {
31133
+ const streamId = SIMULATOR_STREAM_ID;
31134
+ const streamUrl = buildDurableStreamUrl(streamId, getDurableStreamOffset(streamId));
31135
+ const source = new EventSource(streamUrl);
31136
+ setConnectionStatus("connecting");
31137
+ source.onopen = () => {
31138
+ setConnectionStatus("connected");
31139
+ setErrors([]);
31140
+ };
31141
+ source.onerror = () => {
31142
+ setConnectionStatus("error");
31143
+ setErrors((prev) => prev.includes("Stream connection error") ? prev : [
31144
+ ...prev,
31145
+ "Stream connection error"
31146
+ ]);
31147
+ setIsRunning(false);
31148
+ setStreamText("");
31149
+ };
31150
+ const handleMessage = (event) => {
31151
+ let msg = null;
31152
+ try {
31153
+ msg = JSON.parse(event.data);
31154
+ } catch (err) {
31155
+ console.error("[sim] failed to parse stream event payload", err);
31156
+ return;
31157
+ }
31158
+ const parsedOffset = Number(event.lastEventId);
31159
+ if (Number.isFinite(parsedOffset)) {
31160
+ setDurableStreamOffset(streamId, parsedOffset + 1);
31161
+ }
31162
+ if (!msg || typeof msg !== "object") return;
31163
+ if (msg.type === "state") {
31164
+ setSavedState(msg.state);
31165
+ if (Array.isArray(msg.state.traces)) {
31166
+ setTraceEvents(msg.state.traces);
31167
+ }
31168
+ } else if (msg.type === "stream") {
31169
+ if (typeof msg.chunk === "string" && msg.chunk.length > 0) {
31170
+ setStreamText((prev) => prev + msg.chunk);
31171
+ }
31172
+ } else if (msg.type === "result") {
31173
+ setIsRunning(false);
31174
+ setStreamText("");
31175
+ } else if (msg.type === "trace" && msg.event) {
31176
+ setTraceEvents((prev) => [
31177
+ ...prev,
31178
+ msg.event
31179
+ ].slice(-200));
31180
+ } else if (msg.type === "error") {
31181
+ const message = msg.message ?? "Unknown error";
31182
+ setErrors((prev) => [
31183
+ ...prev,
31184
+ message
31185
+ ]);
31186
+ if (msg.runId || message !== "Run already in progress") {
31187
+ setIsRunning(false);
31188
+ }
31189
+ setStreamText("");
31190
+ }
31191
+ };
31192
+ const simulatorEventTypes = [
31193
+ "ready",
31194
+ "pong",
31195
+ "stream",
31196
+ "result",
31197
+ "trace",
31198
+ "state",
31199
+ "error"
31200
+ ];
31201
+ for (const type of simulatorEventTypes) {
31202
+ source.addEventListener(type, handleMessage);
31203
+ }
31204
+ return () => {
31205
+ for (const type of simulatorEventTypes) {
31206
+ source.removeEventListener(type, handleMessage);
31207
+ }
31208
+ source.close();
31209
+ setConnectionStatus("closed");
31210
+ setIsRunning(false);
31211
+ setStreamText("");
31212
+ };
31213
+ }, [
29244
31214
  connectSeq
29245
31215
  ]);
29246
- const run = (0, import_react40.useCallback)(async (opts) => {
31216
+ const run = (0, import_react41.useCallback)(async (opts) => {
29247
31217
  setIsRunning(true);
29248
31218
  setStreamText("");
29249
31219
  const sessionId = opts.resetState ? void 0 : savedState?.meta?.sessionId;
@@ -29278,7 +31248,7 @@ function useSimulator() {
29278
31248
  }, [
29279
31249
  savedState?.meta?.sessionId
29280
31250
  ]);
29281
- const sendFeedback = (0, import_react40.useCallback)(async (messageRefId, score, reason) => {
31251
+ const sendFeedback = (0, import_react41.useCallback)(async (messageRefId, score, reason) => {
29282
31252
  const sessionId = savedState?.meta?.sessionId;
29283
31253
  if (!sessionId) return;
29284
31254
  try {
@@ -29305,7 +31275,7 @@ function useSimulator() {
29305
31275
  }, [
29306
31276
  savedState?.meta?.sessionId
29307
31277
  ]);
29308
- const loadSession = (0, import_react40.useCallback)(async (sessionId) => {
31278
+ const loadSession = (0, import_react41.useCallback)(async (sessionId) => {
29309
31279
  try {
29310
31280
  const res = await fetch("/api/simulator/load-session", {
29311
31281
  method: "POST",
@@ -29334,7 +31304,7 @@ function useSimulator() {
29334
31304
  ]);
29335
31305
  }
29336
31306
  }, []);
29337
- const saveNotes = (0, import_react40.useCallback)(async (text) => {
31307
+ const saveNotes = (0, import_react41.useCallback)(async (text) => {
29338
31308
  const sessionId = savedState?.meta?.sessionId;
29339
31309
  if (!sessionId) return;
29340
31310
  try {
@@ -29359,7 +31329,7 @@ function useSimulator() {
29359
31329
  }, [
29360
31330
  savedState?.meta?.sessionId
29361
31331
  ]);
29362
- const saveSessionScore = (0, import_react40.useCallback)(async (score) => {
31332
+ const saveSessionScore = (0, import_react41.useCallback)(async (score) => {
29363
31333
  const sessionId = savedState?.meta?.sessionId;
29364
31334
  if (!sessionId) return;
29365
31335
  try {
@@ -29384,10 +31354,10 @@ function useSimulator() {
29384
31354
  }, [
29385
31355
  savedState?.meta?.sessionId
29386
31356
  ]);
29387
- const reconnect = (0, import_react40.useCallback)(() => {
31357
+ const reconnect = (0, import_react41.useCallback)(() => {
29388
31358
  setConnectSeq((prev) => prev + 1);
29389
31359
  }, []);
29390
- const resetLocal = (0, import_react40.useCallback)(() => {
31360
+ const resetLocal = (0, import_react41.useCallback)(() => {
29391
31361
  setSavedState(null);
29392
31362
  setTraceEvents([]);
29393
31363
  setErrors([]);
@@ -29410,10 +31380,10 @@ function useSimulator() {
29410
31380
  };
29411
31381
  }
29412
31382
  function useWorkspaces() {
29413
- const [workspaces, setWorkspaces] = (0, import_react40.useState)([]);
29414
- const [loading, setLoading] = (0, import_react40.useState)(false);
29415
- const [error, setError] = (0, import_react40.useState)(null);
29416
- const byNewest = (0, import_react40.useCallback)((items) => {
31383
+ const [workspaces, setWorkspaces] = (0, import_react41.useState)([]);
31384
+ const [loading, setLoading] = (0, import_react41.useState)(false);
31385
+ const [error, setError] = (0, import_react41.useState)(null);
31386
+ const byNewest = (0, import_react41.useCallback)((items) => {
29417
31387
  return [
29418
31388
  ...items
29419
31389
  ].sort((a, b) => {
@@ -29424,7 +31394,7 @@ function useWorkspaces() {
29424
31394
  return safeBTime - safeATime;
29425
31395
  });
29426
31396
  }, []);
29427
- const refresh = (0, import_react40.useCallback)(async () => {
31397
+ const refresh = (0, import_react41.useCallback)(async () => {
29428
31398
  setLoading(true);
29429
31399
  setError(null);
29430
31400
  try {
@@ -29440,7 +31410,7 @@ function useWorkspaces() {
29440
31410
  }, [
29441
31411
  byNewest
29442
31412
  ]);
29443
- const deleteWorkspace = (0, import_react40.useCallback)(async (workspaceId) => {
31413
+ const deleteWorkspace = (0, import_react41.useCallback)(async (workspaceId) => {
29444
31414
  setLoading(true);
29445
31415
  setError(null);
29446
31416
  try {
@@ -29463,7 +31433,7 @@ function useWorkspaces() {
29463
31433
  }, [
29464
31434
  refresh
29465
31435
  ]);
29466
- const deleteAll = (0, import_react40.useCallback)(async (scope) => {
31436
+ const deleteAll = (0, import_react41.useCallback)(async (scope) => {
29467
31437
  setLoading(true);
29468
31438
  setError(null);
29469
31439
  try {
@@ -29504,44 +31474,44 @@ function useWorkspaces() {
29504
31474
  function RecentSessionsEmptyState(props) {
29505
31475
  const { sessions, loading, error, onSelect, onOpenAll } = props;
29506
31476
  const preview = sessions.slice(0, 4);
29507
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
31477
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
29508
31478
  className: "empty-state",
29509
31479
  children: [
29510
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", {
31480
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", {
29511
31481
  children: "Start a new chat or load a previous session to review feedback."
29512
31482
  }),
29513
- loading && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", {
31483
+ loading && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", {
29514
31484
  children: "Loading recent sessions\u2026"
29515
31485
  }),
29516
- error && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", {
31486
+ error && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", {
29517
31487
  className: "error",
29518
31488
  children: error
29519
31489
  }),
29520
- !loading && !error && preview.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", {
31490
+ !loading && !error && preview.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", {
29521
31491
  children: "No saved sessions yet."
29522
31492
  }),
29523
- !loading && !error && preview.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
31493
+ !loading && !error && preview.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
29524
31494
  className: "recent-sessions",
29525
- children: preview.map((session) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("button", {
31495
+ children: preview.map((session) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("button", {
29526
31496
  type: "button",
29527
31497
  className: "recent-session-button",
29528
31498
  onClick: () => onSelect(session.id),
29529
31499
  children: [
29530
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", {
31500
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("strong", {
29531
31501
  children: session.testBotName ?? session.deckSlug ?? session.deck ?? "session"
29532
31502
  }),
29533
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", {
31503
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", {
29534
31504
  children: formatTimestamp(session.createdAt)
29535
31505
  }),
29536
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("code", {
31506
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("code", {
29537
31507
  children: session.id
29538
31508
  })
29539
31509
  ]
29540
31510
  }, session.id))
29541
31511
  }),
29542
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
31512
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
29543
31513
  className: "empty-state-actions",
29544
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, {
31514
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Button, {
29545
31515
  variant: "ghost",
29546
31516
  onClick: onOpenAll,
29547
31517
  children: "View all sessions"
@@ -29560,35 +31530,35 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29560
31530
  const sessionBasePath = rootPath === "/" ? WORKSPACES_BASE_PATH : rootPath;
29561
31531
  const normalizedSessionBase = normalizeBasePath(sessionBasePath);
29562
31532
  const newSessionPath = `${normalizedSessionBase === "" ? WORKSPACES_BASE_PATH : normalizedSessionBase}/new`.replace(/\/{2,}/g, "/");
29563
- const buildSessionUrl = (0, import_react40.useCallback)((sessionId2) => `${normalizedSessionBase === "" ? WORKSPACES_BASE_PATH : normalizedSessionBase}/${encodeURIComponent(sessionId2)}/debug`.replace(/\/{2,}/g, "/"), [
31533
+ const buildSessionUrl = (0, import_react41.useCallback)((sessionId2) => `${normalizedSessionBase === "" ? WORKSPACES_BASE_PATH : normalizedSessionBase}/${encodeURIComponent(sessionId2)}/debug`.replace(/\/{2,}/g, "/"), [
29564
31534
  normalizedSessionBase
29565
31535
  ]);
29566
- const [message, setMessage] = (0, import_react40.useState)("");
29567
- const [pendingReset, setPendingReset] = (0, import_react40.useState)(false);
29568
- const [initValue, setInitValue] = (0, import_react40.useState)(void 0);
29569
- const [initDirty, setInitDirty] = (0, import_react40.useState)(false);
29570
- const [initMode, setInitMode] = (0, import_react40.useState)("form");
29571
- const [initJsonText, setInitJsonText] = (0, import_react40.useState)("");
29572
- const [initJsonError, setInitJsonError] = (0, import_react40.useState)(null);
29573
- const [initOpen, setInitOpen] = (0, import_react40.useState)(false);
29574
- const [jsonErrors, setJsonErrors] = (0, import_react40.useState)({});
29575
- const [pendingSessionId, setPendingSessionId] = (0, import_react40.useState)(null);
29576
- const appliedSessionIdRef = (0, import_react40.useRef)(null);
29577
- const externalSessionIdRef = (0, import_react40.useRef)(null);
29578
- const initializedRef = (0, import_react40.useRef)(false);
29579
- const [noteDraft, setNoteDraft] = (0, import_react40.useState)("");
29580
- const [noteStatus, setNoteStatus] = (0, import_react40.useState)("idle");
29581
- const pendingNoteRef = (0, import_react40.useRef)(null);
29582
- const [scoreStatus, setScoreStatus] = (0, import_react40.useState)("idle");
29583
- const pendingScoreRef = (0, import_react40.useRef)(null);
29584
- (0, import_react40.useEffect)(() => {
31536
+ const [message, setMessage] = (0, import_react41.useState)("");
31537
+ const [pendingReset, setPendingReset] = (0, import_react41.useState)(false);
31538
+ const [initValue, setInitValue] = (0, import_react41.useState)(void 0);
31539
+ const [initDirty, setInitDirty] = (0, import_react41.useState)(false);
31540
+ const [initMode, setInitMode] = (0, import_react41.useState)("form");
31541
+ const [initJsonText, setInitJsonText] = (0, import_react41.useState)("");
31542
+ const [initJsonError, setInitJsonError] = (0, import_react41.useState)(null);
31543
+ const [initOpen, setInitOpen] = (0, import_react41.useState)(false);
31544
+ const [jsonErrors, setJsonErrors] = (0, import_react41.useState)({});
31545
+ const [pendingSessionId, setPendingSessionId] = (0, import_react41.useState)(null);
31546
+ const appliedSessionIdRef = (0, import_react41.useRef)(null);
31547
+ const externalSessionIdRef = (0, import_react41.useRef)(null);
31548
+ const initializedRef = (0, import_react41.useRef)(false);
31549
+ const [noteDraft, setNoteDraft] = (0, import_react41.useState)("");
31550
+ const [noteStatus, setNoteStatus] = (0, import_react41.useState)("idle");
31551
+ const pendingNoteRef = (0, import_react41.useRef)(null);
31552
+ const [scoreStatus, setScoreStatus] = (0, import_react41.useState)("idle");
31553
+ const pendingScoreRef = (0, import_react41.useRef)(null);
31554
+ (0, import_react41.useEffect)(() => {
29585
31555
  if (simulator.connectionStatus === "connecting") {
29586
31556
  appliedSessionIdRef.current = null;
29587
31557
  }
29588
31558
  }, [
29589
31559
  simulator.connectionStatus
29590
31560
  ]);
29591
- (0, import_react40.useEffect)(() => {
31561
+ (0, import_react41.useEffect)(() => {
29592
31562
  refresh();
29593
31563
  }, [
29594
31564
  refresh
@@ -29598,7 +31568,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29598
31568
  const schemaError = httpSchema.schemaResponse?.error ?? httpSchema.error ?? void 0;
29599
31569
  const conversationStarted = Boolean(simulator.savedState && simulator.savedState.messages.length > 0);
29600
31570
  const initEditable = Boolean(schema) && (!conversationStarted || pendingReset);
29601
- const lockedInitValue = (0, import_react40.useMemo)(() => {
31571
+ const lockedInitValue = (0, import_react41.useMemo)(() => {
29602
31572
  const fromTraces = extractInitFromTraces(simulator.savedState?.traces);
29603
31573
  if (fromTraces !== void 0) return fromTraces;
29604
31574
  return schemaDefaults ?? deriveInitialFromSchema(schema);
@@ -29607,7 +31577,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29607
31577
  schemaDefaults,
29608
31578
  schema
29609
31579
  ]);
29610
- (0, import_react40.useEffect)(() => {
31580
+ (0, import_react41.useEffect)(() => {
29611
31581
  if (!schema) return;
29612
31582
  if (initDirty) return;
29613
31583
  if (schemaDefaults !== void 0) {
@@ -29620,7 +31590,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29620
31590
  schemaDefaults,
29621
31591
  initDirty
29622
31592
  ]);
29623
- (0, import_react40.useEffect)(() => {
31593
+ (0, import_react41.useEffect)(() => {
29624
31594
  if (initMode !== "json") return;
29625
31595
  if (initDirty) return;
29626
31596
  try {
@@ -29633,19 +31603,19 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29633
31603
  initValue,
29634
31604
  initDirty
29635
31605
  ]);
29636
- (0, import_react40.useEffect)(() => {
31606
+ (0, import_react41.useEffect)(() => {
29637
31607
  if (initEditable) {
29638
31608
  setInitOpen(true);
29639
31609
  }
29640
31610
  }, [
29641
31611
  initEditable
29642
31612
  ]);
29643
- const messages = (0, import_react40.useMemo)(() => {
31613
+ const messages = (0, import_react41.useMemo)(() => {
29644
31614
  return buildConversationEntries(simulator.savedState);
29645
31615
  }, [
29646
31616
  simulator.savedState
29647
31617
  ]);
29648
- const missingRequired = (0, import_react40.useMemo)(() => {
31618
+ const missingRequired = (0, import_react41.useMemo)(() => {
29649
31619
  if (!schema || !initEditable) return [];
29650
31620
  return findMissingRequiredFields(schema, initValue);
29651
31621
  }, [
@@ -29653,13 +31623,13 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29653
31623
  initEditable,
29654
31624
  initValue
29655
31625
  ]);
29656
- const jsonErrorCount = (0, import_react40.useMemo)(() => {
31626
+ const jsonErrorCount = (0, import_react41.useMemo)(() => {
29657
31627
  return Object.values(jsonErrors).filter((v) => typeof v === "string" && v).length;
29658
31628
  }, [
29659
31629
  jsonErrors
29660
31630
  ]);
29661
31631
  const canStartWithInit = Boolean(schema) && initEditable && missingRequired.length === 0 && jsonErrorCount === 0;
29662
- const resetInitValue = (0, import_react40.useCallback)(() => {
31632
+ const resetInitValue = (0, import_react41.useCallback)(() => {
29663
31633
  setInitJsonError(null);
29664
31634
  setJsonErrors((prev) => ({
29665
31635
  ...prev,
@@ -29677,7 +31647,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29677
31647
  schema,
29678
31648
  schemaDefaults
29679
31649
  ]);
29680
- const startNewChat = (0, import_react40.useCallback)((opts) => {
31650
+ const startNewChat = (0, import_react41.useCallback)((opts) => {
29681
31651
  const shouldPush = opts?.pushHistory ?? true;
29682
31652
  if (shouldPush) {
29683
31653
  if (opts?.replace) {
@@ -29707,14 +31677,14 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29707
31677
  resetInitValue,
29708
31678
  newSessionPath
29709
31679
  ]);
29710
- const adoptSessionFromPath = (0, import_react40.useCallback)((sessionId2) => {
31680
+ const adoptSessionFromPath = (0, import_react41.useCallback)((sessionId2) => {
29711
31681
  appliedSessionIdRef.current = null;
29712
31682
  setPendingSessionId(sessionId2);
29713
31683
  setPendingReset(false);
29714
31684
  setInitOpen(false);
29715
31685
  setInitDirty(true);
29716
31686
  }, []);
29717
- const navigateToSession = (0, import_react40.useCallback)((sessionId2, opts) => {
31687
+ const navigateToSession = (0, import_react41.useCallback)((sessionId2, opts) => {
29718
31688
  const url = buildSessionUrl(sessionId2);
29719
31689
  if (opts?.replace) {
29720
31690
  window.history.replaceState({}, "", url);
@@ -29726,7 +31696,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29726
31696
  adoptSessionFromPath,
29727
31697
  buildSessionUrl
29728
31698
  ]);
29729
- (0, import_react40.useEffect)(() => {
31699
+ (0, import_react41.useEffect)(() => {
29730
31700
  if (initializedRef.current) return;
29731
31701
  initializedRef.current = true;
29732
31702
  const initialSession = getWorkspaceIdFromPath(void 0, sessionBasePath) ?? getWorkspaceIdFromPath();
@@ -29744,7 +31714,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29744
31714
  startNewChat,
29745
31715
  sessionBasePath
29746
31716
  ]);
29747
- (0, import_react40.useEffect)(() => {
31717
+ (0, import_react41.useEffect)(() => {
29748
31718
  if (!activeWorkspaceId) {
29749
31719
  externalSessionIdRef.current = null;
29750
31720
  return;
@@ -29756,7 +31726,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29756
31726
  activeWorkspaceId,
29757
31727
  adoptSessionFromPath
29758
31728
  ]);
29759
- (0, import_react40.useEffect)(() => {
31729
+ (0, import_react41.useEffect)(() => {
29760
31730
  const handler = () => {
29761
31731
  const sessionFromPath = getWorkspaceIdFromPath(void 0, sessionBasePath) ?? getWorkspaceIdFromPath();
29762
31732
  if (sessionFromPath) {
@@ -29774,7 +31744,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29774
31744
  startNewChat,
29775
31745
  sessionBasePath
29776
31746
  ]);
29777
- (0, import_react40.useEffect)(() => {
31747
+ (0, import_react41.useEffect)(() => {
29778
31748
  if (!pendingSessionId) return;
29779
31749
  if (simulator.connectionStatus !== "connected") return;
29780
31750
  if (appliedSessionIdRef.current === pendingSessionId) return;
@@ -29789,7 +31759,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29789
31759
  const serverNotesUpdatedAt = simulator.savedState?.notes?.updatedAt;
29790
31760
  const serverScore = simulator.savedState?.conversationScore?.score ?? null;
29791
31761
  const serverScoreUpdatedAt = simulator.savedState?.conversationScore?.updatedAt;
29792
- (0, import_react40.useEffect)(() => {
31762
+ (0, import_react41.useEffect)(() => {
29793
31763
  if (pendingNoteRef.current !== null) {
29794
31764
  if (serverNotesText === pendingNoteRef.current) {
29795
31765
  pendingNoteRef.current = null;
@@ -29802,7 +31772,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29802
31772
  }, [
29803
31773
  serverNotesText
29804
31774
  ]);
29805
- (0, import_react40.useEffect)(() => {
31775
+ (0, import_react41.useEffect)(() => {
29806
31776
  if (noteStatus !== "dirty") return;
29807
31777
  const handle = window.setTimeout(() => {
29808
31778
  setNoteStatus("saving");
@@ -29815,7 +31785,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29815
31785
  noteDraft,
29816
31786
  simulator
29817
31787
  ]);
29818
- (0, import_react40.useEffect)(() => {
31788
+ (0, import_react41.useEffect)(() => {
29819
31789
  if (pendingScoreRef.current !== null) {
29820
31790
  if (serverScore === pendingScoreRef.current) {
29821
31791
  pendingScoreRef.current = null;
@@ -29831,7 +31801,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29831
31801
  }, [
29832
31802
  serverScore
29833
31803
  ]);
29834
- const handleSend = (0, import_react40.useCallback)(() => {
31804
+ const handleSend = (0, import_react41.useCallback)(() => {
29835
31805
  const trimmed = message.trim();
29836
31806
  if (schema && initEditable) {
29837
31807
  if (!canStartWithInit) return;
@@ -29871,12 +31841,12 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29871
31841
  canStartWithInit,
29872
31842
  initValue
29873
31843
  ]);
29874
- const handleScore = (0, import_react40.useCallback)((refId, score, reason) => {
31844
+ const handleScore = (0, import_react41.useCallback)((refId, score, reason) => {
29875
31845
  simulator.sendFeedback(refId, score, reason);
29876
31846
  }, [
29877
31847
  simulator
29878
31848
  ]);
29879
- const handleReason = (0, import_react40.useCallback)((refId, score, reason) => {
31849
+ const handleReason = (0, import_react41.useCallback)((refId, score, reason) => {
29880
31850
  simulator.sendFeedback(refId, score, reason);
29881
31851
  }, [
29882
31852
  simulator
@@ -29886,16 +31856,16 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29886
31856
  const sessionPermalink = sessionId ? buildSessionUrl(sessionId) : null;
29887
31857
  const sessionStatePath = typeof runMeta.sessionStatePath === "string" ? runMeta.sessionStatePath : typeof runMeta.sessionDir === "string" ? `${runMeta.sessionDir}/state.json` : void 0;
29888
31858
  const currentSessionScore = pendingScoreRef.current !== null ? pendingScoreRef.current : serverScore;
29889
- (0, import_react40.useEffect)(() => {
31859
+ (0, import_react41.useEffect)(() => {
29890
31860
  if (!setNavActions) return;
29891
- setNavActions(/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, {
31861
+ setNavActions(/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, {
29892
31862
  children: [
29893
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, {
31863
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Button, {
29894
31864
  variant: "secondary",
29895
31865
  onClick: () => startNewChat(),
29896
31866
  children: "New chat"
29897
31867
  }),
29898
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
31868
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
29899
31869
  className: `status-indicator ${simulator.connectionStatus}`,
29900
31870
  children: simulator.connectionStatus
29901
31871
  })
@@ -29909,7 +31879,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29909
31879
  simulator.connectionStatus,
29910
31880
  startNewChat
29911
31881
  ]);
29912
- const deckSessions = (0, import_react40.useMemo)(() => {
31882
+ const deckSessions = (0, import_react41.useMemo)(() => {
29913
31883
  return workspaces.filter((session) => {
29914
31884
  if (!session) return false;
29915
31885
  if (typeof session.deck === "string") {
@@ -29928,22 +31898,22 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
29928
31898
  normalizedDeckPath,
29929
31899
  repoRootPath
29930
31900
  ]);
29931
- const recentSessionsEmpty = /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(RecentSessionsEmptyState, {
31901
+ const recentSessionsEmpty = /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(RecentSessionsEmptyState, {
29932
31902
  sessions: deckSessions,
29933
31903
  loading: workspacesLoading,
29934
31904
  error: workspacesError,
29935
31905
  onSelect: (id) => navigateToSession(id),
29936
31906
  onOpenAll: onOpenSessionsDrawer
29937
31907
  });
29938
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(PageShell, {
31908
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(PageShell, {
29939
31909
  children: [
29940
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(PageGrid, {
31910
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(PageGrid, {
29941
31911
  as: "main",
29942
31912
  className: "app-main",
29943
31913
  children: [
29944
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ConversationView, {
31914
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ConversationView, {
29945
31915
  messages,
29946
- header: schema ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(InitPanel, {
31916
+ header: schema ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(InitPanel, {
29947
31917
  schema,
29948
31918
  value: initValue,
29949
31919
  lockedValue: lockedInitValue,
@@ -30003,18 +31973,18 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
30003
31973
  onScore: handleScore,
30004
31974
  onReasonChange: handleReason
30005
31975
  }),
30006
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(TraceList, {
31976
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(TraceList, {
30007
31977
  traces: simulator.traceEvents
30008
31978
  })
30009
31979
  ]
30010
31980
  }),
30011
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("footer", {
31981
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("footer", {
30012
31982
  className: "composer",
30013
31983
  children: [
30014
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
31984
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30015
31985
  className: "composer-inputs",
30016
31986
  children: [
30017
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("textarea", {
31987
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("textarea", {
30018
31988
  className: "message-input",
30019
31989
  "data-testid": "debug-message-input",
30020
31990
  placeholder: schema && initEditable ? "Optional first message (init will be sent too)" : "Optional message (assistant can start)",
@@ -30027,23 +31997,23 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
30027
31997
  }
30028
31998
  }
30029
31999
  }),
30030
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
32000
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30031
32001
  className: "notes-inline",
30032
32002
  children: [
30033
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("header", {
32003
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("header", {
30034
32004
  children: [
30035
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("label", {
32005
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("label", {
30036
32006
  htmlFor: "session-notes",
30037
32007
  children: "Session notes"
30038
32008
  }),
30039
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
32009
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30040
32010
  className: "rating-controls",
30041
32011
  children: [
30042
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", {
32012
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", {
30043
32013
  className: "rating-label",
30044
32014
  children: "Overall score"
30045
32015
  }),
30046
- SCORE_VALUES.map((value) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", {
32016
+ SCORE_VALUES.map((value) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", {
30047
32017
  type: "button",
30048
32018
  className: classNames("rating-button", currentSessionScore === value && "active"),
30049
32019
  onClick: () => {
@@ -30057,7 +32027,7 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
30057
32027
  })
30058
32028
  ]
30059
32029
  }),
30060
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("textarea", {
32030
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("textarea", {
30061
32031
  id: "session-notes",
30062
32032
  value: noteDraft,
30063
32033
  onChange: (e) => {
@@ -30066,14 +32036,14 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
30066
32036
  },
30067
32037
  placeholder: "Add context or TODOs..."
30068
32038
  }),
30069
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
32039
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
30070
32040
  className: "notes-inline-status",
30071
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", {
32041
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", {
30072
32042
  className: classNames("state", noteStatus === "saving" && "saving", noteStatus === "dirty" && "unsaved", noteStatus === "idle" && "idle", noteStatus === "saved" && "saved"),
30073
32043
  children: noteStatus === "saving" ? "Saving\u2026" : noteStatus === "dirty" ? "Unsaved changes\u2026" : noteStatus === "saved" ? serverNotesUpdatedAt ? `Saved ${formatTimestamp(serverNotesUpdatedAt)}` : "Saved" : "No notes yet."
30074
32044
  })
30075
32045
  }),
30076
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
32046
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30077
32047
  className: "rating-status",
30078
32048
  children: [
30079
32049
  "Overall score:",
@@ -30087,52 +32057,52 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
30087
32057
  })
30088
32058
  ]
30089
32059
  }),
30090
- pendingReset && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
32060
+ pendingReset && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
30091
32061
  className: "reset-note",
30092
32062
  children: "Next message will start a new chat."
30093
32063
  }),
30094
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
32064
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30095
32065
  className: "composer-actions",
30096
32066
  children: [
30097
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, {
32067
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Button, {
30098
32068
  variant: "primary",
30099
32069
  onClick: handleSend,
30100
32070
  disabled: schema && initEditable && !canStartWithInit,
30101
32071
  "data-testid": "debug-send",
30102
32072
  children: schema && initEditable ? "Start chat" : "Send"
30103
32073
  }),
30104
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, {
32074
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Button, {
30105
32075
  variant: "secondary",
30106
32076
  onClick: simulator.reconnect,
30107
32077
  children: "Reconnect"
30108
32078
  })
30109
32079
  ]
30110
32080
  }),
30111
- simulator.errors.map((err, idx) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
32081
+ simulator.errors.map((err, idx) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
30112
32082
  className: "error",
30113
32083
  children: err
30114
32084
  }, idx)),
30115
- sessionId && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
32085
+ sessionId && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30116
32086
  className: "session-meta",
30117
32087
  children: [
30118
32088
  "Session: ",
30119
- sessionPermalink ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", {
32089
+ sessionPermalink ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("a", {
30120
32090
  href: sessionPermalink,
30121
32091
  className: "session-link",
30122
32092
  title: "Open session permalink",
30123
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("code", {
32093
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("code", {
30124
32094
  children: sessionId
30125
32095
  })
30126
- }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("code", {
32096
+ }) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("code", {
30127
32097
  children: sessionId
30128
32098
  })
30129
32099
  ]
30130
32100
  }),
30131
- sessionStatePath && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
32101
+ sessionStatePath && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30132
32102
  className: "session-meta session-path",
30133
32103
  children: [
30134
32104
  "State file: ",
30135
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("code", {
32105
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("code", {
30136
32106
  children: sessionStatePath
30137
32107
  })
30138
32108
  ]
@@ -30144,18 +32114,18 @@ function SimulatorApp({ basePath, setNavActions, workspacesApi, onOpenSessionsDr
30144
32114
  }
30145
32115
  function App() {
30146
32116
  const simulatorBasePath = WORKSPACES_BASE_PATH;
30147
- const [path, setPath] = (0, import_react40.useState)(() => normalizeAppPath(window.location.pathname));
30148
- const [bundleStamp, setBundleStamp] = (0, import_react40.useState)(null);
30149
- const [navActions, setNavActions] = (0, import_react40.useState)(null);
30150
- const [sessionsDrawerOpen, setSessionsDrawerOpen] = (0, import_react40.useState)(false);
30151
- const [workbenchDrawerOpen, setWorkbenchDrawerOpen] = (0, import_react40.useState)(true);
30152
- const [workbenchComposerChips, setWorkbenchComposerChips] = (0, import_react40.useState)([]);
30153
- const [workspaceRunIds, setWorkspaceRunIds] = (0, import_react40.useState)({
32117
+ const [path, setPath] = (0, import_react41.useState)(() => normalizeAppPath(window.location.pathname));
32118
+ const [bundleStamp, setBundleStamp] = (0, import_react41.useState)(null);
32119
+ const [navActions, setNavActions] = (0, import_react41.useState)(null);
32120
+ const [sessionsDrawerOpen, setSessionsDrawerOpen] = (0, import_react41.useState)(false);
32121
+ const [workbenchDrawerOpen, setWorkbenchDrawerOpen] = (0, import_react41.useState)(true);
32122
+ const [workbenchComposerChips, setWorkbenchComposerChips] = (0, import_react41.useState)([]);
32123
+ const [workspaceRunIds, setWorkspaceRunIds] = (0, import_react41.useState)({
30154
32124
  testRunId: null,
30155
32125
  gradeRunId: null
30156
32126
  });
30157
32127
  const workspacesApi = useWorkspaces();
30158
- const [testBotResetToken, setTestBotResetToken] = (0, import_react40.useState)(0);
32128
+ const [testBotResetToken, setTestBotResetToken] = (0, import_react41.useState)(0);
30159
32129
  const pathRoute = getWorkspaceRouteFromPath(path);
30160
32130
  const livePath = window.location.pathname.replace(/\/+$/, "") || "/";
30161
32131
  const liveRoute = getWorkspaceRouteFromPath(livePath);
@@ -30164,23 +32134,23 @@ function App() {
30164
32134
  const activeWorkspaceId = routeRequestsNewWorkspace ? null : routeState?.workspaceId ?? workspaceIdFromWindow;
30165
32135
  const requestedTestRunId = routeState?.tab === "test" ? routeState.testRunId ?? null : null;
30166
32136
  const requestedGradeRunId = routeState?.tab === "grade" ? routeState.gradeRunId ?? null : null;
30167
- const lastWorkspaceIdRef = (0, import_react40.useRef)(null);
30168
- const [workbenchSessionDetail, setWorkbenchSessionDetail] = (0, import_react40.useState)(null);
30169
- const [workbenchSessionDetailError, setWorkbenchSessionDetailError] = (0, import_react40.useState)(null);
30170
- const [workbenchSessionDetailLoading, setWorkbenchSessionDetailLoading] = (0, import_react40.useState)(false);
30171
- const workbenchSessionDetailRequestRef = (0, import_react40.useRef)(0);
30172
- const workbenchSessionRetryRef = (0, import_react40.useRef)({});
30173
- const workbenchRefreshTimeoutRef = (0, import_react40.useRef)(null);
30174
- const activeWorkspaceIdRef = (0, import_react40.useRef)(activeWorkspaceId);
30175
- const workspaceInitRef = (0, import_react40.useRef)(false);
30176
- (0, import_react40.useEffect)(() => {
32137
+ const lastWorkspaceIdRef = (0, import_react41.useRef)(null);
32138
+ const [workbenchSessionDetail, setWorkbenchSessionDetail] = (0, import_react41.useState)(null);
32139
+ const [workbenchSessionDetailError, setWorkbenchSessionDetailError] = (0, import_react41.useState)(null);
32140
+ const [workbenchSessionDetailLoading, setWorkbenchSessionDetailLoading] = (0, import_react41.useState)(false);
32141
+ const workbenchSessionDetailRequestRef = (0, import_react41.useRef)(0);
32142
+ const workbenchSessionRetryRef = (0, import_react41.useRef)({});
32143
+ const workbenchRefreshTimeoutRef = (0, import_react41.useRef)(null);
32144
+ const activeWorkspaceIdRef = (0, import_react41.useRef)(activeWorkspaceId);
32145
+ const workspaceInitRef = (0, import_react41.useRef)(false);
32146
+ (0, import_react41.useEffect)(() => {
30177
32147
  if (activeWorkspaceId) {
30178
32148
  lastWorkspaceIdRef.current = activeWorkspaceId;
30179
32149
  }
30180
32150
  }, [
30181
32151
  activeWorkspaceId
30182
32152
  ]);
30183
- (0, import_react40.useEffect)(() => {
32153
+ (0, import_react41.useEffect)(() => {
30184
32154
  if (!activeWorkspaceId) {
30185
32155
  setWorkbenchComposerChips([]);
30186
32156
  return;
@@ -30189,7 +32159,7 @@ function App() {
30189
32159
  }, [
30190
32160
  activeWorkspaceId
30191
32161
  ]);
30192
- (0, import_react40.useEffect)(() => {
32162
+ (0, import_react41.useEffect)(() => {
30193
32163
  const syncPath = () => setPath(normalizeAppPath(window.location.pathname));
30194
32164
  const historyObj = window.history;
30195
32165
  const originalPushState = historyObj.pushState.bind(historyObj);
@@ -30211,7 +32181,7 @@ function App() {
30211
32181
  window.removeEventListener("locationchange", syncPath);
30212
32182
  };
30213
32183
  }, []);
30214
- const loadWorkbenchSessionDetail = (0, import_react40.useCallback)(async (sessionId) => {
32184
+ const loadWorkbenchSessionDetail = (0, import_react41.useCallback)(async (sessionId) => {
30215
32185
  const requestId = ++workbenchSessionDetailRequestRef.current;
30216
32186
  const shouldApply = () => requestId === workbenchSessionDetailRequestRef.current && activeWorkspaceIdRef.current === sessionId;
30217
32187
  try {
@@ -30253,7 +32223,7 @@ function App() {
30253
32223
  }
30254
32224
  }
30255
32225
  }, []);
30256
- const scheduleWorkbenchRefresh = (0, import_react40.useCallback)(() => {
32226
+ const scheduleWorkbenchRefresh = (0, import_react41.useCallback)(() => {
30257
32227
  if (!activeWorkspaceId) return;
30258
32228
  if (workbenchRefreshTimeoutRef.current) {
30259
32229
  window.clearTimeout(workbenchRefreshTimeoutRef.current);
@@ -30268,7 +32238,7 @@ function App() {
30268
32238
  activeWorkspaceId,
30269
32239
  loadWorkbenchSessionDetail
30270
32240
  ]);
30271
- (0, import_react40.useEffect)(() => {
32241
+ (0, import_react41.useEffect)(() => {
30272
32242
  activeWorkspaceIdRef.current = activeWorkspaceId;
30273
32243
  if (workbenchRefreshTimeoutRef.current) {
30274
32244
  window.clearTimeout(workbenchRefreshTimeoutRef.current);
@@ -30277,14 +32247,14 @@ function App() {
30277
32247
  }, [
30278
32248
  activeWorkspaceId
30279
32249
  ]);
30280
- (0, import_react40.useEffect)(() => {
32250
+ (0, import_react41.useEffect)(() => {
30281
32251
  return () => {
30282
32252
  if (workbenchRefreshTimeoutRef.current) {
30283
32253
  window.clearTimeout(workbenchRefreshTimeoutRef.current);
30284
32254
  }
30285
32255
  };
30286
32256
  }, []);
30287
- (0, import_react40.useEffect)(() => {
32257
+ (0, import_react41.useEffect)(() => {
30288
32258
  if (!activeWorkspaceId) {
30289
32259
  setWorkbenchSessionDetail(null);
30290
32260
  setWorkbenchSessionDetailError(null);
@@ -30297,14 +32267,14 @@ function App() {
30297
32267
  activeWorkspaceId,
30298
32268
  loadWorkbenchSessionDetail
30299
32269
  ]);
30300
- const handleFeedbackPersisted = (0, import_react40.useCallback)((workspaceId) => {
32270
+ const handleFeedbackPersisted = (0, import_react41.useCallback)((workspaceId) => {
30301
32271
  if (!workspaceId) return;
30302
32272
  if (activeWorkspaceIdRef.current !== workspaceId) return;
30303
32273
  scheduleWorkbenchRefresh();
30304
32274
  }, [
30305
32275
  scheduleWorkbenchRefresh
30306
32276
  ]);
30307
- const applyFlagsUpdate = (0, import_react40.useCallback)((flags) => {
32277
+ const applyFlagsUpdate = (0, import_react41.useCallback)((flags) => {
30308
32278
  setWorkbenchSessionDetail((prev) => {
30309
32279
  if (!prev) return prev;
30310
32280
  return {
@@ -30319,7 +32289,7 @@ function App() {
30319
32289
  }, [
30320
32290
  scheduleWorkbenchRefresh
30321
32291
  ]);
30322
- const optimisticToggleFlag = (0, import_react40.useCallback)((item) => {
32292
+ const optimisticToggleFlag = (0, import_react41.useCallback)((item) => {
30323
32293
  setWorkbenchSessionDetail((prev) => {
30324
32294
  if (!prev) return prev;
30325
32295
  const meta = prev.meta ?? {};
@@ -30344,7 +32314,7 @@ function App() {
30344
32314
  };
30345
32315
  });
30346
32316
  }, []);
30347
- const optimisticFlagReason = (0, import_react40.useCallback)((refId, reason) => {
32317
+ const optimisticFlagReason = (0, import_react41.useCallback)((refId, reason) => {
30348
32318
  setWorkbenchSessionDetail((prev) => {
30349
32319
  if (!prev) return prev;
30350
32320
  const meta = prev.meta ?? {};
@@ -30362,7 +32332,7 @@ function App() {
30362
32332
  };
30363
32333
  });
30364
32334
  }, []);
30365
- (0, import_react40.useEffect)(() => {
32335
+ (0, import_react41.useEffect)(() => {
30366
32336
  const loadBundleStamp = async () => {
30367
32337
  try {
30368
32338
  const res = await fetch("/ui/bundle.js", {
@@ -30378,36 +32348,36 @@ function App() {
30378
32348
  };
30379
32349
  loadBundleStamp();
30380
32350
  }, []);
30381
- const navigate = (0, import_react40.useCallback)((next) => {
32351
+ const navigate = (0, import_react41.useCallback)((next) => {
30382
32352
  if (next === path) return;
30383
32353
  window.history.pushState({}, "", next);
30384
32354
  setPath(next);
30385
32355
  }, [
30386
32356
  path
30387
32357
  ]);
30388
- const replacePath = (0, import_react40.useCallback)((next) => {
32358
+ const replacePath = (0, import_react41.useCallback)((next) => {
30389
32359
  if (next === path) return;
30390
32360
  window.history.replaceState({}, "", next);
30391
32361
  setPath(next);
30392
32362
  }, [
30393
32363
  path
30394
32364
  ]);
30395
- const handleAppPathChange = (0, import_react40.useCallback)((next) => {
32365
+ const handleAppPathChange = (0, import_react41.useCallback)((next) => {
30396
32366
  setPath(normalizeAppPath(next));
30397
32367
  }, []);
30398
- const handleReplaceTestBotSession = (0, import_react40.useCallback)((workspaceId, runId) => replacePath(buildTestPath(workspaceId, runId)), [
32368
+ const handleReplaceTestBotSession = (0, import_react41.useCallback)((workspaceId, runId) => replacePath(buildTestPath(workspaceId, runId)), [
30399
32369
  replacePath
30400
32370
  ]);
30401
- const handleResetTestBotSession = (0, import_react40.useCallback)(() => replacePath(buildTestPath(activeWorkspaceId ?? void 0)), [
32371
+ const handleResetTestBotSession = (0, import_react41.useCallback)(() => replacePath(buildTestPath(activeWorkspaceId ?? void 0)), [
30402
32372
  activeWorkspaceId,
30403
32373
  replacePath
30404
32374
  ]);
30405
- const handleWorkspaceChange = (0, import_react40.useCallback)((workspaceId) => {
32375
+ const handleWorkspaceChange = (0, import_react41.useCallback)((workspaceId) => {
30406
32376
  replacePath(buildWorkspacePath("build", workspaceId));
30407
32377
  }, [
30408
32378
  replacePath
30409
32379
  ]);
30410
- (0, import_react40.useEffect)(() => {
32380
+ (0, import_react41.useEffect)(() => {
30411
32381
  if (!buildTabEnabled && path === "/build") {
30412
32382
  replacePath(DOCS_PATH);
30413
32383
  }
@@ -30415,17 +32385,42 @@ function App() {
30415
32385
  path,
30416
32386
  replacePath
30417
32387
  ]);
32388
+ (0, import_react41.useEffect)(() => {
32389
+ if (verifyTabEnabled) return;
32390
+ const route = getWorkspaceRouteFromPath(path);
32391
+ if (route?.tab !== "verify") return;
32392
+ const fallback = route.workspaceId ? buildGradePath(route.workspaceId) : DEFAULT_GRADE_PATH;
32393
+ replacePath(fallback);
32394
+ }, [
32395
+ path,
32396
+ replacePath,
32397
+ verifyTabEnabled
32398
+ ]);
30418
32399
  const isDocs = path === DOCS_PATH;
30419
32400
  const routeTab = liveRoute?.tab ?? pathRoute?.tab;
30420
32401
  const isBuild = buildTabEnabled && (routeTab === "build" || path === "/build");
30421
32402
  const isTestBot = !isDocs && (routeTab === "test" || /\/test$/.test(path));
30422
32403
  const isGrade = !isDocs && routeTab === "grade";
30423
- const currentPage = isDocs ? "docs" : isBuild ? "build" : isTestBot ? "test" : isGrade ? "grade" : "debug";
30424
- (0, import_react40.useEffect)(() => {
32404
+ const isVerify = !isDocs && verifyTabEnabled && routeTab === "verify";
32405
+ let currentPage;
32406
+ if (isDocs) {
32407
+ currentPage = "docs";
32408
+ } else if (isBuild) {
32409
+ currentPage = "build";
32410
+ } else if (isTestBot) {
32411
+ currentPage = "test";
32412
+ } else if (isGrade) {
32413
+ currentPage = "grade";
32414
+ } else if (isVerify) {
32415
+ currentPage = "verify";
32416
+ } else {
32417
+ currentPage = "debug";
32418
+ }
32419
+ (0, import_react41.useEffect)(() => {
30425
32420
  if (activeWorkspaceId || lastWorkspaceIdRef.current) return;
30426
32421
  if (!routeRequestsNewWorkspace) return;
30427
32422
  if (workspaceInitRef.current) return;
30428
- if (currentPage !== "build" && currentPage !== "test" && currentPage !== "grade") {
32423
+ if (currentPage !== "build" && currentPage !== "test" && currentPage !== "grade" && currentPage !== "verify") {
30429
32424
  return;
30430
32425
  }
30431
32426
  workspaceInitRef.current = true;
@@ -30434,7 +32429,22 @@ function App() {
30434
32429
  }).then(async (res) => {
30435
32430
  const data = await res.json().catch(() => ({}));
30436
32431
  if (!res.ok || typeof data.workspaceId !== "string") return;
30437
- const nextPath = currentPage === "test" ? buildWorkspacePath("test", data.workspaceId) : currentPage === "grade" ? buildGradePath(data.workspaceId) : buildWorkspacePath("build", data.workspaceId);
32432
+ let nextPath;
32433
+ switch (currentPage) {
32434
+ case "test":
32435
+ nextPath = buildWorkspacePath("test", data.workspaceId);
32436
+ break;
32437
+ case "grade":
32438
+ nextPath = buildGradePath(data.workspaceId);
32439
+ break;
32440
+ case "verify":
32441
+ nextPath = buildWorkspacePath("verify", data.workspaceId);
32442
+ break;
32443
+ case "build":
32444
+ default:
32445
+ nextPath = buildWorkspacePath("build", data.workspaceId);
32446
+ break;
32447
+ }
30438
32448
  replacePath(nextPath);
30439
32449
  }).finally(() => {
30440
32450
  workspaceInitRef.current = false;
@@ -30445,9 +32455,9 @@ function App() {
30445
32455
  replacePath,
30446
32456
  routeRequestsNewWorkspace
30447
32457
  ]);
30448
- const resolveNavWorkspaceId = (0, import_react40.useCallback)(() => {
32458
+ const resolveNavWorkspaceId = (0, import_react41.useCallback)(() => {
30449
32459
  const normalizedPath = (window.location.pathname || "/").replace(/\/+$/, "") || "/";
30450
- const directMatch = normalizedPath.match(/^\/workspaces\/([^/]+)\/(?:debug|build|test|grade)(?:\/[^/]+)?$/);
32460
+ const directMatch = normalizedPath.match(/^\/workspaces\/([^/]+)\/(?:debug|build|test|grade|verify)(?:\/[^/]+)?$/);
30451
32461
  if (directMatch?.[1] && directMatch[1] !== "new") {
30452
32462
  return decodeURIComponent(directMatch[1]);
30453
32463
  }
@@ -30455,7 +32465,7 @@ function App() {
30455
32465
  }, [
30456
32466
  activeWorkspaceId
30457
32467
  ]);
30458
- const resolveNavPath = (0, import_react40.useCallback)((next) => {
32468
+ const resolveNavPath = (0, import_react41.useCallback)((next) => {
30459
32469
  if (next === "docs") return DOCS_PATH;
30460
32470
  const workspaceId = resolveNavWorkspaceId();
30461
32471
  if (next === "build") return buildWorkspacePath("build", workspaceId);
@@ -30465,21 +32475,44 @@ function App() {
30465
32475
  if (next === "grade") {
30466
32476
  return workspaceId ? buildGradePath(workspaceId, workspaceRunIds.gradeRunId ?? void 0) : DEFAULT_GRADE_PATH;
30467
32477
  }
32478
+ if (next === "verify") {
32479
+ return workspaceId ? buildVerifyPath(workspaceId) : DEFAULT_VERIFY_PATH;
32480
+ }
30468
32481
  return buildWorkspacePath("debug", workspaceId);
30469
32482
  }, [
32483
+ DEFAULT_VERIFY_PATH,
30470
32484
  resolveNavWorkspaceId,
30471
32485
  workspaceRunIds.gradeRunId,
30472
32486
  workspaceRunIds.testRunId
30473
32487
  ]);
30474
- const handleSelectSession = (0, import_react40.useCallback)((sessionId) => {
30475
- const nextPath = currentPage === "test" || currentPage === "docs" ? buildWorkspacePath("test", sessionId) : currentPage === "grade" ? buildGradePath(sessionId) : currentPage === "build" ? buildWorkspacePath("build", sessionId) : buildWorkspacePath("debug", sessionId);
32488
+ const handleSelectSession = (0, import_react41.useCallback)((sessionId) => {
32489
+ let nextPath;
32490
+ switch (currentPage) {
32491
+ case "docs":
32492
+ case "test":
32493
+ nextPath = buildWorkspacePath("test", sessionId);
32494
+ break;
32495
+ case "grade":
32496
+ nextPath = buildGradePath(sessionId);
32497
+ break;
32498
+ case "verify":
32499
+ nextPath = buildVerifyPath(sessionId);
32500
+ break;
32501
+ case "build":
32502
+ nextPath = buildWorkspacePath("build", sessionId);
32503
+ break;
32504
+ case "debug":
32505
+ default:
32506
+ nextPath = buildWorkspacePath("debug", sessionId);
32507
+ break;
32508
+ }
30476
32509
  navigate(nextPath);
30477
32510
  setSessionsDrawerOpen(false);
30478
32511
  }, [
30479
32512
  currentPage,
30480
32513
  navigate
30481
32514
  ]);
30482
- (0, import_react40.useEffect)(() => {
32515
+ (0, import_react41.useEffect)(() => {
30483
32516
  if (sessionsDrawerOpen) {
30484
32517
  workspacesApi.refresh();
30485
32518
  }
@@ -30487,7 +32520,7 @@ function App() {
30487
32520
  workspacesApi.refresh,
30488
32521
  sessionsDrawerOpen
30489
32522
  ]);
30490
- const deckSessions = (0, import_react40.useMemo)(() => {
32523
+ const deckSessions = (0, import_react41.useMemo)(() => {
30491
32524
  if (workspaceIdFromWindow) {
30492
32525
  return workspacesApi.workspaces;
30493
32526
  }
@@ -30510,7 +32543,7 @@ function App() {
30510
32543
  repoRootPath,
30511
32544
  workspaceIdFromWindow
30512
32545
  ]);
30513
- const handleDeleteAll = (0, import_react40.useCallback)(async () => {
32546
+ const handleDeleteAll = (0, import_react41.useCallback)(async () => {
30514
32547
  await workspacesApi.deleteAll(deckSessions);
30515
32548
  setTestBotResetToken((prev) => prev + 1);
30516
32549
  setSessionsDrawerOpen(false);
@@ -30519,7 +32552,7 @@ function App() {
30519
32552
  deckSessions,
30520
32553
  workspacesApi.deleteAll
30521
32554
  ]);
30522
- const handleDeleteSession = (0, import_react40.useCallback)(async (sessionId) => {
32555
+ const handleDeleteSession = (0, import_react41.useCallback)(async (sessionId) => {
30523
32556
  await workspacesApi.deleteWorkspace(sessionId);
30524
32557
  if (sessionId === activeWorkspaceId) {
30525
32558
  window.location.assign(DEFAULT_TEST_PATH);
@@ -30528,11 +32561,12 @@ function App() {
30528
32561
  activeWorkspaceId,
30529
32562
  workspacesApi.deleteWorkspace
30530
32563
  ]);
30531
- const handleAddScenarioErrorToWorkbench = (0, import_react40.useCallback)((payload) => {
32564
+ const handleAddErrorToWorkbench = (0, import_react41.useCallback)((payload) => {
30532
32565
  const resolvedWorkspaceId = payload.workspaceId ?? activeWorkspaceId ?? void 0;
32566
+ const source = payload.source ?? "scenario_run_error";
30533
32567
  const nextChip = {
30534
- chipId: `error:${resolvedWorkspaceId ?? ""}:${payload.runId ?? ""}:${payload.error}`,
30535
- source: "scenario_run_error",
32568
+ chipId: `error:${source}:${resolvedWorkspaceId ?? ""}:${payload.runId ?? ""}:${payload.error}`,
32569
+ source,
30536
32570
  workspaceId: resolvedWorkspaceId,
30537
32571
  runId: payload.runId,
30538
32572
  error: payload.error,
@@ -30559,30 +32593,97 @@ function App() {
30559
32593
  }, [
30560
32594
  activeWorkspaceId
30561
32595
  ]);
30562
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(WorkspaceProvider, {
32596
+ const pageContent = (0, import_react41.useMemo)(() => {
32597
+ switch (currentPage) {
32598
+ case "docs":
32599
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(DocsPage, {});
32600
+ case "build":
32601
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(BuildPage, {
32602
+ setNavActions
32603
+ });
32604
+ case "debug":
32605
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(SimulatorApp, {
32606
+ basePath: simulatorBasePath,
32607
+ setNavActions,
32608
+ workspacesApi,
32609
+ onOpenSessionsDrawer: () => setSessionsDrawerOpen(true),
32610
+ activeWorkspaceId
32611
+ });
32612
+ case "test":
32613
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(TestBotPage, {
32614
+ onReplaceTestBotSession: handleReplaceTestBotSession,
32615
+ onResetTestBotSession: handleResetTestBotSession,
32616
+ activeWorkspaceId,
32617
+ requestedRunId: requestedTestRunId,
32618
+ resetToken: testBotResetToken,
32619
+ setNavActions,
32620
+ onFeedbackPersisted: handleFeedbackPersisted,
32621
+ onAddErrorToWorkbench: handleAddErrorToWorkbench
32622
+ });
32623
+ case "verify":
32624
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(VerifyPage_default, {
32625
+ setNavActions,
32626
+ onAppPathChange: handleAppPathChange,
32627
+ activeWorkspaceId,
32628
+ composerChips: workbenchComposerChips,
32629
+ onComposerChipsChange: setWorkbenchComposerChips
32630
+ });
32631
+ case "grade":
32632
+ default:
32633
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(GradePage_default, {
32634
+ setNavActions,
32635
+ onAppPathChange: handleAppPathChange,
32636
+ activeWorkspaceId,
32637
+ requestedGradeRunId,
32638
+ onFlagsUpdate: applyFlagsUpdate,
32639
+ onOptimisticToggleFlag: optimisticToggleFlag,
32640
+ onOptimisticFlagReason: optimisticFlagReason,
32641
+ onAddErrorToWorkbench: handleAddErrorToWorkbench
32642
+ });
32643
+ }
32644
+ }, [
32645
+ activeWorkspaceId,
32646
+ applyFlagsUpdate,
32647
+ currentPage,
32648
+ handleAddErrorToWorkbench,
32649
+ handleAppPathChange,
32650
+ handleFeedbackPersisted,
32651
+ handleReplaceTestBotSession,
32652
+ handleResetTestBotSession,
32653
+ optimisticFlagReason,
32654
+ optimisticToggleFlag,
32655
+ requestedGradeRunId,
32656
+ requestedTestRunId,
32657
+ setNavActions,
32658
+ simulatorBasePath,
32659
+ testBotResetToken,
32660
+ workbenchComposerChips,
32661
+ workspacesApi
32662
+ ]);
32663
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(WorkspaceProvider, {
30563
32664
  workspaceId: activeWorkspaceId,
30564
32665
  onWorkspaceChange: handleWorkspaceChange,
30565
32666
  requestedTestRunId: routeState?.tab === "test" ? requestedTestRunId : void 0,
30566
32667
  requestedGradeRunId: routeState?.tab === "grade" ? requestedGradeRunId : void 0,
30567
32668
  onRoutingStateChange: setWorkspaceRunIds,
30568
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, {
32669
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, {
30569
32670
  children: [
30570
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
32671
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
30571
32672
  className: "app-frame",
30572
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
32673
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30573
32674
  className: "app-root",
30574
32675
  children: [
30575
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
32676
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30576
32677
  className: "top-nav",
30577
32678
  children: [
30578
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
32679
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
30579
32680
  className: "top-nav-left",
30580
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, {
32681
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Button, {
30581
32682
  variant: sessionsDrawerOpen ? "primary-deemph" : "ghost",
30582
32683
  className: classNames("sessions-toggle", sessionsDrawerOpen && "active"),
30583
32684
  onClick: () => setSessionsDrawerOpen(true),
30584
32685
  "data-testid": "nav-sessions",
30585
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Icon, {
32686
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Icon, {
30586
32687
  name: "hamburgerMenu",
30587
32688
  size: 17,
30588
32689
  style: {
@@ -30591,7 +32692,7 @@ function App() {
30591
32692
  })
30592
32693
  })
30593
32694
  }),
30594
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Tabs, {
32695
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Tabs, {
30595
32696
  className: "top-nav-buttons",
30596
32697
  activeId: currentPage,
30597
32698
  onChange: (next) => navigate(resolveNavPath(next)),
@@ -30622,6 +32723,14 @@ function App() {
30622
32723
  testId: "nav-grade",
30623
32724
  href: resolveNavPath("grade")
30624
32725
  },
32726
+ ...verifyTabEnabled ? [
32727
+ {
32728
+ id: "verify",
32729
+ label: "Verify",
32730
+ testId: "nav-verify",
32731
+ href: resolveNavPath("verify")
32732
+ }
32733
+ ] : [],
30625
32734
  {
30626
32735
  id: "debug",
30627
32736
  label: "Debug",
@@ -30630,27 +32739,27 @@ function App() {
30630
32739
  }
30631
32740
  ]
30632
32741
  }),
30633
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
32742
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
30634
32743
  className: "top-nav-center",
30635
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", {
32744
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", {
30636
32745
  className: "top-nav-deck",
30637
32746
  title: deckPath,
30638
32747
  children: deckLabel
30639
32748
  })
30640
32749
  }),
30641
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
32750
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
30642
32751
  className: "top-nav-right",
30643
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
32752
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30644
32753
  className: "top-nav-actions",
30645
32754
  children: [
30646
32755
  navActions,
30647
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, {
32756
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Button, {
30648
32757
  variant: workbenchDrawerOpen ? "primary-deemph" : "ghost",
30649
32758
  className: classNames("workbench-toggle", workbenchDrawerOpen && "active"),
30650
32759
  onClick: () => setWorkbenchDrawerOpen((prev) => !prev),
30651
32760
  "aria-label": workbenchDrawerOpen ? "Close workbench drawer" : "Open workbench drawer",
30652
32761
  "data-testid": "nav-workbench",
30653
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Icon, {
32762
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Icon, {
30654
32763
  name: "chat",
30655
32764
  size: 16,
30656
32765
  style: {
@@ -30663,39 +32772,14 @@ function App() {
30663
32772
  })
30664
32773
  ]
30665
32774
  }),
30666
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", {
32775
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", {
30667
32776
  className: "app-content-frame",
30668
32777
  children: [
30669
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", {
32778
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", {
30670
32779
  className: "page-shell",
30671
- children: currentPage === "docs" ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(DocsPage, {}) : currentPage === "build" ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(BuildPage, {
30672
- setNavActions
30673
- }) : currentPage === "debug" ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SimulatorApp, {
30674
- basePath: simulatorBasePath,
30675
- setNavActions,
30676
- workspacesApi,
30677
- onOpenSessionsDrawer: () => setSessionsDrawerOpen(true),
30678
- activeWorkspaceId
30679
- }) : currentPage === "test" ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(TestBotPage, {
30680
- onReplaceTestBotSession: handleReplaceTestBotSession,
30681
- onResetTestBotSession: handleResetTestBotSession,
30682
- activeWorkspaceId,
30683
- requestedRunId: requestedTestRunId,
30684
- resetToken: testBotResetToken,
30685
- setNavActions,
30686
- onFeedbackPersisted: handleFeedbackPersisted,
30687
- onAddScenarioErrorToWorkbench: handleAddScenarioErrorToWorkbench
30688
- }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(GradePage_default, {
30689
- setNavActions,
30690
- onAppPathChange: handleAppPathChange,
30691
- activeWorkspaceId,
30692
- requestedGradeRunId,
30693
- onFlagsUpdate: applyFlagsUpdate,
30694
- onOptimisticToggleFlag: optimisticToggleFlag,
30695
- onOptimisticFlagReason: optimisticFlagReason
30696
- })
32780
+ children: pageContent
30697
32781
  }),
30698
- workbenchDrawerOpen && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(WorkbenchDrawer, {
32782
+ workbenchDrawerOpen && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(WorkbenchDrawer, {
30699
32783
  open: workbenchDrawerOpen,
30700
32784
  onClose: () => setWorkbenchDrawerOpen(false),
30701
32785
  loading: workbenchSessionDetailLoading,
@@ -30710,7 +32794,7 @@ function App() {
30710
32794
  ]
30711
32795
  })
30712
32796
  }),
30713
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AppDrawer, {
32797
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AppDrawer, {
30714
32798
  open: sessionsDrawerOpen,
30715
32799
  workspaces: deckSessions,
30716
32800
  loading: workspacesApi.loading,
@@ -30727,8 +32811,8 @@ function App() {
30727
32811
  })
30728
32812
  });
30729
32813
  }
30730
- (0, import_client.createRoot)(document.getElementById("root")).render(/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react40.default.StrictMode, {
30731
- children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(App, {})
32814
+ (0, import_client.createRoot)(document.getElementById("root")).render(/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react41.default.StrictMode, {
32815
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(App, {})
30732
32816
  }));
30733
32817
  /**
30734
32818
  * @license React