Skip to main content

Request

Struct Request 

Source
pub struct Request { /* private fields */ }
Expand description

A run, described but not yet started.

Built fluently and then handed to crate::run or crate::stream:

use agent_abstraction::{Agent, Permission, Request};

let request = Request::new(Agent::Claude, "summarize this repo")
    .model("sonnet")
    .permission(Permission::ReadOnly);

Implementations§

Source§

impl Request

Source

pub fn new(agent: Agent, prompt: impl Into<String>) -> Self

A request for agent with prompt.

Defaults are deliberately conservative: Permission::ReadOnly, EnvPolicy::Minimal, and the agent’s structured output format. Widen them explicitly.

Source

pub fn command(agent: Agent, command: &Command) -> Self

A run that carries a slash command instead of a prompt.

The agent’s own verbs, addressed as values: /compact summarises a conversation that has grown too long to think in, /clear discards it. See crate::Command.

Pair it with Request::session or Request::resume. A command with no conversation behind it has nothing to act on: /compact on a fresh session is refused, and says so.

§A command is a turn, not an interruption

Deliberately a constructor rather than something crate::Run::send delivers mid-turn. Verified against claude 2.1.212: a command injected into a running turn emits its own result record after the turn’s, which overwrites the outcome — the answer’s text becomes the compaction’s empty string and the turn’s usage becomes the compaction’s zeroes. As its own run the same command produces one clean terminal.

§Reading the result

The outcome’s text is empty and num_turns is zero, because a compaction generates no answer. Neither is a failure, and neither is a refusal: crate::Event::Compaction carries whether it worked, so this wants crate::stream rather than crate::run.

Claude only. No other agent has a command vocabulary, so both refuse before spawning.

Source

pub fn bin(self, bin: impl Into<String>) -> Self

Override the binary. Defaults to the agent’s own name on PATH.

Source

pub fn system(self, system: impl Into<String>) -> Self

A system prompt. Delivered by flag where the agent has one and prepended to the prompt where it does not. It is never dropped.

Source

pub fn model(self, model: impl Into<String>) -> Self

Pin the model. Passed through verbatim; this crate does not validate model names, so an unknown one surfaces as the agent’s own error.

Source

pub fn effort(self, effort: impl Into<String>) -> Self

Set the reasoning effort level.

Passed through verbatim, exactly like Request::model and for the same reason: the accepted set belongs to the provider, differs between agents, and has already grown once. crate::Model::efforts lists what each model is known to take, and nothing here validates against it.

Delivered as --effort on Claude and Copilot, and as -c model_reasoning_effort=<level> on Codex, which has no flag for it.

Source

pub fn thinking(self, enabled: bool) -> Self

Turn the model’s reasoning (“thinking”) on or off for this run.

Left unset the agent keeps its own default, which for Claude is adaptive thinking. thinking(false) disables it; thinking(true) is the same as leaving it unset and exists so a caller driven by a UI toggle can pass the switch through without branching.

§Only Claude has a lever here

Delivered as MAX_THINKING_TOKENS=0 in the child’s environment, which is exactly the switch the claude CLI reads to decide whether to send a thinking block to the API (verified against claude 2.1.212: the gate is MAX_THINKING_TOKENS > 0, so 0 omits the block). It rides the environment rather than an argument because the CLI exposes no flag for it, and it wins over EnvPolicy the same way an explicit Request::env does.

Codex and Copilot have no equivalent off switch, so thinking(false) is a no-op for them rather than a silent lie. Their reasoning is steered by Request::effort instead.

Source

pub fn interactive(self) -> Self

Keep the input channel open for the turn, so the caller can send more.

Without this a run takes one prompt and that is the whole conversation. With it, crate::Run::send delivers another message while the agent is still working, which is what lets a chat UI accept a correction the moment a user types it rather than making them wait for the turn to end.

The agent takes the message at its next step boundary, not mid-token. Verified against claude 2.1.212 and codex-cli 0.145.0.

Claude and Codex support this. Codex switches from exec to app-server for the interactive turn. Copilot is crate::Error::Unsupported.

Source

pub fn approvals(self) -> Self

Route gated tool calls to the caller for a decision, instead of letting the posture answer them.

Every Permission resolves the approval question up front, which is what lets a headless run finish unattended. This asks instead: a gated call arrives as crate::Event::ApprovalRequest and the run waits, mid-turn, until crate::Run::respond answers it.

Two constraints, both raised before spawning rather than met as a hang: this needs crate::stream, since crate::run yields no events for anyone to answer. Claude and Codex expose approval callbacks; Copilot does not and is crate::Error::Unsupported.

Permission still applies to everything the agent does not ask about. Agents may allow read-only commands without asking, so the absence of a question is not proof that nothing ran.

Source

pub fn permission(self, permission: Permission) -> Self

Set the permission posture.

Source

pub fn format(self, format: Format) -> Self

