@tonyclaw/agent-inspector 3.0.9 → 3.0.11

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 (38) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-CJKL4LMm.js → CompareDrawer-gb4FHIDP.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-yqasBIbY.js +106 -0
  4. package/.output/public/assets/{ReplayDialog-BYanl-a_.js → ReplayDialog-uXfMIorn.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-DvPz1jqE.js → RequestAnatomy-NqGFn7lk.js} +1 -1
  6. package/.output/public/assets/{ResponseView-sZnxp9GN.js → ResponseView-BWSWdjPl.js} +2 -2
  7. package/.output/public/assets/{StreamingChunkSequence-G-tiYiBd.js → StreamingChunkSequence-qeCLglzr.js} +1 -1
  8. package/.output/public/assets/{_sessionId-_hDcsmXq.js → _sessionId-COT-xg31.js} +1 -1
  9. package/.output/public/assets/index-BIgsQvaF.css +1 -0
  10. package/.output/public/assets/{index-SuOSQb2_.js → index-CKVD6xzC.js} +1 -1
  11. package/.output/public/assets/index-swjqFLcG.js +1 -0
  12. package/.output/public/assets/{json-viewer-yQdhgjaw.js → json-viewer-ux5usy0f.js} +1 -1
  13. package/.output/public/assets/{main-CgjcDxjR.js → main-BM5Sp2nO.js} +2 -2
  14. package/.output/server/_libs/lucide-react.mjs +2 -2
  15. package/.output/server/{_sessionId-BGISf2En.mjs → _sessionId-8D0eTdRJ.mjs} +2 -2
  16. package/.output/server/_ssr/{CompareDrawer-s-UF9gW3.mjs → CompareDrawer-Hcs0aQWl.mjs} +3 -3
  17. package/.output/server/_ssr/{ProxyViewerContainer-C0Sbz9ED.mjs → ProxyViewerContainer-D2CkbvcS.mjs} +185 -246
  18. package/.output/server/_ssr/{ReplayDialog-DvS8gvJr.mjs → ReplayDialog-O2R9y9xD.mjs} +3 -3
  19. package/.output/server/_ssr/{RequestAnatomy-BwhWglJL.mjs → RequestAnatomy-DkvrjK-3.mjs} +2 -2
  20. package/.output/server/_ssr/{ResponseView-wBVreqQf.mjs → ResponseView-CPcMs3Um.mjs} +2 -2
  21. package/.output/server/_ssr/{StreamingChunkSequence-Dr6eg-MJ.mjs → StreamingChunkSequence-FlBdqDP3.mjs} +2 -2
  22. package/.output/server/_ssr/{index-B98Wia1X.mjs → index-ChG0L62e.mjs} +2 -2
  23. package/.output/server/_ssr/index.mjs +2 -2
  24. package/.output/server/_ssr/{json-viewer-D7L8y0FH.mjs → json-viewer-Bb1g2nec.mjs} +2 -2
  25. package/.output/server/_ssr/{router-g9mo0nWT.mjs → router-840N-dk9.mjs} +21 -12
  26. package/.output/server/{_tanstack-start-manifest_v-CbGc-o50.mjs → _tanstack-start-manifest_v-Qi0D1Tl0.mjs} +1 -1
  27. package/.output/server/index.mjs +70 -70
  28. package/package.json +1 -1
  29. package/src/components/ProxyViewerContainer.tsx +10 -2
  30. package/src/components/providers/ProviderCard.tsx +98 -136
  31. package/src/components/providers/ProvidersPanel.tsx +61 -106
  32. package/src/components/providers/SettingsDialog.tsx +17 -22
  33. package/src/components/proxy-viewer/LogEntryHeader.tsx +17 -43
  34. package/src/components/ui/tooltip.tsx +1 -1
  35. package/src/routes/api/logs.ts +14 -5
  36. package/.output/public/assets/ProxyViewerContainer-DBUy29O-.js +0 -106
  37. package/.output/public/assets/index-DAPAWsAd.js +0 -1
  38. package/.output/public/assets/index-DspnLqUW.css +0 -1
@@ -31,13 +31,6 @@ import {
31
31
  providerHasContextMetadata,
32
32
  } from "../../lib/providerModelMetadata";
33
33
  import { formatContextWindowTokens } from "../../lib/utils";
