@tonyclaw/llm-inspector 1.15.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.output/cli.js +1 -0
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/index-BmkN9DxE.js +107 -0
  4. package/.output/public/assets/index-DPe3eOih.css +1 -0
  5. package/.output/public/assets/{main-BLYgekFx.js → main-BjnjXVBU.js} +1 -1
  6. package/.output/server/_libs/diff.mjs +2 -2
  7. package/.output/server/_ssr/{index-P66uoVEU.mjs → index-BIOEVAzU.mjs} +783 -588
  8. package/.output/server/_ssr/index.mjs +2 -2
  9. package/.output/server/_ssr/{router-DpLCKk51.mjs → router-THS9ptvu.mjs} +439 -177
  10. package/.output/server/{_tanstack-start-manifest_v-C9Wq6YdJ.mjs → _tanstack-start-manifest_v-BYhN7q_z.mjs} +1 -1
  11. package/.output/server/index.mjs +31 -31
  12. package/README.md +200 -113
  13. package/package.json +1 -1
  14. package/src/cli.ts +1 -0
  15. package/src/components/ProxyViewer.tsx +77 -85
  16. package/src/components/ProxyViewerContainer.tsx +148 -76
  17. package/src/components/providers/ImportWizardDialog.tsx +27 -3
  18. package/src/components/proxy-viewer/CompareDrawer.tsx +17 -4
  19. package/src/components/proxy-viewer/ConversationGroup.tsx +15 -47
  20. package/src/components/proxy-viewer/ConversationHeader.tsx +58 -5
  21. package/src/components/proxy-viewer/LogEntry.tsx +297 -329
  22. package/src/components/proxy-viewer/LogEntryHeader.tsx +126 -137
  23. package/src/components/proxy-viewer/ResponseView.tsx +14 -34
  24. package/src/components/proxy-viewer/StreamingChunkSequence.tsx +3 -3
  25. package/src/components/proxy-viewer/TurnGroup.tsx +25 -21
  26. package/src/components/proxy-viewer/diff/DiffView.tsx +5 -3
  27. package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +13 -9
  28. package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +3 -3
  29. package/src/components/proxy-viewer/formats/index.tsx +19 -10
  30. package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +7 -3
  31. package/src/components/proxy-viewer/log-formats/anthropic.ts +48 -0
  32. package/src/components/proxy-viewer/log-formats/index.ts +23 -0
  33. package/src/components/proxy-viewer/log-formats/openai.ts +40 -0
  34. package/src/components/proxy-viewer/log-formats/types.ts +33 -0
  35. package/src/components/proxy-viewer/log-formats/unknown.ts +14 -0
  36. package/src/components/proxy-viewer/viewerState.ts +58 -0
  37. package/src/components/ui/json-viewer.tsx +3 -3
  38. package/src/lib/objectUtils.ts +22 -0
  39. package/src/proxy/claudeCodeStrip.ts +5 -8
  40. package/src/proxy/formats/index.ts +1 -1
  41. package/src/proxy/formats/registry.ts +9 -0
  42. package/src/proxy/handler.ts +2 -8
  43. package/src/proxy/logIndex.ts +58 -43
  44. package/src/proxy/logger.ts +51 -27
  45. package/src/proxy/openaiOrphanToolStrip.ts +11 -17
  46. package/src/proxy/providerImporters.ts +245 -19
  47. package/src/proxy/providers.ts +20 -7
  48. package/src/proxy/schemas.ts +5 -9
  49. package/src/proxy/socketTracker.ts +109 -78
  50. package/src/proxy/store.ts +68 -83
  51. package/src/routes/api/logs.ts +31 -2
  52. package/styles/globals.css +22 -0
  53. package/.output/public/assets/index-CMuJQyt1.js +0 -105
  54. package/.output/public/assets/index-DciyfYBk.css +0 -1
