Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 102 additions & 68 deletions src/renderer/src/components/NewThread.vue
Original file line number Diff line number Diff line change
Expand Up @@ -201,85 +201,117 @@ watch(
// console.log('maxTokens', maxTokens.value)
}
)
watch(
() => [settingsStore.enabledModels, chatStore.threads],
async () => {
// 如果有现有线程,使用最近线程的模型
if (chatStore.threads.length > 0) {
if (chatStore.threads[0].dtThreads.length > 0) {
const thread = chatStore.threads[0].dtThreads[0]
const modelId = thread.settings.modelId
const providerId = thread.settings.providerId
// 初始化与校验逻辑:只在激活时初始化一次;仅监听 enabledModels 变化做有效性校验
const initialized = ref(false)

// 同时匹配 modelId 和 providerId
if (modelId && providerId) {
for (const provider of settingsStore.enabledModels) {
if (provider.providerId === providerId) {
for (const model of provider.models) {
if (model.id === modelId) {
activeModel.value = {
name: model.name,
id: model.id,
providerId: provider.providerId,
tags: [],
type: model.type ?? ModelType.Chat
}
return
}
}
}
}
const findEnabledModel = (providerId: string, modelId: string) => {
for (const provider of settingsStore.enabledModels) {
if (provider.providerId === providerId) {
for (const model of provider.models) {
if (model.id === modelId) {
return { model, providerId: provider.providerId }
}
}
}
}
return undefined
}

// 如果没有现有线程,尝试使用用户上次选择的模型
try {
const preferredModel = (await configPresenter.getSetting('preferredModel')) as
| PreferredModel
| undefined
if (preferredModel && preferredModel.modelId && preferredModel.providerId) {
// 验证偏好模型是否还在可用模型列表中
for (const provider of settingsStore.enabledModels) {
if (provider.providerId === preferredModel.providerId) {
for (const model of provider.models) {
if (model.id === preferredModel.modelId) {
activeModel.value = {
name: model.name,
id: model.id,
providerId: provider.providerId,
tags: [],
type: model.type ?? ModelType.Chat
}
return
}
}
}
}
const pickFirstEnabledModel = () => {
const found = settingsStore.enabledModels
.flatMap((p) => p.models.map((m) => ({ ...m, providerId: p.providerId })))
.find((m) => m.type === ModelType.Chat || m.type === ModelType.ImageGeneration)
return found
}

const setActiveFromEnabled = (m: {
name: string
id: string
providerId: string
type?: ModelType
}) => {
activeModel.value = {
name: m.name,
id: m.id,
providerId: m.providerId,
tags: [],
type: m.type ?? ModelType.Chat
}
}

const initActiveModel = async () => {
if (initialized.value) return
// 1) 尝试根据最近会话(区分 pinned/非 pinned)选择
if (chatStore.threads.length > 0) {
const pinnedGroup = chatStore.threads.find((g) => g.dt === 'Pinned')
const pinnedFirst = pinnedGroup?.dtThreads?.[0]
const normalGroup = chatStore.threads.find((g) => g.dt !== 'Pinned' && g.dtThreads.length > 0)
const normalFirst = normalGroup?.dtThreads?.[0]
const candidate = [pinnedFirst, normalFirst]
.filter(Boolean)
.sort((a, b) => (b!.updatedAt || 0) - (a!.updatedAt || 0))[0] as
| typeof pinnedFirst
| undefined
if (candidate?.settings?.modelId && candidate?.settings?.providerId) {
const match = findEnabledModel(candidate.settings.providerId, candidate.settings.modelId)
if (match) {
setActiveFromEnabled({ ...match.model, providerId: match.providerId })
initialized.value = true
return
}
} catch (error) {
console.warn('Failed to get user preferred model:', error)
}
}

// 如果没有偏好模型或偏好模型不可用,使用第一个可用模型
if (settingsStore.enabledModels.length > 0) {
const model = settingsStore.enabledModels
.flatMap((provider) =>
provider.models.map((m) => ({ ...m, providerId: provider.providerId }))
)
.find((m) => m.type === ModelType.Chat || m.type === ModelType.ImageGeneration)
if (model) {
activeModel.value = {
name: model.name,
id: model.id,
providerId: model.providerId,
tags: [],
type: model.type ?? ModelType.Chat
}
// 2) 尝试用户上次选择的偏好模型
try {
const preferredModel = (await configPresenter.getSetting('preferredModel')) as
| PreferredModel
| undefined
if (preferredModel?.modelId && preferredModel?.providerId) {
const match = findEnabledModel(preferredModel.providerId, preferredModel.modelId)
if (match) {
setActiveFromEnabled({ ...match.model, providerId: match.providerId })
initialized.value = true
return
}
}
} catch (error) {
console.warn('Failed to get user preferred model:', error)
}

// 3) 选择第一个可用模型
const first = pickFirstEnabledModel()
if (first) {
setActiveFromEnabled(first)
initialized.value = true
}
}

Comment on lines +242 to +289
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Do not overwrite user/deeplink model selection on mount

If a deeplink (or user action) sets the model before mount, await initActiveModel() can still override it because initialized isn’t flipped in handleModelUpdate. Add an early-return in initActiveModel when a valid activeModel already exists, and mark initialized in handleModelUpdate.

Apply this diff:

@@
-const initActiveModel = async () => {
+const initActiveModel = async () => {
   if (initialized.value) return
+  // Respect an already-selected model (e.g., via deeplink or user action)
+  if (activeModel.value?.id && activeModel.value?.providerId) {
+    const exists = findEnabledModel(activeModel.value.providerId, activeModel.value.id)
+    if (exists) {
+      initialized.value = true
+      return
+    }
+  }
@@
 const handleModelUpdate = (model: MODEL_META, providerId: string) => {
   activeModel.value = {
@@
   }
   chatStore.updateChatConfig({
@@
   })
@@
   configPresenter.setSetting('preferredModel', {
@@
   })
+
+  // Prevent init flow from overriding an explicit selection
+  initialized.value = true
@@
 }
@@
 onMounted(async () => {
@@
-  // 组件激活时初始化一次默认模型
+  // Initialize default model once on component activation (if none selected yet)
   await initActiveModel()

Also applies to: 335-355, 426-427

🤖 Prompt for AI Agents
In src/renderer/src/components/NewThread.vue around lines 242-289 (also apply
same change at 335-355 and 426-427), initActiveModel can override a model set
via deeplink/user action because handleModelUpdate never flips initialized; add
an early return at the start of initActiveModel that returns if activeModel is
already set and valid (has providerId and modelId), and update handleModelUpdate
to set initialized.value = true when it applies a user/deeplink model (use the
same validity check) so initActiveModel won't overwrite it on mount.

// 仅监听 enabledModels:
// - 若未初始化,进行一次初始化
// - 若已初始化但当前模型不再可用,则回退到第一个 enabled 模型
watch(
() => settingsStore.enabledModels,
async () => {
if (!initialized.value) {
await initActiveModel()
return
}

// 校验当前模型是否仍可用
const current = activeModel.value
if (!current?.id || !current?.providerId) {
const first = pickFirstEnabledModel()
if (first) setActiveFromEnabled(first)
return
}
const stillExists = !!findEnabledModel(current.providerId, current.id)
if (!stillExists) {
const first = pickFirstEnabledModel()
if (first) setActiveFromEnabled(first)
}
},
{ immediate: true, deep: true }
{ immediate: false, deep: true }
)

const modelSelectOpen = ref(false)
Expand Down Expand Up @@ -391,6 +423,8 @@ onMounted(async () => {
configPresenter.getDefaultSystemPrompt().then((prompt) => {
systemPrompt.value = prompt
})
// 组件激活时初始化一次默认模型
await initActiveModel()
if (groupElement) {
useEventListener(groupElement, 'mouseenter', handleMouseEnter)
useEventListener(groupElement, 'mouseleave', handleMouseLeave)
Expand Down