fix(chat): keep route agent for conversation deep links

This commit is contained in:
matevip 2026-08-13 03:20:39 -04:00
parent b8a8aac7f9
commit 49d31d0847
3 changed files with 42 additions and 5 deletions

View File

@ -23,3 +23,14 @@ export function resolveRouteHydrationQuery(options: {
return { agentId, conversationId }
}
export function resolveConversationAgentSelection(options: {
routeAgentId?: string
conversationAgentId?: IdLike | null
currentAgentId?: IdLike | null
}): string {
if (options.routeAgentId) return options.routeAgentId
if (options.conversationAgentId != null) return String(options.conversationAgentId)
if (options.currentAgentId != null) return String(options.currentAgentId)
return ''
}

View File

@ -291,7 +291,7 @@ import { useChat } from '@/composables/chat/useChat'
import RunOverviewPanel from '@/components/chat/RunOverviewPanel.vue'
import { reconstructErrorInfo } from '@/types/chatError'
import { reconcileMessages, extractMessages } from '@/utils/messageReconcile'
import { resolveRouteHydrationQuery } from '@/utils/chatRouteHydration'
import { resolveConversationAgentSelection, resolveRouteHydrationQuery } from '@/utils/chatRouteHydration'
import type { Conversation, Agent, ModelConfig, ProviderInfo, ActiveModelsInfo, ChatAttachment, MessageContentPart, Message, ToolCallMeta } from '@/types'
//
@ -1632,7 +1632,7 @@ async function hydrateStateFromRoute() {
if (conversationId && conversationId !== currentConversationId.value) {
const matchedConversation = conversations.value.find(conv => conv.conversationId === conversationId)
if (matchedConversation) {
await selectConversation(matchedConversation)
await selectConversation(matchedConversation, agentId)
} else {
// Sessions
currentConversationId.value = conversationId
@ -1669,7 +1669,7 @@ function syncRouteState() {
router.replace({ path: '/chat', query })
}
async function selectConversation(conv: Conversation) {
async function selectConversation(conv: Conversation, routeAgentId = '') {
if (isMobile.value) convPanelOpen.value = false
// UI/SSEresetForNewConversation stream.disconnect +
// POST /chat/{A}/stop A agent run
@ -1682,7 +1682,11 @@ async function selectConversation(conv: Conversation) {
messageListRef.value?.resetScrollLock()
}
currentConversationId.value = conv.conversationId
selectedAgentId.value = conv.agentId || selectedAgentId.value
selectedAgentId.value = resolveConversationAgentSelection({
routeAgentId,
conversationAgentId: conv.agentId,
currentAgentId: selectedAgentId.value,
})
// Opening another conversation: its pin (or the agent/global fallback) is
// authoritative, so clear the previous conversation's manual-pick guard.
userPickedModel.value = false

View File

@ -1,6 +1,6 @@
// @vitest-environment happy-dom
import { describe, expect, it } from 'vitest'
import { resolveRouteHydrationQuery } from '@/utils/chatRouteHydration'
import { resolveConversationAgentSelection, resolveRouteHydrationQuery } from '@/utils/chatRouteHydration'
const agents = [{ id: 'agent-visible' }]
const conversations = [{ conversationId: 'conv-listed' }]
@ -34,3 +34,25 @@ describe('resolveRouteHydrationQuery', () => {
})
})
})
describe('resolveConversationAgentSelection', () => {
it('keeps a valid route agent when opening an existing conversation with stale metadata', () => {
const selected = resolveConversationAgentSelection({
routeAgentId: '20798621241343139868',
conversationAgentId: '2079862124313986',
currentAgentId: '',
})
expect(selected).toBe('20798621241343139868')
})
it('uses the conversation agent when no route agent is provided', () => {
const selected = resolveConversationAgentSelection({
routeAgentId: '',
conversationAgentId: '2079862124313986',
currentAgentId: 'fallback',
})
expect(selected).toBe('2079862124313986')
})
})