@tonyclaw/agent-inspector 3.0.42 → 3.0.43

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 (60) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-7Gr3T28l.js → CompareDrawer-BAXxwTwT.js} +1 -1
  3. package/.output/public/assets/{InspectorPet-BYY_Sa_k.js → InspectorPet-xYuGV4Qz.js} +167 -167
  4. package/.output/public/assets/ProxyViewerContainer-B6GZnUWi.js +126 -0
  5. package/.output/public/assets/{ReplayDialog-By1tvcuO.js → ReplayDialog-D73pyIg3.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-AbVJG4VA.js → RequestAnatomy-CSDta_nu.js} +1 -1
  7. package/.output/public/assets/{ResponseView-BqfnTwq-.js → ResponseView-C4aIUPby.js} +1 -1
  8. package/.output/public/assets/{StreamingChunkSequence-BK_GhL1n.js → StreamingChunkSequence-D4xxosLx.js} +1 -1
  9. package/.output/public/assets/{_sessionId-BsoVln_N.js → _sessionId-CZHbJyWO.js} +1 -1
  10. package/.output/public/assets/{_sessionId-BEVn_RD0.js → _sessionId-DvuNLzSE.js} +1 -1
  11. package/.output/public/assets/{index-BmKouSES.js → index-B17u7JMC.js} +16 -22
  12. package/.output/public/assets/index-BWjeqxbk.css +1 -0
  13. package/.output/public/assets/{index-DPsfwdop.js → index-C0g79BAs.js} +1 -1
  14. package/.output/public/assets/{index-DavUo6mY.js → index-CmEO8ykj.js} +1 -1
  15. package/.output/public/assets/{index-D1Ar_Dtb.js → index-DZ_wpqQM.js} +1 -1
  16. package/.output/public/assets/{json-viewer-vkLlnvyf.js → json-viewer-CuWU-H6K.js} +1 -1
  17. package/.output/public/assets/{jszip.min-CMLonFfU.js → jszip.min-DPJI_UKW.js} +1 -1
  18. package/.output/server/{_sessionId-DYkPEoJd.mjs → _sessionId-CoFyeOti.mjs} +2 -2
  19. package/.output/server/{_sessionId-BH52f7aR.mjs → _sessionId-Cun21KZF.mjs} +1 -1
  20. package/.output/server/_ssr/{CompareDrawer-Bt3LIoPy.mjs → CompareDrawer-Bgc2TZh_.mjs} +2 -2
  21. package/.output/server/_ssr/{InspectorPet-CikVNW8S.mjs → InspectorPet-DyK2ojeh.mjs} +20 -10
  22. package/.output/server/_ssr/{ProxyViewerContainer-BS6MZd0t.mjs → ProxyViewerContainer-hvn6oVWD.mjs} +326 -235
  23. package/.output/server/_ssr/{ReplayDialog-DxFLoYlZ.mjs → ReplayDialog-KpnrGtZ-.mjs} +3 -3
  24. package/.output/server/_ssr/{RequestAnatomy-CbLJjhKb.mjs → RequestAnatomy-uCsfucn8.mjs} +2 -2
  25. package/.output/server/_ssr/{ResponseView-Bs1sYg_8.mjs → ResponseView-C8UPqoPO.mjs} +2 -2
  26. package/.output/server/_ssr/{StreamingChunkSequence-D0dBru3U.mjs → StreamingChunkSequence-BP28I9sh.mjs} +2 -2
  27. package/.output/server/_ssr/{index-DIHmtfFU.mjs → index-BVwVoQlZ.mjs} +1 -1
  28. package/.output/server/_ssr/{index-hK95DE4-.mjs → index-Du3YNDKx.mjs} +2 -2
  29. package/.output/server/_ssr/index.mjs +2 -2
  30. package/.output/server/_ssr/{json-viewer-BfRCUg1t.mjs → json-viewer-DrE0vtlB.mjs} +2 -2
  31. package/.output/server/_ssr/{router-NjASMtmk.mjs → router-C6nWUZHK.mjs} +18 -24
  32. package/.output/server/{_tanstack-start-manifest_v-BNqjyvHx.mjs → _tanstack-start-manifest_v-rshlRaiN.mjs} +1 -1
  33. package/.output/server/index.mjs +98 -98
  34. package/package.json +5 -1
  35. package/scripts/generate-theme-scales.mjs +22 -0
  36. package/src/components/ProxyViewer.tsx +217 -103
  37. package/src/components/alerts/AlertsDialog.tsx +17 -17
  38. package/src/components/ecosystem/AgentLabDialog.tsx +11 -4
  39. package/src/components/groups/GroupsDialog.tsx +41 -26
  40. package/src/components/inspector-pet/InspectorPet.tsx +9 -9
  41. package/src/components/inspector-pet/inspectorPetLogic.ts +15 -1
  42. package/src/components/pi-agent/PiAgentPanel.tsx +12 -35
  43. package/src/components/pi-agent/piAgentChatLogic.ts +0 -24
  44. package/src/components/providers/ImportWizardDialog.tsx +1 -1
  45. package/src/components/providers/ProviderCard.tsx +4 -4
  46. package/src/components/providers/ProviderForm.tsx +11 -7
  47. package/src/components/providers/ProviderTestResultsView.tsx +15 -17
  48. package/src/components/providers/ProvidersPanel.tsx +1 -1
  49. package/src/components/providers/SettingsDialog.tsx +11 -7
  50. package/src/components/proxy-viewer/LogEntryHeader.tsx +2 -2
  51. package/src/components/proxy-viewer/TurnGroup.tsx +1 -1
  52. package/src/components/ui/icon-trigger.ts +1 -1
  53. package/src/lib/themeMode.ts +1 -5
  54. package/src/lib/uiScale.ts +8 -3
  55. package/src/routes/__root.tsx +5 -10
  56. package/styles/globals.css +35 -143
  57. package/styles/theme-scales.css +50 -0
  58. package/styles/themes.css +157 -0
  59. package/.output/public/assets/ProxyViewerContainer-CCtygisW.js +0 -126
  60. package/.output/public/assets/index-DKwrwHsI.css +0 -1
