@tonyclaw/llm-inspector 1.11.2 → 1.11.4
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/nitro.json +1 -1
- package/.output/public/assets/{index-DLvqlFS9.js → index-CjjXIYIt.js} +20 -20
- package/.output/public/assets/{index-Chp_30CP.js → index-Do7wdaYZ.js} +1 -1
- package/.output/server/_ssr/{index-CYuV1ljD.mjs → index-BWMVJy33.mjs} +44 -17
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-e-RbjELX.mjs → router-DRA0j7Zv.mjs} +44 -21
- package/.output/server/{_tanstack-start-manifest_v-C5P5lsG5.mjs → _tanstack-start-manifest_v-DKfW4gRz.mjs} +1 -1
- package/.output/server/index.mjs +17 -17
- package/package.json +1 -1
- package/src/components/providers/ProviderForm.tsx +22 -15
- package/src/components/providers/ProvidersPanel.tsx +31 -13
- package/src/components/proxy-viewer/ResponseView.tsx +5 -1
- package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +1 -0
- package/src/proxy/formats/anthropic/schemas.ts +8 -1
- package/src/proxy/formats/anthropic/stream.ts +41 -18
- package/src/routes/api/providers.ts +5 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as reactExports, j as jsxRuntimeExports, R as React } from "../_libs/react.mjs";
|
|
2
|
-
import { C as CapturedLogSchema, R as RuntimeConfigSchema, a as parseRequest, s as stripClaudeCodeBillingHeader, p as parseOpenAIResponse, I as InspectorResponseSchema } from "./router-
|
|
2
|
+
import { C as CapturedLogSchema, R as RuntimeConfigSchema, a as parseRequest, s as stripClaudeCodeBillingHeader, p as parseOpenAIResponse, I as InspectorResponseSchema } from "./router-DRA0j7Zv.mjs";
|
|
3
3
|
import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
|
|
4
4
|
import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
|
|
5
5
|
import { J as JSZip } from "../_libs/jszip.mjs";
|
|
@@ -255,7 +255,7 @@ async function exportLogsAsZip(logs) {
|
|
|
255
255
|
document.body.removeChild(anchor);
|
|
256
256
|
URL.revokeObjectURL(url);
|
|
257
257
|
}
|
|
258
|
-
const version = "1.11.
|
|
258
|
+
const version = "1.11.4";
|
|
259
259
|
const packageJson = {
|
|
260
260
|
version
|
|
261
261
|
};
|
|
@@ -1778,6 +1778,7 @@ function ResponseContentBlockRenderer({
|
|
|
1778
1778
|
case "text":
|
|
1779
1779
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(TextBlock, { text: block.text });
|
|
1780
1780
|
case "thinking":
|
|
1781
|
+
case "think":
|
|
1781
1782
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(ThinkingBlock, { thinking: block.thinking });
|
|
1782
1783
|
case "tool_use":
|
|
1783
1784
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(ToolUseBlock, { name: block.name, input: block.input });
|
|
@@ -1907,7 +1908,10 @@ function getStatusClasses(category) {
|
|
|
1907
1908
|
}
|
|
1908
1909
|
function parseResponse(text, apiFormat) {
|
|
1909
1910
|
try {
|
|
1910
|
-
|
|
1911
|
+
let json = JSON.parse(text);
|
|
1912
|
+
if (typeof json === "string") {
|
|
1913
|
+
json = JSON.parse(json);
|
|
1914
|
+
}
|
|
1911
1915
|
if (apiFormat === "openai") {
|
|
1912
1916
|
const result2 = parseOpenAIResponse(text);
|
|
1913
1917
|
if (result2) return result2;
|
|
@@ -2937,7 +2941,8 @@ const KNOWN_PROVIDER_PRESETS = {
|
|
|
2937
2941
|
},
|
|
2938
2942
|
minimax: {
|
|
2939
2943
|
format: "anthropic",
|
|
2940
|
-
baseUrl: "https://api.minimaxi.com/anthropic"
|
|
2944
|
+
baseUrl: "https://api.minimaxi.com/anthropic",
|
|
2945
|
+
apiDocsUrl: "https://platform.minimaxi.com/docs/api-reference/api-overview"
|
|
2941
2946
|
},
|
|
2942
2947
|
alibaba: {
|
|
2943
2948
|
format: "openai",
|
|
@@ -2945,6 +2950,7 @@ const KNOWN_PROVIDER_PRESETS = {
|
|
|
2945
2950
|
}
|
|
2946
2951
|
};
|
|
2947
2952
|
const MINIMAX_MODELS = [
|
|
2953
|
+
"MiniMax M3",
|
|
2948
2954
|
"MiniMax M2.7",
|
|
2949
2955
|
"MiniMax M2.7-highspeed",
|
|
2950
2956
|
"MiniMax M2.5",
|
|
@@ -2985,6 +2991,9 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
2985
2991
|
setFormat(preset.format);
|
|
2986
2992
|
setBaseUrl(preset.baseUrl);
|
|
2987
2993
|
}
|
|
2994
|
+
if (preset.apiDocsUrl !== void 0 && !apiDocsUrl) {
|
|
2995
|
+
setApiDocsUrl(preset.apiDocsUrl);
|
|
2996
|
+
}
|
|
2988
2997
|
if (keyword === "minimax" && !model) {
|
|
2989
2998
|
setModel(MINIMAX_MODELS[0] ?? "");
|
|
2990
2999
|
}
|
|
@@ -3331,11 +3340,17 @@ function ProvidersPanel({
|
|
|
3331
3340
|
anthropicBaseUrl: data.format === "anthropic" ? data.baseUrl : void 0,
|
|
3332
3341
|
openaiBaseUrl: data.format === "openai" ? data.baseUrl : void 0
|
|
3333
3342
|
};
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3343
|
+
let res;
|
|
3344
|
+
try {
|
|
3345
|
+
res = await fetch("/api/providers", {
|
|
3346
|
+
method: "POST",
|
|
3347
|
+
headers: { "Content-Type": "application/json" },
|
|
3348
|
+
body: JSON.stringify(payload)
|
|
3349
|
+
});
|
|
3350
|
+
} catch (err) {
|
|
3351
|
+
setError("Network error: could not reach the server. Is the proxy running?");
|
|
3352
|
+
return;
|
|
3353
|
+
}
|
|
3339
3354
|
if (!res.ok) {
|
|
3340
3355
|
const err = await res.json();
|
|
3341
3356
|
setError(err.error ?? "Failed to add provider");
|
|
@@ -3358,11 +3373,17 @@ function ProvidersPanel({
|
|
|
3358
3373
|
anthropicBaseUrl: data.format === "anthropic" ? data.baseUrl : void 0,
|
|
3359
3374
|
openaiBaseUrl: data.format === "openai" ? data.baseUrl : void 0
|
|
3360
3375
|
};
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3376
|
+
let res;
|
|
3377
|
+
try {
|
|
3378
|
+
res = await fetch(`/api/providers/${editingProvider.id}`, {
|
|
3379
|
+
method: "PUT",
|
|
3380
|
+
headers: { "Content-Type": "application/json" },
|
|
3381
|
+
body: JSON.stringify(payload)
|
|
3382
|
+
});
|
|
3383
|
+
} catch (err) {
|
|
3384
|
+
setError("Network error: could not reach the server. Is the proxy running?");
|
|
3385
|
+
return;
|
|
3386
|
+
}
|
|
3366
3387
|
if (!res.ok) {
|
|
3367
3388
|
const err = await res.json();
|
|
3368
3389
|
setError(err.error ?? "Failed to update provider");
|
|
@@ -3377,9 +3398,15 @@ function ProvidersPanel({
|
|
|
3377
3398
|
function handleDeleteProvider(providerId) {
|
|
3378
3399
|
if (!window.confirm("Are you sure you want to delete this provider?")) return;
|
|
3379
3400
|
void (async () => {
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3401
|
+
let res;
|
|
3402
|
+
try {
|
|
3403
|
+
res = await fetch(`/api/providers/${providerId}`, {
|
|
3404
|
+
method: "DELETE"
|
|
3405
|
+
});
|
|
3406
|
+
} catch (err) {
|
|
3407
|
+
setError("Network error: could not reach the server. Is the proxy running?");
|
|
3408
|
+
return;
|
|
3409
|
+
}
|
|
3383
3410
|
if (!res.ok) {
|
|
3384
3411
|
const err = await res.json();
|
|
3385
3412
|
setError(err.error ?? "Failed to delete provider");
|
|
@@ -85,7 +85,7 @@ function getResponse() {
|
|
|
85
85
|
}
|
|
86
86
|
var HEADERS = { TSS_SHELL: "X-TSS_SHELL" };
|
|
87
87
|
async function getStartManifest(matchedRoutes) {
|
|
88
|
-
const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-
|
|
88
|
+
const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-DKfW4gRz.mjs");
|
|
89
89
|
const startManifest = tsrStartManifest();
|
|
90
90
|
let routes = startManifest.routes;
|
|
91
91
|
routes[rootRouteId];
|
|
@@ -1157,7 +1157,7 @@ var getBaseManifest = getProdBaseManifest;
|
|
|
1157
1157
|
var createEarlyHintsForRequest = createEarlyHintsCollector;
|
|
1158
1158
|
async function loadEntries() {
|
|
1159
1159
|
const [routerEntry, startEntry, pluginAdapters] = await Promise.all([
|
|
1160
|
-
import("./router-
|
|
1160
|
+
import("./router-DRA0j7Zv.mjs").then((n) => n.r),
|
|
1161
1161
|
import("./start-HYkvq4Ni.mjs"),
|
|
1162
1162
|
import("./empty-plugin-adapters-BFgPZ6_d.mjs")
|
|
1163
1163
|
]);
|
|
@@ -66,7 +66,7 @@ function RootDocument({ children }) {
|
|
|
66
66
|
] })
|
|
67
67
|
] });
|
|
68
68
|
}
|
|
69
|
-
const $$splitComponentImporter = () => import("./index-
|
|
69
|
+
const $$splitComponentImporter = () => import("./index-BWMVJy33.mjs");
|
|
70
70
|
const Route$g = createFileRoute("/")({
|
|
71
71
|
component: lazyRouteComponent($$splitComponentImporter, "component")
|
|
72
72
|
});
|
|
@@ -346,6 +346,11 @@ const ThinkingContentBlock = object({
|
|
|
346
346
|
thinking: string(),
|
|
347
347
|
signature: string().optional()
|
|
348
348
|
});
|
|
349
|
+
const ThinkContentBlock = object({
|
|
350
|
+
type: literal("think"),
|
|
351
|
+
thinking: string(),
|
|
352
|
+
signature: string().optional()
|
|
353
|
+
});
|
|
349
354
|
const ImageSourceBlock = object({
|
|
350
355
|
type: literal("base64"),
|
|
351
356
|
media_type: string(),
|
|
@@ -419,6 +424,7 @@ const AnthropicRequestSchema = object({
|
|
|
419
424
|
const ResponseContentBlock = discriminatedUnion("type", [
|
|
420
425
|
TextContentBlock,
|
|
421
426
|
ThinkingContentBlock,
|
|
427
|
+
ThinkContentBlock,
|
|
422
428
|
ToolUseContentBlock
|
|
423
429
|
]);
|
|
424
430
|
const ResponseUsageSchema = object({
|
|
@@ -434,7 +440,7 @@ const AnthropicResponseSchema$1 = object({
|
|
|
434
440
|
role: literal("assistant"),
|
|
435
441
|
content: array(ResponseContentBlock),
|
|
436
442
|
stop_reason: string().nullable(),
|
|
437
|
-
stop_sequence: string().nullable(),
|
|
443
|
+
stop_sequence: string().nullable().optional(),
|
|
438
444
|
usage: ResponseUsageSchema
|
|
439
445
|
}).passthrough();
|
|
440
446
|
const SseMessageStartEvent = object({
|
|
@@ -1068,6 +1074,11 @@ function finalizeBlock(block) {
|
|
|
1068
1074
|
if (block.signature !== "") out.signature = block.signature;
|
|
1069
1075
|
return out;
|
|
1070
1076
|
}
|
|
1077
|
+
case "think": {
|
|
1078
|
+
const out = { type: "think", thinking: block.thinking };
|
|
1079
|
+
if (block.signature !== "") out.signature = block.signature;
|
|
1080
|
+
return out;
|
|
1081
|
+
}
|
|
1071
1082
|
case "tool_use":
|
|
1072
1083
|
return {
|
|
1073
1084
|
type: "tool_use",
|
|
@@ -1122,21 +1133,32 @@ function extractAnthropicStream(raw, log, fallbackModel, collectChunks) {
|
|
|
1122
1133
|
break;
|
|
1123
1134
|
case "content_block_start": {
|
|
1124
1135
|
const cb = data.content_block;
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1136
|
+
switch (cb.type) {
|
|
1137
|
+
case "text":
|
|
1138
|
+
blocks.set(data.index, { type: "text", text: cb.text ?? "" });
|
|
1139
|
+
break;
|
|
1140
|
+
case "thinking":
|
|
1141
|
+
blocks.set(data.index, {
|
|
1142
|
+
type: "thinking",
|
|
1143
|
+
thinking: cb.thinking ?? "",
|
|
1144
|
+
signature: cb.signature ?? ""
|
|
1145
|
+
});
|
|
1146
|
+
break;
|
|
1147
|
+
case "think":
|
|
1148
|
+
blocks.set(data.index, {
|
|
1149
|
+
type: "think",
|
|
1150
|
+
thinking: cb.thinking ?? "",
|
|
1151
|
+
signature: cb.signature ?? ""
|
|
1152
|
+
});
|
|
1153
|
+
break;
|
|
1154
|
+
case "tool_use":
|
|
1155
|
+
blocks.set(data.index, {
|
|
1156
|
+
type: "tool_use",
|
|
1157
|
+
id: cb.id,
|
|
1158
|
+
name: cb.name,
|
|
1159
|
+
inputJson: ""
|
|
1160
|
+
});
|
|
1161
|
+
break;
|
|
1140
1162
|
}
|
|
1141
1163
|
break;
|
|
1142
1164
|
}
|
|
@@ -1146,9 +1168,9 @@ function extractAnthropicStream(raw, log, fallbackModel, collectChunks) {
|
|
|
1146
1168
|
const delta = data.delta;
|
|
1147
1169
|
if (delta.type === "text_delta" && block.type === "text") {
|
|
1148
1170
|
block.text += delta.text;
|
|
1149
|
-
} else if (delta.type === "thinking_delta" && block.type === "thinking") {
|
|
1171
|
+
} else if (delta.type === "thinking_delta" && (block.type === "thinking" || block.type === "think")) {
|
|
1150
1172
|
block.thinking += delta.thinking;
|
|
1151
|
-
} else if (delta.type === "signature_delta" && block.type === "thinking") {
|
|
1173
|
+
} else if (delta.type === "signature_delta" && (block.type === "thinking" || block.type === "think")) {
|
|
1152
1174
|
block.signature += delta.signature;
|
|
1153
1175
|
} else if (delta.type === "input_json_delta" && block.type === "tool_use") {
|
|
1154
1176
|
block.inputJson += delta.partial_json;
|
|
@@ -2408,7 +2430,8 @@ const ProviderInputSchema = object({
|
|
|
2408
2430
|
name: string().min(1, "Name is required"),
|
|
2409
2431
|
apiKey: string().min(1, "API key is required"),
|
|
2410
2432
|
format: _enum(["anthropic", "openai"]),
|
|
2411
|
-
|
|
2433
|
+
anthropicBaseUrl: string().optional(),
|
|
2434
|
+
openaiBaseUrl: string().optional(),
|
|
2412
2435
|
model: string().min(1, "Model is required"),
|
|
2413
2436
|
authHeader: _enum(["bearer", "x-api-key"]).optional().default("bearer"),
|
|
2414
2437
|
apiDocsUrl: string().optional()
|
|
@@ -2428,7 +2451,7 @@ const Route$d = createFileRoute("/api/providers")({
|
|
|
2428
2451
|
parsed.data.name,
|
|
2429
2452
|
parsed.data.apiKey,
|
|
2430
2453
|
parsed.data.format,
|
|
2431
|
-
parsed.data.
|
|
2454
|
+
parsed.data.format === "anthropic" ? parsed.data.anthropicBaseUrl : parsed.data.openaiBaseUrl,
|
|
2432
2455
|
parsed.data.model,
|
|
2433
2456
|
parsed.data.authHeader,
|
|
2434
2457
|
parsed.data.apiDocsUrl
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const tsrStartManifest = () => ({ routes: { __root__: { filePath: "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", children: ["/", "/api/config", "/api/health", "/api/logs", "/api/models", "/api/providers", "/api/sessions", "/proxy/$"], preloads: ["/assets/index-
|
|
1
|
+
const tsrStartManifest = () => ({ routes: { __root__: { filePath: "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", children: ["/", "/api/config", "/api/health", "/api/logs", "/api/models", "/api/providers", "/api/sessions", "/proxy/$"], preloads: ["/assets/index-Do7wdaYZ.js"], scripts: [{ attrs: { type: "module", async: true, src: "/assets/index-Do7wdaYZ.js" } }] }, "/": { filePath: "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", children: void 0, preloads: ["/assets/index-CjjXIYIt.js"] } } });
|
|
2
2
|
export {
|
|
3
3
|
tsrStartManifest
|
|
4
4
|
};
|
package/.output/server/index.mjs
CHANGED
|
@@ -38,51 +38,51 @@ const assets = {
|
|
|
38
38
|
"/assets/alibaba-TTwafVwX.svg": {
|
|
39
39
|
"type": "image/svg+xml",
|
|
40
40
|
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
41
|
-
"mtime": "2026-06-
|
|
41
|
+
"mtime": "2026-06-08T00:49:07.051Z",
|
|
42
42
|
"size": 5915,
|
|
43
43
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
44
44
|
},
|
|
45
45
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
46
46
|
"type": "image/jpeg",
|
|
47
47
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
48
|
-
"mtime": "2026-06-
|
|
48
|
+
"mtime": "2026-06-08T00:49:07.048Z",
|
|
49
49
|
"size": 6918,
|
|
50
50
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
51
51
|
},
|
|
52
52
|
"/assets/index-BpKPXEcb.css": {
|
|
53
53
|
"type": "text/css; charset=utf-8",
|
|
54
54
|
"etag": '"11628-5GjLelHqc7BEfGB/7qUFPt5/gyM"',
|
|
55
|
-
"mtime": "2026-06-
|
|
55
|
+
"mtime": "2026-06-08T00:49:07.051Z",
|
|
56
56
|
"size": 71208,
|
|
57
57
|
"path": "../public/assets/index-BpKPXEcb.css"
|
|
58
58
|
},
|
|
59
59
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
60
60
|
"type": "image/svg+xml",
|
|
61
61
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
62
|
-
"mtime": "2026-06-
|
|
62
|
+
"mtime": "2026-06-08T00:49:07.051Z",
|
|
63
63
|
"size": 11256,
|
|
64
64
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
65
65
|
},
|
|
66
|
+
"/assets/index-Do7wdaYZ.js": {
|
|
67
|
+
"type": "text/javascript; charset=utf-8",
|
|
68
|
+
"etag": '"5103c-aaFcAP7Accy+WRst7gdyeAfO198"',
|
|
69
|
+
"mtime": "2026-06-08T00:49:07.051Z",
|
|
70
|
+
"size": 331836,
|
|
71
|
+
"path": "../public/assets/index-Do7wdaYZ.js"
|
|
72
|
+
},
|
|
66
73
|
"/assets/qwen-CONDcHqt.png": {
|
|
67
74
|
"type": "image/png",
|
|
68
75
|
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
69
|
-
"mtime": "2026-06-
|
|
76
|
+
"mtime": "2026-06-08T00:49:07.051Z",
|
|
70
77
|
"size": 357059,
|
|
71
78
|
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
72
79
|
},
|
|
73
|
-
"/assets/index-
|
|
74
|
-
"type": "text/javascript; charset=utf-8",
|
|
75
|
-
"etag": '"5103c-5HK4V8mRGKw17pJ5x54GVb2N5bU"',
|
|
76
|
-
"mtime": "2026-06-06T09:13:20.380Z",
|
|
77
|
-
"size": 331836,
|
|
78
|
-
"path": "../public/assets/index-Chp_30CP.js"
|
|
79
|
-
},
|
|
80
|
-
"/assets/index-DLvqlFS9.js": {
|
|
80
|
+
"/assets/index-CjjXIYIt.js": {
|
|
81
81
|
"type": "text/javascript; charset=utf-8",
|
|
82
|
-
"etag": '"
|
|
83
|
-
"mtime": "2026-06-
|
|
84
|
-
"size":
|
|
85
|
-
"path": "../public/assets/index-
|
|
82
|
+
"etag": '"8b905-rdaof1vYelA3ENck4MON8W7NPww"',
|
|
83
|
+
"mtime": "2026-06-08T00:49:07.051Z",
|
|
84
|
+
"size": 571653,
|
|
85
|
+
"path": "../public/assets/index-CjjXIYIt.js"
|
|
86
86
|
}
|
|
87
87
|
};
|
|
88
88
|
function readAsset(id) {
|
package/package.json
CHANGED
|
@@ -3,24 +3,28 @@ import { Button } from "../ui/button";
|
|
|
3
3
|
import type { ProviderConfig } from "../../proxy/providers";
|
|
4
4
|
|
|
5
5
|
// Known provider presets - maps provider name keywords to their API URLs
|
|
6
|
-
const KNOWN_PROVIDER_PRESETS: Record<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
const KNOWN_PROVIDER_PRESETS: Record<
|
|
7
|
+
string,
|
|
8
|
+
{ format: "anthropic" | "openai"; baseUrl: string; apiDocsUrl?: string }
|
|
9
|
+
> = {
|
|
10
|
+
deepseek: {
|
|
11
|
+
format: "openai",
|
|
12
|
+
baseUrl: "https://api.deepseek.com",
|
|
13
|
+
},
|
|
14
|
+
minimax: {
|
|
15
|
+
format: "anthropic",
|
|
16
|
+
baseUrl: "https://api.minimaxi.com/anthropic",
|
|
17
|
+
apiDocsUrl: "https://platform.minimaxi.com/docs/api-reference/api-overview",
|
|
18
|
+
},
|
|
19
|
+
alibaba: {
|
|
20
|
+
format: "openai",
|
|
21
|
+
baseUrl: "https://dashscope.aliyuncs.com/compatible-mode",
|
|
22
|
+
},
|
|
23
|
+
};
|
|
21
24
|
|
|
22
25
|
// MiniMax model options
|
|
23
26
|
const MINIMAX_MODELS = [
|
|
27
|
+
"MiniMax M3",
|
|
24
28
|
"MiniMax M2.7",
|
|
25
29
|
"MiniMax M2.7-highspeed",
|
|
26
30
|
"MiniMax M2.5",
|
|
@@ -85,6 +89,9 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
|
|
|
85
89
|
setFormat(preset.format);
|
|
86
90
|
setBaseUrl(preset.baseUrl);
|
|
87
91
|
}
|
|
92
|
+
if (preset.apiDocsUrl !== undefined && !apiDocsUrl) {
|
|
93
|
+
setApiDocsUrl(preset.apiDocsUrl);
|
|
94
|
+
}
|
|
88
95
|
// For MiniMax, auto-select the first model if not already set
|
|
89
96
|
if (keyword === "minimax" && !model) {
|
|
90
97
|
setModel(MINIMAX_MODELS[0] ?? "");
|
|
@@ -261,11 +261,17 @@ export function ProvidersPanel({
|
|
|
261
261
|
anthropicBaseUrl: data.format === "anthropic" ? data.baseUrl : undefined,
|
|
262
262
|
openaiBaseUrl: data.format === "openai" ? data.baseUrl : undefined,
|
|
263
263
|
};
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
264
|
+
let res: Response;
|
|
265
|
+
try {
|
|
266
|
+
res = await fetch("/api/providers", {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: { "Content-Type": "application/json" },
|
|
269
|
+
body: JSON.stringify(payload),
|
|
270
|
+
});
|
|
271
|
+
} catch (err) {
|
|
272
|
+
setError("Network error: could not reach the server. Is the proxy running?");
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
269
275
|
if (!res.ok) {
|
|
270
276
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
271
277
|
const err = (await res.json()) as { error?: string };
|
|
@@ -299,11 +305,17 @@ export function ProvidersPanel({
|
|
|
299
305
|
anthropicBaseUrl: data.format === "anthropic" ? data.baseUrl : undefined,
|
|
300
306
|
openaiBaseUrl: data.format === "openai" ? data.baseUrl : undefined,
|
|
301
307
|
};
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
308
|
+
let res: Response;
|
|
309
|
+
try {
|
|
310
|
+
res = await fetch(`/api/providers/${editingProvider.id}`, {
|
|
311
|
+
method: "PUT",
|
|
312
|
+
headers: { "Content-Type": "application/json" },
|
|
313
|
+
body: JSON.stringify(payload),
|
|
314
|
+
});
|
|
315
|
+
} catch (err) {
|
|
316
|
+
setError("Network error: could not reach the server. Is the proxy running?");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
307
319
|
if (!res.ok) {
|
|
308
320
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
309
321
|
const err = (await res.json()) as { error?: string };
|
|
@@ -323,9 +335,15 @@ export function ProvidersPanel({
|
|
|
323
335
|
// eslint-disable-next-line no-alert
|
|
324
336
|
if (!window.confirm("Are you sure you want to delete this provider?")) return;
|
|
325
337
|
void (async () => {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
338
|
+
let res: Response;
|
|
339
|
+
try {
|
|
340
|
+
res = await fetch(`/api/providers/${providerId}`, {
|
|
341
|
+
method: "DELETE",
|
|
342
|
+
});
|
|
343
|
+
} catch (err) {
|
|
344
|
+
setError("Network error: could not reach the server. Is the proxy running?");
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
329
347
|
if (!res.ok) {
|
|
330
348
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
331
349
|
const err = (await res.json()) as { error?: string };
|
|
@@ -41,7 +41,11 @@ function parseResponse(
|
|
|
41
41
|
apiFormat: "anthropic" | "openai" | "unknown" | undefined,
|
|
42
42
|
): InspectorResponse | OpenAIResponse | null {
|
|
43
43
|
try {
|
|
44
|
-
|
|
44
|
+
let json: unknown = JSON.parse(text);
|
|
45
|
+
// Handle double-encoded JSON (some providers send response body as JSON-encoded string)
|
|
46
|
+
if (typeof json === "string") {
|
|
47
|
+
json = JSON.parse(json);
|
|
48
|
+
}
|
|
45
49
|
if (apiFormat === "openai") {
|
|
46
50
|
const result = parseOpenAIResponse(text);
|
|
47
51
|
if (result) return result;
|
|
@@ -163,6 +163,7 @@ export function ResponseContentBlockRenderer({
|
|
|
163
163
|
case "text":
|
|
164
164
|
return <TextBlock text={block.text} />;
|
|
165
165
|
case "thinking":
|
|
166
|
+
case "think":
|
|
166
167
|
return <ThinkingBlock thinking={block.thinking} />;
|
|
167
168
|
case "tool_use":
|
|
168
169
|
return <ToolUseBlock name={block.name} input={block.input} />;
|
|
@@ -19,6 +19,12 @@ const ThinkingContentBlock = z.object({
|
|
|
19
19
|
signature: z.string().optional(),
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
const ThinkContentBlock = z.object({
|
|
23
|
+
type: z.literal("think"),
|
|
24
|
+
thinking: z.string(),
|
|
25
|
+
signature: z.string().optional(),
|
|
26
|
+
});
|
|
27
|
+
|
|
22
28
|
const ImageSourceBlock = z.object({
|
|
23
29
|
type: z.literal("base64"),
|
|
24
30
|
media_type: z.string(),
|
|
@@ -107,6 +113,7 @@ export const AnthropicRequestSchema = z.object({
|
|
|
107
113
|
const ResponseContentBlock = z.discriminatedUnion("type", [
|
|
108
114
|
TextContentBlock,
|
|
109
115
|
ThinkingContentBlock,
|
|
116
|
+
ThinkContentBlock,
|
|
110
117
|
ToolUseContentBlock,
|
|
111
118
|
]);
|
|
112
119
|
|
|
@@ -127,7 +134,7 @@ export const AnthropicResponseSchema = z
|
|
|
127
134
|
role: z.literal("assistant"),
|
|
128
135
|
content: z.array(ResponseContentBlock),
|
|
129
136
|
stop_reason: z.string().nullable(),
|
|
130
|
-
stop_sequence: z.string().nullable(),
|
|
137
|
+
stop_sequence: z.string().nullable().optional(),
|
|
131
138
|
usage: ResponseUsageSchema,
|
|
132
139
|
})
|
|
133
140
|
.passthrough(); // Allow extra unknown fields
|
|
@@ -4,8 +4,9 @@ import { SseEventSchema } from "./schemas";
|
|
|
4
4
|
|
|
5
5
|
type StreamTextBlock = { type: "text"; text: string };
|
|
6
6
|
type StreamThinkingBlock = { type: "thinking"; thinking: string; signature: string };
|
|
7
|
+
type StreamThinkBlock = { type: "think"; thinking: string; signature: string };
|
|
7
8
|
type StreamToolUseBlock = { type: "tool_use"; id: string; name: string; inputJson: string };
|
|
8
|
-
type StreamBlock = StreamTextBlock | StreamThinkingBlock | StreamToolUseBlock;
|
|
9
|
+
type StreamBlock = StreamTextBlock | StreamThinkingBlock | StreamThinkBlock | StreamToolUseBlock;
|
|
9
10
|
|
|
10
11
|
function parseInputJson(json: string): Record<string, unknown> {
|
|
11
12
|
if (json === "") return {};
|
|
@@ -29,6 +30,11 @@ function finalizeBlock(block: StreamBlock): Record<string, unknown> {
|
|
|
29
30
|
if (block.signature !== "") out.signature = block.signature;
|
|
30
31
|
return out;
|
|
31
32
|
}
|
|
33
|
+
case "think": {
|
|
34
|
+
const out: Record<string, unknown> = { type: "think", thinking: block.thinking };
|
|
35
|
+
if (block.signature !== "") out.signature = block.signature;
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
32
38
|
case "tool_use":
|
|
33
39
|
return {
|
|
34
40
|
type: "tool_use",
|
|
@@ -98,21 +104,32 @@ export function extractAnthropicStream(
|
|
|
98
104
|
break;
|
|
99
105
|
case "content_block_start": {
|
|
100
106
|
const cb = data.content_block;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
107
|
+
switch (cb.type) {
|
|
108
|
+
case "text":
|
|
109
|
+
blocks.set(data.index, { type: "text", text: cb.text ?? "" });
|
|
110
|
+
break;
|
|
111
|
+
case "thinking":
|
|
112
|
+
blocks.set(data.index, {
|
|
113
|
+
type: "thinking",
|
|
114
|
+
thinking: cb.thinking ?? "",
|
|
115
|
+
signature: cb.signature ?? "",
|
|
116
|
+
});
|
|
117
|
+
break;
|
|
118
|
+
case "think":
|
|
119
|
+
blocks.set(data.index, {
|
|
120
|
+
type: "think",
|
|
121
|
+
thinking: cb.thinking ?? "",
|
|
122
|
+
signature: cb.signature ?? "",
|
|
123
|
+
});
|
|
124
|
+
break;
|
|
125
|
+
case "tool_use":
|
|
126
|
+
blocks.set(data.index, {
|
|
127
|
+
type: "tool_use",
|
|
128
|
+
id: cb.id,
|
|
129
|
+
name: cb.name,
|
|
130
|
+
inputJson: "",
|
|
131
|
+
});
|
|
132
|
+
break;
|
|
116
133
|
}
|
|
117
134
|
break;
|
|
118
135
|
}
|
|
@@ -122,9 +139,15 @@ export function extractAnthropicStream(
|
|
|
122
139
|
const delta = data.delta;
|
|
123
140
|
if (delta.type === "text_delta" && block.type === "text") {
|
|
124
141
|
block.text += delta.text;
|
|
125
|
-
} else if (
|
|
142
|
+
} else if (
|
|
143
|
+
delta.type === "thinking_delta" &&
|
|
144
|
+
(block.type === "thinking" || block.type === "think")
|
|
145
|
+
) {
|
|
126
146
|
block.thinking += delta.thinking;
|
|
127
|
-
} else if (
|
|
147
|
+
} else if (
|
|
148
|
+
delta.type === "signature_delta" &&
|
|
149
|
+
(block.type === "thinking" || block.type === "think")
|
|
150
|
+
) {
|
|
128
151
|
block.signature += delta.signature;
|
|
129
152
|
} else if (delta.type === "input_json_delta" && block.type === "tool_use") {
|
|
130
153
|
block.inputJson += delta.partial_json;
|
|
@@ -6,7 +6,8 @@ const ProviderInputSchema = z.object({
|
|
|
6
6
|
name: z.string().min(1, "Name is required"),
|
|
7
7
|
apiKey: z.string().min(1, "API key is required"),
|
|
8
8
|
format: z.enum(["anthropic", "openai"]),
|
|
9
|
-
|
|
9
|
+
anthropicBaseUrl: z.string().optional(),
|
|
10
|
+
openaiBaseUrl: z.string().optional(),
|
|
10
11
|
model: z.string().min(1, "Model is required"),
|
|
11
12
|
authHeader: z.enum(["bearer", "x-api-key"]).optional().default("bearer"),
|
|
12
13
|
apiDocsUrl: z.string().optional(),
|
|
@@ -27,7 +28,9 @@ export const Route = createFileRoute("/api/providers")({
|
|
|
27
28
|
parsed.data.name,
|
|
28
29
|
parsed.data.apiKey,
|
|
29
30
|
parsed.data.format,
|
|
30
|
-
parsed.data.
|
|
31
|
+
parsed.data.format === "anthropic"
|
|
32
|
+
? parsed.data.anthropicBaseUrl
|
|
33
|
+
: parsed.data.openaiBaseUrl,
|
|
31
34
|
parsed.data.model,
|
|
32
35
|
parsed.data.authHeader,
|
|
33
36
|
parsed.data.apiDocsUrl,
|