From f4172fea381dcb8bb6a420aea1b0c5f1a2495a3b Mon Sep 17 00:00:00 2001 From: xiaoxixi Date: Thu, 16 Jul 2026 17:49:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0tui=E5=92=8Cwebui=E7=9A=84?= =?UTF-8?q?=E9=99=84=E4=BB=B6=E6=94=B6=E5=8F=91=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=9C=A8=E6=B6=88=E6=81=AF=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 1 + Cargo.toml | 4 +- README.md | 7 +- docs/ARCHITECTURE.md | 3 + docs/FILE_TRANSFER_DESIGN.md | 374 ++++++++++++++++++++++ resources/templates/config.example.json | 10 +- src/agent/agent_loop.rs | 117 ++++++- src/agent/media_handler.rs | 4 + src/channels/cli_chat.rs | 186 ++++++++++- src/client/mod.rs | 36 ++- src/client/tui/app.rs | 37 ++- src/client/tui/components/chat_history.rs | 6 + src/client/tui/components/help_popup.rs | 2 + src/client/tui/components/input_area.rs | 6 +- src/client/tui/event.rs | 243 +++++++++++++- src/client/tui/ui.rs | 27 ++ src/config/mod.rs | 64 ++++ src/gateway/http.rs | 249 +++++++++++++- src/gateway/mod.rs | 30 +- src/gateway/uploads.rs | 310 ++++++++++++++++++ src/gateway/ws.rs | 5 + src/protocol.rs | 49 ++- src/session/messenger.rs | 7 +- src/storage/mod.rs | 34 ++ tests/test_request_format.rs | 22 ++ tmp.jpg | Bin 0 -> 247595 bytes webui/src/pages/ChatPage.svelte | 140 +++++++- webui/src/styles.css | 13 +- 28 files changed, 1926 insertions(+), 60 deletions(-) create mode 100644 docs/FILE_TRANSFER_DESIGN.md create mode 100644 src/gateway/uploads.rs create mode 100644 tmp.jpg diff --git a/AGENTS.md b/AGENTS.md index 5200274..1a4c8e9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -83,6 +83,7 @@ Scheduler → SessionManager scheduled execution → AgentLoop → Scheduler del - **WebUI management APIs** only expose allowlisted config/profile/log/storage operations; keep response limits, secret redaction, atomic config writes, and profile path allowlists intact - **WebUI slash completion** must consume the existing `get_slash_commands` WebSocket response; do not duplicate the backend command list in frontend source - **WebUI chat rendering** sanitizes Markdown before inserting HTML; session history must preserve structured tool-call metadata so calls and results remain independently collapsible +- **WebUI/TUI file transfer** streams bytes over authenticated HTTP and sends only short-lived upload IDs/attachment metadata over WebSocket; messages persist local media paths without guaranteeing later availability, and client responses must never expose those paths - **WebUI authentication** protects every management API and `/ws`; only static pairing assets, public health/status, and pairing submission may bypass device auth. Pair-code issuance requires both a real loopback peer and the filesystem-held admin token; never put bearer tokens in URLs or logs - **Providers** are pure HTTP clients; no bus/session/channel awareness - **Tools** are executed by `AgentLoop`; they receive raw arguments and return string results diff --git a/Cargo.toml b/Cargo.toml index 657fa99..dd10b00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,10 @@ serde_json = "1.0" async-trait = "0.1" thiserror = "2.0.18" tokio = { version = "1.52", features = ["full"] } -tokio-util = { version = "0.7", features = ["rt"] } +tokio-util = { version = "0.7", features = ["rt", "io"] } dashmap = "6.1" uuid = { version = "1.23", features = ["v4"] } -axum = { version = "0.8", features = ["ws"] } +axum = { version = "0.8", features = ["ws", "multipart"] } tokio-tungstenite = { version = "0.29.0", features = ["rustls-tls-webpki-roots", "rustls"] } futures-util = "0.3" clap = { version = "4", features = ["derive"] } diff --git a/README.md b/README.md index 71b1351..83e6d25 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ picobot pair WebUI 随二进制嵌入,不需要 Node.js、npm 或单独部署静态文件,提供: - 在线聊天、会话创建/切换、历史回放、Markdown 消息、可折叠工具调用卡片,以及基于 Gateway 实时命令清单的 `/` 斜杠命令补全。 +- 文件选择、拖放和剪贴板图片上传;消息中的附件可预览或下载。附件按服务端路径引用,原文件移动或删除后历史附件可能不可用。 - 可持久化的浅色/深色主题,首次访问时跟随系统偏好。 - Cron 定时任务、最近运行记录和后台子任务状态。 - 当前聊天 session 的可展开 Todo 侧栏;计划变化时自动展开,其他 session 的变化显示未读提示。 @@ -156,7 +157,7 @@ picobot service uninstall unit 位于 `~/.config/systemd/user/picobot.service`,以执行 `service install` 时的当前目录作为初始工作目录。服务异常退出时由 systemd 自动重启;`stop` 和 `restart` 会通过 SIGTERM 触发 Gateway 的有界优雅关停。 -TUI 会把一个随机客户端标识保存到 `~/.picobot/tui_client_id`,因此关闭并重新打开客户端后会恢复同一组 dialog 和最近使用的会话。界面支持历史回放、会话列表与归档筛选、命令补全、Unicode/中文编辑、括号粘贴和多行输入。 +TUI 会把一个随机客户端标识保存到 `~/.picobot/tui_client_id`,因此关闭并重新打开客户端后会恢复同一组 dialog 和最近使用的会话。界面支持历史回放、会话列表与归档筛选、命令补全、Unicode/中文编辑、括号粘贴、多行输入和文件传输。 常用快捷键: @@ -168,6 +169,9 @@ TUI 会把一个随机客户端标识保存到 `~/.picobot/tui_client_id`,因 | `Ctrl+R` / `Ctrl+A` / `Ctrl+D` | 重命名 / 归档 / 删除所选会话 | | `Ctrl+L` / `Ctrl+O` | 清空历史 / 显示归档会话 | | `Enter` / `Shift+Enter` | 发送 / 换行 | +| `Ctrl+F` / `F2` | 添加附件 / 下载历史中最近的附件 | + +WebUI/TUI 上传文件默认保存到 `~/.picobot/media/cli_chat`,单文件上限 25 MiB;可通过 `gateway.file_transfer` 调整目录、上限和待发送上传的有效期。消息只保存文件路径,不保证文件被移动或删除后仍能下载。 | `PageUp` / `PageDown` | 滚动对话历史 | | 连按两次 `Ctrl+C` | 退出客户端 | @@ -402,6 +406,7 @@ docs/ 面向维护者和 Agent 的架构与开发文档 ## 进一步阅读 - [维护者架构文档](docs/ARCHITECTURE.md) +- [WebUI 与 TUI 文件收发设计](docs/FILE_TRANSFER_DESIGN.md) - [内置 Skill:架构机制](resources/skills/about-picobot/references/architecture.md) - [配置说明](resources/skills/about-picobot/references/config.md) - [命令说明](resources/skills/about-picobot/references/commands.md) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 4560363..45b9018 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -199,6 +199,8 @@ WebSocket 每个客户端的 writer task 是连接局部任务,由连接 handl Gateway 在 `/` 提供随二进制编译的 HTML/CSS/JavaScript,不依赖外部 CDN 或前端运行服务。前端源码位于 `webui/`,由 Svelte 5 + Vite 构建,Bits UI 提供无样式的可访问组件原语。`build.rs` 监听前端源码、锁文件和构建配置,增量地将生产资源生成到 Cargo `OUT_DIR`,Rust 再从该目录编译嵌入;前端产物不进入仓库,最终用户使用发布二进制时不需要 Node.js。浏览器聊天继续使用 `/ws` 和 `cli_chat` 渠道,因此复用现有 dialog scope、每会话串行 worker、历史持久化和出站 lane;会话历史帧保留工具调用 ID、名称、参数和工具结果角色,WebUI 在本轮完成后刷新历史并将其渲染为默认折叠的工具卡片;聊天页的 Todo 侧栏默认隐藏,按 session 保存快照和未读状态,并通过结构化 `session_plan`/`plan_updated` 帧刷新,计划变化不会写入聊天历史;斜杠命令补全通过 `get_slash_commands` 获取 Gateway 的实时命令与别名清单,不在前端重复定义;WebUI 不直接调用 Provider 或 SessionManager。 +WebUI/TUI 文件字节通过受鉴权的 HTTP 接口流式传输,WebSocket 只携带短期 `upload_id` 和结构化附件描述。`UploadRegistry` 在内存中按 `cli_chat` chat scope 校验并消费待发送上传;消息继续以 `media_refs` 保存 Gateway 本地路径,不建立永久附件资产。下载接口必须通过 client、session、message 和附件序号反查路径,不能接受客户端路径。历史附件路径失效属于正常状态,不得影响历史文本读取。待发送但未进入消息的上传由 `TaskSupervisor` 所有的限时清理任务回收。Agent 上下文会为所有媒体注入内部路径清单,客户端响应不得暴露该路径。 + `AuthManager` 默认保护所有管理 API 和 `/ws`。静态资源、`/health`、`/api/auth/status` 与 `/api/auth/pair` 保持公开,使未配对浏览器只能加载配对界面。`picobot pair` 使用权限为 `0600` 的本机管理密钥调用仅接受真实回环连接的 `/api/auth/code`;反向代理即使从回环连接也无法在没有该密钥时签发代码。配对码为 8 位、5 分钟有效、单次消费,并按来源实施失败锁定。浏览器收到 HttpOnly、SameSite=Strict Cookie,CLI 使用 Bearer token;服务端仅持久化 SHA-256 哈希。`--revoke-all` 的持久化成功后才清空内存令牌,活动 WebSocket 每 5 秒复核身份并回收已撤销连接。 同源 `/api/*` 管理接口只提供显式白名单能力: @@ -207,6 +209,7 @@ Gateway 在 `/` 提供随二进制编译的 HTML/CSS/JavaScript,不依赖外 - `USER.md`、`AGENTS.md` 只允许固定文件名,不接受任意路径。 - 日志、记忆、任务和运行记录均限制单次返回数量;日志目录固定为 `~/.picobot/logs`。 - 任务与记忆读取复用 Storage API,不允许 WebUI 直接持有 SQLite 连接或拼接任意查询。 +- 文件上传/下载复用设备鉴权并校验 chat/session/message scope;客户端不能提交或获得服务端路径,inline 预览仅允许安全 MIME 白名单。 - 前端依赖只存在于源码构建阶段;生产页面不加载 CDN。`build.rs` 以 `package-lock.json` 的依赖 stamp 判断是否需要 `npm ci`,并依靠 Cargo `rerun-if-changed` 避免后端代码变化触发前端重建。前端开发仍须运行 `npm run check`,并以 `cargo build` 验证最终嵌入路径。 配对鉴权只证明设备持有凭据,不提供机密性。非回环部署仍必须由反向代理或其他外层提供 TLS;显式设置 `gateway.require_pairing=false` 会恢复无鉴权模式,仅适合隔离环境。 diff --git a/docs/FILE_TRANSFER_DESIGN.md b/docs/FILE_TRANSFER_DESIGN.md new file mode 100644 index 0000000..8cd5102 --- /dev/null +++ b/docs/FILE_TRANSFER_DESIGN.md @@ -0,0 +1,374 @@ +# WebUI 与 TUI 文件收发设计 + +## 1. 目标与非目标 + +当前统一消息链路已经有 `MediaItem`、`MediaRef` 和 `messages.media_refs`,Agent 能处理图片,飞书及 `send_message(files=...)` 也能收发媒体。缺口集中在 `cli_chat`:WebSocket 入站把 `media` 固定为空,实时响应和历史协议也没有附件字段,因此 WebUI/TUI 无法使用已有能力。 + +本设计补齐: + +- WebUI 文件选择、拖放、粘贴图片、上传进度、附件展示和下载; +- TUI 通过本地路径上传、展示附件和下载文件; +- 文本加附件及纯附件消息进入现有 session worker; +- Agent 通过现有 `send_message(files=...)` 发出的文件可被 WebUI/TUI 获取; +- 文件大小、并发、scope、路径和 MIME 安全边界。 + +附件采用“路径引用”语义,而不是持久化文件资产: + +- 消息仍在 `messages.media_refs` 中记录服务端本地路径和媒体类型; +- 不新增附件表、消息附件关联表、内容寻址、引用计数或永久 blob 存储; +- 不保证历史附件可获取。路径变化、文件被覆盖或删除后,预览/下载可以返回不可用; +- 历史消息必须仍能正常显示,文件不可用不能导致整段历史读取失败; +- 客户端永远看不到或提交服务端路径,路径只在 Gateway 内部使用。 + +首版不包含目录上传、断点续传、对象存储、跨 Gateway 部署、缩略图服务和自动文档解析。 + +## 2. 总体方案 + +采用“HTTP 传字节,WebSocket 传短期上传引用和消息事件”: + +```mermaid +sequenceDiagram + participant C as WebUI / TUI + participant H as Attachment HTTP API + participant U as UploadRegistry + participant W as cli_chat WebSocket + participant S as Session worker + + C->>H: POST multipart file + H->>H: 流式保存到本地媒体目录 + H->>U: 注册 upload_id -> path + chat scope + H-->>C: UploadDescriptor(upload_id, name, size, type) + C->>W: user_input(content, upload_ids) + W->>U: 校验并消费 upload IDs + W->>S: InboundMessage(media paths) + S->>S: 按现有 media_refs 持久化路径 + S-->>C: assistant_response / session_history + C->>H: GET message attachment by message ID + index + H->>H: 查询 media_refs,按当前路径流式读取 + H-->>C: bytes 或 404/410 +``` + +不把文件塞入 WebSocket binary frame 或 base64 JSON:现有 WebSocket writer、Bus 和 session 队列面向小型消息,大帧会造成内存峰值与队头阻塞;HTTP 更适合流式 I/O、上传进度、状态码和后续 Range 支持。 + +## 3. 模型与协议 + +### 3.1 短期上传描述 + +上传成功后返回只在短期内有效的 `UploadDescriptor`: + +```rust +pub struct UploadDescriptor { + pub upload_id: String, // UUID v4,仅用于随后提交 user_input + pub name: String, + pub media_type: String, // image | audio | video | file + pub mime_type: String, + pub size: u64, + pub expires_at: i64, +} +``` + +`upload_id` 不是持久化附件 ID。Gateway 重启、过期或被成功消费后均可失效。 + +### 3.2 消息附件描述 + +WebSocket 对客户端返回的描述不含路径: + +```rust +pub struct MessageAttachment { + pub index: u32, // 在该消息 media_refs 中的位置 + pub name: String, // 从当前 path basename 安全派生 + pub media_type: String, + pub mime_type: String, // 按扩展名推断,仅用于展示/响应默认值 +} +``` + +下载定位使用 `session_id + message_id + index`。不在描述中放服务端路径,也不使用可映射回路径的编码 ID。 + +是否增加 `available` 字段:首版不增加。历史查询不为最多 2000 条消息逐个执行文件 `stat`;客户端点击预览/下载时,由 HTTP 状态码反映文件是否仍存在。WebUI/TUI 收到 `404/410` 后把该附件标记为“文件已不存在”。 + +### 3.3 WebSocket 扩展 + +保持旧 JSON 可解析: + +```rust +WsInbound::UserInput { + content: String, + upload_ids: Vec, // serde(default),最多 8 个 + client_message_id: Option, + // 现有字段保留 +} + +HistoryMessage { + // 现有字段保留 + attachments: Vec, // serde(default) +} + +WsOutbound::AssistantResponse { + // 现有字段保留 + attachments: Vec, // serde(default) +} +``` + +上传引用无效、跨 scope、重复/过期、文件数量或总量超限时,Gateway 使用现有 `error` 帧返回明确原因。成功提交沿用普通消息的处理/响应语义,不新增附件专用确认帧。 + +`SessionEstablished` 增加默认空的 `capabilities`;支持本方案的 Gateway 返回 `file_transfer_v1`。新 TUI 连接旧 Gateway 时隐藏文件功能并提示升级,旧客户端忽略新增字段。 + +## 4. UploadRegistry + +新增轻量 `UploadRegistry`,由 `GatewayState` 持有,只管理尚未提交到消息的上传: + +```rust +struct PendingUpload { + upload_id: String, + owner_channel: String, + owner_chat_id: String, + path: PathBuf, + name: String, + media_type: String, + mime_type: String, + size: u64, + expires_at: Instant, + state: Pending | Consuming, +} +``` + +Registry 存于内存,不写 SQLite。默认文件目录建议为 `~/.picobot/media/cli_chat`,配置归入 `gateway.file_transfer`: + +```json +{ + "enabled": true, + "upload_dir": "~/.picobot/media/cli_chat", + "max_file_bytes": 26214400, + "max_files_per_message": 8, + "max_message_bytes": 67108864, + "pending_ttl_seconds": 3600 +} +``` + +文件布局不使用用户文件名定位: + +```text +cli_chat//.upload +cli_chat/.staging/.part +``` + +原始文件名只保存在 registry 中;消息最终记录的路径可以带安全扩展名,但不能包含未经清理的目录组件。 + +状态规则: + +1. 上传完成后为 `Pending`。 +2. `user_input` 批量校验所有 upload ID 后,从 registry 原子取出。 +3. 成功发布到 inbound Bus 后不删除文件;后续消息持有路径引用。 +4. 发布到 inbound Bus 失败时恢复 registry 记录,允许客户端重试。 +5. 到期且仍在 registry 中的孤儿上传由 GC 删除。 +6. Gateway 重启后 registry 丢失;残留文件由启动时按文件年龄限量清理。它们没有进入消息,因此可以删除。 + +一旦路径已经写入消息,该文件不再由“pending upload GC”追踪。项目不承诺它的保存期限;用户、工具、外部清理任务或后续保留策略都可以移动或删除它。 + +GC 任务必须由 `TaskSupervisor` 持有,观察取消,并限制每轮扫描数和总执行时间。 + +## 5. HTTP API + +路由加入现有受保护 Router,复用 Cookie/Bearer 鉴权。 + +### 5.1 上传 + +```http +POST /api/chat/{client_id}/uploads +Content-Type: multipart/form-data + +file= +``` + +成功返回 `201 Created` 和 `UploadDescriptor`。上传 handler: + +1. 校验与 WebSocket 相同规则的 `client_id`; +2. 流式读取 multipart,不聚合整个文件; +3. 边写临时文件边计算实际大小,超限立即停止并清理; +4. 清理文件名,限制 UTF-8 长度,去除路径、控制字符和保留名称; +5. MIME 以有限 magic-byte 检测为主、扩展名为辅,未知为 `application/octet-stream`; +6. `sync_all` 后原子 rename,再注册 upload ID;注册失败删除文件; +7. 每个身份/chat scope 使用 semaphore 限制并发上传。 + +主要错误为 `400` 非法请求、`401` 未认证、`413` 超限、`429` 并发或暂存量超限、`507` 空间不足。 + +### 5.2 下载与预览 + +```http +GET /api/chat/{client_id}/sessions/{session_id}/messages/{message_id}/attachments/{index} +GET /api/chat/{client_id}/sessions/{session_id}/messages/{message_id}/attachments/{index}?disposition=inline +``` + +handler 必须: + +1. 验证设备身份和 `client_id`; +2. 使用 Session/Storage API 验证该 session 属于 `cli_chat:{client_id}`; +3. 查询指定 message,并从其 `media_refs[index]` 取得内部路径; +4. 重新检查路径当前指向普通文件;不存在、已移动、是目录或不可读时返回 `404` 或 `410`; +5. 流式读取当前文件内容,不在打开前把整个文件载入内存。 + +响应设置 `Content-Length`、推断的 `Content-Type`、安全编码的 `Content-Disposition`、`X-Content-Type-Options: nosniff` 和 `Cache-Control: private, no-store`。`inline` 仅允许白名单图片/音视频 MIME,其余强制下载。 + +下载路由不能接受 path 查询参数。错误响应和日志都不能包含服务端路径。路径在消息存在不等于文件存在,这属于正常的可预期状态。 + +`client_id` 是非秘密 chat scope,可以出现在路径;Bearer token 仍只能进入 Authorization header,不能放入 URL。WebUI `` 使用同源 HttpOnly Cookie,TUI 使用 Bearer header。 + +## 6. 入站处理 + +`cli_chat` 收到带上传的 `user_input` 后: + +1. 允许正文为空,但正文和 `upload_ids` 不能同时为空; +2. 校验数量、去重并批量验证所有上传属于 `client.chat_id`; +3. 检查上传未过期、文件当前仍是普通文件且总大小未超限; +4. 原子取得 upload IDs,转换为带本地路径的 `MediaItem`; +5. 走现有 Bus → SessionManager → session worker; +6. 成功发布到 inbound Bus 后消费 registry 记录;发布失败则恢复记录并返回现有 error 帧; +7. worker 按现有流程把路径写入 `messages.media_refs`。 + +为此,`SessionManager::handle_message` 应返回结构化的“已入队/拒绝”,不能再把队列满包装为普通命令输出。Gateway 主循环仍只等待快速入队,不等待模型。 + +Slash command 不接受上传。正文识别为 slash command 且带 `upload_ids` 时返回 `UPLOADS_NOT_ALLOWED_FOR_COMMAND`,避免文件被静默忽略。 + +## 7. 出站和历史 + +### 7.1 出站文件 + +Agent 继续使用 `send_message(files=...)`。文件路径由服务端内部产生,不需要复制到附件资产目录: + +1. `SendMessageTool` 将路径转换为现有 `MediaItem`; +2. 发送前检查每个路径当前是可读普通文件且未超过发送限制; +3. `OutboundMessenger` 按现有逻辑把路径写入 assistant 消息的 `media_refs`; +4. `OutboundMessage.media` 传给 `CliChatChannel`; +5. `cli_chat` 只返回文件名、类型和消息内 index,不返回路径; +6. 用户点击下载时再次读取当前路径,因此发送后路径变化或文件删除会导致下载失败。 + +多个文件建议在发送前全部校验;校验通过后仍可能发生 TOCTOU 删除,下载端必须把这种情况作为正常不可用处理。 + +即时 `AssistantResponse` 需要携带已持久化消息的真实 `message_id`,不能继续使用与历史无关的临时短 ID,否则客户端无法构造安全下载地址。若当前投递链路暂时拿不到 message ID,客户端收到响应后立即刷新历史,以历史记录为附件展示权威来源。 + +### 7.2 历史读取 + +`HistoryMessage.attachments` 从已保存的 `media_refs` 映射而来。映射只做字符串解析和 basename/MIME 推断,不访问文件系统,因此: + +- 历史查询性能不依赖附件文件数量和存储速度; +- 文件缺失不会导致历史帧失败; +- 展示附件不代表下载一定成功; +- 旧 `media_refs` 数据无需 schema 迁移即可生效。 + +客户端在下载返回不可用后只更新本地 UI 状态,不修改历史消息。 + +### 7.3 Agent 上下文中的路径 + +构造发给模型的用户消息时,无论附件类型是否被模型原生支持,都先增加一个结构化附件清单。清单包含安全文件名、媒体类型和 Gateway 内部路径,例如: + +```text +[附件清单:path 是 Gateway 内部存储路径,可供文件工具读取] +[ + { + "name": "report.pdf", + "media_type": "file", + "path": "/gateway/media/report.pdf" + } +] +``` + +随后再追加图片等原生多模态 content block。这样支持视觉输入的模型既能看到图片内容,也知道其文件路径;普通文件同样可以由 LLM 使用 `file_read`、Bash 等工具读取。附件路径只进入服务端到 Provider 的模型上下文,不进入 WebSocket/HTTP 客户端响应。 + +历史路径已经失效时,清单仍反映消息所记录的原路径;工具读取失败应作为普通、可解释的“文件已移动或删除”结果返回,不能导致 Agent loop panic。 + +## 8. WebUI 交互 + +Composer 增加回形针按钮、隐藏多选 file input,并支持拖放和剪贴板图片。待发送区域展示文件名、大小、进度、失败、重试和移除。 + +- 选中文件后立即通过 HTTP 上传,并发不超过 3; +- 全部上传成功后才可发送;文本为空但有上传时允许发送; +- 上传或消息提交返回 error 时给出明确提示,过期项要求重新上传; +- 切换 session 时按 session 保存内存草稿,刷新页面后的孤儿上传由 TTL 清理; +- 历史消息在正文下显示附件卡;图片可尝试 inline 预览; +- 下载/预览为 404/410 时显示“原文件已移动或删除”; +- 不把文件字节、服务端路径或 upload ID 长期写入 localStorage; +- object URL 在移除或销毁时 revoke。 + +Markdown 继续走现有 sanitizer;附件使用结构化字段渲染,文件名不能拼接成 HTML。 + +## 9. TUI 交互 + +TUI 保存 Gateway HTTP base URL、Bearer token 和 `client_id`: + +- `Ctrl+F` 打开“添加附件”路径输入框;相对路径按 TUI 启动目录解释; +- TUI 读取本机文件并通过 HTTP 上传,不能把客户端路径直接传给 Gateway; +- Composer 上方显示待发送文件和上传状态,支持移除; +- 消息显示 `[附件 1] report.pdf`;按 `F2` 将历史中最近的附件下载到当前目录; +- 下载先写目标目录临时文件,再原子 rename,默认不覆盖已有文件; +- 服务端返回不可用时显示“原文件已移动或删除”; +- HTTP 上传/下载通过受管理任务和内部 channel 回报进度,不阻塞键盘或 WebSocket;退出时取消并有界 join。 + +不新增伪服务端 `/attach`、`/download` 命令,避免与 `get_slash_commands` 的权威列表冲突。 + +## 10. 安全与资源边界 + +- **路径穿越**:上传目标路径完全由 Gateway 生成;清理后的名字只用于展示。 +- **任意文件读取**:客户端只提交 upload ID;下载只通过已归属该 session/message 的 `media_refs` 定位,不接受路径参数。 +- **跨 scope**:上传消费、session 查询和下载都验证 `cli_chat:{client_id}`。 +- **符号链接与特殊文件**:上传落盘为普通文件;出站和下载每次打开前拒绝目录、设备、FIFO 等非普通文件。对于工具路径是否跟随 symlink,应保留现有工具权限语义并在打开后检查 metadata。 +- **资源耗尽**:限制单文件、单消息总量、文件数、并发上传、multipart body、pending TTL 和每轮 GC 数量。 +- **内容伪装**:不信任客户端 MIME;inline 采用白名单并设置 `nosniff`。 +- **恶意文件**:Gateway 不自动解压或解析任意文档;图片进入模型前另设格式、像素和编码后大小限制。 +- **提示注入**:附件是不可信用户内容;普通文件只提供路径提示,由 Agent 显式调用工具读取。 +- **路径泄漏**:协议、HTTP 错误和常规日志不得包含完整服务端路径。 +- **传输安全**:非回环部署仍要求外层 HTTPS/WSS;设备配对本身不提供机密性。 + +## 11. 生命周期与并发 + +UploadRegistry 的 pending GC 和启动残留清理由 `TaskSupervisor` 持有,观察 cancellation 并有硬超时。已经进入消息的路径不属于该 GC。 + +HTTP 连接断开或 Gateway shutdown 时停止读写并删除未提交 `.part` 文件。任何 session mutex 都不得跨上传、下载、文件 `stat/open` 或数据库 I/O 持有。慢文件 I/O 完成后提交会话结果时继续验证 `worker_generation`/`state_version`。 + +## 12. 分阶段实施 + +### 阶段 A:协议与服务端 + +1. 新增 file-transfer 配置、UploadRegistry、HTTP 上传/下载路由和 pending GC。 +2. 扩展 WebSocket capability、upload IDs 和附件描述,并复用现有 error 帧。 +3. `cli_chat` 入站恢复 `media`,出站和历史不再丢弃 `media_refs`。 +4. 给 Storage/SessionManager 增加按 scope 查询单条消息的安全 API。 + +本阶段不修改数据库 schema。 + +### 阶段 B:WebUI + +实现选择/拖放/粘贴、上传进度、附件卡、预览和不可用提示;运行 `npm run check`、`npm run build` 和 `cargo build`。 + +### 阶段 C:TUI + +实现路径 modal、HTTP 传输任务、状态渲染和安全下载;补齐断线、退出取消和旧 Gateway capability 降级。 + +### 阶段 D:收口 + +完善 `send_message(files=...)` 校验、可观测性和保留策略说明。实现后同步更新 `README.md`、`docs/ARCHITECTURE.md`、`AGENTS.md` 和配置示例。 + +## 13. 测试与验收 + +重点测试: + +- 上传分片计数、超限中止、文件名清理、MIME 映射和 orphan 清理; +- upload ID 的 scope、过期、重复消费、批量原子取得与入队失败恢复; +- 文本+附件、纯附件、slash command 带附件拒绝和 session 队列满; +- 历史 `media_refs` → `MessageAttachment` 映射绝不泄露路径; +- 文件存在时可下载,路径删除/移动/变成目录时返回不可用且历史仍正常; +- 跨 client/session/message/index 访问被拒绝且不泄露文件是否存在; +- Cookie 与 Bearer 认证、UTF-8 文件名、inline 白名单和下载中断; +- Agent 图片输入和 `send_message(files)` 的在线/历史展示; +- Gateway shutdown 时传输与 GC 有界退出,无裸后台任务; +- 旧文本客户端继续工作,新 TUI 对旧 Gateway 安全降级。 + +验收标准: + +1. WebUI/TUI 可发送限制内的本地文件,不使用 WebSocket base64。 +2. 纯附件消息可靠入队,失败有明确、可重试反馈。 +3. 在线响应和历史均能显示附件引用;文件仍存在时可下载。 +4. 文件路径变化或删除后允许下载失败,但历史消息、文本和其他附件不受影响。 +5. 客户端看不到服务端路径,也不能利用接口读取未归属当前 chat scope 的路径。 +6. 同一 session 顺序、跨 session 并发和现有锁/取消不变量保持不变。 + +Rust 实现完成后运行目标测试、`cargo test --lib`、离线协议/调度集成测试、Clippy warnings denied 和 `cargo build`;WebUI 额外执行独立 check/build。 diff --git a/resources/templates/config.example.json b/resources/templates/config.example.json index c4dbbca..fb18857 100644 --- a/resources/templates/config.example.json +++ b/resources/templates/config.example.json @@ -49,7 +49,15 @@ "gateway": { "host": "127.0.0.1", "port": 19876, - "require_pairing": true + "require_pairing": true, + "file_transfer": { + "enabled": true, + "upload_dir": "~/.picobot/media/cli_chat", + "max_file_bytes": 26214400, + "max_files_per_message": 8, + "max_message_bytes": 67108864, + "pending_ttl_seconds": 3600 + } }, "client": { "gateway_url": "ws://127.0.0.1:19876/ws" diff --git a/src/agent/agent_loop.rs b/src/agent/agent_loop.rs index 88468b5..a242ee4 100644 --- a/src/agent/agent_loop.rs +++ b/src/agent/agent_loop.rs @@ -28,13 +28,53 @@ fn build_content_blocks( ) -> Vec { let mut blocks = Vec::new(); - if !text.is_empty() { - blocks.push(ContentBlock::text(text)); - } - if !media_refs.is_empty() { + let attachments = media_refs + .iter() + .map(|media_ref| { + let path = std::path::Path::new(&media_ref.path); + let name = path + .file_name() + .map(|name| name.to_string_lossy().into_owned()) + .unwrap_or_else(|| media_ref.path.clone()); + let extension = path + .extension() + .map(|extension| extension.to_string_lossy().into_owned()); + let mime_type = mime_guess::from_path(path) + .first_or_octet_stream() + .to_string(); + let size_bytes = std::fs::metadata(path).ok().map(|metadata| metadata.len()); + let native_input = input_types.contains(&media_ref.media_type) + && registry.supports(&media_ref.media_type); + serde_json::json!({ + "name": name, + "extension": extension, + "media_type": media_ref.media_type, + "mime_type": mime_type, + "size_bytes": size_bytes, + "path": media_ref.path, + "content_delivery": if native_input { + "also included as a model-native content block" + } else { + "content is not embedded; use a file tool with path to inspect it" + }, + }) + }) + .collect::>(); + let manifest = serde_json::Value::Array(attachments).to_string(); + let message_text = if text.is_empty() { + format!( + "[用户发送了以下附件。path 是 Gateway 内部存储路径,可供文件工具读取;附件内容未必已嵌入模型输入。]\n{manifest}" + ) + } else { + format!( + "{text}\n\n[随本条用户消息同时提交的附件。path 是 Gateway 内部存储路径,可供文件工具读取;content_delivery 说明附件内容是否另以模型原生内容块提供。]\n{manifest}" + ) + }; + blocks.push(ContentBlock::text(message_text)); + for mr in media_refs { - if input_types.contains(&mr.media_type) { + if input_types.contains(&mr.media_type) && registry.supports(&mr.media_type) { match registry.handle(&mr.media_type, &mr.path) { Ok(content_blocks) => blocks.extend(content_blocks), Err(e) => { @@ -55,14 +95,12 @@ fn build_content_blocks( path = %mr.path, media_type = %mr.media_type, model_input_types = ?input_types, - "Media type not supported by model, using text placeholder" + "Media type not supported by model; attachment manifest remains available" ); - blocks.push(ContentBlock::text(format!( - "[用户发来了一个文件: {}]", - mr.path - ))); } } + } else if !text.is_empty() { + blocks.push(ContentBlock::text(text)); } if blocks.is_empty() { @@ -868,12 +906,63 @@ mod tests { ®istry, ); - assert!( - matches!(blocks.first(), Some(ContentBlock::Text { text }) if text == "先看这段文字") + assert_eq!(blocks.len(), 1); + assert!(matches!(blocks.first(), Some(ContentBlock::Text { text }) + if text.starts_with("先看这段文字\n\n") + && text.contains("随本条用户消息同时提交的附件") + && text.contains("missing.png") + && text.contains("\"media_type\":\"image\"") + && text.contains("content is not embedded"))); + } + + #[test] + fn test_build_content_blocks_describes_attachment_only_message() { + let registry = MediaHandlerRegistry::new(); + let blocks = build_content_blocks( + "", + &[MediaRef { + path: "/tmp/report.docx".to_string(), + media_type: "file".to_string(), + }], + &[], + ®istry, ); - assert!( - matches!(blocks.get(1), Some(ContentBlock::Text { text }) if text.contains("用户发来了一个文件")) + + assert_eq!(blocks.len(), 1); + assert!(matches!(blocks.first(), Some(ContentBlock::Text { text }) + if text.starts_with("[用户发送了以下附件") + && text.contains("report.docx") + && text.contains("application/vnd.openxmlformats-officedocument.wordprocessingml.document") + && text.contains("\"extension\":\"docx\"") + && text.contains("\"size_bytes\":null") + && text.contains("content is not embedded"))); + } + + #[test] + fn test_build_content_blocks_includes_path_for_supported_images() { + use std::io::Write; + + let mut image = tempfile::Builder::new().suffix(".png").tempfile().unwrap(); + image.write_all(b"image bytes").unwrap(); + let path = image.path().to_string_lossy().into_owned(); + let registry = MediaHandlerRegistry::with_defaults(); + + let blocks = build_content_blocks( + "分析图片", + &[MediaRef { + path: path.clone(), + media_type: "image".to_string(), + }], + &["image".to_string()], + ®istry, ); + + assert!(matches!(blocks.first(), Some(ContentBlock::Text { text }) + if text.starts_with("分析图片\n\n") + && text.contains("随本条用户消息同时提交的附件") + && text.contains(&path) + && text.contains("model-native content block"))); + assert!(matches!(blocks.get(1), Some(ContentBlock::ImageUrl { .. }))); } } diff --git a/src/agent/media_handler.rs b/src/agent/media_handler.rs index 96b412c..5765bb0 100644 --- a/src/agent/media_handler.rs +++ b/src/agent/media_handler.rs @@ -99,6 +99,10 @@ impl MediaHandlerRegistry { } } + pub fn supports(&self, media_type: &str) -> bool { + self.handlers.contains_key(media_type) + } + pub fn with_defaults() -> Self { let mut reg = Self::new(); reg.register(Box::new(ImageHandler)); diff --git a/src/channels/cli_chat.rs b/src/channels/cli_chat.rs index c3e2ad9..031cf4e 100644 --- a/src/channels/cli_chat.rs +++ b/src/channels/cli_chat.rs @@ -4,7 +4,10 @@ use std::sync::Arc; use tokio::sync::{Mutex, mpsc}; use crate::bus::{ControlMessage, InboundMessage, MessageBus, OutboundMessage}; -use crate::protocol::{HistoryMessage, SlashCommandInfo, WsInbound, WsOutbound, parse_inbound}; +use crate::gateway::uploads::UploadRegistry; +use crate::protocol::{ + HistoryMessage, MessageAttachment, SlashCommandInfo, WsInbound, WsOutbound, parse_inbound, +}; use crate::session::{SessionCommand, SessionEvent, UnifiedSessionId}; use super::base::{Channel, ChannelError}; @@ -32,6 +35,7 @@ impl Client { pub struct CliChatChannel { bus: std::sync::Mutex>>, clients: Mutex>>, + uploads: UploadRegistry, } impl Default for CliChatChannel { @@ -42,9 +46,14 @@ impl Default for CliChatChannel { impl CliChatChannel { pub fn new() -> Self { + Self::with_upload_registry(UploadRegistry::disabled()) + } + + pub fn with_upload_registry(uploads: UploadRegistry) -> Self { Self { bus: std::sync::Mutex::new(None), clients: Mutex::new(HashMap::new()), + uploads, } } @@ -166,21 +175,49 @@ impl CliChatChannel { match inbound { WsInbound::UserInput { - content, chat_id, .. + content, + upload_ids, + chat_id, + .. } => { // All messages (including slash commands) go through the normal inbound flow // SessionManager handles session creation/reuse internally + if content.trim().is_empty() && upload_ids.is_empty() { + return Err(ChannelError::Other("Message is empty".to_string())); + } + if !upload_ids.is_empty() + && crate::channels::parse_slash_command(&content).is_some() + { + return Err(ChannelError::Other( + "Attachments cannot be sent with slash commands".to_string(), + )); + } + let target_chat_id = chat_id.unwrap_or_else(|| client.chat_id.clone()); + if target_chat_id != client.chat_id { + return Err(ChannelError::Other( + "Chat does not belong to this client".to_string(), + )); + } + let uploads = self + .uploads + .take_many(&client.chat_id, &upload_ids) + .await + .map_err(|error| ChannelError::Other(error.to_string()))?; + let media = uploads.iter().map(UploadRegistry::as_media).collect(); let msg = InboundMessage { channel: self.name().to_string(), sender_id: "cli".to_string(), - chat_id: chat_id.unwrap_or_else(|| client.chat_id.clone()), + chat_id: target_chat_id, content, timestamp: crate::bus::message::current_timestamp(), - media: Vec::new(), + media, metadata: Default::default(), forwarded_metadata: Default::default(), }; - bus.publish_inbound(msg).await?; + if let Err(error) = bus.publish_inbound(msg).await { + self.uploads.restore(uploads).await; + return Err(error.into()); + } } WsInbound::ClearHistory { chat_id, @@ -391,20 +428,37 @@ impl CliChatChannel { .into_iter() .filter(|message| { !message.content.is_empty() + || message.media_refs.is_some() || message.tool_calls.is_some() || message.role == "tool" }) - .map(|message| HistoryMessage { - id: message.id, - seq: message.seq, - role: message.role, - content: message.content, - created_at: message.created_at, - tool_call_id: message.tool_call_id, - tool_name: message.tool_name, - tool_calls: message - .tool_calls - .and_then(|calls| serde_json::from_str(&calls).ok()), + .map(|message| { + let attachments = message + .media_refs + .as_deref() + .and_then(|refs| { + serde_json::from_str::>(refs).ok() + }) + .unwrap_or_default() + .iter() + .enumerate() + .map(|(index, media_ref)| { + MessageAttachment::from_media_ref(index, media_ref) + }) + .collect(); + HistoryMessage { + id: message.id, + seq: message.seq, + role: message.role, + content: message.content, + created_at: message.created_at, + tool_call_id: message.tool_call_id, + tool_name: message.tool_name, + tool_calls: message + .tool_calls + .and_then(|calls| serde_json::from_str(&calls).ok()), + attachments, + } }) .collect(); let _ = client @@ -778,6 +832,17 @@ impl Channel for CliChatChannel { }; let message_type = msg.metadata.get("_type").map(String::as_str); let session_id = msg.metadata.get("_session_id").cloned(); + let message_id = msg + .metadata + .get("_message_id") + .cloned() + .unwrap_or_else(crate::util::short_id); + let attachments = msg + .media + .iter() + .enumerate() + .map(|(index, media)| MessageAttachment::from_media_ref(index, &media.to_media_ref())) + .collect(); let outbound = if message_type == Some("notification") { WsOutbound::SystemNotification { content: msg.content, @@ -789,9 +854,10 @@ impl Channel for CliChatChannel { } } else { WsOutbound::AssistantResponse { - id: crate::util::short_id(), + id: message_id, content: msg.content, role: "assistant".to_string(), + attachments, session_id, } }; @@ -874,4 +940,90 @@ mod tests { .is_some_and(|client| Arc::ptr_eq(client, &replacement)) ); } + + #[tokio::test] + async fn upload_ids_become_inbound_media_paths() { + let uploads = UploadRegistry::new(crate::config::FileTransferConfig::default()); + uploads + .register( + "upload-1".into(), + "client".into(), + std::path::PathBuf::from("/tmp/report.pdf"), + crate::protocol::UploadDescriptor { + upload_id: String::new(), + name: "report.pdf".into(), + media_type: "file".into(), + mime_type: "application/pdf".into(), + size: 42, + expires_at: 0, + }, + ) + .await + .unwrap(); + let channel = CliChatChannel::with_upload_registry(uploads); + let bus = MessageBus::new(4); + channel.start(bus.clone()).await.unwrap(); + let (sender, _receiver) = mpsc::channel(1); + let client = Arc::new(Client { + sender, + chat_id: "client".into(), + current_session_id: Mutex::new(None), + }); + + channel + .handle_ws_inbound( + client, + WsInbound::UserInput { + content: "处理附件".into(), + upload_ids: vec!["upload-1".into()], + channel: None, + chat_id: None, + sender_id: None, + }, + ) + .await + .unwrap(); + + let inbound = bus.consume_inbound().await.unwrap(); + assert_eq!(inbound.media.len(), 1); + assert_eq!(inbound.media[0].path, "/tmp/report.pdf"); + assert_eq!(inbound.media[0].media_type, "file"); + } + + #[tokio::test] + async fn outbound_media_is_exposed_as_safe_attachment_metadata() { + let channel = CliChatChannel::new(); + let (sender, mut receiver) = mpsc::channel(1); + let client = Arc::new(Client { + sender, + chat_id: "client".into(), + current_session_id: Mutex::new(None), + }); + channel.clients.lock().await.insert("client".into(), client); + + channel + .send(OutboundMessage { + channel: "cli_chat".into(), + chat_id: "client".into(), + content: "报告".into(), + reply_to: None, + media: vec![crate::bus::MediaItem::new("/secret/report.pdf", "file")], + metadata: HashMap::from([("_message_id".into(), "message-1".into())]), + delivery: None, + }) + .await + .unwrap(); + + match receiver.recv().await.unwrap() { + WsOutbound::AssistantResponse { + id, attachments, .. + } => { + assert_eq!(id, "message-1"); + assert_eq!(attachments[0].name, "report.pdf"); + let json = serde_json::to_string(&attachments).unwrap(); + assert!(!json.contains("/secret")); + } + other => panic!("unexpected outbound: {other:?}"), + } + } } diff --git a/src/client/mod.rs b/src/client/mod.rs index 722062e..c976c2f 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -36,7 +36,7 @@ pub async fn run( load_auth_token() }; let mut request = connect_url.into_client_request()?; - if let Some(token) = token { + if let Some(token) = &token { request .headers_mut() .insert(header::AUTHORIZATION, format!("Bearer {token}").parse()?); @@ -51,6 +51,9 @@ pub async fn run( let (ws_sender, ws_receiver) = ws_stream.split(); let mut app = App::new(); + app.http_base_url = gateway_http_base_url(gateway_url)?; + app.auth_token = token; + app.client_id = client_id; app.ws_sender = Some(ws_sender); app.ws_receiver = Some(ws_receiver); @@ -75,6 +78,23 @@ pub async fn run( result } +fn gateway_http_base_url(gateway_url: &str) -> Result> { + let mut url = reqwest::Url::parse(gateway_url)?; + let scheme = match url.scheme() { + "ws" => "http", + "wss" => "https", + "http" => "http", + "https" => "https", + other => return Err(format!("unsupported gateway URL scheme: {other}").into()), + }; + url.set_scheme(scheme) + .map_err(|_| "failed to set gateway URL scheme")?; + url.set_path(""); + url.set_query(None); + url.set_fragment(None); + Ok(url.to_string().trim_end_matches('/').to_string()) +} + async fn exchange_pairing_code( gateway_url: &str, code: &str, @@ -234,7 +254,9 @@ async fn run_app( async fn handle_ws_message(app: &mut App, outbound: WsOutbound) { match outbound { WsOutbound::AssistantResponse { + id, content, + attachments, session_id, .. } => { @@ -244,7 +266,10 @@ async fn handle_ws_message(app: &mut App, outbound: WsOutbound) { .as_ref() .is_none_or(|session_id| app.current_session_id.as_ref() == Some(session_id)) { - app.add_message(MessageRole::Assistant, content); + app.add_message_with_attachments(id, MessageRole::Assistant, content, attachments); + if let Some(current) = app.current_session_id.clone() { + request_history(app, current).await; + } } else { app.status_message = Some("另一个会话已完成响应".to_string()); } @@ -255,8 +280,13 @@ async fn handle_ws_message(app: &mut App, outbound: WsOutbound) { app.status_message = Some(message.clone()); app.add_message(MessageRole::System, format!("Error: {}", message)); } - WsOutbound::SessionEstablished { session_id } => { + WsOutbound::SessionEstablished { + session_id, + capabilities, + } => { app.connected = true; + app.file_transfer_supported = + capabilities.iter().any(|value| value == "file_transfer_v1"); app.set_current_session(Some(session_id.clone())); request_history(app, session_id).await; request_session_list(app).await; diff --git a/src/client/tui/app.rs b/src/client/tui/app.rs index 051d343..613791e 100644 --- a/src/client/tui/app.rs +++ b/src/client/tui/app.rs @@ -1,4 +1,6 @@ -use crate::protocol::{HistoryMessage, SessionSummary, SlashCommandInfo}; +use crate::protocol::{ + HistoryMessage, MessageAttachment, SessionSummary, SlashCommandInfo, UploadDescriptor, +}; use std::collections::VecDeque; use tokio_tungstenite::tungstenite::Message; @@ -14,8 +16,10 @@ pub enum MessageRole { #[derive(Debug, Clone)] pub struct ChatMessage { + pub id: String, pub role: MessageRole, pub content: String, + pub attachments: Vec, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -34,6 +38,7 @@ pub enum ConfirmAction { #[derive(Debug, Clone, PartialEq, Eq)] pub enum Modal { Rename { input: String, cursor: usize }, + AttachPath { input: String, cursor: usize }, Confirm(ConfirmAction), } @@ -73,6 +78,11 @@ pub struct App { pub commands: Vec, pub show_command_menu: bool, pub selected_command_idx: usize, + pub http_base_url: String, + pub auth_token: Option, + pub client_id: String, + pub file_transfer_supported: bool, + pub pending_uploads: Vec, } impl App { @@ -99,11 +109,31 @@ impl App { commands: Vec::new(), show_command_menu: false, selected_command_idx: 0, + http_base_url: String::new(), + auth_token: None, + client_id: String::new(), + file_transfer_supported: false, + pending_uploads: Vec::new(), } } pub fn add_message(&mut self, role: MessageRole, content: String) { - self.messages.push_back(ChatMessage { role, content }); + self.add_message_with_attachments(crate::util::short_id(), role, content, Vec::new()); + } + + pub fn add_message_with_attachments( + &mut self, + id: String, + role: MessageRole, + content: String, + attachments: Vec, + ) { + self.messages.push_back(ChatMessage { + id, + role, + content, + attachments, + }); while self.messages.len() > MAX_MESSAGES { self.messages.pop_front(); } @@ -124,8 +154,10 @@ impl App { _ => return None, }; Some(ChatMessage { + id: message.id, role, content: message.content, + attachments: message.attachments, }) }) .collect(); @@ -153,6 +185,7 @@ impl App { if self.current_session_id != session_id { self.current_session_id = session_id; self.messages.clear(); + self.pending_uploads.clear(); self.chat_scroll_from_bottom = 0; } if let Some(current) = &self.current_session_id diff --git a/src/client/tui/components/chat_history.rs b/src/client/tui/components/chat_history.rs index 60be6d0..38dbadf 100644 --- a/src/client/tui/components/chat_history.rs +++ b/src/client/tui/components/chat_history.rs @@ -35,6 +35,12 @@ pub fn render(frame: &mut Frame, area: Rect, app: &App) { ); } } + for attachment in &message.attachments { + lines.push(Line::from(Span::styled( + format!(" [附件 {}] {}", attachment.index + 1, attachment.name), + Style::default().fg(Color::Cyan), + ))); + } lines.push(Line::from("")); } if app.pending_responses > 0 { diff --git a/src/client/tui/components/help_popup.rs b/src/client/tui/components/help_popup.rs index a14c156..69e249b 100644 --- a/src/client/tui/components/help_popup.rs +++ b/src/client/tui/components/help_popup.rs @@ -18,6 +18,8 @@ pub fn render(frame: &mut Frame, area: Rect) { Line::from(" Ctrl+R 重命名 Ctrl+O 显示/隐藏归档"), Line::from(" Ctrl+A 归档 Ctrl+D 删除"), Line::from(" Ctrl+L 清空历史 Ctrl+C 两次 退出"), + Line::from(" Ctrl+F 添加附件 F2 下载最近附件"), + Line::from(" Ctrl+X 清除待发送附件"), Line::from(""), Line::from(Span::styled( "输入", diff --git a/src/client/tui/components/input_area.rs b/src/client/tui/components/input_area.rs index c29dbcc..21f1af1 100644 --- a/src/client/tui/components/input_area.rs +++ b/src/client/tui/components/input_area.rs @@ -15,7 +15,11 @@ pub fn render(frame: &mut Frame, area: Rect, app: &App) { Style::default() }; let title = if app.connected { - " 输入 · Enter 发送 / Shift+Enter 换行 " + if app.pending_uploads.is_empty() { + " 输入 · Enter 发送 / Ctrl+F 附件 " + } else { + " 输入 · Enter 发送(已有附件)" + } } else { " 输入 · Gateway 已断开 " }; diff --git a/src/client/tui/event.rs b/src/client/tui/event.rs index ddd8cbc..a80b639 100644 --- a/src/client/tui/event.rs +++ b/src/client/tui/event.rs @@ -1,8 +1,10 @@ use crate::client::tui::app::{App, ConfirmAction, Focus, MessageRole, Modal}; -use crate::protocol::{WsInbound, serialize_inbound}; +use crate::protocol::{MessageAttachment, UploadDescriptor, WsInbound, serialize_inbound}; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use futures_util::SinkExt; +use tokio::io::AsyncWriteExt; use tokio_tungstenite::tungstenite::Message; +use tokio_util::io::ReaderStream; pub async fn handle_key_event(app: &mut App, key: KeyEvent) { if app.show_help { @@ -64,10 +66,24 @@ pub async fn handle_key_event(app: &mut App, key: KeyEvent) { app.show_archived = !app.show_archived; request_session_list(app).await; } + KeyCode::Char('f') => { + if app.file_transfer_supported { + app.modal = Some(Modal::AttachPath { + input: String::new(), + cursor: 0, + }); + } else { + app.status_message = Some("当前 Gateway 不支持文件传输".to_string()); + } + } KeyCode::Char('u') if app.focus == Focus::Input => { app.input.clear(); app.input_cursor_pos = 0; } + KeyCode::Char('x') if app.focus == Focus::Input => { + app.pending_uploads.clear(); + app.status_message = Some("已移除待发送附件".to_string()); + } KeyCode::Up => app.scroll_chat_up(3), KeyCode::Down => app.scroll_chat_down(3), _ => {} @@ -85,6 +101,7 @@ pub async fn handle_key_event(app: &mut App, key: KeyEvent) { KeyCode::Esc => app.focus = Focus::Input, KeyCode::PageUp => app.scroll_chat_up(10), KeyCode::PageDown => app.scroll_chat_down(10), + KeyCode::F(2) => download_latest_attachment(app).await, KeyCode::Home if app.focus == Focus::Sessions => app.selected_session = 0, KeyCode::End if app.focus == Focus::Sessions => { app.selected_session = app.sessions.len().saturating_sub(1); @@ -95,7 +112,9 @@ pub async fn handle_key_event(app: &mut App, key: KeyEvent) { } pub fn handle_paste(app: &mut App, text: &str) { - if let Some(Modal::Rename { input, cursor }) = &mut app.modal { + if let Some(Modal::Rename { input, cursor } | Modal::AttachPath { input, cursor }) = + &mut app.modal + { let remaining = 256_usize.saturating_sub(input.len()); let mut end = text.len().min(remaining); while !text.is_char_boundary(end) { @@ -157,14 +176,36 @@ async fn handle_input_key(app: &mut App, key: KeyEvent) { KeyCode::Enter => { let input = app.take_input(); close_command_menu(app); - if !input.trim().is_empty() { - app.add_message(MessageRole::User, input.clone()); + if !input.trim().is_empty() || !app.pending_uploads.is_empty() { + let upload_ids = app + .pending_uploads + .iter() + .map(|upload| upload.upload_id.clone()) + .collect::>(); + let attachments = app + .pending_uploads + .iter() + .enumerate() + .map(|(index, upload)| MessageAttachment { + index: u32::try_from(index).unwrap_or(u32::MAX), + name: upload.name.clone(), + media_type: upload.media_type.clone(), + mime_type: upload.mime_type.clone(), + }) + .collect(); + app.add_message_with_attachments( + crate::util::short_id(), + MessageRole::User, + input.clone(), + attachments, + ); app.pending_responses = app.pending_responses.saturating_add(1); app.status_message = Some("PicoBot 正在处理…".to_string()); let sent = send( app, WsInbound::UserInput { content: input, + upload_ids, channel: None, // Session routing is owned by the server. A full session // id is not a chat id and must never be sent here. @@ -175,6 +216,8 @@ async fn handle_input_key(app: &mut App, key: KeyEvent) { .await; if !sent { app.pending_responses = app.pending_responses.saturating_sub(1); + } else { + app.pending_uploads.clear(); } } } @@ -259,10 +302,202 @@ async fn handle_modal_key(app: &mut App, key: KeyEvent) { } _ => app.modal = Some(Modal::Rename { input, cursor }), }, + Some(Modal::AttachPath { + mut input, + mut cursor, + }) => match key.code { + KeyCode::Esc => {} + KeyCode::Enter => { + let path = input.trim().to_string(); + if !path.is_empty() { + upload_tui_file(app, &path).await; + } + } + KeyCode::Char(character) => { + input.insert(cursor, character); + cursor += character.len_utf8(); + app.modal = Some(Modal::AttachPath { input, cursor }); + } + KeyCode::Backspace => { + if let Some((index, _)) = input[..cursor].char_indices().next_back() { + input.drain(index..cursor); + cursor = index; + } + app.modal = Some(Modal::AttachPath { input, cursor }); + } + KeyCode::Delete => { + if let Some(character) = input[cursor..].chars().next() { + input.drain(cursor..cursor + character.len_utf8()); + } + app.modal = Some(Modal::AttachPath { input, cursor }); + } + KeyCode::Left => { + if let Some((index, _)) = input[..cursor].char_indices().next_back() { + cursor = index; + } + app.modal = Some(Modal::AttachPath { input, cursor }); + } + KeyCode::Right => { + if let Some(character) = input[cursor..].chars().next() { + cursor += character.len_utf8(); + } + app.modal = Some(Modal::AttachPath { input, cursor }); + } + _ => app.modal = Some(Modal::AttachPath { input, cursor }), + }, None => {} } } +async fn upload_tui_file(app: &mut App, raw_path: &str) { + let path = std::path::PathBuf::from(raw_path); + let metadata = match tokio::fs::metadata(&path).await { + Ok(metadata) if metadata.is_file() => metadata, + _ => { + app.status_message = Some("附件路径不是可读普通文件".to_string()); + return; + } + }; + let file_name = path + .file_name() + .and_then(|value| value.to_str()) + .unwrap_or("attachment") + .to_string(); + let file = match tokio::fs::File::open(&path).await { + Ok(file) => file, + Err(error) => { + app.status_message = Some(format!("无法打开附件:{error}")); + return; + } + }; + app.status_message = Some(format!("正在上传 {file_name}…")); + let body = reqwest::Body::wrap_stream(ReaderStream::new(file)); + let part = reqwest::multipart::Part::stream_with_length(body, metadata.len()) + .file_name(file_name.clone()); + let form = reqwest::multipart::Form::new().part("file", part); + let url = format!("{}/api/chat/{}/uploads", app.http_base_url, app.client_id); + let client = reqwest::Client::new(); + let mut request = client.post(url).multipart(form); + if let Some(token) = &app.auth_token { + request = request.bearer_auth(token); + } + match request.send().await { + Ok(response) if response.status().is_success() => { + match response.json::().await { + Ok(upload) => { + app.status_message = Some(format!("已添加附件:{}", upload.name)); + app.pending_uploads.push(upload); + } + Err(error) => app.status_message = Some(format!("上传响应无效:{error}")), + } + } + Ok(response) => { + let status = response.status(); + let detail = response.text().await.unwrap_or_default(); + app.status_message = Some(format!("上传失败 ({status}):{detail}")); + } + Err(error) => app.status_message = Some(format!("上传失败:{error}")), + } +} + +async fn download_latest_attachment(app: &mut App) { + let Some(session_id) = app.current_session_id.clone() else { + return; + }; + let Some((message_id, attachment)) = app.messages.iter().rev().find_map(|message| { + message + .attachments + .first() + .map(|attachment| (message.id.clone(), attachment.clone())) + }) else { + app.status_message = Some("当前历史中没有附件".to_string()); + return; + }; + let mut url = match reqwest::Url::parse(&app.http_base_url) { + Ok(url) => url, + Err(error) => { + app.status_message = Some(format!("下载地址无效:{error}")); + return; + } + }; + if let Ok(mut segments) = url.path_segments_mut() { + segments.extend([ + "api", + "chat", + &app.client_id, + "sessions", + &session_id, + "messages", + &message_id, + "attachments", + &attachment.index.to_string(), + ]); + } + let client = reqwest::Client::new(); + let mut request = client.get(url); + if let Some(token) = &app.auth_token { + request = request.bearer_auth(token); + } + let response = match request.send().await { + Ok(response) if response.status().is_success() => response, + Ok(response) => { + app.status_message = Some(format!("附件不可用 ({})", response.status())); + return; + } + Err(error) => { + app.status_message = Some(format!("下载失败:{error}")); + return; + } + }; + let target = unique_download_path(&attachment.name); + let temporary = target.with_extension("picobot.part"); + let mut output = match tokio::fs::File::create(&temporary).await { + Ok(output) => output, + Err(error) => { + app.status_message = Some(format!("无法创建下载文件:{error}")); + return; + } + }; + let mut stream = response.bytes_stream(); + while let Some(chunk) = futures_util::StreamExt::next(&mut stream).await { + match chunk { + Ok(chunk) => { + if let Err(error) = output.write_all(&chunk).await { + let _ = tokio::fs::remove_file(&temporary).await; + app.status_message = Some(format!("写入下载文件失败:{error}")); + return; + } + } + Err(error) => { + let _ = tokio::fs::remove_file(&temporary).await; + app.status_message = Some(format!("下载中断:{error}")); + return; + } + } + } + drop(output); + if let Err(error) = tokio::fs::rename(&temporary, &target).await { + let _ = tokio::fs::remove_file(&temporary).await; + app.status_message = Some(format!("保存附件失败:{error}")); + return; + } + app.status_message = Some(format!("附件已保存到 {}", target.display())); +} + +fn unique_download_path(name: &str) -> std::path::PathBuf { + let safe = std::path::Path::new(name) + .file_name() + .and_then(|value| value.to_str()) + .unwrap_or("attachment"); + let mut candidate = std::path::PathBuf::from(safe); + let mut counter = 1_u32; + while candidate.exists() { + candidate = std::path::PathBuf::from(format!("{safe}.{counter}")); + counter += 1; + } + candidate +} + fn open_rename(app: &mut App) { if target_session_id(app).is_some() { let input = if app.focus == Focus::Sessions { diff --git a/src/client/tui/ui.rs b/src/client/tui/ui.rs index cef9b9d..64e337b 100644 --- a/src/client/tui/ui.rs +++ b/src/client/tui/ui.rs @@ -110,6 +110,33 @@ fn render_modal(frame: &mut Frame, area: Rect, modal: &Modal) { frame.set_cursor_position((cursor_x, cursor_y)); } } + Modal::AttachPath { input, cursor } => { + frame.render_widget( + Paragraph::new(vec![ + Line::from(Span::styled( + "添加附件路径", + Style::default().add_modifier(Modifier::BOLD), + )), + Line::from(""), + Line::from(input.as_str()), + Line::from(Span::styled( + "Enter 上传 · Esc 取消", + Style::default().fg(Color::DarkGray), + )), + ]) + .block(block) + .wrap(Wrap { trim: false }), + area, + ); + let cursor_x = area.x + + 1 + + UnicodeWidthStr::width(&input[..*cursor]) + .min(area.width.saturating_sub(3) as usize) as u16; + let cursor_y = area.y.saturating_add(3); + if cursor_x < area.right() && cursor_y < area.bottom() { + frame.set_cursor_position((cursor_x, cursor_y)); + } + } Modal::Confirm(action) => { let prompt = match action { ConfirmAction::Archive => "归档所选会话?", diff --git a/src/config/mod.rs b/src/config/mod.rs index 08c7404..f05b366 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -158,6 +158,8 @@ pub struct GatewayConfig { pub max_concurrent_background_tasks: usize, #[serde(default)] pub scheduler: Option, + #[serde(default)] + pub file_transfer: FileTransferConfig, } impl Default for GatewayConfig { @@ -171,10 +173,67 @@ impl Default for GatewayConfig { session_db_path: None, max_concurrent_background_tasks: 10, scheduler: None, + file_transfer: FileTransferConfig::default(), } } } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FileTransferConfig { + #[serde(default = "default_file_transfer_enabled")] + pub enabled: bool, + #[serde(default = "default_upload_dir")] + pub upload_dir: String, + #[serde(default = "default_max_file_bytes")] + pub max_file_bytes: u64, + #[serde(default = "default_max_files_per_message")] + pub max_files_per_message: usize, + #[serde(default = "default_max_message_bytes")] + pub max_message_bytes: u64, + #[serde(default = "default_pending_ttl_seconds")] + pub pending_ttl_seconds: u64, +} + +impl Default for FileTransferConfig { + fn default() -> Self { + Self { + enabled: default_file_transfer_enabled(), + upload_dir: default_upload_dir(), + max_file_bytes: default_max_file_bytes(), + max_files_per_message: default_max_files_per_message(), + max_message_bytes: default_max_message_bytes(), + pending_ttl_seconds: default_pending_ttl_seconds(), + } + } +} + +fn default_file_transfer_enabled() -> bool { + true +} + +fn default_upload_dir() -> String { + get_user_config_dir() + .join("media/cli_chat") + .to_string_lossy() + .to_string() +} + +fn default_max_file_bytes() -> u64 { + 25 * 1024 * 1024 +} + +fn default_max_files_per_message() -> usize { + 8 +} + +fn default_max_message_bytes() -> u64 { + 64 * 1024 * 1024 +} + +fn default_pending_ttl_seconds() -> u64 { + 60 * 60 +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SchedulerConfig { /// Whether the scheduler is enabled @@ -639,6 +698,11 @@ mod tests { assert_eq!(config.gateway.host, "0.0.0.0"); assert_eq!(config.gateway.port, 19876); assert!(config.gateway.require_pairing); + assert!(config.gateway.file_transfer.enabled); + assert_eq!( + config.gateway.file_transfer.max_file_bytes, + 25 * 1024 * 1024 + ); } #[test] diff --git a/src/gateway/http.rs b/src/gateway/http.rs index 3c72263..2ee16bf 100644 --- a/src/gateway/http.rs +++ b/src/gateway/http.rs @@ -3,7 +3,7 @@ use crate::config::Config; use crate::memory::MemoryCategory; use axum::Json; use axum::body::Body; -use axum::extract::{Path, Query, State}; +use axum::extract::{Multipart, Path, Query, State}; use axum::http::{StatusCode, header}; use axum::response::{IntoResponse, Response}; use serde::{Deserialize, Serialize}; @@ -11,12 +11,26 @@ use serde_json::{Value, json}; use std::collections::VecDeque; use std::path::{Path as FsPath, PathBuf}; use std::sync::Arc; -use tokio::io::{AsyncReadExt, AsyncSeekExt}; +use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; +use tokio_util::io::ReaderStream; const REDACTED: &str = "********"; const MAX_CONFIG_BYTES: usize = 1024 * 1024; const MAX_PROFILE_BYTES: usize = 256 * 1024; +struct TemporaryUpload { + path: PathBuf, + committed: bool, +} + +impl Drop for TemporaryUpload { + fn drop(&mut self) { + if !self.committed { + let _ = std::fs::remove_file(&self.path); + } + } +} + #[derive(Serialize)] pub struct HealthResponse { status: String, @@ -85,6 +99,13 @@ impl ApiError { } } + fn payload_too_large(message: impl Into) -> Self { + Self { + status: StatusCode::PAYLOAD_TOO_LARGE, + message: message.into(), + } + } + fn internal(error: impl std::fmt::Display) -> Self { tracing::error!(error = %error, "WebUI API request failed"); Self { @@ -94,6 +115,219 @@ impl ApiError { } } +pub async fn upload_file( + State(state): State>, + Path(client_id): Path, + mut multipart: Multipart, +) -> Result<(StatusCode, Json), ApiError> { + if !valid_client_id(&client_id) { + return Err(ApiError::bad_request("invalid client id")); + } + if !state.uploads.enabled() { + return Err(ApiError::bad_request("file transfer is disabled")); + } + + let mut field = multipart + .next_field() + .await + .map_err(|error| ApiError::bad_request(format!("invalid multipart body: {error}")))? + .ok_or_else(|| ApiError::bad_request("file field is required"))?; + if field.name() != Some("file") { + return Err(ApiError::bad_request("expected multipart field named file")); + } + let original_name = field.file_name().unwrap_or("attachment").to_string(); + let safe_name = crate::gateway::uploads::UploadRegistry::safe_file_name(&original_name); + let (temporary_path, final_path, upload_id) = state + .uploads + .allocate_path(&client_id, &safe_name) + .await + .map_err(ApiError::internal)?; + let mut temporary = TemporaryUpload { + path: temporary_path.clone(), + committed: false, + }; + let mut output = tokio::fs::File::create(&temporary_path) + .await + .map_err(ApiError::internal)?; + let mut size = 0_u64; + while let Some(chunk) = field + .chunk() + .await + .map_err(|error| ApiError::bad_request(format!("failed to read upload: {error}")))? + { + size = size.saturating_add(chunk.len() as u64); + if size > state.uploads.max_file_bytes() { + drop(output); + let _ = tokio::fs::remove_file(&temporary_path).await; + return Err(ApiError::payload_too_large(format!( + "file exceeds {} bytes", + state.uploads.max_file_bytes() + ))); + } + if let Err(error) = output.write_all(&chunk).await { + drop(output); + let _ = tokio::fs::remove_file(&temporary_path).await; + return Err(ApiError::internal(error)); + } + } + if size == 0 { + drop(output); + let _ = tokio::fs::remove_file(&temporary_path).await; + return Err(ApiError::bad_request("empty files are not supported")); + } + output.sync_all().await.map_err(ApiError::internal)?; + drop(output); + tokio::fs::rename(&temporary_path, &final_path) + .await + .map_err(ApiError::internal)?; + temporary.committed = true; + + let mime_type = mime_guess::from_path(&safe_name) + .first_or_octet_stream() + .to_string(); + let media_type = media_type_for_mime(&mime_type).to_string(); + let descriptor = match state + .uploads + .register( + upload_id, + client_id, + final_path.clone(), + crate::protocol::UploadDescriptor { + upload_id: String::new(), + name: safe_name, + media_type, + mime_type, + size, + expires_at: 0, + }, + ) + .await + { + Ok(descriptor) => descriptor, + Err(error) => { + let _ = tokio::fs::remove_file(final_path).await; + return Err(ApiError::bad_request(error.to_string())); + } + }; + Ok((StatusCode::CREATED, Json(descriptor))) +} + +#[derive(Debug, Default, Deserialize)] +pub struct AttachmentQuery { + disposition: Option, +} + +pub async fn download_attachment( + State(state): State>, + Path((client_id, session_id, message_id, index)): Path<(String, String, String, usize)>, + Query(query): Query, +) -> Result { + if !valid_client_id(&client_id) { + return Err(ApiError::not_found("attachment not found")); + } + let unified = crate::session::UnifiedSessionId::parse(&session_id) + .filter(|id| id.channel == "cli_chat" && id.chat_id == client_id) + .ok_or_else(|| ApiError::not_found("attachment not found"))?; + let message = state + .storage + .get_message(&unified.to_string(), &message_id) + .await + .map_err(ApiError::internal)? + .ok_or_else(|| ApiError::not_found("attachment not found"))?; + let media_refs = message + .media_refs + .as_deref() + .and_then(|value| serde_json::from_str::>(value).ok()) + .unwrap_or_default(); + let media_ref = media_refs + .get(index) + .ok_or_else(|| ApiError::not_found("attachment not found"))?; + let path = FsPath::new(&media_ref.path); + let metadata = tokio::fs::metadata(path) + .await + .map_err(|_| ApiError::not_found("the original file was moved or deleted"))?; + if !metadata.is_file() { + return Err(ApiError::not_found( + "the original file was moved or deleted", + )); + } + let file = tokio::fs::File::open(path) + .await + .map_err(|_| ApiError::not_found("the original file was moved or deleted"))?; + let name = path + .file_name() + .and_then(|value| value.to_str()) + .map(crate::gateway::uploads::UploadRegistry::safe_file_name) + .unwrap_or_else(|| "attachment".to_string()); + let mime_type = mime_guess::from_path(&name) + .first_or_octet_stream() + .to_string(); + let inline = query.disposition.as_deref() == Some("inline") && inline_mime_allowed(&mime_type); + let disposition = if inline { "inline" } else { "attachment" }; + let encoded_name = encode_header_filename(&name); + + Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_TYPE, mime_type) + .header(header::CONTENT_LENGTH, metadata.len()) + .header( + header::CONTENT_DISPOSITION, + format!("{disposition}; filename*=UTF-8''{encoded_name}"), + ) + .header("X-Content-Type-Options", "nosniff") + .header(header::CACHE_CONTROL, "private, no-store") + .body(Body::from_stream(ReaderStream::new(file))) + .map_err(ApiError::internal) +} + +fn valid_client_id(value: &str) -> bool { + !value.is_empty() + && value.len() <= 64 + && value + .bytes() + .all(|byte| byte.is_ascii_alphanumeric() || byte == b'-' || byte == b'_') +} + +fn media_type_for_mime(mime: &str) -> &'static str { + if mime.starts_with("image/") { + "image" + } else if mime.starts_with("audio/") { + "audio" + } else if mime.starts_with("video/") { + "video" + } else { + "file" + } +} + +fn inline_mime_allowed(mime: &str) -> bool { + matches!( + mime, + "image/png" + | "image/jpeg" + | "image/gif" + | "image/webp" + | "audio/mpeg" + | "audio/ogg" + | "audio/wav" + | "video/mp4" + | "video/webm" + ) +} + +fn encode_header_filename(value: &str) -> String { + value + .as_bytes() + .iter() + .map(|byte| match *byte { + b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'.' | b'_' | b'-' => { + (*byte as char).to_string() + } + other => format!("%{other:02X}"), + }) + .collect() +} + impl IntoResponse for ApiError { fn into_response(self) -> Response { (self.status, Json(json!({ "error": self.message }))).into_response() @@ -482,4 +716,15 @@ mod tests { ); assert!(response.headers().contains_key("Content-Security-Policy")); } + + #[test] + fn attachment_headers_are_safely_encoded_and_inline_is_allowlisted() { + assert_eq!( + encode_header_filename("报告 1.pdf"), + "%E6%8A%A5%E5%91%8A%201.pdf" + ); + assert!(inline_mime_allowed("image/png")); + assert!(!inline_mime_allowed("image/svg+xml")); + assert!(!inline_mime_allowed("text/html")); + } } diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index 772c785..9d40aa1 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -1,5 +1,6 @@ pub mod auth; pub mod http; +pub mod uploads; pub mod ws; use axum::{Router, middleware, routing}; @@ -28,6 +29,7 @@ pub struct GatewayState { pub task_supervisor: TaskSupervisor, pub connection_shutdown: tokio_util::sync::CancellationToken, pub auth: auth::AuthManager, + pub uploads: uploads::UploadRegistry, } impl GatewayState { @@ -41,6 +43,7 @@ impl GatewayState { crate::config::get_user_config_dir().join("web_auth.json"), ) .await?; + let uploads = uploads::UploadRegistry::new(config.gateway.file_transfer.clone()); // Initialize workspace directory: expand path and ensure it exists let workspace_path = expand_path(&config.workspace_dir); @@ -118,7 +121,7 @@ impl GatewayState { let session_manager = Arc::new(session_manager); // Create ChannelManager and init channels - let cli_chat_channel = Arc::new(CliChatChannel::new()); + let cli_chat_channel = Arc::new(CliChatChannel::with_upload_registry(uploads.clone())); let channel_manager = ChannelManager::with_bus(cli_chat_channel, bus); channel_manager .init(&config, workspace_path.clone()) @@ -201,6 +204,7 @@ impl GatewayState { task_supervisor, connection_shutdown, auth, + uploads, }) } @@ -220,6 +224,22 @@ impl GatewayState { let bus_for_outbound = bus.clone(); let session_manager = self.session_manager.clone(); + if self.uploads.enabled() { + let uploads = self.uploads.clone(); + self.task_supervisor + .spawn("pending-upload-cleanup", async move { + let mut interval = tokio::time::interval(std::time::Duration::from_secs(300)); + interval.tick().await; + loop { + interval.tick().await; + let removed = uploads.cleanup_expired().await; + if removed > 0 { + tracing::debug!(removed, "Expired pending uploads removed"); + } + } + }); + } + // Relay structured plan changes to WebSocket clients. This remains // separate from chat messages, so task UI updates never pollute history. let mut plan_events = self.session_manager.work_manager().subscribe(); @@ -480,6 +500,14 @@ pub async fn run( .route("/api/jobs", routing::get(http::get_jobs)) .route("/api/jobs/{id}/runs", routing::get(http::get_job_runs)) .route("/api/memories", routing::get(http::get_memories)) + .route( + "/api/chat/{client_id}/uploads", + routing::post(http::upload_file).layer(axum::extract::DefaultBodyLimit::disable()), + ) + .route( + "/api/chat/{client_id}/sessions/{session_id}/messages/{message_id}/attachments/{index}", + routing::get(http::download_attachment), + ) .route("/ws", routing::get(ws::ws_handler)) .route_layer(middleware::from_fn_with_state( state.auth.clone(), diff --git a/src/gateway/uploads.rs b/src/gateway/uploads.rs new file mode 100644 index 0000000..f6aac07 --- /dev/null +++ b/src/gateway/uploads.rs @@ -0,0 +1,310 @@ +use std::collections::{HashMap, HashSet}; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +use sha2::{Digest, Sha256}; +use tokio::sync::Mutex; + +use crate::bus::MediaItem; +use crate::config::{FileTransferConfig, expand_path}; +use crate::protocol::UploadDescriptor; + +#[derive(Debug, Clone)] +pub struct PendingUpload { + pub descriptor: UploadDescriptor, + pub owner_chat_id: String, + pub path: PathBuf, + expires_at: Instant, +} + +#[derive(Debug, thiserror::Error)] +pub enum UploadError { + #[error("file transfer is disabled")] + Disabled, + #[error("too many files; maximum is {0}")] + TooManyFiles(usize), + #[error("duplicate upload id")] + Duplicate, + #[error("upload not found or expired")] + NotFound, + #[error("upload does not belong to this client")] + WrongOwner, + #[error("attachments exceed the per-message limit of {0} bytes")] + MessageTooLarge(u64), +} + +#[derive(Clone)] +pub struct UploadRegistry { + config: FileTransferConfig, + upload_dir: PathBuf, + pending: Arc>>, +} + +impl UploadRegistry { + pub fn new(config: FileTransferConfig) -> Self { + let upload_dir = expand_path(&config.upload_dir); + Self { + config, + upload_dir, + pending: Arc::new(Mutex::new(HashMap::new())), + } + } + + pub fn disabled() -> Self { + let config = FileTransferConfig { + enabled: false, + ..FileTransferConfig::default() + }; + Self::new(config) + } + + pub fn enabled(&self) -> bool { + self.config.enabled + } + + pub fn max_file_bytes(&self) -> u64 { + self.config.max_file_bytes + } + + pub fn safe_file_name(name: &str) -> String { + let base = Path::new(name) + .file_name() + .and_then(|value| value.to_str()) + .unwrap_or("attachment"); + let cleaned = base + .chars() + .filter(|character| !character.is_control() && *character != '/' && *character != '\\') + .collect::(); + let cleaned = cleaned.trim().trim_matches('.'); + let mut result = if cleaned.is_empty() { + "attachment".to_string() + } else { + cleaned.to_string() + }; + while result.len() > 180 { + result.pop(); + } + result + } + + pub async fn allocate_path( + &self, + chat_id: &str, + file_name: &str, + ) -> Result<(PathBuf, PathBuf, String), std::io::Error> { + let scope_hash = hex_digest(chat_id.as_bytes()); + let upload_id = uuid::Uuid::new_v4().to_string(); + let directory = self.upload_dir.join(&scope_hash[..16]).join(&upload_id); + tokio::fs::create_dir_all(&directory).await?; + let safe_name = Self::safe_file_name(file_name); + let final_path = directory.join(&safe_name); + let temporary_path = directory.join(".upload.part"); + Ok((temporary_path, final_path, upload_id)) + } + + pub async fn register( + &self, + upload_id: String, + chat_id: String, + path: PathBuf, + mut descriptor: UploadDescriptor, + ) -> Result { + if !self.enabled() { + return Err(UploadError::Disabled); + } + let ttl = Duration::from_secs(self.config.pending_ttl_seconds.max(1)); + let expires_at = Instant::now() + ttl; + let expires_at_unix = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_secs() + .saturating_add(ttl.as_secs()) as i64; + descriptor.upload_id = upload_id.clone(); + descriptor.expires_at = expires_at_unix; + let mut pending = self.pending.lock().await; + pending.insert( + upload_id, + PendingUpload { + descriptor: descriptor.clone(), + owner_chat_id: chat_id, + path, + expires_at, + }, + ); + Ok(descriptor) + } + + pub async fn take_many( + &self, + chat_id: &str, + upload_ids: &[String], + ) -> Result, UploadError> { + if upload_ids.is_empty() { + return Ok(Vec::new()); + } + if !self.enabled() { + return Err(UploadError::Disabled); + } + if upload_ids.len() > self.config.max_files_per_message { + return Err(UploadError::TooManyFiles(self.config.max_files_per_message)); + } + let unique = upload_ids.iter().collect::>(); + if unique.len() != upload_ids.len() { + return Err(UploadError::Duplicate); + } + + let now = Instant::now(); + let mut pending = self.pending.lock().await; + let mut total = 0_u64; + for id in upload_ids { + let upload = pending.get(id).ok_or(UploadError::NotFound)?; + if upload.expires_at <= now { + return Err(UploadError::NotFound); + } + if upload.owner_chat_id != chat_id { + return Err(UploadError::WrongOwner); + } + total = total.saturating_add(upload.descriptor.size); + } + if total > self.config.max_message_bytes { + return Err(UploadError::MessageTooLarge(self.config.max_message_bytes)); + } + + Ok(upload_ids + .iter() + .filter_map(|id| pending.remove(id)) + .collect()) + } + + pub async fn restore(&self, uploads: Vec) { + let mut pending = self.pending.lock().await; + for upload in uploads { + pending.insert(upload.descriptor.upload_id.clone(), upload); + } + } + + pub async fn cleanup_expired(&self) -> usize { + let now = Instant::now(); + let expired = { + let mut pending = self.pending.lock().await; + let ids = pending + .iter() + .filter(|(_, upload)| upload.expires_at <= now) + .map(|(id, _)| id.clone()) + .collect::>(); + ids.into_iter() + .filter_map(|id| pending.remove(&id)) + .map(|upload| upload.path) + .collect::>() + }; + let count = expired.len(); + for path in expired { + let _ = tokio::fs::remove_file(&path).await; + if let Some(parent) = path.parent() { + let _ = tokio::fs::remove_dir(parent).await; + } + } + count + } + + pub fn as_media(upload: &PendingUpload) -> MediaItem { + MediaItem { + path: upload.path.to_string_lossy().into_owned(), + media_type: upload.descriptor.media_type.clone(), + mime_type: Some(upload.descriptor.mime_type.clone()), + original_key: None, + } + } +} + +fn hex_digest(value: &[u8]) -> String { + let digest = Sha256::digest(value); + digest.iter().map(|byte| format!("{byte:02x}")).collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sanitizes_file_names() { + assert_eq!( + UploadRegistry::safe_file_name("../../report.pdf"), + "report.pdf" + ); + assert_eq!(UploadRegistry::safe_file_name(".."), "attachment"); + assert_eq!(UploadRegistry::safe_file_name("a\n.txt"), "a.txt"); + } + + #[tokio::test] + async fn upload_ids_are_scoped_and_consumed() { + let registry = UploadRegistry::new(FileTransferConfig::default()); + registry + .register( + "upload-1".into(), + "client-a".into(), + PathBuf::from("/tmp/a"), + UploadDescriptor { + upload_id: String::new(), + name: "a.txt".into(), + media_type: "file".into(), + mime_type: "text/plain".into(), + size: 10, + expires_at: 0, + }, + ) + .await + .unwrap(); + + assert!(matches!( + registry.take_many("client-b", &["upload-1".into()]).await, + Err(UploadError::WrongOwner) + )); + assert_eq!( + registry + .take_many("client-a", &["upload-1".into()]) + .await + .unwrap() + .len(), + 1 + ); + assert!(matches!( + registry.take_many("client-a", &["upload-1".into()]).await, + Err(UploadError::NotFound) + )); + } + + #[tokio::test] + async fn expired_pending_uploads_are_removed() { + let directory = tempfile::tempdir().unwrap(); + let config = FileTransferConfig { + upload_dir: directory.path().to_string_lossy().into_owned(), + pending_ttl_seconds: 1, + ..FileTransferConfig::default() + }; + let registry = UploadRegistry::new(config); + let path = directory.path().join("expired.txt"); + tokio::fs::write(&path, b"expired").await.unwrap(); + registry + .register( + "expired".into(), + "client".into(), + path.clone(), + UploadDescriptor { + upload_id: String::new(), + name: "expired.txt".into(), + media_type: "file".into(), + mime_type: "text/plain".into(), + size: 7, + expires_at: 0, + }, + ) + .await + .unwrap(); + tokio::time::sleep(Duration::from_millis(1_050)).await; + + assert_eq!(registry.cleanup_expired().await, 1); + assert!(!path.exists()); + } +} diff --git a/src/gateway/ws.rs b/src/gateway/ws.rs index e9c4c60..5831e72 100644 --- a/src/gateway/ws.rs +++ b/src/gateway/ws.rs @@ -56,6 +56,11 @@ async fn handle_socket( let _ = sender .send(WsOutbound::SessionEstablished { session_id: session_id.clone(), + capabilities: if state.uploads.enabled() { + vec!["file_transfer_v1".to_string()] + } else { + Vec::new() + }, }) .await; diff --git a/src/protocol.rs b/src/protocol.rs index 637c68f..9a43174 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -19,6 +19,43 @@ pub struct SlashCommandInfo { pub aliases: Vec, } +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct UploadDescriptor { + pub upload_id: String, + pub name: String, + pub media_type: String, + pub mime_type: String, + pub size: u64, + pub expires_at: i64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct MessageAttachment { + pub index: u32, + pub name: String, + pub media_type: String, + pub mime_type: String, +} + +impl MessageAttachment { + pub fn from_media_ref(index: usize, media_ref: &crate::bus::MediaRef) -> Self { + let name = std::path::Path::new(&media_ref.path) + .file_name() + .map(|name| name.to_string_lossy().into_owned()) + .filter(|name| !name.is_empty()) + .unwrap_or_else(|| "attachment".to_string()); + let mime_type = mime_guess::from_path(&name) + .first_or_octet_stream() + .to_string(); + Self { + index: u32::try_from(index).unwrap_or(u32::MAX), + name, + media_type: media_ref.media_type.clone(), + mime_type, + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HistoryMessage { pub id: String, @@ -32,6 +69,8 @@ pub struct HistoryMessage { pub tool_name: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub tool_calls: Option>, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub attachments: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -40,6 +79,8 @@ pub enum WsInbound { #[serde(rename = "user_input")] UserInput { content: String, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + upload_ids: Vec, #[serde(default, skip_serializing_if = "Option::is_none")] channel: Option, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -104,13 +145,19 @@ pub enum WsOutbound { id: String, content: String, role: String, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + attachments: Vec, #[serde(default, skip_serializing_if = "Option::is_none")] session_id: Option, }, #[serde(rename = "error")] Error { code: String, message: String }, #[serde(rename = "session_established")] - SessionEstablished { session_id: String }, + SessionEstablished { + session_id: String, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + capabilities: Vec, + }, #[serde(rename = "session_created")] SessionCreated { session_id: String, title: String }, #[serde(rename = "session_list")] diff --git a/src/session/messenger.rs b/src/session/messenger.rs index d527f1d..26fad85 100644 --- a/src/session/messenger.rs +++ b/src/session/messenger.rs @@ -54,6 +54,7 @@ impl OutboundMessenger for SessionManager { }; let message = outbound_history_message(marked_content.clone(), source, &media); + let message_id = message.id.clone(); append_persisted_messages(&session, vec![message]) .await .map_err(|error| error.to_string())?; @@ -62,6 +63,10 @@ impl OutboundMessenger for SessionManager { self.restore_origin_dialog(&origin_id, &target_sid).await; } + let metadata = HashMap::from([ + ("_session_id".to_string(), target_sid.to_string()), + ("_message_id".to_string(), message_id), + ]); self.bus .deliver_outbound(OutboundMessage { channel: channel.to_string(), @@ -69,7 +74,7 @@ impl OutboundMessenger for SessionManager { content: marked_content, reply_to: None, media, - metadata: HashMap::new(), + metadata, delivery: None, }) .await diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 3628f55..1d3612d 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -859,6 +859,40 @@ impl Storage { .collect()) } + pub async fn get_message( + &self, + session_id: &str, + message_id: &str, + ) -> Result, StorageError> { + let row = sqlx::query( + r#" + SELECT id, session_id, seq, role, content, reasoning_content, media_refs, + tool_call_id, tool_name, tool_calls, source, created_at + FROM messages + WHERE session_id = ? AND id = ? + "#, + ) + .bind(session_id) + .bind(message_id) + .fetch_optional(self.pool()) + .await?; + + Ok(row.map(|row| crate::storage::message::MessageMeta { + id: row.get("id"), + session_id: row.get("session_id"), + seq: row.get("seq"), + role: row.get("role"), + content: row.get("content"), + reasoning_content: row.get("reasoning_content"), + media_refs: row.get("media_refs"), + tool_call_id: row.get("tool_call_id"), + tool_name: row.get("tool_name"), + tool_calls: row.get("tool_calls"), + source: row.get("source"), + created_at: row.get("created_at"), + })) + } + pub async fn get_max_message_seq(&self, session_id: &str) -> Result { let row = sqlx::query( "SELECT COALESCE(MAX(seq), 0) as max_seq FROM messages WHERE session_id = ?", diff --git a/tests/test_request_format.rs b/tests/test_request_format.rs index bf2d10b..a6a5be7 100644 --- a/tests/test_request_format.rs +++ b/tests/test_request_format.rs @@ -139,6 +139,7 @@ fn test_bounded_session_history_protocol() { tool_call_id: None, tool_name: None, tool_calls: None, + attachments: Vec::new(), }], }; let decoded: WsOutbound = @@ -152,6 +153,26 @@ fn test_bounded_session_history_protocol() { } } +#[test] +fn test_user_input_accepts_upload_ids_and_old_payloads() { + let old: WsInbound = + serde_json::from_str(r#"{"type":"user_input","content":"hello"}"#).unwrap(); + match old { + WsInbound::UserInput { upload_ids, .. } => assert!(upload_ids.is_empty()), + other => panic!("unexpected decoded variant: {other:?}"), + } + + let message = WsInbound::UserInput { + content: "处理文件".to_string(), + upload_ids: vec!["upload-1".to_string()], + channel: None, + chat_id: None, + sender_id: None, + }; + let json = serde_json::to_string(&message).unwrap(); + assert!(json.contains(r#""upload_ids":["upload-1"]"#)); +} + #[test] fn test_session_history_preserves_tool_call_metadata() { let outbound = WsOutbound::SessionHistory { @@ -169,6 +190,7 @@ fn test_session_history_preserves_tool_call_metadata() { name: "read_file".to_string(), arguments: serde_json::json!({ "path": "README.md" }), }]), + attachments: Vec::new(), }], }; diff --git a/tmp.jpg b/tmp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..029b253f03bc1e654d3569086bae080c50ac2fa3 GIT binary patch literal 247595 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

