PawzoChat v0.1.7
新增
- 朋友圈:新增独立的「朋友圈」模块,UI 入口在主导航;用户与角色可以共用一条 feed 互相发动态、点赞和评论。每个角色可配置「是否可发动态」(publishers)、「是否参与评论」(repliers)、评论概率 0–100、以及是否将本次朋友圈互动写入该角色记忆;动态封面图、
post/reply提示词模板可在设置中自定义;底层数据按moments.json原子写入到data/moments/,图片按动态 ID 隔离在data/moments/images/<mom_id>/ - 朋友圈生成与回复链路:单 worker 串行调度,所有 LLM 调用(动态生成 / 评论 / 用户被回复后的 counter-reply)共用一把跨 workflow 互斥锁,避免并发触发上游限流;用户在评论区追问被回复角色时,由后台 FIFO 队列处理,不会与正在进行的对话轮次交错;动态作者已支持调用
generate_image工具自动配图(最多一张),系统会将动态文本和配图作为多模态输入提供给评论角色 - 朋友圈记忆联动:默认开启「写入记忆」时,角色自己发布的动态、对用户朋友圈的评论会以第一人称摘要写入该角色的记忆;用户之间或角色之间的互动则按产品决策刻意不写入
- 角色创建 / 导入 / 删除时同步维护朋友圈名单:新角色默认自动加入 publishers 与 repliers,删除角色时清理
publishers/repliers/reply_probabilities/memory_enabled - 内置工具
view_reference_image:让对话中的 LLM 自查当前角色的形象参考图(头像或自定义参考图)。通过pending_images+[图片 ID:xxx]占位符的统一通道注册,再让 LLM 用已有的recognize_image能力适配器读取图片内容——避开 OpenAI / Gemini 工具结果会把图片摊平为占位文本、以及 Anthropic 通道会把参考图作为新图二次推送给用户的问题;当生图功能关闭或角色无可用参考图时,自动从工具列表中过滤 generate_image新增use_reference_image参数:纯风景 / 物品 / 食物等不需要出现人物的画面,AI 可在调用时主动传false跳过角色形象参考图;用户在角色配置里设为ref_mode=none时本参数无效(不会被反向打开)- 插件 MCP 访问(
ctx.mcp):新增list_servers()/list_tools()/call_tool(name, arguments),按声明的权限分别需要mcp.read(列表)和mcp.invoke(调用);工具调用错误不抛异常,而是以工具调用出错: ...文本块返回,与 LLM tool_use 路径同语义 - 插件发布 in-process LLM 工具(
ctx.mcp.register_tool):插件可注册命名空间为plugin_<id>__<name>的工具,与 MCP-server 工具和内置能力并列出现在 LLM 工具列表与 MCP 概览页 / 插件详情页;生命周期跟随插件,disable / reload / 加载失败时自动反注册。新增权限mcp.publish - 插件文件消息支持:
ctx.messaging.send_message新增files参数([{"path": "...", "name": "...", "mime": "..."}]),可推送非图片文件(doc / pdf / zip 等)。微信通道会先复制文件到data/chats/<persona>/files/<随机前缀>__<原名>以保证 Web 预览可用,再走新的 CDN 上传链路(transport/cdn.upload_file、transport/sender.send_file、ILinkClient.build_file_message,沿用图片相同的 AES-ECB 加密 + 重试上限 3 次) - 插件 LLM 复用角色绑定:
ctx.llm新增chat_as_persona(persona_id, messages, ...)复用角色绑定的 provider / model / temperature / max_tokens,每次调用重读 persona 配置;新增list_providers()列出已注册 provider 名、get_persona_binding(persona_id)返回角色当前绑定快照 LLMResponse新增reasoning_content字段;OpenAI 兼容渠道在 tool_use 多轮循环中回传reasoning_content给上游,避免 DeepSeek-v4 / o1 风格代理在 thinking-mode 模型上拒绝继续请求/api/mcp/tools现在为每个工具返回owner标签(builtin/plugin:<id>/mcp:<server>/""表示来自capability_adapters配置项),前端据此对来自插件 / 内置的工具隐藏编辑与删除入口
修复
- 修复 MCP stdio 启动失败:原路径启发式把任何含
/的字符串当作本地路径并重写到APP_HOME,导致 npm scoped 包名 (@scope/name)、--key=value标志、https:///file://URL 被破坏,npx启动的官方 MCP 服务器(如@playwright/mcp)以 ENOENT 失败、被 SDK 包装为Connection closed。收紧规则:仅显式相对路径前缀 (.//../)、绝对路径或已知路径后缀(.py/.exe/.sh等)会被解析为路径 - 修复 MCP 连接生命周期:原先用手工
__aenter__/__aexit__栈,anyio 任务组的 enter 与 exit 跨 asyncio task 执行(每次run_coroutine_threadsafe都是新 task),SDK 仅以 DEBUG 日志吞掉失败、实际清理交给 asyncgen GC。改为一个长存的_lifecycle_task在同一 task 内持有 transport +ClientSession上下文,断开时通过_shutdown_event在限时窗口内优雅退出,必要时再 cancel - 修复 MCP 工具结果中的图片丢失:MCP 服务器可能以三种形式返回图片(
ImageContent块 /EmbeddedResource/TextContent内嵌data:image/...;base64,...URI 或 markdown 包装的同 URI),新增services/mcp_image_extractor.py统一识别并落盘到data/chats/<persona_id>/images/mcp_*.<ext>,再以独立 assistant 消息分发;带格式嗅探(PNG / JPEG / GIF / WebP / BMP)、单图 ≤20MB、单次工具调用最多 8 张、目录 resolve 后强校验不能逃出chats/;generate_image等会自行注册出站图片的工具不再被二次抽取 - 修复 OpenAI 兼容渠道偶发 SSE 误返:部分中继(个别 grok 代理等)在
stream=False时仍返回text/event-stream,原先直接报格式错误。新增_looks_like_sse_stream+_parse_sse_completion,按行重组data:切片为单个LLMResponse(含文本、tool_calls、reasoning_content,并尊重finish_reason) - 修复朋友圈刷新按钮在 feed 生成中无可视反馈:刷新图标在
is_generating=true时持续转圈,状态来源于/api/moments/state
内部
- 新增模块:
pawzochat/services/moments.py、pawzochat/store/moments.py、pawzochat/web/routes/api_moments.py、pawzochat/web/static/modules/moments.js、pawzochat/utils/profile.py、pawzochat/services/mcp_image_extractor.py、pawzochat/mcp/builtin/view_reference_image.py - 新增路径常量:
MOMENTS_DIR/MOMENTS_IMAGES_DIR/MOMENTS_STORE_PATH ConfigManager默认结构新增moments节(publishers/repliers/reply_probabilities/memory_enabled/prompts.post/prompts.reply)- 新增路由:
GET/POST /api/moments、GET/DELETE /api/moments/<id>、POST/DELETE /api/moments/<id>/like、POST /api/moments/<id>/replies、DELETE /api/moments/<id>/replies/<rid>、POST /api/moments/refresh、GET /api/moments/state、GET/PUT /api/moments/settings、GET/POST/DELETE /api/moments/cover、GET /api/moments/images/<id>/<filename> CapabilityAdapterRegistry由「内置 vs 配置」二分改为 owner 标签三态(""配置项可重载、builtin程序内置保留、plugin:<id>插件保留),register(adapter, owner=...)与unregister_owner(prefix)配套;reload(adapters_cfg)只清理空 owner 的条目MemoryService._load_profile_name抽离为pawzochat/utils/profile.py.load_profile_name()单一来源- 插件 API 扩展:
PluginContext新增mcp字段;MCPFacade新增register_tool(name, description, parameters, handler, *, namespace=...);ExtensionManager通过set_capability_registry()在start()之前注入注册表,并在插件 disable / reload / 加载失败时调用_unregister_plugin_tools()清理;KNOWN_PERMISSIONS新增mcp.publish MessagingFacade._normalize_files/_persist_files_for_persona负责文件块校验、复制和text/image/file三类内容块的合并构建services/chat.py工具调用循环新增 MCP 图片回收阶段;_build_tools顺序调整为先按 policy 过滤、再按生图开关过滤、最后按参考图可用性过滤view_reference_image;_build_image_tool_guidance接受active_tool_names仅注入实际暴露给本轮的工具的提示词- 移除 MCP
list_resources/list_prompts未使用桩函数与manager内冗余的聚合任务包装
完整变更日志见 CHANGELOG.md。