Commit Graph
51 Commits
Author SHA1 Message Date
qing 7ff73b7d07 fix(aibox): 缩短 WebSocket 心跳间隔并补全直连页面心跳
前置代理(Nginx/CDN)的 proxy_read_timeout 约 20s,原 25s 心跳
无法在超时前到达,导致连接被代理切断。aibox.js 心跳从 25s 缩短至
10s;frontend.html 直连页面此前完全无心跳,新增 10s 应用层心跳。
2026-08-06 09:16:34 +00:00
qing fc351f569a fix(aibox): 禁用 websockets 服务端 20s 协议层 ping 超时断连 (ping_interval=None) 2026-08-06 16:16:12 +08:00
qing d680dcd058 fix: 修复 WebSocket 长连接空闲断线问题
三处协同修复:
1. 前端 aibox.js 添加 25s 心跳(ping),防止 gateway 30s 空闲超时
2. gateway libhttp doWsRead 对 WS 代理连接跳过空闲超时
3. aibox.py _handle_tool_calls 启动 drain 线程实时排空输出队列,
   避免 SubAgent 等长时间工具执行期间前端收不到数据
2026-08-05 01:58:19 +08:00
qing 058eb11f5f docs(aibox): 更新 README 补充 express_emotion 工具与 /search 命令(移除过时说明、命令表新增 /search、工具表新增 express_emotion、消息类型表补充 task_list/task_completed、更新日志新增 v2.8) 2026-08-05 01:51:10 +08:00
qing d71f526af4 feat(aibox): 子代理思考过程实时输出到主对话侧栏
- run_full_subagent 新增 output_callback 参数,转发子代理 reasoning 事件
- SubAgentTool 新增 _subagent_output 回调,将子代理思考过程以 line 流式输出到前端
2026-08-05 00:16:34 +08:00
qing 09556c9ef4 feat(aibox): run_command 强制流式输出;子代理升级为完整工具代理;补充情绪应对策略
- run_command 移除 stream 参数,删除非流式 subprocess.run 执行路径,统一走流式输出
- 子代理 (create_subagent) 从轻量无工具升级为拥有全部工具的完整代理,支持多轮工具调用与 max_turns 限制,结束后自动总结
- 系统提示词补充子代理使用建议与情绪应对策略
2026-08-05 00:09:25 +08:00
qing dc52ec13ad fix(aibox): 工具结果超长仅返回提示,隔离各会话命令执行器
- 工具结果超过 max_result_length 时不再保留截断内容,仅返回提示信息,避免超大结果污染 AI 上下文

