feat: add browser script skill execution

This commit is contained in:
zyl
2026-03-30 02:15:07 +08:00
parent f7e2ff256e
commit d2c9902966
22 changed files with 1775 additions and 249 deletions

View File

@@ -810,18 +810,18 @@ pub fn skills_to_prompt_with_mode(
}
if !skill.tools.is_empty() {
// Tools with known kinds (shell, script, http) are registered as
// Tools with known kinds (shell, script, http, browser_script) are registered as
// callable tool specs and can be invoked directly via function calling.
// We note them here for context but mark them as callable.
let registered: Vec<_> = skill
.tools
.iter()
.filter(|t| matches!(t.kind.as_str(), "shell" | "script" | "http"))
.filter(|t| matches!(t.kind.as_str(), "shell" | "script" | "http" | "browser_script"))
.collect();
let unregistered: Vec<_> = skill
.tools
.iter()
.filter(|t| !matches!(t.kind.as_str(), "shell" | "script" | "http"))
.filter(|t| !matches!(t.kind.as_str(), "shell" | "script" | "http" | "browser_script"))
.collect();
if !registered.is_empty() {
@@ -887,6 +887,7 @@ pub fn skills_to_tools(
tool,
)));
}
"browser_script" => {}
other => {
tracing::warn!(
"Unknown skill tool kind '{}' for {}.{}, skipping",
@@ -1900,6 +1901,32 @@ description = "Bare minimum"
assert!(prompt.contains("<description>Fetch forecast</description>"));
}
#[test]
fn skills_to_prompt_marks_browser_script_tools_as_callable() {
let skills = vec![Skill {
name: "zhihu-hotlist".to_string(),
description: "Collect hotlist rows".to_string(),
version: "1.0.0".to_string(),
author: None,
tags: vec![],
tools: vec![SkillTool {
name: "extract_hotlist".to_string(),
description: "Extract structured hotlist rows from the current page".to_string(),
kind: "browser_script".to_string(),
command: "scripts/extract_hotlist.js".to_string(),
args: HashMap::new(),
}],
prompts: vec![],
location: None,
}];
let prompt = skills_to_prompt(&skills, Path::new("/tmp"));
assert!(prompt.contains("<callable_tools"));
assert!(prompt.contains("<name>zhihu-hotlist.extract_hotlist</name>"));
assert!(!prompt.contains("<kind>browser_script</kind>"));
}
#[test]
fn skills_to_prompt_escapes_xml_content() {
let skills = vec![Skill {