Skip to main content

awaken_runtime/runtime/agent_runtime/
run_request.rs

1//! RunRequest — unified request for starting or resuming a run.
2
3use std::collections::HashMap;
4
5use crate::inbox::{InboxReceiver, InboxSender};
6use awaken_contract::contract::inference::InferenceOverride;
7use awaken_contract::contract::message::Message;
8use awaken_contract::contract::storage::{RunRecord, RunRequestOrigin};
9use awaken_contract::contract::suspension::ToolCallResume;
10use awaken_contract::contract::tool::ToolDescriptor;
11use awaken_contract::contract::tool_intercept::{AdapterKind, RunMode};
12
13/// Read-only snapshot of cached thread state, passed from mailbox to runtime.
14#[non_exhaustive]
15pub struct ThreadContextSnapshot {
16    pub messages: Vec<Message>,
17    pub latest_run: Option<RunRecord>,
18    pub run_cache: HashMap<String, RunRecord>,
19}
20
21impl ThreadContextSnapshot {
22    #[must_use]
23    pub fn new(
24        messages: Vec<Message>,
25        latest_run: Option<RunRecord>,
26        run_cache: HashMap<String, RunRecord>,
27    ) -> Self {
28        Self {
29            messages,
30            latest_run,
31            run_cache,
32        }
33    }
34}
35
36/// In-process inbox pair owned by a single run.
37pub struct RunInbox {
38    pub sender: InboxSender,
39    pub receiver: InboxReceiver,
40}
41
42/// Unified request for starting or resuming a run.
43pub struct RunRequest {
44    /// New messages to append before running.
45    pub messages: Vec<Message>,
46    /// True when `messages` already exist in the thread message log.
47    ///
48    /// Mailbox-backed dispatch reconstructs new input messages from
49    /// `RunRecord.request` and the thread log, so the runtime must use them as
50    /// the current turn without appending a duplicate copy.
51    pub messages_already_persisted: bool,
52    /// Thread ID. Existing → load history; new → create.
53    pub thread_id: String,
54    /// Target agent ID.
55    /// `None` = infer from latest thread state/run record, fallback to default.
56    pub agent_id: Option<String>,
57    /// Runtime parameter overrides for this run.
58    pub overrides: Option<InferenceOverride>,
59    /// Resume decisions for suspended tool calls. Empty = fresh run.
60    pub decisions: Vec<(String, ToolCallResume)>,
61    /// Frontend-defined tools for this run.
62    pub frontend_tools: Vec<ToolDescriptor>,
63    /// Where this request originated.
64    pub origin: RunRequestOrigin,
65    /// Execution mode used by framework-level policy hooks.
66    pub run_mode: RunMode,
67    /// Protocol or adapter that submitted this request.
68    pub adapter: AdapterKind,
69    /// Parent run ID for child run linkage (tracing/lineage).
70    pub parent_run_id: Option<String>,
71    /// Parent thread ID for message routing back to parent.
72    pub parent_thread_id: Option<String>,
73    /// Continue a previous run instead of creating a new one.
74    pub continue_run_id: Option<String>,
75    /// Optional canonical run ID preallocated by the caller.
76    pub run_id_hint: Option<String>,
77    /// Optional transport dispatch/task ID that should be used as the run ID.
78    pub dispatch_id_hint: Option<String>,
79    /// Queue dispatch that delivered this run request, if any.
80    pub dispatch_id: Option<String>,
81    /// External session/dispatch identifier associated with this run.
82    pub session_id: Option<String>,
83    /// Transport request identifier associated with this run.
84    pub transport_request_id: Option<String>,
85    /// Optional in-process inbox pair for background-task notifications.
86    pub run_inbox: Option<RunInbox>,
87}
88
89impl RunRequest {
90    /// Build a message-first request with default options.
91    pub fn new(thread_id: impl Into<String>, messages: Vec<Message>) -> Self {
92        Self {
93            messages,
94            messages_already_persisted: false,
95            thread_id: thread_id.into(),
96            agent_id: None,
97            overrides: None,
98            decisions: Vec::new(),
99            frontend_tools: Vec::new(),
100            origin: RunRequestOrigin::User,
101            run_mode: RunMode::Foreground,
102            adapter: AdapterKind::Internal,
103            parent_run_id: None,
104            parent_thread_id: None,
105            continue_run_id: None,
106            run_id_hint: None,
107            dispatch_id_hint: None,
108            dispatch_id: None,
109            session_id: None,
110            transport_request_id: None,
111            run_inbox: None,
112        }
113    }
114
115    #[must_use]
116    pub fn with_agent_id(mut self, agent_id: impl Into<String>) -> Self {
117        self.agent_id = Some(agent_id.into());
118        self
119    }
120
121    #[must_use]
122    pub fn with_overrides(mut self, overrides: InferenceOverride) -> Self {
123        self.overrides = Some(overrides);
124        self
125    }
126
127    #[must_use]
128    pub fn with_decisions(mut self, decisions: Vec<(String, ToolCallResume)>) -> Self {
129        self.decisions = decisions;
130        self
131    }
132
133    #[must_use]
134    pub fn with_frontend_tools(mut self, tools: Vec<ToolDescriptor>) -> Self {
135        self.frontend_tools = tools;
136        self
137    }
138
139    #[must_use]
140    pub fn with_origin(mut self, origin: RunRequestOrigin) -> Self {
141        self.origin = origin;
142        self
143    }
144
145    #[must_use]
146    pub fn with_run_mode(mut self, run_mode: RunMode) -> Self {
147        self.run_mode = run_mode;
148        self
149    }
150
151    #[must_use]
152    pub fn with_adapter(mut self, adapter: AdapterKind) -> Self {
153        self.adapter = adapter;
154        self
155    }
156
157    #[must_use]
158    pub fn with_parent_run_id(mut self, parent_run_id: impl Into<String>) -> Self {
159        self.parent_run_id = Some(parent_run_id.into());
160        self
161    }
162
163    #[must_use]
164    pub fn with_parent_thread_id(mut self, parent_thread_id: impl Into<String>) -> Self {
165        self.parent_thread_id = Some(parent_thread_id.into());
166        self
167    }
168
169    #[must_use]
170    pub fn with_continue_run_id(mut self, continue_run_id: impl Into<String>) -> Self {
171        self.continue_run_id = Some(continue_run_id.into());
172        self
173    }
174
175    #[must_use]
176    pub fn with_run_id_hint(mut self, run_id_hint: impl Into<String>) -> Self {
177        self.run_id_hint = Some(run_id_hint.into());
178        self
179    }
180
181    #[must_use]
182    pub fn with_dispatch_id_hint(mut self, dispatch_id_hint: impl Into<String>) -> Self {
183        self.dispatch_id_hint = Some(dispatch_id_hint.into());
184        self
185    }
186
187    #[must_use]
188    pub fn with_trace_dispatch_id(mut self, dispatch_id: impl Into<String>) -> Self {
189        self.dispatch_id = Some(dispatch_id.into());
190        self
191    }
192
193    #[must_use]
194    pub fn with_dispatch_id(mut self, dispatch_id: impl Into<String>) -> Self {
195        self.dispatch_id = Some(dispatch_id.into());
196        self
197    }
198
199    #[must_use]
200    pub fn with_session_id(mut self, session_id: impl Into<String>) -> Self {
201        self.session_id = Some(session_id.into());
202        self
203    }
204
205    #[must_use]
206    pub fn with_transport_request_id(mut self, transport_request_id: impl Into<String>) -> Self {
207        self.transport_request_id = Some(transport_request_id.into());
208        self
209    }
210
211    #[must_use]
212    pub fn with_inbox(mut self, sender: InboxSender, receiver: InboxReceiver) -> Self {
213        self.run_inbox = Some(RunInbox { sender, receiver });
214        self
215    }
216
217    #[must_use]
218    pub fn with_messages_already_persisted(mut self, value: bool) -> Self {
219        self.messages_already_persisted = value;
220        self
221    }
222}