Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Task

The Task trait produces an artefact from input. It’s the starting point of every workflow.

Definition

#![allow(unused)]
fn main() {
#[async_trait::async_trait]
pub trait Task: Send + Sync {
    type Input;
    type Output;
    type Error;

    async fn run(&self, runtime: &Runtime, input: &Self::Input) -> Result<Self::Output, Self::Error>;
}
}

Parameters

  • Input — The type of data this task consumes
  • Output — The type of data this task produces
  • Error — The error type this task may return

Example

use naaf_core::{Runtime, Task};

struct GenerateCode;

#[async_trait::async_trait]
impl Task for GenerateCode {
    type Input = String;
    type Output = String;
    type Error = std::io::Error;

    async fn run(&self, _: &Runtime, input: &String) -> Result<String, std::io::Error> {
        Ok(format!("fn solution() {{ // {}\n    unimplemented!()\n}}", input))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let runtime = Runtime::new();
    let task = GenerateCode;

    let output = task.run(&runtime, &"add two numbers".to_string()).await?;
    println!("{}", output);

    Ok(())
}

Using Runtime Capabilities

The runtime provides access to shared capabilities:

#![allow(unused)]
fn main() {
use naaf_core::{Runtime, Task};
use naaf_llm::LlmClient;

struct LlmTask {
    prompt: String,
}

#[async_trait::async_trait]
impl Task for LlmTask {
    type Input = String;
    type Output = String;
    type Error = std::io::Error;

    async fn run(&self, runtime: &Runtime, input: &String) -> Result<String, std::io::Error> {
        let llm = runtime.llm().ok_or_else(|| std::io::Error::new(
            std::io::ErrorKind::NotFound,
            "LLM not configured"
        ))?;

        let full_prompt = format!("{}: {}", self.prompt, input);
        let response = llm.complete(&full_prompt).await?;
        Ok(response)
    }
}
}

Task Combinators

Tasks can be combined using the TaskExt extension trait:

#![allow(unused)]
fn main() {
use naaf_core::TaskExt;

// Wrap a task with observability
let observed = my_task.observed();

// Wrap with a custom name
let named = my_task.observed_as("generate_code");
}

See Also

  • Check — Validates task output
  • Materialiser — Transforms task output
  • Step — Combines Task with Check and RepairPlanner