feat: release 2.0.6

This commit is contained in:
zhayujie
2026-04-14 12:08:57 +08:00
parent acc09543b7
commit 83f6625e0c
7 changed files with 155 additions and 10 deletions

View File

@@ -54,7 +54,7 @@ MEMORY.md 会注入每次对话的系统提示词中,因此必须保持精炼
- **合并提炼**:将含义相近的多条合并为一条高密度表述,而非简单罗列
- **新增萃取**:从今日日记中提取值得永久记住的新信息(偏好、决策、人物、规则、经验)
- **冲突更新**:当新信息与旧条目矛盾时,以新信息为准,替换旧条目
- **清理无效**:删除临时性记录、空白条目、格式残留等
- **清理无效**:删除临时性记录、空白条目、格式残留、无意义、重复内容
- **删除冗余**:已被更精炼表述涵盖的旧条目应删除,避免信息重复
- 每条一行,用 "- " 开头,不带日期前缀
- 目标:控制在 50 条以内,每条尽量一句话概括

View File

@@ -203,7 +203,7 @@ function applyI18n() {
el.setAttribute('data-tooltip', t(el.dataset.tipKey));
});
const langLabel = document.getElementById('lang-label');
if (langLabel) langLabel.textContent = currentLang === 'zh' ? 'EN' : '中文';
if (langLabel) langLabel.textContent = currentLang === 'zh' ? '中文' : 'EN';
}
function toggleLanguage() {
@@ -430,6 +430,20 @@ const fileInput = document.getElementById('file-input');
// Intercept internal navigation links in chat messages
messagesDiv.addEventListener('click', (e) => {
const copyBtn = e.target.closest('.copy-msg-btn');
if (copyBtn) {
e.preventDefault();
const msgRoot = copyBtn.closest('.flex.gap-3');
const answerEl = msgRoot && msgRoot.querySelector('.answer-content');
const rawMd = answerEl && answerEl.dataset.rawMd;
if (rawMd) {
navigator.clipboard.writeText(rawMd).then(() => {
const icon = copyBtn.querySelector('i');
if (icon) { icon.className = 'fas fa-check'; setTimeout(() => { icon.className = 'fas fa-copy'; }, 1500); }
});
}
return;
}
const a = e.target.closest('a');
if (!a) return;
const href = a.getAttribute('href') || '';
@@ -936,7 +950,12 @@ function startSSE(requestId, loadingEl, timestamp, titleInfo) {
<div class="answer-content sse-streaming"></div>
<div class="media-content"></div>
</div>
<div class="text-xs text-slate-400 dark:text-slate-500 mt-1.5">${formatTime(timestamp)}</div>
<div class="flex items-center gap-2 mt-1.5">
<span class="text-xs text-slate-400 dark:text-slate-500">${formatTime(timestamp)}</span>
<button class="copy-msg-btn text-xs text-slate-300 dark:text-slate-600 hover:text-slate-500 dark:hover:text-slate-400 transition-colors cursor-pointer" title="${currentLang === 'zh' ? '复制' : 'Copy'}" style="display:none">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
`;
messagesDiv.appendChild(botEl);
@@ -1116,8 +1135,10 @@ function startSSE(requestId, loadingEl, timestamp, titleInfo) {
addBotMessage(finalText, new Date((item.timestamp || Date.now() / 1000) * 1000), requestId);
} else if (botEl) {
contentEl.classList.remove('sse-streaming');
// Only update text content when there is something new to show.
if (finalText) contentEl.innerHTML = renderMarkdown(finalText);
contentEl.dataset.rawMd = finalText || '';
const copyBtn = botEl.querySelector('.copy-msg-btn');
if (copyBtn && finalText) copyBtn.style.display = '';
applyHighlighting(botEl);
}
scrollChatToBottom();
@@ -1366,9 +1387,15 @@ function createBotMessageEl(content, timestamp, requestId, msg) {
${stepsHtml ? `<div class="agent-steps">${stepsHtml}</div>` : ''}
<div class="answer-content">${renderMarkdown(displayContent)}</div>
</div>
<div class="text-xs text-slate-400 dark:text-slate-500 mt-1.5">${formatTime(timestamp)}</div>
<div class="flex items-center gap-2 mt-1.5">
<span class="text-xs text-slate-400 dark:text-slate-500">${formatTime(timestamp)}</span>
<button class="copy-msg-btn text-xs text-slate-300 dark:text-slate-600 hover:text-slate-500 dark:hover:text-slate-400 transition-colors cursor-pointer" title="${currentLang === 'zh' ? '复制' : 'Copy'}">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
`;
el.querySelector('.answer-content').dataset.rawMd = displayContent;
applyHighlighting(el);
bindChatKnowledgeLinks(el);
return el;

View File

@@ -1 +1 @@
2.0.5
2.0.6

View File

@@ -199,6 +199,7 @@
"group": "发布记录",
"pages": [
"releases/overview",
"releases/v2.0.6",
"releases/v2.0.5",
"releases/v2.0.4",
"releases/v2.0.3",

View File

@@ -5,6 +5,7 @@ description: CowAgent 版本更新历史
| 版本 | 日期 | 说明 |
| --- | --- | --- |
| [2.0.6](/releases/v2.0.6) | 2026.04.14 | 项目更名、知识库系统、梦境记忆蒸馏、上下文智能压缩、Web 控制台多会话及多项优化 |
| [2.0.5](/releases/v2.0.5) | 2026.04.01 | Cow CLI、Skill Hub 开源、浏览器工具、企微扫码创建、多项优化和修复 |
| [2.0.4](/releases/v2.0.4) | 2026.03.22 | 新增个人微信通道、新模型支持、日文文档、脚本重构及多项修复 |
| [2.0.3](/releases/v2.0.3) | 2026.03.18 | 新增企微智能机器人和 QQ 通道、支持Coding Plan、新增多个模型、Web端文件处理、记忆系统升级 |

82
docs/releases/v2.0.6.mdx Normal file
View File

@@ -0,0 +1,82 @@
---
title: v2.0.6
description: CowAgent 2.0.6 - 知识库系统、梦境记忆蒸馏、上下文智能压缩、Web 控制台多会话及多项优化
---
## 项目正式更名为 CowAgent
项目仓库正式从 `chatgpt-on-wechat` 更名为 **CowAgent**,演进为功能完备的 AI Agent 助理。
- 新地址:[github.com/zhayujie/CowAgent](https://github.com/zhayujie/CowAgent),旧地址 GitHub 会自动重定向
- CLI 命令、配置文件、文档链接均保持兼容,无需额外操作
## 📚 知识库系统
新增个人知识库系统Agent 可自主构建和维护结构化知识,并在对话中按需检索引用:
- **索引驱动的自组织结构**:知识库采用 `knowledge/` 目录,按分类自动组织,每个知识页面为独立的 Markdown 文件
- **自动写入**:向 Agent 发送文件、链接等知识,或在讨论中识别到有价值的知识时,自动创建或更新知识页面
- **混合检索**:支持关键词全文搜索和向量语义检索,在对话中按需加载相关知识
- **可视化**:支持文件树浏览和知识图谱可视化,文档内链接可直接跳转查看
- **命令管理**`/knowledge` 查看统计、`/knowledge list` 查看目录结构、`/knowledge on|off` 开关知识库
<img src="https://cdn.link-ai.tech/doc/20260413105435.png" width="750" />
相关文档:[知识库](https://docs.cowagent.ai/knowledge)
## 🌙 梦境记忆蒸馏Deep Dream
全新的记忆整理机制,每日自动将分散的对话记忆蒸馏为精炼的长期记忆:
- **三层记忆流转**:对话上下文(短期)→ 天级记忆(中期)→ MEMORY.md长期形成完整的记忆生命周期
- **自动蒸馏**:每日 23:55 定时执行,读取当天天级记忆和 MEMORY.md通过 LLM 进行去重、合并、修剪,输出精炼的新版 MEMORY.md
- **梦境日记**:每次蒸馏生成一篇叙事风格的梦境日记,记录整理过程的发现和洞察,存储在 `memory/dreams/` 目录
- **手动触发**:支持 `/memory dream [N]` 手动触发,可指定整理天数(默认 3 天,最大 30 天),完成后在对话中通知结果
- **Web 控制台**记忆管理页面新增「梦境日记」tab可浏览和查看所有梦境日记
相关文档:[梦境蒸馏](https://docs.cowagent.ai/memory/deep-dream)
<img src="https://cdn.link-ai.tech/doc/20260414120158.png" width="750" />
## 🧠 上下文智能压缩
上下文超出限制时将裁剪的部分通过 LLM 总结后异步注入,保持对话连贯性:
- **LLM 异步摘要**:裁剪的消息由 LLM 总结为关键信息,同时写入天级记忆文件和注入保留的上下文
- **多模型兼容**:优先使用主模型进行摘要,兼容 Claude、OpenAI、MiniMax 等不同模型的消息格式要求
相关文档:[短期记忆](https://docs.cowagent.ai/memory/context)
## 💬 Web 控制台升级
Web 控制台多项功能增强:
- **多会话管理**:支持创建和切换多个独立会话,侧边栏展示会话列表,支持会话标题自动生成和手动编辑
- **密码保护**:支持为控制台设置登录密码,可通过 `web_console_password` 配置项控制
- **深度思考**:支持在 Web 端展示模型的思考过程,可通过`enable_thinking` 配置项控制
- **定时推送**:支持定时任务结果推送到 Web 控制台
- **消息复制**AI 回复支持一键复制原始 Markdown 内容
## 🤖 模型相关
- **视觉识别优化**:图片识别工具优先使用主模型,支持多模型厂商自动降级。相关文档:[视觉工具](https://docs.cowagent.ai/tools/vision)
- **MiniMax 新模型**:新增 MiniMax-M2.7-highspeed 模型和 MiniMax TTS 语音合成支持。Thanks @octo-patch
- **通义千问**:新增 qwen3.6-plus 模型支持
## 🐛 其他优化与修复
- **记忆提示词优化**`MEMORY.md` 默认注入系统提示词,精细化记忆检索和写入的触发条件,增强主动写入能力
- **系统提示词**:优化系统提示词的风格和语气引导
- **浏览器工具**:增强隐式交互元素检测
- **文件发送**修复通用文件类型tar.gz、zip 等未能正确发送的问题。Thanks @6vision
- **macOS 兼容**修复网络预检超时兼容性问题。Thanks @Moliang Zhou
- **Windows 兼容**:修复 Windows 下 PowerShell 兼容性、进程更新、终端编码等多项问题
- **Python 3.13+**:修复 Python 3.13 及以上版本缺少 `legacy-cgi` 依赖的问题
- **个人微信**:更新个人微信通道版本
## 📦 升级方式
源码部署可执行 `cow update` 或 `./run.sh update` 一键升级,或手动拉取代码后重启。详见 [更新升级文档](https://docs.cowagent.ai/guide/upgrade)。
**发布日期**2026.04.14 | [Full Changelog](https://github.com/zhayujie/CowAgent/compare/2.0.5...master)

View File

@@ -895,14 +895,14 @@ class CowCliPlugin(Plugin):
if not flush_mgr.llm_model:
return "⚠️ 未配置 LLM 模型,无法执行记忆蒸馏"
is_web = self._is_web_channel(e_context)
def _run():
try:
result = flush_mgr.deep_dream(lookback_days=days, force=True)
if result:
self._notify(
e_context,
"✅ 记忆蒸馏完成\n\n[MEMORY.md](/memory/MEMORY.md) 已更新,[查看梦境日记](/memory/dreams)"
)
msg = self._build_dream_result(flush_mgr, is_web)
self._notify(e_context, msg)
else:
self._notify(e_context, "💤 记忆蒸馏跳过 — 没有新的记忆内容需要整理")
except Exception as e:
@@ -927,6 +927,40 @@ class CowCliPlugin(Plugin):
except Exception as e:
logger.warning(f"[CowCli] notify failed: {e}")
@staticmethod
def _is_web_channel(e_context) -> bool:
if e_context is None:
return False
try:
return e_context["context"].kwargs.get("channel_type") == "web"
except Exception:
return False
@staticmethod
def _build_dream_result(flush_mgr, is_web: bool) -> str:
"""Build dream completion message with diary content."""
from datetime import datetime
lines = ["✅ 记忆蒸馏完成"]
# Read today's dream diary
today = datetime.now().strftime("%Y-%m-%d")
diary_file = flush_mgr.memory_dir / "dreams" / f"{today}.md"
if diary_file.exists():
diary = diary_file.read_text(encoding="utf-8").strip()
# Strip the "# Dream Diary: ..." header line
diary_lines = diary.split("\n")
if diary_lines and diary_lines[0].startswith("# "):
diary = "\n".join(diary_lines[1:]).strip()
if diary:
lines.append(f"\n{diary}")
if is_web:
lines.append("\n[MEMORY.md](/memory/MEMORY.md) | [梦境日记](/memory/dreams)")
else:
lines.append("\nMEMORY.md 已更新")
return "\n".join(lines)
@staticmethod
def _create_standalone_flush_manager():
"""Create a MemoryFlushManager without a running agent (for pre-init dream)."""