Implement standalone AutoAgent::run() for poc-hook agents
Creates an Agent from global config (API credentials, system prompt, identity), overrides tools with the agent's tool set, and runs through the standard Backend → run_with_backend → Agent::turn() path. This enables poc-hook spawned agents (surface-observe, journal, etc.) to work with the completions API instead of the deleted chat API. Also added Default derive to CliArgs for config loading. Co-Authored-By: Proof of Concept <poc@bcachefs.org> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
bf1fa62d14
commit
850008ece7
3 changed files with 56 additions and 6 deletions
|
|
@ -110,9 +110,39 @@ impl AutoAgent {
|
|||
|
||||
pub async fn run(
|
||||
&mut self,
|
||||
_bail_fn: Option<&(dyn Fn(usize) -> Result<(), String> + Sync)>,
|
||||
bail_fn: Option<&(dyn Fn(usize) -> Result<(), String> + Sync)>,
|
||||
) -> Result<String, String> {
|
||||
Err("standalone agent run not yet migrated to completions API".to_string())
|
||||
let config = crate::config::get();
|
||||
let base_url = config.api_base_url.as_deref().unwrap_or("");
|
||||
let api_key = config.api_key.as_deref().unwrap_or("");
|
||||
let model = config.api_model.as_deref().unwrap_or("");
|
||||
if base_url.is_empty() || model.is_empty() {
|
||||
return Err("API not configured (no base_url or model)".to_string());
|
||||
}
|
||||
let client = super::api::ApiClient::new(base_url, api_key, model);
|
||||
|
||||
// Load system prompt + identity from config
|
||||
let cli = crate::user::CliArgs::default();
|
||||
let (app, _) = crate::config::load_app(&cli)
|
||||
.map_err(|e| format!("config: {}", e))?;
|
||||
let (system_prompt, personality) = crate::config::reload_for_model(
|
||||
&app, &app.prompts.other,
|
||||
).map_err(|e| format!("config: {}", e))?;
|
||||
|
||||
let agent = Agent::new(
|
||||
client, system_prompt, personality,
|
||||
app, String::new(),
|
||||
None,
|
||||
super::tools::ActiveTools::new(),
|
||||
).await;
|
||||
{
|
||||
let mut st = agent.state.lock().await;
|
||||
st.provenance = format!("standalone:{}", self.name);
|
||||
st.tools = self.tools.clone();
|
||||
}
|
||||
|
||||
let mut backend = Backend(agent);
|
||||
self.run_with_backend(&mut backend, bail_fn).await
|
||||
}
|
||||
|
||||
/// Run forked using a shared agent Arc. The UI can lock the same
|
||||
|
|
@ -254,15 +284,35 @@ pub fn run_one_agent(
|
|||
defs::run_agent(store, &def, effective_count, &Default::default())?
|
||||
};
|
||||
|
||||
// Filter tools based on agent def
|
||||
// Filter tools based on agent def, add filesystem output tool
|
||||
let all_tools = super::tools::memory_and_journal_tools();
|
||||
let effective_tools: Vec<super::tools::Tool> = if def.tools.is_empty() {
|
||||
let mut effective_tools: Vec<super::tools::Tool> = if def.tools.is_empty() {
|
||||
all_tools.to_vec()
|
||||
} else {
|
||||
all_tools.into_iter()
|
||||
.filter(|t| def.tools.iter().any(|w| w == &t.name))
|
||||
.collect()
|
||||
};
|
||||
effective_tools.push(super::tools::Tool {
|
||||
name: "output",
|
||||
description: "Produce a named output value for passing between steps.",
|
||||
parameters_json: r#"{"type":"object","properties":{"key":{"type":"string","description":"Output name"},"value":{"type":"string","description":"Output value"}},"required":["key","value"]}"#,
|
||||
handler: std::sync::Arc::new(|_agent, v| Box::pin(async move {
|
||||
let key = v["key"].as_str()
|
||||
.ok_or_else(|| anyhow::anyhow!("output requires 'key'"))?;
|
||||
if key.starts_with("pid-") || key.contains('/') || key.contains("..") {
|
||||
anyhow::bail!("invalid output key: {}", key);
|
||||
}
|
||||
let value = v["value"].as_str()
|
||||
.ok_or_else(|| anyhow::anyhow!("output requires 'value'"))?;
|
||||
let dir = std::env::var("POC_AGENT_OUTPUT_DIR")
|
||||
.map_err(|_| anyhow::anyhow!("no output directory set"))?;
|
||||
let path = std::path::Path::new(&dir).join(key);
|
||||
std::fs::write(&path, value)
|
||||
.map_err(|e| anyhow::anyhow!("writing output {}: {}", path.display(), e))?;
|
||||
Ok(format!("{}: {}", key, value))
|
||||
})),
|
||||
});
|
||||
let n_steps = agent_batch.steps.len();
|
||||
|
||||
// Guard: reject oversized first prompt
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue