-
+
-
+
@@ -102,7 +103,9 @@
{{ t('toolCall.responseData') }}
-
+
+
+
@@ -115,8 +118,10 @@
import { Icon } from '@iconify/vue'
import { useI18n } from 'vue-i18n'
import { AssistantMessageBlock } from '@shared/chat'
-import { ref } from 'vue'
+import { ref, onMounted, watch } from 'vue'
import { JsonObject } from '@/components/json-viewer'
+import MarkdownRenderer from '@/components/markdown/MarkdownRenderer.vue'
+import TurndownService from 'turndown';
// 创建一个安全的翻译函数
const t = (() => {
@@ -148,6 +153,21 @@ const props = defineProps<{
const isExpanded = ref(false)
+// 在组件挂载时检查direct_return属性
+onMounted(() => {
+ console.log("pMessageBlockToolCall-block.tool_call",props.block.tool_call?.direct_return)
+ if (props.block.tool_call?.direct_return === true) {
+ isExpanded.value = true
+ }
+})
+
+// 监听direct_return属性变化
+watch(() => props.block.tool_call?.direct_return, (newVal) => {
+ if (newVal === true) {
+ isExpanded.value = true
+ }
+})
+
const toggleExpanded = () => {
isExpanded.value = !isExpanded.value
}
@@ -192,6 +212,49 @@ const parseJson = (jsonStr: string) => {
return { raw: jsonStr }
}
}
+//JSON转换markdown方法
+function csvToMarkdownTable(csvString: string): string {
+ // 按行分割,并去掉空行
+ const lines = csvString
+ .trim()
+ .split(/\r?\n/)
+ .filter(line => line.trim())
+
+ if (lines.length === 0) return ''
+
+ // 解析每行
+ const rows = lines.map(line =>
+ line
+ .split(',')
+ .map(cell => cell.trim()) // 去掉首尾空格
+ )
+
+ // 表头
+ const header = rows[0]
+ const separator = header.map(() => '---') // 分隔符
+
+ // 组合表格
+ const table = [
+ `| ${header.join(' | ')} |`,
+ `| ${separator.join(' | ')} |`,
+ ...rows.slice(1).map(row => `| ${row.join(' | ')} |`)
+ ]
+
+ return table.join('\n')
+}
+// 提取Markdown内容
+const getMarkdownContent = (content: string) => {
+ if (!content) return ''
+
+ try {
+ console.log("getMarkdownContent-content",content)
+ const markdownContent = csvToMarkdownTable(content);
+ return markdownContent
+ } catch (e) {
+ // 不是JSON格式,直接返回原始内容
+ return content
+ }
+}
// const simpleIn = computed(() => {
// if (!props.block.tool_call) return false
diff --git a/src/renderer/src/i18n/zh-CN/chat.json b/src/renderer/src/i18n/zh-CN/chat.json
index de273873b..0a0ddf578 100644
--- a/src/renderer/src/i18n/zh-CN/chat.json
+++ b/src/renderer/src/i18n/zh-CN/chat.json
@@ -5,6 +5,7 @@
"inputArea": "输入区域",
"functionSwitch": "功能开关",
"fileSelect": "选择文件",
+ "aiChange":"AI处理结果",
"pasteFiles": "支持复制粘贴文件",
"dropFiles": "拖拽文件到此处",
"promptFilesAdded": "Prompt 文件已添加",
diff --git a/src/renderer/src/stores/aiStore.ts b/src/renderer/src/stores/aiStore.ts
new file mode 100644
index 000000000..e8a7fba93
--- /dev/null
+++ b/src/renderer/src/stores/aiStore.ts
@@ -0,0 +1,16 @@
+// stores/aiStore.ts
+import { defineStore } from 'pinia'
+
+export const useAiStore = defineStore('ai', {
+ state: () => ({
+ aiChange: false // 默认值
+ }),
+ actions: {
+ toggleAiChange() {
+ this.aiChange = !this.aiChange
+ },
+ setAiChange(value: boolean) {
+ this.aiChange = value
+ }
+ }
+})
diff --git a/src/renderer/src/stores/chat.ts b/src/renderer/src/stores/chat.ts
index 12e5e7a01..99a1d9271 100644
--- a/src/renderer/src/stores/chat.ts
+++ b/src/renderer/src/stores/chat.ts
@@ -331,6 +331,7 @@ export const useChatStore = defineStore('chat', () => {
queueLength: number
estimatedWaitTime?: number
}
+ direct_return?: boolean
}) => {
// 从缓存中查找消息
const cached = getGeneratingMessagesCache().get(msg.eventId)
@@ -465,6 +466,11 @@ export const useChatStore = defineStore('chat', () => {
existingToolCallBlock.status = 'success'
if (msg.tool_call_response && existingToolCallBlock.tool_call) {
existingToolCallBlock.tool_call.response = msg.tool_call_response
+
+ // 如果是直接返回的工具调用结果,添加标记
+ if (msg.direct_return) {
+ existingToolCallBlock.tool_call.direct_return = true
+ }
}
}
}
diff --git a/src/renderer/src/stores/mcp.ts b/src/renderer/src/stores/mcp.ts
index 2f77e6f9a..0a481be5c 100644
--- a/src/renderer/src/stores/mcp.ts
+++ b/src/renderer/src/stores/mcp.ts
@@ -27,6 +27,7 @@ interface MCPToolCallRequest {
interface MCPToolCallResult {
function_name?: string
content: string | { type: string; text: string }[]
+ directReturn?: boolean
}
export const useMcpStore = defineStore('mcp', () => {
@@ -497,9 +498,13 @@ export const useMcpStore = defineStore('mcp', () => {
window.electron.ipcRenderer.on(
MCP_EVENTS.TOOL_CALL_RESULT,
(_event, result: MCPToolCallResult) => {
- console.log(`MCP tool call result:`, result.function_name)
+ console.log(`MCP tool call result:`, result)
+
if (result && result.function_name) {
toolResults.value[result.function_name] = result.content
+ const currentValue = localStorage.getItem('aiChange') as string
+ result.directReturn = JSON.parse(currentValue)
+ console.log('MCP AIChange', result.directReturn)
}
}
)
diff --git a/src/shared/chat.d.ts b/src/shared/chat.d.ts
index 7de7696dc..ccbaaaae3 100644
--- a/src/shared/chat.d.ts
+++ b/src/shared/chat.d.ts
@@ -125,6 +125,7 @@ export type AssistantMessageBlock = {
server_name?: string
server_icons?: string
server_description?: string
+ direct_return?: boolean
}
action_type?: 'tool_call_permission' | 'maximum_tool_calls_reached' | 'rate_limit'
image_data?: {
diff --git a/src/shared/presenter.d.ts b/src/shared/presenter.d.ts
index b73a94f8d..a6e120d65 100644
--- a/src/shared/presenter.d.ts
+++ b/src/shared/presenter.d.ts
@@ -1050,7 +1050,8 @@ export interface MCPToolResponse {
/** 是否需要权限 */
requiresPermission?: boolean
-
+ /** 是否直接返回不再继续喂回判断 */
+ directReturn?: boolean | { aiChange: boolean }
/** 权限请求信息 */
permissionRequest?: {
toolName: string
@@ -1257,6 +1258,7 @@ export interface LLMAgentEventData {
tool_call_server_name?: string
tool_call_server_icons?: string
tool_call_server_description?: string
+ directReturn?: boolean | { aiChange: boolean }
tool_call_response_raw?: any
tool_call?: 'start' | 'running' | 'end' | 'error' | 'update' | 'permission-required'
From 466045f0ebec0c82b4d38a6bcb3a8fc804ee44b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=9B=AA=E5=B3=B0?= <2235113304@qq.com>
Date: Thu, 14 Aug 2025 11:26:21 +0800
Subject: [PATCH 2/8] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E5=9B=BE=E6=A0=87ICON?=
=?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=8C=89=E9=92=AE=E4=B8=8D=E5=90=8C?=
=?UTF-8?q?=E6=97=B6=E6=9C=BA=E4=B8=8D=E5=90=8C=E6=A0=B7=E5=BC=8F=EF=BC=8C?=
=?UTF-8?q?=E5=90=8C=E6=97=B6=E5=9C=A8=E6=96=B0=E5=BB=BA=E9=A1=B5=E9=9D=A2?=
=?UTF-8?q?=E6=97=B6=E5=88=9D=E5=A7=8B=E5=8C=96=E6=9C=AC=E5=9C=B0=E5=8C=96?=
=?UTF-8?q?=E5=AD=98=E5=82=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/renderer/src/components/ChatInput.vue | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/src/renderer/src/components/ChatInput.vue b/src/renderer/src/components/ChatInput.vue
index ec555eabc..2da2292be 100644
--- a/src/renderer/src/components/ChatInput.vue
+++ b/src/renderer/src/components/ChatInput.vue
@@ -70,10 +70,11 @@
{{ t('chat.input.aiChange') }}
@@ -485,16 +486,15 @@ const openFilePicker = () => {
}
//切换pinia中保存的aiChange状态
const aiChange = () =>{
-// aiStore.toggleAiChange();
-// console.log("aiChange",aiStore.aiChange)
-// console.log("aiChange",aiStore.aiChange)
// 1. 获取当前值(转换为布尔值)
const currentValue = localStorage.getItem("aiChange");
+ console.log("currentValueORI",currentValue)
const isAiChange = JSON.parse(currentValue) === true; // 字符串比较
// 2. 切换值
const newValue = !isAiChange;
+aiChangeIsActive.value = !(newValue ?? true);
console.log("触发了AiChange",newValue)
// 3. 保存新值
// localStorage.setItem("aiChange", newValue);
@@ -505,6 +505,13 @@ const aiChange = () =>{
})
}
+const getInitialValue = () => {
+ const savedValue = localStorage.getItem('newValue');
+ // 如果 localStorage 没有值,可以设置默认行为(例如默认 false)
+ return savedValue !== null ? !JSON.parse(savedValue) : true;
+};
+const aiChangeIsActive = ref(getInitialValue());
+
const previewFile = (filePath: string) => {
windowPresenter.previewFile(filePath)
}
@@ -1035,6 +1042,12 @@ onMounted(() => {
window.electron.ipcRenderer.on('rate-limit:request-queued', handleRateLimitEvent)
statusInterval = window.setInterval(loadRateLimitStatus, 1000)
+
+ window.electron.ipcRenderer.send('aiChangeEvent',{
+ aiChange:false
+ })
+ localStorage.setItem("aiChange", 'false');
+ aiChangeIsActive.value = true
})
onUnmounted(() => {
From 3b038eb6a473c0910873413db2eb0a1aa86f9cf8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=9B=AA=E5=B3=B0?= <2235113304@qq.com>
Date: Fri, 15 Aug 2025 09:21:26 +0800
Subject: [PATCH 3/8] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E6=97=A0=E7=94=A8?=
=?UTF-8?q?=E4=BB=A3=E7=A0=81=EF=BC=8C=E4=B8=8D=E5=86=8D=E4=BD=BF=E7=94=A8?=
=?UTF-8?q?=E6=8C=81=E4=B9=85=E5=8C=96=E5=AD=98=E5=82=A8=EF=BC=8C=E6=B7=BB?=
=?UTF-8?q?=E5=8A=A0=E9=83=A8=E5=88=86=E6=B3=A8=E9=87=8A=EF=BC=8C=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E5=88=87=E6=8D=A2=E4=BA=8C=E6=AC=A1=E6=8A=95=E5=96=82?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/renderer/src/components/ChatInput.vue | 51 ++++++++++++-----------
src/renderer/src/stores/mcp.ts | 12 +++---
2 files changed, 33 insertions(+), 30 deletions(-)
diff --git a/src/renderer/src/components/ChatInput.vue b/src/renderer/src/components/ChatInput.vue
index 2da2292be..446e70f91 100644
--- a/src/renderer/src/components/ChatInput.vue
+++ b/src/renderer/src/components/ChatInput.vue
@@ -64,7 +64,7 @@
{{ t('chat.input.fileSelect') }}
-
+
-
-
+
{
@@ -485,32 +486,34 @@ const openFilePicker = () => {
fileInput.value?.click()
}
//切换pinia中保存的aiChange状态
-const aiChange = () =>{
+const aiChange = () => {
+ // 1. 获取当前值(转换为布尔值)
+ const isAiChange = JSON.parse(aiChangeState.value) === true // 字符串比较,将isAiChange转换为aiChangeState.value的布尔值
- // 1. 获取当前值(转换为布尔值)
- const currentValue = localStorage.getItem("aiChange");
- console.log("currentValueORI",currentValue)
- const isAiChange = JSON.parse(currentValue) === true; // 字符串比较
-
// 2. 切换值
- const newValue = !isAiChange;
-aiChangeIsActive.value = !(newValue ?? true);
- console.log("触发了AiChange",newValue)
+ //newValue 为 true 时,关闭二次投喂, newValue 为 false 时 ,开启二次投喂
+ //默认状态aiChangeState为false,IPC传输的aiChange值为false 此时存在AI的二次投喂
+ //当第一次点击触发了aiChange方法 aiChangeState.value 为false isAiChange为fasle, newValue 为true ,关闭二次投喂
+
+ const newValue = !isAiChange
+ aiChangeIsActive.value = !(newValue ?? true)
+ console.log('触发了AiChange', newValue)
+ console.log('二次投喂', aiChangeIsActive.value)
+
// 3. 保存新值
- // localStorage.setItem("aiChange", newValue);
- localStorage.setItem("aiChange", JSON.stringify(newValue));
-
- window.electron.ipcRenderer.send('aiChangeEvent',{
- aiChange:newValue
+ aiChangeState.value = JSON.stringify(newValue)
+
+ window.electron.ipcRenderer.send('aiChangeEvent', {
+ aiChange: newValue
})
}
const getInitialValue = () => {
- const savedValue = localStorage.getItem('newValue');
+ const savedValue = localStorage.getItem('newValue')
// 如果 localStorage 没有值,可以设置默认行为(例如默认 false)
- return savedValue !== null ? !JSON.parse(savedValue) : true;
-};
-const aiChangeIsActive = ref(getInitialValue());
+ return savedValue !== null ? !JSON.parse(savedValue) : true
+}
+const aiChangeIsActive = ref(getInitialValue())
const previewFile = (filePath: string) => {
windowPresenter.previewFile(filePath)
@@ -1043,10 +1046,10 @@ onMounted(() => {
statusInterval = window.setInterval(loadRateLimitStatus, 1000)
- window.electron.ipcRenderer.send('aiChangeEvent',{
- aiChange:false
+ window.electron.ipcRenderer.send('aiChangeEvent', {
+ aiChange: false
})
- localStorage.setItem("aiChange", 'false');
+ aiChangeState.value = 'false'
aiChangeIsActive.value = true
})
diff --git a/src/renderer/src/stores/mcp.ts b/src/renderer/src/stores/mcp.ts
index 0a481be5c..64e69d1af 100644
--- a/src/renderer/src/stores/mcp.ts
+++ b/src/renderer/src/stores/mcp.ts
@@ -500,12 +500,12 @@ export const useMcpStore = defineStore('mcp', () => {
(_event, result: MCPToolCallResult) => {
console.log(`MCP tool call result:`, result)
- if (result && result.function_name) {
- toolResults.value[result.function_name] = result.content
- const currentValue = localStorage.getItem('aiChange') as string
- result.directReturn = JSON.parse(currentValue)
- console.log('MCP AIChange', result.directReturn)
- }
+ // if (result && result.function_name) {
+ // toolResults.value[result.function_name] = result.content
+ // const currentValue = localStorage.getItem('aiChange') as string
+ // result.directReturn = JSON.parse(currentValue)
+ // console.log('MCP AIChange', result.directReturn)
+ // }
}
)
}
From 6dd8883e38afecda879d8c26ee861118617db9b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=9B=AA=E5=B3=B0?= <2235113304@qq.com>
Date: Fri, 15 Aug 2025 14:17:16 +0800
Subject: [PATCH 4/8] =?UTF-8?q?=E9=80=82=E9=85=8DTS=E8=A7=84=E8=8C=83?=
=?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E6=98=AF=E5=90=A6=E4=BA=8C=E6=AC=A1?=
=?UTF-8?q?=E6=8A=95=E5=96=82=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BF=AE=E6=94=B9?=
=?UTF-8?q?=E7=94=9F=E5=91=BD=E5=91=A8=E6=9C=9F=E5=88=9D=E5=A7=8B=E5=8C=96?=
=?UTF-8?q?=E4=B8=AD=E7=8A=B6=E6=80=81=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../presenter/llmProviderPresenter/index.ts | 4 +-
.../presenter/mcpPresenter/toolManager.ts | 2 +-
src/renderer/src/components/ChatInput.vue | 40 ++++++++++++-------
.../message/MessageBlockToolCall.vue | 33 ++++++++-------
src/shared/presenter.d.ts | 4 +-
5 files changed, 48 insertions(+), 35 deletions(-)
diff --git a/src/main/presenter/llmProviderPresenter/index.ts b/src/main/presenter/llmProviderPresenter/index.ts
index cf1dce98d..f9fc8b0fa 100644
--- a/src/main/presenter/llmProviderPresenter/index.ts
+++ b/src/main/presenter/llmProviderPresenter/index.ts
@@ -963,7 +963,7 @@ export class LLMProviderPresenter implements ILlmProviderPresenter {
// 发送结束事件
yield {
type: 'end',
- data: { eventId }
+ data: { eventId, userStop: false }
}
return // 结束代理循环
}
@@ -1038,7 +1038,7 @@ export class LLMProviderPresenter implements ILlmProviderPresenter {
// 发送结束事件
yield {
type: 'end',
- data: { eventId }
+ data: { eventId, userStop: false }
}
return // 结束代理循环
}
diff --git a/src/main/presenter/mcpPresenter/toolManager.ts b/src/main/presenter/mcpPresenter/toolManager.ts
index 612df89b9..d56c6d47d 100644
--- a/src/main/presenter/mcpPresenter/toolManager.ts
+++ b/src/main/presenter/mcpPresenter/toolManager.ts
@@ -18,7 +18,7 @@ import { ipcMain } from 'electron'
// const aiStore = useAiStore();
// console.log("MCPToolResponse123",response)
let aiChange = false
-ipcMain.on('aiChangeEvent', (event, arg) => {
+ipcMain.on('aiChangeEvent', (_event, arg) => {
console.log('收到渲染进程消息aiChangeEvent:', arg)
// 处理逻辑...
aiChange = arg
diff --git a/src/renderer/src/components/ChatInput.vue b/src/renderer/src/components/ChatInput.vue
index 446e70f91..aeacd55cb 100644
--- a/src/renderer/src/components/ChatInput.vue
+++ b/src/renderer/src/components/ChatInput.vue
@@ -64,7 +64,7 @@
{{ t('chat.input.fileSelect') }}
-
+