Skip to content

Commit

Permalink
new: ignore_stderr field and various output fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
evilsocket committed Feb 6, 2025
1 parent a4d4995 commit 033a471
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 34 deletions.
1 change: 1 addition & 0 deletions docs/tasklets.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ In addition to the ones already mentioned, tools can optionally define the follo
- `complete_task`: if set to `true`, the task will be marked as complete after the tool is executed.
- `judge`: uses another tasklet as a judge to validate the output of the tool (see [examples/code_auditor_with_judge](https://github.com/dreadnode/nerve/tree/main/examples/code_auditor_with_judge))
- `alias`: use to create a tool that's an alias to one of the predefined ones (see [examples/docker-agent](https://github.com/dreadnode/nerve/tree/main/examples/docker-agent))
- `ignore_stderr`: if set to `true`, the stderr of the tool will be ignored.

## Evaluators

Expand Down
3 changes: 3 additions & 0 deletions src/agent/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ pub enum EventType {
invocation: Invocation,
elapsed: std::time::Duration,
},
ActionExecuting {
invocation: Invocation,
},
ActionExecuted {
invocation: Invocation,
error: Option<String>,
Expand Down
9 changes: 7 additions & 2 deletions src/agent/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,8 +363,13 @@ impl Agent {
.unwrap();
}

async fn on_valid_action(&self) {
async fn on_valid_action(&self, invocation: &Invocation) {
self.state.lock().await.metrics.valid_actions += 1;

let invocation = invocation.clone();

self.on_event(Event::new(EventType::ActionExecuting { invocation }))
.unwrap();
}

async fn on_timed_out_action(&self, invocation: Invocation, start: &std::time::Instant) {
Expand Down Expand Up @@ -525,7 +530,7 @@ impl Agent {
self.on_invalid_action(inv.clone(), Some(err.to_string()))
.await;
} else {
self.on_valid_action().await;
self.on_valid_action(&inv).await;

// determine if we have a timeout
let timeout = if let Some(action_tm) = action.timeout().as_ref() {
Expand Down
2 changes: 1 addition & 1 deletion src/agent/namespaces/time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl Action for Wait {
) -> Result<Option<ActionOutput>> {
let secs = payload.unwrap().parse::<u64>()?;

log::info!("sleeping for {secs} seconds ...");
log::info!("💤 sleeping for {secs} seconds ...");

tokio::time::sleep(Duration::from_secs(secs)).await;

Expand Down
30 changes: 4 additions & 26 deletions src/agent/task/tasklet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub struct TaskletAction {
judge_path: Option<PathBuf>,

complete_task: Option<bool>,
ignore_stderr: Option<bool>,

tool: Option<String>,

Expand Down Expand Up @@ -195,38 +196,15 @@ impl TaskletAction {
}
}

log::info!(
"{}{}{}",
self.name.bold(),
if payload.is_some() {
format!(" {}", payload.as_ref().unwrap().red())
} else {
"".to_string()
},
if attributes.is_some() {
format!(
" {}",
attributes
.as_ref()
.unwrap()
.iter()
.map(|(key, value)| format!("{key}{}{}", "=".dimmed(), value.bright_blue()))
.collect::<Vec<String>>()
.join(" ")
)
} else {
"".to_string()
},
);

log::debug!("! {:?}", &cmd);

let output = cmd.output();
if let Ok(output) = output {
let err = String::from_utf8_lossy(&output.stderr).trim().to_string();
let out = String::from_utf8_lossy(&output.stdout).trim().to_string();

if !err.is_empty() {
if !err.is_empty() && self.max_shown_output > 0 && !self.ignore_stderr.unwrap_or(false)
{
log::error!(
"{}",
if err.len() > self.max_shown_output {
Expand Down Expand Up @@ -269,7 +247,7 @@ impl TaskletAction {
return Ok(Some("task complete".into()));
}

if !err.is_empty() {
if !err.is_empty() && !self.ignore_stderr.unwrap_or(false) {
Err(anyhow!(err))
} else {
Ok(Some(out))
Expand Down
35 changes: 30 additions & 5 deletions src/cli/ui/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,30 @@ use crate::{
cli::Args,
};

fn on_action_about_to_execute(invocation: Invocation) {
let mut view = String::new();

view.push_str("🧠 ");
view.push_str(&invocation.action.bold().to_string());
view.push('(');
if let Some(payload) = &invocation.payload {
view.push_str(&payload.dimmed().to_string());
}
if let Some(attributes) = &invocation.attributes {
view.push_str(", ");
view.push_str(
&attributes
.iter()
.map(|(k, v)| format!("{}={}", k, v).dimmed().to_string())
.collect::<Vec<String>>()
.join(", "),
);
}
view.push(')');

log::info!("{} ...", view);
}

fn on_action_executed(
judge_mode: bool,
error: Option<String>,
Expand Down Expand Up @@ -53,14 +77,14 @@ fn on_action_executed(
if let Some(err) = error {
log::error!("{}: {}", view, err);
} else if let Some(res) = result {
log::info!(
log::debug!(
"{} -> {} bytes in {:?}",
view,
res.to_string().as_bytes().len(),
elapsed
);
} else {
log::info!("{} {} in {:?}", view, "no output".dimmed(), elapsed);
log::debug!("{} {} in {:?}", view, "no output".dimmed(), elapsed);
}
}

Expand All @@ -83,9 +107,7 @@ pub async fn consume_events(mut events_rx: Receiver, args: Args, is_workflow: bo
log::info!("💤 sleeping for {} seconds ...", seconds);
}
EventType::MetricsUpdate(metrics) => {
if !is_workflow {
println!("{}", metrics.to_string().dimmed());
}
log::debug!("{}", metrics.to_string());
}
EventType::StateUpdate(_state) => {}
EventType::Thinking(thinking) => {
Expand Down Expand Up @@ -113,6 +135,9 @@ pub async fn consume_events(mut events_rx: Receiver, args: Args, is_workflow: bo
elapsed
);
}
EventType::ActionExecuting { invocation } => {
on_action_about_to_execute(invocation);
}
EventType::ActionExecuted {
invocation,
error,
Expand Down

0 comments on commit 033a471

Please sign in to comment.