fix: stabilize zhihu export and dashboard flow

This commit is contained in:
zhaoyilun
2026-04-10 17:09:19 +08:00
parent 4becf81066
commit 34035cdc9c
10 changed files with 955 additions and 276 deletions

View File

@@ -117,6 +117,7 @@ pub fn execute_route<T: Transport + 'static>(
transport: &T,
browser_tool: &BrowserPipeTool<T>,
workspace_root: &Path,
skills_dir: &Path,
instruction: &str,
task_context: &CompatTaskContext,
route: WorkflowRoute,
@@ -124,7 +125,13 @@ pub fn execute_route<T: Transport + 'static>(
match route {
WorkflowRoute::ZhihuHotlistExportXlsx | WorkflowRoute::ZhihuHotlistScreen => {
let top_n = extract_top_n(instruction);
let items = collect_hotlist_items(transport, browser_tool, top_n, task_context)?;
let items = collect_hotlist_items(
transport,
browser_tool,
skills_dir,
top_n,
task_context,
)?;
if items.is_empty() {
return Err(PipeError::Protocol(
"知乎热榜采集失败:未能从页面文本中解析到热榜条目".to_string(),
@@ -141,13 +148,27 @@ pub fn execute_route<T: Transport + 'static>(
}
}
WorkflowRoute::ZhihuArticleEntry => {
execute_zhihu_article_entry_route(transport, browser_tool)
execute_zhihu_article_entry_route(transport, browser_tool, skills_dir)
}
WorkflowRoute::ZhihuArticleDraft => {
execute_zhihu_article_route(transport, browser_tool, instruction, task_context, false)
execute_zhihu_article_route(
transport,
browser_tool,
skills_dir,
instruction,
task_context,
false,
)
}
WorkflowRoute::ZhihuArticlePublish => {
execute_zhihu_article_route(transport, browser_tool, instruction, task_context, true)
execute_zhihu_article_route(
transport,
browser_tool,
skills_dir,
instruction,
task_context,
true,
)
}
}
}
@@ -155,10 +176,13 @@ pub fn execute_route<T: Transport + 'static>(
fn collect_hotlist_items<T: Transport + 'static>(
transport: &T,
browser_tool: &BrowserPipeTool<T>,
skills_dir: &Path,
top_n: usize,
task_context: &CompatTaskContext,
) -> Result<Vec<HotlistItem>, PipeError> {
if let Some(items) = ensure_hotlist_page_ready(transport, browser_tool, top_n, task_context)? {
if let Some(items) =
ensure_hotlist_page_ready(transport, browser_tool, skills_dir, top_n, task_context)?
{
return Ok(items);
}
transport.send(&AgentMessage::LogEntry {
@@ -167,7 +191,7 @@ fn collect_hotlist_items<T: Transport + 'static>(
})?;
let response = browser_tool.invoke(
Action::Eval,
json!({ "script": load_hotlist_extractor_script(top_n)? }),
json!({ "script": load_hotlist_extractor_script(skills_dir, top_n)? }),
ZHIHU_DOMAIN,
)?;
if !response.success {
@@ -188,6 +212,7 @@ fn collect_hotlist_items<T: Transport + 'static>(
fn ensure_hotlist_page_ready<T: Transport + 'static>(
transport: &T,
browser_tool: &BrowserPipeTool<T>,
skills_dir: &Path,
top_n: usize,
task_context: &CompatTaskContext,
) -> Result<Option<Vec<HotlistItem>>, PipeError> {
@@ -204,7 +229,7 @@ fn ensure_hotlist_page_ready<T: Transport + 'static>(
return Ok(None);
}
if starts_on_hotlist {
if let Some(items) = probe_hotlist_extractor(transport, browser_tool, top_n)? {
if let Some(items) = probe_hotlist_extractor(transport, browser_tool, skills_dir, top_n)? {
return Ok(Some(items));
}
}
@@ -215,7 +240,7 @@ fn ensure_hotlist_page_ready<T: Transport + 'static>(
if poll_for_hotlist_readiness(browser_tool)? {
return Ok(None);
}
if let Some(items) = probe_hotlist_extractor(transport, browser_tool, top_n)? {
if let Some(items) = probe_hotlist_extractor(transport, browser_tool, skills_dir, top_n)? {
return Ok(Some(items));
}
last_error = Some(PipeError::Protocol(format!(
@@ -230,6 +255,7 @@ fn ensure_hotlist_page_ready<T: Transport + 'static>(
fn probe_hotlist_extractor<T: Transport + 'static>(
transport: &T,
browser_tool: &BrowserPipeTool<T>,
skills_dir: &Path,
top_n: usize,
) -> Result<Option<Vec<HotlistItem>>, PipeError> {
transport.send(&AgentMessage::LogEntry {
@@ -238,7 +264,7 @@ fn probe_hotlist_extractor<T: Transport + 'static>(
})?;
let response = browser_tool.invoke(
Action::Eval,
json!({ "script": load_hotlist_extractor_script(top_n)? }),
json!({ "script": load_hotlist_extractor_script(skills_dir, top_n)? }),
ZHIHU_DOMAIN,
)?;
if !response.success {
@@ -379,6 +405,7 @@ fn export_screen<T: Transport>(
fn execute_zhihu_article_route<T: Transport + 'static>(
transport: &T,
browser_tool: &BrowserPipeTool<T>,
skills_dir: &Path,
instruction: &str,
task_context: &CompatTaskContext,
publish_mode: bool,
@@ -401,6 +428,7 @@ fn execute_zhihu_article_route<T: Transport + 'static>(
})?;
let creator_state = execute_browser_skill_script(
browser_tool,
skills_dir,
"zhihu-navigate",
"open_creator_entry.js",
json!({ "desired_target": "article_editor" }),
@@ -424,6 +452,7 @@ fn execute_zhihu_article_route<T: Transport + 'static>(
})?;
let editor_state = execute_browser_skill_script(
browser_tool,
skills_dir,
"zhihu-write",
"prepare_article_editor.js",
json!({ "desired_mode": if publish_mode { "publish" } else { "draft" } }),
@@ -446,6 +475,7 @@ fn execute_zhihu_article_route<T: Transport + 'static>(
})?;
let fill_result = execute_browser_skill_script(
browser_tool,
skills_dir,
"zhihu-write",
"fill_article_draft.js",
json!({
@@ -482,6 +512,7 @@ fn execute_zhihu_article_route<T: Transport + 'static>(
fn execute_zhihu_article_entry_route<T: Transport + 'static>(
transport: &T,
browser_tool: &BrowserPipeTool<T>,
skills_dir: &Path,
) -> Result<String, PipeError> {
navigate_zhihu_page(transport, browser_tool, ZHIHU_CREATOR_URL)?;
transport.send(&AgentMessage::LogEntry {
@@ -490,6 +521,7 @@ fn execute_zhihu_article_entry_route<T: Transport + 'static>(
})?;
let creator_state = execute_browser_skill_script(
browser_tool,
skills_dir,
"zhihu-navigate",
"open_creator_entry.js",
json!({ "desired_target": "article_editor" }),
@@ -513,6 +545,7 @@ fn execute_zhihu_article_entry_route<T: Transport + 'static>(
})?;
let editor_state = execute_browser_skill_script(
browser_tool,
skills_dir,
"zhihu-write",
"prepare_article_editor.js",
json!({ "desired_mode": "draft" }),
@@ -532,8 +565,9 @@ fn execute_zhihu_article_entry_route<T: Transport + 'static>(
)))
}
fn load_hotlist_extractor_script(top_n: usize) -> Result<String, PipeError> {
fn load_hotlist_extractor_script(skills_dir: &Path, top_n: usize) -> Result<String, PipeError> {
load_browser_skill_script(
skills_dir,
"zhihu-hotlist",
"extract_hotlist.js",
json!({ "top_n": top_n.to_string() }),
@@ -618,12 +652,14 @@ fn navigate_zhihu_page<T: Transport + 'static>(
fn execute_browser_skill_script<T: Transport + 'static>(
browser_tool: &BrowserPipeTool<T>,
skills_dir: &Path,
skill_name: &str,
script_name: &str,
args: Value,
expected_domain: &str,
) -> Result<Value, PipeError> {
let wrapped_script = load_browser_skill_script(skill_name, script_name, args)?;
let wrapped_script =
load_browser_skill_script(skills_dir, skill_name, script_name, args)?;
let response = browser_tool.invoke(
Action::Eval,
json!({ "script": wrapped_script }),
@@ -977,15 +1013,12 @@ mod tests {
}
fn load_browser_skill_script(
skills_dir: &Path,
skill_name: &str,
script_name: &str,
args: Value,
) -> Result<String, PipeError> {
let script_path = Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap_or_else(|| Path::new(env!("CARGO_MANIFEST_DIR")))
.join("skill_lib")
.join("skills")
let script_path = skills_dir
.join(skill_name)
.join("scripts")
.join(script_name);