agent-Specialization/static/src/app/methods/ui/route.ts

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;
}
};