@tonyclaw/agent-inspector 3.0.26 → 3.0.27
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 +80 -11
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-SZRUDQc9.js → CompareDrawer-BVCAAbbu.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-BJvwOrSi.js → ProxyViewerContainer-CYOXB81n.js} +200 -200
- package/.output/public/assets/{ReplayDialog-DgfmqiM3.js → ReplayDialog-DMX23O5G.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-CS6c7Qfn.js → RequestAnatomy-S17pYDRc.js} +1 -1
- package/.output/public/assets/{ResponseView-C0Ri_5gm.js → ResponseView-Cf1XrawD.js} +2 -2
- package/.output/public/assets/{StreamingChunkSequence-7dYcHWyZ.js → StreamingChunkSequence-BdOrVlCi.js} +1 -1
- package/.output/public/assets/{_sessionId-D-V84cgw.js → _sessionId-BnKGmJrR.js} +1 -1
- package/.output/public/assets/{index-DgFWCxOs.js → index-9fMLCU4d.js} +1 -1
- package/.output/public/assets/{index-CSIL7-MK.js → index-B1atk19i.js} +2 -2
- package/.output/public/assets/{index-DrVJsks2.js → index-gY3I-7-D.js} +1 -1
- package/.output/public/assets/{json-viewer-C9Ji3gYN.js → json-viewer-CpyYpPjx.js} +1 -1
- package/.output/server/_libs/lucide-react.mjs +6 -6
- package/.output/server/{_sessionId-BQ6YQOO1.mjs → _sessionId-eA_h2_s6.mjs} +4 -2
- package/.output/server/_ssr/{CompareDrawer-CqNzIeMR.mjs → CompareDrawer-K2k9G7r1.mjs} +5 -3
- package/.output/server/_ssr/{ProxyViewerContainer-CMC7Vsbw.mjs → ProxyViewerContainer-CbyBpCAj.mjs} +27 -60
- package/.output/server/_ssr/{ReplayDialog-D9p_LaTr.mjs → ReplayDialog-DacI2Iv0.mjs} +5 -3
- package/.output/server/_ssr/{RequestAnatomy-B4ge3qNZ.mjs → RequestAnatomy-gh-pAdkO.mjs} +4 -2
- package/.output/server/_ssr/{ResponseView-BCqMKApI.mjs → ResponseView-BRJKN50-.mjs} +5 -3
- package/.output/server/_ssr/{StreamingChunkSequence-BA4zTLE4.mjs → StreamingChunkSequence-BQLVEuWY.mjs} +4 -2
- package/.output/server/_ssr/{index-CzxhDjlq.mjs → index-DuSWrjbH.mjs} +4 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-B3qV6iEJ.mjs → json-viewer-DNs1ZjKI.mjs} +4 -2
- package/.output/server/_ssr/{router-CZe_R31M.mjs → router-Dgx6-ot3.mjs} +712 -217
- package/.output/server/{_tanstack-start-manifest_v-B50VTLrH.mjs → _tanstack-start-manifest_v-CoGjnkQD.mjs} +1 -1
- package/.output/server/index.mjs +64 -64
- package/README.md +8 -0
- package/package.json +4 -5
- package/src/cli.ts +43 -9
- package/src/components/providers/ProviderCard.tsx +3 -36
- package/src/components/providers/ProviderForm.tsx +13 -12
- package/src/components/providers/ProvidersPanel.tsx +2 -2
- package/src/components/providers/SettingsDialog.tsx +3 -3
- package/src/components/proxy-viewer/ProviderLogoStack.tsx +0 -3
- package/src/contracts/anthropic.ts +0 -5
- package/src/contracts/index.ts +0 -4
- package/src/contracts/log.ts +0 -1
- package/src/contracts/openai.ts +0 -3
- package/src/knowledge/openclawClient.ts +22 -9
- package/src/knowledge/openclawGatewayClient.ts +20 -13
- package/src/lib/alertContract.ts +0 -3
- package/src/lib/ecosystemContract.ts +0 -3
- package/src/lib/export-logs.ts +1 -4
- package/src/lib/safeFetch.ts +100 -0
- package/src/lib/ssrfGuard.ts +133 -0
- package/src/lib/stopReason.ts +1 -4
- package/src/lib/unknown.ts +27 -0
- package/src/lib/useProviders.ts +1 -1
- package/src/mcp/mode.ts +3 -9
- package/src/mcp/server.ts +5 -14
- package/src/mcp/toolHandlers.ts +45 -54
- package/src/proxy/constants.ts +17 -0
- package/src/proxy/formats/anthropic/handler.ts +5 -1
- package/src/proxy/formats/anthropic/schemas.ts +1 -7
- package/src/proxy/formats/index.ts +1 -1
- package/src/proxy/formats/openai/schemas.ts +0 -3
- package/src/proxy/formats/registry.ts +0 -3
- package/src/proxy/handler.ts +91 -12
- package/src/proxy/identityProxy.ts +74 -1
- package/src/proxy/logImporter.ts +82 -12
- package/src/proxy/logIndex.ts +1 -4
- package/src/proxy/providerSecretStore.ts +181 -0
- package/src/proxy/providers.ts +84 -11
- package/src/proxy/schemas.ts +1 -8
- package/src/proxy/sqliteLogIndex.ts +0 -16
- package/src/proxy/store.ts +1 -5
- package/src/proxy/toolSchemaWarnings.ts +1 -9
- package/src/routes/api/logs.$id.replay.ts +17 -5
- package/src/routes/api/providers.$providerId.model-metadata.ts +11 -1
- package/src/routes/api/providers.$providerId.ts +18 -5
- package/src/routes/api/providers.ts +18 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const tsrStartManifest = () => ({ routes: { __root__: { filePath: "C:/Users/claw/workspace/agent-inspector/src/routes/__root.tsx", children: ["/", "/api/alerts", "/api/config", "/api/groups", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/pi-agent", "/api/providers", "/api/runs", "/api/sessions", "/proxy/$", "/session/$sessionId", "/api/ecosystem/packages", "/api/ecosystem/tasks", "/api/knowledge/candidates", "/api/knowledge/project-context", "/api/knowledge/search", "/api/ecosystem/recipes/$recipeId/run", "/api/knowledge/sessions/$sessionId/candidates"], preloads: ["/assets/index-
|
|
1
|
+
const tsrStartManifest = () => ({ routes: { __root__: { filePath: "C:/Users/claw/workspace/agent-inspector/src/routes/__root.tsx", children: ["/", "/api/alerts", "/api/config", "/api/groups", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/pi-agent", "/api/providers", "/api/runs", "/api/sessions", "/proxy/$", "/session/$sessionId", "/api/ecosystem/packages", "/api/ecosystem/tasks", "/api/knowledge/candidates", "/api/knowledge/project-context", "/api/knowledge/search", "/api/ecosystem/recipes/$recipeId/run", "/api/knowledge/sessions/$sessionId/candidates"], preloads: ["/assets/index-B1atk19i.js"], scripts: [{ attrs: { type: "module", async: true, src: "/assets/index-B1atk19i.js" } }] }, "/": { filePath: "C:/Users/claw/workspace/agent-inspector/src/routes/index.tsx", children: void 0, preloads: ["/assets/index-gY3I-7-D.js", "/assets/ProxyViewerContainer-CYOXB81n.js"] }, "/session/$sessionId": { filePath: "C:/Users/claw/workspace/agent-inspector/src/routes/session/$sessionId.tsx", children: void 0, preloads: ["/assets/_sessionId-BnKGmJrR.js", "/assets/ProxyViewerContainer-CYOXB81n.js"] } } });
|
|
2
2
|
export {
|
|
3
3
|
tsrStartManifest
|
|
4
4
|
};
|
package/.output/server/index.mjs
CHANGED
|
@@ -20,121 +20,121 @@ const assets = {
|
|
|
20
20
|
"/assets/agent-inspector-58K1_MsC.ico": {
|
|
21
21
|
"type": "image/vnd.microsoft.icon",
|
|
22
22
|
"etag": '"38fa-ZD8kPABHYjPIkcH82FMY6iZM7fI"',
|
|
23
|
-
"mtime": "2026-07-
|
|
23
|
+
"mtime": "2026-07-11T04:43:38.031Z",
|
|
24
24
|
"size": 14586,
|
|
25
25
|
"path": "../public/assets/agent-inspector-58K1_MsC.ico"
|
|
26
26
|
},
|
|
27
27
|
"/assets/alibaba-TTwafVwX.svg": {
|
|
28
28
|
"type": "image/svg+xml",
|
|
29
29
|
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
30
|
-
"mtime": "2026-07-
|
|
30
|
+
"mtime": "2026-07-11T04:43:38.031Z",
|
|
31
31
|
"size": 5915,
|
|
32
32
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
33
33
|
},
|
|
34
|
-
"/assets/
|
|
34
|
+
"/assets/CompareDrawer-BVCAAbbu.js": {
|
|
35
35
|
"type": "text/javascript; charset=utf-8",
|
|
36
|
-
"etag": '"
|
|
37
|
-
"mtime": "2026-07-
|
|
36
|
+
"etag": '"4bc4-Zb2MZSke4PGsZAZQWlHQldYzm9M"',
|
|
37
|
+
"mtime": "2026-07-11T04:43:38.031Z",
|
|
38
|
+
"size": 19396,
|
|
39
|
+
"path": "../public/assets/CompareDrawer-BVCAAbbu.js"
|
|
40
|
+
},
|
|
41
|
+
"/assets/json-viewer-CpyYpPjx.js": {
|
|
42
|
+
"type": "text/javascript; charset=utf-8",
|
|
43
|
+
"etag": '"1ae7-AXjzdLeB9CtNkkvC/oR6PHIpZrw"',
|
|
44
|
+
"mtime": "2026-07-11T04:43:38.032Z",
|
|
38
45
|
"size": 6887,
|
|
39
|
-
"path": "../public/assets/json-viewer-
|
|
46
|
+
"path": "../public/assets/json-viewer-CpyYpPjx.js"
|
|
40
47
|
},
|
|
41
|
-
"/assets/
|
|
48
|
+
"/assets/index-gY3I-7-D.js": {
|
|
42
49
|
"type": "text/javascript; charset=utf-8",
|
|
43
|
-
"etag": '"
|
|
44
|
-
"mtime": "2026-07-
|
|
45
|
-
"size":
|
|
46
|
-
"path": "../public/assets/
|
|
50
|
+
"etag": '"265-61LM1QLhhYspwWAw/ft2ETl95Zg"',
|
|
51
|
+
"mtime": "2026-07-11T04:43:38.031Z",
|
|
52
|
+
"size": 613,
|
|
53
|
+
"path": "../public/assets/index-gY3I-7-D.js"
|
|
54
|
+
},
|
|
55
|
+
"/assets/index-9fMLCU4d.js": {
|
|
56
|
+
"type": "text/javascript; charset=utf-8",
|
|
57
|
+
"etag": '"1cd2d-vhf/v641OwP3pvt2nzTr2vXPzE4"',
|
|
58
|
+
"mtime": "2026-07-11T04:43:38.032Z",
|
|
59
|
+
"size": 118061,
|
|
60
|
+
"path": "../public/assets/index-9fMLCU4d.js"
|
|
47
61
|
},
|
|
48
62
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
49
63
|
"type": "image/jpeg",
|
|
50
64
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
51
|
-
"mtime": "2026-07-
|
|
65
|
+
"mtime": "2026-07-11T04:43:38.031Z",
|
|
52
66
|
"size": 6918,
|
|
53
67
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
54
68
|
},
|
|
55
|
-
"/assets/index-CSIL7-MK.js": {
|
|
56
|
-
"type": "text/javascript; charset=utf-8",
|
|
57
|
-
"etag": '"537cd-GPVivJXxNqhczKks68tQgmJTPDE"',
|
|
58
|
-
"mtime": "2026-07-11T00:24:54.156Z",
|
|
59
|
-
"size": 341965,
|
|
60
|
-
"path": "../public/assets/index-CSIL7-MK.js"
|
|
61
|
-
},
|
|
62
69
|
"/assets/index-CmeF5XXS.css": {
|
|
63
70
|
"type": "text/css; charset=utf-8",
|
|
64
71
|
"etag": '"28a56-x7Wmw+oL5ZFDjFw5JRwjxSop3gg"',
|
|
65
|
-
"mtime": "2026-07-
|
|
72
|
+
"mtime": "2026-07-11T04:43:38.031Z",
|
|
66
73
|
"size": 166486,
|
|
67
74
|
"path": "../public/assets/index-CmeF5XXS.css"
|
|
68
75
|
},
|
|
69
|
-
"/assets/
|
|
76
|
+
"/assets/RequestAnatomy-S17pYDRc.js": {
|
|
70
77
|
"type": "text/javascript; charset=utf-8",
|
|
71
|
-
"etag": '"
|
|
72
|
-
"mtime": "2026-07-
|
|
73
|
-
"size":
|
|
74
|
-
"path": "../public/assets/
|
|
78
|
+
"etag": '"43f3-DId6+xakRnGM+B/ZQpGxfeV9YU0"',
|
|
79
|
+
"mtime": "2026-07-11T04:43:38.032Z",
|
|
80
|
+
"size": 17395,
|
|
81
|
+
"path": "../public/assets/RequestAnatomy-S17pYDRc.js"
|
|
75
82
|
},
|
|
76
|
-
"/assets/
|
|
83
|
+
"/assets/ResponseView-Cf1XrawD.js": {
|
|
77
84
|
"type": "text/javascript; charset=utf-8",
|
|
78
|
-
"etag": '"
|
|
79
|
-
"mtime": "2026-07-
|
|
80
|
-
"size":
|
|
81
|
-
"path": "../public/assets/
|
|
85
|
+
"etag": '"47fe-kAztjtZjRuPE6xDPPKWIypxT0pw"',
|
|
86
|
+
"mtime": "2026-07-11T04:43:38.032Z",
|
|
87
|
+
"size": 18430,
|
|
88
|
+
"path": "../public/assets/ResponseView-Cf1XrawD.js"
|
|
82
89
|
},
|
|
83
|
-
"/assets/
|
|
90
|
+
"/assets/StreamingChunkSequence-BdOrVlCi.js": {
|
|
84
91
|
"type": "text/javascript; charset=utf-8",
|
|
85
|
-
"etag": '"
|
|
86
|
-
"mtime": "2026-07-
|
|
87
|
-
"size":
|
|
88
|
-
"path": "../public/assets/
|
|
92
|
+
"etag": '"e96-lQJVKxQQeI+CfoFlIj48wFou0qg"',
|
|
93
|
+
"mtime": "2026-07-11T04:43:38.032Z",
|
|
94
|
+
"size": 3734,
|
|
95
|
+
"path": "../public/assets/StreamingChunkSequence-BdOrVlCi.js"
|
|
89
96
|
},
|
|
90
|
-
"/assets/
|
|
97
|
+
"/assets/ReplayDialog-DMX23O5G.js": {
|
|
91
98
|
"type": "text/javascript; charset=utf-8",
|
|
92
|
-
"etag": '"
|
|
93
|
-
"mtime": "2026-07-
|
|
94
|
-
"size":
|
|
95
|
-
"path": "../public/assets/
|
|
99
|
+
"etag": '"3348-Y6DIYl0Hh8PNYNBckbjWZMRAVXk"',
|
|
100
|
+
"mtime": "2026-07-11T04:43:38.032Z",
|
|
101
|
+
"size": 13128,
|
|
102
|
+
"path": "../public/assets/ReplayDialog-DMX23O5G.js"
|
|
96
103
|
},
|
|
97
|
-
"/assets/
|
|
104
|
+
"/assets/_sessionId-BnKGmJrR.js": {
|
|
98
105
|
"type": "text/javascript; charset=utf-8",
|
|
99
|
-
"etag": '"
|
|
100
|
-
"mtime": "2026-07-
|
|
101
|
-
"size":
|
|
102
|
-
"path": "../public/assets/
|
|
106
|
+
"etag": '"36d-RhevzYZMuLpSJjgi/aeqAk1rL4A"',
|
|
107
|
+
"mtime": "2026-07-11T04:43:38.031Z",
|
|
108
|
+
"size": 877,
|
|
109
|
+
"path": "../public/assets/_sessionId-BnKGmJrR.js"
|
|
103
110
|
},
|
|
104
|
-
"/assets/
|
|
111
|
+
"/assets/index-B1atk19i.js": {
|
|
105
112
|
"type": "text/javascript; charset=utf-8",
|
|
106
|
-
"etag": '"
|
|
107
|
-
"mtime": "2026-07-
|
|
108
|
-
"size":
|
|
109
|
-
"path": "../public/assets/
|
|
113
|
+
"etag": '"537cd-GY35Hkfq1WcIm1S1m2dfzIGL8WU"',
|
|
114
|
+
"mtime": "2026-07-11T04:43:38.031Z",
|
|
115
|
+
"size": 341965,
|
|
116
|
+
"path": "../public/assets/index-B1atk19i.js"
|
|
110
117
|
},
|
|
111
118
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
112
119
|
"type": "image/svg+xml",
|
|
113
120
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
114
|
-
"mtime": "2026-07-
|
|
121
|
+
"mtime": "2026-07-11T04:43:38.031Z",
|
|
115
122
|
"size": 11256,
|
|
116
123
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
117
124
|
},
|
|
118
|
-
"/assets/_sessionId-D-V84cgw.js": {
|
|
119
|
-
"type": "text/javascript; charset=utf-8",
|
|
120
|
-
"etag": '"36d-yOd6Us3ZWW0UESw+7JXnLzgeMbY"',
|
|
121
|
-
"mtime": "2026-07-11T00:24:54.156Z",
|
|
122
|
-
"size": 877,
|
|
123
|
-
"path": "../public/assets/_sessionId-D-V84cgw.js"
|
|
124
|
-
},
|
|
125
125
|
"/assets/qwen-CONDcHqt.png": {
|
|
126
126
|
"type": "image/png",
|
|
127
127
|
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
128
|
-
"mtime": "2026-07-
|
|
128
|
+
"mtime": "2026-07-11T04:43:38.031Z",
|
|
129
129
|
"size": 357059,
|
|
130
130
|
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
131
131
|
},
|
|
132
|
-
"/assets/ProxyViewerContainer-
|
|
132
|
+
"/assets/ProxyViewerContainer-CYOXB81n.js": {
|
|
133
133
|
"type": "text/javascript; charset=utf-8",
|
|
134
|
-
"etag": '"
|
|
135
|
-
"mtime": "2026-07-
|
|
136
|
-
"size":
|
|
137
|
-
"path": "../public/assets/ProxyViewerContainer-
|
|
134
|
+
"etag": '"1404bd-m6RVh35PDpz6DtJ+NOh+zTs1XG8"',
|
|
135
|
+
"mtime": "2026-07-11T04:43:38.032Z",
|
|
136
|
+
"size": 1311933,
|
|
137
|
+
"path": "../public/assets/ProxyViewerContainer-CYOXB81n.js"
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
140
|
function readAsset(id) {
|
package/README.md
CHANGED
|
@@ -31,6 +31,14 @@ npm install -g @tonyclaw/agent-inspector-mcp
|
|
|
31
31
|
agent-inspector-mcp doctor
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
Agent Inspector requires Node.js 22 or newer. Node.js 24 LTS is recommended for production use.
|
|
35
|
+
|
|
36
|
+
By default, Agent Inspector binds to `127.0.0.1`. With `--host 0.0.0.0`, remote coding tools may
|
|
37
|
+
use `/proxy`, while the UI, REST API, and MCP control plane remain local-only. Set
|
|
38
|
+
`AGENT_INSPECTOR_CONTROL_TOKEN` for authenticated remote API/MCP clients, or explicitly set
|
|
39
|
+
`AGENT_INSPECTOR_ALLOW_REMOTE_CONTROL=1` only behind a trusted firewall or loopback-only port
|
|
40
|
+
mapping.
|
|
41
|
+
|
|
34
42
|
`@tonyclaw/agent-inspector` runs the local UI, proxy, REST API, storage, and built-in
|
|
35
43
|
`/api/mcp` endpoint. `@tonyclaw/agent-inspector-mcp` is the enhancement package for
|
|
36
44
|
stdio-first MCP clients and setup automation; it bridges to the local Inspector endpoint without
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tonyclaw/agent-inspector",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.27",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agent observability and knowledge capture layer for AI coding tools.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"engines": {
|
|
8
|
-
"node": ">=
|
|
8
|
+
"node": ">=22.0.0"
|
|
9
9
|
},
|
|
10
10
|
"author": "TonyClaw",
|
|
11
11
|
"repository": {
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"dev": "vite dev",
|
|
56
56
|
"start": "node .output/cli.js",
|
|
57
57
|
"build": "vite build && bun build:cli && bun build:mcp",
|
|
58
|
-
"build:cli": "npx esbuild src/cli.ts --bundle --platform=node --target=
|
|
59
|
-
"build:mcp": "npx esbuild packages/agent-inspector-mcp/src/cli.ts --bundle --platform=node --target=
|
|
58
|
+
"build:cli": "npx esbuild src/cli.ts --bundle --platform=node --target=node22 --format=esm --outfile=.output/cli.js",
|
|
59
|
+
"build:mcp": "npx esbuild packages/agent-inspector-mcp/src/cli.ts --bundle --platform=node --target=node22 --format=esm --outfile=packages/agent-inspector-mcp/dist/cli.js",
|
|
60
60
|
"postinstall": "node scripts/setup-windows-runtime.mjs && node scripts/setup-agent-skills.mjs",
|
|
61
61
|
"prepublishOnly": "npm run build",
|
|
62
62
|
"typecheck": "tsc --noEmit",
|
|
@@ -102,7 +102,6 @@
|
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|
|
104
104
|
"@biomejs/biome": "^2.3.14",
|
|
105
|
-
"@cfworker/json-schema": "^4.1.1",
|
|
106
105
|
"@eslint/js": "^10.0.1",
|
|
107
106
|
"@ladle/react": "^5.1.1",
|
|
108
107
|
"@tailwindcss/vite": "^4.1.18",
|
package/src/cli.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { existsSync } from "node:fs";
|
|
|
8
8
|
import type { Readable, Writable } from "node:stream";
|
|
9
9
|
import {
|
|
10
10
|
formatAccessHintLines,
|
|
11
|
+
isLoopbackHost,
|
|
11
12
|
isValidBindHost,
|
|
12
13
|
localUrlForPort,
|
|
13
14
|
networkUrlsForBindHost,
|
|
@@ -31,6 +32,7 @@ const __dirname = dirname(__filename);
|
|
|
31
32
|
const DEFAULT_PORT = 9527;
|
|
32
33
|
const LEGACY_ALIAS_PORT = 9527;
|
|
33
34
|
const DEFAULT_UPSTREAM_PORT = 9529;
|
|
35
|
+
const DEFAULT_BIND_HOST = "127.0.0.1";
|
|
34
36
|
const LOCAL_PROBE_TIMEOUT_MS = 2000;
|
|
35
37
|
const BRANDED_WINDOWS_RUNTIME_EXE = "agent-inspector.exe";
|
|
36
38
|
const DEFAULT_CAPTURE_MODE = "simple";
|
|
@@ -229,6 +231,16 @@ function printAccessHints(port: number, host?: string): void {
|
|
|
229
231
|
for (const line of formatAccessHintLines(port, networkUrls, host)) {
|
|
230
232
|
console.log(line);
|
|
231
233
|
}
|
|
234
|
+
if (!isLoopbackHost(host)) {
|
|
235
|
+
if (process.env["AGENT_INSPECTOR_ALLOW_REMOTE_CONTROL"] === "1") {
|
|
236
|
+
console.warn(" Control plane: REMOTE ACCESS ENABLED by administrator override");
|
|
237
|
+
} else {
|
|
238
|
+
console.log(" Control plane: local only; remote clients may use /proxy");
|
|
239
|
+
if ((process.env["AGENT_INSPECTOR_CONTROL_TOKEN"] ?? "") !== "") {
|
|
240
|
+
console.log(" Remote API: Bearer token authentication enabled");
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
232
244
|
}
|
|
233
245
|
|
|
234
246
|
type BackgroundSupervisorOptions = {
|
|
@@ -289,13 +301,18 @@ function pickUpstreamPort(publicPort: number, legacyAliasPort: number | null): n
|
|
|
289
301
|
async function tryStartIdentityProxy(
|
|
290
302
|
identityPort: number,
|
|
291
303
|
upstreamPort: number,
|
|
292
|
-
|
|
304
|
+
listenHost: string,
|
|
305
|
+
upstreamHost: string,
|
|
293
306
|
): Promise<import("node:http").Server | null> {
|
|
294
307
|
try {
|
|
295
308
|
const server = await startIdentityProxy({
|
|
296
309
|
listenPort: identityPort,
|
|
297
|
-
|
|
310
|
+
listenHost,
|
|
311
|
+
upstreamHost,
|
|
298
312
|
upstreamPort,
|
|
313
|
+
restrictRemoteControl: !isLoopbackHost(listenHost),
|
|
314
|
+
allowRemoteControl: process.env["AGENT_INSPECTOR_ALLOW_REMOTE_CONTROL"] === "1",
|
|
315
|
+
controlToken: process.env["AGENT_INSPECTOR_CONTROL_TOKEN"],
|
|
299
316
|
});
|
|
300
317
|
return server;
|
|
301
318
|
} catch (err) {
|
|
@@ -317,7 +334,8 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
317
334
|
process.env["AGENT_INSPECTOR_CAPTURE_MODE"] ?? process.env["AGENT_INSPECTOR_MODE"];
|
|
318
335
|
|
|
319
336
|
let port = portDefault;
|
|
320
|
-
let host =
|
|
337
|
+
let host =
|
|
338
|
+
envHost !== undefined && envHost.trim().length > 0 ? envHost.trim() : DEFAULT_BIND_HOST;
|
|
321
339
|
let open = true;
|
|
322
340
|
let openWasSpecified = false;
|
|
323
341
|
let background = false;
|
|
@@ -457,6 +475,18 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
457
475
|
return;
|
|
458
476
|
}
|
|
459
477
|
|
|
478
|
+
if (
|
|
479
|
+
!enableIdentityProxy &&
|
|
480
|
+
!isLoopbackHost(host) &&
|
|
481
|
+
process.env["AGENT_INSPECTOR_ALLOW_REMOTE_CONTROL"] !== "1"
|
|
482
|
+
) {
|
|
483
|
+
console.error(
|
|
484
|
+
"Refusing an unprotected remote bind with --no-identity-proxy. Keep the identity proxy enabled or set AGENT_INSPECTOR_ALLOW_REMOTE_CONTROL=1 explicitly.",
|
|
485
|
+
);
|
|
486
|
+
process.exitCode = 1;
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
460
490
|
/**
|
|
461
491
|
* Check if a port is in use and kill the process using it
|
|
462
492
|
*/
|
|
@@ -475,6 +505,7 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
475
505
|
// the public-facing port(s). When the identity proxy is disabled we fall
|
|
476
506
|
// back to TanStack listening on the public port directly.
|
|
477
507
|
const upstreamPort = enableIdentityProxy ? pickUpstreamPort(port, legacyAliasPort) : port;
|
|
508
|
+
const upstreamHost = enableIdentityProxy ? DEFAULT_BIND_HOST : host;
|
|
478
509
|
process.env["PORT"] = String(upstreamPort);
|
|
479
510
|
|
|
480
511
|
const url = urlForHost(port, host);
|
|
@@ -627,10 +658,8 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
627
658
|
if (providersJson !== undefined) {
|
|
628
659
|
serverEnv["AGENT_INSPECTOR_PROVIDERS_JSON"] = providersJson;
|
|
629
660
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
serverEnv["NITRO_HOST"] = host;
|
|
633
|
-
}
|
|
661
|
+
serverEnv["HOST"] = upstreamHost;
|
|
662
|
+
serverEnv["NITRO_HOST"] = upstreamHost;
|
|
634
663
|
serverEnv["AGENT_INSPECTOR_PUBLIC_PORT"] = String(port);
|
|
635
664
|
serverEnv["PROXY_PORT"] = String(port);
|
|
636
665
|
serverEnv["AGENT_INSPECTOR_CAPTURE_MODE"] = captureMode;
|
|
@@ -664,12 +693,17 @@ async function runStart(args: string[]): Promise<void> {
|
|
|
664
693
|
server: import("node:http").Server;
|
|
665
694
|
}> = [];
|
|
666
695
|
if (enableIdentityProxy) {
|
|
667
|
-
const primaryProxy = await tryStartIdentityProxy(port, upstreamPort, host);
|
|
696
|
+
const primaryProxy = await tryStartIdentityProxy(port, upstreamPort, host, upstreamHost);
|
|
668
697
|
if (primaryProxy !== null) {
|
|
669
698
|
identityProxies.push({ label: "primary", port, server: primaryProxy });
|
|
670
699
|
}
|
|
671
700
|
if (legacyAliasPort !== null) {
|
|
672
|
-
const legacyProxy = await tryStartIdentityProxy(
|
|
701
|
+
const legacyProxy = await tryStartIdentityProxy(
|
|
702
|
+
legacyAliasPort,
|
|
703
|
+
upstreamPort,
|
|
704
|
+
host,
|
|
705
|
+
upstreamHost,
|
|
706
|
+
);
|
|
673
707
|
if (legacyProxy !== null) {
|
|
674
708
|
identityProxies.push({ label: "legacy", port: legacyAliasPort, server: legacyProxy });
|
|
675
709
|
}
|
|
@@ -2,22 +2,16 @@ import { type JSX, useState } from "react";
|
|
|
2
2
|
import { Button } from "../ui/button";
|
|
3
3
|
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../ui/tooltip";
|
|
4
4
|
import {
|
|
5
|
-
Eye,
|
|
6
|
-
EyeOff,
|
|
7
5
|
Pencil,
|
|
8
6
|
Trash2,
|
|
9
7
|
RotateCw,
|
|
10
8
|
CheckCircle,
|
|
11
9
|
ExternalLink,
|
|
12
10
|
Clock,
|
|
13
|
-
Copy,
|
|
14
|
-
Check,
|
|
15
11
|
ChevronDown,
|
|
16
12
|
ChevronRight,
|
|
17
13
|
} from "lucide-react";
|
|
18
14
|
import type { ProviderConfig } from "../../proxy/providers";
|
|
19
|
-
import { copyTextToClipboard } from "../../lib/clipboard";
|
|
20
|
-
import { maskApiKey } from "../../lib/mask";
|
|
21
15
|
import {
|
|
22
16
|
findProviderModelMetadata,
|
|
23
17
|
providerHasContextMetadata,
|
|
@@ -174,18 +168,8 @@ export function ProviderCard({
|
|
|
174
168
|
onRefreshMetadata,
|
|
175
169
|
isRefreshingMetadata = false,
|
|
176
170
|
}: ProviderCardProps): JSX.Element {
|
|
177
|
-
const [showApiKey, setShowApiKey] = useState(false);
|
|
178
|
-
const [copied, setCopied] = useState(false);
|
|
179
171
|
const [showDetails, setShowDetails] = useState(false);
|
|
180
172
|
|
|
181
|
-
function handleCopy() {
|
|
182
|
-
void copyTextToClipboard(provider.apiKey).then((success) => {
|
|
183
|
-
if (!success) return;
|
|
184
|
-
setCopied(true);
|
|
185
|
-
setTimeout(() => setCopied(false), 2000);
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
|
|
189
173
|
const docsUrl =
|
|
190
174
|
provider.apiDocsUrl ??
|
|
191
175
|
Object.entries(KNOWN_PROVIDER_DOCS).find(([keyword]) =>
|
|
@@ -285,26 +269,9 @@ export function ProviderCard({
|
|
|
285
269
|
|
|
286
270
|
{showDetails && (
|
|
287
271
|
<div className="space-y-3 border-t border-border/60 pt-3">
|
|
288
|
-
<div className="flex items-center gap-2">
|
|
289
|
-
<
|
|
290
|
-
|
|
291
|
-
</code>
|
|
292
|
-
<button
|
|
293
|
-
type="button"
|
|
294
|
-
onClick={() => setShowApiKey((s) => !s)}
|
|
295
|
-
className="p-1 text-muted-foreground transition-colors hover:text-foreground"
|
|
296
|
-
aria-label={showApiKey ? "Hide API key" : "Show API key"}
|
|
297
|
-
>
|
|
298
|
-
{showApiKey ? <EyeOff className="size-4" /> : <Eye className="size-4" />}
|
|
299
|
-
</button>
|
|
300
|
-
<button
|
|
301
|
-
type="button"
|
|
302
|
-
onClick={handleCopy}
|
|
303
|
-
className="p-1 text-muted-foreground transition-colors hover:text-foreground"
|
|
304
|
-
aria-label="Copy API key"
|
|
305
|
-
>
|
|
306
|
-
{copied ? <Check className="size-4 text-cyan-300" /> : <Copy className="size-4" />}
|
|
307
|
-
</button>
|
|
272
|
+
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
273
|
+
<CheckCircle className="size-3.5 text-emerald-500" />
|
|
274
|
+
<span>API key configured</span>
|
|
308
275
|
</div>
|
|
309
276
|
|
|
310
277
|
{provider.models !== undefined && provider.models.length > 0 && (
|
|
@@ -4,7 +4,6 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from ".
|
|
|
4
4
|
import { Eye, EyeOff, Copy, Check, ChevronDown } from "lucide-react";
|
|
5
5
|
import type { ProviderConfig, ProviderModelMetadata } from "../../lib/providerContract";
|
|
6
6
|
import { copyTextToClipboard } from "../../lib/clipboard";
|
|
7
|
-
import { maskApiKey } from "../../lib/mask";
|
|
8
7
|
import {
|
|
9
8
|
PATH_V1_CHAT_COMPLETIONS,
|
|
10
9
|
PATH_V1_MESSAGES,
|
|
@@ -327,7 +326,7 @@ function EndpointUrlPreview({
|
|
|
327
326
|
export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps): JSX.Element {
|
|
328
327
|
const initialCapabilities = deriveProviderCapabilities(provider);
|
|
329
328
|
const [name, setName] = useState(provider?.name ?? "");
|
|
330
|
-
const [apiKey, setApiKey] = useState(
|
|
329
|
+
const [apiKey, setApiKey] = useState("");
|
|
331
330
|
const [showApiKey, setShowApiKey] = useState(false);
|
|
332
331
|
const [copied, setCopied] = useState(false);
|
|
333
332
|
const initialModels = provider?.models;
|
|
@@ -411,7 +410,8 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
|
|
|
411
410
|
useEffect(() => {
|
|
412
411
|
if (provider) {
|
|
413
412
|
setName(provider.name);
|
|
414
|
-
setApiKey(
|
|
413
|
+
setApiKey("");
|
|
414
|
+
setShowApiKey(false);
|
|
415
415
|
const nextModels = (provider.models?.length ?? 0) > 0 ? provider.models : [""];
|
|
416
416
|
setModels(nextModels);
|
|
417
417
|
setModelMetadataDrafts(createMetadataDrafts(provider, nextModels));
|
|
@@ -482,7 +482,7 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
|
|
|
482
482
|
if (!name.trim()) {
|
|
483
483
|
newErrors.name = "Name is required";
|
|
484
484
|
}
|
|
485
|
-
if (!apiKey.trim()) {
|
|
485
|
+
if (provider === undefined && !apiKey.trim()) {
|
|
486
486
|
newErrors.apiKey = "API key is required";
|
|
487
487
|
}
|
|
488
488
|
if (models.length === 0 || models.every((m) => !m.trim())) {
|
|
@@ -950,19 +950,15 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
|
|
|
950
950
|
|
|
951
951
|
<div className="space-y-2">
|
|
952
952
|
<label htmlFor="provider-apikey" className="text-sm font-medium">
|
|
953
|
-
API Key <span className="text-destructive">*</span>
|
|
953
|
+
API Key {provider === undefined && <span className="text-destructive">*</span>}
|
|
954
954
|
</label>
|
|
955
955
|
<div className="flex items-center gap-2">
|
|
956
956
|
<input
|
|
957
957
|
id="provider-apikey"
|
|
958
|
-
type="text"
|
|
959
|
-
value={
|
|
958
|
+
type={showApiKey ? "text" : "password"}
|
|
959
|
+
value={apiKey}
|
|
960
960
|
onChange={(e) => setApiKey(e.target.value)}
|
|
961
|
-
|
|
962
|
-
if (!showApiKey && apiKey.length > 0) setShowApiKey(true);
|
|
963
|
-
}}
|
|
964
|
-
placeholder="sk-ant-..."
|
|
965
|
-
readOnly={!showApiKey && apiKey.length > 0}
|
|
961
|
+
placeholder={provider === undefined ? "sk-ant-..." : "Leave blank to keep current key"}
|
|
966
962
|
className="flex-1 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
|
|
967
963
|
/>
|
|
968
964
|
<button
|
|
@@ -982,6 +978,11 @@ export function ProviderForm({ provider, onSubmit, onCancel }: ProviderFormProps
|
|
|
982
978
|
{copied ? <Check className="size-4 text-cyan-300" /> : <Copy className="size-4" />}
|
|
983
979
|
</button>
|
|
984
980
|
</div>
|
|
981
|
+
{provider !== undefined && apiKey.trim() === "" && (
|
|
982
|
+
<p className="text-xs text-muted-foreground">
|
|
983
|
+
A key is configured. Enter a new value only to rotate it.
|
|
984
|
+
</p>
|
|
985
|
+
)}
|
|
985
986
|
{errors.apiKey !== undefined && <p className="text-xs text-destructive">{errors.apiKey}</p>}
|
|
986
987
|
</div>
|
|
987
988
|
|
|
@@ -81,7 +81,7 @@ function endpointPayloadValue(
|
|
|
81
81
|
function createProviderPayload(data: ProviderFormData, preserveEmptyEndpoints = false) {
|
|
82
82
|
return {
|
|
83
83
|
name: data.name,
|
|
84
|
-
apiKey: data.apiKey,
|
|
84
|
+
...(data.apiKey.trim() === "" ? {} : { apiKey: data.apiKey }),
|
|
85
85
|
models: data.models,
|
|
86
86
|
anthropicBaseUrl: endpointPayloadValue(data.anthropicBaseUrl, preserveEmptyEndpoints),
|
|
87
87
|
openaiBaseUrl: endpointPayloadValue(data.openaiBaseUrl, preserveEmptyEndpoints),
|
|
@@ -430,7 +430,7 @@ export function ProvidersPanel({
|
|
|
430
430
|
refreshProviders();
|
|
431
431
|
// Only run connection test when critical fields (apiKey, model, base URLs) changed
|
|
432
432
|
const criticalFieldsChanged =
|
|
433
|
-
|
|
433
|
+
data.apiKey.trim() !== "" ||
|
|
434
434
|
JSON.stringify(data.models) !== JSON.stringify(editingProvider.models) ||
|
|
435
435
|
(data.anthropicBaseUrl ?? "") !== (editingProvider.anthropicBaseUrl ?? "") ||
|
|
436
436
|
(data.openaiBaseUrl ?? "") !== (editingProvider.openaiBaseUrl ?? "") ||
|
|
@@ -471,9 +471,9 @@ function McpSettingsTab(): JSX.Element {
|
|
|
471
471
|
value: `agent-inspector-mcp doctor --url ${endpoint}`,
|
|
472
472
|
},
|
|
473
473
|
{
|
|
474
|
-
id: "
|
|
475
|
-
label: "
|
|
476
|
-
value: "
|
|
474
|
+
id: "writes",
|
|
475
|
+
label: "Enable write tools",
|
|
476
|
+
value: "AGENT_INSPECTOR_MCP_WRITES=1 agent-inspector",
|
|
477
477
|
},
|
|
478
478
|
{
|
|
479
479
|
id: "capabilities",
|
|
@@ -5,9 +5,6 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/
|
|
|
5
5
|
|
|
6
6
|
const MAX_VISIBLE_LOGOS = 3;
|
|
7
7
|
|
|
8
|
-
export const ROW_CHEVRON_SLOT_CLASS =
|
|
9
|
-
"flex h-8 w-5 shrink-0 items-center justify-center text-muted-foreground";
|
|
10
|
-
|
|
11
8
|
export type ProviderLogoStackItem = {
|
|
12
9
|
provider: Provider;
|
|
13
10
|
tooltip: string;
|
|
@@ -228,8 +228,3 @@ export const SseEventSchema = z.discriminatedUnion("type", [
|
|
|
228
228
|
|
|
229
229
|
export type AnthropicResponse = z.infer<typeof AnthropicResponseSchema>;
|
|
230
230
|
export type ResponseContentBlockType = z.infer<typeof ResponseContentBlock>;
|
|
231
|
-
|
|
232
|
-
// Backward-compatible aliases (originally named Inspector*)
|
|
233
|
-
export const InspectorRequestSchema = AnthropicRequestSchema;
|
|
234
|
-
export const InspectorResponseSchema = AnthropicResponseSchema;
|
|
235
|
-
export type InspectorResponse = AnthropicResponse;
|
package/src/contracts/index.ts
CHANGED
|
@@ -12,7 +12,6 @@ export type {
|
|
|
12
12
|
CapturedLog,
|
|
13
13
|
LogBodyChunk,
|
|
14
14
|
LogBodyPart,
|
|
15
|
-
RequestFormat,
|
|
16
15
|
StreamingChunk,
|
|
17
16
|
TokenUsage,
|
|
18
17
|
} from "./log";
|
|
@@ -46,9 +45,6 @@ export {
|
|
|
46
45
|
} from "./openai";
|
|
47
46
|
export type {
|
|
48
47
|
OpenAIResponse,
|
|
49
|
-
OpenAIResponsesRequest,
|
|
50
48
|
OpenAIResponsesResponse,
|
|
51
|
-
OpenAIResponsesSSEvent,
|
|
52
|
-
OpenAIResponsesOutputItem,
|
|
53
49
|
OpenAIToolCall,
|
|
54
50
|
} from "./openai";
|
package/src/contracts/log.ts
CHANGED
package/src/contracts/openai.ts
CHANGED
|
@@ -242,10 +242,7 @@ export const OpenAIResponsesSSEventSchema = z
|
|
|
242
242
|
.passthrough();
|
|
243
243
|
|
|
244
244
|
export type OpenAIResponse = z.infer<typeof OpenAIResponseSchema>;
|
|
245
|
-
export type OpenAIResponsesRequest = z.infer<typeof OpenAIResponsesRequestSchema>;
|
|
246
245
|
export type OpenAIResponsesResponse = z.infer<typeof OpenAIResponsesResponseSchema>;
|
|
247
|
-
export type OpenAIResponsesSSEvent = z.infer<typeof OpenAIResponsesSSEventSchema>;
|
|
248
|
-
export type OpenAIResponsesOutputItem = z.infer<typeof OpenAIResponsesOutputItemSchema>;
|
|
249
246
|
|
|
250
247
|
export function parseOpenAIResponse(rawBody: string): OpenAIResponse | null {
|
|
251
248
|
try {
|