Skip to main content

starweaver_runtime/agent/run_loop/
entrypoints.rs

1use starweaver_context::AgentContext;
2use starweaver_core::ConversationId;
3use starweaver_model::ModelMessage;
4
5use crate::{
6    agent::{Agent, AgentError, AgentInput, AgentResult},
7    iteration::{AgentIterResult, AgentIterationTrace},
8    stream::{AgentStreamRecord, AgentStreamResult},
9};
10
11impl Agent {
12    /// Run the agent with a user prompt.
13    ///
14    /// # Errors
15    ///
16    /// Returns an error when the model, capabilities, validation, tools, or runtime policy fails.
17    pub async fn run(&self, prompt: impl Into<AgentInput>) -> Result<AgentResult, AgentError> {
18        Box::pin(self.run_with_history(prompt, Vec::new())).await
19    }
20
21    /// Run the agent and collect a compact iteration trace.
22    ///
23    /// # Errors
24    ///
25    /// Returns an error when the model, capabilities, validation, tools, or runtime policy fails.
26    pub async fn run_iter(
27        &self,
28        prompt: impl Into<AgentInput>,
29    ) -> Result<AgentIterResult, AgentError> {
30        let mut events = Vec::new();
31        let result = Box::pin(self.run_with_stream_events(prompt, &mut events)).await?;
32        let iterations = AgentIterationTrace::from_stream_records(&events);
33        Ok(AgentIterResult {
34            result,
35            iterations,
36            events,
37        })
38    }
39
40    /// Run the agent and collect typed stream events emitted during execution.
41    ///
42    /// # Errors
43    ///
44    /// Returns an error when the model, capabilities, validation, tools, or runtime policy fails.
45    pub async fn run_stream(
46        &self,
47        prompt: impl Into<AgentInput>,
48    ) -> Result<AgentStreamResult, AgentError> {
49        let mut events = Vec::new();
50        let result = Box::pin(self.run_with_stream_events(prompt, &mut events)).await?;
51        Ok(AgentStreamResult { result, events })
52    }
53
54    /// Run the agent with prior history and collect a compact iteration trace.
55    ///
56    /// # Errors
57    ///
58    /// Returns an error when the model, capabilities, validation, tools, or runtime policy fails.
59    pub async fn run_with_history_iter(
60        &self,
61        prompt: impl Into<AgentInput>,
62        message_history: Vec<ModelMessage>,
63    ) -> Result<AgentIterResult, AgentError> {
64        let mut events = Vec::new();
65        let result =
66            Box::pin(self.run_with_history_and_stream_events(prompt, message_history, &mut events))
67                .await?;
68        let iterations = AgentIterationTrace::from_stream_records(&events);
69        Ok(AgentIterResult {
70            result,
71            iterations,
72            events,
73        })
74    }
75
76    /// Run the agent with an explicit typed stream event collector.
77    ///
78    /// # Errors
79    ///
80    /// Returns an error when the model, capabilities, validation, tools, or runtime policy fails.
81    pub async fn run_with_stream_events(
82        &self,
83        prompt: impl Into<AgentInput>,
84        events: &mut Vec<AgentStreamRecord>,
85    ) -> Result<AgentResult, AgentError> {
86        Box::pin(self.run_with_history_and_stream_events(prompt, Vec::new(), events)).await
87    }
88
89    /// Run the agent with prior history and collect typed stream events.
90    ///
91    /// # Errors
92    ///
93    /// Returns an error when the model, capabilities, validation, tools, or runtime policy fails.
94    pub async fn run_with_history_and_stream_events(
95        &self,
96        prompt: impl Into<AgentInput>,
97        message_history: Vec<ModelMessage>,
98        events: &mut Vec<AgentStreamRecord>,
99    ) -> Result<AgentResult, AgentError> {
100        let mut context = self.context_from_history(message_history);
101        Box::pin(self.run_with_context_and_stream_events(prompt, &mut context, events)).await
102    }
103
104    /// Run the agent with prior canonical message history.
105    ///
106    /// # Errors
107    ///
108    /// Returns an error when the model, capabilities, validation, tools, or runtime policy fails.
109    pub async fn run_with_history(
110        &self,
111        prompt: impl Into<AgentInput>,
112        message_history: Vec<ModelMessage>,
113    ) -> Result<AgentResult, AgentError> {
114        let mut context = self.context_from_history(message_history);
115        Box::pin(self.run_with_context(prompt, &mut context)).await
116    }
117
118    /// Run the agent using a lifecycle-wide context and collect a compact iteration trace.
119    ///
120    /// # Errors
121    ///
122    /// Returns an error when the model, capabilities, validation, tools, or runtime policy fails.
123    pub async fn run_with_context_iter(
124        &self,
125        prompt: impl Into<AgentInput>,
126        context: &mut AgentContext,
127    ) -> Result<AgentIterResult, AgentError> {
128        let mut events = Vec::new();
129        let result =
130            Box::pin(self.run_with_context_and_stream_events(prompt, context, &mut events)).await?;
131        let iterations = AgentIterationTrace::from_stream_records(&events);
132        Ok(AgentIterResult {
133            result,
134            iterations,
135            events,
136        })
137    }
138
139    /// Run the agent using a lifecycle-wide context and typed stream event collector.
140    ///
141    /// # Errors
142    ///
143    /// Returns an error when the model, capabilities, validation, tools, or runtime policy fails.
144    pub async fn run_with_context_and_stream_events(
145        &self,
146        prompt: impl Into<AgentInput>,
147        context: &mut AgentContext,
148        events: &mut Vec<AgentStreamRecord>,
149    ) -> Result<AgentResult, AgentError> {
150        Box::pin(self.run_with_context_inner(prompt, context, Some(events))).await
151    }
152
153    /// Run the agent using a lifecycle-wide context.
154    ///
155    /// # Errors
156    ///
157    /// Returns an error when the model, capabilities, validation, tools, or runtime policy fails.
158    #[allow(clippy::too_many_lines)]
159    pub async fn run_with_context(
160        &self,
161        prompt: impl Into<AgentInput>,
162        context: &mut AgentContext,
163    ) -> Result<AgentResult, AgentError> {
164        Box::pin(self.run_with_context_inner(prompt, context, None)).await
165    }
166    fn context_from_history(&self, message_history: Vec<ModelMessage>) -> AgentContext {
167        let conversation_id = latest_conversation_id(&message_history).unwrap_or_default();
168        let mut context = self.new_context();
169        context.conversation_id = conversation_id;
170        context.message_history = message_history;
171        context
172    }
173}
174
175fn latest_conversation_id(message_history: &[ModelMessage]) -> Option<ConversationId> {
176    message_history
177        .iter()
178        .rev()
179        .find_map(|message| match message {
180            ModelMessage::Request(request) => request.conversation_id.clone(),
181            ModelMessage::Response(response) => response.conversation_id.clone(),
182        })
183}