#V1;EeQ%83WbC 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 cB9{F=cSuYd%o#gc`5{VIJ8u*(Vh`r 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 VkA~^erWu%yWMK-`~U!G}Sra16x)4jT%$C4j_ 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 PbYeg9pDd5uzi0j%< upload.status === "ready"); + if ((!content && !ready.length) || !connected || pendingUploads.some((upload) => upload.status === "uploading")) return; + appendMessage("user", content, ready.map((upload, index) => ({ + index, + name: upload.name, + media_type: upload.media_type, + mime_type: upload.mime_type, + local_url: upload.localUrl + }))); thinking = true; - send({ type: "user_input", content }); + send({ type: "user_input", content, upload_ids: ready.map((upload) => upload.upload_id) }); draft = ""; + pendingUploads = []; commandMenuDismissed = false; selectedCommand = 0; if (input) input.style.height = "auto"; } + function attachmentUrl(message, attachment, inline = false) { + if (attachment.local_url) return attachment.local_url; + if (!currentId || !message.id) return ""; + const base = `/api/chat/${encodeURIComponent(clientId())}/sessions/${encodeURIComponent(currentId)}/messages/${encodeURIComponent(message.id)}/attachments/${attachment.index}`; + return inline ? `${base}?disposition=inline` : base; + } + + function formatBytes(value) { + if (!Number.isFinite(value)) return ""; + if (value < 1024) return `${value} B`; + if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KiB`; + return `${(value / 1024 / 1024).toFixed(1)} MiB`; + } + + function canPreview(attachment) { + return ["image/png", "image/jpeg", "image/gif", "image/webp"].includes(attachment.mime_type); + } + + function addFiles(files) { + for (const file of Array.from(files || [])) uploadFile(file); + } + + function uploadFile(file) { + if (!connected) return notify("聊天连接尚未就绪", true); + const localId = crypto.randomUUID(); + const localUrl = file.type.startsWith("image/") ? URL.createObjectURL(file) : null; + pendingUploads = [...pendingUploads, { + localId, name: file.name, size: file.size, progress: 0, status: "uploading", localUrl + }]; + const body = new FormData(); + body.append("file", file, file.name); + const request = new XMLHttpRequest(); + request.open("POST", `/api/chat/${encodeURIComponent(clientId())}/uploads`); + request.upload.onprogress = (event) => { + if (!event.lengthComputable) return; + pendingUploads = pendingUploads.map((item) => item.localId === localId + ? { ...item, progress: Math.round(event.loaded / event.total * 100) } + : item); + }; + request.onload = () => { + let response = {}; + try { response = JSON.parse(request.responseText || "{}"); } catch {} + if (request.status >= 200 && request.status < 300) { + pendingUploads = pendingUploads.map((item) => item.localId === localId + ? { ...item, ...response, status: "ready", progress: 100 } + : item); + } else { + pendingUploads = pendingUploads.map((item) => item.localId === localId + ? { ...item, status: "error", error: response.error || `上传失败 (${request.status})` } + : item); + } + }; + request.onerror = () => { + pendingUploads = pendingUploads.map((item) => item.localId === localId + ? { ...item, status: "error", error: "网络错误" } + : item); + }; + request.send(body); + } + + function removeUpload(localId) { + const upload = pendingUploads.find((item) => item.localId === localId); + if (upload?.localUrl) URL.revokeObjectURL(upload.localUrl); + pendingUploads = pendingUploads.filter((item) => item.localId !== localId); + } + + function clearPendingUploads() { + for (const upload of pendingUploads) if (upload.localUrl) URL.revokeObjectURL(upload.localUrl); + pendingUploads = []; + } + + function dropFiles(event) { + event.preventDefault(); + addFiles(event.dataTransfer?.files); + } + + function pasteFiles(event) { + const files = Array.from(event.clipboardData?.items || []) + .filter((item) => item.kind === "file") + .map((item) => item.getAsFile()) + .filter(Boolean); + if (files.length) addFiles(files); + } + async function moveCommandSelection(offset) { const length = commandSuggestions.length; if (!length) return; @@ -247,6 +342,7 @@ stopped = true; clearTimeout(reconnectTimer); socket?.close(); + clearPendingUploads(); }; }); @@ -283,11 +379,24 @@