@@ -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/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$"], "preloads": ["/assets/main-BLYgekFx.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-CMuJQyt1.js"] }, "/api/config": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.ts", "children": ["/api/config/paths"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/mcp": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/mcp.ts" }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-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/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.import.ts" }, "/api/providers/scan": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.scan.ts" }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts", "children": ["/api/providers/$providerId/test/log"] }, "/api/providers/$providerId/test/log": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.log.ts" } }, "clientEntry": "/assets/main-BLYgekFx.js" });
1
+ const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$"], "preloads": ["/assets/main-BjnjXVBU.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-BmkN9DxE.js"] }, "/api/config": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.ts", "children": ["/api/config/paths"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/mcp": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/mcp.ts" }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-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/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.import.ts" }, "/api/providers/scan": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.scan.ts" }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts", "children": ["/api/providers/$providerId/test/log"] }, "/api/providers/$providerId/test/log": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.log.ts" } }, "clientEntry": "/assets/main-BjnjXVBU.js" });
2
2
  export {
3
3
  tsrStartManifest
4
4
  };
@@ -35,54 +35,54 @@ const headers = ((m) => function headersRouteRule(event) {
35
35
  }
36
36
  });
37
37
  const assets = {
38
- "/assets/index-DciyfYBk.css": {
39
- "type": "text/css; charset=utf-8",
40
- "etag": '"15867-TOX1Gddns0p3jKt+7co1NuZS+d8"',
41
- "mtime": "2026-06-12T07:17:56.431Z",
42
- "size": 88167,
43
- "path": "../public/assets/index-DciyfYBk.css"
44
- },
45
38
  "/assets/alibaba-TTwafVwX.svg": {
46
39
  "type": "image/svg+xml",
47
40
  "etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
48
- "mtime": "2026-06-12T07:17:56.428Z",
41
+ "mtime": "2026-06-13T05:45:10.081Z",
49
42
  "size": 5915,
50
43
  "path": "../public/assets/alibaba-TTwafVwX.svg"
51
44
  },
52
- "/assets/main-BLYgekFx.js": {
45
+ "/assets/index-DPe3eOih.css": {
46
+ "type": "text/css; charset=utf-8",
47
+ "etag": '"15a32-YUlUFJPXe5WrOzMkLVz9gOyERE4"',
48
+ "mtime": "2026-06-13T05:45:10.081Z",
49
+ "size": 88626,
50
+ "path": "../public/assets/index-DPe3eOih.css"
51
+ },
52
+ "/assets/qwen-CONDcHqt.png": {
53
+ "type": "image/png",
54
+ "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
55
+ "mtime": "2026-06-13T05:45:10.081Z",
56
+ "size": 357059,
57
+ "path": "../public/assets/qwen-CONDcHqt.png"
58
+ },
59
+ "/assets/main-BjnjXVBU.js": {
53
60
  "type": "text/javascript; charset=utf-8",
54
- "etag": '"50599-tks6aTeb/Edw4laR3cdpiWA48mc"',
55
- "mtime": "2026-06-12T07:17:56.431Z",
61
+ "etag": '"50599-TBFFt8m3KX+84o0h5FGqLcw9zvM"',
62
+ "mtime": "2026-06-13T05:45:10.081Z",
56
63
  "size": 329113,
57
- "path": "../public/assets/main-BLYgekFx.js"
58
- },
59
- "/assets/zhipuai-BPNAnxo-.svg": {
60
- "type": "image/svg+xml",
61
- "etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
62
- "mtime": "2026-06-12T07:17:56.431Z",
63
- "size": 11256,
64
- "path": "../public/assets/zhipuai-BPNAnxo-.svg"
64
+ "path": "../public/assets/main-BjnjXVBU.js"
65
65
  },
66
66
  "/assets/minimax-BPMzvuL-.jpeg": {
67
67
  "type": "image/jpeg",
68
68
  "etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
69
- "mtime": "2026-06-12T07:17:56.431Z",
69
+ "mtime": "2026-06-13T05:45:10.078Z",
70
70
  "size": 6918,
71
71
  "path": "../public/assets/minimax-BPMzvuL-.jpeg"
72
72
  },
73
- "/assets/qwen-CONDcHqt.png": {
74
- "type": "image/png",
75
- "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
76
- "mtime": "2026-06-12T07:17:56.431Z",
77
- "size": 357059,
78
- "path": "../public/assets/qwen-CONDcHqt.png"
73
+ "/assets/zhipuai-BPNAnxo-.svg": {
74
+ "type": "image/svg+xml",
75
+ "etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
76
+ "mtime": "2026-06-13T05:45:10.081Z",
77
+ "size": 11256,
78
+ "path": "../public/assets/zhipuai-BPNAnxo-.svg"
79
79
  },
80
- "/assets/index-CMuJQyt1.js": {
80
+ "/assets/index-BmkN9DxE.js": {
81
81
  "type": "text/javascript; charset=utf-8",
82
- "etag": '"97f56-eCDTvraNzTc2Un6pdqimYNiZVhw"',
83
- "mtime": "2026-06-12T07:17:56.431Z",
84
- "size": 622422,
85
- "path": "../public/assets/index-CMuJQyt1.js"
82
+ "etag": '"9ae0c-h7IO5tRUMmZre12bMt7hEiFWLhQ"',
83
+ "mtime": "2026-06-13T05:45:10.081Z",
84
+ "size": 634380,
85
+ "path": "../public/assets/index-BmkN9DxE.js"
86
86
  }
87
87
  };
88
88
  function readAsset(id) {
package/README.md CHANGED
@@ -1,34 +1,36 @@
1
1
  # llm-inspector
2
2
 
3
- > LLM Inspector
3
+ 透明捕获、解析和重放 AI 编码工具的 LLM API 流量。
4
4
 
5
- ![Proxy Overview](docs/Proxy.png)
5
+ ![LLM Inspector](docs/封面v1.15.0.png)
6
6
 
7
- ## What is llm-inspector?
7
+ `llm-inspector` 是一个运行在本机的 HTTP 代理和 Web 调试器。将 Claude Code、OpenCode、Cursor、Cody 或其他兼容客户端的 API Base URL 指向它,即可实时查看请求、响应、工具调用、Thinking、SSE chunks 和 Token 用量。
8
8
 
9
- **llm-inspector** 是一个 LLM API 透明代理调试工具,能够捕获 AI 编程工具(Claude Code、OpenCode、Cursor、Cody 等)与 LLM 提供商之间的所有 API 请求和响应,在 Web UI 中实时展示:
9
+ 默认地址:
10
10
 
11
- - 系统提示词 (System Prompts)
12
- - 工具定义 (Tool Definitions)
13
- - 消息内容 (Messages)
14
- - SSE 流式数据块 (Streaming Chunks)
15
- - Token 用量 (Token Usage)
11
+ - Web UI:`http://localhost:25947`
12
+ - 代理入口:`http://localhost:25947/proxy`
13
+ - MCP Server:`http://localhost:25947/api/mcp`
16
14
 
17
- **专为理解 AI 编程工具底层 API 调用行为而设计。帮助开发者看清 LLM API 的"最后一公里"。**
15
+ ## 功能
18
16
 
19
- ## Key Advantages / 核心优势
17
+ - 同时支持 Anthropic Messages API 和 OpenAI Chat Completions API
18
+ - 分开解析两种协议的请求、响应、Thinking、Answer 和 Tool Call
19
+ - 按请求路径识别协议:
20
+ - `/proxy/v1/messages` -> Anthropic
21
+ - `/proxy/v1/chat/completions` -> OpenAI
22
+ - 实时捕获普通响应和 SSE 流式响应
23
+ - 查看原始/处理后的 Headers 和 Request Diff
24
+ - 比较同一会话、同一协议的相邻请求
25
+ - 请求 Replay、日志 ZIP 导出和按会话/模型筛选
26
+ - 会话分组、Turn 边界、缓存 Token 趋势和 Token 汇总
27
+ - 提供商管理、双协议 URL、连接测试、导入与导出
28
+ - 记录客户端 PID、工作目录和项目目录,便于定位请求来源
29
+ - 内置 MCP Server,让 Coding Agent 直接查询日志和管理提供商
20
30
 
21
- | 优势 | 说明 |
22
- |------|------|
23
- | **透明代理、零侵入** | 只需设置环境变量即可拦截所有流量,无需修改 AI 编程工具本身 |
24
- | **结构化 API 可视化** | 交互式 JSON 树查看器,自动解析并渲染 Markdown 文本、思考块、工具调用块 |
25
- | **完整的 SSE 流式解析** | 捕获并重建每个流式事件,原始事件时间线一目了然 |
26
- | **Token 用量实时追踪** | 单请求 + 会话级 + 全局级 Token 统计 |
27
- | **多提供商自动路由** | 支持 Anthropic、OpenAI、DeepSeek、MiniMax、Qwen、ZhipuAI,自动识别格式和认证 |
28
- | **客户端进程追踪** | 自动关联 PID、工作目录、项目文件夹,区分请求来源 |
29
- | **持久化存储 + 导出** | 磁盘日志存储 + ZIP 导出,支持离线分析 |
31
+ ![Proxy Overview](docs/Proxy.png)
30
32
 
31
- ## Quick Start / 快速开始
33
+ ## 快速开始
32
34
 
33
35
  ### npm 安装
34
36
 
@@ -37,93 +39,145 @@ npm install -g @tonyclaw/llm-inspector
37
39
  llm-inspector
38
40
  ```
39
41
 
42
+ 启动后会自动打开浏览器。也可以使用:
43
+
44
+ ```bash
45
+ llm-inspector --no-open
46
+ llm-inspector --port 3000
47
+ llm-inspector --config-dir ./local-config
48
+ ```
49
+
40
50
  ### Docker
41
51
 
42
52
  ```bash
43
- cd docker && docker compose up -d
53
+ cd docker
54
+ docker compose up -d
44
55
  ```
45
56
 
46
57
  ### 源码运行
47
58
 
59
+ 需要安装 [Bun](https://bun.sh/)。
60
+
48
61
  ```bash
49
62
  bun install
50
63
  bun run dev
51
64
  ```
52
65
 
53
- 打开浏览器访问 http://localhost:25947 查看实时捕获的请求。
66
+ ## 配置提供商
67
+
68
+ 打开 Web UI,进入 **Settings** 添加提供商:
54
69
 
55
- ### 配置 AI 编程工具
70
+ 1. 填写提供商名称和 API Key。
71
+ 2. 添加一个或多个模型名称。代理使用模型名称匹配提供商。
72
+ 3. 按实际能力填写协议 URL:
73
+ - **Anthropic Base URL**:例如 `https://api.anthropic.com`
74
+ - **OpenAI Base URL**:例如 `https://api.openai.com`
75
+ 4. 选择认证方式:`Bearer` 或 `x-api-key`。
76
+ 5. 使用 Provider Test 分别验证流式和非流式请求。
56
77
 
57
- 配置你的 AI 编程工具,将 API 请求路由到 llm-inspector 代理:
78
+ 同一个提供商可以同时配置 Anthropic OpenAI URL。代理会根据客户端请求路径选择协议与上游地址,而不是根据请求 body 猜测格式。
79
+
80
+ ## 接入 AI 编码工具
81
+
82
+ ### Claude Code
83
+
84
+ macOS / Linux:
58
85
 
59
86
  ```bash
60
- # Claude Code
61
87
  ANTHROPIC_BASE_URL=http://localhost:25947/proxy claude
88
+ ```
62
89
 
63
- # OpenCode
64
- LLM_BASE_URL=http://localhost:25947/proxy opencode
90
+ Windows PowerShell:
65
91
 
66
- # Cursor, Cody 等
67
- ANTHROPIC_BASE_URL=http://localhost:25947/proxy <your-tool>
92
+ ```powershell
93
+ $env:ANTHROPIC_BASE_URL = "http://localhost:25947/proxy"
94
+ claude
68
95
  ```
69
96
 
70
- ### 验证代理工作正常
97
+ 如果 API Key 已保存在 llm-inspector 的提供商配置中,客户端令牌可以留空:
71
98
 
72
- 1. 启动 llm-inspector 后,打开浏览器访问 http://localhost:25947
73
- 2. 配置好环境变量后,向代理发送一个请求
74
- 3. 观察 Web UI 中是否实时显示捕获的请求和响应
99
+ ```powershell
100
+ $env:ANTHROPIC_AUTH_TOKEN = ""
101
+ ```
75
102
 
76
- ![Proxy Hello](docs/Proxy%20Hello.png)
103
+ ### OpenCode 和其他客户端
77
104
 
78
- ---
105
+ 不同客户端使用的环境变量名称不同。将其 Anthropic 或 OpenAI Base URL 设置为:
79
106
 
80
- ## MCP Server (Coding Agent Integration)
107
+ ```text
108
+ http://localhost:25947/proxy
109
+ ```
81
110
 
82
- llm-inspector ships with an embedded [Model Context Protocol](https://modelcontextprotocol.io)
83
- (MCP) server, mounted at `POST http://localhost:25947/api/mcp` on the same port as
84
- the Web UI. Any MCP-aware Coding Agent running on the same machine can
85
- discover and invoke 11 `inspector_*` tools to read captured traffic and
86
- manage provider configuration without a human round-trip.
111
+ 例如:
87
112
 
88
- ### Tool catalog (11 tools, all prefixed `inspector_`)
113
+ ```bash
114
+ LLM_BASE_URL=http://localhost:25947/proxy opencode
115
+ ```
116
+
117
+ 对于 Cursor、Cody 等工具,请在其设置中修改 API Base URL。
118
+
119
+ ## 直接发送请求
89
120
 
90
- **Read (6) cheap discovery of what was just sent**
121
+ 请先在 Settings 中配置与 `model` 匹配的提供商。
91
122
 
92
- | Tool | Purpose |
93
- |------|---------|
94
- | `inspector_list_logs` | Recent captured logs in reverse-chronological order, with parsed previews of the last user message and the assistant response. Default limit 3, hard-capped at 5. |
95
- | `inspector_get_log` | Full `CapturedLog` for a single id, including `rawRequestBody` and `responseText` with no truncation. Streaming chunks are NOT included. |
96
- | `inspector_get_log_chunks` | SSE streaming chunks for a single log, in order received. |
97
- | `inspector_list_sessions` | All session ids that have been observed in captured logs. |
98
- | `inspector_list_models` | Distinct model names seen across all logs. |
99
- | `inspector_list_providers` | All configured providers, including `apiKey` in plaintext. |
123
+ ### Anthropic 格式
124
+
125
+ ```bash
126
+ curl http://localhost:25947/proxy/v1/messages \
127
+ -H "content-type: application/json" \
128
+ -H "x-api-key: resolved-by-llm-inspector" \
129
+ -d '{
130
+ "model": "claude-sonnet-4-6",
131
+ "max_tokens": 128,
132
+ "messages": [{"role": "user", "content": "Hello"}]
133
+ }'
134
+ ```
135
+
136
+ ### OpenAI 格式
137
+
138
+ ```bash
139
+ curl http://localhost:25947/proxy/v1/chat/completions \
140
+ -H "content-type: application/json" \
141
+ -H "authorization: Bearer resolved-by-llm-inspector" \
142
+ -d '{
143
+ "model": "gpt-4o-mini",
144
+ "max_tokens": 128,
145
+ "messages": [{"role": "user", "content": "Hello"}]
146
+ }'
147
+ ```
100
148
 
101
- **Action (2)**
149
+ ## 使用查看器
102
150
 
103
- | Tool | Purpose |
104
- |------|---------|
105
- | `inspector_get_provider` | Full `ProviderConfig` for a single id, `apiKey` in plaintext. |
106
- | `inspector_replay_log` | Re-send a captured request body to its upstream and return the response summary. |
151
+ ### Simple / Full
107
152
 
108
- **Provider write (3) — mutate provider config**
153
+ - **Simple**:聚焦 Request 和解析后的 Response。
154
+ - **Full**:额外显示 Raw Headers、Headers、Raw Request、Raw Response 和 SSE chunks。
109
155
 
110
- | Tool | Purpose |
111
- |------|---------|
112
- | `inspector_add_provider` | Persist a new provider to `<dataDir>/providers.json`. |
113
- | `inspector_update_provider` | Patch-style update of an existing provider. |
114
- | `inspector_test_provider` | Run the UI's connectivity test against a provider. |
156
+ ### Thinking Answer
115
157
 
116
- **Explicitly NOT exposed** (kept UI-only by design):
158
+ 查看器按协议分别解析响应:
117
159
 
118
- - `delete_provider` irreversible.
119
- - `clear_log_cache` only clears the in-memory LRU; misleads agents that expect a full wipe.
120
- - `get_runtime_config` / `set_runtime_config` — runtime policy surface; UI is the source of truth.
160
+ - Anthropic:`content[].type === "thinking"``content[].type === "text"`
161
+ - OpenAI:`reasoning_content`、`thinking`、`think` `message.content`
121
162
 
122
- ### Connecting an MCP client
163
+ Thinking 和最终 Answer 会分区显示。如果响应因 `max_tokens` 提前结束且只返回 Thinking,界面只展示真实存在的 Thinking,不会生成不存在的 Answer。
123
164
 
124
- The server speaks **HTTP Streamable transport** (JSON-RPC over HTTP). The
125
- simplest way to point a client at it is to register the endpoint URL. For
126
- example, in Claude Code's `.mcp.json`:
165
+ ### Diff Replay
166
+
167
+ - **Diff with Raw**:比较代理处理前后的 Request 或 Headers。
168
+ - **Diff with Previous**:比较同一会话、同一协议中的相邻请求。
169
+ - **Replay**:使用当前提供商配置重新发送历史请求。
170
+ - **Export**:将捕获日志导出为 ZIP,供离线分析。
171
+
172
+ ## MCP Server
173
+
174
+ 内置 MCP Server 使用 HTTP Streamable transport:
175
+
176
+ ```text
177
+ POST http://localhost:25947/api/mcp
178
+ ```
179
+
180
+ Claude Code `.mcp.json` 示例:
127
181
 
128
182
  ```json
129
183
  {
@@ -136,49 +190,82 @@ example, in Claude Code's `.mcp.json`:
136
190
  }
137
191
  ```
138
192
 
139
- For raw clients that send JSON-RPC directly:
193
+ 提供 11 `inspector_*` 工具:
194
+
195
+ | 类型 | 工具 |
196
+ | --- | --- |
197
+ | 日志查询 | `inspector_list_logs`, `inspector_get_log`, `inspector_get_log_chunks` |
198
+ | 索引查询 | `inspector_list_sessions`, `inspector_list_models` |
199
+ | 提供商查询 | `inspector_list_providers`, `inspector_get_provider` |
200
+ | 操作 | `inspector_replay_log`, `inspector_test_provider` |
201
+ | 提供商写入 | `inspector_add_provider`, `inspector_update_provider` |
202
+
203
+ 完整说明见 [MCP Server 文档](docs/MCP-Server.md)。
204
+
205
+ > MCP 接口仅应在可信本机环境使用。提供商查询工具会返回明文 API Key,请勿将服务暴露到不可信网络。
206
+
207
+ ## 数据目录与环境变量
208
+
209
+ 默认数据目录:
210
+
211
+ - Windows:`%USERPROFILE%\.llm-inspector`
212
+ - macOS / Linux:`$HOME/.llm-inspector`
213
+
214
+ 常用环境变量:
215
+
216
+ | 变量 | 默认值 | 说明 |
217
+ | --- | --- | --- |
218
+ | `PORT` | `25947` | Web UI 和代理端口 |
219
+ | `LLM_INSPECTOR_DATA_DIR` | 系统默认目录 | providers、runtime config 等数据目录 |
220
+ | `LOG_DIR` | `<dataDir>/logs` | 捕获日志和运行日志目录 |
221
+ | `LOG_RETENTION_DAYS` | `7` | 日志保留天数 |
222
+ | `CHUNKS_DIR` | `<dataDir>/chunks` | SSE chunks 存储目录 |
223
+
224
+ 提供商 API Key 以明文 JSON 保存在本机数据目录中。请保护该目录,并避免在共享或不可信主机上运行服务。
225
+
226
+ ## HTTP API
227
+
228
+ | Endpoint | Method | 说明 |
229
+ | --- | --- | --- |
230
+ | `/api/health` | GET | 健康检查 |
231
+ | `/api/logs` | GET / DELETE | 查询或清空日志 |
232
+ | `/api/logs/:id` | GET | 获取完整日志 |
233
+ | `/api/logs/:id/chunks` | GET | 获取 SSE chunks |
234
+ | `/api/logs/:id/replay` | POST | 重放请求 |
235
+ | `/api/logs/stream` | GET | 实时日志更新 |
236
+ | `/api/sessions` | GET | 会话列表 |
237
+ | `/api/models` | GET | 模型列表 |
238
+ | `/api/providers` | GET / POST | 查询或添加提供商 |
239
+ | `/api/providers/:id` | GET / PUT / DELETE | 管理单个提供商 |
240
+ | `/api/providers/:id/test` | POST | 测试提供商连接 |
241
+ | `/api/mcp` | POST | MCP HTTP Streamable endpoint |
242
+
243
+ ## 开发与验证
244
+
245
+ ```bash
246
+ bun test
247
+ npm run typecheck
248
+ npm run lint
249
+ npm run format:check
250
+ npm run build
251
+ ```
252
+
253
+ 涉及代理或 UI 的改动还应启动开发服务器,并使用真实 AI 编码工具通过代理完成端到端验证:
140
254
 
141
255
  ```bash
142
- curl -X POST http://localhost:25947/api/mcp \
143
- -H 'content-type: application/json' \
144
- -H 'accept: application/json, text/event-stream' \
145
- -d '{
146
- "jsonrpc": "2.0",
147
- "id": 1,
148
- "method": "initialize",
149
- "params": {
150
- "protocolVersion": "2025-06-18",
151
- "capabilities": {},
152
- "clientInfo": { "name": "my-client", "version": "0.0.0" }
153
- }
154
- }'
256
+ bun run dev
257
+ ANTHROPIC_BASE_URL=http://localhost:25947/proxy claude
155
258
  ```
156
259
 
157
- ### Posture and limitations
158
-
159
- - **Localhost only, no auth.** The MCP endpoint inherits inspector's
160
- existing localhost binding. Any process that can call `/api/mcp` can also
161
- read `<dataDir>/providers.json` directly. Do not run inspector on a
162
- host where untrusted local users can reach it.
163
- - **Provider API keys are returned in plaintext** by `inspector_list_providers`
164
- and `inspector_get_provider`. This is intentional — redacting in MCP but
165
- not in the underlying JSON file would be performative security.
166
- - **Reflexive loop:** `inspector_list_logs` may include the agent's own
167
- recent `/proxy` calls. Filter by `clientPid` (your own PID) or by
168
- timestamp on the client side. The tool description surfaces this warning.
169
- - **List limits are hardcoded** at default 3, max 5. Not user-configurable.
170
- - **Deferred to v1.1** (not in this change): MCP Resources for logs
171
- (`mcp://llm-inspector/log/{id}`), notifications/subscriptions for live
172
- log push, filtering out reflexive-loop entries server-side, full-text
173
- or time-range search, MCP-level auth.
174
-
175
- ---
176
-
177
- ## Documentation / 文档目录
178
-
179
- - [特性 (Features)](docs/Features.md) - 核心功能介绍
180
- - [安装 (Installation)](docs/Installation.md) - 安装指南
181
- - [使用 (Usage)](docs/Usage.md) - 详细使用说明
182
- - [架构 (Architecture)](docs/Architecture.md) - 系统架构
183
- - [开发 (Development)](docs/Development.md) - 开发指南
184
- - [MCP Server](docs/MCP-Server.md) - 把 llm-inspector 当作 MCP 工具接入 Coding Agent
260
+ ## 更多文档
261
+
262
+ - [功能介绍](docs/Features.md)
263
+ - [安装指南](docs/Installation.md)
264
+ - [使用说明](docs/Usage.md)
265
+ - [架构说明](docs/Architecture.md)
266
+ - [开发指南](docs/Development.md)
267
+ - [MCP Server](docs/MCP-Server.md)
268
+
269
+ ## License
270
+
271
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonyclaw/llm-inspector",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "type": "module",
5
5
  "description": "LLM API proxy inspector — captures and displays requests/responses from AI coding tools in a web UI",
6
6
  "license": "MIT",
package/src/cli.ts CHANGED
@@ -126,6 +126,7 @@ console.log(``);
126
126
  console.log(`Route AI coding tools through the proxy:`);
127
127
  console.log(` Claude Code: ANTHROPIC_BASE_URL=${url}/proxy claude`);
128
128
  console.log(` OpenCode: LLM_BASE_URL=${url}/proxy opencode`);
129
+ console.log(` MiMo Code: OPENAI_BASE_URL=${url}/proxy mimo`);
129
130
  console.log(` Direct HTTP: curl ${url}/proxy/v1/messages -d '{"model":"...","messages":[...]}'`);
130
131
  console.log(``);
131
132
  console.log(`Routing environment variables:`);