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);
|
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.$nextTick(() => {
|
||||||
this.ensureScrollListener();
|
this.ensureScrollListener();
|
||||||
});
|
});
|
||||||
setupShowImageObserver();
|
setupShowImageObserver();
|
||||||
|
|
||||||
// 延迟加载初始数据
|
// 立即加载初始数据(并行获取状态,优先同步运行模式)
|
||||||
setTimeout(() => {
|
this.loadInitialData();
|
||||||
this.loadInitialData();
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
document.addEventListener('click', this.handleClickOutsideQuickMenu);
|
document.addEventListener('click', this.handleClickOutsideQuickMenu);
|
||||||
document.addEventListener('click', this.handleClickOutsidePanelMenu);
|
document.addEventListener('click', this.handleClickOutsidePanelMenu);
|
||||||
@ -1288,54 +1289,56 @@ const appOptions = {
|
|||||||
async loadInitialData() {
|
async loadInitialData() {
|
||||||
try {
|
try {
|
||||||
debugLog('加载初始数据...');
|
debugLog('加载初始数据...');
|
||||||
|
|
||||||
await this.fileFetchTree();
|
// 并行拉取文件/待办,优先获取状态以尽快同步运行模式
|
||||||
await this.focusFetchFiles();
|
const treePromise = this.fileFetchTree();
|
||||||
await this.fileFetchTodoList();
|
const focusPromise = this.focusFetchFiles();
|
||||||
|
const todoPromise = this.fileFetchTodoList();
|
||||||
|
|
||||||
const statusResponse = await fetch('/api/status');
|
const statusResponse = await fetch('/api/status');
|
||||||
const statusData = await statusResponse.json();
|
const statusData = await statusResponse.json();
|
||||||
this.projectPath = statusData.project_path || '';
|
this.projectPath = statusData.project_path || '';
|
||||||
this.agentVersion = statusData.version || this.agentVersion;
|
this.agentVersion = statusData.version || this.agentVersion;
|
||||||
this.thinkingMode = !!statusData.thinking_mode;
|
this.thinkingMode = !!statusData.thinking_mode;
|
||||||
this.applyStatusSnapshot(statusData);
|
this.applyStatusSnapshot(statusData);
|
||||||
await this.fetchUsageQuota();
|
// 立即更新配额和运行模式,避免等待其他慢接口
|
||||||
|
this.fetchUsageQuota();
|
||||||
|
|
||||||
// 获取当前对话信息
|
// 获取当前对话信息
|
||||||
const statusConversationId = statusData.conversation && statusData.conversation.current_id;
|
const statusConversationId = statusData.conversation && statusData.conversation.current_id;
|
||||||
if (statusConversationId) {
|
if (statusConversationId && !this.currentConversationId) {
|
||||||
if (!this.currentConversationId) {
|
this.skipConversationHistoryReload = true;
|
||||||
this.skipConversationHistoryReload = true;
|
// 首次从状态恢复对话时,避免 socket 的 conversation_loaded 再次触发历史加载
|
||||||
// 首次从状态恢复对话时,避免 socket 的 conversation_loaded 再次触发历史加载
|
this.skipConversationLoadedEvent = true;
|
||||||
this.skipConversationLoadedEvent = true;
|
this.currentConversationId = statusConversationId;
|
||||||
this.currentConversationId = statusConversationId;
|
|
||||||
|
|
||||||
// 如果有当前对话,尝试获取标题和历史
|
// 如果有当前对话,尝试获取标题和历史
|
||||||
try {
|
try {
|
||||||
const convResponse = await fetch(`/api/conversations/current`);
|
const convResponse = await fetch(`/api/conversations/current`);
|
||||||
const convData = await convResponse.json();
|
const convData = await convResponse.json();
|
||||||
if (convData.success && convData.data) {
|
if (convData.success && convData.data) {
|
||||||
this.currentConversationTitle = convData.data.title;
|
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);
|
|
||||||
}
|
}
|
||||||
|
// 初始化时调用一次,因为 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);
|
await this.loadToolSettings(true);
|
||||||
|
|
||||||
debugLog('初始数据加载完成');
|
debugLog('初始数据加载完成');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载初始数据失败:', error);
|
console.error('加载初始数据失败:', error);
|
||||||
@ -1835,17 +1838,19 @@ const appOptions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (toolAction) {
|
if (toolAction) {
|
||||||
// 解析工具结果
|
// 解析工具结果(优先使用JSON,其次使用元数据的 tool_payload,以保证搜索结果在刷新后仍可展示)
|
||||||
let result;
|
let result;
|
||||||
try {
|
try {
|
||||||
// 尝试解析为JSON
|
|
||||||
result = JSON.parse(message.content);
|
result = JSON.parse(message.content);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// 如果不是JSON,就作为纯文本
|
if (message.metadata && message.metadata.tool_payload) {
|
||||||
result = {
|
result = message.metadata.tool_payload;
|
||||||
output: message.content,
|
} else {
|
||||||
success: true
|
result = {
|
||||||
};
|
output: message.content,
|
||||||
|
success: true
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toolAction.tool.status = 'completed';
|
toolAction.tool.status = 'completed';
|
||||||
|
|||||||
@ -545,6 +545,38 @@ def format_tool_result_notice(tool_name: str, tool_call_id: Optional[str], conte
|
|||||||
body = "(无附加输出)"
|
body = "(无附加输出)"
|
||||||
return f"{header}\n{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"
|
DEBUG_LOG_FILE = Path(LOGS_DIR).expanduser().resolve() / "debug_stream.log"
|
||||||
CHUNK_BACKEND_LOG_FILE = Path(LOGS_DIR).expanduser().resolve() / "chunk_backend.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
|
metadata_payload = None
|
||||||
if isinstance(result_data, dict):
|
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}
|
metadata_payload = {"tool_payload": result_data}
|
||||||
else:
|
else:
|
||||||
tool_result_content = tool_result
|
tool_result_content = tool_result
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user