fix: persist search results and speed init
This commit is contained in:
parent
9ae43e89ff
commit
95285747c0
@ -301,17 +301,18 @@ const appOptions = {
|
||||
console.warn('CSRF token 初始化失败:', err);
|
||||
});
|
||||
}
|
||||
await this.bootstrapRoute();
|
||||
await this.initSocket();
|
||||
// 并行启动路由解析与实时连接,避免等待路由加载阻塞思考模式同步
|
||||
const routePromise = this.bootstrapRoute();
|
||||
const socketPromise = this.initSocket();
|
||||
await routePromise;
|
||||
await socketPromise;
|
||||
this.$nextTick(() => {
|
||||
this.ensureScrollListener();
|
||||
});
|
||||
setupShowImageObserver();
|
||||
|
||||
// 延迟加载初始数据
|
||||
setTimeout(() => {
|
||||
this.loadInitialData();
|
||||
}, 500);
|
||||
// 立即加载初始数据(并行获取状态,优先同步运行模式)
|
||||
this.loadInitialData();
|
||||
|
||||
document.addEventListener('click', this.handleClickOutsideQuickMenu);
|
||||
document.addEventListener('click', this.handleClickOutsidePanelMenu);
|
||||
@ -1288,54 +1289,56 @@ const appOptions = {
|
||||
async loadInitialData() {
|
||||
try {
|
||||
debugLog('加载初始数据...');
|
||||
|
||||
await this.fileFetchTree();
|
||||
await this.focusFetchFiles();
|
||||
await this.fileFetchTodoList();
|
||||
|
||||
|
||||
// 并行拉取文件/待办,优先获取状态以尽快同步运行模式
|
||||
const treePromise = this.fileFetchTree();
|
||||
const focusPromise = this.focusFetchFiles();
|
||||
const todoPromise = this.fileFetchTodoList();
|
||||
|
||||
const statusResponse = await fetch('/api/status');
|
||||
const statusData = await statusResponse.json();
|
||||
this.projectPath = statusData.project_path || '';
|
||||
this.agentVersion = statusData.version || this.agentVersion;
|
||||
this.thinkingMode = !!statusData.thinking_mode;
|
||||
this.applyStatusSnapshot(statusData);
|
||||
await this.fetchUsageQuota();
|
||||
|
||||
// 立即更新配额和运行模式,避免等待其他慢接口
|
||||
this.fetchUsageQuota();
|
||||
|
||||
// 获取当前对话信息
|
||||
const statusConversationId = statusData.conversation && statusData.conversation.current_id;
|
||||
if (statusConversationId) {
|
||||
if (!this.currentConversationId) {
|
||||
this.skipConversationHistoryReload = true;
|
||||
// 首次从状态恢复对话时,避免 socket 的 conversation_loaded 再次触发历史加载
|
||||
this.skipConversationLoadedEvent = true;
|
||||
this.currentConversationId = statusConversationId;
|
||||
if (statusConversationId && !this.currentConversationId) {
|
||||
this.skipConversationHistoryReload = true;
|
||||
// 首次从状态恢复对话时,避免 socket 的 conversation_loaded 再次触发历史加载
|
||||
this.skipConversationLoadedEvent = true;
|
||||
this.currentConversationId = statusConversationId;
|
||||
|
||||
// 如果有当前对话,尝试获取标题和历史
|
||||
try {
|
||||
const convResponse = await fetch(`/api/conversations/current`);
|
||||
const convData = await convResponse.json();
|
||||
if (convData.success && convData.data) {
|
||||
this.currentConversationTitle = convData.data.title;
|
||||
}
|
||||
// 初始化时调用一次,因为 skipConversationHistoryReload 会阻止 watch 触发
|
||||
if (
|
||||
this.lastHistoryLoadedConversationId !== this.currentConversationId ||
|
||||
!Array.isArray(this.messages) ||
|
||||
this.messages.length === 0
|
||||
) {
|
||||
await this.fetchAndDisplayHistory();
|
||||
}
|
||||
// 获取当前对话的Token统计
|
||||
this.fetchConversationTokenStatistics();
|
||||
this.updateCurrentContextTokens();
|
||||
} catch (e) {
|
||||
console.warn('获取当前对话标题失败:', e);
|
||||
// 如果有当前对话,尝试获取标题和历史
|
||||
try {
|
||||
const convResponse = await fetch(`/api/conversations/current`);
|
||||
const convData = await convResponse.json();
|
||||
if (convData.success && convData.data) {
|
||||
this.currentConversationTitle = convData.data.title;
|
||||
}
|
||||
// 初始化时调用一次,因为 skipConversationHistoryReload 会阻止 watch 触发
|
||||
if (
|
||||
this.lastHistoryLoadedConversationId !== this.currentConversationId ||
|
||||
!Array.isArray(this.messages) ||
|
||||
this.messages.length === 0
|
||||
) {
|
||||
await this.fetchAndDisplayHistory();
|
||||
}
|
||||
// 获取当前对话的Token统计
|
||||
this.fetchConversationTokenStatistics();
|
||||
this.updateCurrentContextTokens();
|
||||
} catch (e) {
|
||||
console.warn('获取当前对话标题失败:', e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 等待其他加载项完成(允许部分失败不阻塞模式切换)
|
||||
await Promise.allSettled([treePromise, focusPromise, todoPromise]);
|
||||
await this.loadToolSettings(true);
|
||||
|
||||
|
||||
debugLog('初始数据加载完成');
|
||||
} catch (error) {
|
||||
console.error('加载初始数据失败:', error);
|
||||
@ -1835,17 +1838,19 @@ const appOptions = {
|
||||
}
|
||||
|
||||
if (toolAction) {
|
||||
// 解析工具结果
|
||||
// 解析工具结果(优先使用JSON,其次使用元数据的 tool_payload,以保证搜索结果在刷新后仍可展示)
|
||||
let result;
|
||||
try {
|
||||
// 尝试解析为JSON
|
||||
result = JSON.parse(message.content);
|
||||
} catch (e) {
|
||||
// 如果不是JSON,就作为纯文本
|
||||
result = {
|
||||
output: message.content,
|
||||
success: true
|
||||
};
|
||||
if (message.metadata && message.metadata.tool_payload) {
|
||||
result = message.metadata.tool_payload;
|
||||
} else {
|
||||
result = {
|
||||
output: message.content,
|
||||
success: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
toolAction.tool.status = 'completed';
|
||||
|
||||
@ -545,6 +545,38 @@ def format_tool_result_notice(tool_name: str, tool_call_id: Optional[str], conte
|
||||
body = "(无附加输出)"
|
||||
return f"{header}\n{body}"
|
||||
|
||||
|
||||
def compact_web_search_result(result_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""提取 web_search 结果中前端展示所需的关键字段,避免持久化时丢失列表。"""
|
||||
if not isinstance(result_data, dict):
|
||||
return {"success": False, "error": "invalid search result"}
|
||||
|
||||
compact: Dict[str, Any] = {
|
||||
"success": bool(result_data.get("success")),
|
||||
"summary": result_data.get("summary"),
|
||||
"query": result_data.get("query"),
|
||||
"filters": result_data.get("filters") or {},
|
||||
"total_results": result_data.get("total_results", 0)
|
||||
}
|
||||
|
||||
# 仅保留前端需要渲染的字段,避免巨大正文导致历史加载时缺失
|
||||
items: List[Dict[str, Any]] = []
|
||||
for item in result_data.get("results") or []:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
items.append({
|
||||
"index": item.get("index"),
|
||||
"title": item.get("title") or item.get("name"),
|
||||
"url": item.get("url")
|
||||
})
|
||||
|
||||
compact["results"] = items
|
||||
|
||||
if not compact.get("success") and result_data.get("error"):
|
||||
compact["error"] = result_data.get("error")
|
||||
|
||||
return compact
|
||||
|
||||
# 创建调试日志文件
|
||||
DEBUG_LOG_FILE = Path(LOGS_DIR).expanduser().resolve() / "debug_stream.log"
|
||||
CHUNK_BACKEND_LOG_FILE = Path(LOGS_DIR).expanduser().resolve() / "chunk_backend.log"
|
||||
@ -4751,7 +4783,14 @@ async def handle_task_with_sender(terminal: WebTerminal, workspace: UserWorkspac
|
||||
# ===== 增量保存:立即保存工具结果 =====
|
||||
metadata_payload = None
|
||||
if isinstance(result_data, dict):
|
||||
tool_result_content = format_tool_result_for_context(function_name, result_data, tool_result)
|
||||
# 特殊处理 web_search:保留可供前端渲染的精简结构,以便历史记录复现搜索结果
|
||||
if function_name == "web_search":
|
||||
try:
|
||||
tool_result_content = json.dumps(compact_web_search_result(result_data), ensure_ascii=False)
|
||||
except Exception:
|
||||
tool_result_content = tool_result
|
||||
else:
|
||||
tool_result_content = format_tool_result_for_context(function_name, result_data, tool_result)
|
||||
metadata_payload = {"tool_payload": result_data}
|
||||
else:
|
||||
tool_result_content = tool_result
|
||||
|
||||
Loading…
Reference in New Issue
Block a user