From 3ddd49384744c89825ed83a8cc7278aaf8c5bf38 Mon Sep 17 00:00:00 2001
From: thzxx
Date: Sun, 28 Jun 2026 19:52:53 +0800
Subject: [PATCH] =?UTF-8?q?chore:=20=E7=89=88=E6=9C=AC=E5=8F=B7=200.14.2?=
=?UTF-8?q?=20=E2=86=92=200.14.3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
fix: AI 回复消息卡片重复渲染 — onDone 去掉 updateLastAssistantMessage 避免双重 DOM
fix: 用户消息卡片只显示用户文字,代码生成的附件标记不显示
fix: onDone assistantMsg 补充 model 字段
---
README.md | 6 ++---
package-lock.json | 4 +--
package.json | 2 +-
src/main/menu.ts | 2 +-
src/renderer/components/input-area.ts | 35 ++++++++-------------------
src/renderer/index.html | 2 +-
src/renderer/types.d.ts | 2 ++
7 files changed, 20 insertions(+), 33 deletions(-)
diff --git a/README.md b/README.md
index ab11877..527690b 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
-
+
@@ -253,7 +253,7 @@ npm start
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
```
-产出:`release/Metona Ollama Setup v0.14.2.exe`
+产出:`release/Metona Ollama Setup v0.14.3.exe`
## 🛠️ 常用命令
@@ -501,7 +501,7 @@ npm start
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
```
-Output: `release/Metona Ollama Setup v0.14.2.exe`
+Output: `release/Metona Ollama Setup v0.14.3.exe`
## 🛠️ Common Commands
diff --git a/package-lock.json b/package-lock.json
index b8fca5d..b27a86f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "metona-ollama-desktop",
- "version": "0.14.2",
+ "version": "0.14.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "metona-ollama-desktop",
- "version": "0.14.2",
+ "version": "0.14.3",
"license": "MIT",
"dependencies": {
"ffmpeg-static": "^5.2.0",
diff --git a/package.json b/package.json
index 3995f0b..cd02b83 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "metona-ollama-desktop",
- "version": "0.14.2",
+ "version": "0.14.3",
"description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端",
"main": "dist/main/main.js",
"author": "thzxx",
diff --git a/src/main/menu.ts b/src/main/menu.ts
index a3849c0..20f0a80 100644
--- a/src/main/menu.ts
+++ b/src/main/menu.ts
@@ -101,7 +101,7 @@ export function createMenu(): void {
dialog.showMessageBox(mainWindow!, {
type: 'info',
title: '关于 Metona Ollama',
- message: 'Metona Ollama Desktop v0.14.2',
+ message: 'Metona Ollama Desktop v0.14.3',
detail: 'TypeScript + Electron Ollama AI 聊天客户端\n\nhttps://gitee.com/thzxx/metona-ollama',
icon: getIconPath()
});
diff --git a/src/renderer/components/input-area.ts b/src/renderer/components/input-area.ts
index 7d3ba54..c3b6133 100644
--- a/src/renderer/components/input-area.ts
+++ b/src/renderer/components/input-area.ts
@@ -588,7 +588,7 @@ async function handleRetry(): Promise {
if (retryIterations > 0) {
if (finalContent) {
const lastMsg: ChatMessage = {
- role: 'assistant', content: finalContent, timestamp: Date.now(),
+ role: 'assistant', content: finalContent, model: getSelectedModel(), timestamp: Date.now(),
...(retryThinkContent && { think: retryThinkContent }),
...(toolRecords?.length && { toolCalls: toolRecords }),
...(loopStats?.eval_count && { eval_count: loopStats.eval_count }),
@@ -599,10 +599,9 @@ async function handleRetry(): Promise {
...s, messages: [...s.messages, lastMsg], updatedAt: Date.now()
}));
}
- updateLastAssistantMessage(finalContent, retryThinkContent || null, loopStats || null, getSelectedModel(), Date.now(), toolRecords?.length ? toolRecords : undefined);
} else {
const assistantMsg: ChatMessage = {
- role: 'assistant', content: finalContent || '', timestamp: Date.now(),
+ role: 'assistant', content: finalContent || '', model: getSelectedModel(), timestamp: Date.now(),
...(retryThinkContent && { think: retryThinkContent }),
...(toolRecords?.length && { toolCalls: toolRecords }),
...(loopStats?.eval_count && { eval_count: loopStats.eval_count }),
@@ -612,8 +611,9 @@ async function handleRetry(): Promise {
state.update(KEYS.CURRENT_SESSION, (s: any) => ({
...s, messages: [...s.messages, assistantMsg], updatedAt: Date.now()
}));
- updateLastAssistantMessage(finalContent, retryThinkContent || null, loopStats || null, getSelectedModel(), Date.now(), toolRecords?.length ? toolRecords : undefined);
}
+ // renderMessages 统一渲染 session 数据,先清掉流式 placeholder 避免 DOM 重复
+ clearMessagesDOM();
renderMessages();
// ── 保存 Plan Mode 最终进度到会话(供下一轮 Loop 注入)──
const lastPlanStatus = state.get('_lastPlanStatus', '');
@@ -1135,26 +1135,10 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
const hasAttachments = pendingImages.length > 0 || hasVideos || userFiles.length > 0;
if (hasAttachments) {
- // 聊天卡片显示用的简短描述
- const displayParts: string[] = [];
- if (text) displayParts.push(text);
- if (pendingVideoMeta && pendingVideoFrames.length > 0) {
- displayParts.push(`[视频: ${pendingVideoMeta.fileName}, ${pendingVideoFrames.length}帧, 1fps]`);
- }
- for (const v of completedVideos) {
- displayParts.push(`[视频: ${v.fileName}, ${v.frames.length}帧, 1fps]`);
- }
- if (pendingImages.length === 1) {
- displayParts.push(`[图片: ${pendingImages[0].name}]`);
- } else if (pendingImages.length > 1) {
- displayParts.push(`[${pendingImages.length} 张图片]`);
- }
- for (const f of userFiles) {
- displayParts.push(`[文件: ${f.name}]`);
- }
- const displayContent = displayParts.join('\n');
+ // ── 聊天卡片:只显示用户自己的文字 + 附件视觉预览(缩略图/文件卡片/视频帧),不含代码生成的文本标记 ──
+ const displayContent = text || '';
- // Ollama API 用的完整描述(文字 + 文件 + 视频帧序列 + 图片提示)
+ // ── Ollama API 用:完整描述(文字 + 文件内容 + 视频帧序列 + 图片提示)──
const apiParts: string[] = [];
if (text) apiParts.push(text);
if (userFiles.length > 0) {
@@ -1164,9 +1148,9 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
logInfo('📄 文件内容已注入', `${fileParts.length} 段, 共 ${fileContents.reduce((s, f) => s + f.content.length, 0)} 字符`);
}
if (pendingImages.length === 1) {
- apiParts.push(`[已上传图片: ${pendingImages[0].name} — 此图片已随消息提供,你可以直接分析,无需去磁盘查找]`);
+ apiParts.push(`[已上传图片: ${pendingImages[0].name}]`);
} else if (pendingImages.length > 1) {
- apiParts.push(`[已上传 ${pendingImages.length} 张图片: ${pendingImages.map(img => img.name).join(', ')} — 这些图片已随消息提供,你可以直接分析,无需去磁盘查找]`);
+ apiParts.push(`[已上传 ${pendingImages.length} 张图片: ${pendingImages.map(img => img.name).join(', ')}]`);
}
let allVids: Array<{ name: string; count: number; dur: number; frames: Array<{ timestampSeconds: number; name: string; base64: string }> }> = [];
if (hasVideos) {
@@ -1190,6 +1174,7 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
role: 'user',
content: displayContent,
images: [...pendingImages.map(img => img.base64)],
+ _apiContent: apiContentForModel, // 给模型的完整内容,不显示给用户
timestamp: now
};
if (allVids.length > 0) {
diff --git a/src/renderer/index.html b/src/renderer/index.html
index 2701985..3698022 100644
--- a/src/renderer/index.html
+++ b/src/renderer/index.html
@@ -28,7 +28,7 @@