今天想做些什么?

消息与 CLI 客户端使用同一套会话、记忆和工具能力。

{/if} {#each messages as message (message.id)} - {#if message.role !== "tool" && (message.content || message.tool_calls?.length)} + {#if message.role !== "tool" && (message.content || message.tool_calls?.length || message.attachments?.length)}
{message.role === "user" ? "你" : "P"}
{#if message.content}
{/if} + {#if message.attachments?.length} +
+ {#each message.attachments as attachment (`${message.id}:${attachment.index}`)} +
+ {#if canPreview(attachment)} + {attachment.name} + {:else}{/if} +
{attachment.name}{attachment.mime_type || attachment.media_type}
+ +
+ {/each} +
+ {/if} {#if message.tool_calls?.length}
{#each message.tool_calls as call (call.id)} @@ -301,7 +410,7 @@ {/each} {#if thinking}
P
正在思考…
{/if}
-
{ event.preventDefault(); submit(); }}> + { event.preventDefault(); submit(); }} ondragover={(event) => event.preventDefault()} ondrop={dropFiles}> {#if commandSuggestions.length}
斜杠命令↑↓ 选择 · Tab/Enter 补全 · Esc 关闭
@@ -320,11 +429,24 @@ {/each}
{/if} + {#if pendingUploads.length} +
+ {#each pendingUploads as upload (upload.localId)} +
+
{upload.name}{upload.status === "uploading" ? `上传中 ${upload.progress}%` : upload.status === "error" ? upload.error : formatBytes(upload.size)}
+ +
+ {/each} +
+ {/if} + { addFiles(event.currentTarget.files); event.currentTarget.value = ""; }} /> + - + {connected ? "已连接" : "已断开,正在重连"}/ 打开命令 · Shift+Enter 换行
diff --git a/webui/src/styles.css b/webui/src/styles.css index 5efe6ea..63265cd 100644 --- a/webui/src/styles.css +++ b/webui/src/styles.css @@ -143,6 +143,12 @@ main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } .message.user .message-content { justify-items: end; } .bubble { max-width: 100%; padding: 11px 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); font-size: 14px; line-height: 1.62; overflow-wrap: anywhere; } .message.user .bubble { background: var(--user-bubble); border-color: var(--accent-border); } +.message-attachments { display: grid; gap: 7px; width: min(100%, 520px); } +.attachment-card { display: grid; grid-template-columns: 42px minmax(0, 1fr) 30px; gap: 9px; align-items: center; padding: 8px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel); } +.attachment-card img, .attachment-icon { width: 42px; height: 42px; border-radius: 7px; object-fit: cover; background: var(--panel-2); display: grid; place-items: center; color: var(--accent); } +.attachment-card strong, .attachment-card small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.attachment-card strong { font-size: 12px; }.attachment-card small { margin-top: 3px; color: var(--muted); font-size: 9px; } +.attachment-card a { width: 28px; height: 28px; display: grid; place-items: center; border: 1px solid var(--line); border-radius: 7px; color: var(--accent); text-decoration: none; } .typing .bubble { color: var(--muted); } .pulse { display: inline-block; width: 6px; height: 6px; margin-right: 8px; border-radius: 50%; background: var(--accent); animation: pulse 1.1s infinite; } @keyframes pulse { 50% { opacity: .25; transform: scale(.8); } } @@ -182,8 +188,13 @@ main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } .tool-call-details > div > span { display: block; margin-bottom: 6px; color: var(--muted); font-size: 9px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; } .tool-call-details pre, .tool-result { max-height: 300px; margin: 0; padding: 10px 11px; overflow: auto; border: 1px solid var(--line); border-radius: 8px; color: var(--text-soft); background: var(--code-bg); font: 11px/1.55 ui-monospace, SFMono-Regular, Consolas, monospace; white-space: pre-wrap; overflow-wrap: anywhere; } .tool-result .markdown-body { font: inherit; } -.composer { position: relative; margin: 0 max(18px, calc((100% - 850px) / 2)) 18px; border: 1px solid var(--line); background: var(--panel); border-radius: 14px; padding: 10px 11px 6px; display: grid; grid-template-columns: 1fr 38px; box-shadow: var(--shadow); } +.composer { position: relative; margin: 0 max(18px, calc((100% - 850px) / 2)) 18px; border: 1px solid var(--line); background: var(--panel); border-radius: 14px; padding: 10px 11px 6px; display: grid; grid-template-columns: 38px 1fr 38px; box-shadow: var(--shadow); } .composer textarea { resize: none; max-height: 180px; background: transparent; border: 0; outline: 0; color: var(--text); padding: 7px; line-height: 1.5; } +.file-input { display: none; } +.attach { width: 34px; height: 34px; align-self: end; border: 1px solid var(--line); border-radius: 9px; color: var(--muted); background: var(--panel-2); cursor: pointer; font-size: 18px; } +.pending-uploads { grid-column: 1 / -1; display: flex; gap: 7px; padding: 2px 4px 8px; overflow-x: auto; } +.pending-upload { min-width: 170px; max-width: 260px; display: grid; grid-template-columns: 24px minmax(0, 1fr) 22px; gap: 6px; align-items: center; padding: 7px; border: 1px solid var(--line); border-radius: 9px; background: var(--panel-2); } +.pending-upload.error { border-color: var(--danger); }.pending-upload strong, .pending-upload small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }.pending-upload strong { font-size: 10px; }.pending-upload small { color: var(--muted); font-size: 9px; }.pending-upload button { border: 0; color: var(--muted); background: none; cursor: pointer; } .send { width: 36px; height: 36px; border-radius: 10px; color: var(--accent-contrast); background: var(--accent); border: 0; font-size: 19px; cursor: pointer; } .composer small { grid-column: 1 / -1; display: flex; justify-content: space-between; padding: 3px 7px; color: var(--muted); font-size: 10px; } .composer small .online { color: var(--accent); }