- 每个任务/WebSocket 连接使用独立 SubprocessCommandExecutor,避免 cancel() 误杀其他任务/用户正在运行的子进程
2026-08-04 13:11:37 +08:00
qing 5ff1dfa4d2 系统状态技能 2026-08-04 12:57:27 +08:00
qing 2eb6d3c310 生成技术手册技能 2026-08-04 12:46:50 +08:00
qing d921f84b83 feat(aibox): WebSocket连接用户独立AI实例,支持多用户并发对话
- 每个连接创建独立DeepSeekChat实例,拥有独立messages/工具注册表/消息锁
- 对话状态与并发控制从全局改为会话级,多用户可同时与AI对话互不干扰
- 中断/重置/重载提示词等命令改为针对当前连接的会话AI
- 技能管理器懒加载共享,避免每个连接重复扫描技能
2026-08-04 11:44:57 +08:00
qing 69a8eee192 feat(aibox): 调度器任务间上下文隔离
- 每个定时任务创建独立DeepSeekChat实例,拥有独立messages/工具注册表/消息锁
- 任务与WebSocket主对话互不干扰,消除并发冲突与上下文污染根因
- 共享技能管理器懒加载一次供所有任务复用,避免重复扫描技能
- DeepSeekChat支持传入skill_manager复用,任务实例history_manager=None不污染历史
2026-08-04 09:23:51 +08:00
qing fa9679b7a6 fix(aibox): 修复并发线程导致对话历史污染引发HTTP 400错误
- 添加线程锁(RLock)保护 self.messages,防止WebSocket与调度器线程并发修改
- 重写 _repair_tool_pairs 方法,支持穿透system消息查找tool响应、去重、清理孤立tool消息
- 新增 _validate_enhanced_messages API调用前最终校验,就地修复消息结构
- 调度器执行定时任务前先cancel+wait锁释放,避免与WebSocket对话冲突
- /new命令和global_exit_handler改用锁保护的reset_conversation,不再裸改messages
- 新增 is_busy() 非阻塞方法供外部判断AI是否正在处理中
2026-08-04 09:11:31 +08:00
qing 53ddcb364f feat(aibox): 创建/安装技能工具统一生成 .md 扩展名 + 下线旧版 smtp.py
- CreateSkillTool/InstallSkillTool 改为生成带 .md 扩展名的技能文件,与人格技能文件规范一致
- 同步更新 7_extension_skills.md 模板与工具描述
- 删除旧版 smtp.py(P0-1)并同步审计文档与 README
2026-08-04 08:26:57 +08:00
qing 02904f711e fix(aibox): 修复工具调用配对缺失导致的 insufficient tool messages 400
当 assistant 携带 tool_calls 但对应 tool 响应缺失(工具被中断/压缩丢弃)时,
下一次请求报 400。新增 _repair_tool_pairs 在构建请求前补齐缺失的 tool 响应。
2026-08-03 23:05:28 +08:00
qing d24066369b refactor(aibox): 解耦大模型调用,新增 llm_client 抽象层以支持多厂商切换
将 think_and_respond 与 _compress_via_llm 中的直接 DeepSeek API 调用
收敛到 LLMClient 抽象层(DeepSeekClient 实现 + create_llm_client 工厂),
统一流式事件格式,为子代理/多模型切换预留扩展点;配置新增 api.provider。
2026-08-03 23:03:03 +08:00
qing 417fda5479 refactor(aibox): 文件/网络操作工具改为返回命令行指引并移除beautifulsoup4依赖 2026-08-03 22:52:12 +08:00
qing a7a78d1424 docs: aggregate project documentation under docs/ with unified index
- Move all per-module security audit reports to docs/security/
- Move code review logs to docs/reviews/, analysis reports to docs/reports/
- Add docs/INDEX.md as single entry point for all project documentation
- Add documentation management conventions section to README.md
- Clean up empty per-module docs/ directories
2026-08-03 13:21:48 +08:00
qing 52052e51a8 feat(aibox): 在pre_prompt中新增情绪感知提醒
每轮首轮对话的用户输入前,新增【情绪感知提醒】段落,引导AI:
- 识别用户情绪状态并共情回应
- 按情绪状态调整回应策略(安抚/分享/道歉)
- 用户要求特定情绪模式时搜索对应技能
2026-08-02 14:30:20 +08:00
qing ffbe076a32 feat: add execute method to ExpressEmotionTool 2026-08-02 14:17:33 +08:00
qing 92820799fa 补全情绪化工具 2026-08-02 14:02:51 +08:00
qing 054f65f858 增加智能体生气的模板 2026-08-02 13:54:58 +08:00
qing 918f3ea32a fix(aibox): reasoning展示严格遵循配置文件reasoning_enabled开关
之前即使reasoning_enabled=false,模型自发返回的reasoning_content
仍会被动态展示——配置只管了API请求参数,不管展示逻辑。
现在添加constants.REASONING_ENABLED门控,关着时静默忽略。
2026-08-02 13:26:34 +08:00
qing b216535757 comment 2026-08-02 13:21:45 +08:00
qing af5cd02663 fix(aibox/botops): 思考区域按时间顺序分布,不再全部堆在顶部
问题根因:
1. ChatView.end_reasoning() 不清空 _reasoning_widget 引用,导致
   多轮工具调用时 start_reasoning() 直接 return,所有轮次的思考
   内容都被追加到第一个思考区域(在聊天区最顶部)。
2. AI widget 在工具调用期间不重置,导致后续轮次的思考区域被
   挂载在AI widget中间,顺序混乱。

修复:
1. end_reasoning()/abort_reasoning() 更新标签后清除引用(widget
   保留在DOM显示),下一轮 reasoning_start 创建新的思考区域。
2. 新增 ai_break 协议信号:服务端在工具调用执行前发送,前端
   break_ai() 清除AI widget引用(保留已显示内容),后续chunk
   创建新的AI widget,确保思考区域按时间顺序插入在两段AI文本之间。
3. ai_break 前flush chunk_buffer,防止工具调用前的最后文本片段丢失。
2026-08-01 21:10:42 +08:00
qing f3d06252bb fix(aibox/botops): 修复两处重复输出根因
1. 侧栏重复:_handle_tool_calls 中 msg_type in ("line", "complete")
   将流式工具末尾的 complete 信号也当作 line 转发,导致所有支持
   流式输出的工具(get_current_time、run_command、read_file等20+个)
   结果在侧栏显示两次。改为仅转发 "line" 类型。

