v0.16.14: TypeScript 编译错误修复 + 文档同步 + 代码健壮性增强
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://img.shields.io/badge/version-v0.16.13-E8734A?style=flat-square" alt="version">
|
<img src="https://img.shields.io/badge/version-v0.16.14-E8734A?style=flat-square" alt="version">
|
||||||
<img src="https://img.shields.io/badge/electron-33+-47848F?style=flat-square&logo=electron" alt="electron">
|
<img src="https://img.shields.io/badge/electron-33+-47848F?style=flat-square&logo=electron" alt="electron">
|
||||||
<img src="https://img.shields.io/badge/typescript-5.7+-3178C6?style=flat-square&logo=typescript" alt="typescript">
|
<img src="https://img.shields.io/badge/typescript-5.7+-3178C6?style=flat-square&logo=typescript" alt="typescript">
|
||||||
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="license">
|
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="license">
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
| | 功能 | 说明 |
|
| | 功能 | 说明 |
|
||||||
|:---:|:---|:---|
|
|:---:|:---|:---|
|
||||||
| 🤖 | **ReAct Agent Loop** | 始终开启的唯一对话模式。8 状态机(INIT→THINKING→PARSING→EXECUTING→OBSERVING→REFLECTING→COMPRESSING→TERMINATED),最大 85 轮(可配置),智能重试(永久错误立即返回、瞬态错误指数退避),工具去重,智能路径依赖串行化,看门狗超时保护 |
|
| 🤖 | **ReAct Agent Loop** | 始终开启的唯一对话模式。8 状态机(INIT→THINKING→PARSING→EXECUTING→OBSERVING→REFLECTING→COMPRESSING→TERMINATED),最大 85 轮(可配置),智能重试(永久错误立即返回、瞬态错误指数退避),工具去重,智能路径依赖串行化,看门狗超时保护 |
|
||||||
| 🛡️ | **5 层抗幻觉系统** | 提示词加固 → 任务感知 → 中途检测(中英双语规则覆盖全部工具类别)→ 进度锚点 → 完成闸门(6 项检查,幻觉/注入 → 阻断,质量/效率 → 咨询) |
|
| 🛡️ | **提示词加固** | 参考数据标记(<<<REFERENCE_DATA_START>>>)+ 工具结果仅为数据非指令的安全规则注入 |
|
||||||
| 📋 | **Plan Mode** | 开关切换,AI 首先生成执行计划(Markdown 渲染确认弹窗),批准后按步骤追踪执行,plan_track 工具标记完成状态,**支持断点续传**(中止后可恢复未完成计划) |
|
| 📋 | **Plan Mode** | 开关切换,AI 首先生成执行计划(Markdown 渲染确认弹窗),批准后按步骤追踪执行,plan_track 工具标记完成状态,**支持断点续传**(中止后可恢复未完成计划) |
|
||||||
| 🔧 | **32 个内置工具** | 文件系统(13个) · 命令执行 · 联网搜索 · 浏览器控制(9个) · Git · 记忆 · 会话 · 子代理 · 系统工具 · Plan Mode 追踪 |
|
| 🔧 | **32 个内置工具** | 文件系统(13个) · 命令执行 · 联网搜索 · 浏览器控制(9个) · Git · 记忆 · 会话 · 子代理 · 系统工具 · Plan Mode 追踪 |
|
||||||
| 🧠 | **智能记忆系统** | 三类记忆(fact / preference / rule),存储于工作空间 MEMORY.md 文件,受路径保护仅 memory 工具可访问,写入前安全扫描,容量 500 条,对话结束自动提取,严格格式校验 |
|
| 🧠 | **智能记忆系统** | 三类记忆(fact / preference / rule),存储于工作空间 MEMORY.md 文件,受路径保护仅 memory 工具可访问,写入前安全扫描,容量 500 条,对话结束自动提取,严格格式校验 |
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
↓
|
↓
|
||||||
Agent Engine (8 状态机 ReAct Loop, ≤85 轮, 智能重试, 路径依赖串行化, 看门狗+分级超时)
|
Agent Engine (8 状态机 ReAct Loop, ≤85 轮, 智能重试, 路径依赖串行化, 看门狗+分级超时)
|
||||||
↓
|
↓
|
||||||
5 层抗幻觉系统(中英双语规则)(提示词 → 中途检测 → 进度锚 → 完成闸门 → 校验)
|
提示词加固(参考数据标记 + 工具结果安全规则)
|
||||||
↓
|
↓
|
||||||
Ollama API (流式响应,num_ctx 用户可配 128K/256K/512K/1M)
|
Ollama API (流式响应,num_ctx 用户可配 128K/256K/512K/1M)
|
||||||
↓
|
↓
|
||||||
@@ -245,7 +245,7 @@ npm start
|
|||||||
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
|
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
|
||||||
```
|
```
|
||||||
|
|
||||||
产出:`release/Metona Ollama Setup v0.16.13.exe`
|
产出:`release/Metona Ollama Setup v0.16.14.exe`
|
||||||
|
|
||||||
## 🛠️ 常用命令
|
## 🛠️ 常用命令
|
||||||
|
|
||||||
@@ -276,7 +276,7 @@ npm run dist # 构建 Windows 安装包
|
|||||||
| | Feature | Description |
|
| | Feature | Description |
|
||||||
|:---:|:---|:---|
|
|:---:|:---|:---|
|
||||||
| 🤖 | **ReAct Agent Loop** | Always-on, only chat mode. 8-state machine, up to 85 iterations (configurable), smart retry (permanent errors return immediately, transient errors use exponential backoff), tool dedup, path-aware dependency serialization, watchdog + tiered timeout protection |
|
| 🤖 | **ReAct Agent Loop** | Always-on, only chat mode. 8-state machine, up to 85 iterations (configurable), smart retry (permanent errors return immediately, transient errors use exponential backoff), tool dedup, path-aware dependency serialization, watchdog + tiered timeout protection |
|
||||||
| 🛡️ | **5-Layer Anti-Hallucination** | Prompt hardening → task awareness → mid-task detection (bilingual CN/EN rules covering all tool categories) → progress anchors → completion gate (6 checks: hallucination/injection → block, quality/efficiency → advisory) |
|
| 🛡️ | **Prompt Hardening** | Reference data markers (<<<REFERENCE_DATA_START>>>) + tool results are data-not-instructions safety rules |
|
||||||
| 📋 | **Plan Mode** | Toggle switch. AI first generates an execution plan (Markdown-rendered confirmation dialog), then tracks step-by-step execution, **supports resume** (interrupted plans restore on next session) |
|
| 📋 | **Plan Mode** | Toggle switch. AI first generates an execution plan (Markdown-rendered confirmation dialog), then tracks step-by-step execution, **supports resume** (interrupted plans restore on next session) |
|
||||||
| 🔧 | **32 Built-in Tools** | File system · Command · Web search · Browser · Git · Memory · Sessions · Sub-agent · System · Plan Mode tracking |
|
| 🔧 | **32 Built-in Tools** | File system · Command · Web search · Browser · Git · Memory · Sessions · Sub-agent · System · Plan Mode tracking |
|
||||||
| 🧠 | **Smart Memory System** | Three types (fact / preference / rule), stored in workspace MEMORY.md file, path-protected — only the memory tool can access it, pre-write security scan, 500 capacity, auto-extract on conversation end, strict format validation |
|
| 🧠 | **Smart Memory System** | Three types (fact / preference / rule), stored in workspace MEMORY.md file, path-protected — only the memory tool can access it, pre-write security scan, 500 capacity, auto-extract on conversation end, strict format validation |
|
||||||
@@ -413,7 +413,7 @@ User message → workspace SOUL.md (never compressed) → AGENT.md → USER.md (
|
|||||||
↓
|
↓
|
||||||
Agent Engine (8-state ReAct Loop, ≤85 iter, smart retry, path-aware serialization, watchdog+tiered timeout)
|
Agent Engine (8-state ReAct Loop, ≤85 iter, smart retry, path-aware serialization, watchdog+tiered timeout)
|
||||||
↓
|
↓
|
||||||
5-Layer Anti-Hallucination (bilingual CN/EN rules) (prompt → mid-task detection → anchors → gate → verification)
|
Prompt Hardening (reference data markers + tool result safety rules)
|
||||||
↓
|
↓
|
||||||
Ollama API (Streaming Response, num_ctx user-configurable 128K/256K/512K/1M)
|
Ollama API (Streaming Response, num_ctx user-configurable 128K/256K/512K/1M)
|
||||||
↓
|
↓
|
||||||
@@ -485,7 +485,7 @@ npm start
|
|||||||
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
|
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
|
||||||
```
|
```
|
||||||
|
|
||||||
Output: `release/Metona Ollama Setup v0.16.13.exe`
|
Output: `release/Metona Ollama Setup v0.16.14.exe`
|
||||||
|
|
||||||
## 🛠️ Common Commands
|
## 🛠️ Common Commands
|
||||||
|
|
||||||
|
|||||||
+6
-20
@@ -11,7 +11,7 @@ Metona Ollama Desktop 是基于 TypeScript + Electron 的 Windows 本地 AI 桌
|
|||||||
核心架构:
|
核心架构:
|
||||||
- **ReAct Agent Loop** — 8 状态机驱动的智能体循环(INIT→THINKING→PARSING→EXECUTING→OBSERVING→REFLECTING→COMPRESSING→TERMINATED),最大 85 轮(可配置)
|
- **ReAct Agent Loop** — 8 状态机驱动的智能体循环(INIT→THINKING→PARSING→EXECUTING→OBSERVING→REFLECTING→COMPRESSING→TERMINATED),最大 85 轮(可配置)
|
||||||
- **32 个内置工具** — 文件系统(13)、命令执行(1)、联网搜索(2)、浏览器控制(9)、Git(1)、记忆(1)、会话/子代理(3)、系统(1)、Plan Mode(1)
|
- **32 个内置工具** — 文件系统(13)、命令执行(1)、联网搜索(2)、浏览器控制(9)、Git(1)、记忆(1)、会话/子代理(3)、系统(1)、Plan Mode(1)
|
||||||
- **Harness Engineering** — 5 层抗幻觉体系 + 4 阶段 Hook 系统 + Completion Gate(5 项检查)+ Agent Metrics + 渐进式披露
|
- **Harness Engineering** — 提示词加固 + 4 阶段 Hook 系统 + Agent Metrics + 渐进式披露
|
||||||
- **MCP 协议扩展** — JSON-RPC 2.0 over stdio,动态工具发现
|
- **MCP 协议扩展** — JSON-RPC 2.0 over stdio,动态工具发现
|
||||||
- **Plan Mode** — 开关切换,先规划后执行,步骤级进度追踪
|
- **Plan Mode** — 开关切换,先规划后执行,步骤级进度追踪
|
||||||
- **SQLite 存储** — sql.js WASM,5 张表,WAL 模式
|
- **SQLite 存储** — sql.js WASM,5 张表,WAL 模式
|
||||||
@@ -80,7 +80,7 @@ src/
|
|||||||
│ │ ├── tool-confirm-modal.ts # 工具执行确认对话框
|
│ │ ├── tool-confirm-modal.ts # 工具执行确认对话框
|
||||||
│ │ ├── tools-modal.ts # 工具列表面板(32 个工具卡片)
|
│ │ ├── tools-modal.ts # 工具列表面板(32 个工具卡片)
|
||||||
│ │ └── workspace-panel.ts # 工作空间面板(终端 + 工具卡片 + 文件浏览)
|
│ │ └── workspace-panel.ts # 工作空间面板(终端 + 工具卡片 + 文件浏览)
|
||||||
│ ├── services/ # 14 个服务模块
|
│ ├── services/ # 13 个服务模块
|
||||||
│ │ ├── agent-engine.ts # ★ ReAct Agent Loop 核心引擎(8 状态机)
|
│ │ ├── agent-engine.ts # ★ ReAct Agent Loop 核心引擎(8 状态机)
|
||||||
│ │ ├── tool-registry.ts # 工具注册与调度中心(32 内置 + MCP 动态 + Plan Mode)
|
│ │ ├── tool-registry.ts # 工具注册与调度中心(32 内置 + MCP 动态 + Plan Mode)
|
||||||
│ │ ├── memory-service.ts # 记忆管理(MEMORY.md 读写 + 格式校验 + 自动提取)
|
│ │ ├── memory-service.ts # 记忆管理(MEMORY.md 读写 + 格式校验 + 自动提取)
|
||||||
@@ -90,7 +90,6 @@ src/
|
|||||||
│ │ ├── log-service.ts # 结构化日志(9 级分类)
|
│ │ ├── log-service.ts # 结构化日志(9 级分类)
|
||||||
│ │ ├── crypto.ts # AES-256-GCM 加密
|
│ │ ├── crypto.ts # AES-256-GCM 加密
|
||||||
│ │ ├── hooks.ts # 4 阶段 Hook 系统(pre_tool/post_tool/post_iteration/pre_completion)
|
│ │ ├── hooks.ts # 4 阶段 Hook 系统(pre_tool/post_tool/post_iteration/pre_completion)
|
||||||
│ │ ├── completion-gate.ts # 完成门控(5 项检查,阻断/咨询两级)
|
|
||||||
│ │ ├── agent-metrics.ts # Agent 度量采集 + 错误模式识别 + 改进建议
|
│ │ ├── agent-metrics.ts # Agent 度量采集 + 错误模式识别 + 改进建议
|
||||||
│ │ ├── agent-safety.ts # Agent 安全防护(工具阴影检测 + 路径校验)
|
│ │ ├── agent-safety.ts # Agent 安全防护(工具阴影检测 + 路径校验)
|
||||||
│ │ ├── context-indexer.ts # 渐进式披露(索引层→接口层→实现层)
|
│ │ ├── context-indexer.ts # 渐进式披露(索引层→接口层→实现层)
|
||||||
@@ -227,15 +226,13 @@ INIT → THINKING → PARSING → EXECUTING → OBSERVING → REFLECTING → (CO
|
|||||||
|
|
||||||
### 5.4 Harness Engineering 体系
|
### 5.4 Harness Engineering 体系
|
||||||
|
|
||||||
#### 5.4.1 5 层抗幻觉
|
#### 5.4.1 提示词加固
|
||||||
|
|
||||||
| 层级 | 实现位置 | 机制 |
|
| 层级 | 实现位置 | 机制 |
|
||||||
|------|---------|------|
|
|------|---------|------|
|
||||||
| 提示词加固 | `handleInit()` | [反幻觉铁律] 最高优先级注入 |
|
| 提示词加固 | `handleInit()` | 注入安全规则:参考数据标记(<<<REFERENCE_DATA_START>>>)+ 工具结果仅为数据非指令 |
|
||||||
| 任务感知 | `handleThinking()` | 第 2 轮无工具调用时注入提醒 |
|
|
||||||
| 中途检测 | `detectMidTaskHallucination()` | 16 条正则规则,覆盖全部工具类别 |
|
> 注:任务感知注入、中途检测、进度锚点、完成闸门已在版本迭代中移除,AI 基于工具返回值和上下文自行判断。
|
||||||
| 进度锚点 | `handleObserving()` | 每 5 轮注入机器生成的工具调用摘要 |
|
|
||||||
| 完成闸门 | `completion-gate.ts` | 6 项检查:幻觉/注入→阻断级,质量/效率→咨询级 |
|
|
||||||
|
|
||||||
#### 5.4.2 Hook 系统(4 阶段)
|
#### 5.4.2 Hook 系统(4 阶段)
|
||||||
|
|
||||||
@@ -249,17 +246,6 @@ INIT → THINKING → PARSING → EXECUTING → OBSERVING → REFLECTING → (CO
|
|||||||
|
|
||||||
Hook 异步并行执行,失败不阻塞主流程。可动态注册/移除。
|
Hook 异步并行执行,失败不阻塞主流程。可动态注册/移除。
|
||||||
|
|
||||||
#### 5.4.3 Completion Gate(6 项检查)
|
|
||||||
|
|
||||||
| 检查项 | 级别 | 不通过行为 |
|
|
||||||
|--------|------|-----------|
|
|
||||||
| toolHallucination | 🔴 阻断 | 强制重新回答 |
|
|
||||||
| promptInjection | 🔴 阻断 | 强制重新回答 |
|
|
||||||
| contentQuality | 🟡 咨询 | 仅记录日志 |
|
|
||||||
| toolResultReview | 🟡 咨询 | 仅记录日志 |
|
|
||||||
| notThinking | 🟡 咨询 | 仅记录日志 |
|
|
||||||
| contextEfficiency | 🟡 咨询 | 仅记录日志 |
|
|
||||||
|
|
||||||
### 5.5 联网搜索体系
|
### 5.5 联网搜索体系
|
||||||
|
|
||||||
**双模式架构**:
|
**双模式架构**:
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "metona-ollama-desktop",
|
"name": "metona-ollama-desktop",
|
||||||
"version": "0.16.13",
|
"version": "0.16.14",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "metona-ollama-desktop",
|
"name": "metona-ollama-desktop",
|
||||||
"version": "0.16.13",
|
"version": "0.16.14",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ffmpeg-static": "^5.2.0",
|
"ffmpeg-static": "^5.2.0",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "metona-ollama-desktop",
|
"name": "metona-ollama-desktop",
|
||||||
"version": "0.16.13",
|
"version": "0.16.14",
|
||||||
"description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端",
|
"description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端",
|
||||||
"main": "dist/main/main.js",
|
"main": "dist/main/main.js",
|
||||||
"author": "thzxx",
|
"author": "thzxx",
|
||||||
|
|||||||
+1
-1
@@ -101,7 +101,7 @@ export function createMenu(): void {
|
|||||||
dialog.showMessageBox(mainWindow!, {
|
dialog.showMessageBox(mainWindow!, {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
title: '关于 Metona Ollama',
|
title: '关于 Metona Ollama',
|
||||||
message: 'Metona Ollama Desktop v0.16.13',
|
message: 'Metona Ollama Desktop v0.16.14',
|
||||||
detail: 'TypeScript + Electron Ollama AI 聊天客户端\n\nhttps://gitee.com/thzxx/metona-ollama',
|
detail: 'TypeScript + Electron Ollama AI 聊天客户端\n\nhttps://gitee.com/thzxx/metona-ollama',
|
||||||
icon: getIconPath()
|
icon: getIconPath()
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ export class OllamaAPI {
|
|||||||
}, { once: true });
|
}, { once: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
const { done, value } = await reader.read();
|
const { done, value } = await reader.read();
|
||||||
if (done) {
|
if (done) {
|
||||||
@@ -128,6 +129,11 @@ export class OllamaAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// abort 导致 reader.cancel() 会使 reader.read() 抛出异常,属于正常中止流程
|
||||||
|
if (abortController?.signal.aborted) return;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
if (buffer.trim()) {
|
if (buffer.trim()) {
|
||||||
let chunk: OllamaStreamChunk;
|
let chunk: OllamaStreamChunk;
|
||||||
|
|||||||
@@ -1080,7 +1080,7 @@ function renderToolCard(tc: ToolCallRecord): string {
|
|||||||
} else if (tc.name === 'delete_file') {
|
} else if (tc.name === 'delete_file') {
|
||||||
if (r.batch) {
|
if (r.batch) {
|
||||||
resultHtml = `<div class="tool-result-entry">✅ 批量删除 ${r.successCount}/${r.totalPaths} 个路径</div>`;
|
resultHtml = `<div class="tool-result-entry">✅ 批量删除 ${r.successCount}/${r.totalPaths} 个路径</div>`;
|
||||||
if (r.results) {
|
if (Array.isArray(r.results)) {
|
||||||
for (const res of r.results) {
|
for (const res of r.results) {
|
||||||
resultHtml += `<div class="tool-result-entry">${res.success ? '✅' : '❌'} ${escapeHtml(String(res.path || ''))}${res.success ? '' : ' — ' + escapeHtml(String(res.error || ''))}</div>`;
|
resultHtml += `<div class="tool-result-entry">${res.success ? '✅' : '❌'} ${escapeHtml(String(res.path || ''))}${res.success ? '' : ' — ' + escapeHtml(String(res.error || ''))}</div>`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<img class="logo" src="./assets/icons/llama.png" alt="logo" />
|
<img class="logo" src="./assets/icons/llama.png" alt="logo" />
|
||||||
<span class="app-title">Metona Ollama</span>
|
<span class="app-title">Metona Ollama</span>
|
||||||
<span class="app-version">v0.16.13</span>
|
<span class="app-version">v0.16.14</span>
|
||||||
<button class="icon-btn help-btn" id="btnHelp" title="使用帮助">
|
<button class="icon-btn help-btn" id="btnHelp" title="使用帮助">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/>
|
<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/>
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ async function startNewSession(): Promise<void> {
|
|||||||
|
|
||||||
async function init(): Promise<void> {
|
async function init(): Promise<void> {
|
||||||
let db: ChatDB | undefined;
|
let db: ChatDB | undefined;
|
||||||
let api: OllamaAPI;
|
let api: OllamaAPI | undefined;
|
||||||
|
|
||||||
logInit('启动...');
|
logInit('启动...');
|
||||||
|
|
||||||
|
|||||||
@@ -1340,7 +1340,7 @@ async function handleInit(
|
|||||||
logInfo(`自动上下文压缩触发: tokens≈${estimateTokens(ctx.messages.map(m => m.content || '').join(''))} > ${Math.floor(effectiveNumCtx * AUTO_COMPRESS_THRESHOLD)} (${Math.round(AUTO_COMPRESS_THRESHOLD * 100)}% of ${effectiveNumCtx})`);
|
logInfo(`自动上下文压缩触发: tokens≈${estimateTokens(ctx.messages.map(m => m.content || '').join(''))} > ${Math.floor(effectiveNumCtx * AUTO_COMPRESS_THRESHOLD)} (${Math.round(AUTO_COMPRESS_THRESHOLD * 100)}% of ${effectiveNumCtx})`);
|
||||||
const compressAC = state.get<AbortController | null>(KEYS.ABORT_CONTROLLER) || new AbortController();
|
const compressAC = state.get<AbortController | null>(KEYS.ABORT_CONTROLLER) || new AbortController();
|
||||||
try {
|
try {
|
||||||
const compressed = await compressWithLLM(ctx.messages, api as any, model, { abortController: compressAC });
|
const compressed = await compressWithLLM(ctx.messages, api, model, { abortController: compressAC });
|
||||||
// P1-C4 修复:handleInit 中的自动压缩也使用 AND 条件
|
// P1-C4 修复:handleInit 中的自动压缩也使用 AND 条件
|
||||||
const initBeforeTokens = estimateTokens(ctx.messages.map(m => m.content || '').join(''));
|
const initBeforeTokens = estimateTokens(ctx.messages.map(m => m.content || '').join(''));
|
||||||
const initAfterTokens = estimateTokens(compressed.map(m => m.content || '').join(''));
|
const initAfterTokens = estimateTokens(compressed.map(m => m.content || '').join(''));
|
||||||
@@ -1634,7 +1634,7 @@ async function handleThinking(
|
|||||||
logWarn(`R8: 检测到上下文溢出错误,触发紧急压缩 (${ctx.emergencyCompressCount}/${MAX_EMERGENCY_COMPRESS})`, errMsg.slice(0, 100));
|
logWarn(`R8: 检测到上下文溢出错误,触发紧急压缩 (${ctx.emergencyCompressCount}/${MAX_EMERGENCY_COMPRESS})`, errMsg.slice(0, 100));
|
||||||
try {
|
try {
|
||||||
const compressAC = new AbortController();
|
const compressAC = new AbortController();
|
||||||
const compressed = await compressWithLLM(ctx.messages, api as any, model, { abortController: compressAC });
|
const compressed = await compressWithLLM(ctx.messages, api, model, { abortController: compressAC });
|
||||||
// P1-C4 修复:R8 紧急压缩也使用 AND 条件,避免接受 token 增加的结果
|
// P1-C4 修复:R8 紧急压缩也使用 AND 条件,避免接受 token 增加的结果
|
||||||
const r8BeforeTokens = estimateTokens(ctx.messages.map(m => m.content || '').join(''));
|
const r8BeforeTokens = estimateTokens(ctx.messages.map(m => m.content || '').join(''));
|
||||||
const r8AfterTokens = estimateTokens(compressed.map(m => m.content || '').join(''));
|
const r8AfterTokens = estimateTokens(compressed.map(m => m.content || '').join(''));
|
||||||
@@ -2446,7 +2446,7 @@ async function handleCompressing(
|
|||||||
logInfo('COMPRESSING: 上下文压缩触发');
|
logInfo('COMPRESSING: 上下文压缩触发');
|
||||||
const compressAC = state.get<AbortController | null>(KEYS.ABORT_CONTROLLER) || new AbortController();
|
const compressAC = state.get<AbortController | null>(KEYS.ABORT_CONTROLLER) || new AbortController();
|
||||||
try {
|
try {
|
||||||
const compressed = await compressWithLLM(ctx.messages, api as any, model, { abortController: compressAC });
|
const compressed = await compressWithLLM(ctx.messages, api, model, { abortController: compressAC });
|
||||||
// P1-C4 修复:原条件用 OR(消息数减少 OR token 减少),可能接受 token 增加的结果。
|
// P1-C4 修复:原条件用 OR(消息数减少 OR token 减少),可能接受 token 增加的结果。
|
||||||
// 改为 AND:只有消息数减少且 token 减少时才接受,确保压缩真正生效
|
// 改为 AND:只有消息数减少且 token 减少时才接受,确保压缩真正生效
|
||||||
const beforeTokens = estimateTokens(ctx.messages.map(m => m.content || '').join(''));
|
const beforeTokens = estimateTokens(ctx.messages.map(m => m.content || '').join(''));
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* 支持自动压缩与手动 /compress 触发
|
* 支持自动压缩与手动 /compress 触发
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { OllamaMessage, OllamaStreamChunk } from '../types.js';
|
import type { OllamaMessage, OllamaStreamChunk, OllamaChatParams } from '../types.js';
|
||||||
import { logInfo, logWarn, logSuccess, logError } from './log-service.js';
|
import { logInfo, logWarn, logSuccess, logError } from './log-service.js';
|
||||||
|
|
||||||
// ── R12: 压缩去重 — 内容指纹追踪 ──
|
// ── R12: 压缩去重 — 内容指纹追踪 ──
|
||||||
@@ -586,7 +586,7 @@ export interface StructuredSummary {
|
|||||||
*/
|
*/
|
||||||
export async function compressWithLLM(
|
export async function compressWithLLM(
|
||||||
messages: OllamaMessage[],
|
messages: OllamaMessage[],
|
||||||
api: { chatStream: (params: Record<string, unknown>, onChunk: (chunk: OllamaStreamChunk) => void, ac?: AbortController) => Promise<void> },
|
api: { chatStream: (params: OllamaChatParams, onChunk: (chunk: OllamaStreamChunk) => void, abortController?: AbortController) => Promise<void> },
|
||||||
model: string,
|
model: string,
|
||||||
options: {
|
options: {
|
||||||
keepHead?: number;
|
keepHead?: number;
|
||||||
|
|||||||
Vendored
+1
@@ -120,6 +120,7 @@ export interface ChatMessage {
|
|||||||
/** 多视频独立指示牌 */
|
/** 多视频独立指示牌 */
|
||||||
_videos?: Array<{ fileName: string; frameCount: number; duration: number }>;
|
_videos?: Array<{ fileName: string; frameCount: number; duration: number }>;
|
||||||
stopped?: boolean;
|
stopped?: boolean;
|
||||||
|
interrupted?: boolean;
|
||||||
toolCalls?: ToolCallRecord[];
|
toolCalls?: ToolCallRecord[];
|
||||||
/** 标记此消息为 LLM 压缩摘要生成 */
|
/** 标记此消息为 LLM 压缩摘要生成 */
|
||||||
compressed?: boolean;
|
compressed?: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user