@tonyclaw/agent-inspector 2.1.16 → 2.1.18
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/.output/cli.js +57 -13
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-Ccrrcx1j.js → CompareDrawer-Fqqw5Lci.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-CP_RzwW9.js +106 -0
- package/.output/public/assets/{ReplayDialog-C7axhr-l.js → ReplayDialog-hYhz_i6W.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-WOptg8j_.js → RequestAnatomy-CTuWbtwC.js} +1 -1
- package/.output/public/assets/{ResponseView-CSAcxh_M.js → ResponseView-CsZ7S5Gv.js} +2 -2
- package/.output/public/assets/{StreamingChunkSequence-DJS5KhPx.js → StreamingChunkSequence-PIbJMotU.js} +1 -1
- package/.output/public/assets/_sessionId-CUGA9qU3.js +1 -0
- package/.output/public/assets/{index-DMPNh46t.js → index-F7mynwuH.js} +1 -1
- package/.output/public/assets/index-G4dTUobw.js +1 -0
- package/.output/public/assets/index-gvYkgMPF.css +1 -0
- package/.output/public/assets/{json-viewer-inX5QSa3.js → json-viewer-DCXtNmmD.js} +1 -1
- package/.output/public/assets/{main-aCAKYGSD.js → main-BJZf7_Ib.js} +2 -2
- package/.output/server/_libs/lucide-react.mjs +220 -202
- package/.output/server/{_sessionId-C0fhvQnn.mjs → _sessionId-DjSHDNh8.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-CO-Ti5sg.mjs → CompareDrawer-Dal52IFo.mjs} +3 -3
- package/.output/server/_ssr/{ProxyViewerContainer-N4J7uBCX.mjs → ProxyViewerContainer-CVqFZGff.mjs} +1833 -1366
- package/.output/server/_ssr/{ReplayDialog-J1VxC0In.mjs → ReplayDialog-BOEgdMes.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-DBH-F3rq.mjs → RequestAnatomy-gch7_vCV.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-DLFwV7Hd.mjs → ResponseView-lEWPy-H4.mjs} +3 -3
- package/.output/server/_ssr/{StreamingChunkSequence-BywmuND0.mjs → StreamingChunkSequence-DnudbJ1O.mjs} +2 -2
- package/.output/server/_ssr/{index-CStymIc0.mjs → index-Cza8zDrW.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-DlQu0N1x.mjs → json-viewer-C2lIVEX3.mjs} +3 -3
- package/.output/server/_ssr/{router-CQ4Zxhmr.mjs → router-bF9uzd1k.mjs} +939 -113
- package/.output/server/{_tanstack-start-manifest_v-BHeJBGfo.mjs → _tanstack-start-manifest_v-ErvW-mtr.mjs} +1 -1
- package/.output/server/index.mjs +74 -74
- package/README.md +57 -2
- package/package.json +1 -1
- package/src/cli/startupOutput.ts +16 -0
- package/src/cli.ts +61 -15
- package/src/components/ProxyViewer.tsx +395 -64
- package/src/components/providers/ProviderCard.tsx +132 -31
- package/src/components/providers/ProviderForm.tsx +43 -11
- package/src/components/providers/ProvidersPanel.tsx +1 -1
- package/src/components/proxy-viewer/ConversationHeader.tsx +133 -112
- package/src/components/proxy-viewer/LogEntry.tsx +109 -26
- package/src/components/proxy-viewer/LogEntryHeader.tsx +339 -329
- package/src/components/proxy-viewer/ThreadConnector.tsx +49 -46
- package/src/components/proxy-viewer/TurnGroup.tsx +22 -62
- package/src/components/proxy-viewer/bodyHydration.ts +56 -0
- package/src/lib/providerTestContract.ts +56 -10
- package/src/lib/providerTestPrompt.ts +23 -1
- package/src/lib/upstreamUrl.ts +105 -1
- package/src/mcp/server.ts +275 -0
- package/src/mcp/toolHandlers.ts +381 -4
- package/src/proxy/logSearch.ts +3 -0
- package/src/proxy/store.ts +40 -15
- package/src/routes/api/logs.ts +8 -2
- package/src/routes/api/providers.$providerId.test.log.ts +85 -10
- package/.output/public/assets/ProxyViewerContainer-DLqClc9A.js +0 -106
- package/.output/public/assets/_sessionId-DUSalzKH.js +0 -1
- package/.output/public/assets/index-BPpA21dY.css +0 -1
- package/.output/public/assets/index-Bt0Az2I2.js +0 -1
|
@@ -31,7 +31,15 @@ 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";
|
|
34
41
|
import type {
|
|
42
|
+
ProviderFormatTestResults,
|
|
35
43
|
ProviderTestErrorType as ErrorType,
|
|
36
44
|
ProviderTestResult as TestResult,
|
|
37
45
|
ProviderTestResults as TestResults,
|
|
@@ -65,8 +73,6 @@ function isNotConfiguredState(result: ProviderTestState): result is { notConfigu
|
|
|
65
73
|
return Object.prototype.hasOwnProperty.call(result, "notConfigured");
|
|
66
74
|
}
|
|
67
75
|
|
|
68
|
-
type ProviderFormatTestResults = TestResults["anthropic"];
|
|
69
|
-
|
|
70
76
|
function hasText(value: string | undefined): value is string {
|
|
71
77
|
return value !== undefined && value.trim() !== "";
|
|
72
78
|
}
|
|
@@ -206,12 +212,12 @@ function ProviderFormatTestStatus({
|
|
|
206
212
|
results: ProviderFormatTestResults;
|
|
207
213
|
}): JSX.Element {
|
|
208
214
|
return (
|
|
209
|
-
<div className="
|
|
210
|
-
<div className="
|
|
215
|
+
<div className="grid min-w-0 gap-2 sm:grid-cols-2">
|
|
216
|
+
<div className="min-w-0 rounded-md border border-border/60 bg-muted/20 px-2 py-1.5">
|
|
211
217
|
<span className="text-[10px] text-muted-foreground">Non-stream</span>
|
|
212
218
|
<TestStatus result={results.nonStreaming} />
|
|
213
219
|
</div>
|
|
214
|
-
<div className="
|
|
220
|
+
<div className="min-w-0 rounded-md border border-border/60 bg-muted/20 px-2 py-1.5">
|
|
215
221
|
<span className="text-[10px] text-muted-foreground">Stream</span>
|
|
216
222
|
<TestStatus result={results.streaming} />
|
|
217
223
|
</div>
|
|
@@ -219,6 +225,56 @@ function ProviderFormatTestStatus({
|
|
|
219
225
|
);
|
|
220
226
|
}
|
|
221
227
|
|
|
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({
|
|
241
|
+
label,
|
|
242
|
+
baseUrl,
|
|
243
|
+
endpoint,
|
|
244
|
+
providerName,
|
|
245
|
+
children,
|
|
246
|
+
}: {
|
|
247
|
+
label: string;
|
|
248
|
+
baseUrl: string;
|
|
249
|
+
endpoint: string;
|
|
250
|
+
providerName: string;
|
|
251
|
+
children?: ReactNode;
|
|
252
|
+
}): JSX.Element {
|
|
253
|
+
const preview = previewUpstreamUrl(baseUrl, endpoint, { providerName });
|
|
254
|
+
|
|
255
|
+
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
|
+
)}
|
|
273
|
+
{children}
|
|
274
|
+
</div>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
222
278
|
function getErrorIcon(type: ErrorType): JSX.Element {
|
|
223
279
|
const iconProps = { className: "size-3", strokeWidth: 2 };
|
|
224
280
|
switch (type) {
|
|
@@ -314,8 +370,8 @@ function TestStatus({ result }: { result: ProviderTestState }): JSX.Element {
|
|
|
314
370
|
<TooltipProvider>
|
|
315
371
|
<Tooltip>
|
|
316
372
|
<TooltipTrigger asChild>
|
|
317
|
-
<div className="flex items-center gap-1 text-xs text-
|
|
318
|
-
<CheckCircle className="size-3" />
|
|
373
|
+
<div className="flex items-center gap-1 text-xs text-cyan-100 shrink-0">
|
|
374
|
+
<CheckCircle className="size-3 text-cyan-300" />
|
|
319
375
|
<span>Connected</span>
|
|
320
376
|
{tokenParts.length > 0 && (
|
|
321
377
|
<span className="text-muted-foreground">({displayTokens})</span>
|
|
@@ -440,6 +496,30 @@ export function ProviderCard({
|
|
|
440
496
|
const canRefreshMetadata =
|
|
441
497
|
provider.modelMetadataUrl !== undefined && provider.modelMetadataUrl.trim() !== "";
|
|
442
498
|
const metadataImportLabel = canRefreshMetadata ? "Refresh" : "Import defaults";
|
|
499
|
+
const providerSourceBadge =
|
|
500
|
+
provider.source === "company" ? (
|
|
501
|
+
<TooltipProvider>
|
|
502
|
+
<Tooltip>
|
|
503
|
+
<TooltipTrigger asChild>
|
|
504
|
+
<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">
|
|
505
|
+
Company
|
|
506
|
+
</span>
|
|
507
|
+
</TooltipTrigger>
|
|
508
|
+
<TooltipContent>Company-provided API key</TooltipContent>
|
|
509
|
+
</Tooltip>
|
|
510
|
+
</TooltipProvider>
|
|
511
|
+
) : provider.source === "personal" ? (
|
|
512
|
+
<TooltipProvider>
|
|
513
|
+
<Tooltip>
|
|
514
|
+
<TooltipTrigger asChild>
|
|
515
|
+
<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">
|
|
516
|
+
Personal
|
|
517
|
+
</span>
|
|
518
|
+
</TooltipTrigger>
|
|
519
|
+
<TooltipContent>Your personal API key</TooltipContent>
|
|
520
|
+
</Tooltip>
|
|
521
|
+
</TooltipProvider>
|
|
522
|
+
) : null;
|
|
443
523
|
|
|
444
524
|
return (
|
|
445
525
|
<div
|
|
@@ -448,7 +528,8 @@ export function ProviderCard({
|
|
|
448
528
|
<div className="flex items-start justify-between gap-2">
|
|
449
529
|
<div className="flex items-center gap-2 min-w-0">
|
|
450
530
|
<span className="font-medium truncate">{provider.name}</span>
|
|
451
|
-
{
|
|
531
|
+
{providerSourceBadge}
|
|
532
|
+
{providerSourceBadge === null && provider.source === "company" && (
|
|
452
533
|
<TooltipProvider>
|
|
453
534
|
<Tooltip>
|
|
454
535
|
<TooltipTrigger asChild>
|
|
@@ -460,7 +541,7 @@ export function ProviderCard({
|
|
|
460
541
|
</Tooltip>
|
|
461
542
|
</TooltipProvider>
|
|
462
543
|
)}
|
|
463
|
-
{provider.source === "personal" && (
|
|
544
|
+
{providerSourceBadge === null && provider.source === "personal" && (
|
|
464
545
|
<TooltipProvider>
|
|
465
546
|
<Tooltip>
|
|
466
547
|
<TooltipTrigger asChild>
|
|
@@ -575,39 +656,47 @@ export function ProviderCard({
|
|
|
575
656
|
className="text-muted-foreground hover:text-foreground transition-colors p-1"
|
|
576
657
|
aria-label="Copy API key"
|
|
577
658
|
>
|
|
578
|
-
{copied ? <Check className="size-4 text-
|
|
659
|
+
{copied ? <Check className="size-4 text-cyan-300" /> : <Copy className="size-4" />}
|
|
579
660
|
</button>
|
|
580
661
|
</div>
|
|
581
662
|
|
|
582
663
|
{provider.anthropicBaseUrl !== undefined && provider.anthropicBaseUrl !== "" && (
|
|
583
|
-
<
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
664
|
+
<ProviderEndpointSummary
|
|
665
|
+
label="Anthropic"
|
|
666
|
+
baseUrl={provider.anthropicBaseUrl}
|
|
667
|
+
endpoint={PATH_V1_MESSAGES}
|
|
668
|
+
providerName={provider.name}
|
|
669
|
+
>
|
|
588
670
|
{testResults !== undefined && (
|
|
589
671
|
<ProviderFormatTestStatus results={testResults.anthropic} />
|
|
590
672
|
)}
|
|
591
|
-
</
|
|
673
|
+
</ProviderEndpointSummary>
|
|
592
674
|
)}
|
|
593
675
|
|
|
594
676
|
{provider.openaiBaseUrl !== undefined && provider.openaiBaseUrl !== "" && (
|
|
595
|
-
<
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
677
|
+
<ProviderEndpointSummary
|
|
678
|
+
label="OpenAI Chat"
|
|
679
|
+
baseUrl={provider.openaiBaseUrl}
|
|
680
|
+
endpoint={PATH_V1_CHAT_COMPLETIONS}
|
|
681
|
+
providerName={provider.name}
|
|
682
|
+
>
|
|
683
|
+
{testResults !== undefined && (
|
|
684
|
+
<ProviderFormatTestStatus results={testResults.openaiChat} />
|
|
685
|
+
)}
|
|
686
|
+
</ProviderEndpointSummary>
|
|
602
687
|
)}
|
|
603
688
|
|
|
604
689
|
{provider.openaiResponsesBaseUrl !== undefined && provider.openaiResponsesBaseUrl !== "" && (
|
|
605
|
-
<
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
690
|
+
<ProviderEndpointSummary
|
|
691
|
+
label="OpenAI Responses"
|
|
692
|
+
baseUrl={provider.openaiResponsesBaseUrl}
|
|
693
|
+
endpoint={PATH_V1_RESPONSES}
|
|
694
|
+
providerName={provider.name}
|
|
695
|
+
>
|
|
696
|
+
{testResults !== undefined && (
|
|
697
|
+
<ProviderFormatTestStatus results={testResults.openaiResponses} />
|
|
698
|
+
)}
|
|
699
|
+
</ProviderEndpointSummary>
|
|
611
700
|
)}
|
|
612
701
|
|
|
613
702
|
{testResults?.testedAt !== undefined && (
|
|
@@ -644,9 +733,15 @@ export function ProviderCard({
|
|
|
644
733
|
)}
|
|
645
734
|
{provider.openaiBaseUrl !== undefined && provider.openaiBaseUrl !== "" && (
|
|
646
735
|
<th className="text-left py-1 px-2 font-medium text-muted-foreground">
|
|
647
|
-
|
|
736
|
+
Chat
|
|
648
737
|
</th>
|
|
649
738
|
)}
|
|
739
|
+
{provider.openaiResponsesBaseUrl !== undefined &&
|
|
740
|
+
provider.openaiResponsesBaseUrl !== "" && (
|
|
741
|
+
<th className="text-left py-1 px-2 font-medium text-muted-foreground">
|
|
742
|
+
Responses
|
|
743
|
+
</th>
|
|
744
|
+
)}
|
|
650
745
|
</tr>
|
|
651
746
|
</thead>
|
|
652
747
|
<tbody>
|
|
@@ -661,9 +756,15 @@ export function ProviderCard({
|
|
|
661
756
|
)}
|
|
662
757
|
{provider.openaiBaseUrl !== undefined && provider.openaiBaseUrl !== "" && (
|
|
663
758
|
<td className="py-1 px-2 align-top">
|
|
664
|
-
<ProviderFormatTestStatus results={modelResult.
|
|
759
|
+
<ProviderFormatTestStatus results={modelResult.openaiChat} />
|
|
665
760
|
</td>
|
|
666
761
|
)}
|
|
762
|
+
{provider.openaiResponsesBaseUrl !== undefined &&
|
|
763
|
+
provider.openaiResponsesBaseUrl !== "" && (
|
|
764
|
+
<td className="py-1 px-2 align-top">
|
|
765
|
+
<ProviderFormatTestStatus results={modelResult.openaiResponses} />
|
|
766
|
+
</td>
|
|
767
|
+
)}
|
|
667
768
|
</tr>
|
|
668
769
|
))}
|
|
669
770
|
</tbody>
|
|
@@ -6,7 +6,13 @@ import { Eye, EyeOff, Copy, Check, ChevronDown } from "lucide-react";
|
|
|
6
6
|
import type { ProviderConfig, ProviderModelMetadata } from "../../lib/providerContract";
|
|
7
7
|
import { copyTextToClipboard } from "../../lib/clipboard";
|
|
8
8
|
import { maskApiKey } from "../../lib/mask";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
PATH_V1_CHAT_COMPLETIONS,
|
|
11
|
+
PATH_V1_MESSAGES,
|
|
12
|
+
PATH_V1_RESPONSES,
|
|
13
|
+
previewUpstreamUrl,
|
|
14
|
+
type UpstreamUrlPreview,
|
|
15
|
+
} from "../../lib/upstreamUrl";
|
|
10
16
|
import { formatContextWindowInput, parseContextWindowTokensInput } from "../../lib/utils";
|
|
11
17
|
|
|
12
18
|
const ZHIPU_PROVIDER_KEYWORDS = ["zhipu", "zhipuai", "bigmodel", "z.ai", "zai", "glm"];
|
|
@@ -17,9 +23,9 @@ const ZHIPU_CODING_PROVIDER_KEYWORDS = [
|
|
|
17
23
|
"z.ai coding",
|
|
18
24
|
"zai coding",
|
|
19
25
|
];
|
|
20
|
-
const ANTHROPIC_MESSAGES_ENDPOINT =
|
|
21
|
-
const OPENAI_CHAT_COMPLETIONS_ENDPOINT =
|
|
22
|
-
const OPENAI_RESPONSES_ENDPOINT =
|
|
26
|
+
const ANTHROPIC_MESSAGES_ENDPOINT = PATH_V1_MESSAGES;
|
|
27
|
+
const OPENAI_CHAT_COMPLETIONS_ENDPOINT = PATH_V1_CHAT_COMPLETIONS;
|
|
28
|
+
const OPENAI_RESPONSES_ENDPOINT = PATH_V1_RESPONSES;
|
|
23
29
|
|
|
24
30
|
// Known provider presets - maps provider name keywords to their API URLs
|
|
25
31
|
const KNOWN_PROVIDER_PRESETS: Record<
|
|
@@ -275,25 +281,45 @@ function stripEndpointSuffix(value: string | undefined, endpoint: string): strin
|
|
|
275
281
|
: trimmed;
|
|
276
282
|
}
|
|
277
283
|
|
|
278
|
-
function previewEndpointUrl(
|
|
284
|
+
function previewEndpointUrl(
|
|
285
|
+
baseUrl: string,
|
|
286
|
+
endpoint: string,
|
|
287
|
+
providerName: string,
|
|
288
|
+
): UpstreamUrlPreview | null {
|
|
279
289
|
const trimmed = baseUrl.trim();
|
|
280
|
-
return trimmed === "" ? null :
|
|
290
|
+
return trimmed === "" ? null : previewUpstreamUrl(trimmed, endpoint, { providerName });
|
|
281
291
|
}
|
|
282
292
|
|
|
283
293
|
function EndpointUrlPreview({
|
|
284
294
|
baseUrl,
|
|
285
295
|
endpoint,
|
|
296
|
+
providerName,
|
|
286
297
|
}: {
|
|
287
298
|
baseUrl: string;
|
|
288
299
|
endpoint: string;
|
|
300
|
+
providerName: string;
|
|
289
301
|
}): JSX.Element | null {
|
|
290
|
-
const
|
|
291
|
-
if (
|
|
302
|
+
const preview = previewEndpointUrl(baseUrl, endpoint, providerName);
|
|
303
|
+
if (preview === null) return null;
|
|
292
304
|
|
|
293
305
|
return (
|
|
294
306
|
<div className="border border-border bg-muted/40 rounded-md px-3 py-2 text-xs">
|
|
295
307
|
<div className="text-muted-foreground">Final URL</div>
|
|
296
|
-
<div className="break-all font-mono text-foreground">{finalUrl}</div>
|
|
308
|
+
<div className="break-all font-mono text-foreground">{preview.finalUrl}</div>
|
|
309
|
+
{preview.diagnostics.length > 0 && (
|
|
310
|
+
<div className="mt-2 space-y-1">
|
|
311
|
+
{preview.diagnostics.map((diagnostic) => (
|
|
312
|
+
<div
|
|
313
|
+
key={`${diagnostic.severity}:${diagnostic.message}`}
|
|
314
|
+
className={
|
|
315
|
+
diagnostic.severity === "warning" ? "text-amber-200" : "text-muted-foreground"
|
|
316
|
+
}
|
|
317
|
+
>
|
|
318
|
+
{diagnostic.message}
|
|
319
|
+
</div>
|
|
320
|
+
))}
|
|
321
|
+
</div>
|
|
322
|
+
)}
|
|
297
323
|
</div>
|
|
298
324
|
);
|
|
299
325
|
}
|
|
@@ -729,7 +755,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
|
|
|
729
755
|
className="text-muted-foreground hover:text-foreground transition-colors p-1 shrink-0"
|
|
730
756
|
aria-label="Copy API key"
|
|
731
757
|
>
|
|
732
|
-
{copied ? <Check className="size-4 text-
|
|
758
|
+
{copied ? <Check className="size-4 text-cyan-300" /> : <Copy className="size-4" />}
|
|
733
759
|
</button>
|
|
734
760
|
</div>
|
|
735
761
|
{errors.apiKey !== undefined && <p className="text-xs text-destructive">{errors.apiKey}</p>}
|
|
@@ -964,7 +990,11 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
|
|
|
964
990
|
{errors.anthropicBaseUrl !== undefined && (
|
|
965
991
|
<p className="text-xs text-destructive">{errors.anthropicBaseUrl}</p>
|
|
966
992
|
)}
|
|
967
|
-
<EndpointUrlPreview
|
|
993
|
+
<EndpointUrlPreview
|
|
994
|
+
baseUrl={anthropicBaseUrl}
|
|
995
|
+
endpoint={ANTHROPIC_MESSAGES_ENDPOINT}
|
|
996
|
+
providerName={name}
|
|
997
|
+
/>
|
|
968
998
|
<p className="text-xs text-muted-foreground">
|
|
969
999
|
Anthropic-compatible base URL. Leave empty if this provider does not support Anthropic
|
|
970
1000
|
format.
|
|
@@ -1000,6 +1030,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
|
|
|
1000
1030
|
<EndpointUrlPreview
|
|
1001
1031
|
baseUrl={openaiBaseUrl}
|
|
1002
1032
|
endpoint={OPENAI_CHAT_COMPLETIONS_ENDPOINT}
|
|
1033
|
+
providerName={name}
|
|
1003
1034
|
/>
|
|
1004
1035
|
<p className="text-xs text-muted-foreground">
|
|
1005
1036
|
OpenAI Chat Completions-compatible base URL. Leave empty if this provider only
|
|
@@ -1032,6 +1063,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
|
|
|
1032
1063
|
<EndpointUrlPreview
|
|
1033
1064
|
baseUrl={openaiResponsesBaseUrl}
|
|
1034
1065
|
endpoint={OPENAI_RESPONSES_ENDPOINT}
|
|
1066
|
+
providerName={name}
|
|
1035
1067
|
/>
|
|
1036
1068
|
<p className="text-xs text-muted-foreground">
|
|
1037
1069
|
Optional Responses-compatible base URL. Set only when the provider supports the
|