2. 聊天区Markdown列表重复:Textual 的 Markdown.append() 在 chunk
   边界切断 Markdown 语法(如列表项 "- "被拆成两个chunk)时,增量
   解析可能导致内容重复渲染。改为累积完整文本后调用 update() 整体
   重新解析,避免增量解析的边界问题。
2026-08-01 21:01:31 +08:00
qing 27ab50ae68 fix(aibox/botops): 修复重复输出问题
1. 服务端:is_continuation(工具调用后递归继续)时不再重复发送
   "思考中"提示和reasoning_start信号,避免多轮工具调用时侧栏
   出现多条冗余"思考中"消息
2. BotOps:line消息过滤前缀从5个扩展到9个,过滤掉"分析工具结果"
   "需要调用工具"等被后续具体信息覆盖的过渡提示
3. BotOps:移除危险的fallback分支(未知消息类型直接append到AI
   聊天区),改为写入侧栏日志,防止非AI内容污染回复
2026-08-01 20:53:40 +08:00
qing f701730016 fix(aibox): 修复中断信号延迟生效问题,确保Ctrl+C能立即中断AI响应
根因:WebSocket消息接收循环使用await串行处理,导致interrupt消息在
AI整段对话完成后才被读取和处理。

修复内容:
1. 消息接收与处理解耦:用create_task异步处理消息,不再await阻塞接收循环
2. cancel()直接同步调用而非通过run_in_executor,消除线程池调度延迟
3. 强制关闭response.raw底层socket连接,中断阻塞的iter_lines() recv()
4. 添加_is_processing_message标志防止多消息并发污染对话历史
5. 连接关闭时自动取消正在进行的处理任务
2026-08-01 14:55:49 +08:00
qing 9d737897df fix(aibox): v2.6 - 修复Ctrl+C中断无法停止服务器的问题
问题根因:
1. WebSocketHandler.handle_message 完全没有处理 interrupt 消息类型(前端Ctrl+C发送的消息被丢弃)
2. DeepSeekChat 缺少取消机制,阻塞的 API 请求(iter_lines)和子进程无法被中断

修复方案 - 三层取消机制:
1. threading.Event 取消标志:流式响应循环每轮检查 _is_cancelled(),工具调用前检查
2. HTTP连接关闭:保存 _current_response 引用,cancel() 时调用 response.close() 中断 iter_lines()
3. 子进程终止:SubprocessCommandExecutor 添加 cancel() 方法,保存 _current_process,cancel时kill

修改内容:
- DeepSeekChat: 添加 _cancel_event/_current_response/_command_executor 字段,cancel()/_is_cancelled()/_check_cancelled() 方法
- SubprocessCommandExecutor: 添加 __init__/_process_lock/cancel(),execute()/execute_streaming() 中设置和清除进程引用
- WebSocketHandler: 添加 handle_interrupt() 处理 interrupt 消息,回复 interrupt_ack 后调用 ai_manager.cancel()
- EnhancedAIManager: 添加 cancel() 统一入口,同时取消AI和命令执行器
- think_and_respond: 首轮清除cancel标志,流式循环检查取消,API/JSON/未知异常中均检查取消标志
- _handle_tool_calls: 每个工具调用前检查取消信号
- 更新README v2.6日志和API文档
2026-08-01 14:09:24 +08:00
qing c06eb19f64 refix 2026-08-01 11:47:14 +08:00
qing cebef9fe70 docs: 各模块安全审计报告 + 补充 .gitignore 忽略规则 2026-08-01 05:21:23 +08:00
qing b79044d631 feat(aibox): add DeepSeek reasoning mode support with tool calling on deepseek-v4-flash
- Add api.reasoning_enabled config (default false) to enable thinking mode
- Uses deepseek-v4-flash native thinking capability (thinking param), supports tool calls while reasoning
- Real-time reasoning content streaming via reasoning_start/reasoning/reasoning_end WS messages
- Frontend shows reasoning in gray italic area, auto-folds long reasoning (>2000 chars)
- Dynamic reasoning detection: shows reasoning even if model returns it without explicit config
- Increase default API timeout to 120s for longer reasoning responses
- Remove duplicate _add_assistant_message_with_reasoning method
- Update docs: config example, message types table, v2.5 changelog
2026-08-01 04:33:55 +08:00
qing bd544a4181 docs(aibox): update file line count to ~8450 2026-08-01 03:51:17 +08:00
qing 164bc65b95 feat(aibox): add dedicated workspace directory to prevent file pollution
- Add WORKSPACE_DIR constant pointing to ~/.aibox/workspace by default
- Update file operations prompt to require writing temp files to workspace
- Update command execution prompt to use workspace as default work_dir
- Add command output size limit note in command execution prompt
- Update README with workspace directory structure and specification
- Add system.workspace_dir config item documentation
- Add v2.4 changelog entry
2026-08-01 03:49:25 +08:00
qing 2f3e63e499 fix(aibox): prevent OOM from large tool outputs with multi-layer safeguards
- ReadFileTool: replace readlines() with on-demand range reading; add reverse block reading for large file tail; limit single line to 10KB; hard-cap max_lines to 500
- SubprocessCommandExecutor: replace capture_output with line-by-line Popen reading; enforce 1MB output limit with immediate process termination; merge stdout/stderr counting for both sync and streaming modes
- Raise TOOL_MAX_RESULT_LENGTH default from 10KB to 1MB as final safety net
- Add SECURITY_AUDIT.md documenting vulnerabilities and remediation roadmap
- Update README with memory safety features and v2.3 changelog
2026-08-01 03:46:02 +08:00
qing 3be9e78335 docs(aibox): update README for v2.2 prompt system fixes
- Expand prompts directory listing to show all 10 skill files explicitly
- Update prompt system table: '1_*.md' → 'N_*.md (N=1~10)' with numeric ordering
- Document load order guarantee (identity → skills 1-10 → soul → status)
- Document is_continuation behavior (no repeated pre_prompt on recursive calls)
- Add v2.2 changelog: prompt ordering fix, token waste reduction,
  recursion pre_prompt dedup, large-file threshold, memory search tuning
