pub trait AgentRole {
type Input;
type Output: DeserializeOwned + JsonSchema + AgentAnswer;
Show 14 methods
// Required method
fn prompt(&self, input: Self::Input) -> String;
// Provided methods
fn name(&self) -> &str { ... }
fn system_prompt(&self) -> Option<&str> { ... }
fn append_system_prompt(&self) -> Option<&str> { ... }
fn tools(&self) -> Vec<Tool> { ... }
fn permission_mode(&self) -> Option<PermissionMode> { ... }
fn mcp_config(&self) -> Option<&str> { ... }
fn strict_mcp_config(&self) -> bool { ... }
fn model(&self) -> Option<&str> { ... }
fn max_budget_usd(&self) -> Option<f64> { ... }
fn max_turns(&self) -> Option<u32> { ... }
fn effort(&self) -> Option<Effort> { ... }
fn timeout(&self) -> Option<Duration> { ... }
fn task(&self, input: Self::Input) -> AgentTask<Self::Output> { ... }
}Expand description
A reusable agent with a fixed role: persona, tools, rights and output type.
Only prompt is required. The persona, tools, permission
mode, MCP config and output type are locked by the role: the caller of
task cannot change them (a role with more rights is another
role). The model, budget, turn limit, effort, timeout and per-call settings
are defaults the caller may override on the AgentTask.
§Examples
use ironflow_engine::config::{AgentAnswer, AgentRole, AgentStep, Tool};
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(Deserialize, JsonSchema, AgentAnswer)]
struct Verdict {
approved: bool,
}
struct Reviewer;
impl AgentRole for Reviewer {
type Input = String;
type Output = Verdict;
fn prompt(&self, input: String) -> String {
format!("Review: {input}")
}
fn append_system_prompt(&self) -> Option<&str> {
Some("You are a strict reviewer.")
}
fn tools(&self) -> Vec<Tool> {
vec![Tool::Read]
}
fn max_turns(&self) -> Option<u32> {
Some(4)
}
}
let config = Reviewer.task("diff".to_string()).max_budget_usd(0.10).into_config();
assert_eq!(config.append_system_prompt.as_deref(), Some("You are a strict reviewer."));
assert_eq!(config.allowed_tools, vec!["Read"]);
assert!(config.json_schema.is_some());
assert_eq!(config.max_budget_usd, Some(0.10));Calling it from a workflow:
let verdict: Verdict = ctx.agent("review", Reviewer.task(diff)).await?;Required Associated Types§
Sourcetype Output: DeserializeOwned + JsonSchema + AgentAnswer
type Output: DeserializeOwned + JsonSchema + AgentAnswer
What the role answers; ctx.agent returns it. Its free-text fields
are AgentText: see AgentAnswer.
Required Methods§
Provided Methods§
Sourcefn name(&self) -> &str
fn name(&self) -> &str
Name of the role, recorded on every step it runs and shown by the API,
CLI and dashboard. Defaults to the type name without its module path
(Reviewer). Override it to keep the name stable across a type rename.
Renaming the type changes the default name: the steps and costs of the
role are then split between the old and the new name. The caller of
task cannot override it.
§Examples
struct Reviewer;
impl AgentRole for Reviewer {
type Input = String;
type Output = Verdict;
fn prompt(&self, input: String) -> String {
input
}
}
struct Named;
impl AgentRole for Named {
type Input = String;
type Output = Verdict;
fn name(&self) -> &str {
"code-reviewer"
}
fn prompt(&self, input: String) -> String {
input
}
}
assert_eq!(Reviewer.name(), "Reviewer");
assert_eq!(Named.name(), "code-reviewer");
let config = Named.task("diff".to_string()).into_config();
assert_eq!(config.role.as_deref(), Some("code-reviewer"));Sourcefn system_prompt(&self) -> Option<&str>
fn system_prompt(&self) -> Option<&str>
Replaces the provider system prompt. Claude Code loses its own (tools,
skills) when it is replaced. None by default.
Sourcefn append_system_prompt(&self) -> Option<&str>
fn append_system_prompt(&self) -> Option<&str>
Persona appended to the provider system prompt. Prefer it to
system_prompt for a role with tools. None by
default.
Sourcefn permission_mode(&self) -> Option<PermissionMode>
fn permission_mode(&self) -> Option<PermissionMode>
Permission mode of the role; None keeps the
AgentConfig::new default.
Sourcefn mcp_config(&self) -> Option<&str>
fn mcp_config(&self) -> Option<&str>
MCP configuration, as JSON or a path. None by default.
Sourcefn strict_mcp_config(&self) -> bool
fn strict_mcp_config(&self) -> bool
Restrict the MCP servers to mcp_config. false by
default.
Sourcefn model(&self) -> Option<&str>
fn model(&self) -> Option<&str>
Default model; None keeps the AgentConfig::new default. The
caller may override it.
Sourcefn max_budget_usd(&self) -> Option<f64>
fn max_budget_usd(&self) -> Option<f64>
Default budget in USD. The caller may override it.
Sourcefn max_turns(&self) -> Option<u32>
fn max_turns(&self) -> Option<u32>
Default turn limit. The caller may override it.
A structured output needs at least 2 turns; like AgentStepConfig,
the role does not validate it.
Sourcefn timeout(&self) -> Option<Duration>
fn timeout(&self) -> Option<Duration>
Default step timeout, see
AgentConfig::timeout.
The caller may override it.
Sourcefn task(&self, input: Self::Input) -> AgentTask<Self::Output>
fn task(&self, input: Self::Input) -> AgentTask<Self::Output>
Build one task of this role.
§Panics
Panics if name is empty or blank, has leading or
trailing whitespace, or is longer than
MAX_ROLE_NAME_LEN bytes.
§Examples
let config = Reviewer.task("diff".to_string()).into_config();
assert_eq!(config.prompt, "Review: diff");Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".