@sanity/ailf-studio 1.6.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -521,6 +521,15 @@ interface JudgmentData {
521
521
  /** Docs the task expected the model to use */
522
522
  canonicalDocs?: DocumentRef[];
523
523
  dimension: string;
524
+ /**
525
+ * `graderJudgments` manifest entry key = `formatEntryKey({mode, task,
526
+ * model, grader})` from the slim-report publisher. Present on reports
527
+ * published under W0051+. Consumed by `useArtifactDetail` in
528
+ * `JudgmentDetailDrawer` to hydrate the full reasoning from GCS, and by
529
+ * `JudgmentList` to drive hover-prefetch and the list row's data hook.
530
+ * Optional so legacy reports (pre-W0051) still type-check.
531
+ */
532
+ id?: string;
524
533
  modelId: string;
525
534
  /** True when the model failed to produce output (empty response, API error, refusal) */
526
535
  outputFailure?: boolean;
@@ -588,7 +597,6 @@ interface SummaryData {
588
597
  rawResults?: ArtifactRef;
589
598
  graderPrompts?: ArtifactRef;
590
599
  taskDefinitions?: ArtifactRef;
591
- evalResults?: ArtifactRef;
592
600
  traces?: ArtifactRef;
593
601
  };
594
602
  belowCritical: string[];
package/dist/index.js CHANGED
@@ -1701,11 +1701,6 @@ var reportSchema = defineType4({
1701
1701
  name: "taskDefinitions",
1702
1702
  title: "Task Definitions"
1703
1703
  }),
1704
- defineField4({
1705
- ...artifactRefSchema(),
1706
- name: "evalResults",
1707
- title: "Eval Results"
1708
- }),
1709
1704
  defineField4({
1710
1705
  ...artifactRefSchema(),
1711
1706
  name: "traces",
@@ -3285,7 +3280,7 @@ import {
3285
3280
  TabPanel as TabPanel3,
3286
3281
  Text as Text46
3287
3282
  } from "@sanity/ui";
3288
- import { useCallback as useCallback36 } from "react";
3283
+ import { useCallback as useCallback36, useEffect as useEffect15 } from "react";
3289
3284
  import { useRouter as useRouter3 } from "sanity/router";
3290
3285
 
3291
3286
  // src/lib/help-context.ts
@@ -7162,6 +7157,7 @@ function cacheKey({ runId, type, key }) {
7162
7157
  }
7163
7158
  var hydratedEntries = /* @__PURE__ */ new Map();
7164
7159
  var inFlight = /* @__PURE__ */ new Map();
7160
+ var knownNotFound = /* @__PURE__ */ new Set();
7165
7161
  var subscribers = /* @__PURE__ */ new Map();
7166
7162
  function getCached(k) {
7167
7163
  const hit = hydratedEntries.get(cacheKey(k));
@@ -7195,6 +7191,12 @@ function recordInFlight(k, start) {
7195
7191
  inFlight.set(composite, p);
7196
7192
  return p;
7197
7193
  }
7194
+ function markNotFound(k) {
7195
+ knownNotFound.add(cacheKey(k));
7196
+ }
7197
+ function isKnownNotFound(k) {
7198
+ return knownNotFound.has(cacheKey(k));
7199
+ }
7198
7200
  function notify(composite) {
7199
7201
  const set2 = subscribers.get(composite);
7200
7202
  if (!set2) return;
@@ -7202,6 +7204,14 @@ function notify(composite) {
7202
7204
  }
7203
7205
 
7204
7206
  // src/lib/artifact-fetch.ts
7207
+ var ArtifactHttpError = class extends Error {
7208
+ status;
7209
+ constructor(message, status) {
7210
+ super(message);
7211
+ this.name = "ArtifactHttpError";
7212
+ this.status = status;
7213
+ }
7214
+ };
7205
7215
  function buildSigningUrl(runId, type, entryKey) {
7206
7216
  const base = `${ARTIFACT_API_BASE_URL}/runs/${encodeURIComponent(runId)}/artifacts/${encodeURIComponent(type)}`;
7207
7217
  return entryKey === void 0 ? base : `${base}/${encodeURIComponent(entryKey)}`;
@@ -7210,8 +7220,9 @@ async function signAndFetchJson(signingUrl) {
7210
7220
  const signed = await exchangeSigningUrl(signingUrl);
7211
7221
  const res = await fetch(signed, { credentials: "omit" });
7212
7222
  if (!res.ok) {
7213
- throw new Error(
7214
- `GCS artifact fetch failed: ${res.status} ${res.statusText}`
7223
+ throw new ArtifactHttpError(
7224
+ `GCS artifact fetch failed: ${res.status} ${res.statusText}`,
7225
+ res.status
7215
7226
  );
7216
7227
  }
7217
7228
  return await res.json();
@@ -7220,8 +7231,9 @@ async function signAndFetchNdjson(signingUrl) {
7220
7231
  const signed = await exchangeSigningUrl(signingUrl);
7221
7232
  const res = await fetch(signed, { credentials: "omit" });
7222
7233
  if (!res.ok) {
7223
- throw new Error(
7224
- `GCS artifact fetch failed: ${res.status} ${res.statusText}`
7234
+ throw new ArtifactHttpError(
7235
+ `GCS artifact fetch failed: ${res.status} ${res.statusText}`,
7236
+ res.status
7225
7237
  );
7226
7238
  }
7227
7239
  const body = await res.text();
@@ -7239,6 +7251,36 @@ async function signAndFetchNdjson(signingUrl) {
7239
7251
  }
7240
7252
  return rows;
7241
7253
  }
7254
+ async function fetchBatchReadUrls(runId, type, keys) {
7255
+ const res = await fetch(
7256
+ `${ARTIFACT_API_BASE_URL}/runs/${encodeURIComponent(runId)}/artifacts/batch/read-urls`,
7257
+ {
7258
+ method: "POST",
7259
+ credentials: "omit",
7260
+ headers: { "Content-Type": "application/json" },
7261
+ body: JSON.stringify({ types: [type], keys: { [type]: keys } })
7262
+ }
7263
+ );
7264
+ if (!res.ok) {
7265
+ const body = await res.text().catch(() => "");
7266
+ throw new Error(
7267
+ `Batch signing failed: ${res.status} ${res.statusText}${body ? ` \u2014 ${body.slice(0, 200)}` : ""}`
7268
+ );
7269
+ }
7270
+ const envelope = await res.json();
7271
+ if (envelope.object === "error" || !envelope.urls) {
7272
+ throw new Error(
7273
+ envelope.error?.message ?? "Invalid batch signing response \u2014 missing urls"
7274
+ );
7275
+ }
7276
+ const entries = envelope.urls[type];
7277
+ if (!entries) return {};
7278
+ const out = {};
7279
+ for (const [key, entry] of Object.entries(entries)) {
7280
+ out[key] = entry.url;
7281
+ }
7282
+ return out;
7283
+ }
7242
7284
  async function exchangeSigningUrl(signingUrl) {
7243
7285
  const res = await fetch(signingUrl, {
7244
7286
  credentials: "omit",
@@ -7246,8 +7288,9 @@ async function exchangeSigningUrl(signingUrl) {
7246
7288
  });
7247
7289
  if (!res.ok) {
7248
7290
  const body = await res.text().catch(() => "");
7249
- throw new Error(
7250
- `Artifact signing failed: ${res.status} ${res.statusText}${body ? ` \u2014 ${body.slice(0, 200)}` : ""}`
7291
+ throw new ArtifactHttpError(
7292
+ `Artifact signing failed: ${res.status} ${res.statusText}${body ? ` \u2014 ${body.slice(0, 200)}` : ""}`,
7293
+ res.status
7251
7294
  );
7252
7295
  }
7253
7296
  const envelope = await res.json();
@@ -7279,21 +7322,29 @@ function useArtifactDetail(type, key) {
7279
7322
  }, [runId, type, key]);
7280
7323
  const request = useCallback16(async () => {
7281
7324
  if (!runId || !ref || !key) return;
7282
- const hit = getCached({ runId, type, key });
7325
+ const cacheId = { runId, type, key };
7326
+ if (isKnownNotFound(cacheId)) {
7327
+ setStatus("error");
7328
+ return;
7329
+ }
7330
+ const hit = getCached(cacheId);
7283
7331
  if (hit !== null) {
7284
7332
  setStatus("ready");
7285
7333
  return;
7286
7334
  }
7287
7335
  setStatus("loading");
7288
7336
  try {
7289
- await recordInFlight({ runId, type, key }, async () => {
7337
+ await recordInFlight(cacheId, async () => {
7290
7338
  const url = buildSigningUrl(runId, type, key);
7291
7339
  const body = NDJSON_TYPES.has(type) ? await signAndFetchNdjson(url) : await signAndFetchJson(url);
7292
- setCached({ runId, type, key }, body);
7340
+ setCached(cacheId, body);
7293
7341
  return body;
7294
7342
  });
7295
7343
  setStatus("ready");
7296
- } catch {
7344
+ } catch (err) {
7345
+ if (err instanceof ArtifactHttpError && err.status === 404) {
7346
+ markNotFound(cacheId);
7347
+ }
7297
7348
  setStatus("error");
7298
7349
  }
7299
7350
  }, [runId, ref, type, key]);
@@ -7328,33 +7379,73 @@ import { useCallback as useCallback17, useMemo as useMemo7 } from "react";
7328
7379
  var NDJSON_TYPES2 = /* @__PURE__ */ new Set([
7329
7380
  "traces"
7330
7381
  ]);
7382
+ var HOVER_DEBOUNCE_MS = 200;
7383
+ var MAX_CONCURRENT_PREFETCHES = 4;
7384
+ var pendingHoverTimers = /* @__PURE__ */ new Map();
7385
+ var activePrefetches = 0;
7386
+ var prefetchWaitQueue = [];
7387
+ async function withPrefetchSlot(run) {
7388
+ if (activePrefetches >= MAX_CONCURRENT_PREFETCHES) {
7389
+ await new Promise((resolve) => prefetchWaitQueue.push(resolve));
7390
+ }
7391
+ activePrefetches++;
7392
+ try {
7393
+ return await run();
7394
+ } finally {
7395
+ activePrefetches--;
7396
+ const next = prefetchWaitQueue.shift();
7397
+ if (next) next();
7398
+ }
7399
+ }
7400
+ async function prefetchArtifactCore(args) {
7401
+ const { runId, type, key } = args;
7402
+ if (!runId || !key) return;
7403
+ const cacheId = { runId, type, key };
7404
+ if (isKnownNotFound(cacheId)) return;
7405
+ if (getCached(cacheId) !== null) return;
7406
+ try {
7407
+ await recordInFlight(
7408
+ cacheId,
7409
+ () => withPrefetchSlot(async () => {
7410
+ const url = buildSigningUrl(runId, type, key);
7411
+ const body = NDJSON_TYPES2.has(type) ? await signAndFetchNdjson(url) : await signAndFetchJson(url);
7412
+ setCached(cacheId, body);
7413
+ return body;
7414
+ })
7415
+ );
7416
+ } catch (err) {
7417
+ if (err instanceof ArtifactHttpError && err.status === 404) {
7418
+ markNotFound(cacheId);
7419
+ }
7420
+ }
7421
+ }
7422
+ function scheduleHoverPrefetch(type, run, debounceMs = HOVER_DEBOUNCE_MS) {
7423
+ const existing = pendingHoverTimers.get(type);
7424
+ if (existing) clearTimeout(existing);
7425
+ const timer = setTimeout(() => {
7426
+ pendingHoverTimers.delete(type);
7427
+ run();
7428
+ }, debounceMs);
7429
+ pendingHoverTimers.set(type, timer);
7430
+ }
7331
7431
  function useArtifactPrefetch(type) {
7332
7432
  const { runId } = useReportArtifactContext();
7333
7433
  const ref = useArtifactRef(type);
7334
7434
  const prefetch = useCallback17(
7335
7435
  async (key) => {
7336
7436
  if (!runId || !ref || !key) return;
7337
- const cached = getCached({ runId, type, key });
7338
- if (cached !== null) return;
7339
- try {
7340
- await recordInFlight({ runId, type, key }, async () => {
7341
- const url = buildSigningUrl(runId, type, key);
7342
- const body = NDJSON_TYPES2.has(type) ? await signAndFetchNdjson(url) : await signAndFetchJson(url);
7343
- setCached({ runId, type, key }, body);
7344
- return body;
7345
- });
7346
- } catch {
7347
- }
7437
+ await prefetchArtifactCore({ runId, type, key });
7348
7438
  },
7349
7439
  [runId, ref, type]
7350
7440
  );
7351
7441
  const onHover = useCallback17(
7352
7442
  (key) => {
7353
7443
  return () => {
7354
- void prefetch(key);
7444
+ if (!runId || !ref || !key) return;
7445
+ scheduleHoverPrefetch(type, () => void prefetch(key));
7355
7446
  };
7356
7447
  },
7357
- [prefetch]
7448
+ [runId, ref, type, prefetch]
7358
7449
  );
7359
7450
  const prefetchWindow = useCallback17(
7360
7451
  async (keys, centerIndex, radius = 5) => {
@@ -7372,49 +7463,28 @@ function useArtifactPrefetch(type) {
7372
7463
  (k) => getCached({ runId, type, key: k }) === null
7373
7464
  );
7374
7465
  if (pending.length === 0) return;
7375
- const batchUrls = await tryBatchSign(runId, type, pending);
7376
- if (batchUrls) {
7377
- await Promise.all(
7378
- Object.entries(batchUrls).map(async ([k, signedUrl]) => {
7379
- await recordInFlight({ runId, type, key: k }, async () => {
7380
- const body = await fetchSigned(signedUrl, NDJSON_TYPES2.has(type));
7381
- setCached({ runId, type, key: k }, body);
7382
- return body;
7383
- });
7384
- })
7385
- );
7386
- return;
7387
- }
7388
- for (const k of pending) {
7389
- await prefetch(k);
7390
- }
7466
+ const signedByKey = await fetchBatchReadUrls(runId, type, pending);
7467
+ await Promise.all(
7468
+ Object.entries(signedByKey).map(async ([k, signedUrl]) => {
7469
+ await recordInFlight({ runId, type, key: k }, async () => {
7470
+ const body = await fetchSignedBody(
7471
+ signedUrl,
7472
+ NDJSON_TYPES2.has(type)
7473
+ );
7474
+ setCached({ runId, type, key: k }, body);
7475
+ return body;
7476
+ });
7477
+ })
7478
+ );
7391
7479
  },
7392
- [runId, ref, type, prefetch]
7480
+ [runId, ref, type]
7393
7481
  );
7394
7482
  return useMemo7(
7395
7483
  () => ({ prefetch, onHover, prefetchWindow, warmAll }),
7396
7484
  [prefetch, onHover, prefetchWindow, warmAll]
7397
7485
  );
7398
7486
  }
7399
- async function tryBatchSign(runId, type, keys) {
7400
- try {
7401
- const res = await fetch(
7402
- `${ARTIFACT_API_BASE_URL}/runs/${encodeURIComponent(runId)}/artifacts/batch/read-urls`,
7403
- {
7404
- method: "POST",
7405
- credentials: "omit",
7406
- headers: { "Content-Type": "application/json" },
7407
- body: JSON.stringify({ types: [type], keys: { [type]: keys } })
7408
- }
7409
- );
7410
- if (!res.ok) return null;
7411
- const body = await res.json();
7412
- return body.urls?.[type] ?? null;
7413
- } catch {
7414
- return null;
7415
- }
7416
- }
7417
- async function fetchSigned(signedUrl, ndjson) {
7487
+ async function fetchSignedBody(signedUrl, ndjson) {
7418
7488
  const res = await fetch(signedUrl, { credentials: "omit" });
7419
7489
  if (!res.ok) {
7420
7490
  throw new Error(
@@ -8190,12 +8260,15 @@ function JudgmentList({
8190
8260
  }
8191
8261
  }, [flatSlugs, activeRowSlug]);
8192
8262
  const { close: closeDrawer, open: openDrawer } = useJudgmentDrawer();
8263
+ const { runId: artifactRunId, manifest: artifactManifest } = useReportArtifactContext();
8193
8264
  useEffect9(() => {
8194
8265
  if (focus && focusedJudgment) {
8195
8266
  openDrawer({
8196
8267
  artifactCache,
8197
8268
  judgment: focusedJudgment,
8198
- testResult: focusedTestResult
8269
+ testResult: focusedTestResult,
8270
+ runId: artifactRunId,
8271
+ manifest: artifactManifest
8199
8272
  });
8200
8273
  } else if (!focus) {
8201
8274
  closeDrawer();
@@ -8206,7 +8279,9 @@ function JudgmentList({
8206
8279
  focusedTestResult,
8207
8280
  artifactCache,
8208
8281
  openDrawer,
8209
- closeDrawer
8282
+ closeDrawer,
8283
+ artifactRunId,
8284
+ artifactManifest
8210
8285
  ]);
8211
8286
  const prevFocusRef = useRef6(focus);
8212
8287
  useEffect9(() => {
@@ -8508,14 +8583,18 @@ function JudgmentCard({
8508
8583
  },
8509
8584
  [handleClick]
8510
8585
  );
8586
+ const onHoverTestOutputs = useMemo9(
8587
+ () => testOutputsKey ? testOutputsPrefetch.onHover(testOutputsKey) : null,
8588
+ [testOutputsPrefetch, testOutputsKey]
8589
+ );
8511
8590
  const handleMouseEnter = useCallback21(() => {
8512
8591
  row.handlers.onMouseEnter();
8513
- if (testOutputsKey) void testOutputsPrefetch.prefetch(testOutputsKey);
8514
- }, [row.handlers, testOutputsPrefetch, testOutputsKey]);
8592
+ onHoverTestOutputs?.();
8593
+ }, [row.handlers, onHoverTestOutputs]);
8515
8594
  const handleFocusPrefetch = useCallback21(() => {
8516
8595
  row.handlers.onFocus();
8517
- if (testOutputsKey) void testOutputsPrefetch.prefetch(testOutputsKey);
8518
- }, [row.handlers, testOutputsPrefetch, testOutputsKey]);
8596
+ onHoverTestOutputs?.();
8597
+ }, [row.handlers, onHoverTestOutputs]);
8519
8598
  return /* @__PURE__ */ jsx32(
8520
8599
  Box18,
8521
8600
  {
@@ -11218,6 +11297,16 @@ function JudgmentDetailDrawer({
11218
11297
  const rawTaskName = sep > 0 ? judgment.taskId.substring(sep + 3) : judgment.taskId;
11219
11298
  const { name: taskName, variant } = splitVariant(rawTaskName);
11220
11299
  const dimLabel = dimensionLabel2(judgment.dimension);
11300
+ const judgmentId = judgment.id ?? "";
11301
+ const [fullJudgment, fullStatus, requestFullJudgment] = useArtifactDetail("graderJudgments", judgmentId);
11302
+ useEffect12(() => {
11303
+ if (!judgmentId) return;
11304
+ if (fullStatus !== "idle") return;
11305
+ void requestFullJudgment();
11306
+ }, [judgmentId, fullStatus, requestFullJudgment]);
11307
+ const fullReason = typeof fullJudgment?.reason === "string" && fullJudgment.reason.length > 0 ? fullJudgment.reason : null;
11308
+ const reasoningText = fullReason ?? judgment.reason;
11309
+ const reasoningIsPreview = fullReason === null && judgmentId.length > 0 && fullStatus !== "error";
11221
11310
  useEffect12(() => {
11222
11311
  setTab("reasoning");
11223
11312
  }, [judgment.taskId, judgment.dimension, judgment.modelId]);
@@ -11449,10 +11538,11 @@ function JudgmentDetailDrawer({
11449
11538
  {
11450
11539
  copiedLabel: "Reasoning copied",
11451
11540
  label: "Copy reasoning",
11452
- text: judgment.reason
11541
+ text: reasoningText
11453
11542
  }
11454
11543
  ) }),
11455
- /* @__PURE__ */ jsx59(Markdown, { content: judgment.reason })
11544
+ /* @__PURE__ */ jsx59(Markdown, { content: reasoningText }),
11545
+ reasoningIsPreview && /* @__PURE__ */ jsx59(Text44, { muted: true, size: 1, style: { marginTop: 8 }, children: fullStatus === "loading" ? "Loading full reasoning\u2026" : "Showing preview (280 chars). Full reasoning not yet loaded." })
11456
11546
  ] })
11457
11547
  }
11458
11548
  ),
@@ -11625,7 +11715,7 @@ function JudgmentDetailDrawerOutlet({
11625
11715
  flexDirection: "column",
11626
11716
  overflow: "hidden"
11627
11717
  },
11628
- children: /* @__PURE__ */ jsx60(
11718
+ children: /* @__PURE__ */ jsx60(ReportArtifactProvider, { runId: active.runId, manifest: active.manifest, children: /* @__PURE__ */ jsx60(
11629
11719
  JudgmentDetailDrawer,
11630
11720
  {
11631
11721
  artifactCache: active.artifactCache,
@@ -11633,7 +11723,7 @@ function JudgmentDetailDrawerOutlet({
11633
11723
  onClose,
11634
11724
  testResult: active.testResult
11635
11725
  }
11636
- )
11726
+ ) })
11637
11727
  }
11638
11728
  )
11639
11729
  ]
@@ -11869,17 +11959,29 @@ var VIEW_PARAM_MAP = {
11869
11959
  timeline: "timeline"
11870
11960
  };
11871
11961
  function Dashboard() {
11962
+ return /* @__PURE__ */ jsx62(HelpProvider, { children: /* @__PURE__ */ jsx62(JudgmentDrawerProvider, { children: /* @__PURE__ */ jsx62(DashboardShell, {}) }) });
11963
+ }
11964
+ function DashboardShell() {
11872
11965
  const router = useRouter3();
11966
+ const { close: closeDrawer } = useJudgmentDrawer();
11967
+ const routerState = router.state;
11968
+ const reportId = routerState.reportId ?? null;
11969
+ useEffect15(() => {
11970
+ if (!reportId) closeDrawer();
11971
+ }, [reportId, closeDrawer]);
11873
11972
  const handleJudgmentDrawerClose = useCallback36(() => {
11973
+ closeDrawer();
11874
11974
  const state = { ...router.state };
11875
- delete state.focus;
11876
- router.navigate(state);
11877
- }, [router]);
11878
- return /* @__PURE__ */ jsx62(HelpProvider, { children: /* @__PURE__ */ jsx62(JudgmentDrawerProvider, { children: /* @__PURE__ */ jsxs45(Flex34, { style: { height: "100%" }, children: [
11975
+ if (state.focus) {
11976
+ delete state.focus;
11977
+ router.navigate(state);
11978
+ }
11979
+ }, [closeDrawer, router]);
11980
+ return /* @__PURE__ */ jsxs45(Flex34, { style: { height: "100%" }, children: [
11879
11981
  /* @__PURE__ */ jsx62(Box29, { flex: 1, overflow: "auto", children: /* @__PURE__ */ jsx62(DashboardContent, {}) }),
11880
11982
  /* @__PURE__ */ jsx62(JudgmentDetailDrawerOutlet, { onClose: handleJudgmentDrawerClose }),
11881
11983
  /* @__PURE__ */ jsx62(HelpDrawer, {})
11882
- ] }) }) });
11984
+ ] });
11883
11985
  }
11884
11986
  function DashboardContent() {
11885
11987
  const router = useRouter3();
@@ -12012,7 +12114,7 @@ function ailfTool(options = {}) {
12012
12114
  // src/actions/RunEvaluationAction.tsx
12013
12115
  import { BarChartIcon as BarChartIcon2 } from "@sanity/icons";
12014
12116
  import { useToast as useToast10 } from "@sanity/ui";
12015
- import { useCallback as useCallback37, useEffect as useEffect15, useRef as useRef9, useState as useState27 } from "react";
12117
+ import { useCallback as useCallback37, useEffect as useEffect16, useRef as useRef9, useState as useState27 } from "react";
12016
12118
  import {
12017
12119
  getReleaseIdFromReleaseDocumentId as getReleaseIdFromReleaseDocumentId3,
12018
12120
  useClient as useClient12,
@@ -12046,7 +12148,7 @@ function createRunEvaluationAction(options = {}) {
12046
12148
  const [state, setState] = useState27({ status: "loading" });
12047
12149
  const requestedAtRef = useRef9(null);
12048
12150
  const perspectiveId = getReleaseIdFromReleaseDocumentId3(release._id);
12049
- useEffect15(() => {
12151
+ useEffect16(() => {
12050
12152
  let cancelled = false;
12051
12153
  client.fetch(contentImpactQuery, buildReportQueryParams(perspectiveId)).then((results) => {
12052
12154
  if (cancelled) return;
@@ -12069,7 +12171,7 @@ function createRunEvaluationAction(options = {}) {
12069
12171
  cancelled = true;
12070
12172
  };
12071
12173
  }, [client, perspectiveId]);
12072
- useEffect15(() => {
12174
+ useEffect16(() => {
12073
12175
  if (state.status !== "requested" && state.status !== "polling") return;
12074
12176
  const { requestId, startedAt } = state;
12075
12177
  if (state.status === "requested") {
@@ -12119,7 +12221,7 @@ function createRunEvaluationAction(options = {}) {
12119
12221
  }, POLL_INTERVAL_MS2);
12120
12222
  return () => clearInterval(interval);
12121
12223
  }, [client, perspectiveId, state]);
12122
- useEffect15(() => {
12224
+ useEffect16(() => {
12123
12225
  if (state.status !== "error") return;
12124
12226
  const timer = setTimeout(() => {
12125
12227
  client.fetch(contentImpactQuery, buildReportQueryParams(perspectiveId)).then((results) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/ailf-studio",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "AI Literacy Framework — Sanity Studio dashboard plugin",
5
5
  "type": "module",
6
6
  "license": "MIT",