2026-08-01 03:24:39 +08:00
qing e8fa26d79f fix(aibox): fix prompt ordering, reduce per-turn token waste, and improve defaults
Prompt system bugs and improvements:

1. **SKILL_PREFIX bug fixed**: SKILL_PREFIX = "1_" only matched files starting
   with "1_", causing 2_ through 10_ skill prompt files to be misclassified
   as "other" files and sorted in wrong order (e.g., 10_task_handling.md
   sorted before 2_memory_save.md due to lexicographic ordering). Replaced
   with regex _SKILL_FILE_RE = re.compile(r'^(\d+)_') and _skill_sort_key()
   that extracts the numeric prefix for proper numeric sorting.

2. **_init_system_prompts used unsorted list**: get_prompts_list() returned
   prompts in os.listdir() lexicographic order, which put 100_STATUS.md
   before 1_memory_search.md and 10_task_handling.md before 1_memory_search.md.
   Now uses get_sorted_prompts_list() for correct ordering:
   identity → skill prompts (1-10 by number) → soul → status.

3. **Verbose pre_prompt injected every turn (~30 lines)**: The pre_prompt
   contained detailed workflow instructions (search_skills first, memory
   search, ask_user, etc.) that duplicated what system skill prompts
   already say, wasting ~300+ tokens per user message. Worse, the same
   verbose prompt was injected on recursive think_and_respond calls after
   tool execution, confusing the model with repeated "第一步搜索技能"
   instructions when it was already mid-conversation with tool results.
   - Reduced pre_prompt to 5 concise bullet points as a reminder
   - Added is_continuation parameter: recursive calls after tool execution
     skip pre_prompt entirely and just pass "请基于以上工具执行结果继续回答。"
   - Removed post_prompt (save_memory/update_soul instructions already in
     2_memory_save.md and 8_identity_management.md)

4. **Unreasonable large-file thresholds**: 3_file_operations.md default
   said >50KB or >200 lines is "too large" — too conservative for code
   files. Raised to 500KB/2000 lines; added tail=true and binary file
   guidance.

5. **Overly rigid memory search instruction**: 1_memory_search.md said
   "每次都要做!" (must do every time), causing unnecessary memory searches
   for simple greetings/acknowledgments. Softened to "根据话题相关性判断",
   with explicit examples of when to skip (greetings, confirmations).

New/changed methods:
- PromptManager._skill_sort_key(cls, filename) - extract numeric prefix
- PromptManager._prompt_sort_key(self, p) - tuple-based sort key
- PromptManager.get_sorted_prompts_list() - returns correctly ordered list
- PromptManager.get_skill_prompts() - uses regex instead of startswith("1_")
- DeepSeekChat.think_and_respond() - added is_continuation parameter
2026-08-01 03:19:58 +08:00
qing ae42ab8a91 docs(aibox): update README for v2.1 robustness fixes and correct entry filename
- Fix all references from main.py to aibox.py (actual entry file)
- Update installation to use pip install -r requirements.txt
- Expand WebSocket message types table: add line/task_error/task_added/
  notification/connection_ack/interrupt_ack, correct chunk/complete/error semantics
- Fix message flow example: tool calls are reported via 'line' messages,
  not a non-existent 'tool_call' type
