Repository navigation
v0.1.23
[0.1.23] - 2026-09-29
Added
- robit-agent:图片进入上下文前自动压缩。
read图片文件与用户图片附件在 base64 编码前,若最长边超过[app.context].max_image_dimension(默认 1024,0 禁用)则等比缩放(Lanczos3)并重编码为 JPEG(质量 85),透明通道合成白底;2K PNG 单图体积可降低一个数量级,配合 0.1.23 的"图片用后即弃"进一步保障长会话请求体不超网关限制。GIF(动图)直通不压缩;重编码后反而变大(已高度优化的图)时保留原字节。工具结果文本会标注压缩信息(如2048×2048 → 1024×1024 JPEG),模型可据此判断可用细节量。解码前施加防护上限(单边最大 16384px、解码总分配 256MB),超高分辨率"解码炸弹"图片直接报错而非耗尽内存。注意:附件为未启用解码器的格式(BMP/TIFF/SVG 等)时降级为文本描述;压缩会忽略 EXIF 方向信息。
Fixed
- robit-agent:修复会话历史中 base64 图片随每次 LLM 调用全量重发,长会话累积后请求体超出服务商网关限制(HTTP 413 Request Entity Too Large,openresty 拒绝)。
read图片等返回图片的工具结果、用户图片附件此前以多模态 user 消息注入历史且永不清理,多张 2K PNG 的 base64 累积达几十 MB;而服务商对每张图片仅计约 1k token,token 估算与截断对此完全无感。现在图片在成功发送给模型一次后即降级为文本占位符([历史图片已省略:N 张图片已发送给模型...]),每张图片只随紧随其后的一次调用发送,后续调用不再重复携带图片数据。图片消息本就不持久化到 DB,重启后历史为纯文本,存量会话无需迁移即可正常加载。 - robit-ai:服务商反向代理(openresty 等)对超限请求返回 HTML 错误页,async-openai 只能报出裸的 JSON 反序列化失败(
failed to deserialize api response: error:expected value at line 1 column 1 content:<html>...),真实原因被掩埋。现在检测 HTML 载荷并提取<title>,映射为友好提示:413 会说明常见原因是上下文中图片过多或过大并建议清空上下文/新建会话,其他网关错误(如 502)给出稍后重试的通用建议。
[0.1.22] - 2026-09-21
Added
- robit-ai:服务商错误友好提示。LLM 请求与流式响应中的提供商错误现在映射为清晰的中文提示:已知内容审核错误码(DashScope
data_inspection_failed、OpenAI 系content_filter/content_policy_violation)区分输入侧/输出侧拦截——输入侧(对话上下文被判定不适宜,该会话后续请求会持续失败)提示清空上下文或新建会话,输出侧提示调整提问或稍后重试;其余错误码显示服务商返回错误(code):message,载荷无法解析时保持原始错误,服务商原始消息始终保留供排查。此前流中段推送的{"error": ...}事件(无choices字段)只报出裸的 JSON 反序列化失败,HTTP 400 拒绝只显示400 Bad Request ...,真实原因埋在载荷里。
Fixed
- robit-agent:修复 QQ Bot 执行
/new后报UNIQUE constraint failed: sessions.chat_id,且该聊天后续所有消息均无法开启会话。sessions表唯一索引idx_sessions_chat_id此前只排除chat_id IS NULL、未排除is_active = 0的归档行,等于限制同一chat_id终身只能有一条记录,与"归档旧会话 + 新建会话"的设计(/list、/switch)冲突。索引放宽为仅约束活跃会话(WHERE chat_id IS NOT NULL AND is_active = 1,每个聊天同时最多一个活跃会话,归档记录不限量);schema v4 → v5 自动迁移重建索引,存量受影响的库启动时自动修复,历史会话与消息完整保留,无需删库。
[0.1.21] - 2026-09-20
Fixed
- robit-agent:修复并行图片工具调用触发 400
insufficient tool messages following tool_calls message(DeepSeek 等严格校验的提供商)。read图片文件等返回图片的工具结果此前在工具执行循环内逐个注入多模态 user 消息,并行调用批次中该消息被插在 tool 响应中间,违反 "assistant(tool_calls) 后必须紧跟每个 tool_call_id 的 tool 响应" 的协议约束。现在图片 user 消息在整批工具结果之后统一注入,保证序列为assistant(tool_calls) → tool×N → user(图片)。 - robit-ai:新增
repair_interleaved_tool_responses历史修复,在chat_stream/chat发送前(repair_tool_pairing之前)执行:把夹在tool_calls与 tool 响应之间的非 tool 消息移到批次末尾,保持相对顺序。DB 加载的历史、旧版本写出的交错序列在每次 API 调用前自动被修复,无需迁移存量数据。
[0.1.20] - 2026-08-23
Changed
- robit-agent:系统提示词不再注入工具清单(移除
system.md的Available Tools段与PromptBuilder的tools参数)。工具定义完全通过 OpenAI function calling 的tools请求参数下发(name/description/参数 JSON Schema),消除与tools参数重复的文本描述,节省每轮上下文 Token。
Fixed
- robit-agent:
tools请求参数现在仅在模型支持 function calling 时下发(supports_tools配置项生效,此前该标志定义了但从未被使用),不支持该参数的 OpenAI 兼容端点不再收到无法处理的请求。注意:supports_tools默认为true(保持既有行为不变),不支持工具调用的模型(如 DeepSeek reasoner)需在配置中显式设置supports_tools = false。
[0.1.19] - 2026-08-17
Added
- robit-agent:Token 校准计数。每次 API 响应后用
usage.prompt_tokens作为精确基线回填(last_known_prompt_tokens+snapshot_message_count),之后仅对新增消息做增量估算;历史被截断/压缩时自动失效回退启发式估算。零新依赖,显著降低上下文 Token 估算误差,避免过早触发截断。 - robit-ai:流式请求携带
stream_options.include_usage = true,使流式响应也能返回usage统计(OpenAI/DeepSeek 均支持),支撑上述 Token 校准。 - robit-gui:
AgentEvent::Error现在以系统消息形式展示在会话中(此前仅打印到浏览器 console,前端无任何错误反馈)。
Changed
- 日志精简:每步无变化的上下文估算/截断检查(
estimate_context_tokens、maybe_truncate)降为 TRACE;删除逐流式 chunk 日志(此前每次 LLM 调用刷数十至数百行);同一次工具调用的多条重复日志合并为一条 INFO(Executing tool),工具注册表不再每次调用 dump 全量工具列表;repair_tool_pairing的孤儿消息告警改为每次调用聚合一条 WARN(此前每条孤儿消息每次 API 调用都 WARN);可能超长的工具参数(如write的文件内容)进日志前截断。生图模块(image_gen)的连接详情/任务提交/任务成功降为 DEBUG(Agent 的[async]日志已覆盖),轮询中的still running降为 TRACE(此前每 3 秒一条 INFO),INFO 不再出现脱敏 API key。
Fixed
- robit-ai:新增
repair_tool_pairing历史修复,在chat_stream/chat发送前执行:丢弃没有前置assistant(tool_calls)声明的孤儿tool消息,为缺失响应的tool_calls合成占位tool结果。修复 GUI 恢复历史会话时报 400Messages with role 'tool' must be a response to a preceding message with 'tool_calls'(DeepSeek 等严格校验的提供商)。 - robit-gui:GUI 关闭后不再残留
.robit/LOCK锁文件。Tauri 退出时以process::exit终止进程、不执行 main 的析构函数,DirectoryLock的 RAII 释放从未运行。改为在RunEvent::Exit事件中显式释放锁(解锁并删除 LOCK 文件)。 - robit-gui:会话持久化补齐工具调用结构。此前
ToolCallRequested只存tool消息、不存携带tool_calls的 assistant 消息,且tool消息的content一直停留在调用参数而非实际输出,导致恢复的历史出现孤儿 tool 消息。现在每次工具调用前插入对应的assistant(tool_calls)消息,工具完成时回写真实输出;前端跳过空内容 assistant 消息的渲染。 - robit-agent:不支持图片的模型(如 DeepSeek)现在会在每次 API 调用前净化历史(
sanitize_history_for_model),移除image_url内容块,避免 400unknown variant 'image_url'。
[0.1.18] - 2026-08-11
Added
- robit-ai:日志改用本地时间。时间戳和每日日志文件名(
robit-YYYY-MM-DD.log)按系统本地时区输出(如2026-08-11T10:19:01.790373+08:00、本地午夜切文件),取不到本地偏移时回退 UTC。 - robit-ai:新增
app.log_retention_days配置(默认 14 天)。启动时扫描日志目录,删除超过保留期的robit-*.log;0禁用清理。此前日志按天生成但永不删除、无限累积。 - robit-ai:安装 panic hook,将 panic 信息经
tracing::error!写入日志文件再链到默认 stderr hook。此前 detached 运行的二进制(nohup/systemd 下的 robit-qq 等)panic 只进 stderr,日志文件无痕迹,故障表现为无声停滞。
Fixed
- robit-qq:修复重连 supervisor 的
JoinHandle polled after completionpanic。tokio::select!消费了先结束任务的 JoinHandle 后又 re-await 同一个句柄触发 panic;panic 只进 stderr,supervisor 静默死亡,导致每次 ~30 分钟网关轮换后不再重连、机器人掉线("该机器人未连接服务")。改为只 await 未被消费的另一个句柄。 - robit-gui:GUI 产物名长期停在
Robit_0.1.1_*。移除tauri.conf.json中硬编码的version字段,Tauri 改从 Cargo.toml(经CARGO_PKG_VERSION跟随 workspace)读版本,产物名与运行时版本显示均正确。
[0.1.17] - 2026-08-10
Fixed
- robit-qq:WebSocket 重连不再重启进程。QQ 网关约每 ~30 分钟要求重连,此前适配器发出
Disconnected事件导致ChatbotManager退出、进程被外部 supervisor 重启,所有进行中的异步任务(如生图)被中途丢弃。现在重连逻辑收进适配器内部的后台 supervisor:dispatch / heartbeat 任一退出时取消另一个并按指数退避重建 WebSocket,不再发出Disconnected,manager 与其持有的 Agent 跨重连存活。 - robit-agent:
image_gen::truncate_str按字节下标切片字符串会 panic(end byte index 2000 is not a char boundary; it is inside '着'),日志记录含中文的 DashScope 响应体时触发。改用floor_char_boundary在最近的字符边界切割。 - robit-agent:
AsyncTaskRunner::submit无 panic 兜底——work future panic 会跳出select!、跳过done_tx.send,导致 Agent 永远收不到结果、query_task永久 pending。现在用AssertUnwindSafe(...).catch_unwind()捕获 panic,记录 ERROR 日志并投递 error 结果给 Agent。
上述后两条共同导致了「万象生图请求被拦截无响应、智能体得不到超时提醒」的现场现象:截断 panic 发生在异步生图任务里,而该任务无 panic 兜底,于是静默死掉、永不回报。