Pin the output format. Left unset, a run picks the agent’s structured format, which is also the one that carries a session id.

Source

pub fn cwd(self, cwd: impl Into<PathBuf>) -> Self

The working directory the agent runs in.

Source

pub fn add_dir(self, dir: impl Into<PathBuf>) -> Self

Add another working root beside Request::cwd.

Claude and codex exec receive --add-dir. Interactive Codex runs use the same path as an app-server runtime root and workspace-write root, so the access described here survives transport changes without a caller assembling provider-specific arguments.

Source

pub fn env(self, key: impl Into<String>, value: impl Into<String>) -> Self

Set an environment variable for the child. Repeatable.

Source

pub fn env_policy(self, policy: EnvPolicy) -> Self

Choose which of the host’s environment variables reach the agent.

Defaults to EnvPolicy::Minimal, which passes through only what the selected agent needs. Reach for EnvPolicy::Inherit when the host holds nothing the agent should not see, or when something this crate does not know about has to reach the CLI.

let request = Request::new(Agent::Claude, "review this")
    .env_policy(EnvPolicy::Inherit);
Source

pub fn timeout(self, timeout: Duration) -> Self

Kill the run if it has not finished within timeout.

Source

pub fn unchecked_args<I, S>(self, args: I) -> Self
where I: IntoIterator<Item = S>, S: Into<String>,

Append raw arguments after everything this crate builds.

The escape hatch for agent-specific flags with no unified spelling.

This voids the crate’s guarantees. Arguments land after the generated ones, so they can contradict Request::permission, redirect the output format the parser expects, or point the run at a different session. Codex’s -c key=value in particular can rewrite sandbox and approval policy for the invocation. Nothing here is validated, and a security review of the permission posture means little without also reviewing whatever is passed here.

Arguments are passed straight to the binary without a shell.

Source

pub fn schema(self, schema: impl Into<String>) -> Self

Constrain the answer to a JSON Schema.

The agent is asked to return a value conforming to schema, which Outcome::structured then carries already parsed. Useful when the answer is data rather than prose: a set of review findings, an extraction, a classification. Reading it beats parsing prose, which is a guess about formatting the model never promised.

The two CLIs that support this take it differently, and the difference is hidden: Claude accepts the schema inline, Codex reads it from a file this crate writes for the run and removes afterwards. Copilot 1.0.75 has no schema support, so asking is crate::Error::Unsupported rather than a prose answer presented as data.

The schema is passed through unvalidated; a malformed one surfaces as the agent’s own error.

§Write the schema strictly

Codex sends it to OpenAI’s structured-output API, which rejects anything permissive. Every object needs "additionalProperties": false and every property listed in required, or the request fails with a 400 before the model runs:

'additionalProperties' is required to be supplied and to be false

Claude is more forgiving, so a schema that works there can still fail on Codex. Writing to the stricter rule keeps one schema usable for both.

Source

pub fn resume(self, id: impl Into<String>) -> Self

Continue an earlier conversation by its native id, bypassing the session store. Prefer Request::session unless you are tracking ids yourself.

Source

pub fn session_id(self, id: impl Into<String>) -> Self

Start a new conversation under an id you choose, rather than one the agent picks.

Useful when a host already has its own identifier for a thread and wants the agent’s session to match it, with no mapping table in between. The id is known before the process starts, so the association survives a run that dies mid-turn.

Only Claude and Copilot accept an assigned id (SessionSupport::Minted). Codex reveals its thread_id only in its own output, so this is crate::Error::Unsupported for it, raised when the argv is built rather than silently starting an unrelated session.

Both CLIs require a valid UUID here; this crate passes the string through without checking, so a non-UUID surfaces as the agent’s own error.

Source

pub fn session( self, store: &SessionStore, project: impl AsRef<Path>, name: impl Into<String>, fork: bool, ) -> Result<Self>

Attach this run to a caller-owned session name.

The store decides whether this turn creates, continues, or forks, and the binding is written back once the run yields an id. fork branches a new conversation off the stored one instead of appending to it.

The store is cloned into the request so the run can write the binding back without borrowing it. That clone is a PathBuf, not the sessions themselves: records are read and written on demand and never held in memory, so this stays cheap however many sessions exist.

§Errors

crate::Error::SessionConflict if the name belongs to another agent, or crate::Error::Unsupported if this agent cannot fork or has no session id at all.

Source

pub fn effective_format(&self) -> Format

The format this request will actually use.

Source

pub fn session_phase(&self) -> Option<Phase>

Whether this turn opens, continues, or branches its named session. None when the request is not attached to one.

Known before the run starts, so a UI can label the turn up front.

Source

pub fn argv(&self) -> Result<Vec<String>>

The full command line, for logging or for showing a user exactly what will run before they approve it.

§Errors

crate::Error::Unsupported if the agent cannot honour this request.

Trait Implementations§

Source§

impl Clone for Request

Source§

fn clone(&self) -> Request

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Request

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.