- Document _sanitize_tool_result() and error recovery (_rollback_messages)
  in development guide
- Add FAQ entry for tool-call-induced API failures
- Add v2.1 changelog covering all robustness fixes (reasoning_content
  filtering, tool_call id fallback, control character sanitization,
  message rollback on API failure)
2026-08-01 03:09:34 +08:00
qing a80bd582da fix(aibox): prevent tool results from corrupting conversation and breaking API requests
Root causes of API request failures after tool calls:
1. reasoning_content (an API response field) was echoed back in assistant
   messages, which could cause API format errors
2. tool_call id could be empty string when model didn't return one in a
   streaming chunk, producing invalid tool_calls that caused 400 errors
3. Tool execute() could return None or non-string types; direct string
   operations (len(), + "\n", [:200]) raised TypeError and produced
   non-string content in tool messages, breaking JSON serialization
4. Tool output (e.g. from run_command) could contain control characters
   (NULL/BEL/BS) that corrupted JSON payloads
5. When API request failed (network/4xx/5xx/parse error), messages added
   in that turn (user msg, assistant msg with tool_calls, tool responses)
   remained in self.messages, permanently poisoning conversation history
   so all subsequent requests would also fail

Fixes:
- Stop sending reasoning_content back to API in message construction;
  normalize assistant message content: null when tool_calls present, ""
  when neither content nor tool_calls exist, str otherwise
- Sanitize tool messages: ensure tool_call_id is non-empty (fallback id)
  and content is always a string
- Generate fallback tool_call id when model omits it; handle streaming id
  delivery where id arrives in a later chunk
- Add _sanitize_tool_result(): coerce None/non-string to str, strip
  control characters (preserve \n \t \r) to prevent JSON/API corruption
- Wrap execute_tool call in try/except in _handle_tool_calls for double
  safety; ensure history logging never crashes
- Truncate oversized results with an explicit note instead of replacing
  with a generic error that lost all useful output
- Add _rollback_messages(to_length) and record msgs_before_turn at start
  of think_and_respond; on any exception (RequestException, JSONDecodeError,
  or unexpected Exception), rollback self.messages to the pre-turn state
  so the conversation is not left in a broken state
- In _handle_tool_calls, wrap execute_tool in try/except and always
  produce a safe string result
2026-08-01 03:06:34 +08:00
qing 74610c32c8 微调 2026-07-30 19:03:34 +08:00
qing d309f41e47 refix 2026-07-30 15:52:18 +08:00
qing 254fbf4628 docs(aibox): 更新 README.md 并新增 README.robot.md 技术手册
README.md 修复:
- 新增 ask_user 工具到工具列表
- 补充配置表中缺失的 17 个字段(system/scheduler/api/context/memo/files/commands/web/memory/conversation/tools/compressor/proxy)
- 补充对话压缩完整配置项

README.robot.md 新增:
- 17 章节完整技术手册(~500 行)
- 架构图、数据流、协议详情
- 19 个工具的完整实现信息
- 配置参考(含所有字段说明)
- 已知限制与安全建议
- 部署与故障排查指南
2026-07-30 12:08:17 +08:00
qing e6e5dab4cd 智能体提问 2026-07-29 21:54:22 +08:00
qing 3c02ba43ad AskUserTool 内置技能 2026-07-29 21:23:04 +08:00
qing dabd892601 fix(aibox/client): 放弃 rich.Live 改为 complete 时一次性静态渲染,修复内容一闪而过 2026-07-28 22:01:21 +08:00
qing 2982bc30a4 feat(aibox/client): AI 回复流式渲染 Markdown(rich.Live,无 rich 时降级纯文本) 2026-07-28 21:51:53 +08:00
qing aaeac343d3 fix(aibox/client): 修4处——stdin单线程防泄漏、LRU去重上限、自动重连、弃用get_event_loop 2026-07-28 21:44:23 +08:00
qing ee44e1bef1 docs & ui: 完善 captcha/aibox 文档,登录注册改为邮箱制
- captcha/README.md: 补充字段级接口文档与错误码表
- aibox/README.md: 对照 main.py 源码核对修正(入口/模型/工具/配置)
- static/public/login.html & register.html: 用户名改为邮箱
- static/public/js/register.js: 合并注册页双邮箱框为单一邮箱字段
2026-07-27 22:51:57 +08:00
qing f601efdd3f refix 2026-07-27 22:27:18 +08:00
qing c58cafcdcf fixbug: 机器人在定时任务中创建重复的定时任务 2026-07-27 22:11:02 +08:00
qing 3501168f45 inst aibo 2026-07-27 22:03:50 +08:00