Merge branch 'main' into fix/next-release-bugs

This commit is contained in:
kangfenmao 2025-05-10 09:54:38 +08:00
commit 42733d0fc8
10 changed files with 116 additions and 9 deletions

View File

@ -9,12 +9,29 @@ class ContextMenu {
const template: MenuItemConstructorOptions[] = this.createEditMenuItems(properties) const template: MenuItemConstructorOptions[] = this.createEditMenuItems(properties)
const filtered = template.filter((item) => item.visible !== false) const filtered = template.filter((item) => item.visible !== false)
if (filtered.length > 0) { if (filtered.length > 0) {
const menu = Menu.buildFromTemplate(filtered) const menu = Menu.buildFromTemplate([...filtered, ...this.createInspectMenuItems(w)])
menu.popup() menu.popup()
} }
}) })
} }
private createInspectMenuItems(w: Electron.BrowserWindow): MenuItemConstructorOptions[] {
const locale = locales[configManager.getLanguage()]
const { common } = locale.translation
const template: MenuItemConstructorOptions[] = [
{
id: 'inspect',
label: common.inspect,
click: () => {
w.webContents.toggleDevTools()
},
enabled: true
}
]
return template
}
private createEditMenuItems(properties: Electron.ContextMenuParams): MenuItemConstructorOptions[] { private createEditMenuItems(properties: Electron.ContextMenuParams): MenuItemConstructorOptions[] {
const locale = locales[configManager.getLanguage()] const locale = locales[configManager.getLanguage()]
const { common } = locale.translation const { common } = locale.translation

View File

@ -304,6 +304,7 @@
"confirm": "Confirm", "confirm": "Confirm",
"copied": "Copied", "copied": "Copied",
"copy": "Copy", "copy": "Copy",
"inspect": "Inspect",
"cut": "Cut", "cut": "Cut",
"default": "Default", "default": "Default",
"delete": "Delete", "delete": "Delete",

View File

@ -304,6 +304,7 @@
"confirm": "確認", "confirm": "確認",
"copied": "コピーされました", "copied": "コピーされました",
"copy": "コピー", "copy": "コピー",
"inspect": "検査",
"cut": "切り取り", "cut": "切り取り",
"default": "デフォルト", "default": "デフォルト",
"delete": "削除", "delete": "削除",

View File

@ -304,6 +304,7 @@
"confirm": "Подтверждение", "confirm": "Подтверждение",
"copied": "Скопировано", "copied": "Скопировано",
"copy": "Копировать", "copy": "Копировать",
"inspect": "Осмотреть",
"cut": "Вырезать", "cut": "Вырезать",
"default": "По умолчанию", "default": "По умолчанию",
"delete": "Удалить", "delete": "Удалить",

View File

@ -304,6 +304,7 @@
"confirm": "确认", "confirm": "确认",
"copied": "已复制", "copied": "已复制",
"copy": "复制", "copy": "复制",
"inspect": "检查",
"cut": "剪切", "cut": "剪切",
"default": "默认", "default": "默认",
"delete": "删除", "delete": "删除",

View File

@ -304,6 +304,7 @@
"confirm": "確認", "confirm": "確認",
"copied": "已複製", "copied": "已複製",
"copy": "複製", "copy": "複製",
"inspect": "檢查",
"cut": "剪下", "cut": "剪下",
"default": "預設", "default": "預設",
"delete": "刪除", "delete": "刪除",

View File

@ -6,7 +6,11 @@ import {
MdiLightbulbOn90 MdiLightbulbOn90
} from '@renderer/components/Icons/SVGIcon' } from '@renderer/components/Icons/SVGIcon'
import { useQuickPanel } from '@renderer/components/QuickPanel' import { useQuickPanel } from '@renderer/components/QuickPanel'
import { isSupportedReasoningEffortGrokModel, isSupportedThinkingTokenGeminiModel } from '@renderer/config/models' import {
isSupportedReasoningEffortGrokModel,
isSupportedThinkingTokenGeminiModel,
isSupportedThinkingTokenQwenModel
} from '@renderer/config/models'
import { useAssistant } from '@renderer/hooks/useAssistant' import { useAssistant } from '@renderer/hooks/useAssistant'
import { Assistant, Model, ReasoningEffortOptions } from '@renderer/types' import { Assistant, Model, ReasoningEffortOptions } from '@renderer/types'
import { Tooltip } from 'antd' import { Tooltip } from 'antd'
@ -30,7 +34,8 @@ interface Props {
const MODEL_SUPPORTED_OPTIONS: Record<string, ThinkingOption[]> = { const MODEL_SUPPORTED_OPTIONS: Record<string, ThinkingOption[]> = {
default: ['off', 'low', 'medium', 'high'], default: ['off', 'low', 'medium', 'high'],
grok: ['off', 'low', 'high'], grok: ['off', 'low', 'high'],
gemini: ['off', 'low', 'medium', 'high', 'auto'] gemini: ['off', 'low', 'medium', 'high', 'auto'],
qwen: ['off', 'low', 'medium', 'high', 'auto']
} }
// 选项转换映射表:当选项不支持时使用的替代选项 // 选项转换映射表:当选项不支持时使用的替代选项
@ -49,6 +54,7 @@ const ThinkingButton: FC<Props> = ({ ref, model, assistant, ToolbarButton }): Re
const isGrokModel = isSupportedReasoningEffortGrokModel(model) const isGrokModel = isSupportedReasoningEffortGrokModel(model)
const isGeminiModel = isSupportedThinkingTokenGeminiModel(model) const isGeminiModel = isSupportedThinkingTokenGeminiModel(model)
const isQwenModel = isSupportedThinkingTokenQwenModel(model)
const currentReasoningEffort = useMemo(() => { const currentReasoningEffort = useMemo(() => {
return assistant.settings?.reasoning_effort || 'off' return assistant.settings?.reasoning_effort || 'off'
@ -58,8 +64,9 @@ const ThinkingButton: FC<Props> = ({ ref, model, assistant, ToolbarButton }): Re
const modelType = useMemo(() => { const modelType = useMemo(() => {
if (isGeminiModel) return 'gemini' if (isGeminiModel) return 'gemini'
if (isGrokModel) return 'grok' if (isGrokModel) return 'grok'
if (isQwenModel) return 'qwen'
return 'default' return 'default'
}, [isGeminiModel, isGrokModel]) }, [isGeminiModel, isGrokModel, isQwenModel])
// 获取当前模型支持的选项 // 获取当前模型支持的选项
const supportedOptions = useMemo(() => { const supportedOptions = useMemo(() => {
@ -73,7 +80,8 @@ const ThinkingButton: FC<Props> = ({ ref, model, assistant, ToolbarButton }): Re
const fallbackOption = OPTION_FALLBACK[currentReasoningEffort as ThinkingOption] const fallbackOption = OPTION_FALLBACK[currentReasoningEffort as ThinkingOption]
updateAssistantSettings({ updateAssistantSettings({
reasoning_effort: fallbackOption === 'off' ? undefined : fallbackOption reasoning_effort: fallbackOption === 'off' ? undefined : fallbackOption,
qwenThinkMode: fallbackOption === 'off'
}) })
} }
}, [currentReasoningEffort, supportedOptions, updateAssistantSettings, model.id]) }, [currentReasoningEffort, supportedOptions, updateAssistantSettings, model.id])
@ -103,12 +111,14 @@ const ThinkingButton: FC<Props> = ({ ref, model, assistant, ToolbarButton }): Re
// 然后更新设置 // 然后更新设置
if (!isEnabled) { if (!isEnabled) {
updateAssistantSettings({ updateAssistantSettings({
reasoning_effort: undefined reasoning_effort: undefined,
qwenThinkMode: false
}) })
return return
} }
updateAssistantSettings({ updateAssistantSettings({
reasoning_effort: option reasoning_effort: option,
qwenThinkMode: true
}) })
return return
}, },

View File

@ -25,7 +25,7 @@ import {
filterEmptyMessages, filterEmptyMessages,
filterUserRoleStartMessages filterUserRoleStartMessages
} from '@renderer/services/MessagesService' } from '@renderer/services/MessagesService'
import { processReqMessages } from '@renderer/services/ModelMessageService' import { processPostsuffixQwen3Model, processReqMessages } from '@renderer/services/ModelMessageService'
import store from '@renderer/store' import store from '@renderer/store'
import { import {
Assistant, Assistant,
@ -401,6 +401,20 @@ export default class OpenAICompatibleProvider extends BaseOpenAiProvider {
const { signal } = abortController const { signal } = abortController
await this.checkIsCopilot() await this.checkIsCopilot()
const lastUserMsg = userMessages.findLast((m) => m.role === 'user')
if (lastUserMsg) {
const postsuffix = '/no_think'
// qwenThinkMode === true 表示思考模式啓用,此時不應添加 /no_think如果存在則移除
const qwenThinkModeEnabled = assistant.settings?.qwenThinkMode === true
const currentContent = lastUserMsg.content // content 類型string | ChatCompletionContentPart[] | null
lastUserMsg.content = processPostsuffixQwen3Model(
currentContent,
postsuffix,
qwenThinkModeEnabled
) as ChatCompletionContentPart[]
}
//当 systemMessage 内容为空时不发送 systemMessage //当 systemMessage 内容为空时不发送 systemMessage
let reqMessages: ChatCompletionMessageParam[] let reqMessages: ChatCompletionMessageParam[]
if (!systemMessage.content) { if (!systemMessage.content) {

View File

@ -1,5 +1,5 @@
import { Model } from '@renderer/types' import { Model } from '@renderer/types'
import { ChatCompletionMessageParam } from 'openai/resources' import { ChatCompletionContentPart, ChatCompletionContentPartText, ChatCompletionMessageParam } from 'openai/resources'
export function processReqMessages( export function processReqMessages(
model: Model, model: Model,
@ -40,3 +40,63 @@ function interleaveUserAndAssistantMessages(messages: ChatCompletionMessageParam
return processedMessages return processedMessages
} }
// Process postsuffix for Qwen3 model
export function processPostsuffixQwen3Model(
// content 類型string | ChatCompletionContentPart[] | null
content: string | ChatCompletionContentPart[] | null,
postsuffix: string,
qwenThinkModeEnabled: boolean
): string | ChatCompletionContentPart[] | null {
if (typeof content === 'string') {
if (qwenThinkModeEnabled) {
// 思考模式启用,移除 postsuffix
if (content.endsWith(postsuffix)) {
return content.substring(0, content.length - postsuffix.length).trimEnd()
}
} else {
// 思考模式未启用,添加 postsuffix
if (!content.endsWith(postsuffix)) {
return content + postsuffix
}
}
} else if (Array.isArray(content)) {
let lastTextPartIndex = -1
for (let i = content.length - 1; i >= 0; i--) {
if (content[i].type === 'text') {
lastTextPartIndex = i
break
}
}
if (lastTextPartIndex !== -1) {
const textPart = content[lastTextPartIndex] as ChatCompletionContentPartText
if (qwenThinkModeEnabled) {
// 思考模式启用,移除 postsuffix
if (textPart.text.endsWith(postsuffix)) {
textPart.text = textPart.text.substring(0, textPart.text.length - postsuffix.length).trimEnd()
// 可選:如果 textPart.text 變為空,可以考慮是否移除該 part
}
} else {
// 思考模式未启用,添加 postsuffix
if (!textPart.text.endsWith(postsuffix)) {
textPart.text += postsuffix
}
}
} else {
// 數組中沒有文本部分
if (!qwenThinkModeEnabled) {
// 思考模式未啓用,需要添加 postsuffix
// 如果沒有文本部分,則添加一個新的文本部分
content.push({ type: 'text', text: postsuffix })
}
}
} else {
// currentContent 是 null
if (!qwenThinkModeEnabled) {
// 思考模式未启用,需要添加 postsuffix
return content
}
}
return content
}

View File

@ -60,6 +60,7 @@ export type AssistantSettings = {
defaultModel?: Model defaultModel?: Model
customParameters?: AssistantSettingCustomParameters[] customParameters?: AssistantSettingCustomParameters[]
reasoning_effort?: ReasoningEffortOptions reasoning_effort?: ReasoningEffortOptions
qwenThinkMode?: boolean
} }
export type Agent = Omit<Assistant, 'model'> & { export type Agent = Omit<Assistant, 'model'> & {