34
- import {
35
- PATH_V1_CHAT_COMPLETIONS,
36
- PATH_V1_MESSAGES,
37
- PATH_V1_RESPONSES,
38
- previewUpstreamUrl,
39
- type UpstreamUrlDiagnostic,
40
- } from "../../lib/upstreamUrl";
41
34
  import type {
42
35
  ProviderFormatTestResults,
43
36
  ProviderTestErrorType as ErrorType,
@@ -225,51 +218,16 @@ function ProviderFormatTestStatus({
225
218
  );
226
219
  }
227
220
 
228
- function EndpointDiagnosticLine({
229
- diagnostic,
230
- }: {
231
- diagnostic: UpstreamUrlDiagnostic;
232
- }): JSX.Element {
233
- return (
234
- <div className={diagnostic.severity === "warning" ? "text-amber-200" : "text-muted-foreground"}>
235
- {diagnostic.message}
236
- </div>
237
- );
238
- }
239
-
240
- function ProviderEndpointSummary({
221
+ function ProviderFormatStatusBlock({
241
222
  label,
242
- baseUrl,
243
- endpoint,
244
- providerName,
245
223
  children,
246
224
  }: {
247
225
  label: string;
248
- baseUrl: string;
249
- endpoint: string;
250
- providerName: string;
251
226
  children?: ReactNode;
252
227
  }): JSX.Element {
253
- const preview = previewUpstreamUrl(baseUrl, endpoint, { providerName });
254
-
255
228
  return (
256
- <div className="flex min-w-0 flex-col gap-2 border-t border-border/60 pt-2 first:border-t-0 first:pt-0">
257
- <div className="grid min-w-0 gap-1 text-xs sm:grid-cols-[104px_minmax(0,1fr)]">
258
- <span className="font-medium text-muted-foreground">{label}</span>
259
- <code className="min-w-0 break-all font-mono text-foreground/80">{baseUrl}</code>
260
- <span className="text-[10px] uppercase text-muted-foreground/80">Final</span>
261
- <code className="min-w-0 break-all font-mono text-foreground">{preview.finalUrl}</code>
262
- </div>
263
- {preview.diagnostics.length > 0 && (
264
- <div className="space-y-1 text-xs">
265
- {preview.diagnostics.map((diagnostic) => (
266
- <EndpointDiagnosticLine
267
- key={`${diagnostic.severity}:${diagnostic.message}`}
268
- diagnostic={diagnostic}
269
- />
270
- ))}
271
- </div>
272
- )}
229
+ <div className="min-w-0 space-y-2 rounded-md border border-border/60 bg-muted/15 p-2">
230
+ <div className="text-xs font-medium text-foreground/80">{label}</div>
273
231
  {children}
274
232
  </div>
275
233
  );
@@ -293,9 +251,38 @@ function providerTestTargets(provider: ProviderConfig): string[] {
293
251
  return targets;
294
252
  }
295
253
 
296
- function ProviderTestCoverage({ provider }: { provider: ProviderConfig }): JSX.Element {
297
- const targets = providerTestTargets(provider);
298
- if (targets.length === 0) {
254
+ type CapabilityChipTone = "active" | "quiet" | "response";
255
+
256
+ function CapabilityChip({
257
+ label,
258
+ enabled,
259
+ tone,
260
+ }: {
261
+ label: string;
262
+ enabled: boolean;
263
+ tone?: CapabilityChipTone;
264
+ }): JSX.Element {
265
+ const resolvedTone: CapabilityChipTone = tone ?? (enabled ? "active" : "quiet");
266
+ const className =
267
+ resolvedTone === "response" && enabled
268
+ ? "border-sky-300/30 bg-sky-300/[0.09] text-sky-100"
269
+ : enabled
270
+ ? "border-border/70 bg-muted/25 text-foreground/80"
271
+ : "border-border/50 bg-transparent text-muted-foreground/70";
272
+ return (
273
+ <span className={`inline-flex items-center gap-1 rounded border px-1.5 py-0.5 ${className}`}>
274
+ {enabled ? <CheckCircle className="size-3" /> : <Minus className="size-3" />}
275
+ {label}
276
+ </span>
277
+ );
278
+ }
279
+
280
+ function ProviderCapabilitySummary({ provider }: { provider: ProviderConfig }): JSX.Element {
281
+ const hasAnthropic = providerHasEndpoint(provider.anthropicBaseUrl);
282
+ const hasChat = providerHasEndpoint(provider.openaiBaseUrl);
283
+ const hasResponses = providerHasEndpoint(provider.openaiResponsesBaseUrl);
284
+
285
+ if (!hasAnthropic && !hasChat && !hasResponses) {
299
286
  return (
300
287
  <div className="text-xs text-muted-foreground">
301
288
  Test requires at least one configured endpoint.
@@ -305,16 +292,15 @@ function ProviderTestCoverage({ provider }: { provider: ProviderConfig }): JSX.E
305
292
 
306
293
  return (
307
294
  <div className="flex min-w-0 flex-wrap items-center gap-1.5 text-xs text-muted-foreground">
308
- <span>Test covers</span>
309
- {targets.map((target) => (
310
- <span
311
- key={target}
312
- className="rounded border border-border/70 bg-muted/25 px-1.5 py-0.5 text-foreground/80"
313
- >
314
- {target}
315
- </span>
316
- ))}
317
- <span>non-stream + stream</span>
295
+ <span>Capabilities</span>
296
+ {hasAnthropic && <CapabilityChip label="Anthropic" enabled={true} />}
297
+ {hasChat && <CapabilityChip label="OpenAI Chat" enabled={true} />}
298
+ <CapabilityChip
299
+ label={hasResponses ? "OpenAI Responses" : "No OpenAI Responses"}
300
+ enabled={hasResponses}
301
+ tone="response"
302
+ />
303
+ <span>tested non-stream + stream</span>
318
304
  </div>
319
305
  );
320
306
  }
@@ -570,23 +556,14 @@ function TestStatus({ result }: { result: ProviderTestState }): JSX.Element {
570
556
  displayTiming.push(timingParts[i]);
571
557
  }
572
558
  return (
573
- <TooltipProvider>
574
- <Tooltip>
575
- <TooltipTrigger asChild>
576
- <div className="flex items-center gap-1 text-xs text-cyan-100 shrink-0">
577
- <CheckCircle className="size-3 text-cyan-300" />
578
- <span>Connected</span>
579
- {tokenParts.length > 0 && (
580
- <span className="text-muted-foreground">({displayTokens})</span>
581
- )}
582
- {timingParts.length > 0 && (
583
- <span className="hidden text-muted-foreground lg:inline">({displayTiming})</span>
584
- )}
585
- </div>
586
- </TooltipTrigger>
587
- <TooltipContent>Connection test passed</TooltipContent>
588
- </Tooltip>
589
- </TooltipProvider>
559
+ <div className="flex shrink-0 items-center gap-1 text-xs text-cyan-100">
560
+ <CheckCircle className="size-3 text-cyan-300" />
561
+ <span>Connected</span>
562
+ {tokenParts.length > 0 && <span className="text-muted-foreground">({displayTokens})</span>}
563
+ {timingParts.length > 0 && (
564
+ <span className="hidden text-muted-foreground lg:inline">({displayTiming})</span>
565
+ )}
566
+ </div>
590
567
  );
591
568
  }
592
569
 
@@ -599,14 +576,7 @@ function TestStatus({ result }: { result: ProviderTestState }): JSX.Element {
599
576
  <div className="flex flex-col gap-1 shrink-0">
600
577
  <div className="flex items-center gap-1 text-xs text-red-600 max-w-[200px]">
601
578
  {getErrorIcon(errorType)}
602
- <TooltipProvider>
603
- <Tooltip>
604
- <TooltipTrigger asChild>
605
- <span className="truncate">{errorMessage}</span>
606
- </TooltipTrigger>
607
- <TooltipContent>Connection test failed</TooltipContent>
608
- </Tooltip>
609
- </TooltipProvider>
579
+ <span className="truncate">{errorMessage}</span>
610
580
  {hasDetails && (
611
581
  <button
612
582
  type="button"
@@ -703,27 +673,13 @@ export function ProviderCard({
703
673
  const testedModelsLabel = modelResultsLabel(testResults);
704
674
  const providerSourceBadge =
705
675
  provider.source === "company" ? (
706
- <TooltipProvider>
707
- <Tooltip>
708
- <TooltipTrigger asChild>
709
- <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">
710
- Company
711
- </span>
712
- </TooltipTrigger>
713
- <TooltipContent>Company-provided API key</TooltipContent>
714
- </Tooltip>
715
- </TooltipProvider>
676
+ <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">
677
+ Company
678
+ </span>
716
679
  ) : provider.source === "personal" ? (
717
- <TooltipProvider>
718
- <Tooltip>
719
- <TooltipTrigger asChild>
720
- <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">
721
- Personal
722
- </span>
723
- </TooltipTrigger>
724
- <TooltipContent>Your personal API key</TooltipContent>
725
- </Tooltip>
726
- </TooltipProvider>
680
+ <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">
681
+ Personal
682
+ </span>
727
683
  ) : null;
728
684
 
729
685
  return (
@@ -762,7 +718,7 @@ export function ProviderCard({
762
718
  </div>
763
719
 
764
720
  <div className="flex flex-col gap-2 text-xs text-muted-foreground sm:flex-row sm:items-center sm:justify-between">
765
- <ProviderTestCoverage provider={provider} />
721
+ <ProviderCapabilitySummary provider={provider} />
766
722
  <div className="flex flex-wrap items-center gap-2">
767
723
  <span>Key configured</span>
768
724
  <span>{provider.authHeader === "x-api-key" ? "x-api-key" : "Bearer"}</span>
@@ -838,43 +794,49 @@ export function ProviderCard({
838
794
  </div>
839
795
  )}
840
796
 
841
- {providerHasEndpoint(provider.anthropicBaseUrl) && (
842
- <ProviderEndpointSummary
843
- label="Anthropic"
844
- baseUrl={provider.anthropicBaseUrl}
845
- endpoint={PATH_V1_MESSAGES}
846
- providerName={provider.name}
847
- >
848
- {testResults !== undefined && (
849
- <ProviderFormatTestStatus results={testResults.anthropic} />
797
+ {(providerHasEndpoint(provider.anthropicBaseUrl) ||
798
+ providerHasEndpoint(provider.openaiBaseUrl) ||
799
+ providerHasEndpoint(provider.openaiResponsesBaseUrl)) && (
800
+ <div className="grid gap-2 lg:grid-cols-3">
801
+ {providerHasEndpoint(provider.anthropicBaseUrl) && (
802
+ <ProviderFormatStatusBlock label="Anthropic">
803
+ {testResults !== undefined && (
804
+ <ProviderFormatTestStatus results={testResults.anthropic} />
805
+ )}
806
+ {testResults === undefined && (
807
+ <div className="text-xs text-muted-foreground">Not tested yet</div>
808
+ )}
809
+ </ProviderFormatStatusBlock>
850
810
  )}
851
- </ProviderEndpointSummary>
852
- )}
853
811
 
854
- {providerHasEndpoint(provider.openaiBaseUrl) && (
855
- <ProviderEndpointSummary
856
- label="Chat"
857
- baseUrl={provider.openaiBaseUrl}
858
- endpoint={PATH_V1_CHAT_COMPLETIONS}
859
- providerName={provider.name}
860
- >
861
- {testResults !== undefined && (
862
- <ProviderFormatTestStatus results={testResults.openaiChat} />
812
+ {providerHasEndpoint(provider.openaiBaseUrl) && (
813
+ <ProviderFormatStatusBlock label="OpenAI Chat">
814
+ {testResults !== undefined && (
815
+ <ProviderFormatTestStatus results={testResults.openaiChat} />
816
+ )}
817
+ {testResults === undefined && (
818
+ <div className="text-xs text-muted-foreground">Not tested yet</div>
819
+ )}
820
+ </ProviderFormatStatusBlock>
863
821
  )}
864
- </ProviderEndpointSummary>
865
- )}
866
822
 
867
- {providerHasEndpoint(provider.openaiResponsesBaseUrl) && (
868
- <ProviderEndpointSummary
869
- label="Responses"
870
- baseUrl={provider.openaiResponsesBaseUrl}
871
- endpoint={PATH_V1_RESPONSES}
872
- providerName={provider.name}
873
- >
874
- {testResults !== undefined && (
875
- <ProviderFormatTestStatus results={testResults.openaiResponses} />
823
+ {providerHasEndpoint(provider.openaiResponsesBaseUrl) && (
824
+ <ProviderFormatStatusBlock label="OpenAI Responses">
825
+ {testResults !== undefined && (
826
+ <ProviderFormatTestStatus results={testResults.openaiResponses} />
827
+ )}
828
+ {testResults === undefined && (
829
+ <div className="text-xs text-muted-foreground">Not tested yet</div>
830
+ )}
831
+ </ProviderFormatStatusBlock>
832
+ )}
833
+
834
+ {!providerHasEndpoint(provider.openaiResponsesBaseUrl) && (
835
+ <div className="min-w-0 rounded-md border border-border/50 bg-transparent p-2 text-xs text-muted-foreground/75">
836
+ OpenAI Responses not configured
837
+ </div>
876
838
  )}
877
- </ProviderEndpointSummary>
839
+ </div>
878
840
  )}
879
841
 
880
842
  {testResults?.models !== undefined && Object.keys(testResults.models).length > 0 && (
@@ -1,7 +1,6 @@
1
1
  import { type JSX, useState, useEffect, useCallback, useMemo, useRef } from "react";
2
2
  import { z } from "zod";
3
3
  import { Button } from "../ui/button";
4
- import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../ui/tooltip";
5
4
  import { Plus, AlertCircle, Copy, Check, Download, Upload, Scan } from "lucide-react";
6
5
  import { ImportWizardDialog } from "./ImportWizardDialog";
7
6
  import { ConfirmDialog } from "../ui/confirm-dialog";
@@ -535,7 +534,7 @@ export function ProvidersPanel({
535
534
  if (showForm || editingProvider) {
536
535
  return (
537
536
  <div className="space-y-4">
538
- <div className="border border-border bg-background/95 shadow-sm sticky top-0 z-10 flex items-center justify-between rounded-[8px] px-3 py-2">
537
+ <div className="sticky top-0 z-10 flex items-center justify-between gap-3 rounded-[8px] bg-background/95 px-1 py-1 backdrop-blur">
539
538
  <h3 className="text-lg font-medium">
540
539
  {editingProvider ? "Edit Provider" : "Add New Provider"}
541
540
  </h3>
@@ -554,41 +553,27 @@ export function ProvidersPanel({
554
553
 
555
554
  return (
556
555
  <div className="space-y-4">
557
- <div className="border border-border bg-background/95 shadow-sm sticky top-0 z-10 flex items-center justify-between rounded-[8px] px-3 py-2">
556
+ <div className="sticky top-0 z-10 flex items-center justify-between gap-3 rounded-[8px] bg-background/95 px-1 py-1 backdrop-blur">
558
557
  <h3 className="text-lg font-medium">Providers</h3>
559
558
  <div className="flex items-center gap-2">
560
- <TooltipProvider>
561
- <Tooltip>
562
- <TooltipTrigger asChild>
563
- <Button
564
- variant="outline"
565
- size="sm"
566
- onClick={() => handleExport(false)}
567
- className="gap-1 hover:bg-muted"
568
- >
569
- <Download className="size-3" />
570
- Export
571
- </Button>
572
- </TooltipTrigger>
573
- <TooltipContent>Download providers as JSON for backup or sharing</TooltipContent>
574
- </Tooltip>
575
- </TooltipProvider>
576
- <TooltipProvider>
577
- <Tooltip>
578
- <TooltipTrigger asChild>
579
- <Button
580
- variant="outline"
581
- size="sm"
582
- onClick={handleImportClick}
583
- className="gap-1 hover:bg-muted"
584
- >
585
- <Upload className="size-3" />
586
- Import
587
- </Button>
588
- </TooltipTrigger>
589
- <TooltipContent>Import providers from an exported JSON file</TooltipContent>
590
- </Tooltip>
591
- </TooltipProvider>
559
+ <Button
560
+ variant="outline"
561
+ size="sm"
562
+ onClick={() => handleExport(false)}
563
+ className="gap-1 hover:bg-muted"
564
+ >
565
+ <Download className="size-3" />
566
+ Export
567
+ </Button>
568
+ <Button
569
+ variant="outline"
570
+ size="sm"
571
+ onClick={handleImportClick}
572
+ className="gap-1 hover:bg-muted"
573
+ >
574
+ <Upload className="size-3" />
575
+ Import
576
+ </Button>
592
577
  <input
593
578
  type="file"
594
579
  ref={fileInputRef}
@@ -596,24 +581,15 @@ export function ProvidersPanel({
596
581
  onChange={handleFileChange}
597
582
  style={{ display: "none" }}
598
583
  />
599
- <TooltipProvider>
600
- <Tooltip>
601
- <TooltipTrigger asChild>
602
- <Button
603
- variant="outline"
604
- size="sm"
605
- onClick={() => setShowImportWizard(true)}
606
- className="gap-1"
607
- >
608
- <Scan className="size-3" />
609
- Scan
610
- </Button>
611
- </TooltipTrigger>
612
- <TooltipContent>
613
- Detect and import provider configs from Claude Code and OpenCode
614
- </TooltipContent>
615
- </Tooltip>
616
- </TooltipProvider>
584
+ <Button
585
+ variant="outline"
586
+ size="sm"
587
+ onClick={() => setShowImportWizard(true)}
588
+ className="gap-1"
589
+ >
590
+ <Scan className="size-3" />
591
+ Scan
592
+ </Button>
617
593
  <Button onClick={() => setShowForm(true)} size="sm" className="gap-1">
618
594
  <Plus className="size-4" />
619
595
  Add Provider
@@ -622,38 +598,29 @@ export function ProvidersPanel({
622
598
  </div>
623
599
 
624
600
  {configPath !== null && (
625
- <div className="border border-border bg-card shadow-sm flex items-center gap-2 rounded-[8px] px-3 py-2 text-xs text-muted-foreground">
601
+ <div className="flex items-center gap-2 rounded-[8px] bg-muted/15 px-3 py-2 text-xs text-muted-foreground">
626
602
  <span className="shrink-0">Config:</span>
627
603
  <span className="font-mono truncate" title={configPath}>
628
604
  {configPath}
629
605
  </span>
630
- <TooltipProvider>
631
- <Tooltip>
632
- <TooltipTrigger asChild>
633
- <button
634
- type="button"
635
- onClick={() => {
636
- void copyTextToClipboard(configPath).then((success) => {
637
- if (!success) return;
638
- setConfigPathCopied(true);
639
- setTimeout(() => setConfigPathCopied(false), 2000);
640
- });
641
- }}
642
- className="shrink-0 ml-auto text-muted-foreground hover:text-foreground transition-colors"
643
- aria-label={
644
- configPathCopied ? "Copied config file path" : "Copy config file path"
645
- }
646
- >
647
- {configPathCopied ? (
648
- <Check className="size-3 text-cyan-300" />
649
- ) : (
650
- <Copy className="size-3" />
651
- )}
652
- </button>
653
- </TooltipTrigger>
654
- <TooltipContent>Copy config file path to clipboard</TooltipContent>
655
- </Tooltip>
656
- </TooltipProvider>
606
+ <button
607
+ type="button"
608
+ onClick={() => {
609
+ void copyTextToClipboard(configPath).then((success) => {
610
+ if (!success) return;
611
+ setConfigPathCopied(true);
612
+ setTimeout(() => setConfigPathCopied(false), 2000);
613
+ });
614
+ }}
615
+ className="ml-auto shrink-0 text-muted-foreground transition-colors hover:text-foreground"
616
+ aria-label={configPathCopied ? "Copied config file path" : "Copy config file path"}
617
+ >
618
+ {configPathCopied ? (
619
+ <Check className="size-3 text-cyan-300" />
620
+ ) : (
621
+ <Copy className="size-3" />
622
+ )}
623
+ </button>
657
624
  </div>
658
625
  )}
659
626
 
@@ -674,32 +641,20 @@ export function ProvidersPanel({
674
641
  </div>
675
642
  ) : (
676
643
  <div className="space-y-3">
677
- <div className="border border-border bg-muted/40 flex gap-1 rounded-[8px] p-1">
644
+ <div className="inline-flex w-fit gap-1 rounded-[8px] bg-muted/20 p-1">
678
645
  {(["all", "personal", "company"] as const).map((tab) => (
679
- <TooltipProvider key={tab}>
680
- <Tooltip>
681
- <TooltipTrigger asChild>
682
- <button
683
- type="button"
684
- onClick={() => setSourceFilter(tab)}
685
- className={`px-3 py-2 text-sm font-medium border-b-2 transition-colors ${
686
- sourceFilter === tab
687
- ? "border-primary text-primary"
688
- : "border-transparent text-muted-foreground hover:text-foreground"
689
- }`}
690
- >
691
- {tab === "all" ? "All" : tab === "personal" ? "Personal" : "Company"}
692
- </button>
693
- </TooltipTrigger>
694
- <TooltipContent>
695
- {tab === "all"
696
- ? "Show all providers"
697
- : tab === "personal"
698
- ? "Providers you configured yourself"
699
- : "Providers set by your organization"}
700
- </TooltipContent>
701
- </Tooltip>
702
- </TooltipProvider>
646
+ <button
647
+ key={tab}
648
+ type="button"
649
+ onClick={() => setSourceFilter(tab)}
650
+ className={`rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${
651
+ sourceFilter === tab
652
+ ? "bg-background text-foreground shadow-sm"
653
+ : "text-muted-foreground hover:text-foreground"
654
+ }`}
655
+ >
656
+ {tab === "all" ? "All" : tab === "personal" ? "Personal" : "Company"}
657
+ </button>
703
658
  ))}
704
659
  </div>
705
660
  <div ref={listScrollRef} className="space-y-3">