@tonyclaw/agent-inspector 2.0.21 → 2.0.23
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 +10 -0
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-ztKMd-FE.js → CompareDrawer-DnYQtd8R.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-BTYGkg36.js +115 -0
- package/.output/public/assets/{ReplayDialog-RNhfLSsW.js → ReplayDialog-B-3V95xT.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-fsUI5HhH.js → RequestAnatomy-CT8hLGLa.js} +1 -1
- package/.output/public/assets/{ResponseView-B3YTDBBX.js → ResponseView-DK3CYom0.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-CbGqQ0mO.js → StreamingChunkSequence-D3jJutjp.js} +1 -1
- package/.output/public/assets/_sessionId-DpdfAzbo.js +1 -0
- package/.output/public/assets/index-780zTVwp.css +1 -0
- package/.output/public/assets/index-BpJNbm9G.js +1 -0
- package/.output/public/assets/{main-lTQKpxiU.js → main-hF_572U6.js} +2 -2
- package/.output/server/_libs/lucide-react.mjs +27 -27
- package/.output/server/{_sessionId-DsF6LFJG.mjs → _sessionId-BqhNE2M8.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-DgdZcMpg.mjs → CompareDrawer-C4LQW4S1.mjs} +3 -3
- package/.output/server/_ssr/{ProxyViewerContainer-DaFW1IVu.mjs → ProxyViewerContainer-BKInvawk.mjs} +214 -41
- package/.output/server/_ssr/{ReplayDialog-BOaTX1ir.mjs → ReplayDialog-C3ZiRihL.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-C-2_dejd.mjs → RequestAnatomy-DlVAPIQZ.mjs} +3 -3
- package/.output/server/_ssr/{ResponseView-BtRVhgzy.mjs → ResponseView-nMS0rkxu.mjs} +3 -3
- package/.output/server/_ssr/{StreamingChunkSequence-DZaerowX.mjs → StreamingChunkSequence-PDWqrNiO.mjs} +3 -3
- package/.output/server/_ssr/{index-B3_fgwFy.mjs → index-Cd1zD-lo.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-CDOnHAWy.mjs → router-R9gm7_sh.mjs} +394 -151
- package/.output/server/{_tanstack-start-manifest_v-Brrx1NEa.mjs → _tanstack-start-manifest_v-BnLVH_EX.mjs} +1 -1
- package/.output/server/index.mjs +60 -60
- package/package.json +1 -1
- package/src/cli/templates/codex-skill-onboard.ts +5 -0
- package/src/cli/templates/skill-onboard.ts +5 -0
- package/src/components/OnboardingBanner.tsx +4 -0
- package/src/components/ProxyViewer.tsx +5 -0
- package/src/components/providers/ProviderCard.tsx +178 -38
- package/src/components/providers/ProvidersPanel.tsx +21 -3
- package/src/components/providers/SettingsDialog.tsx +76 -2
- package/src/lib/providerTestContract.ts +13 -0
- package/src/lib/runtimeConfig.ts +8 -0
- package/src/lib/useOnboarding.ts +3 -0
- package/src/lib/useStripConfig.ts +22 -0
- package/src/proxy/config.ts +4 -0
- package/src/proxy/store.ts +198 -135
- package/src/routes/api/config.ts +7 -0
- package/src/routes/api/logs.stream.ts +1 -1
- package/src/routes/api/providers.$providerId.test.log.ts +28 -12
- package/.output/public/assets/ProxyViewerContainer-BT8Ilsbs.js +0 -114
- package/.output/public/assets/_sessionId-C9cpyfLX.js +0 -1
- package/.output/public/assets/index-0mTTpvA2.js +0 -1
- package/.output/public/assets/index-DynnYt7S.css +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/session/$sessionId", "/api/knowledge/candidates", "/api/knowledge/project-context", "/api/knowledge/search", "/api/knowledge/sessions/$sessionId/candidates"], "preloads": ["/assets/main-
|
|
1
|
+
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/session/$sessionId", "/api/knowledge/candidates", "/api/knowledge/project-context", "/api/knowledge/search", "/api/knowledge/sessions/$sessionId/candidates"], "preloads": ["/assets/main-hF_572U6.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-BpJNbm9G.js", "/assets/ProxyViewerContainer-BTYGkg36.js"] }, "/api/config": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/config.ts", "children": ["/api/config/paths"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/mcp": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/mcp.ts" }, "/api/models": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId", "/api/providers/export", "/api/providers/import", "/api/providers/scan"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/proxy/$.ts" }, "/session/$sessionId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/session/$sessionId.tsx", "assets": [], "preloads": ["/assets/_sessionId-DpdfAzbo.js", "/assets/ProxyViewerContainer-BTYGkg36.js"] }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/config.paths.ts" }, "/api/knowledge/candidates": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.ts", "children": ["/api/knowledge/candidates/$candidateId"] }, "/api/knowledge/project-context": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.project-context.ts" }, "/api/knowledge/search": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.search.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/model-metadata", "/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.import.ts" }, "/api/providers/scan": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.scan.ts" }, "/api/knowledge/candidates/$candidateId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.$candidateId.ts", "children": ["/api/knowledge/candidates/$candidateId/promote"] }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/model-metadata": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.model-metadata.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.test.ts", "children": ["/api/providers/$providerId/test/log"] }, "/api/knowledge/candidates/$candidateId/promote": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.$candidateId.promote.ts" }, "/api/knowledge/sessions/$sessionId/candidates": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.sessions.$sessionId.candidates.ts" }, "/api/providers/$providerId/test/log": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.test.log.ts" } }, "clientEntry": "/assets/main-hF_572U6.js" });
|
|
2
2
|
export {
|
|
3
3
|
tsrStartManifest
|
|
4
4
|
};
|
package/.output/server/index.mjs
CHANGED
|
@@ -38,100 +38,100 @@ 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-29T10:57:03.958Z",
|
|
42
42
|
"size": 5915,
|
|
43
43
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
44
44
|
},
|
|
45
|
-
"/assets/CompareDrawer-
|
|
45
|
+
"/assets/CompareDrawer-DnYQtd8R.js": {
|
|
46
46
|
"type": "text/javascript; charset=utf-8",
|
|
47
|
-
"etag": '"49fe-
|
|
48
|
-
"mtime": "2026-06-
|
|
47
|
+
"etag": '"49fe-b7mmBTYljsLKWenrZlAtgJH1LOY"',
|
|
48
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
49
49
|
"size": 18942,
|
|
50
|
-
"path": "../public/assets/CompareDrawer-
|
|
50
|
+
"path": "../public/assets/CompareDrawer-DnYQtd8R.js"
|
|
51
51
|
},
|
|
52
|
-
"/assets/index-
|
|
52
|
+
"/assets/index-BpJNbm9G.js": {
|
|
53
53
|
"type": "text/javascript; charset=utf-8",
|
|
54
|
-
"etag": '"74-
|
|
55
|
-
"mtime": "2026-06-
|
|
54
|
+
"etag": '"74-5ny3SIFXNJjz8mYDJPqwGLMogII"',
|
|
55
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
56
56
|
"size": 116,
|
|
57
|
-
"path": "../public/assets/index-
|
|
57
|
+
"path": "../public/assets/index-BpJNbm9G.js"
|
|
58
|
+
},
|
|
59
|
+
"/assets/index-780zTVwp.css": {
|
|
60
|
+
"type": "text/css; charset=utf-8",
|
|
61
|
+
"etag": '"1a380-Lz+Shs13XyKSlh9PTaGE50w/BpU"',
|
|
62
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
63
|
+
"size": 107392,
|
|
64
|
+
"path": "../public/assets/index-780zTVwp.css"
|
|
58
65
|
},
|
|
59
66
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
60
67
|
"type": "image/jpeg",
|
|
61
68
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
62
|
-
"mtime": "2026-06-
|
|
69
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
63
70
|
"size": 6918,
|
|
64
71
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
65
72
|
},
|
|
66
|
-
"/assets/
|
|
73
|
+
"/assets/ReplayDialog-B-3V95xT.js": {
|
|
67
74
|
"type": "text/javascript; charset=utf-8",
|
|
68
|
-
"etag": '"
|
|
69
|
-
"mtime": "2026-06-
|
|
70
|
-
"size":
|
|
71
|
-
"path": "../public/assets/
|
|
72
|
-
},
|
|
73
|
-
"/assets/index-DynnYt7S.css": {
|
|
74
|
-
"type": "text/css; charset=utf-8",
|
|
75
|
-
"etag": '"1a2ef-ePBi5QJ1gmSGrdAGsfnIQPhloY0"',
|
|
76
|
-
"mtime": "2026-06-29T08:00:45.251Z",
|
|
77
|
-
"size": 107247,
|
|
78
|
-
"path": "../public/assets/index-DynnYt7S.css"
|
|
75
|
+
"etag": '"318c-1NLootFaQs7KDJvmrRBmp0zrGoY"',
|
|
76
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
77
|
+
"size": 12684,
|
|
78
|
+
"path": "../public/assets/ReplayDialog-B-3V95xT.js"
|
|
79
79
|
},
|
|
80
|
-
"/assets/
|
|
81
|
-
"type": "
|
|
82
|
-
"etag": '"
|
|
83
|
-
"mtime": "2026-06-
|
|
84
|
-
"size":
|
|
85
|
-
"path": "../public/assets/
|
|
80
|
+
"/assets/main-hF_572U6.js": {
|
|
81
|
+
"type": "text/javascript; charset=utf-8",
|
|
82
|
+
"etag": '"51726-eooZ68MhIVAdbT2A97BnHJuW5lM"',
|
|
83
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
84
|
+
"size": 333606,
|
|
85
|
+
"path": "../public/assets/main-hF_572U6.js"
|
|
86
86
|
},
|
|
87
|
-
"/assets/
|
|
87
|
+
"/assets/ResponseView-DK3CYom0.js": {
|
|
88
88
|
"type": "text/javascript; charset=utf-8",
|
|
89
|
-
"etag": '"
|
|
90
|
-
"mtime": "2026-06-
|
|
91
|
-
"size":
|
|
92
|
-
"path": "../public/assets/
|
|
89
|
+
"etag": '"30d0-Cy0g09LS9VDwp/DlETvauFmcBFs"',
|
|
90
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
91
|
+
"size": 12496,
|
|
92
|
+
"path": "../public/assets/ResponseView-DK3CYom0.js"
|
|
93
93
|
},
|
|
94
|
-
"/assets/RequestAnatomy-
|
|
94
|
+
"/assets/RequestAnatomy-CT8hLGLa.js": {
|
|
95
95
|
"type": "text/javascript; charset=utf-8",
|
|
96
|
-
"etag": '"4485-
|
|
97
|
-
"mtime": "2026-06-
|
|
96
|
+
"etag": '"4485-oTcemFMGh2ben0T+njg79IE1+H8"',
|
|
97
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
98
98
|
"size": 17541,
|
|
99
|
-
"path": "../public/assets/RequestAnatomy-
|
|
99
|
+
"path": "../public/assets/RequestAnatomy-CT8hLGLa.js"
|
|
100
100
|
},
|
|
101
|
-
"/assets/
|
|
101
|
+
"/assets/StreamingChunkSequence-D3jJutjp.js": {
|
|
102
102
|
"type": "text/javascript; charset=utf-8",
|
|
103
|
-
"etag": '"
|
|
104
|
-
"mtime": "2026-06-
|
|
105
|
-
"size":
|
|
106
|
-
"path": "../public/assets/
|
|
103
|
+
"etag": '"d57-SqKRwuSq9h9H7zwcDkj5Lqd+u/Y"',
|
|
104
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
105
|
+
"size": 3415,
|
|
106
|
+
"path": "../public/assets/StreamingChunkSequence-D3jJutjp.js"
|
|
107
107
|
},
|
|
108
|
-
"/assets/
|
|
108
|
+
"/assets/_sessionId-DpdfAzbo.js": {
|
|
109
109
|
"type": "text/javascript; charset=utf-8",
|
|
110
|
-
"etag": '"
|
|
111
|
-
"mtime": "2026-06-
|
|
112
|
-
"size":
|
|
113
|
-
"path": "../public/assets/
|
|
110
|
+
"etag": '"d2-tBmz0AuKXPVen+wNzq7oGvD4J44"',
|
|
111
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
112
|
+
"size": 210,
|
|
113
|
+
"path": "../public/assets/_sessionId-DpdfAzbo.js"
|
|
114
|
+
},
|
|
115
|
+
"/assets/qwen-CONDcHqt.png": {
|
|
116
|
+
"type": "image/png",
|
|
117
|
+
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
118
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
119
|
+
"size": 357059,
|
|
120
|
+
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
114
121
|
},
|
|
115
122
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
116
123
|
"type": "image/svg+xml",
|
|
117
124
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
118
|
-
"mtime": "2026-06-
|
|
125
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
119
126
|
"size": 11256,
|
|
120
127
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
121
128
|
},
|
|
122
|
-
"/assets/
|
|
123
|
-
"type": "text/javascript; charset=utf-8",
|
|
124
|
-
"etag": '"d2-0De45/nv3c5PzjfK4qWI19CPHKY"',
|
|
125
|
-
"mtime": "2026-06-29T08:00:45.251Z",
|
|
126
|
-
"size": 210,
|
|
127
|
-
"path": "../public/assets/_sessionId-C9cpyfLX.js"
|
|
128
|
-
},
|
|
129
|
-
"/assets/ProxyViewerContainer-BT8Ilsbs.js": {
|
|
129
|
+
"/assets/ProxyViewerContainer-BTYGkg36.js": {
|
|
130
130
|
"type": "text/javascript; charset=utf-8",
|
|
131
|
-
"etag": '"
|
|
132
|
-
"mtime": "2026-06-
|
|
133
|
-
"size":
|
|
134
|
-
"path": "../public/assets/ProxyViewerContainer-
|
|
131
|
+
"etag": '"adfba-Leh4MRDOCIBADBcckDDDPe8s/NM"',
|
|
132
|
+
"mtime": "2026-06-29T10:57:03.958Z",
|
|
133
|
+
"size": 712634,
|
|
134
|
+
"path": "../public/assets/ProxyViewerContainer-BTYGkg36.js"
|
|
135
135
|
}
|
|
136
136
|
};
|
|
137
137
|
function readAsset(id) {
|
package/package.json
CHANGED
|
@@ -193,6 +193,11 @@ http://localhost:${port}/proxy
|
|
|
193
193
|
|
|
194
194
|
For Anthropic-compatible tools, set \`ANTHROPIC_BASE_URL=http://localhost:${port}/proxy\`. For OpenAI-compatible tools, set \`OPENAI_BASE_URL=http://localhost:${port}/proxy\`.
|
|
195
195
|
|
|
196
|
+
If Codex or another AI tool runs in a different container, VM, WSL distro, or host than Agent
|
|
197
|
+
Inspector, \`localhost\` points at the tool's own environment. Replace \`localhost\` with an Inspector
|
|
198
|
+
address reachable from that environment, then verify the network/firewall path before debugging
|
|
199
|
+
provider credentials.
|
|
200
|
+
|
|
196
201
|
For a Provider Test memory probe, run a provider test in the Agent Inspector UI:
|
|
197
202
|
|
|
198
203
|
1. Open \`http://localhost:${port}\`.
|
|
@@ -422,6 +422,11 @@ mimo
|
|
|
422
422
|
# Cursor / Cody — set the OpenAI base URL in each tool's settings panel to http://localhost:${port}/proxy
|
|
423
423
|
\`\`\`
|
|
424
424
|
|
|
425
|
+
**Container/network note:** If the AI tool runs in a different container, VM, WSL distro, or host
|
|
426
|
+
than Agent Inspector, \`localhost\` points at the tool's own environment. Replace \`localhost\` with
|
|
427
|
+
an Inspector address reachable from that environment, then verify the network/firewall path before
|
|
428
|
+
debugging provider credentials.
|
|
429
|
+
|
|
425
430
|
For a tool that wasn't auto-detected, fall through to the generic curl test in the next phase — the user can wire their tool later.
|
|
426
431
|
|
|
427
432
|
> **PAUSE** — use \`AskUserQuestion\` with header \`Tool wired?\` and options \`["Yes, env var is set, claude is running", "No, I'm going to use the curl test instead"]\`. Wait for the answer.
|
|
@@ -59,6 +59,10 @@ export function OnboardingBanner(): JSX.Element | null {
|
|
|
59
59
|
use <code>/agent-inspector:onboard</code> in Claude Code or ask Codex to use{" "}
|
|
60
60
|
<code>agent-inspector-onboard</code>.
|
|
61
61
|
</li>
|
|
62
|
+
<li>
|
|
63
|
+
<strong>Container networking</strong>: if the AI tool runs outside this Inspector
|
|
64
|
+
container or host, replace <code>localhost</code> with a reachable address.
|
|
65
|
+
</li>
|
|
62
66
|
</ol>
|
|
63
67
|
</div>
|
|
64
68
|
<button
|
|
@@ -944,6 +944,11 @@ export function ProxyViewer({
|
|
|
944
944
|
<CopyableCommand command="ANTHROPIC_BASE_URL=http://localhost:25947/proxy <your-tool>" />
|
|
945
945
|
<CopyableCommand command="OPENAI_BASE_URL=http://localhost:25947/proxy <your-tool>" />
|
|
946
946
|
</div>
|
|
947
|
+
<p className="mx-auto max-w-xl text-xs leading-relaxed text-muted-foreground">
|
|
948
|
+
Container note: if your AI tool runs in a different container or host than Agent
|
|
949
|
+
Inspector, replace localhost with an address reachable from that tool and verify the
|
|
950
|
+
network/firewall path.
|
|
951
|
+
</p>
|
|
947
952
|
</div>
|
|
948
953
|
)
|
|
949
954
|
) : (
|
|
@@ -20,6 +20,8 @@ import {
|
|
|
20
20
|
Clock,
|
|
21
21
|
Copy,
|
|
22
22
|
Check,
|
|
23
|
+
ChevronDown,
|
|
24
|
+
ChevronRight,
|
|
23
25
|
} from "lucide-react";
|
|
24
26
|
import type { ProviderConfig } from "../../proxy/providers";
|
|
25
27
|
import { maskApiKey } from "../../lib/mask";
|
|
@@ -62,6 +64,150 @@ function isNotConfiguredState(result: ProviderTestState): result is { notConfigu
|
|
|
62
64
|
return Object.prototype.hasOwnProperty.call(result, "notConfigured");
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
type ProviderFormatTestResults = TestResults["anthropic"];
|
|
68
|
+
|
|
69
|
+
function hasText(value: string | undefined): value is string {
|
|
70
|
+
return value !== undefined && value.trim() !== "";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function formatHeaders(headers: Record<string, string> | undefined): string | undefined {
|
|
74
|
+
if (headers === undefined) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const lines = Object.entries(headers).map(([name, value]) => `${name}: ${value}`);
|
|
79
|
+
if (lines.length === 0) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return lines.join("\n");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function hasHeaderDetails(headers: Record<string, string> | undefined): boolean {
|
|
87
|
+
return formatHeaders(headers) !== undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function hasDiagnosticDetails(result: TestResult): boolean {
|
|
91
|
+
const debug = result.debug;
|
|
92
|
+
return (
|
|
93
|
+
hasText(result.error?.hint) ||
|
|
94
|
+
hasText(result.error?.details) ||
|
|
95
|
+
hasText(result.rawResponse) ||
|
|
96
|
+
hasText(debug?.requestUrl) ||
|
|
97
|
+
hasText(debug?.requestBody) ||
|
|
98
|
+
hasText(debug?.responseBody) ||
|
|
99
|
+
hasHeaderDetails(debug?.requestHeaders) ||
|
|
100
|
+
hasHeaderDetails(debug?.responseHeaders) ||
|
|
101
|
+
debug?.responseStatus !== undefined
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function DiagnosticSection({
|
|
106
|
+
title,
|
|
107
|
+
children,
|
|
108
|
+
}: {
|
|
109
|
+
title: string;
|
|
110
|
+
children: ReactNode;
|
|
111
|
+
}): JSX.Element {
|
|
112
|
+
return (
|
|
113
|
+
<div className="space-y-1">
|
|
114
|
+
<div className="font-medium text-foreground/80">{title}</div>
|
|
115
|
+
{children}
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function DiagnosticPre({ value }: { value: string }): JSX.Element {
|
|
121
|
+
return (
|
|
122
|
+
<pre className="max-h-40 overflow-auto whitespace-pre-wrap break-all rounded-md bg-background/80 p-2 font-mono text-[11px] leading-relaxed text-foreground/80">
|
|
123
|
+
{value}
|
|
124
|
+
</pre>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function ProviderTestDetails({ result }: { result: TestResult }): JSX.Element {
|
|
129
|
+
const debug = result.debug;
|
|
130
|
+
const requestUrl = debug?.requestUrl;
|
|
131
|
+
const requestMethod = debug?.requestMethod ?? "POST";
|
|
132
|
+
const requestHeaders = formatHeaders(debug?.requestHeaders);
|
|
133
|
+
const responseHeaders = formatHeaders(debug?.responseHeaders);
|
|
134
|
+
const responseStatus =
|
|
135
|
+
debug?.responseStatus !== undefined
|
|
136
|
+
? `${debug.responseStatus}${
|
|
137
|
+
hasText(debug.responseStatusText) ? ` ${debug.responseStatusText}` : ""
|
|
138
|
+
}`
|
|
139
|
+
: undefined;
|
|
140
|
+
const responseBody = debug?.responseBody ?? result.rawResponse;
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<div className="max-h-80 max-w-full space-y-2 overflow-auto rounded-md border bg-muted/50 p-2 text-xs text-muted-foreground shadow-sm sm:w-[520px]">
|
|
144
|
+
{hasText(result.error?.hint) && (
|
|
145
|
+
<DiagnosticSection title="Hint">
|
|
146
|
+
<div>{result.error.hint}</div>
|
|
147
|
+
</DiagnosticSection>
|
|
148
|
+
)}
|
|
149
|
+
{hasText(result.error?.details) && (
|
|
150
|
+
<DiagnosticSection title="Error">
|
|
151
|
+
<DiagnosticPre value={result.error.details} />
|
|
152
|
+
</DiagnosticSection>
|
|
153
|
+
)}
|
|
154
|
+
{hasText(requestUrl) && (
|
|
155
|
+
<DiagnosticSection title="Request">
|
|
156
|
+
<div className="rounded-md bg-background/80 p-2 font-mono text-[11px] break-all text-foreground/80">
|
|
157
|
+
{requestMethod} {requestUrl}
|
|
158
|
+
</div>
|
|
159
|
+
</DiagnosticSection>
|
|
160
|
+
)}
|
|
161
|
+
{requestHeaders !== undefined && (
|
|
162
|
+
<DiagnosticSection title="Request Headers">
|
|
163
|
+
<DiagnosticPre value={requestHeaders} />
|
|
164
|
+
</DiagnosticSection>
|
|
165
|
+
)}
|
|
166
|
+
{hasText(debug?.requestBody) && (
|
|
167
|
+
<DiagnosticSection title="Request Body">
|
|
168
|
+
<DiagnosticPre value={debug.requestBody} />
|
|
169
|
+
</DiagnosticSection>
|
|
170
|
+
)}
|
|
171
|
+
{hasText(responseStatus) && (
|
|
172
|
+
<DiagnosticSection title="Response Status">
|
|
173
|
+
<div className="rounded-md bg-background/80 p-2 font-mono text-[11px] text-foreground/80">
|
|
174
|
+
{responseStatus}
|
|
175
|
+
</div>
|
|
176
|
+
</DiagnosticSection>
|
|
177
|
+
)}
|
|
178
|
+
{responseHeaders !== undefined && (
|
|
179
|
+
<DiagnosticSection title="Response Headers">
|
|
180
|
+
<DiagnosticPre value={responseHeaders} />
|
|
181
|
+
</DiagnosticSection>
|
|
182
|
+
)}
|
|
183
|
+
{hasText(responseBody) && (
|
|
184
|
+
<DiagnosticSection title="Response Body">
|
|
185
|
+
<DiagnosticPre value={responseBody} />
|
|
186
|
+
</DiagnosticSection>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function ProviderFormatTestStatus({
|
|
193
|
+
results,
|
|
194
|
+
}: {
|
|
195
|
+
results: ProviderFormatTestResults;
|
|
196
|
+
}): JSX.Element {
|
|
197
|
+
return (
|
|
198
|
+
<div className="flex min-w-0 flex-col gap-2">
|
|
199
|
+
<div className="flex min-w-0 flex-col gap-1">
|
|
200
|
+
<span className="text-[10px] text-muted-foreground">Non-stream</span>
|
|
201
|
+
<TestStatus result={results.nonStreaming} />
|
|
202
|
+
</div>
|
|
203
|
+
<div className="flex min-w-0 flex-col gap-1">
|
|
204
|
+
<span className="text-[10px] text-muted-foreground">Stream</span>
|
|
205
|
+
<TestStatus result={results.streaming} />
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
65
211
|
function getErrorIcon(type: ErrorType): JSX.Element {
|
|
66
212
|
const iconProps = { className: "size-3", strokeWidth: 2 };
|
|
67
213
|
switch (type) {
|
|
@@ -154,9 +300,8 @@ function TestStatus({ result }: { result: ProviderTestState }): JSX.Element {
|
|
|
154
300
|
|
|
155
301
|
const error = result.error;
|
|
156
302
|
const errorMessage = error?.message ?? "Connection failed";
|
|
157
|
-
const errorHint = error?.hint;
|
|
158
|
-
const errorDetails = error?.details;
|
|
159
303
|
const errorType = error?.type ?? "unknown";
|
|
304
|
+
const hasDetails = hasDiagnosticDetails(result);
|
|
160
305
|
|
|
161
306
|
return (
|
|
162
307
|
<div className="flex flex-col gap-1 shrink-0">
|
|
@@ -170,33 +315,22 @@ function TestStatus({ result }: { result: ProviderTestState }): JSX.Element {
|
|
|
170
315
|
<TooltipContent>Connection test failed</TooltipContent>
|
|
171
316
|
</Tooltip>
|
|
172
317
|
</TooltipProvider>
|
|
173
|
-
{
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
{showDetails ? "Hide error details" : "Show detailed error information"}
|
|
187
|
-
</TooltipContent>
|
|
188
|
-
</Tooltip>
|
|
189
|
-
</TooltipProvider>
|
|
318
|
+
{hasDetails && (
|
|
319
|
+
<button
|
|
320
|
+
type="button"
|
|
321
|
+
onClick={() => setShowDetails((value) => !value)}
|
|
322
|
+
aria-expanded={showDetails}
|
|
323
|
+
aria-label={
|
|
324
|
+
showDetails ? "Hide provider test diagnostics" : "Show provider test diagnostics"
|
|
325
|
+
}
|
|
326
|
+
className="inline-flex h-5 shrink-0 items-center gap-1 rounded border border-border/70 bg-background/70 px-1.5 text-[10px] text-muted-foreground transition-colors hover:text-foreground"
|
|
327
|
+
>
|
|
328
|
+
{showDetails ? <EyeOff className="size-3" /> : <Eye className="size-3" />}
|
|
329
|
+
<span>{showDetails ? "Hide" : "Details"}</span>
|
|
330
|
+
</button>
|
|
190
331
|
)}
|
|
191
332
|
</div>
|
|
192
|
-
{showDetails &&
|
|
193
|
-
<div className="text-xs text-muted-foreground bg-muted/50 rounded p-2 max-w-[300px]">
|
|
194
|
-
{errorHint !== undefined && <div className="mb-1">{errorHint}</div>}
|
|
195
|
-
<div className="font-mono whitespace-pre-wrap break-all text-red-400/80">
|
|
196
|
-
{errorDetails}
|
|
197
|
-
</div>
|
|
198
|
-
</div>
|
|
199
|
-
)}
|
|
333
|
+
{showDetails && hasDetails && <ProviderTestDetails result={result} />}
|
|
200
334
|
</div>
|
|
201
335
|
);
|
|
202
336
|
}
|
|
@@ -411,22 +545,24 @@ export function ProviderCard({
|
|
|
411
545
|
</div>
|
|
412
546
|
|
|
413
547
|
{provider.anthropicBaseUrl !== undefined && provider.anthropicBaseUrl !== "" && (
|
|
414
|
-
<div className="flex
|
|
415
|
-
<div className="text-xs text-muted-foreground
|
|
548
|
+
<div className="flex min-w-0 flex-col gap-2">
|
|
549
|
+
<div className="min-w-0 text-xs text-muted-foreground">
|
|
416
550
|
<span className="font-medium">Anthropic:</span>{" "}
|
|
417
551
|
<span className="truncate">{provider.anthropicBaseUrl}</span>
|
|
418
552
|
</div>
|
|
419
|
-
{testResults
|
|
553
|
+
{testResults !== undefined && (
|
|
554
|
+
<ProviderFormatTestStatus results={testResults.anthropic} />
|
|
555
|
+
)}
|
|
420
556
|
</div>
|
|
421
557
|
)}
|
|
422
558
|
|
|
423
559
|
{provider.openaiBaseUrl !== undefined && provider.openaiBaseUrl !== "" && (
|
|
424
|
-
<div className="flex
|
|
425
|
-
<div className="text-xs text-muted-foreground
|
|
560
|
+
<div className="flex min-w-0 flex-col gap-2">
|
|
561
|
+
<div className="min-w-0 text-xs text-muted-foreground">
|
|
426
562
|
<span className="font-medium">OpenAI:</span>{" "}
|
|
427
563
|
<span className="truncate">{provider.openaiBaseUrl}</span>
|
|
428
564
|
</div>
|
|
429
|
-
{testResults && <
|
|
565
|
+
{testResults !== undefined && <ProviderFormatTestStatus results={testResults.openai} />}
|
|
430
566
|
</div>
|
|
431
567
|
)}
|
|
432
568
|
|
|
@@ -443,7 +579,11 @@ export function ProviderCard({
|
|
|
443
579
|
onClick={() => setShowModelResults((value) => !value)}
|
|
444
580
|
className="text-xs text-muted-foreground hover:text-foreground transition-colors flex items-center gap-1"
|
|
445
581
|
>
|
|
446
|
-
|
|
582
|
+
{showModelResults ? (
|
|
583
|
+
<ChevronDown className="size-3" />
|
|
584
|
+
) : (
|
|
585
|
+
<ChevronRight className="size-3" />
|
|
586
|
+
)}
|
|
447
587
|
Model Test Results ({Object.keys(testResults.models).length})
|
|
448
588
|
</button>
|
|
449
589
|
{showModelResults && (
|
|
@@ -471,13 +611,13 @@ export function ProviderCard({
|
|
|
471
611
|
<td className="py-1 px-2 font-medium">{modelName}</td>
|
|
472
612
|
{provider.anthropicBaseUrl !== undefined &&
|
|
473
613
|
provider.anthropicBaseUrl !== "" && (
|
|
474
|
-
<td className="py-1 px-2">
|
|
475
|
-
<
|
|
614
|
+
<td className="py-1 px-2 align-top">
|
|
615
|
+
<ProviderFormatTestStatus results={modelResult.anthropic} />
|
|
476
616
|
</td>
|
|
477
617
|
)}
|
|
478
618
|
{provider.openaiBaseUrl !== undefined && provider.openaiBaseUrl !== "" && (
|
|
479
|
-
<td className="py-1 px-2">
|
|
480
|
-
<
|
|
619
|
+
<td className="py-1 px-2 align-top">
|
|
620
|
+
<ProviderFormatTestStatus results={modelResult.openai} />
|
|
481
621
|
</td>
|
|
482
622
|
)}
|
|
483
623
|
</tr>
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
ProviderTestResultsSchema,
|
|
20
20
|
type ProviderTestResults as TestResults,
|
|
21
21
|
} from "../../lib/providerTestContract";
|
|
22
|
+
import { useStripConfig } from "../../lib/useStripConfig";
|
|
22
23
|
|
|
23
24
|
export type { ProviderTestResults as TestResults } from "../../lib/providerTestContract";
|
|
24
25
|
|
|
@@ -41,7 +42,6 @@ const ModelMetadataRefreshResponseSchema = z.object({
|
|
|
41
42
|
sourceUrl: z.string(),
|
|
42
43
|
});
|
|
43
44
|
|
|
44
|
-
const TEST_TIMEOUT_SECONDS = 30;
|
|
45
45
|
const NETWORK_ERROR_MESSAGE = "Network error: could not reach the server. Is the proxy running?";
|
|
46
46
|
|
|
47
47
|
type ProviderFormData = {
|
|
@@ -70,6 +70,15 @@ function createProviderPayload(data: ProviderFormData) {
|
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
function getProviderTestTimeoutSeconds(
|
|
74
|
+
provider: ProviderConfig | undefined,
|
|
75
|
+
timeoutSecondsPerModel: number,
|
|
76
|
+
): number {
|
|
77
|
+
const modelCount =
|
|
78
|
+
provider?.models?.map((model) => model.trim()).filter((model) => model !== "").length ?? 0;
|
|
79
|
+
return Math.max(1, modelCount) * timeoutSecondsPerModel;
|
|
80
|
+
}
|
|
81
|
+
|
|
73
82
|
async function persistProviderTestLog(providerId: string, results: TestResults): Promise<void> {
|
|
74
83
|
if (results.models === undefined) {
|
|
75
84
|
return;
|
|
@@ -126,6 +135,7 @@ export function ProvidersPanel({
|
|
|
126
135
|
const [refreshingMetadataProviders, setRefreshingMetadataProviders] = useState<Set<string>>(
|
|
127
136
|
new Set(),
|
|
128
137
|
);
|
|
138
|
+
const { providerTestTimeoutSeconds } = useStripConfig();
|
|
129
139
|
const listScrollRef = useRef<HTMLDivElement>(null);
|
|
130
140
|
const highlightTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
131
141
|
|
|
@@ -239,9 +249,11 @@ export function ProvidersPanel({
|
|
|
239
249
|
|
|
240
250
|
// Create abort controller for this test request
|
|
241
251
|
const controller = new AbortController();
|
|
252
|
+
const provider = providers.find((candidate) => candidate.id === providerId);
|
|
253
|
+
const timeoutSeconds = getProviderTestTimeoutSeconds(provider, providerTestTimeoutSeconds);
|
|
242
254
|
|
|
243
255
|
// Start countdown
|
|
244
|
-
let remaining =
|
|
256
|
+
let remaining = timeoutSeconds;
|
|
245
257
|
setTestingTimeLeft(providerId, remaining);
|
|
246
258
|
const intervalId = setInterval(() => {
|
|
247
259
|
remaining--;
|
|
@@ -289,7 +301,13 @@ export function ProvidersPanel({
|
|
|
289
301
|
updateTestingState(providerId, false);
|
|
290
302
|
}
|
|
291
303
|
},
|
|
292
|
-
[
|
|
304
|
+
[
|
|
305
|
+
providerTestTimeoutSeconds,
|
|
306
|
+
providers,
|
|
307
|
+
setTestingTimeLeft,
|
|
308
|
+
updateTestResults,
|
|
309
|
+
updateTestingState,
|
|
310
|
+
],
|
|
293
311
|
);
|
|
294
312
|
|
|
295
313
|
const refreshProviderMetadata = useCallback(
|