llmpt 1.3.2 → 1.3.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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,125 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.3.4 (2026-06-16)
|
|
4
|
+
|
|
5
|
+
### 修复
|
|
6
|
+
- Response Assistant:非流式响应中 `message.tool_calls` 现在正确提取并以 `tool_use` 块显示在 Response 区域
|
|
7
|
+
- Markdown 渲染一致性:System Prompt / Messages / Response 全部使用相同字体(去掉 `sans` 差异),Thinking 统一用 `compact`(pre-wrap)模式避免 `<p>` margin 累积
|
|
8
|
+
- `ThinkingBlock` / `ThinkingSection` 展开时统一走 `compact` 路径(与 `TextPane` 行为对齐)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## v1.3.3 (2026-06-16)
|
|
13
|
+
|
|
14
|
+
### 其他
|
|
15
|
+
- 版本号修正(内部版本,无功能变更)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## v1.3.2 (2026-06-16)
|
|
20
|
+
|
|
21
|
+
### 修复
|
|
22
|
+
- 清除所有残留 Ollama 相关文档内容(AGENTS.md、README.md、docs/)
|
|
23
|
+
- AGENTS.md 新增「发布版本必须同步更新 CHANGELOG」规则
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## v1.3.1 (2026-06-16)
|
|
28
|
+
|
|
29
|
+
### 修复
|
|
30
|
+
- 清除旧版构建产物中残留的 `dist/server/providers/ollama.*` 文件
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## v1.3.0 (2026-06-16)
|
|
35
|
+
|
|
36
|
+
### 变更
|
|
37
|
+
- **移除 Ollama 支持**:删除 `OllamaProvider`,去掉 `/api/chat`、`/api/generate`、`/api/tags` 路由,清理 types / loader / routes 中所有 ollama 引用
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## v1.2.8 (2026-06-15)
|
|
42
|
+
|
|
43
|
+
### 新增
|
|
44
|
+
- `llmpt claude` 模式下启动后自动打开浏览器 Dashboard
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## v1.2.7 (2026-06-15)
|
|
49
|
+
|
|
50
|
+
### 修复
|
|
51
|
+
- `llmpt claude` 模式下静默所有后续 `console.log`,避免污染 Claude Code TUI 界面
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## v1.2.6 (2026-06-15)
|
|
56
|
+
|
|
57
|
+
### 修复
|
|
58
|
+
- `claude --settings` 只接受文件路径,改回临时文件方案(文件名含 PID 避免冲突,claude 退出后自动删除)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## v1.2.5 (2026-06-15)
|
|
63
|
+
|
|
64
|
+
### 新增
|
|
65
|
+
- 启动时检查端口占用(同时探测 IPv4/IPv6),占用时打印 `netstat`/`lsof` 查找命令后退出
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## v1.2.4 (2026-06-15)
|
|
70
|
+
|
|
71
|
+
### 修复
|
|
72
|
+
- `llmpt claude` 现在先启动 LPT 服务,再 spawn Claude Code;Claude 退出后服务一并关闭
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## v1.2.3 (2026-06-15)
|
|
77
|
+
|
|
78
|
+
### 新增
|
|
79
|
+
- `llmpt claude [...args]` 子命令:通过 `--settings` 临时文件注入 `ANTHROPIC_BASE_URL`,让 Claude Code 流量过代理
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## v1.2.2 (2026-06-15)
|
|
84
|
+
|
|
85
|
+
### 修复
|
|
86
|
+
- Auth header 透传:provider 未配置 `apiKey` 时,将请求中的 `x-api-key` / `authorization` 转发给上游
|
|
87
|
+
- 同时透传 `anthropic-*` 头(如 `anthropic-beta`)
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## v1.2.1 (2026-06-15)
|
|
92
|
+
|
|
93
|
+
### 修复
|
|
94
|
+
- Anthropic 非流式响应 token 解析:使用 `input_tokens`/`output_tokens` 而非 OpenAI 字段名
|
|
95
|
+
- Anthropic 流式 SSE 解析:处理 `content_block_delta` 事件(`text_delta`/`thinking_delta`)
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## v1.2.0 (2026-06-15)
|
|
100
|
+
|
|
101
|
+
### 修复
|
|
102
|
+
- 流式响应错误状态:上游返回 4xx/5xx 时不再走 SSE 路径,统一进入 error 分支记录
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## v1.1.9 (2026-06-15)
|
|
107
|
+
|
|
108
|
+
### 变更
|
|
109
|
+
- `.env.example` 所有值改为注释状态,用户需主动填入才能生效
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## v1.1.3 (2026-06-15)
|
|
114
|
+
|
|
115
|
+
### 新增
|
|
116
|
+
- `resolveEnvPath`:优先读 `cwd/.env`,其次 `AppData/llmpt/.env`,不存在时从 `.env.example` 自动生成
|
|
117
|
+
- `resolveConfigPath`:同优先级逻辑解析 `lpt.config.yaml`
|
|
118
|
+
- `traces` 目录若仍为默认 `./traces`,自动重定向到 `AppData/llmpt/traces`
|
|
119
|
+
- 启动日志精简为三行:🚀 启动中 / ✅ 已启动 / 📝 配置路径
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
3
123
|
## v1.1.0 (2026-06-15)
|
|
4
124
|
|
|
5
125
|
### 新增
|
|
@@ -22,7 +142,7 @@
|
|
|
22
142
|
初始发布。
|
|
23
143
|
|
|
24
144
|
- 单进程单端口代理服务(默认 19900)
|
|
25
|
-
- 支持 OpenAI / Anthropic
|
|
145
|
+
- 支持 OpenAI / Anthropic 两类 Provider
|
|
26
146
|
- 实时 WebSocket 推送,Trace 列表自动更新
|
|
27
147
|
- Trace 详情:System Prompt、Messages、Response、Tool Calls、Raw JSON
|
|
28
148
|
- Markdown 渲染(react-markdown + highlight.js 代码高亮)
|
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# LPT — LLM Proxy Trace
|
|
2
2
|
|
|
3
|
-
> 本地 LLM 代理工具,零侵入地拦截并可视化所有 OpenAI / Anthropic
|
|
3
|
+
> 本地 LLM 代理工具,零侵入地拦截并可视化所有 OpenAI / Anthropic API 调用
|
|
4
4
|
|
|
5
5
|
```
|
|
6
|
-
你的应用 ──► http://localhost:19900 ──► 真实 LLM Provider
|
|
6
|
+
你的应用 ──► http://localhost:19900/v1 ──► 真实 LLM Provider
|
|
7
7
|
│
|
|
8
8
|
▼
|
|
9
9
|
Web Dashboard(实时 Trace 监控)
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
## 功能特性
|
|
15
15
|
|
|
16
|
-
- **零侵入代理** — 只需把 `base_url` 改为 `http://localhost:19900`,无需修改任何应用代码
|
|
16
|
+
- **零侵入代理** — 只需把 `base_url` 改为 `http://localhost:19900/v1`,无需修改任何应用代码
|
|
17
17
|
- **实时流式追踪** — WebSocket 推送,实时响应
|
|
18
|
-
- **完整 Trace 记录** — 请求体、响应体、思考链(thinking)、Tool Call、Token
|
|
18
|
+
- **完整 Trace 记录** — 请求体、响应体、思考链(thinking)、Tool Call、Token 用量全记录,web 前端实时查看
|
|
19
19
|
- **Markdown 渲染** — 响应内容支持原文 / Markdown 双视图,代码块语法高亮
|
|
20
20
|
- **Token 用量统计** — 输入/输出/推理/缓存命中 Token 分项展示,实时速度统计
|
|
21
21
|
|
|
@@ -38,7 +38,7 @@ npm install -g llmpt
|
|
|
38
38
|
llmpt
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
启动后浏览器自动打开 web 前端 `http://localhost:19900`。
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
@@ -12,10 +12,10 @@ import{r as e}from"./rolldown-runtime-QTnfLwEv.js";import{C as t,D as n,E as r,O
|
|
|
12
12
|
|
|
13
13
|
`),children:(0,G.jsx)(`div`,{style:{display:`grid`,gap:`4px`},children:f.map((e,t)=>(0,G.jsx)(Ee,{toolCall:e},t))})}),d.length>0&&(0,G.jsx)(Y,{title:`Tools Definition`,defaultOpen:!1,badge:`${d.length}`,copyText:JSON.stringify(d,null,2),children:(0,G.jsx)(De,{tools:d})}),(0,G.jsx)(Y,{title:`Raw JSON`,defaultOpen:!1,copyText:JSON.stringify(e,null,2),children:(0,G.jsx)(Q,{data:e})})]})}function J(e){return e>=1e3?`${(e/1e3).toFixed(2)}s`:`${e}ms`}function ve({usage:e,duration:t,ttfb:n,isStreaming:r}){let i=(e?.cachedTokens||0)+(e?.cacheReadTokens||0)+(e?.cacheWriteTokens||0)>0;return(0,G.jsx)(`div`,{className:`token-usage-bar`,children:(0,G.jsx)(`div`,{className:`token-bar`,children:r?(0,G.jsxs)(`span`,{style:{display:`inline-flex`,alignItems:`center`,gap:`6px`,fontSize:`11px`,color:`var(--text-tertiary)`},children:[`接收中 `,(0,G.jsxs)(`span`,{className:`streaming-dots`,children:[(0,G.jsx)(`span`,{}),(0,G.jsx)(`span`,{}),(0,G.jsx)(`span`,{})]})]}):e?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{className:`tok-group`,children:(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-label`,children:`合计`}),(0,G.jsx)(`span`,{className:`tok-val`,style:{color:`var(--text)`,fontSize:`12px`},children:e.totalTokens.toLocaleString()})]})}),(0,G.jsxs)(`span`,{className:`tok-group`,children:[(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-arrow`,style:{color:`var(--blue)`},children:`↑`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.promptTokens.toLocaleString()})]}),(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-arrow`,style:{color:`var(--green)`},children:`↓`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.completionTokens.toLocaleString()})]}),(e.reasoningTokens||0)>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-dot`,style:{background:`var(--indigo)`}}),(0,G.jsx)(`span`,{className:`tok-label`,children:`推理`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.reasoningTokens.toLocaleString()})]})]}),i&&(0,G.jsxs)(`span`,{className:`tok-group`,children:[(e.cachedTokens||0)>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-dot`,style:{background:`var(--cyan)`}}),(0,G.jsx)(`span`,{className:`tok-label`,children:`缓存命中`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.cachedTokens.toLocaleString()})]}),(e.cacheReadTokens||0)>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-dot`,style:{background:`var(--cyan)`}}),(0,G.jsx)(`span`,{className:`tok-label`,children:`缓存读`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.cacheReadTokens.toLocaleString()})]}),(e.cacheWriteTokens||0)>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-dot`,style:{background:`var(--amber)`}}),(0,G.jsx)(`span`,{className:`tok-label`,children:`缓存写`}),(0,G.jsx)(`span`,{className:`tok-val`,children:e.cacheWriteTokens.toLocaleString()})]})]}),(0,G.jsxs)(`span`,{className:`tok-group`,children:[n>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-label`,children:`首字`}),(0,G.jsx)(`span`,{className:`tok-val`,children:J(n)})]}),t>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-label`,children:`耗时`}),(0,G.jsx)(`span`,{className:`tok-val`,children:J(t)})]}),t>0&&(e.completionTokens||0)>0&&(0,G.jsxs)(`span`,{className:`tok-item`,children:[(0,G.jsx)(`span`,{className:`tok-label`,children:`速度`}),(0,G.jsxs)(`span`,{className:`tok-val`,children:[Math.round(e.completionTokens/(t/1e3)),` tok/s`]})]})]})]}):(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`,fontSize:`11px`},children:`无 token 数据`})})})}function Y({title:e,defaultOpen:t,badge:n,copyText:r,children:i}){let[a,o]=(0,B.useState)(ge[e]??t);return(0,G.jsxs)(`div`,{className:`section`,children:[(0,G.jsxs)(`div`,{className:`section-header`,onClick:()=>{let t=!a;o(t),ge[e]=t},children:[(0,G.jsx)(`span`,{className:`chevron${a?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`title`,children:e}),n&&(0,G.jsx)(`span`,{className:`badge`,children:n}),r!==void 0&&r!==``&&(0,G.jsx)(Z,{getText:()=>r,className:`copy-btn`,stopPropagation:!0})]}),a&&(0,G.jsx)(`div`,{className:`section-body open`,children:i})]})}function ye({message:e,isStreaming:t}){let n=e.role,r=e.content,i=n===`assistant`,a=typeof r==`string`,[o,s]=(0,B.useState)(i?`markdown`:`raw`),c=()=>typeof r==`string`?r:Array.isArray(r)?r.map(e=>e.text||e.thinking||``).filter(Boolean).join(`
|
|
14
14
|
|
|
15
|
-
`):``,l=n===`user`?`user`:n===`assistant`?`assistant`:n===`system`||n===`developer`?`system`:n===`tool`?`tool_result`:``,u=e.tool_calls;e.tool_call_id;let d=a?r.trim().length>0:Array.isArray(r)&&r.length>0,f=a&&r.trim().length>0,[p,m]=(0,B.useState)(n===`tool`);return(0,G.jsxs)(`div`,{className:`msg ${l}`,children:[(0,G.jsxs)(`div`,{className:`msg-header-row`,children:[(0,G.jsxs)(`span`,{className:`msg-role msg-role-toggle`,onClick:()=>m(e=>!e),title:p?`展开`:`收起`,children:[(0,G.jsx)(`span`,{className:`msg-collapse-arrow${p?``:` open`}`,children:`▶`}),n.toUpperCase()]}),f&&(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginLeft:`8px`,marginTop:0,display:p?`none`:void 0},children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${o===`raw`?` active`:``}`,onClick:()=>s(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${o===`markdown`?` active`:``}`,onClick:()=>s(`markdown`),children:`渲染`})]}),(0,G.jsx)(`span`,{style:{marginLeft:`auto`},children:(0,G.jsx)(Z,{getText:c})})]}),!p&&(0,G.jsxs)(G.Fragment,{children:[a?(0,G.jsx)(Ce,{text:r,mode:o}):Array.isArray(r)?(0,G.jsx)(`div`,{children:r.map((e,n)=>(0,G.jsx)(xe,{block:e,isStreaming:t&&n===r.length-1},n))}):r?(0,G.jsx)(Q,{data:r}):null,u&&u.length>0&&(0,G.jsx)(`div`,{className:`msg-tool-calls`,children:u.map(e=>(0,G.jsx)(be,{toolCall:e},e.id))})]}),p&&(d||u&&u.length>0)&&(0,G.jsx)(`div`,{className:`msg-collapsed-hint`,children:[d?a?`${r.slice(0,60).replace(/\n/g,` `)}…`:`${r.length} 块`:``,u?.length?`${u.length} tool_call`:``].filter(Boolean).join(` · `)})]})}function be({toolCall:e}){let[t,n]=(0,B.useState)(!1),r=e.function.arguments;try{r=JSON.parse(e.function.arguments)}catch{}let i=typeof r==`object`&&r?Object.keys(r).length:0;return(0,G.jsxs)(`div`,{className:`tool-block`,children:[(0,G.jsxs)(`div`,{className:`tool-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsx)(`span`,{className:`tb-arrow${t?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`tb-name`,children:e.function.name}),!t&&i>0&&(0,G.jsxs)(`span`,{className:`tb-desc`,children:[`(`,i,` args)`]})]}),t&&(0,G.jsx)(`div`,{className:`tool-block-body open`,children:typeof r==`object`?(0,G.jsx)(Q,{data:r}):(0,G.jsx)(`pre`,{className:`text-raw`,children:String(r)})})]})}function xe({block:e,isStreaming:t}){let[n,r]=(0,B.useState)(`markdown`);if(e.type===`text`||e.type===`input_text`||e.type===`output_text`){let i=e.text||``;return(0,G.jsxs)(`div`,{className:`content-block`,children:[(0,G.jsx)(`div`,{className:`msg-header-row`,style:{marginBottom:`4px`},children:(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginTop:0},children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${n===`raw`?` active`:``}`,onClick:()=>r(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${n===`markdown`?` active`:``}`,onClick:()=>r(`markdown`),children:`渲染`})]})}),(0,G.jsx)(X,{text:i,mode:n,isStreaming:t})]})}return e.type===`thinking`?(0,G.jsx)(we,{content:e.thinking||``}):e.type===`tool_use`?(0,G.jsxs)(`div`,{className:`content-block block-framed`,children:[(0,G.jsxs)(`span`,{className:`tool-use-label`,children:[`⚙ `,e.name||`tool_use`]}),(0,G.jsx)(Q,{data:e.input})]}):e.type===`tool_result`?(0,G.jsxs)(`div`,{className:`content-block block-framed`,style:{borderColor:`var(--purple)`,background:`var(--purple-bg)`},children:[(0,G.jsxs)(`span`,{className:`tool-use-label`,style:{color:`var(--purple)`,background:`color-mix(in srgb, var(--purple) 15%, transparent)`},children:[`↩ tool_result: `,e.tool_use_id||``]}),(0,G.jsx)(`div`,{className:`content-block-text`,children:typeof e.text==`string`?e.text:(0,G.jsx)(Q,{data:e.text})})]}):(0,G.jsx)(Q,{data:e})}function X({text:e,mode:t,isStreaming:n,sans:r,compact:i,className:a}){return e?(0,G.jsxs)(`div`,{className:`text-pane${a?` `+a:``}`,children:[(0,G.jsx)(`pre`,{className:`text-raw${r?` sans`:``}`,style:{display:t===`raw`?void 0:`none`},children:e}),(0,G.jsx)(`div`,{style:{display:t===`markdown`?void 0:`none`},children:i?(0,G.jsx)(`div`,{className:`text-raw sans`,style:{whiteSpace:`pre-wrap`},children:e}):(0,G.jsx)(he,{text:e,isStreaming:n})})]}):null}function Se({text:e}){let[t,n]=(0,B.useState)(`raw`);return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginBottom:`6px`},children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${t===`raw`?` active`:``}`,onClick:()=>n(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${t===`markdown`?` active`:``}`,onClick:()=>n(`markdown`),children:`渲染`})]}),(0,G.jsx)(X,{text:e,mode:t,sans:!0})]})}function Ce({text:e,mode:t}){return e?(0,G.jsx)(X,{text:e,mode:t}):null}function we({content:e}){let[t,n]=(0,B.useState)(!1),[r,i]=(0,B.useState)(`raw`),a=e.slice(0,80).replace(/\n/g,` `);return(0,G.jsxs)(`div`,{className:`thinking-block content-block`,children:[(0,G.jsxs)(`div`,{className:`thinking-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsxs)(`span`,{className:`thinking-label`,children:[(0,G.jsx)(`span`,{className:`thinking-arrow`,children:t?`▼`:`▶`}),(0,G.jsx)(`span`,{children:`Thinking`})]}),t?(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginTop:0,marginLeft:`4px`},onClick:e=>e.stopPropagation(),children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`raw`?` active`:``}`,onClick:()=>i(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`markdown`?` active`:``}`,onClick:()=>i(`markdown`),children:`渲染`})]}):(0,G.jsxs)(`span`,{className:`thinking-preview`,children:[a,`…`]}),(0,G.jsx)(Z,{getText:()=>e,stopPropagation:!0,className:`copy-btn`})]}),t&&(0,G.jsx)(X,{text:e,mode:r,sans:!0})]})}function Te({content:e}){let[t,n]=(0,B.useState)(!1),[r,i]=(0,B.useState)(`raw`),a=e.slice(0,80).replace(/\n/g,` `);return(0,G.jsxs)(`div`,{className:`thinking-block content-block`,style:{marginBottom:`8px`},children:[(0,G.jsxs)(`div`,{className:`thinking-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsxs)(`span`,{className:`thinking-label`,children:[(0,G.jsx)(`span`,{className:`thinking-arrow`,children:t?`▼`:`▶`}),(0,G.jsx)(`span`,{children:`Thinking`})]}),t?(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginTop:0,marginLeft:`4px`},onClick:e=>e.stopPropagation(),children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`raw`?` active`:``}`,onClick:()=>i(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`markdown`?` active`:``}`,onClick:()=>i(`markdown`),children:`渲染`})]}):(0,G.jsxs)(`span`,{className:`thinking-preview`,children:[a,`…`]}),(0,G.jsx)(Z,{getText:()=>e,stopPropagation:!0,className:`copy-btn`})]}),t&&(0,G.jsx)(X,{text:e,mode:r,sans:!0})]})}function Ee({toolCall:e}){let[t,n]=(0,B.useState)(!1),r=typeof e.arguments==`object`?Object.keys(e.arguments||{}).length:0;return(0,G.jsxs)(`div`,{className:`tool-block`,children:[(0,G.jsxs)(`div`,{className:`tool-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsx)(`span`,{className:`tb-arrow${t?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`tb-name`,children:e.name}),!t&&r>0&&(0,G.jsxs)(`span`,{className:`tb-desc`,children:[`(`,r,` args)`]})]}),t&&(0,G.jsxs)(`div`,{className:`tool-block-body open`,children:[(0,G.jsx)(Q,{data:e.arguments}),e.result!==void 0&&(0,G.jsxs)(`div`,{style:{marginTop:`10px`,paddingTop:`10px`,borderTop:`1px solid var(--border-light)`},children:[(0,G.jsx)(`div`,{style:{fontSize:`11px`,fontWeight:600,color:`var(--orange)`,marginBottom:`6px`,textTransform:`uppercase`},children:`Result`}),(0,G.jsx)(Q,{data:e.result})]})]})]})}function De({tools:e}){return(0,G.jsx)(`div`,{style:{display:`grid`,gap:`4px`},children:e.map((e,t)=>(0,G.jsx)(Oe,{tool:e},t))})}function Oe({tool:e}){let[t,n]=(0,B.useState)(!1),r=e.function||e,i=r.name||e.name||`unknown`,a=r.description||e.description||``,o=r.parameters||e.input_schema||e.parameters,s=o?.required||[],c=o?.properties||{};return(0,G.jsxs)(`div`,{className:`tool-block`,children:[(0,G.jsxs)(`div`,{className:`tool-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsx)(`span`,{className:`tb-arrow${t?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`tb-name`,children:i}),(0,G.jsx)(`span`,{className:`tb-desc`,children:a})]}),t&&(0,G.jsxs)(`div`,{className:`tool-block-body open`,children:[a&&(0,G.jsx)(`div`,{className:`tb-full-desc`,children:a}),Object.keys(c).length>0?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`tb-params-title`,children:`Parameters`}),Object.entries(c).map(([e,t])=>(0,G.jsxs)(`div`,{className:`tb-param`,children:[(0,G.jsxs)(`div`,{className:`tb-param-row1`,children:[(0,G.jsx)(`span`,{className:`tb-pname`,children:e}),t.type&&(0,G.jsx)(`span`,{className:`tb-ptype`,children:t.type}),s.includes(e)&&(0,G.jsx)(`span`,{className:`tb-prequired`,children:`required`})]}),t.description&&(0,G.jsx)(`div`,{className:`tb-pdesc`,children:t.description})]},e))]}):o?(0,G.jsx)(Q,{data:o}):null]})]})}function Z({getText:e,className:n=`copy-btn`,stopPropagation:i=!1}){let[a,o]=(0,B.useState)(!1);return(0,G.jsx)(`button`,{className:`${n}${a?` copied`:``}`,onClick:async t=>{i&&t.stopPropagation();try{await navigator.clipboard.writeText(e()),o(!0),setTimeout(()=>o(!1),1500)}catch{}},"data-tip":`复制`,children:a?(0,G.jsx)(r,{size:10}):(0,G.jsx)(t,{size:10})})}var ke=0;function Q({data:e}){return ke=0,(0,G.jsx)(`div`,{className:`json-view`,children:$(e,0)})}var Ae=new Set([`chunks`,`headers`,`tools`]);function $(e,t,n){if(t>50)return(0,G.jsx)(`span`,{className:`json-punct`,children:`…`});if(e===null)return(0,G.jsx)(`span`,{className:`jnull`,children:`null`});if(e===void 0)return(0,G.jsx)(`span`,{className:`jnull`,children:`undefined`});if(typeof e==`boolean`)return(0,G.jsx)(`span`,{className:`jb`,children:String(e)});if(typeof e==`number`)return(0,G.jsx)(`span`,{className:`jn`,children:e});if(typeof e==`string`)return(0,G.jsxs)(`span`,{className:`js`,children:[`"`,e.length>300?e.slice(0,300)+`…`:e,`"`]});if(typeof e!=`object`)return(0,G.jsx)(`span`,{children:String(e)});let r=Array.isArray(e),i=r?e.map((e,t)=>[t,e]):Object.entries(e),a=i.length;if(a===0)return(0,G.jsx)(`span`,{className:`json-punct`,children:r?`[]`:`{}`});if(a<=3&&t<2&&i.every(([,e])=>typeof e!=`object`||!e)){let e=i.map(([e,n],i)=>(0,G.jsxs)(`span`,{children:[!r&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`span`,{className:`jk`,children:[`"`,String(e),`"`]}),(0,G.jsx)(`span`,{className:`json-punct`,children:`: `})]}),$(n,t+1),i<a-1&&(0,G.jsx)(`span`,{className:`json-punct`,children:`, `})]},String(e)));return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{className:`json-punct`,children:r?`[`:`{`}),e,(0,G.jsx)(`span`,{className:`json-punct`,children:r?`]`:`}`})]})}let o=`jt`+ ke++,s=`${a} ${r?`item`:`key`}${a===1?``:`s`}`,c=n!==void 0&&Ae.has(n),l=i.map(([e,n])=>(0,G.jsxs)(`div`,{className:`jt-line`,children:[!r&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`span`,{className:`jk`,children:[`"`,String(e),`"`]}),(0,G.jsx)(`span`,{className:`json-punct`,children:`: `})]}),$(n,t+1,String(e))]},String(e)));return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{className:`jt-toggle${c?``:` jt-open`}`,onClick:e=>je(e,o),style:{cursor:`pointer`},children:c?`▶`:`▼`}),(0,G.jsx)(`span`,{className:`json-punct`,children:r?`[`:`{`}),(0,G.jsxs)(`span`,{className:`jt-summary${c?` jt-show`:``}`,id:`${o}s`,children:[`… `,s]}),(0,G.jsx)(`div`,{className:`jt-children${c?``:` jt-open`}`,id:o,children:l}),(0,G.jsx)(`div`,{className:`jt-close${c?` jt-hidden`:``}`,id:`${o}c`,children:(0,G.jsx)(`span`,{className:`json-punct`,children:r?`]`:`}`})})]})}function je(e,t){e.stopPropagation();let n=document.getElementById(t),r=document.getElementById(t+`s`),i=document.getElementById(t+`c`),a=e.currentTarget;n&&(n.classList.contains(`jt-open`)?(n.classList.remove(`jt-open`),a.classList.remove(`jt-open`),a.textContent=`▶`,r?.classList.add(`jt-show`),i?.classList.add(`jt-hidden`)):(n.classList.add(`jt-open`),a.classList.add(`jt-open`),a.textContent=`▼`,r?.classList.remove(`jt-show`),i?.classList.remove(`jt-hidden`)))}function Me(e){let t=e.request.body,n=[];if(typeof t.system==`string`&&t.system.trim())n.push(t.system);else if(Array.isArray(t.system)){let e=t.system.map(e=>typeof e==`string`?e:e?.type===`text`&&e.text||``).filter(Boolean).join(`
|
|
15
|
+
`):``,l=n===`user`?`user`:n===`assistant`?`assistant`:n===`system`||n===`developer`?`system`:n===`tool`?`tool_result`:``,u=e.tool_calls;e.tool_call_id;let d=a?r.trim().length>0:Array.isArray(r)&&r.length>0,f=a&&r.trim().length>0,[p,m]=(0,B.useState)(n===`tool`);return(0,G.jsxs)(`div`,{className:`msg ${l}`,children:[(0,G.jsxs)(`div`,{className:`msg-header-row`,children:[(0,G.jsxs)(`span`,{className:`msg-role msg-role-toggle`,onClick:()=>m(e=>!e),title:p?`展开`:`收起`,children:[(0,G.jsx)(`span`,{className:`msg-collapse-arrow${p?``:` open`}`,children:`▶`}),n.toUpperCase()]}),f&&(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginLeft:`8px`,marginTop:0,display:p?`none`:void 0},children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${o===`raw`?` active`:``}`,onClick:()=>s(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${o===`markdown`?` active`:``}`,onClick:()=>s(`markdown`),children:`渲染`})]}),(0,G.jsx)(`span`,{style:{marginLeft:`auto`},children:(0,G.jsx)(Z,{getText:c})})]}),!p&&(0,G.jsxs)(G.Fragment,{children:[a?(0,G.jsx)(Ce,{text:r,mode:o}):Array.isArray(r)?(0,G.jsx)(`div`,{children:r.map((e,n)=>(0,G.jsx)(xe,{block:e,isStreaming:t&&n===r.length-1},n))}):r?(0,G.jsx)(Q,{data:r}):null,u&&u.length>0&&(0,G.jsx)(`div`,{className:`msg-tool-calls`,children:u.map(e=>(0,G.jsx)(be,{toolCall:e},e.id))})]}),p&&(d||u&&u.length>0)&&(0,G.jsx)(`div`,{className:`msg-collapsed-hint`,children:[d?a?`${r.slice(0,60).replace(/\n/g,` `)}…`:`${r.length} 块`:``,u?.length?`${u.length} tool_call`:``].filter(Boolean).join(` · `)})]})}function be({toolCall:e}){let[t,n]=(0,B.useState)(!1),r=e.function.arguments;try{r=JSON.parse(e.function.arguments)}catch{}let i=typeof r==`object`&&r?Object.keys(r).length:0;return(0,G.jsxs)(`div`,{className:`tool-block`,children:[(0,G.jsxs)(`div`,{className:`tool-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsx)(`span`,{className:`tb-arrow${t?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`tb-name`,children:e.function.name}),!t&&i>0&&(0,G.jsxs)(`span`,{className:`tb-desc`,children:[`(`,i,` args)`]})]}),t&&(0,G.jsx)(`div`,{className:`tool-block-body open`,children:typeof r==`object`?(0,G.jsx)(Q,{data:r}):(0,G.jsx)(`pre`,{className:`text-raw`,children:String(r)})})]})}function xe({block:e,isStreaming:t}){let[n,r]=(0,B.useState)(`markdown`);if(e.type===`text`||e.type===`input_text`||e.type===`output_text`){let i=e.text||``;return(0,G.jsxs)(`div`,{className:`content-block`,children:[(0,G.jsx)(`div`,{className:`msg-header-row`,style:{marginBottom:`4px`},children:(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginTop:0},children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${n===`raw`?` active`:``}`,onClick:()=>r(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${n===`markdown`?` active`:``}`,onClick:()=>r(`markdown`),children:`渲染`})]})}),(0,G.jsx)(X,{text:i,mode:n,isStreaming:t})]})}return e.type===`thinking`?(0,G.jsx)(we,{content:e.thinking||``}):e.type===`tool_use`?(0,G.jsxs)(`div`,{className:`content-block block-framed`,children:[(0,G.jsxs)(`span`,{className:`tool-use-label`,children:[`⚙ `,e.name||`tool_use`]}),(0,G.jsx)(Q,{data:e.input})]}):e.type===`tool_result`?(0,G.jsxs)(`div`,{className:`content-block block-framed`,style:{borderColor:`var(--purple)`,background:`var(--purple-bg)`},children:[(0,G.jsxs)(`span`,{className:`tool-use-label`,style:{color:`var(--purple)`,background:`color-mix(in srgb, var(--purple) 15%, transparent)`},children:[`↩ tool_result: `,e.tool_use_id||``]}),(0,G.jsx)(`div`,{className:`content-block-text`,children:typeof e.text==`string`?e.text:(0,G.jsx)(Q,{data:e.text})})]}):(0,G.jsx)(Q,{data:e})}function X({text:e,mode:t,isStreaming:n,sans:r,compact:i,className:a}){return e?(0,G.jsxs)(`div`,{className:`text-pane${a?` `+a:``}`,children:[(0,G.jsx)(`pre`,{className:`text-raw${r?` sans`:``}`,style:{display:t===`raw`?void 0:`none`},children:e}),(0,G.jsx)(`div`,{style:{display:t===`markdown`?void 0:`none`},children:i?(0,G.jsx)(`div`,{className:`text-raw sans`,style:{whiteSpace:`pre-wrap`},children:e}):(0,G.jsx)(he,{text:e,isStreaming:n})})]}):null}function Se({text:e}){let[t,n]=(0,B.useState)(`raw`);return(0,G.jsxs)(`div`,{children:[(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginBottom:`6px`},children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${t===`raw`?` active`:``}`,onClick:()=>n(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${t===`markdown`?` active`:``}`,onClick:()=>n(`markdown`),children:`渲染`})]}),(0,G.jsx)(X,{text:e,mode:t})]})}function Ce({text:e,mode:t}){return e?(0,G.jsx)(X,{text:e,mode:t}):null}function we({content:e}){let[t,n]=(0,B.useState)(!1),[r,i]=(0,B.useState)(`raw`),a=e.slice(0,80).replace(/\n/g,` `);return(0,G.jsxs)(`div`,{className:`thinking-block content-block`,children:[(0,G.jsxs)(`div`,{className:`thinking-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsxs)(`span`,{className:`thinking-label`,children:[(0,G.jsx)(`span`,{className:`thinking-arrow`,children:t?`▼`:`▶`}),(0,G.jsx)(`span`,{children:`Thinking`})]}),t?(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginTop:0,marginLeft:`4px`},onClick:e=>e.stopPropagation(),children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`raw`?` active`:``}`,onClick:()=>i(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`markdown`?` active`:``}`,onClick:()=>i(`markdown`),children:`渲染`})]}):(0,G.jsxs)(`span`,{className:`thinking-preview`,children:[a,`…`]}),(0,G.jsx)(Z,{getText:()=>e,stopPropagation:!0,className:`copy-btn`})]}),t&&(0,G.jsx)(X,{text:e,mode:r,compact:!0})]})}function Te({content:e}){let[t,n]=(0,B.useState)(!1),[r,i]=(0,B.useState)(`raw`),a=e.slice(0,80).replace(/\n/g,` `);return(0,G.jsxs)(`div`,{className:`thinking-block content-block`,style:{marginBottom:`8px`},children:[(0,G.jsxs)(`div`,{className:`thinking-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsxs)(`span`,{className:`thinking-label`,children:[(0,G.jsx)(`span`,{className:`thinking-arrow`,children:t?`▼`:`▶`}),(0,G.jsx)(`span`,{children:`Thinking`})]}),t?(0,G.jsxs)(`div`,{className:`text-toggle-bar`,style:{marginTop:0,marginLeft:`4px`},onClick:e=>e.stopPropagation(),children:[(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`raw`?` active`:``}`,onClick:()=>i(`raw`),children:`原文`}),(0,G.jsx)(`button`,{className:`text-toggle-btn${r===`markdown`?` active`:``}`,onClick:()=>i(`markdown`),children:`渲染`})]}):(0,G.jsxs)(`span`,{className:`thinking-preview`,children:[a,`…`]}),(0,G.jsx)(Z,{getText:()=>e,stopPropagation:!0,className:`copy-btn`})]}),t&&(0,G.jsx)(X,{text:e,mode:r,compact:!0})]})}function Ee({toolCall:e}){let[t,n]=(0,B.useState)(!1),r=typeof e.arguments==`object`?Object.keys(e.arguments||{}).length:0;return(0,G.jsxs)(`div`,{className:`tool-block`,children:[(0,G.jsxs)(`div`,{className:`tool-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsx)(`span`,{className:`tb-arrow${t?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`tb-name`,children:e.name}),!t&&r>0&&(0,G.jsxs)(`span`,{className:`tb-desc`,children:[`(`,r,` args)`]})]}),t&&(0,G.jsxs)(`div`,{className:`tool-block-body open`,children:[(0,G.jsx)(Q,{data:e.arguments}),e.result!==void 0&&(0,G.jsxs)(`div`,{style:{marginTop:`10px`,paddingTop:`10px`,borderTop:`1px solid var(--border-light)`},children:[(0,G.jsx)(`div`,{style:{fontSize:`11px`,fontWeight:600,color:`var(--orange)`,marginBottom:`6px`,textTransform:`uppercase`},children:`Result`}),(0,G.jsx)(Q,{data:e.result})]})]})]})}function De({tools:e}){return(0,G.jsx)(`div`,{style:{display:`grid`,gap:`4px`},children:e.map((e,t)=>(0,G.jsx)(Oe,{tool:e},t))})}function Oe({tool:e}){let[t,n]=(0,B.useState)(!1),r=e.function||e,i=r.name||e.name||`unknown`,a=r.description||e.description||``,o=r.parameters||e.input_schema||e.parameters,s=o?.required||[],c=o?.properties||{};return(0,G.jsxs)(`div`,{className:`tool-block`,children:[(0,G.jsxs)(`div`,{className:`tool-block-header`,onClick:()=>n(e=>!e),children:[(0,G.jsx)(`span`,{className:`tb-arrow${t?` open`:``}`,children:`▶`}),(0,G.jsx)(`span`,{className:`tb-name`,children:i}),(0,G.jsx)(`span`,{className:`tb-desc`,children:a})]}),t&&(0,G.jsxs)(`div`,{className:`tool-block-body open`,children:[a&&(0,G.jsx)(`div`,{className:`tb-full-desc`,children:a}),Object.keys(c).length>0?(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`tb-params-title`,children:`Parameters`}),Object.entries(c).map(([e,t])=>(0,G.jsxs)(`div`,{className:`tb-param`,children:[(0,G.jsxs)(`div`,{className:`tb-param-row1`,children:[(0,G.jsx)(`span`,{className:`tb-pname`,children:e}),t.type&&(0,G.jsx)(`span`,{className:`tb-ptype`,children:t.type}),s.includes(e)&&(0,G.jsx)(`span`,{className:`tb-prequired`,children:`required`})]}),t.description&&(0,G.jsx)(`div`,{className:`tb-pdesc`,children:t.description})]},e))]}):o?(0,G.jsx)(Q,{data:o}):null]})]})}function Z({getText:e,className:n=`copy-btn`,stopPropagation:i=!1}){let[a,o]=(0,B.useState)(!1);return(0,G.jsx)(`button`,{className:`${n}${a?` copied`:``}`,onClick:async t=>{i&&t.stopPropagation();try{await navigator.clipboard.writeText(e()),o(!0),setTimeout(()=>o(!1),1500)}catch{}},"data-tip":`复制`,children:a?(0,G.jsx)(r,{size:10}):(0,G.jsx)(t,{size:10})})}var ke=0;function Q({data:e}){return ke=0,(0,G.jsx)(`div`,{className:`json-view`,children:$(e,0)})}var Ae=new Set([`chunks`,`headers`,`tools`]);function $(e,t,n){if(t>50)return(0,G.jsx)(`span`,{className:`json-punct`,children:`…`});if(e===null)return(0,G.jsx)(`span`,{className:`jnull`,children:`null`});if(e===void 0)return(0,G.jsx)(`span`,{className:`jnull`,children:`undefined`});if(typeof e==`boolean`)return(0,G.jsx)(`span`,{className:`jb`,children:String(e)});if(typeof e==`number`)return(0,G.jsx)(`span`,{className:`jn`,children:e});if(typeof e==`string`)return(0,G.jsxs)(`span`,{className:`js`,children:[`"`,e.length>300?e.slice(0,300)+`…`:e,`"`]});if(typeof e!=`object`)return(0,G.jsx)(`span`,{children:String(e)});let r=Array.isArray(e),i=r?e.map((e,t)=>[t,e]):Object.entries(e),a=i.length;if(a===0)return(0,G.jsx)(`span`,{className:`json-punct`,children:r?`[]`:`{}`});if(a<=3&&t<2&&i.every(([,e])=>typeof e!=`object`||!e)){let e=i.map(([e,n],i)=>(0,G.jsxs)(`span`,{children:[!r&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`span`,{className:`jk`,children:[`"`,String(e),`"`]}),(0,G.jsx)(`span`,{className:`json-punct`,children:`: `})]}),$(n,t+1),i<a-1&&(0,G.jsx)(`span`,{className:`json-punct`,children:`, `})]},String(e)));return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{className:`json-punct`,children:r?`[`:`{`}),e,(0,G.jsx)(`span`,{className:`json-punct`,children:r?`]`:`}`})]})}let o=`jt`+ ke++,s=`${a} ${r?`item`:`key`}${a===1?``:`s`}`,c=n!==void 0&&Ae.has(n),l=i.map(([e,n])=>(0,G.jsxs)(`div`,{className:`jt-line`,children:[!r&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`span`,{className:`jk`,children:[`"`,String(e),`"`]}),(0,G.jsx)(`span`,{className:`json-punct`,children:`: `})]}),$(n,t+1,String(e))]},String(e)));return(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`span`,{className:`jt-toggle${c?``:` jt-open`}`,onClick:e=>je(e,o),style:{cursor:`pointer`},children:c?`▶`:`▼`}),(0,G.jsx)(`span`,{className:`json-punct`,children:r?`[`:`{`}),(0,G.jsxs)(`span`,{className:`jt-summary${c?` jt-show`:``}`,id:`${o}s`,children:[`… `,s]}),(0,G.jsx)(`div`,{className:`jt-children${c?``:` jt-open`}`,id:o,children:l}),(0,G.jsx)(`div`,{className:`jt-close${c?` jt-hidden`:``}`,id:`${o}c`,children:(0,G.jsx)(`span`,{className:`json-punct`,children:r?`]`:`}`})})]})}function je(e,t){e.stopPropagation();let n=document.getElementById(t),r=document.getElementById(t+`s`),i=document.getElementById(t+`c`),a=e.currentTarget;n&&(n.classList.contains(`jt-open`)?(n.classList.remove(`jt-open`),a.classList.remove(`jt-open`),a.textContent=`▶`,r?.classList.add(`jt-show`),i?.classList.add(`jt-hidden`)):(n.classList.add(`jt-open`),a.classList.add(`jt-open`),a.textContent=`▼`,r?.classList.remove(`jt-show`),i?.classList.remove(`jt-hidden`)))}function Me(e){let t=e.request.body,n=[];if(typeof t.system==`string`&&t.system.trim())n.push(t.system);else if(Array.isArray(t.system)){let e=t.system.map(e=>typeof e==`string`?e:e?.type===`text`&&e.text||``).filter(Boolean).join(`
|
|
16
16
|
|
|
17
17
|
`);e.trim()&&n.push(e)}let r=e.request.body.messages||[];for(let e of r)if(e.role===`system`||e.role===`developer`){let t=typeof e.content==`string`?e.content:Array.isArray(e.content)?e.content.map(e=>e.text||``).filter(Boolean).join(`
|
|
18
18
|
|
|
19
19
|
`):``;t.trim()&&n.push(t)}return n.length?n.join(`
|
|
20
20
|
|
|
21
|
-
`):null}function Ne(e){let t=e.response.body;if(!t)return null;if(t.choices&&Array.isArray(t.choices)&&t.choices.length>0){let e=t.choices[0].message;if(e){let t=e.content,n=e.reasoning_content,r=[];if(n&&r.push({type:`thinking`,thinking:n}),typeof t==`string`&&t.trim()?r.push({type:`text`,text:t}):Array.isArray(t)?r.push(...t):t!=null&&r.push({type:`text`,text:JSON.stringify(t)}),r.length===1&&r[0].type===`text`)return r[0].text||null;if(r.length>0)return r}return null}if(t.content&&Array.isArray(t.content)){let e=t.content;return e.length===1&&e[0].type===`text`?e[0].text||null:e}return typeof t.text==`string`?t.text:null}function Pe({onClose:e}){let[t,n]=(0,B.useState)([]),[r,i]=(0,B.useState)(!0),[a,o]=(0,B.useState)(null);(0,B.useEffect)(()=>{Promise.all([W.getProviders().then(n).catch(()=>{}),W.getConfig().then(e=>o(e.proxy?.port??null)).catch(()=>{})]).finally(()=>i(!1))},[]);let s=a??(window.location.port?Number(window.location.port):void 0);return(0,G.jsxs)(`div`,{className:`p-5 space-y-5`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`h2`,{className:`text-base font-semibold`,children:`设置`}),(0,G.jsx)(`button`,{onClick:e,style:{color:`var(--text-tertiary)`},children:(0,G.jsx)(v,{size:16})})]}),(0,G.jsxs)(`div`,{className:`rounded-lg p-3`,style:{background:`var(--bg)`,border:`1px solid var(--border)`},children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium mb-2`,children:`代理服务器`}),(0,G.jsxs)(`div`,{className:`grid grid-cols-2 gap-x-4 gap-y-1.5 text-xs`,children:[(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`监听端口`}),(0,G.jsx)(`span`,{className:`font-mono`,style:{color:`var(--blue)`},children:s}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`OpenAI Base URL`}),(0,G.jsxs)(`span`,{className:`font-mono`,style:{color:`var(--blue)`},children:[`http://localhost:`,s,`/v1`]}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`Anthropic Base URL`}),(0,G.jsxs)(`span`,{className:`font-mono`,style:{color:`var(--blue)`},children:[`http://localhost:`,s]})]})]}),(0,G.jsxs)(`div`,{className:`rounded-lg p-3`,style:{background:`var(--bg)`,border:`1px solid var(--border)`},children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium mb-1`,children:`上游服务商`}),(0,G.jsxs)(`p`,{className:`text-[11px] mb-3`,style:{color:`var(--text-tertiary)`},children:[`修改请编辑项目根目录的 `,(0,G.jsx)(`code`,{className:`font-mono px-1 py-0.5 rounded`,style:{background:`var(--bg-code)`},children:`.env`}),` 文件后重启服务`]}),r?(0,G.jsx)(`div`,{className:`text-sm`,style:{color:`var(--text-tertiary)`},children:`加载中…`}):t.length===0?(0,G.jsxs)(`div`,{className:`text-sm italic`,style:{color:`var(--text-tertiary)`},children:[`未检测到已配置的 Provider。请在 `,(0,G.jsx)(`code`,{className:`font-mono`,children:`.env`}),` 中设置 `,(0,G.jsx)(`code`,{className:`font-mono`,children:`OPENAI_API_KEY`}),` 等变量。`]}):(0,G.jsx)(`div`,{className:`space-y-1.5`,children:t.map(e=>(0,G.jsxs)(`div`,{className:`flex items-center gap-3 px-3 py-2 rounded`,style:{border:`1px solid var(--border)`},children:[(0,G.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full flex-shrink-0`,style:{background:`var(--green)`}}),(0,G.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,G.jsx)(`div`,{className:`text-sm font-medium capitalize`,children:e.type}),(0,G.jsx)(`div`,{className:`text-[11px] font-mono truncate`,style:{color:`var(--text-tertiary)`},children:e.baseUrl})]}),e.apiKey&&(0,G.jsx)(`span`,{className:`text-[11px] font-mono flex-shrink-0`,style:{color:`var(--text-tertiary)`},children:e.apiKey})]},e.type))})]})]})}function Fe({open:e,title:t,message:n,confirmText:r=`确认`,cancelText:i=`取消`,danger:a=!1,onConfirm:o,onCancel:s}){let c=(0,B.useRef)(null);return(0,B.useEffect)(()=>{e&&c.current?.focus()},[e]),(0,B.useEffect)(()=>{if(!e)return;let t=e=>{e.key===`Escape`&&s(),e.key===`Enter`&&o()};return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[e,o,s]),e?(0,G.jsx)(`div`,{className:`confirm-overlay`,onClick:s,children:(0,G.jsxs)(`div`,{className:`confirm-dialog`,onClick:e=>e.stopPropagation(),children:[(0,G.jsx)(`div`,{className:`confirm-icon-row`,children:(0,G.jsx)(`span`,{className:`confirm-icon${a?` danger`:``}`,children:(0,G.jsx)(m,{size:20})})}),(0,G.jsx)(`div`,{className:`confirm-title`,children:t}),(0,G.jsx)(`div`,{className:`confirm-message`,children:n}),(0,G.jsxs)(`div`,{className:`confirm-actions`,children:[(0,G.jsx)(`button`,{className:`confirm-btn cancel`,onClick:s,children:i}),(0,G.jsx)(`button`,{ref:c,className:`confirm-btn ok${a?` danger`:``}`,onClick:o,children:r})]})]})}):null}function Ie(){try{let e=localStorage.getItem(`lpt-theme`);if(e===`dark`||e===`light`)return e}catch{}return window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}function Le(e){document.documentElement.setAttribute(`data-theme`,e);try{localStorage.setItem(`lpt-theme`,e)}catch{}}function Re(){let[e,t]=(0,B.useState)([]),[r,i]=(0,B.useState)(null),[a,c]=(0,B.useState)(null),[u,d]=(0,B.useState)(``),[f,m]=(0,B.useState)(`all`),[h,g]=(0,B.useState)(!1),[_,y]=(0,B.useState)({open:!1,title:``,message:``,onConfirm:()=>{}}),b=(e,t,n)=>{y({open:!0,title:e,message:t,onConfirm:n})},x=()=>y(e=>({...e,open:!1})),[ee,te]=(0,B.useState)(!0),[S,ne]=(0,B.useState)(Ie),[C,w]=(0,B.useState)(320),T=(0,B.useRef)(!1),E=(0,B.useRef)(0),D=(0,B.useRef)(0),[O,k]=(0,B.useState)(!1),A=(0,B.useRef)(null),[j,M]=(0,B.useState)(!1);(0,B.useEffect)(()=>{Le(S)},[S]),(0,B.useEffect)(()=>{if(!O)return;let e=e=>{A.current&&!A.current.contains(e.target)&&k(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[O]);let oe=()=>ne(e=>e===`light`?`dark`:`light`),N=e.find(e=>e.id===a)||null,P=(0,B.useCallback)(async()=>{try{let[e,n]=await Promise.all([W.getTraces({keyword:u||void 0,limit:200}),W.getStats()]);t(e.traces),i(n)}catch{}finally{te(!1)}},[u]),se=(0,B.useCallback)(e=>{if(e.type===`trace:new`){let n=e.data;u||t(e=>[n,...e]),i(e=>e&&{...e,totalCalls:e.totalCalls+1})}else if(e.type===`trace:update`||e.type===`trace:complete`){let n=e.data;t(e=>e.map(e=>e.id===n.id?{...e,...n}:e)),e.type===`trace:complete`&&W.getStats().then(i).catch(()=>{})}},[u]),{connected:F}=ue({url:`ws://${window.location.host}/ws`,onEvent:se});(0,B.useEffect)(()=>{P()},[P]);let I=e=>{T.current=!0,E.current=e.clientX,D.current=C,document.body.style.userSelect=`none`,document.body.style.cursor=`col-resize`;let t=e=>{if(!T.current)return;let t=e.clientX-E.current;w(Math.max(240,Math.min(600,D.current+t)))},n=()=>{T.current=!1,document.body.style.userSelect=``,document.body.style.cursor=``,document.removeEventListener(`mousemove`,t),document.removeEventListener(`mouseup`,n)};document.addEventListener(`mousemove`,t),document.addEventListener(`mouseup`,n)},ce=r?.totalTokens??0,le=r?.totalCalls??0,L=r?.avgDuration??0,R=e.reduce((e,t)=>e+(t.usage?.promptTokens||0),0),z=e.reduce((e,t)=>e+(t.usage?.completionTokens||0),0),V=f===`all`?e:e.filter(e=>e.status===f),H={};for(let t of e)t.model&&(H[t.model]=(H[t.model]||0)+1);let U=Object.entries(H).sort((e,t)=>t[1]-e[1]).slice(0,4),[q,fe]=(0,B.useState)(null),pe=q?V.filter(e=>e.model===q):V,me=e.filter(e=>e.status===`error`).length;return(0,G.jsxs)(`div`,{className:`flex flex-col h-screen overflow-hidden`,style:{background:`var(--bg)`,color:`var(--text)`},children:[(0,G.jsxs)(`header`,{className:`flex items-center gap-3 px-4 flex-shrink-0`,style:{background:`var(--bg-card)`,borderBottom:`1px solid var(--border)`,height:`52px`,zIndex:10},children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,G.jsx)(n,{size:18,style:{color:`var(--blue)`}}),(0,G.jsx)(`span`,{className:`text-sm font-semibold tracking-tight`,children:`LPT`})]}),(0,G.jsx)(`div`,{className:`w-px h-5 flex-shrink-0`,style:{background:`var(--border)`}}),(0,G.jsxs)(`div`,{className:`flex items-center gap-3 text-[11px] flex-shrink-0`,style:{color:`var(--text-tertiary)`},children:[(0,G.jsxs)(`span`,{children:[`请求 `,(0,G.jsx)(`b`,{className:`font-mono`,style:{color:`var(--text-secondary)`},children:le})]}),(0,G.jsxs)(`span`,{children:[`Tokens `,(0,G.jsx)(`b`,{className:`font-mono`,style:{color:`var(--text-secondary)`},children:ce.toLocaleString()})]}),R>0&&(0,G.jsxs)(`span`,{className:`flex items-center gap-0.5 font-mono`,style:{color:`var(--blue)`},children:[`↑`,(0,G.jsx)(`b`,{children:R.toLocaleString()})]}),z>0&&(0,G.jsxs)(`span`,{className:`flex items-center gap-0.5 font-mono`,style:{color:`var(--green)`},children:[`↓`,(0,G.jsx)(`b`,{children:z.toLocaleString()})]}),L>0&&(0,G.jsxs)(`span`,{children:[`均 `,L,`ms`]})]}),U.length>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`w-px h-5 flex-shrink-0`,style:{background:`var(--border)`}}),(0,G.jsx)(`div`,{className:`flex items-center gap-1.5 overflow-hidden flex-1`,children:U.map(([e,t])=>(0,G.jsxs)(`button`,{onClick:()=>fe(t=>t===e?null:e),className:`filter-chip${q===e?` active`:``}`,children:[e.split(`/`).pop()||e,(0,G.jsx)(`span`,{className:`chip-count`,children:t})]},e))})]}),(0,G.jsxs)(`div`,{className:`ml-auto flex items-center gap-2 flex-shrink-0`,children:[(0,G.jsxs)(`span`,{className:`text-[11px] flex items-center gap-1`,style:{color:F?`var(--green)`:`var(--red)`},children:[(0,G.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full`,style:{background:F?`var(--green)`:`var(--red)`}}),F?`实时`:`离线`]}),(0,G.jsx)(K,{content:`从磁盘加载历史记录`,children:(0,G.jsxs)(`button`,{onClick:async()=>{M(!0),await W.reloadTraces().catch(()=>{}),await P(),M(!1)},className:`flex items-center gap-1 text-[11px] px-2 py-1 rounded border transition-colors`,style:{borderColor:`var(--border)`,color:j?`var(--blue)`:`var(--text-tertiary)`},disabled:j,children:[(0,G.jsx)(l,{size:12,style:{animation:j?`spin 1s linear infinite`:`none`}}),`加载记录`]})}),(0,G.jsxs)(`div`,{ref:A,className:`clear-split-btn`,style:{position:`relative`},children:[(0,G.jsx)(K,{content:`清空当前会话`,children:(0,G.jsxs)(`button`,{onClick:()=>{W.deleteTraces(!1).then(()=>{t([]),P()}),k(!1)},className:`clear-split-main`,children:[(0,G.jsx)(p,{size:12}),` 清空`]})}),(0,G.jsx)(`button`,{onClick:()=>k(e=>!e),className:`clear-split-arrow`,"aria-label":`更多清空选项`,children:(0,G.jsx)(o,{size:11})}),O&&(0,G.jsxs)(`div`,{className:`clear-dropdown`,children:[(0,G.jsx)(`div`,{className:`clear-dropdown-label`,children:`选择清空方式`}),(0,G.jsxs)(`button`,{className:`clear-dropdown-item`,onClick:()=>{W.deleteTraces(!1).then(()=>{t([]),P()}),k(!1)},children:[(0,G.jsx)(p,{size:12}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`div`,{className:`clear-dropdown-item-title`,children:`清空当前会话`}),(0,G.jsx)(`div`,{className:`clear-dropdown-item-desc`,children:`仅清内存,文件保留,重启可恢复`})]})]}),(0,G.jsxs)(`button`,{className:`clear-dropdown-item danger`,onClick:()=>{k(!1),b(`永久删除所有文件`,`将永久删除所有 Trace 文件,无法恢复,确认吗?`,()=>{W.deleteTraces(!0).then(()=>{t([]),P()})})},children:[(0,G.jsx)(p,{size:12}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`div`,{className:`clear-dropdown-item-title`,children:`永久删除所有文件`}),(0,G.jsx)(`div`,{className:`clear-dropdown-item-desc`,children:`删除磁盘 JSONL,重启不恢复`})]})]})]})]}),(0,G.jsx)(K,{content:S===`dark`?`浅色模式`:`深色模式`,children:(0,G.jsx)(`button`,{onClick:oe,className:`flex items-center justify-center w-7 h-7 rounded border transition-colors`,style:{borderColor:`var(--border)`,color:`var(--text-tertiary)`},children:S===`dark`?(0,G.jsx)(s,{size:13}):(0,G.jsx)(ie,{size:13})})}),(0,G.jsx)(K,{content:`Provider 与代理设置`,children:(0,G.jsxs)(`button`,{onClick:()=>g(!h),className:`flex items-center gap-1 text-[11px] px-2 py-1 rounded border transition-colors`,style:{borderColor:h?`var(--blue)`:`var(--border)`,color:h?`var(--blue)`:`var(--text-tertiary)`,background:h?`var(--blue-bg)`:`transparent`},children:[(0,G.jsx)(re,{size:12}),` 设置`]})})]})]}),(0,G.jsxs)(`div`,{className:`flex flex-1 overflow-hidden relative`,children:[h&&(0,G.jsx)(`div`,{className:`absolute inset-0 z-20 flex`,style:{background:`rgba(0,0,0,0.15)`},onClick:()=>g(!1),children:(0,G.jsx)(`div`,{className:`ml-auto h-full overflow-auto`,style:{width:`420px`,background:`var(--bg-card)`,borderLeft:`1px solid var(--border)`},onClick:e=>e.stopPropagation(),children:(0,G.jsx)(Pe,{onClose:()=>g(!1)})})}),(0,G.jsxs)(`div`,{className:`flex flex-col flex-shrink-0`,style:{width:`${C}px`,borderRight:`1px solid var(--border)`,background:`var(--bg-card)`},children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-2 border-b flex-shrink-0`,style:{borderColor:`var(--border)`},children:[(0,G.jsx)(ae,{size:13,style:{color:`var(--text-tertiary)`}}),(0,G.jsx)(`input`,{type:`text`,placeholder:`搜索消息、模型…`,value:u,onChange:e=>d(e.target.value),className:`flex-1 text-xs bg-transparent outline-none`,style:{color:`var(--text)`}}),u&&(0,G.jsx)(`button`,{onClick:()=>d(``),style:{color:`var(--text-tertiary)`},children:(0,G.jsx)(v,{size:11})}),(0,G.jsx)(`div`,{className:`flex items-center gap-1 flex-shrink-0`,children:[`all`,`error`].map(t=>(0,G.jsx)(K,{content:t===`all`?`显示全部请求`:`只看报错的请求`,placement:`bottom`,delay:400,children:(0,G.jsx)(`button`,{onClick:()=>m(t),className:`filter-chip${f===t?` active`:``}`,style:{fontSize:`10px`,padding:`2px 7px`},children:t===`all`?`全部 ${e.length}`:`✕ ${me}`})},t))})]}),(0,G.jsx)(de,{traces:pe,activeId:a,onSelect:e=>{c(e)},loading:ee,onDeleteFile:n=>{b(`删除记录文件`,`删除 ${n}?此操作不可恢复。`,async()=>{await W.deleteTraceFile(n).catch(()=>{}),t(e=>e.filter(e=>e.sourceFile!==n)),a&&e.find(e=>e.id===a)?.sourceFile===n&&c(null)})}})]}),(0,G.jsx)(`div`,{className:`resize-handle`,onMouseDown:I,style:{background:`var(--border-light)`}}),(0,G.jsx)(`div`,{className:`flex-1 overflow-auto detail-scroll`,style:{background:`var(--bg)`},children:N?(0,G.jsx)(_e,{trace:N},N.id):(0,G.jsx)(ze,{hasTraces:e.length>0})})]}),(0,G.jsx)(Fe,{open:_.open,title:_.title,message:_.message,confirmText:`确认删除`,danger:!0,onConfirm:()=>{x(),_.onConfirm()},onCancel:x})]})}function ze({hasTraces:e}){let t=window.location.port,r=t?`http://localhost:${t}`:window.location.origin;return e?(0,G.jsx)(`div`,{className:`flex items-center justify-center h-full text-sm`,style:{color:`var(--text-tertiary)`},children:`选择左侧一条请求查看详情`}):(0,G.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-5`,style:{padding:`40px`},children:[(0,G.jsx)(n,{size:28,style:{color:`var(--border)`}}),(0,G.jsxs)(`div`,{style:{textAlign:`center`},children:[(0,G.jsx)(`div`,{style:{fontSize:`15px`,fontWeight:600,color:`var(--text)`,marginBottom:`6px`},children:`等待第一条请求…`}),(0,G.jsx)(`div`,{style:{fontSize:`12px`,color:`var(--text-tertiary)`,lineHeight:1.7},children:`设置以下环境变量,所有兼容 OpenAI 接口的工具都会被自动拦截`})]}),(0,G.jsxs)(`div`,{style:{background:`var(--bg-code)`,border:`1px solid var(--border)`,borderRadius:`8px`,padding:`14px 18px`,fontFamily:`var(--mono)`,fontSize:`13px`,lineHeight:2,minWidth:`340px`},children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{style:{color:`var(--amber)`},children:`export `}),(0,G.jsx)(`span`,{style:{color:`var(--blue)`},children:`OPENAI_BASE_URL`}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`=`}),(0,G.jsxs)(`span`,{style:{color:`var(--green)`},children:[`"`,r,`/v1"`]})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{style:{color:`var(--amber)`},children:`export `}),(0,G.jsx)(`span`,{style:{color:`var(--blue)`},children:`OPENAI_API_KEY`}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`=`}),(0,G.jsx)(`span`,{style:{color:`var(--green)`},children:`"any-key"`}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`,fontStyle:`italic`,fontSize:`11px`},children:` # 代理不验证 key`})]})]}),(0,G.jsxs)(`div`,{style:{fontSize:`11px`,color:`var(--text-tertiary)`,lineHeight:1.7,textAlign:`center`,maxWidth:`320px`},children:[`上游 API 地址在 `,(0,G.jsx)(`span`,{style:{color:`var(--blue)`},children:`设置`}),` 中配置。 记录内容包括流式输出、工具调用与思考过程。`]})]})}V.createRoot(document.getElementById(`root`)).render((0,G.jsx)(B.StrictMode,{children:(0,G.jsx)(Re,{})}));
|
|
21
|
+
`):null}function Ne(e){let t=e.response.body;if(!t)return null;if(t.choices&&Array.isArray(t.choices)&&t.choices.length>0){let e=t.choices[0].message;if(e){let t=e.content,n=e.reasoning_content,r=e.tool_calls,i=[];if(n&&i.push({type:`thinking`,thinking:n}),typeof t==`string`&&t.trim()?i.push({type:`text`,text:t}):Array.isArray(t)?i.push(...t):t!=null&&i.push({type:`text`,text:JSON.stringify(t)}),r&&r.length>0)for(let e of r){let t=e.function.arguments;try{t=JSON.parse(e.function.arguments)}catch{}i.push({type:`tool_use`,id:e.id,name:e.function.name,input:t})}if(i.length===1&&i[0].type===`text`)return i[0].text||null;if(i.length>0)return i}return null}if(t.content&&Array.isArray(t.content)){let e=t.content;return e.length===1&&e[0].type===`text`?e[0].text||null:e}return typeof t.text==`string`?t.text:null}function Pe({onClose:e}){let[t,n]=(0,B.useState)([]),[r,i]=(0,B.useState)(!0),[a,o]=(0,B.useState)(null);(0,B.useEffect)(()=>{Promise.all([W.getProviders().then(n).catch(()=>{}),W.getConfig().then(e=>o(e.proxy?.port??null)).catch(()=>{})]).finally(()=>i(!1))},[]);let s=a??(window.location.port?Number(window.location.port):void 0);return(0,G.jsxs)(`div`,{className:`p-5 space-y-5`,children:[(0,G.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,G.jsx)(`h2`,{className:`text-base font-semibold`,children:`设置`}),(0,G.jsx)(`button`,{onClick:e,style:{color:`var(--text-tertiary)`},children:(0,G.jsx)(v,{size:16})})]}),(0,G.jsxs)(`div`,{className:`rounded-lg p-3`,style:{background:`var(--bg)`,border:`1px solid var(--border)`},children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium mb-2`,children:`代理服务器`}),(0,G.jsxs)(`div`,{className:`grid grid-cols-2 gap-x-4 gap-y-1.5 text-xs`,children:[(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`监听端口`}),(0,G.jsx)(`span`,{className:`font-mono`,style:{color:`var(--blue)`},children:s}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`OpenAI Base URL`}),(0,G.jsxs)(`span`,{className:`font-mono`,style:{color:`var(--blue)`},children:[`http://localhost:`,s,`/v1`]}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`Anthropic Base URL`}),(0,G.jsxs)(`span`,{className:`font-mono`,style:{color:`var(--blue)`},children:[`http://localhost:`,s]})]})]}),(0,G.jsxs)(`div`,{className:`rounded-lg p-3`,style:{background:`var(--bg)`,border:`1px solid var(--border)`},children:[(0,G.jsx)(`h3`,{className:`text-sm font-medium mb-1`,children:`上游服务商`}),(0,G.jsxs)(`p`,{className:`text-[11px] mb-3`,style:{color:`var(--text-tertiary)`},children:[`修改请编辑项目根目录的 `,(0,G.jsx)(`code`,{className:`font-mono px-1 py-0.5 rounded`,style:{background:`var(--bg-code)`},children:`.env`}),` 文件后重启服务`]}),r?(0,G.jsx)(`div`,{className:`text-sm`,style:{color:`var(--text-tertiary)`},children:`加载中…`}):t.length===0?(0,G.jsxs)(`div`,{className:`text-sm italic`,style:{color:`var(--text-tertiary)`},children:[`未检测到已配置的 Provider。请在 `,(0,G.jsx)(`code`,{className:`font-mono`,children:`.env`}),` 中设置 `,(0,G.jsx)(`code`,{className:`font-mono`,children:`OPENAI_API_KEY`}),` 等变量。`]}):(0,G.jsx)(`div`,{className:`space-y-1.5`,children:t.map(e=>(0,G.jsxs)(`div`,{className:`flex items-center gap-3 px-3 py-2 rounded`,style:{border:`1px solid var(--border)`},children:[(0,G.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full flex-shrink-0`,style:{background:`var(--green)`}}),(0,G.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,G.jsx)(`div`,{className:`text-sm font-medium capitalize`,children:e.type}),(0,G.jsx)(`div`,{className:`text-[11px] font-mono truncate`,style:{color:`var(--text-tertiary)`},children:e.baseUrl})]}),e.apiKey&&(0,G.jsx)(`span`,{className:`text-[11px] font-mono flex-shrink-0`,style:{color:`var(--text-tertiary)`},children:e.apiKey})]},e.type))})]})]})}function Fe({open:e,title:t,message:n,confirmText:r=`确认`,cancelText:i=`取消`,danger:a=!1,onConfirm:o,onCancel:s}){let c=(0,B.useRef)(null);return(0,B.useEffect)(()=>{e&&c.current?.focus()},[e]),(0,B.useEffect)(()=>{if(!e)return;let t=e=>{e.key===`Escape`&&s(),e.key===`Enter`&&o()};return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[e,o,s]),e?(0,G.jsx)(`div`,{className:`confirm-overlay`,onClick:s,children:(0,G.jsxs)(`div`,{className:`confirm-dialog`,onClick:e=>e.stopPropagation(),children:[(0,G.jsx)(`div`,{className:`confirm-icon-row`,children:(0,G.jsx)(`span`,{className:`confirm-icon${a?` danger`:``}`,children:(0,G.jsx)(m,{size:20})})}),(0,G.jsx)(`div`,{className:`confirm-title`,children:t}),(0,G.jsx)(`div`,{className:`confirm-message`,children:n}),(0,G.jsxs)(`div`,{className:`confirm-actions`,children:[(0,G.jsx)(`button`,{className:`confirm-btn cancel`,onClick:s,children:i}),(0,G.jsx)(`button`,{ref:c,className:`confirm-btn ok${a?` danger`:``}`,onClick:o,children:r})]})]})}):null}function Ie(){try{let e=localStorage.getItem(`lpt-theme`);if(e===`dark`||e===`light`)return e}catch{}return window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}function Le(e){document.documentElement.setAttribute(`data-theme`,e);try{localStorage.setItem(`lpt-theme`,e)}catch{}}function Re(){let[e,t]=(0,B.useState)([]),[r,i]=(0,B.useState)(null),[a,c]=(0,B.useState)(null),[u,d]=(0,B.useState)(``),[f,m]=(0,B.useState)(`all`),[h,g]=(0,B.useState)(!1),[_,y]=(0,B.useState)({open:!1,title:``,message:``,onConfirm:()=>{}}),b=(e,t,n)=>{y({open:!0,title:e,message:t,onConfirm:n})},x=()=>y(e=>({...e,open:!1})),[ee,te]=(0,B.useState)(!0),[S,ne]=(0,B.useState)(Ie),[C,w]=(0,B.useState)(320),T=(0,B.useRef)(!1),E=(0,B.useRef)(0),D=(0,B.useRef)(0),[O,k]=(0,B.useState)(!1),A=(0,B.useRef)(null),[j,M]=(0,B.useState)(!1);(0,B.useEffect)(()=>{Le(S)},[S]),(0,B.useEffect)(()=>{if(!O)return;let e=e=>{A.current&&!A.current.contains(e.target)&&k(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[O]);let oe=()=>ne(e=>e===`light`?`dark`:`light`),N=e.find(e=>e.id===a)||null,P=(0,B.useCallback)(async()=>{try{let[e,n]=await Promise.all([W.getTraces({keyword:u||void 0,limit:200}),W.getStats()]);t(e.traces),i(n)}catch{}finally{te(!1)}},[u]),se=(0,B.useCallback)(e=>{if(e.type===`trace:new`){let n=e.data;u||t(e=>[n,...e]),i(e=>e&&{...e,totalCalls:e.totalCalls+1})}else if(e.type===`trace:update`||e.type===`trace:complete`){let n=e.data;t(e=>e.map(e=>e.id===n.id?{...e,...n}:e)),e.type===`trace:complete`&&W.getStats().then(i).catch(()=>{})}},[u]),{connected:F}=ue({url:`ws://${window.location.host}/ws`,onEvent:se});(0,B.useEffect)(()=>{P()},[P]);let I=e=>{T.current=!0,E.current=e.clientX,D.current=C,document.body.style.userSelect=`none`,document.body.style.cursor=`col-resize`;let t=e=>{if(!T.current)return;let t=e.clientX-E.current;w(Math.max(240,Math.min(600,D.current+t)))},n=()=>{T.current=!1,document.body.style.userSelect=``,document.body.style.cursor=``,document.removeEventListener(`mousemove`,t),document.removeEventListener(`mouseup`,n)};document.addEventListener(`mousemove`,t),document.addEventListener(`mouseup`,n)},ce=r?.totalTokens??0,le=r?.totalCalls??0,L=r?.avgDuration??0,R=e.reduce((e,t)=>e+(t.usage?.promptTokens||0),0),z=e.reduce((e,t)=>e+(t.usage?.completionTokens||0),0),V=f===`all`?e:e.filter(e=>e.status===f),H={};for(let t of e)t.model&&(H[t.model]=(H[t.model]||0)+1);let U=Object.entries(H).sort((e,t)=>t[1]-e[1]).slice(0,4),[q,fe]=(0,B.useState)(null),pe=q?V.filter(e=>e.model===q):V,me=e.filter(e=>e.status===`error`).length;return(0,G.jsxs)(`div`,{className:`flex flex-col h-screen overflow-hidden`,style:{background:`var(--bg)`,color:`var(--text)`},children:[(0,G.jsxs)(`header`,{className:`flex items-center gap-3 px-4 flex-shrink-0`,style:{background:`var(--bg-card)`,borderBottom:`1px solid var(--border)`,height:`52px`,zIndex:10},children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2 flex-shrink-0`,children:[(0,G.jsx)(n,{size:18,style:{color:`var(--blue)`}}),(0,G.jsx)(`span`,{className:`text-sm font-semibold tracking-tight`,children:`LPT`})]}),(0,G.jsx)(`div`,{className:`w-px h-5 flex-shrink-0`,style:{background:`var(--border)`}}),(0,G.jsxs)(`div`,{className:`flex items-center gap-3 text-[11px] flex-shrink-0`,style:{color:`var(--text-tertiary)`},children:[(0,G.jsxs)(`span`,{children:[`请求 `,(0,G.jsx)(`b`,{className:`font-mono`,style:{color:`var(--text-secondary)`},children:le})]}),(0,G.jsxs)(`span`,{children:[`Tokens `,(0,G.jsx)(`b`,{className:`font-mono`,style:{color:`var(--text-secondary)`},children:ce.toLocaleString()})]}),R>0&&(0,G.jsxs)(`span`,{className:`flex items-center gap-0.5 font-mono`,style:{color:`var(--blue)`},children:[`↑`,(0,G.jsx)(`b`,{children:R.toLocaleString()})]}),z>0&&(0,G.jsxs)(`span`,{className:`flex items-center gap-0.5 font-mono`,style:{color:`var(--green)`},children:[`↓`,(0,G.jsx)(`b`,{children:z.toLocaleString()})]}),L>0&&(0,G.jsxs)(`span`,{children:[`均 `,L,`ms`]})]}),U.length>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsx)(`div`,{className:`w-px h-5 flex-shrink-0`,style:{background:`var(--border)`}}),(0,G.jsx)(`div`,{className:`flex items-center gap-1.5 overflow-hidden flex-1`,children:U.map(([e,t])=>(0,G.jsxs)(`button`,{onClick:()=>fe(t=>t===e?null:e),className:`filter-chip${q===e?` active`:``}`,children:[e.split(`/`).pop()||e,(0,G.jsx)(`span`,{className:`chip-count`,children:t})]},e))})]}),(0,G.jsxs)(`div`,{className:`ml-auto flex items-center gap-2 flex-shrink-0`,children:[(0,G.jsxs)(`span`,{className:`text-[11px] flex items-center gap-1`,style:{color:F?`var(--green)`:`var(--red)`},children:[(0,G.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full`,style:{background:F?`var(--green)`:`var(--red)`}}),F?`实时`:`离线`]}),(0,G.jsx)(K,{content:`从磁盘加载历史记录`,children:(0,G.jsxs)(`button`,{onClick:async()=>{M(!0),await W.reloadTraces().catch(()=>{}),await P(),M(!1)},className:`flex items-center gap-1 text-[11px] px-2 py-1 rounded border transition-colors`,style:{borderColor:`var(--border)`,color:j?`var(--blue)`:`var(--text-tertiary)`},disabled:j,children:[(0,G.jsx)(l,{size:12,style:{animation:j?`spin 1s linear infinite`:`none`}}),`加载记录`]})}),(0,G.jsxs)(`div`,{ref:A,className:`clear-split-btn`,style:{position:`relative`},children:[(0,G.jsx)(K,{content:`清空当前会话`,children:(0,G.jsxs)(`button`,{onClick:()=>{W.deleteTraces(!1).then(()=>{t([]),P()}),k(!1)},className:`clear-split-main`,children:[(0,G.jsx)(p,{size:12}),` 清空`]})}),(0,G.jsx)(`button`,{onClick:()=>k(e=>!e),className:`clear-split-arrow`,"aria-label":`更多清空选项`,children:(0,G.jsx)(o,{size:11})}),O&&(0,G.jsxs)(`div`,{className:`clear-dropdown`,children:[(0,G.jsx)(`div`,{className:`clear-dropdown-label`,children:`选择清空方式`}),(0,G.jsxs)(`button`,{className:`clear-dropdown-item`,onClick:()=>{W.deleteTraces(!1).then(()=>{t([]),P()}),k(!1)},children:[(0,G.jsx)(p,{size:12}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`div`,{className:`clear-dropdown-item-title`,children:`清空当前会话`}),(0,G.jsx)(`div`,{className:`clear-dropdown-item-desc`,children:`仅清内存,文件保留,重启可恢复`})]})]}),(0,G.jsxs)(`button`,{className:`clear-dropdown-item danger`,onClick:()=>{k(!1),b(`永久删除所有文件`,`将永久删除所有 Trace 文件,无法恢复,确认吗?`,()=>{W.deleteTraces(!0).then(()=>{t([]),P()})})},children:[(0,G.jsx)(p,{size:12}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`div`,{className:`clear-dropdown-item-title`,children:`永久删除所有文件`}),(0,G.jsx)(`div`,{className:`clear-dropdown-item-desc`,children:`删除磁盘 JSONL,重启不恢复`})]})]})]})]}),(0,G.jsx)(K,{content:S===`dark`?`浅色模式`:`深色模式`,children:(0,G.jsx)(`button`,{onClick:oe,className:`flex items-center justify-center w-7 h-7 rounded border transition-colors`,style:{borderColor:`var(--border)`,color:`var(--text-tertiary)`},children:S===`dark`?(0,G.jsx)(s,{size:13}):(0,G.jsx)(ie,{size:13})})}),(0,G.jsx)(K,{content:`Provider 与代理设置`,children:(0,G.jsxs)(`button`,{onClick:()=>g(!h),className:`flex items-center gap-1 text-[11px] px-2 py-1 rounded border transition-colors`,style:{borderColor:h?`var(--blue)`:`var(--border)`,color:h?`var(--blue)`:`var(--text-tertiary)`,background:h?`var(--blue-bg)`:`transparent`},children:[(0,G.jsx)(re,{size:12}),` 设置`]})})]})]}),(0,G.jsxs)(`div`,{className:`flex flex-1 overflow-hidden relative`,children:[h&&(0,G.jsx)(`div`,{className:`absolute inset-0 z-20 flex`,style:{background:`rgba(0,0,0,0.15)`},onClick:()=>g(!1),children:(0,G.jsx)(`div`,{className:`ml-auto h-full overflow-auto`,style:{width:`420px`,background:`var(--bg-card)`,borderLeft:`1px solid var(--border)`},onClick:e=>e.stopPropagation(),children:(0,G.jsx)(Pe,{onClose:()=>g(!1)})})}),(0,G.jsxs)(`div`,{className:`flex flex-col flex-shrink-0`,style:{width:`${C}px`,borderRight:`1px solid var(--border)`,background:`var(--bg-card)`},children:[(0,G.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-2 border-b flex-shrink-0`,style:{borderColor:`var(--border)`},children:[(0,G.jsx)(ae,{size:13,style:{color:`var(--text-tertiary)`}}),(0,G.jsx)(`input`,{type:`text`,placeholder:`搜索消息、模型…`,value:u,onChange:e=>d(e.target.value),className:`flex-1 text-xs bg-transparent outline-none`,style:{color:`var(--text)`}}),u&&(0,G.jsx)(`button`,{onClick:()=>d(``),style:{color:`var(--text-tertiary)`},children:(0,G.jsx)(v,{size:11})}),(0,G.jsx)(`div`,{className:`flex items-center gap-1 flex-shrink-0`,children:[`all`,`error`].map(t=>(0,G.jsx)(K,{content:t===`all`?`显示全部请求`:`只看报错的请求`,placement:`bottom`,delay:400,children:(0,G.jsx)(`button`,{onClick:()=>m(t),className:`filter-chip${f===t?` active`:``}`,style:{fontSize:`10px`,padding:`2px 7px`},children:t===`all`?`全部 ${e.length}`:`✕ ${me}`})},t))})]}),(0,G.jsx)(de,{traces:pe,activeId:a,onSelect:e=>{c(e)},loading:ee,onDeleteFile:n=>{b(`删除记录文件`,`删除 ${n}?此操作不可恢复。`,async()=>{await W.deleteTraceFile(n).catch(()=>{}),t(e=>e.filter(e=>e.sourceFile!==n)),a&&e.find(e=>e.id===a)?.sourceFile===n&&c(null)})}})]}),(0,G.jsx)(`div`,{className:`resize-handle`,onMouseDown:I,style:{background:`var(--border-light)`}}),(0,G.jsx)(`div`,{className:`flex-1 overflow-auto detail-scroll`,style:{background:`var(--bg)`},children:N?(0,G.jsx)(_e,{trace:N},N.id):(0,G.jsx)(ze,{hasTraces:e.length>0})})]}),(0,G.jsx)(Fe,{open:_.open,title:_.title,message:_.message,confirmText:`确认删除`,danger:!0,onConfirm:()=>{x(),_.onConfirm()},onCancel:x})]})}function ze({hasTraces:e}){let t=window.location.port,r=t?`http://localhost:${t}`:window.location.origin;return e?(0,G.jsx)(`div`,{className:`flex items-center justify-center h-full text-sm`,style:{color:`var(--text-tertiary)`},children:`选择左侧一条请求查看详情`}):(0,G.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-5`,style:{padding:`40px`},children:[(0,G.jsx)(n,{size:28,style:{color:`var(--border)`}}),(0,G.jsxs)(`div`,{style:{textAlign:`center`},children:[(0,G.jsx)(`div`,{style:{fontSize:`15px`,fontWeight:600,color:`var(--text)`,marginBottom:`6px`},children:`等待第一条请求…`}),(0,G.jsx)(`div`,{style:{fontSize:`12px`,color:`var(--text-tertiary)`,lineHeight:1.7},children:`设置以下环境变量,所有兼容 OpenAI 接口的工具都会被自动拦截`})]}),(0,G.jsxs)(`div`,{style:{background:`var(--bg-code)`,border:`1px solid var(--border)`,borderRadius:`8px`,padding:`14px 18px`,fontFamily:`var(--mono)`,fontSize:`13px`,lineHeight:2,minWidth:`340px`},children:[(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{style:{color:`var(--amber)`},children:`export `}),(0,G.jsx)(`span`,{style:{color:`var(--blue)`},children:`OPENAI_BASE_URL`}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`=`}),(0,G.jsxs)(`span`,{style:{color:`var(--green)`},children:[`"`,r,`/v1"`]})]}),(0,G.jsxs)(`div`,{children:[(0,G.jsx)(`span`,{style:{color:`var(--amber)`},children:`export `}),(0,G.jsx)(`span`,{style:{color:`var(--blue)`},children:`OPENAI_API_KEY`}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`},children:`=`}),(0,G.jsx)(`span`,{style:{color:`var(--green)`},children:`"any-key"`}),(0,G.jsx)(`span`,{style:{color:`var(--text-tertiary)`,fontStyle:`italic`,fontSize:`11px`},children:` # 代理不验证 key`})]})]}),(0,G.jsxs)(`div`,{style:{fontSize:`11px`,color:`var(--text-tertiary)`,lineHeight:1.7,textAlign:`center`,maxWidth:`320px`},children:[`上游 API 地址在 `,(0,G.jsx)(`span`,{style:{color:`var(--blue)`},children:`设置`}),` 中配置。 记录内容包括流式输出、工具调用与思考过程。`]})]})}V.createRoot(document.getElementById(`root`)).render((0,G.jsx)(B.StrictMode,{children:(0,G.jsx)(Re,{})}));
|
package/dist/web/index.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>LLM Proxy Trace</title>
|
|
7
7
|
|
|
8
8
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%233b82f6' stroke-width='2'><circle cx='12' cy='12' r='10'/><path d='M12 6v6l4 2'/></svg>" />
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-lc_TM1FG.js"></script>
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-QTnfLwEv.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/markdown-DsSlw-Z4.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/react-vendor-BnH7jZBV.js">
|