194 lines
7.9 KiB
TypeScript
194 lines
7.9 KiB
TypeScript
// @ts-nocheck
|
|
import { debugLog } from '../common';
|
|
import { usePolicyStore } from '../../../stores/policy';
|
|
import { useModelStore } from '../../../stores/model';
|
|
import { usePersonalizationStore } from '../../../stores/personalization';
|
|
import { useTutorialStore } from '../../../stores/tutorial';
|
|
import { renderMarkdown as renderMarkdownHelper } from '../../../composables/useMarkdownRenderer';
|
|
import { scrollToBottom as scrollToBottomHelper, conditionalScrollToBottom as conditionalScrollToBottomHelper, scrollThinkingToBottom as scrollThinkingToBottomHelper } from '../../../composables/useScrollControl';
|
|
import { startResize as startPanelResize, handleResize as handlePanelResize, stopResize as stopPanelResize } from '../../../composables/usePanelResize';
|
|
import {
|
|
SUB_AGENT_DONE_PREFIX_RE,
|
|
BG_RUN_COMMAND_DONE_PREFIX_RE,
|
|
userMDebug,
|
|
UI_BOUNCE_TRACE_MAX,
|
|
uiBounceTraceLastTsByKey,
|
|
isUiBounceTraceEnabled,
|
|
uiBounceTrace,
|
|
isConnectionDiagEnabled,
|
|
pushConnectionDiagRecord,
|
|
connectionDiag,
|
|
parseSubAgentDoneLabel,
|
|
parseBackgroundRunCommandDoneLabel,
|
|
parseSystemNoticeLabel,
|
|
} from './shared';
|
|
|
|
export const routeMethods = {
|
|
async bootstrapRoute() {
|
|
// 在路由解析期间抑制标题动画,避免预置"新对话"闪烁
|
|
this.suppressTitleTyping = true;
|
|
this.titleReady = false;
|
|
this.currentConversationTitle = '';
|
|
this.titleTypingText = '';
|
|
const path = window.location.pathname.replace(/^\/+/, '');
|
|
// 检查多智能体模式入口
|
|
if (path === 'multiagent/new' || path === 'multiagent') {
|
|
this.multiAgentMode = true;
|
|
this.currentConversationId = null;
|
|
this.currentConversationTitle = '多智能体模式';
|
|
this.logMessageState('bootstrapRoute:clear-messages-for-multiagent-new');
|
|
this.messages = [];
|
|
this.titleReady = true;
|
|
this.suppressTitleTyping = false;
|
|
this.startTitleTyping('多智能体模式', { animate: false });
|
|
this.initialRouteResolved = true;
|
|
this.refreshBlankHeroState();
|
|
// 进入多智能体模式时触发后端重建索引以补全 multi_agent_mode 字段
|
|
try {
|
|
await fetch('/api/multiagent/rebuild-index', { method: 'POST' });
|
|
} catch (_e) {
|
|
// 重建失败不阻断主流程
|
|
}
|
|
await this.restoreComposerDraftState('bootstrap-route:multiagent');
|
|
return;
|
|
}
|
|
// 当 URL 是 /multiagent/conv_xxx 时也走多智能体模式
|
|
if (path.startsWith('multiagent/')) {
|
|
this.multiAgentMode = true;
|
|
const convPart = path.slice('multiagent/'.length);
|
|
const convId = convPart.startsWith('conv_') ? convPart : `conv_${convPart}`;
|
|
try {
|
|
const resp = await fetch(`/api/conversations/${convId}/load`, { method: 'PUT' });
|
|
const result = await resp.json();
|
|
if (result.success) {
|
|
if (typeof result.run_mode === 'string') {
|
|
this.runMode = result.run_mode;
|
|
this.thinkingMode = typeof result.thinking_mode === 'boolean' ? result.thinking_mode : result.run_mode !== 'fast';
|
|
} else if (typeof result.thinking_mode === 'boolean') {
|
|
this.thinkingMode = result.thinking_mode;
|
|
this.runMode = result.thinking_mode ? 'thinking' : 'fast';
|
|
}
|
|
if (typeof result.model_key === 'string' && result.model_key) this.modelSet(result.model_key);
|
|
this.currentConversationId = convId;
|
|
this.currentConversationTitle = result.title || '多智能体模式';
|
|
this.titleReady = true;
|
|
this.suppressTitleTyping = false;
|
|
this.startTitleTyping(this.currentConversationTitle, { animate: false });
|
|
history.replaceState({ conversationId: convId }, '', `/multiagent/${this.stripConversationPrefix(convId)}`);
|
|
this.initialRouteResolved = true;
|
|
await this.restoreComposerDraftState('bootstrap-route:multiagent-existing');
|
|
return;
|
|
}
|
|
} catch (error) {
|
|
console.warn('[multiagent] 加载多智能体对话失败:', error);
|
|
}
|
|
// 加载失败回退到 multiagent/new 路径
|
|
history.replaceState({}, '', '/multiagent/new');
|
|
window.location.reload();
|
|
return;
|
|
}
|
|
// 非多智能体模式:清除标志
|
|
this.multiAgentMode = false;
|
|
if (!path || this.isExplicitNewConversationRoute()) {
|
|
this.currentConversationId = null;
|
|
this.currentConversationTitle = '新对话';
|
|
this.logMessageState('bootstrapRoute:clear-messages-for-new');
|
|
this.messages = [];
|
|
this.titleReady = true;
|
|
this.suppressTitleTyping = false;
|
|
this.startTitleTyping('新对话', { animate: false });
|
|
this.initialRouteResolved = true;
|
|
this.refreshBlankHeroState();
|
|
await this.restoreComposerDraftState('bootstrap-route:new');
|
|
return;
|
|
}
|
|
|
|
const convId = path.startsWith('conv_') ? path : `conv_${path}`;
|
|
try {
|
|
const resp = await fetch(`/api/conversations/${convId}/load`, { method: 'PUT' });
|
|
const result = await resp.json();
|
|
if (result.success) {
|
|
if (typeof result.run_mode === 'string') {
|
|
this.runMode = result.run_mode;
|
|
this.thinkingMode =
|
|
typeof result.thinking_mode === 'boolean'
|
|
? result.thinking_mode
|
|
: result.run_mode !== 'fast';
|
|
} else if (typeof result.thinking_mode === 'boolean') {
|
|
this.thinkingMode = result.thinking_mode;
|
|
this.runMode = result.thinking_mode ? 'thinking' : 'fast';
|
|
}
|
|
if (typeof result.model_key === 'string' && result.model_key) {
|
|
this.modelSet(result.model_key);
|
|
}
|
|
this.currentConversationId = convId;
|
|
this.currentConversationTitle = result.title || '';
|
|
this.titleReady = true;
|
|
this.suppressTitleTyping = false;
|
|
this.startTitleTyping(this.currentConversationTitle, { animate: false });
|
|
history.replaceState(
|
|
{ conversationId: convId },
|
|
'',
|
|
`/${this.stripConversationPrefix(convId)}`
|
|
);
|
|
} else {
|
|
history.replaceState({}, '', '/new');
|
|
this.currentConversationId = null;
|
|
this.currentConversationTitle = '新对话';
|
|
this.titleReady = true;
|
|
this.suppressTitleTyping = false;
|
|
this.startTitleTyping('新对话', { animate: false });
|
|
}
|
|
} catch (error) {
|
|
console.warn('初始化路由失败:', error);
|
|
history.replaceState({}, '', '/new');
|
|
this.currentConversationId = null;
|
|
this.currentConversationTitle = '新对话';
|
|
this.titleReady = true;
|
|
this.suppressTitleTyping = false;
|
|
this.startTitleTyping('新对话', { animate: false });
|
|
} finally {
|
|
this.initialRouteResolved = true;
|
|
}
|
|
await this.restoreComposerDraftState('bootstrap-route:conversation');
|
|
},
|
|
handlePopState(event) {
|
|
const state = event.state || {};
|
|
const convId = state.conversationId;
|
|
if (!convId) {
|
|
this.currentConversationId = null;
|
|
this.currentConversationTitle = '新对话';
|
|
this.logMessageState('handlePopState:clear-messages-no-conversation');
|
|
this.messages = [];
|
|
this.logMessageState('handlePopState:after-clear-no-conversation');
|
|
this.resetAllStates('handlePopState:no-conversation');
|
|
this.resetTokenStatistics();
|
|
this.restoreComposerDraftState('popstate:new').catch(() => {});
|
|
return;
|
|
}
|
|
this.loadConversation(convId);
|
|
},
|
|
refreshCurrentPage() {
|
|
if (typeof window === 'undefined') {
|
|
return;
|
|
}
|
|
this.persistComposerDraftNow({
|
|
reason: 'refresh-page',
|
|
force: true,
|
|
keepalive: true
|
|
})
|
|
.catch(() => {})
|
|
.finally(() => {
|
|
window.location.reload();
|
|
});
|
|
},
|
|
isExplicitNewConversationRoute() {
|
|
const normalizedPath = window.location.pathname.replace(/^\/+|\/+$/g, '');
|
|
return normalizedPath === 'new' || normalizedPath === 'multiagent/new' || normalizedPath === 'multiagent';
|
|
},
|
|
stripConversationPrefix(conversationId) {
|
|
if (!conversationId) return '';
|
|
return conversationId.startsWith('conv_') ? conversationId.slice(5) : conversationId;
|
|
}
|
|
};
|