merge: integrate main deterministic submit into ws branch
Keep the ws submit path while bringing over main's deterministic lineloss routing and the focused merge verification updates. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use reqwest::Url;
|
||||
use serde_json::{Map, Value};
|
||||
use zeroclaw::skills::load_skills_from_directory;
|
||||
use zeroclaw::skills::{load_skills_from_directory, SkillTool};
|
||||
|
||||
use crate::browser::PipeBrowserBackend;
|
||||
use crate::browser::{BrowserBackend, PipeBrowserBackend};
|
||||
use crate::compat::browser_script_skill_tool::execute_browser_script_tool;
|
||||
use crate::compat::config_adapter::resolve_skills_dir_from_sgclaw_settings;
|
||||
use crate::compat::runtime::CompatTaskContext;
|
||||
@@ -30,13 +31,96 @@ pub fn execute_direct_submit_skill<T: Transport + 'static>(
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.ok_or_else(|| PipeError::Protocol("direct submit skill is not configured".to_string()))?;
|
||||
let (skill_name, tool_name) = parse_configured_tool_name(configured_tool)?;
|
||||
let expected_domain = derive_expected_domain(task_context)?;
|
||||
let period = derive_period(instruction)?;
|
||||
|
||||
let mut args = Map::new();
|
||||
args.insert("expected_domain".to_string(), Value::String(expected_domain));
|
||||
args.insert("period".to_string(), Value::String(period));
|
||||
|
||||
let output = execute_browser_script_skill_raw_output(
|
||||
browser_tool,
|
||||
configured_tool,
|
||||
workspace_root,
|
||||
settings,
|
||||
args,
|
||||
)?;
|
||||
|
||||
Ok(interpret_direct_submit_output(&output))
|
||||
}
|
||||
|
||||
pub fn execute_direct_submit_skill_with_browser_backend(
|
||||
browser_backend: Arc<dyn BrowserBackend>,
|
||||
instruction: &str,
|
||||
task_context: &CompatTaskContext,
|
||||
workspace_root: &Path,
|
||||
settings: &SgClawSettings,
|
||||
) -> Result<DirectSubmitOutcome, PipeError> {
|
||||
let configured_tool = settings
|
||||
.direct_submit_skill
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.ok_or_else(|| PipeError::Protocol("direct submit skill is not configured".to_string()))?;
|
||||
let expected_domain = derive_expected_domain(task_context)?;
|
||||
let period = derive_period(instruction)?;
|
||||
|
||||
let mut args = Map::new();
|
||||
args.insert("expected_domain".to_string(), Value::String(expected_domain));
|
||||
args.insert("period".to_string(), Value::String(period));
|
||||
|
||||
let output = execute_browser_script_skill_raw_output_with_browser_backend(
|
||||
browser_backend,
|
||||
configured_tool,
|
||||
workspace_root,
|
||||
settings,
|
||||
args,
|
||||
)?;
|
||||
|
||||
Ok(interpret_direct_submit_output(&output))
|
||||
}
|
||||
|
||||
pub fn execute_browser_script_skill_raw_output<T: Transport + 'static>(
|
||||
browser_tool: BrowserPipeTool<T>,
|
||||
configured_tool: &str,
|
||||
workspace_root: &Path,
|
||||
settings: &SgClawSettings,
|
||||
args: Map<String, Value>,
|
||||
) -> Result<String, PipeError> {
|
||||
let (tool, skill_root) = resolve_browser_script_skill(configured_tool, workspace_root, settings)?;
|
||||
|
||||
execute_browser_script_tool_output(browser_tool, configured_tool, &tool, &skill_root, args)
|
||||
}
|
||||
|
||||
pub fn execute_browser_script_skill_raw_output_with_browser_backend(
|
||||
browser_backend: Arc<dyn BrowserBackend>,
|
||||
configured_tool: &str,
|
||||
workspace_root: &Path,
|
||||
settings: &SgClawSettings,
|
||||
args: Map<String, Value>,
|
||||
) -> Result<String, PipeError> {
|
||||
let (tool, skill_root) =
|
||||
resolve_browser_script_skill(configured_tool, workspace_root, settings)?;
|
||||
|
||||
execute_browser_script_tool_output_with_backend(
|
||||
browser_backend.as_ref(),
|
||||
configured_tool,
|
||||
&tool,
|
||||
&skill_root,
|
||||
args,
|
||||
)
|
||||
}
|
||||
|
||||
fn resolve_browser_script_skill(
|
||||
configured_tool: &str,
|
||||
workspace_root: &Path,
|
||||
settings: &SgClawSettings,
|
||||
) -> Result<(SkillTool, std::path::PathBuf), PipeError> {
|
||||
let (skill_name, tool_name) = parse_configured_tool_name(configured_tool)?;
|
||||
let skills_dir = resolve_skills_dir_from_sgclaw_settings(workspace_root, settings);
|
||||
let skills = load_skills_from_directory(&skills_dir, true);
|
||||
let skill = skills
|
||||
.iter()
|
||||
.into_iter()
|
||||
.find(|skill| skill.name == skill_name)
|
||||
.ok_or_else(|| {
|
||||
PipeError::Protocol(format!(
|
||||
@@ -44,16 +128,54 @@ pub fn execute_direct_submit_skill<T: Transport + 'static>(
|
||||
skills_dir.display()
|
||||
))
|
||||
})?;
|
||||
let skill_root = skill
|
||||
.location
|
||||
.as_deref()
|
||||
.and_then(Path::parent)
|
||||
.map(Path::to_path_buf)
|
||||
.ok_or_else(|| {
|
||||
PipeError::Protocol(format!(
|
||||
"direct submit skill {skill_name} is missing a resolvable location"
|
||||
))
|
||||
})?;
|
||||
let tool = skill
|
||||
.tools
|
||||
.iter()
|
||||
.find(|tool| tool.name == tool_name)
|
||||
.cloned()
|
||||
.ok_or_else(|| {
|
||||
PipeError::Protocol(format!(
|
||||
"direct submit tool {configured_tool} was not found"
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok((tool, skill_root))
|
||||
}
|
||||
|
||||
fn execute_browser_script_tool_output<T: Transport + 'static>(
|
||||
browser_tool: BrowserPipeTool<T>,
|
||||
configured_tool: &str,
|
||||
tool: &SkillTool,
|
||||
skill_root: &Path,
|
||||
args: Map<String, Value>,
|
||||
) -> Result<String, PipeError> {
|
||||
let browser_backend = PipeBrowserBackend::from_inner(browser_tool);
|
||||
execute_browser_script_tool_output_with_backend(
|
||||
&browser_backend,
|
||||
configured_tool,
|
||||
tool,
|
||||
skill_root,
|
||||
args,
|
||||
)
|
||||
}
|
||||
|
||||
fn execute_browser_script_tool_output_with_backend(
|
||||
browser_backend: &dyn BrowserBackend,
|
||||
configured_tool: &str,
|
||||
tool: &SkillTool,
|
||||
skill_root: &Path,
|
||||
args: Map<String, Value>,
|
||||
) -> Result<String, PipeError> {
|
||||
if tool.kind != "browser_script" {
|
||||
return Err(PipeError::Protocol(format!(
|
||||
"direct submit tool {configured_tool} must be browser_script, got {}",
|
||||
@@ -61,34 +183,22 @@ pub fn execute_direct_submit_skill<T: Transport + 'static>(
|
||||
)));
|
||||
}
|
||||
|
||||
let skill_root = skill
|
||||
.location
|
||||
.as_deref()
|
||||
.and_then(Path::parent)
|
||||
.ok_or_else(|| {
|
||||
PipeError::Protocol(format!(
|
||||
"direct submit skill {skill_name} is missing a resolvable location"
|
||||
))
|
||||
})?;
|
||||
|
||||
let mut args = Map::new();
|
||||
args.insert("expected_domain".to_string(), Value::String(expected_domain));
|
||||
args.insert("period".to_string(), Value::String(period));
|
||||
let mut tool = tool.clone();
|
||||
tool.args.remove("expected_domain");
|
||||
|
||||
let runtime = tokio::runtime::Runtime::new()
|
||||
.map_err(|err| PipeError::Protocol(format!("failed to create tokio runtime: {err}")))?;
|
||||
let browser_backend = PipeBrowserBackend::from_inner(browser_tool);
|
||||
let result = runtime
|
||||
.block_on(execute_browser_script_tool(
|
||||
tool,
|
||||
&tool,
|
||||
skill_root,
|
||||
&browser_backend,
|
||||
browser_backend,
|
||||
Value::Object(args),
|
||||
))
|
||||
.map_err(|err| PipeError::Protocol(err.to_string()))?;
|
||||
|
||||
if result.success {
|
||||
Ok(interpret_direct_submit_output(&result.output))
|
||||
Ok(result.output)
|
||||
} else {
|
||||
Err(PipeError::Protocol(
|
||||
result
|
||||
|
||||
Reference in New Issue
Block a user