diff --git a/dashboard/src/components/chat/Chat.vue b/dashboard/src/components/chat/Chat.vue index 71e46e690..2bbd96ba9 100644 --- a/dashboard/src/components/chat/Chat.vue +++ b/dashboard/src/components/chat/Chat.vue @@ -228,6 +228,9 @@ const props = withDefaults(defineProps(), { chatboxMode: false }); +// TODO: Remove debug log +console.warn('[Chat] component loaded', { chatboxMode: props.chatboxMode }); + const router = useRouter(); const route = useRoute(); const { t } = useI18n(); @@ -583,6 +586,11 @@ async function handleSendMessage() { const currentProjectId = selectedProjectId.value; // 保存当前项目ID if (isCreatingNewSession) { + // TODO: Remove debug log + console.warn('[Chat] No active session; calling newSession() before send', { + selectedProjectId: currentProjectId, + currSessionId: currSessionId.value + }); await newSession(); // 如果在项目视图中创建新会话,立即退出项目视图 @@ -675,6 +683,8 @@ watch(sessions, (newSessions) => { }); onMounted(() => { + // TODO: Remove debug log + console.warn('[Chat] mounted'); checkMobile(); window.addEventListener('resize', checkMobile); getSessions(); diff --git a/dashboard/src/components/chat/ConfigSelector.vue b/dashboard/src/components/chat/ConfigSelector.vue index d77e91072..3566b2264 100644 --- a/dashboard/src/components/chat/ConfigSelector.vue +++ b/dashboard/src/components/chat/ConfigSelector.vue @@ -77,6 +77,7 @@ import { computed, onMounted, ref, watch } from 'vue'; import axios from 'axios'; import { useToast } from '@/utils/toast'; import { useModuleI18n } from '@/i18n/composables'; +import { CHAT_SELECTED_CONFIG_STORAGE_KEY } from '@/utils/chatConfigBinding'; interface ConfigInfo { id: string; @@ -88,7 +89,7 @@ interface ConfigChangedPayload { agentRunnerType: string; } -const STORAGE_KEY = 'chat.selectedConfigId'; +const STORAGE_KEY = CHAT_SELECTED_CONFIG_STORAGE_KEY; const props = withDefaults(defineProps<{ sessionId?: string | null; diff --git a/dashboard/src/components/chat/StandaloneChat.vue b/dashboard/src/components/chat/StandaloneChat.vue index 44d3fc594..68fc91a65 100644 --- a/dashboard/src/components/chat/StandaloneChat.vue +++ b/dashboard/src/components/chat/StandaloneChat.vue @@ -70,6 +70,7 @@ import { useMessages } from '@/composables/useMessages'; import { useMediaHandling } from '@/composables/useMediaHandling'; import { useRecording } from '@/composables/useRecording'; import { useToast } from '@/utils/toast'; +import { buildWebchatUmoDetails } from '@/utils/chatConfigBinding'; interface Props { configId?: string | null; @@ -82,6 +83,9 @@ const props = withDefaults(defineProps(), { const { t } = useI18n(); const { error: showError } = useToast(); +// TODO: Remove debug log +console.warn('[StandaloneChat] component loaded', { configId: props.configId }); + // UI 状态 const imagePreviewDialog = ref(false); const previewImageUrl = ref(''); @@ -90,35 +94,11 @@ const previewImageUrl = ref(''); const currSessionId = ref(''); const getCurrentSession = computed(() => null); // 独立测试模式不需要会话信息 -function buildWebchatUmo(sessionId: string): { - umo: string; - username: string | null; - sessionKey: string; - exactUmo: string | null; - wildcardUmo: string; -} { - const platformId = 'webchat'; - const messageType = 'FriendMessage'; - const username = (localStorage.getItem('user') || '').trim(); - const exactSessionKey = username ? `${platformId}!${username}!${sessionId}` : null; - const wildcardSessionKey = `${platformId}!*!${sessionId}`; - const selectedSessionKey = exactSessionKey || wildcardSessionKey; - - const selectedUmo = `${platformId}:${messageType}:${selectedSessionKey}`; - return { - umo: selectedUmo, - username: username || null, - sessionKey: selectedSessionKey, - exactUmo: exactSessionKey ? `${platformId}:${messageType}:${exactSessionKey}` : null, - wildcardUmo: `${platformId}:${messageType}:${wildcardSessionKey}` - }; -} - async function bindConfigToSession(sessionId: string) { const confId = (props.configId || '').trim(); if (!confId || confId === 'default') { // TODO: Remove debug log - console.info('[StandaloneChat] Skip binding config to session', { + console.warn('[StandaloneChat] Skip binding config to session', { sessionId, confId, reason: !confId ? 'empty_configId' : 'default_configId' @@ -126,38 +106,34 @@ async function bindConfigToSession(sessionId: string) { return; } - const umoDetails = buildWebchatUmo(sessionId); + const umoDetails = buildWebchatUmoDetails(sessionId, false); // TODO: Remove debug log - console.info('[StandaloneChat] Binding config to session', { + console.warn('[StandaloneChat] Binding config to session', { sessionId, confId, localStorageUser: localStorage.getItem('user'), - selectedUmo: umoDetails.umo, - exactUmo: umoDetails.exactUmo, - wildcardUmo: umoDetails.wildcardUmo + umo: umoDetails.umo, + username: umoDetails.username, + sessionKey: umoDetails.sessionKey }); - const updatePayload = { + const payload = { + umo: umoDetails.umo, conf_id: confId }; - const targetUmos = [umoDetails.exactUmo, umoDetails.wildcardUmo].filter(Boolean) as string[]; - for (const umo of targetUmos) { - const payload = { ...updatePayload, umo }; + // TODO: Remove debug log + console.warn('[StandaloneChat] POST /api/config/umo_abconf_route/update', payload); - // TODO: Remove debug log - console.info('[StandaloneChat] POST /api/config/umo_abconf_route/update', payload); + const updateRes = await axios.post('/api/config/umo_abconf_route/update', payload); - const updateRes = await axios.post('/api/config/umo_abconf_route/update', payload); - - // TODO: Remove debug log - console.info('[StandaloneChat] Route update response', { - umo, - status: updateRes.status, - data: updateRes.data - }); - } + // TODO: Remove debug log + console.warn('[StandaloneChat] Route update response', { + umo: payload.umo, + status: updateRes.status, + data: updateRes.data + }); try { const routesRes = await axios.get('/api/config/umo_abconf_routes'); @@ -168,7 +144,7 @@ async function bindConfigToSession(sessionId: string) { .map(([umo, id]) => ({ umo, confId: id })); // TODO: Remove debug log - console.info('[StandaloneChat] Routing table after update', { + console.warn('[StandaloneChat] Routing table after update', { totalEntries: Object.keys(routing).length, selectedUmo: umoDetails.umo, boundConfId, @@ -188,13 +164,13 @@ async function bindConfigToSession(sessionId: string) { async function newSession() { try { // TODO: Remove debug log - console.info('[StandaloneChat] Creating new session', { configId: props.configId }); + console.warn('[StandaloneChat] Creating new session', { configId: props.configId }); const response = await axios.get('/api/chat/new_session'); const sessionId = response.data.data.session_id; // TODO: Remove debug log - console.info('[StandaloneChat] New session created', { + console.warn('[StandaloneChat] New session created', { sessionId, platformId: response.data.data.platform_id }); @@ -217,7 +193,7 @@ async function newSession() { currSessionId.value = sessionId; // TODO: Remove debug log - console.info('[StandaloneChat] Session activated in UI', { sessionId }); + console.warn('[StandaloneChat] Session activated in UI', { sessionId }); return sessionId; } catch (err) { @@ -338,6 +314,8 @@ async function handleSendMessage() { } onMounted(async () => { + // TODO: Remove debug log + console.warn('[StandaloneChat] mounted'); // 独立模式在挂载时创建新会话 try { await newSession(); diff --git a/dashboard/src/composables/useSessions.ts b/dashboard/src/composables/useSessions.ts index 1cbe6284d..33e22b3fc 100644 --- a/dashboard/src/composables/useSessions.ts +++ b/dashboard/src/composables/useSessions.ts @@ -1,6 +1,7 @@ import { ref, computed } from 'vue'; import axios from 'axios'; import { useRouter } from 'vue-router'; +import { buildWebchatUmoDetails, getStoredSelectedChatConfigId } from '@/utils/chatConfigBinding'; export interface Session { session_id: string; @@ -19,6 +20,9 @@ export function useSessions(chatboxMode: boolean = false) { const currSessionId = ref(''); const pendingSessionId = ref(null); + // TODO: Remove debug log + console.warn('[useSessions] composable initialized', { chatboxMode }); + // 编辑标题相关 const editTitleDialog = ref(false); const editingTitle = ref(''); @@ -62,10 +66,81 @@ export function useSessions(chatboxMode: boolean = false) { async function newSession() { try { + // TODO: Remove debug log + console.warn('[useSessions] newSession() entered', { chatboxMode }); + + const selectedConfigId = getStoredSelectedChatConfigId(); + // TODO: Remove debug log + console.warn('[useSessions] Stored chat selected config', { selectedConfigId }); const response = await axios.get('/api/chat/new_session'); const sessionId = response.data.data.session_id; + const platformId = response.data.data.platform_id; + + // TODO: Remove debug log + console.warn('[useSessions] New session created', { sessionId, platformId }); currSessionId.value = sessionId; + if (selectedConfigId && selectedConfigId !== 'default' && platformId === 'webchat') { + const umoDetails = buildWebchatUmoDetails(sessionId, false); + + // TODO: Remove debug log + console.warn('[useSessions] Binding config to new session', { + sessionId, + selectedConfigId, + umo: umoDetails.umo, + username: umoDetails.username + }); + + try { + const updateRes = await axios.post('/api/config/umo_abconf_route/update', { + umo: umoDetails.umo, + conf_id: selectedConfigId + }); + + // TODO: Remove debug log + console.warn('[useSessions] Route update response', { + status: updateRes.status, + data: updateRes.data + }); + + try { + const routesRes = await axios.get('/api/config/umo_abconf_routes'); + const routing = routesRes.data?.data?.routing || {}; + // TODO: Remove debug log + console.warn('[useSessions] Routing table check', { + umo: umoDetails.umo, + boundConfId: routing[umoDetails.umo], + totalEntries: Object.keys(routing).length + }); + } catch (err) { + const axiosErr = err as any; + // TODO: Remove debug log + console.warn('[useSessions] Failed to fetch routing table after update', { + message: axiosErr?.message, + status: axiosErr?.response?.status, + data: axiosErr?.response?.data + }); + } + } catch (err) { + const axiosErr = err as any; + // TODO: Remove debug log + console.error('[useSessions] Failed to bind config to session', { + sessionId, + selectedConfigId, + message: axiosErr?.message, + status: axiosErr?.response?.status, + data: axiosErr?.response?.data + }); + } + } else { + // TODO: Remove debug log + console.warn('[useSessions] Skip binding config to new session', { + sessionId, + selectedConfigId, + platformId + }); + } + // 更新 URL const basePath = chatboxMode ? '/chatbox' : '/chat'; router.push(`${basePath}/${sessionId}`); diff --git a/dashboard/src/utils/chatConfigBinding.ts b/dashboard/src/utils/chatConfigBinding.ts new file mode 100644 index 000000000..8a5b009bd --- /dev/null +++ b/dashboard/src/utils/chatConfigBinding.ts @@ -0,0 +1,34 @@ +export const CHAT_SELECTED_CONFIG_STORAGE_KEY = 'chat.selectedConfigId'; + +export type ChatMessageType = 'FriendMessage' | 'GroupMessage'; + +export interface WebchatUmoDetails { + platformId: string; + messageType: ChatMessageType; + username: string; + sessionKey: string; + umo: string; +} + +export function getStoredDashboardUsername(): string { + return (localStorage.getItem('user') || '').trim() || 'guest'; +} + +export function getStoredSelectedChatConfigId(): string { + return (localStorage.getItem(CHAT_SELECTED_CONFIG_STORAGE_KEY) || '').trim() || 'default'; +} + +export function buildWebchatUmoDetails(sessionId: string, isGroup = false): WebchatUmoDetails { + const platformId = 'webchat'; + const username = getStoredDashboardUsername(); + const messageType: ChatMessageType = isGroup ? 'GroupMessage' : 'FriendMessage'; + const sessionKey = `${platformId}!${username}!${sessionId}`; + return { + platformId, + messageType, + username, + sessionKey, + umo: `${platformId}:${messageType}:${sessionKey}` + }; +} +