@@ -130,16 +130,16 @@ export function buildGroupMemberRows(
130
130
  function statusClassName(status: InspectorGroup["status"] | MemberStatus): string {
131
131
  switch (status) {
132
132
  case "completed":
133
- return "border-emerald-200 bg-emerald-50 text-emerald-700";
133
+ return "border-status-success/30 bg-status-success/10 text-status-success";
134
134
  case "failed":
135
135
  case "cancelled":
136
- return "border-red-200 bg-red-50 text-red-700";
136
+ return "border-status-danger/30 bg-status-danger/10 text-status-danger";
137
137
  case "running":
138
- return "border-sky-200 bg-sky-50 text-sky-700";
138
+ return "border-status-cool/30 bg-status-cool/10 text-status-cool";
139
139
  case "created":
140
- return "border-zinc-200 bg-zinc-50 text-zinc-600";
140
+ return "border-border bg-muted/30 text-muted-foreground";
141
141
  case null:
142
- return "border-zinc-200 bg-zinc-50 text-zinc-500";
142
+ return "border-border bg-muted/30 text-muted-foreground";
143
143
  }
144
144
  }
145
145
 
@@ -150,13 +150,13 @@ function statusLabel(status: InspectorGroup["status"] | MemberStatus): string {
150
150
  function reportStatusClassName(status: EvidenceReport["status"]): string {
151
151
  switch (status) {
152
152
  case "PASS":
153
- return "border-emerald-200 bg-emerald-50 text-emerald-700";
153
+ return "border-status-success/30 bg-status-success/10 text-status-success";
154
154
  case "FAIL":
155
- return "border-red-200 bg-red-50 text-red-700";
155
+ return "border-status-danger/30 bg-status-danger/10 text-status-danger";
156
156
  case "RUNNING":
157
- return "border-sky-200 bg-sky-50 text-sky-700";
157
+ return "border-status-cool/30 bg-status-cool/10 text-status-cool";
158
158
  case "UNKNOWN":
159
- return "border-zinc-200 bg-zinc-50 text-zinc-600";
159
+ return "border-border bg-muted/30 text-muted-foreground";
160
160
  }
161
161
  }
162
162
 
@@ -283,7 +283,11 @@ function evidenceReportFor(
283
283
  return null;
284
284
  }
285
285
 
286
- export function GroupsDialog(): JSX.Element {
286
+ export function GroupsDialog({
287
+ labelledTrigger = false,
288
+ }: {
289
+ labelledTrigger?: boolean;
290
+ }): JSX.Element {
287
291
  const [open, setOpen] = useState(false);
288
292
  const [selectedGroupId, setSelectedGroupId] = useState<string | null>(null);
289
293
  const [exportingGroupId, setExportingGroupId] = useState<string | null>(null);
@@ -446,8 +450,11 @@ export function GroupsDialog(): JSX.Element {
446
450
  <Button
447
451
  type="button"
448
452
  variant="ghost"
449
- size="icon"
450
- className={INSPECTOR_ICON_TRIGGER_CLASS}
453
+ size={labelledTrigger ? "default" : "icon"}
454
+ className={cn(
455
+ INSPECTOR_ICON_TRIGGER_CLASS,
456
+ labelledTrigger && "w-auto gap-2 px-3 text-xs max-lg:h-11 max-lg:w-auto",
457
+ )}
451
458
  aria-label="Evaluation groups"
452
459
  title="Evaluation groups"
453
460
  >
@@ -459,7 +466,7 @@ export function GroupsDialog(): JSX.Element {
459
466
  {groups.length}
460
467
  </span>
461
468
  ) : null}
462
- <span className="sr-only">Evaluation groups</span>
469
+ <span className={labelledTrigger ? "" : "sr-only"}>Groups</span>
463
470
  </Button>
464
471
  </DialogTrigger>
465
472
  <DialogContent className="flex max-h-[85vh] max-w-5xl flex-col overflow-hidden">
@@ -553,7 +560,7 @@ function GroupList({
553
560
 
554
561
  if (error !== undefined) {
555
562
  return (
556
- <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700">
563
+ <div className="rounded-md border border-status-danger/30 bg-status-danger/10 px-3 py-2 text-xs text-status-danger">
557
564
  {error.message}
558
565
  </div>
559
566
  );
@@ -677,7 +684,7 @@ function GroupDetails({
677
684
  type="button"
678
685
  variant="outline"
679
686
  size="icon"
680
- className="size-8 text-red-600 hover:text-red-700"
687
+ className="size-8 text-status-danger hover:text-status-danger/80"
681
688
  aria-label="Delete group"
682
689
  title="Delete group"
683
690
  disabled={isDeleting}
@@ -751,13 +758,13 @@ function GroupDetails({
751
758
  <EvidencePaths evidence={evidence} />
752
759
 
753
760
  {exportError !== null && (
754
- <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700">
761
+ <div className="rounded-md border border-status-danger/30 bg-status-danger/10 px-3 py-2 text-xs text-status-danger">
755
762
  {exportError}
756
763
  </div>
757
764
  )}
758
765
 
759
766
  {deleteError !== null && !isConfirmingDelete && (
760
- <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700">
767
+ <div className="rounded-md border border-status-danger/30 bg-status-danger/10 px-3 py-2 text-xs text-status-danger">
761
768
  {deleteError}
762
769
  </div>
763
770
  )}
@@ -789,14 +796,14 @@ function DeleteGroupPanel({
789
796
  const evidencePath = group.evidence?.markdownPath ?? "No evidence pack exported.";
790
797
 
791
798
  return (
792
- <div className="rounded-md border border-red-200 bg-red-50 px-3 py-3 text-red-900">
799
+ <div className="rounded-md border border-status-danger/30 bg-status-danger/10 px-3 py-3 text-status-danger">
793
800
  <div className="flex min-w-0 flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
794
801
  <div className="min-w-0 space-y-2">
795
802
  <div className="flex items-center gap-2 text-sm font-semibold">
796
- <Trash2 className="size-4 text-red-600" />
803
+ <Trash2 className="size-4 text-status-danger" />
797
804
  <span>Delete group?</span>
798
805
  </div>
799
- <p className="text-xs text-red-800">
806
+ <p className="text-xs text-status-danger">
800
807
  Delete <span className="font-medium">{group.title}</span>. Session logs and run records
801
808
  stay intact.
802
809
  </p>
@@ -815,13 +822,13 @@ function DeleteGroupPanel({
815
822
  />
816
823
  <span className="min-w-0">
817
824
  <span className="block font-medium">Also delete exported evidence files</span>
818
- <code className="mt-1 block truncate font-mono text-[11px] text-red-700">
825
+ <code className="mt-1 block truncate font-mono text-[11px] text-status-danger">
819
826
  {evidencePath}
820
827
  </code>
821
828
  </span>
822
829
  </label>
823
830
  {error !== null && (
824
- <div className="rounded-md border border-red-200 bg-white px-2 py-1.5 text-xs text-red-700">
831
+ <div className="rounded-md border border-status-danger/30 bg-card px-2 py-1.5 text-xs text-status-danger">
825
832
  {error}
826
833
  </div>
827
834
  )}
@@ -891,7 +898,7 @@ function EvidenceReportCard({
891
898
 
892
899
  if (error !== undefined && hasEvidence) {
893
900
  return (
894
- <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700">
901
+ <div className="rounded-md border border-status-danger/30 bg-status-danger/10 px-3 py-2 text-xs text-status-danger">
895
902
  Failed to load evidence report: {error.message}
896
903
  </div>
897
904
  );
@@ -916,7 +923,11 @@ function EvidenceReportCard({
916
923
  aria-label={copied ? "Copied evidence report" : "Copy evidence report"}
917
924
  onClick={copy}
918
925
  >
919
- {copied ? <Check className="size-3.5 text-emerald-500" /> : <Copy className="size-3.5" />}
926
+ {copied ? (
927
+ <Check className="size-3.5 text-status-success" />
928
+ ) : (
929
+ <Copy className="size-3.5" />
930
+ )}
920
931
  </Button>
921
932
  </div>
922
933
  <p className="mt-1 text-xs text-muted-foreground">{report.summary}</p>
@@ -964,7 +975,11 @@ function CopyPathRow({ label, value }: { label: string; value: string }): JSX.El
964
975
  aria-label={copied ? `Copied ${label} path` : `Copy ${label} path`}
965
976
  onClick={copy}
966
977
  >
967
- {copied ? <Check className="size-3.5 text-emerald-500" /> : <Copy className="size-3.5" />}
978
+ {copied ? (
979
+ <Check className="size-3.5 text-status-success" />
980
+ ) : (
981
+ <Copy className="size-3.5" />
982
+ )}
968
983
  </Button>
969
984
  </div>
970
985
  );
@@ -1095,7 +1110,7 @@ function MemberRow({
1095
1110
  <span className="min-w-0 truncate">{sessionLabel}</span>
1096
1111
  <Badge
1097
1112
  variant="outline"
1098
- className="shrink-0 border-zinc-200 bg-zinc-50 text-zinc-600"
1113
+ className="shrink-0 border-border bg-muted/30 text-muted-foreground"
1099
1114
  >
1100
1115
  evidence
1101
1116
  </Badge>
@@ -22,7 +22,7 @@ import {
22
22
  nextInspectorPetWalkingPosition,
23
23
  randomInspectorPetEdgePosition,
24
24
  resolveInspectorPetStatus,
25
- snapInspectorPetToEdge,
25
+ snapInspectorPetToCorner,
26
26
  } from "./inspectorPetLogic";
27
27
  import { InspectorPetCrab3D } from "./InspectorPetCrab3D";
28
28
 
@@ -63,11 +63,11 @@ function readViewport(): InspectorPetViewport {
63
63
  }
64
64
 
65
65
  function readStoredRoaming(): boolean {
66
- if (typeof window === "undefined") return true;
66
+ if (typeof window === "undefined") return false;
67
67
  try {
68
- return window.localStorage.getItem(INSPECTOR_PET_ROAMING_STORAGE_KEY) !== "0";
68
+ return window.localStorage.getItem(INSPECTOR_PET_ROAMING_STORAGE_KEY) === "1";
69
69
  } catch {
70
- return true;
70
+ return false;
71
71
  }
72
72
  }
73
73
 
@@ -126,7 +126,7 @@ export function InspectorPet({ logs }: InspectorPetProps): JSX.Element {
126
126
  useEffect(() => {
127
127
  const nextViewport = readViewport();
128
128
  setViewport(nextViewport);
129
- setPosition(randomInspectorPetEdgePosition(nextViewport, Math.random()));
129
+ setPosition(randomInspectorPetEdgePosition(nextViewport, 1));
130
130
  }, []);
131
131
 
132
132
  useEffect(() => {
@@ -181,7 +181,7 @@ export function InspectorPet({ logs }: InspectorPetProps): JSX.Element {
181
181
  const nextViewport = readViewport();
182
182
  setScuttling(false);
183
183
  setViewport(nextViewport);
184
- setPosition((current) => snapInspectorPetToEdge(current, nextViewport));
184
+ setPosition((current) => snapInspectorPetToCorner(current, nextViewport));
185
185
  };
186
186
  window.addEventListener("resize", handleResize);
187
187
  return () => window.removeEventListener("resize", handleResize);
@@ -264,7 +264,7 @@ export function InspectorPet({ logs }: InspectorPetProps): JSX.Element {
264
264
  dragOccurredRef.current = dragState.moved;
265
265
  dragStateRef.current = null;
266
266
  setDragging(false);
267
- setPosition((current) => snapInspectorPetToEdge(current, viewport));
267
+ setPosition((current) => snapInspectorPetToCorner(current, viewport));
268
268
  },
269
269
  [viewport],
270
270
  );
@@ -314,7 +314,7 @@ export function InspectorPet({ logs }: InspectorPetProps): JSX.Element {
314
314
  <button
315
315
  type="button"
316
316
  className={cn(
317
- "pointer-events-auto fixed left-0 top-0 z-10 flex size-28 items-center justify-center bg-transparent text-foreground outline-none transition-[filter,opacity] duration-200 hover:opacity-95 hover:drop-shadow-[0_0_28px_rgba(245,158,11,0.32)] focus-visible:drop-shadow-[0_0_14px_rgba(251,191,36,0.72)]",
317
+ "pointer-events-auto fixed left-0 top-0 z-10 flex size-28 items-center justify-center bg-transparent text-foreground opacity-65 outline-none transition-[filter,opacity] duration-200 hover:opacity-100 hover:drop-shadow-[0_0_28px_rgba(245,158,11,0.32)] focus-visible:opacity-100 focus-visible:drop-shadow-[0_0_14px_rgba(251,191,36,0.72)]",
318
318
  dragging ? "cursor-grabbing" : "cursor-grab",
319
319
  )}
320
320
  style={petStyle}
@@ -370,7 +370,7 @@ export function InspectorPet({ logs }: InspectorPetProps): JSX.Element {
370
370
  <span className="min-w-0 flex-1 truncate text-xs font-medium">{status.label}</span>
371
371
  <button
372
372
  type="button"
373
- className="inline-flex size-6 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none"
373
+ className="inline-flex size-7 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none max-lg:size-10"
374
374
  onClick={handleToggleRoaming}
375
375
  aria-label={roamingLabel}
376
376
  title={roamingLabel}
@@ -103,6 +103,20 @@ export function snapInspectorPetToEdge(
103
103
  }
104
104
  }
105
105
 
106
+ export function snapInspectorPetToCorner(
107
+ position: InspectorPetPosition,
108
+ viewport: InspectorPetViewport,
109
+ ): InspectorPetPosition {
110
+ const clamped = clampInspectorPetPosition(position, viewport);
111
+ const edgeGap = scaledMetric(INSPECTOR_PET_EDGE_GAP, viewport);
112
+ const maxX = maximumPetX(viewport);
113
+ const maxY = maximumPetY(viewport);
114
+ return {
115
+ x: clamped.x - edgeGap <= maxX - clamped.x ? edgeGap : maxX,
116
+ y: clamped.y - edgeGap <= maxY - clamped.y ? edgeGap : maxY,
117
+ };
118
+ }
119
+
106
120
  export function randomInspectorPetEdgePosition(
107
121
  viewport: InspectorPetViewport,
108
122
  positionSample: number,
@@ -111,7 +125,7 @@ export function randomInspectorPetEdgePosition(
111
125
  const maxY = maximumPetY(viewport);
112
126
  const edgeGap = scaledMetric(INSPECTOR_PET_EDGE_GAP, viewport);
113
127
  return {
114
- x: edgeGap + clampUnit(positionSample) * (maxX - edgeGap),
128
+ x: clampUnit(positionSample) < 0.5 ? edgeGap : maxX,
115
129
  y: maxY,
116
130
  };
117
131
  }
@@ -5,7 +5,6 @@ import {
5
5
  createEmptyPiAgentConversation,
6
6
  getPiAgentResultLogIds,
7
7
  normalizePiAgentResponse,
8
- PI_AGENT_SCOPE_PILLS,
9
8
  PI_AGENT_STARTERS,
10
9
  type PiAgentConversationMessage,
11
10
  type PiAgentEvidenceView,
@@ -30,8 +29,7 @@ export type PiAgentSearchResult = {
30
29
  reportedLogCount: number;
31
30
  };
32
31
 
33
- const DEFAULT_QUESTION =
34
- "Analyze the current Inspector session. What looks abnormal, slow, or likely to hang?";
32
+ const DEFAULT_QUESTION = "What looks abnormal, slow, or likely to hang?";
35
33
 
36
34
  function providerSupportsPiAgent(provider: {
37
35
  anthropicBaseUrl?: string;
@@ -209,7 +207,7 @@ export function PiAgentPanel({
209
207
  currentSessionId,
210
208
  logCount,
211
209
  onResultChange,
212
- }: PiAgentPanelProps): JSX.Element {
210
+ }: PiAgentPanelProps): JSX.Element | null {
213
211
  const { providers } = useProviders();
214
212
  const piProviders = useMemo(
215
213
  () => sortProviderBySource(providers.filter(providerSupportsPiAgent)),
@@ -228,6 +226,8 @@ export function PiAgentPanel({
228
226
  const question = conversation.question;
229
227
  const canAsk = question.trim() !== "" && piProviders.length > 0 && !loading;
230
228
 
229
+ if (piProviders.length === 0) return null;
230
+
231
231
  const handleQuestionChange = (event: ChangeEvent<HTMLTextAreaElement>): void => {
232
232
  setConversation((current) => ({ ...current, question: event.currentTarget.value }));
233
233
  };
@@ -334,9 +334,9 @@ export function PiAgentPanel({
334
334
  <div className="flex items-center gap-2">
335
335
  <BrainCircuit className="size-4 text-cyan-200" />
336
336
  <div className="min-w-0 flex-1">
337
- <div className="text-xs font-semibold text-foreground">Search with Assistant</div>
337
+ <div className="text-xs font-semibold text-foreground">Assistant</div>
338
338
  <div className="text-[11px] text-muted-foreground">
339
- {currentSessionId === null ? "Search all Inspector evidence" : "Search this session"}
339
+ {currentSessionId === null ? "All evidence" : "Current session"}
340
340
  </div>
341
341
  </div>
342
342
  <button
@@ -350,26 +350,9 @@ export function PiAgentPanel({
350
350
  </div>
351
351
 
352
352
  {conversation.messages.length === 0 && (
353
- <div className="mt-3 rounded-md bg-black/[0.18] px-3 py-2 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.045)]">
354
- <p className="text-[11px] leading-5 text-muted-foreground">
355
- Describe the traffic you want to find in plain language. Assistant searches saved
356
- traffic, sessions, tools, alerts, runs, groups, and knowledge, then uses linked evidence
357
- to shape the log results.
358
- </p>
359
- <div className="mt-2 grid gap-1.5">
360
- {PI_AGENT_SCOPE_PILLS.map((pill) => (
361
- <div
362
- key={pill.id}
363
- className="rounded-sm bg-cyan-400/[0.06] px-2 py-1.5 shadow-[inset_0_0_0_1px_rgba(103,232,249,0.08)]"
364
- >
365
- <div className="text-[10px] font-medium text-cyan-50">{pill.label}</div>
366
- <div className="mt-0.5 text-[9px] leading-4 text-muted-foreground">
367
- {pill.description}
368
- </div>
369
- </div>
370
- ))}
371
- </div>
372
- </div>
353
+ <p className="mt-3 text-[11px] leading-5 text-muted-foreground">
354
+ Ask about failures, latency, tokens, and tools.
355
+ </p>
373
356
  )}
374
357
 
375
358
  <div className="mt-3 grid grid-cols-2 gap-2">
@@ -437,7 +420,7 @@ export function PiAgentPanel({
437
420
  value={question}
438
421
  onChange={handleQuestionChange}
439
422
  className="mt-3 min-h-20 w-full resize-y rounded-md bg-black/25 px-3 py-2 text-xs leading-5 text-foreground outline-none shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)] transition-colors placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring"
440
- placeholder="Search failures, slow requests, token spikes, tool calls..."
423
+ placeholder="Ask about this Inspector data..."
441
424
  />
442
425
 
443
426
  <button
@@ -447,21 +430,15 @@ export function PiAgentPanel({
447
430
  className="mt-2 inline-flex h-8 w-full items-center justify-center gap-2 rounded-md bg-cyan-400/12 px-3 text-xs font-medium text-cyan-100 shadow-[inset_0_0_0_1px_rgba(103,232,249,0.18)] transition-colors hover:bg-cyan-400/18 disabled:cursor-not-allowed disabled:opacity-50"
448
431
  >
449
432
  {loading ? <Loader2 className="size-3.5 animate-spin" /> : <Send className="size-3.5" />}
450
- <span>{loading ? "Searching..." : "Search logs"}</span>
433
+ <span>{loading ? "Searching..." : "Ask Assistant"}</span>
451
434
  </button>
452
435
 
453
436
  {conversation.error !== null && (
454
437
  <p className="mt-2 break-words text-[11px] leading-5 text-red-200">{conversation.error}</p>
455
438
  )}
456
- {piProviders.length === 0 && (
457
- <p className="mt-2 text-[11px] leading-5 text-muted-foreground">
458
- Configure a Provider with Responses, Chat, or Anthropic URL to enable Inspector Assistant.
459
- </p>
460
- )}
461
439
  {logCount === 0 && (
462
440
  <p className="mt-2 text-[11px] leading-5 text-muted-foreground">
463
- No logs are visible in this scope yet; Inspector Assistant can still answer Provider setup
464
- questions.
441
+ No logs in this scope. Setup questions still work.
465
442
  </p>
466
443
  )}
467
444
  </section>
@@ -71,30 +71,6 @@ export type PiAgentStarter = {
71
71
  question: string;
72
72
  };
73
73
 
74
- export type PiAgentScopePill = {
75
- id: "saved-data" | "root-cause" | "evidence";
76
- label: string;
77
- description: string;
78
- };
79
-
80
- export const PI_AGENT_SCOPE_PILLS: readonly PiAgentScopePill[] = [
81
- {
82
- id: "saved-data",
83
- label: "Saved Inspector data",
84
- description: "requests, responses, sessions, tools, alerts, runs, groups, and knowledge",
85
- },
86
- {
87
- id: "root-cause",
88
- label: "Root-cause hints",
89
- description: "failures, hangs, slow paths, token spikes, and provider drift",
90
- },
91
- {
92
- id: "evidence",
93
- label: "Evidence links",
94
- description: "matched logs and metrics you can jump back into",
95
- },
96
- ];
97
-
98
74
  export const PI_AGENT_STARTERS: readonly PiAgentStarter[] = [
99
75
  {
100
76
  id: "reliability",
@@ -253,7 +253,7 @@ export function ImportWizardDialog({
253
253
  )}
254
254
 
255
255
  {importResult !== null && (
256
- <div className="text-sm text-green-500 border-t pt-2">{importResult}</div>
256
+ <div className="border-t pt-2 text-sm text-status-success">{importResult}</div>
257
257
  )}
258
258
 
259
259
  {importError !== null && (
@@ -182,11 +182,11 @@ export function ProviderCard({
182
182
  const isTestingValue = isTesting ?? false;
183
183
  const providerSourceBadge =
184
184
  provider.source === "company" ? (
185
- <span className="shrink-0 rounded border border-cyan-300/20 bg-cyan-300/[0.08] px-1.5 py-0.5 text-xs text-cyan-100">
185
+ <span className="shrink-0 rounded border border-status-cool/30 bg-status-cool/10 px-1.5 py-0.5 text-xs text-status-cool">
186
186
  Company
187
187
  </span>
188
188
  ) : provider.source === "personal" ? (
189
- <span className="shrink-0 rounded border border-violet-300/20 bg-violet-300/[0.08] px-1.5 py-0.5 text-xs text-violet-100">
189
+ <span className="shrink-0 rounded border border-status-accent/30 bg-status-accent/10 px-1.5 py-0.5 text-xs text-status-accent">
190
190
  Personal
191
191
  </span>
192
192
  ) : null;
@@ -238,7 +238,7 @@ export function ProviderCard({
238
238
  </div>
239
239
 
240
240
  {!hasContextMetadata && (
241
- <div className="flex items-center justify-between gap-2 rounded-md border border-amber-500/25 bg-amber-500/6 px-2 py-1.5 text-xs text-muted-foreground">
241
+ <div className="flex items-center justify-between gap-2 rounded-md border border-status-watch/30 bg-status-watch/10 px-2 py-1.5 text-xs text-status-watch">
242
242
  <span>Context window metadata missing</span>
243
243
  <div className="flex shrink-0 items-center gap-1">
244
244
  <Button
@@ -270,7 +270,7 @@ export function ProviderCard({
270
270
  {showDetails && (
271
271
  <div className="space-y-3 border-t border-border/60 pt-3">
272
272
  <div className="flex items-center gap-2 text-xs text-muted-foreground">
273
- <CheckCircle className="size-3.5 text-emerald-500" />
273
+ <CheckCircle className="size-3.5 text-status-success" />
274
274
  <span>API key configured</span>
275
275
  </div>
276
276
 
@@ -311,7 +311,7 @@ function EndpointUrlPreview({
311
311
  <div
312
312
  key={`${diagnostic.severity}:${diagnostic.message}`}
313
313
  className={
314
- diagnostic.severity === "warning" ? "text-amber-200" : "text-muted-foreground"
314
+ diagnostic.severity === "warning" ? "text-status-watch" : "text-muted-foreground"
315
315
  }
316
316
  >
317
317
  {diagnostic.message}
@@ -809,7 +809,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
809
809
  placeholder="https://api.anthropic.com"
810
810
  className="min-w-0 flex-1 bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
811
811
  />
812
- <span className="shrink-0 select-none border-l border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-muted-foreground">
812
+ <span className="shrink-0 select-none border-l border-border bg-muted/35 px-3 py-2 font-mono text-xs text-muted-foreground">
813
813
  {ANTHROPIC_MESSAGES_ENDPOINT}
814
814
  </span>
815
815
  </div>
@@ -841,7 +841,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
841
841
  placeholder="https://api.openai.com"
842
842
  className="min-w-0 flex-1 bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
843
843
  />
844
- <span className="shrink-0 select-none border-l border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-muted-foreground">
844
+ <span className="shrink-0 select-none border-l border-border bg-muted/35 px-3 py-2 font-mono text-xs text-muted-foreground">
845
845
  {OPENAI_CHAT_COMPLETIONS_ENDPOINT}
846
846
  </span>
847
847
  </div>
@@ -873,7 +873,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
873
873
  placeholder="https://api.openai.com"
874
874
  className="min-w-0 flex-1 bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
875
875
  />
876
- <span className="shrink-0 select-none border-l border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-muted-foreground">
876
+ <span className="shrink-0 select-none border-l border-border bg-muted/35 px-3 py-2 font-mono text-xs text-muted-foreground">
877
877
  {OPENAI_RESPONSES_ENDPOINT}
878
878
  </span>
879
879
  </div>
@@ -937,7 +937,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
937
937
  </div>
938
938
  )}
939
939
  {provider !== undefined && !hasContextMetadata && modelMetadataUrl.trim() === "" && (
940
- <p className="text-xs text-amber-400">
940
+ <p className="text-xs text-status-watch">
941
941
  This provider has no matching context metadata yet.
942
942
  </p>
943
943
  )}
@@ -975,7 +975,11 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
975
975
  className="text-muted-foreground hover:text-foreground transition-colors p-1 shrink-0"
976
976
  aria-label="Copy API key"
977
977
  >
978
- {copied ? <Check className="size-4 text-cyan-300" /> : <Copy className="size-4" />}
978
+ {copied ? (
979
+ <Check className="size-4 text-status-success" />
980
+ ) : (
981
+ <Copy className="size-4" />
982
+ )}
979
983
  </button>
980
984
  </div>
981
985
  {provider !== undefined && apiKey.trim() === "" && (
@@ -1035,7 +1039,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
1035
1039
  updateModel(i, opt);
1036
1040
  setOpenModelDropdown(null);
1037
1041
  }}
1038
- className="w-full px-3 py-2 text-left text-sm transition-colors hover:bg-white/[0.06]"
1042
+ className="w-full px-3 py-2 text-left text-sm transition-colors hover:bg-muted/60"
1039
1043
  >
1040
1044
  {opt}
1041
1045
  </button>
@@ -357,9 +357,9 @@ function ProviderTestResultDialog({
357
357
  <DialogHeader className="border-b border-border/70 px-5 py-4 pr-12">
358
358
  <div className="flex items-center gap-2">
359
359
  {result.success ? (
360
- <CheckCircle className="size-4 text-cyan-300" />
360
+ <CheckCircle className="size-4 text-status-success" />
361
361
  ) : (
362
- <AlertCircle className="size-4 text-red-300" />
362
+ <AlertCircle className="size-4 text-status-danger" />
363
363
  )}
364
364
  <DialogTitle className="text-base">{probeLabel}</DialogTitle>
365
365
  </div>
@@ -369,7 +369,7 @@ function ProviderTestResultDialog({
369
369
  </DialogHeader>
370
370
  <div className="space-y-4 overflow-y-auto p-5">
371
371
  {!result.success && (
372
- <div className="rounded-md border border-red-400/20 bg-red-400/[0.06] px-3 py-2 text-sm text-red-200">
372
+ <div className="rounded-md border border-status-danger/30 bg-status-danger/10 px-3 py-2 text-sm text-status-danger">
373
373
  <div className="font-medium">{errorLabel(result.error?.type ?? "unknown")}</div>
374
374
  <div className="mt-1 break-words text-xs text-muted-foreground">{errorMessage}</div>
375
375
  </div>
@@ -405,8 +405,8 @@ function errorIcon(type: ErrorType): JSX.Element {
405
405
  }
406
406
 
407
407
  const PROBE_TONE_CLASSES: Record<ProbeTone, string> = {
408
- success: "bg-cyan-300/[0.07] text-cyan-100 hover:bg-cyan-300/[0.11]",
409
- failure: "bg-red-400/[0.07] text-red-200 hover:bg-red-400/[0.11]",
408
+ success: "bg-status-success/10 text-status-success hover:bg-status-success/15",
409
+ failure: "bg-status-danger/10 text-status-danger hover:bg-status-danger/15",
410
410
  pending: "bg-muted/40 text-foreground/80",
411
411
  quiet: "bg-transparent text-muted-foreground/70",
412
412
  };
@@ -522,11 +522,9 @@ export function ProviderTestMatrix({
522
522
  </div>
523
523
  {hasAnthropic && <ProviderFormatRow label="Anthropic" results={results?.anthropic} />}
524
524
  {hasChat && <ProviderFormatRow label="OpenAI Chat" results={results?.openaiChat} />}
525
- <ProviderFormatRow
526
- label="OpenAI Responses"
527
- results={results?.openaiResponses}
528
- configured={hasResponses}
529
- />
525
+ {hasResponses && (
526
+ <ProviderFormatRow label="OpenAI Responses" results={results?.openaiResponses} />
527
+ )}
530
528
  </div>
531
529
  </div>
532
530
  );
@@ -554,11 +552,11 @@ function FormatSummaryBadge({
554
552
  const summary = summarizeFormat(results);
555
553
  const className =
556
554
  summary.failed > 0
557
- ? "border-red-400/20 bg-red-400/[0.06] text-red-200"
555
+ ? "border-status-danger/30 bg-status-danger/10 text-status-danger"
558
556
  : summary.testing > 0
559
- ? "border-amber-300/20 bg-amber-300/[0.06] text-amber-100"
557
+ ? "border-status-watch/30 bg-status-watch/10 text-status-watch"
560
558
  : summary.total > 0 && summary.passed === summary.total
561
- ? "border-cyan-300/20 bg-cyan-300/[0.06] text-cyan-100"
559
+ ? "border-status-success/30 bg-status-success/10 text-status-success"
562
560
  : "border-border/60 bg-transparent text-muted-foreground";
563
561
  const value =
564
562
  summary.failed > 0
@@ -688,7 +686,7 @@ export function ProviderTestPill({
688
686
 
689
687
  if (isTesting) {
690
688
  return (
691
- <span className="inline-flex items-center gap-1 rounded border border-cyan-300/25 bg-cyan-300/[0.08] px-2 py-1 text-xs text-cyan-100">
689
+ <span className="inline-flex items-center gap-1 rounded border border-status-cool/30 bg-status-cool/10 px-2 py-1 text-xs text-status-cool">
692
690
  <RotateCw className="size-3 animate-spin" />
693
691
  Testing
694
692
  </span>
@@ -710,7 +708,7 @@ export function ProviderTestPill({
710
708
  }
711
709
  if (summary.failed > 0) {
712
710
  return (
713
- <span className="inline-flex items-center gap-1 rounded border border-red-400/25 bg-red-500/[0.08] px-2 py-1 text-xs text-red-200">
711
+ <span className="inline-flex items-center gap-1 rounded border border-status-danger/30 bg-status-danger/10 px-2 py-1 text-xs text-status-danger">
714
712
  <AlertCircle className="size-3" />
715
713
  {summary.failed} failed
716
714
  </span>
@@ -718,13 +716,13 @@ export function ProviderTestPill({
718
716
  }
719
717
  if (summary.testing > 0 || summary.passed < summary.total) {
720
718
  return (
721
- <span className="rounded border border-amber-300/25 bg-amber-400/[0.08] px-2 py-1 text-xs text-amber-100">
719
+ <span className="rounded border border-status-watch/30 bg-status-watch/10 px-2 py-1 text-xs text-status-watch">
722
720
  {summary.passed}/{summary.total}
723
721
  </span>
724
722
  );
725
723
  }
726
724
  return (
727
- <span className="inline-flex items-center gap-1 rounded border border-cyan-300/25 bg-cyan-300/[0.08] px-2 py-1 text-xs text-cyan-100">
725
+ <span className="inline-flex items-center gap-1 rounded border border-status-success/30 bg-status-success/10 px-2 py-1 text-xs text-status-success">
728
726
  <CheckCircle className="size-3" />
729
727
  {summary.passed}/{summary.total}
730
728
  </span>
@@ -625,7 +625,7 @@ export function ProvidersPanel({
625
625
  aria-label={configPathCopied ? "Copied config file path" : "Copy config file path"}
626
626
  >
627
627
  {configPathCopied ? (
628
- <Check className="size-3 text-cyan-300" />
628
+ <Check className="size-3 text-status-success" />
629
629
  ) : (
630
630
  <Copy className="size-3" />
631
631
  )}