pub struct StepGuard<'a, S> { /* private fields */ }Expand description
One open step.
Created by RunContext::step. STEP_STARTED has
already gone out; Drop emits STEP_FINISHED, including on the early
return that a ? produces.
A step is a scope, not a stream, so unlike the message and tool-call handles this one dereferences to the run context — everything nests inside it, steps included:
{
let mut step = ctx.step("research")?;
step.say("looking it up")?; // through Deref
} // STEP_FINISHED here
assert_eq!(events.drain().len(), 5);Implementations§
Methods from Deref<Target = RunContext<S>>§
Sourcepub fn state_mut(&mut self) -> &mut S
pub fn state_mut(&mut self) -> &mut S
The typed state, mutably. Nothing is emitted until you call
publish_state.
Sourcepub fn set_state(&mut self, state: &S) -> Result<()>
pub fn set_state(&mut self, state: &S) -> Result<()>
Replaces the state and publishes the change.
The first publish of a run is a STATE_SNAPSHOT; later ones are a
STATE_DELTA unless the patch would be no smaller than the snapshot.
See StateManager.
Sourcepub fn update_state(&mut self, update: impl FnOnce(&mut S)) -> Result<()>
pub fn update_state(&mut self, update: impl FnOnce(&mut S)) -> Result<()>
Mutates the state in place and publishes the change.
#[derive(Default, Serialize, Deserialize)]
struct Draft { revision: u32 }
ctx.update_state(|draft| draft.revision += 1)?;
assert_eq!(ctx.state().revision, 1);Sourcepub fn publish_state(&mut self) -> Result<()>
pub fn publish_state(&mut self) -> Result<()>
Publishes whatever state_mut left behind.
A no-op when nothing changed since the last publish.
Sourcepub fn input(&self) -> &RunAgentInput
pub fn input(&self) -> &RunAgentInput
The whole request, for anything the accessors do not cover.
Sourcepub fn parent_run_id(&self) -> Option<&RunId>
pub fn parent_run_id(&self) -> Option<&RunId>
The run that spawned this one, for nested agents.
Sourcepub fn last_user_text(&self) -> Option<String>
pub fn last_user_text(&self) -> Option<String>
What the user said last, as text.
The turn an agent is almost always answering. Non-text parts of a
multimodal message are dropped — see
UserContent::to_text; reach into
RunContext::messages directly if the images matter.
None when the history holds no user message at all, which is distinct
from a user who sent an empty one.
let mut input = RunAgentInput::new("thread-1", "run-1");
input.messages = vec![Message::user("msg-1", "add milk")];
let (ctx, _events) = RunContext::<()>::new(input)?;
assert_eq!(ctx.last_user_text().as_deref(), Some("add milk"));Sourcepub fn forwarded_props(&self) -> &Value
pub fn forwarded_props(&self) -> &Value
Arbitrary passthrough properties, opaque to the protocol.
Sourcepub fn resume(&self) -> &[ResumeEntry]
pub fn resume(&self) -> &[ResumeEntry]
Answers to the interrupts a previous run paused on.
Empty unless this request resumes a paused run.
Sourcepub fn resume_for(&self, interrupt_id: &str) -> Option<&ResumeEntry>
pub fn resume_for(&self, interrupt_id: &str) -> Option<&ResumeEntry>
The answer to one interrupt, by its Interrupt::id.
Sourcepub fn is_cancelled(&self) -> bool
pub fn is_cancelled(&self) -> bool
Whether the run has been cancelled.
Sourcepub fn check_cancelled(&self) -> Result<()>
pub fn check_cancelled(&self) -> Result<()>
Error::Cancelled once the run is cancelled, for use with ?.
Sourcepub fn cancel_token(&self) -> CancellationToken
pub fn cancel_token(&self) -> CancellationToken
A handle a transport can trip on client disconnect.
Sourcepub fn until_cancelled<F: Future>(
&self,
future: F,
) -> impl Future<Output = Option<F::Output>>
pub fn until_cancelled<F: Future>( &self, future: F, ) -> impl Future<Output = Option<F::Output>>
Races future against cancellation, returning None if cancellation
won.
The way to make a long model call interruptible:
let answer = ctx
.until_cancelled(async { "the model's reply" })
.await
.ok_or(Error::Cancelled)?;
assert_eq!(answer, "the model's reply");Deliberately not an async fn: that would capture &self in the
returned future, and a future holding a borrow of the run context is
only Send if the context is Sync — which it is not, since a
transformer only has to be Send.
Sourcepub fn emit(&mut self, event: Event) -> Result<()>
pub fn emit(&mut self, event: Event) -> Result<()>
Emits an event as-is — the escape hatch under the typed emitters.
Everything the handles emit goes through here, so a raw event is transformed and verified like any other.
Sourcepub fn new_message_id(&mut self) -> MessageId
pub fn new_message_id(&mut self) -> MessageId
A fresh message id, unique within the run.
Derived from the run id and a counter rather than a UUID: the protocol
asks for opaque strings, this crate takes no uuid dependency, and a
deterministic id makes a recorded stream diffable. Pass your own id to
message_with_id when you need one.
Sourcepub fn new_tool_call_id(&mut self) -> ToolCallId
pub fn new_tool_call_id(&mut self) -> ToolCallId
A fresh tool call id, unique within the run.
Sourcepub fn new_subagent_run_id(&mut self) -> SubagentRunId
pub fn new_subagent_run_id(&mut self) -> SubagentRunId
A fresh subagent invocation id, unique within the run.
Derived like the others, from the run id and a counter — so, like
message ids, it is unique across runs only while run ids are. A
resuming run that continues a suspended subagent should reuse the
suspended id instead — see subagent_with.
Sourcepub fn subagent_run_id(&self) -> Option<&SubagentRunId>
pub fn subagent_run_id(&self) -> Option<&SubagentRunId>
The subagent everything emitted right now is attributed to — None
outside any subagent scope.
Sourcepub fn subagent(
&mut self,
name: impl Into<String>,
) -> Result<SubagentHandle<'_, S>>
pub fn subagent( &mut self, name: impl Into<String>, ) -> Result<SubagentHandle<'_, S>>
Announces a subagent under a fresh id and scopes everything emitted
through the returned handle to it — SUBAGENT_STARTED now,
SUBAGENT_FINISHED when the handle drops.
name is the subagent’s reusable type or name, for display; the id is
this invocation’s alone. See SubagentHandle.
Sourcepub fn subagent_with(
&mut self,
started: SubagentStartedEvent,
) -> Result<SubagentHandle<'_, S>>
pub fn subagent_with( &mut self, started: SubagentStartedEvent, ) -> Result<SubagentHandle<'_, S>>
The same, from an announcement you built — for a description, an explicit id, or the agents-as-tools links.
A parent_subagent_run_id left absent is filled from the enclosing
scope, so nesting needs no help. An explicit id is how a resuming run
continues a subagent that suspended: announce the id the suspended
invocation had, and a client transitions its group from waiting back
to running rather than drawing a second one.
let mut call = ctx.tool_call("task")?;
call.args(r#"{"brief":"find sources"}"#)?;
let (call_id, result_id) = (call.id().clone(), call.result_message_id().clone());
call.end()?; // the client sees the call close…
let announce = SubagentStartedEvent::new("researcher-7", "researcher")
.with_parent_tool_call(call_id.clone());
let mut researcher = ctx.subagent_with(announce)?;
researcher.say("Three sources found.")?; // …then the subagent it spawned…
researcher.finish()?;
ctx.emit(Event::tool_call_result(result_id, call_id, "3 sources"))?; // …then its result
let types: Vec<_> = events.drain().iter().map(Event::event_type).collect();
assert_eq!(types[3], EventType::SubagentStarted);
assert_eq!(types[7], EventType::SubagentFinished);
assert_eq!(types[8], EventType::ToolCallResult);Sourcepub fn assistant_message(&mut self) -> Result<MessageHandle<'_, S>>
pub fn assistant_message(&mut self) -> Result<MessageHandle<'_, S>>
Opens an assistant message under a fresh id — TEXT_MESSAGE_START.
Sourcepub fn message(&mut self, role: TextMessageRole) -> Result<MessageHandle<'_, S>>
pub fn message(&mut self, role: TextMessageRole) -> Result<MessageHandle<'_, S>>
Opens a message with the given role under a fresh id.
Sourcepub fn message_with_id(
&mut self,
id: impl Into<MessageId>,
role: TextMessageRole,
) -> Result<MessageHandle<'_, S>>
pub fn message_with_id( &mut self, id: impl Into<MessageId>, role: TextMessageRole, ) -> Result<MessageHandle<'_, S>>
Opens a message under an id you choose.
Sourcepub fn say(&mut self, text: impl Into<String>) -> Result<MessageId>
pub fn say(&mut self, text: impl Into<String>) -> Result<MessageId>
Emits a whole assistant message — start, content, end — and returns its id.
Sourcepub fn reasoning(&mut self) -> Result<ReasoningHandle<'_, S>>
pub fn reasoning(&mut self) -> Result<ReasoningHandle<'_, S>>
Opens a reasoning block under a fresh id — REASONING_START.
Sourcepub fn reasoning_with_id(
&mut self,
id: impl Into<MessageId>,
) -> Result<ReasoningHandle<'_, S>>
pub fn reasoning_with_id( &mut self, id: impl Into<MessageId>, ) -> Result<ReasoningHandle<'_, S>>
Opens a reasoning block under an id you choose.
Sourcepub fn think(&mut self, text: impl Into<String>) -> Result<MessageId>
pub fn think(&mut self, text: impl Into<String>) -> Result<MessageId>
Emits a whole reasoning block in one call and returns its id.
Sourcepub fn tool_call(&mut self, name: &str) -> Result<ToolCallHandle<'_, S>>
pub fn tool_call(&mut self, name: &str) -> Result<ToolCallHandle<'_, S>>
Opens a call to name under a fresh id — TOOL_CALL_START.
Sourcepub fn tool_call_with_id(
&mut self,
id: impl Into<ToolCallId>,
name: &str,
) -> Result<ToolCallHandle<'_, S>>
pub fn tool_call_with_id( &mut self, id: impl Into<ToolCallId>, name: &str, ) -> Result<ToolCallHandle<'_, S>>
Opens a call to name under an id you choose.