Skip to content

Commit 39d5f48

Browse files
authored
refactor(core): split agent public types (#171)
1 parent 2340d86 commit 39d5f48

2 files changed

Lines changed: 187 additions & 176 deletions

File tree

crates/browser-use-core/src/agent.rs

Lines changed: 6 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,13 @@ use crate::{
4646
use browser_use_cdp::{BrowserError, BrowserSession};
4747
use browser_use_dom::BrowserStateSummary;
4848
use browser_use_llm::{ChatCompletion, ChatModel, ChatRequest, LlmError};
49-
use schemars::JsonSchema;
50-
use serde::{Deserialize, Serialize};
5149
use serde_json::Value;
52-
use std::future::Future;
53-
use std::pin::Pin;
5450
use std::time::Duration;
55-
use thiserror::Error;
5651
use tokio::time::{sleep, timeout};
5752
use uuid::Uuid;
5853

5954
mod artifacts;
55+
mod types;
6056

6157
pub(crate) use artifacts::{
6258
encode_conversation_snapshot, expand_user_path, generate_gif_output_path, now_seconds,
@@ -66,177 +62,11 @@ use artifacts::{
6662
is_single_done_output, managed_file_system_for_settings, result_requests_screenshot,
6763
settings_with_direct_start_url, settings_with_llm_screenshot_default, write_history_gif,
6864
};
69-
70-
/// Serializable task envelope with settings and generated id.
71-
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
72-
pub struct AgentTask {
73-
/// Task/run id.
74-
pub id: Uuid,
75-
/// Natural-language task instructions.
76-
pub task: String,
77-
/// Settings used for this task.
78-
#[serde(default)]
79-
pub settings: AgentSettings,
80-
}
81-
82-
impl AgentTask {
83-
/// Creates a task with default settings and a fresh id.
84-
#[must_use]
85-
pub fn new(task: impl Into<String>) -> Self {
86-
Self {
87-
id: new_agent_id(),
88-
task: task.into(),
89-
settings: AgentSettings::default(),
90-
}
91-
}
92-
}
93-
94-
/// Error returned by agent construction, stepping, and running.
95-
#[derive(Debug, Error)]
96-
pub enum AgentRunError {
97-
/// Browser/session error.
98-
#[error(transparent)]
99-
Browser(#[from] BrowserError),
100-
/// LLM/provider error.
101-
#[error(transparent)]
102-
Llm(#[from] LlmError),
103-
/// Model output did not match the expected schema.
104-
#[error("invalid agent output: {0}")]
105-
InvalidOutput(String),
106-
/// LLM call exceeded its timeout.
107-
#[error("LLM call timed out after {seconds} seconds")]
108-
LlmTimedOut {
109-
/// Timeout seconds.
110-
seconds: u64,
111-
},
112-
/// Complete agent step exceeded its timeout.
113-
#[error("agent step timed out after {seconds} seconds")]
114-
StepTimedOut {
115-
/// Timeout seconds.
116-
seconds: u64,
117-
},
118-
/// Run exhausted the configured step budget.
119-
#[error("agent reached max steps ({max_steps}) without completing")]
120-
StepLimitReached {
121-
/// Maximum steps requested by the caller.
122-
max_steps: usize,
123-
},
124-
/// Too many consecutive step/action failures occurred.
125-
#[error("agent stopped after {failures} consecutive failures")]
126-
MaxFailuresExceeded {
127-
/// Consecutive failure count.
128-
failures: u32,
129-
},
130-
/// Repeated-action loop detection fired.
131-
#[error("agent repeated the same action sequence for {window} steps")]
132-
LoopDetected {
133-
/// Detection window size.
134-
window: usize,
135-
},
136-
/// Stop was requested before a step.
137-
#[error("agent stopped before the next step: {reason}")]
138-
Stopped {
139-
/// Stop reason.
140-
reason: String,
141-
},
142-
/// Agent is paused.
143-
#[error("agent paused before the next step")]
144-
Paused,
145-
/// External status callback interrupted the run.
146-
#[error("agent interrupted by external status callback")]
147-
ExternalStatusInterrupted,
148-
/// User-provided callback failed.
149-
#[error("agent callback {callback} failed: {message}")]
150-
Callback {
151-
/// Callback name.
152-
callback: &'static str,
153-
/// Callback error message.
154-
message: String,
155-
},
156-
/// Conversation transcript could not be saved.
157-
#[error("failed to save conversation to {path}: {source}")]
158-
ConversationSave {
159-
/// Output path.
160-
path: String,
161-
/// I/O source error.
162-
#[source]
163-
source: std::io::Error,
164-
},
165-
/// Requested transcript encoding is unknown.
166-
#[error("unsupported conversation transcript encoding {encoding:?}")]
167-
ConversationEncoding {
168-
/// Requested encoding.
169-
encoding: String,
170-
},
171-
/// Transcript text cannot be represented in the requested encoding.
172-
#[error("conversation transcript encoding {encoding:?} cannot represent the transcript text")]
173-
ConversationEncodingLossy {
174-
/// Requested encoding.
175-
encoding: String,
176-
},
177-
/// GIF history artifact could not be written.
178-
#[error("failed to save agent GIF at {path}: {message}")]
179-
GifSave {
180-
/// Output path.
181-
path: String,
182-
/// Error message.
183-
message: String,
184-
},
185-
}
186-
187-
/// Serializable snapshot for pausing and resuming an agent run.
188-
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
189-
pub struct AgentCheckpoint {
190-
/// Agent id.
191-
#[serde(default = "new_agent_id")]
192-
pub id: Uuid,
193-
/// Current task text, including follow-up requests.
194-
pub task: String,
195-
/// Runtime settings.
196-
pub settings: AgentSettings,
197-
/// Durable history so far.
198-
pub history: AgentHistory,
199-
/// Whether initial actions have already run.
200-
pub initial_actions_executed: bool,
201-
/// Whether stop has been requested.
202-
#[serde(default, skip_serializing_if = "is_false")]
203-
pub stopped: bool,
204-
/// Whether the agent is paused.
205-
#[serde(default, skip_serializing_if = "is_false")]
206-
pub paused: bool,
207-
/// Managed file-system snapshot.
208-
pub file_system_state: FileSystemState,
209-
}
210-
211-
fn is_false(value: &bool) -> bool {
212-
!*value
213-
}
214-
215-
fn new_agent_id() -> Uuid {
216-
Uuid::now_v7()
217-
}
218-
219-
/// Boxed future returned by async agent callbacks.
220-
pub type AgentCallbackFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, String>> + Send + 'a>>;
221-
/// Callback invoked after a new step model output is accepted.
222-
pub type AgentStepCallback = Box<
223-
dyn for<'a> FnMut(
224-
&'a BrowserStateSummary,
225-
&'a AgentOutput,
226-
usize,
227-
) -> AgentCallbackFuture<'a, ()>
228-
+ Send
229-
+ 'static,
230-
>;
231-
/// Callback invoked after the agent completes successfully.
232-
pub type AgentDoneCallback =
233-
Box<dyn for<'a> FnMut(&'a AgentHistory) -> AgentCallbackFuture<'a, ()> + Send + 'static>;
234-
/// Callback polled before steps to request a graceful stop.
235-
pub type AgentShouldStopCallback =
236-
Box<dyn FnMut() -> AgentCallbackFuture<'static, bool> + Send + 'static>;
237-
/// Callback polled before steps to report external interruption status.
238-
pub type AgentExternalStatusCallback =
239-
Box<dyn FnMut() -> AgentCallbackFuture<'static, bool> + Send + 'static>;
65+
pub(crate) use types::new_agent_id;
66+
pub use types::{
67+
AgentCallbackFuture, AgentCheckpoint, AgentDoneCallback, AgentExternalStatusCallback,
68+
AgentRunError, AgentShouldStopCallback, AgentStepCallback, AgentTask,
69+
};
24070

24171
/// Browser-use agent run loop.
24272
pub struct Agent<M, S> {
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
use crate::{AgentHistory, AgentOutput, AgentSettings, FileSystemState};
2+
use browser_use_cdp::BrowserError;
3+
use browser_use_dom::BrowserStateSummary;
4+
use browser_use_llm::LlmError;
5+
use schemars::JsonSchema;
6+
use serde::{Deserialize, Serialize};
7+
use std::future::Future;
8+
use std::pin::Pin;
9+
use thiserror::Error;
10+
use uuid::Uuid;
11+
12+
/// Serializable task envelope with settings and generated id.
13+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
14+
pub struct AgentTask {
15+
/// Task/run id.
16+
pub id: Uuid,
17+
/// Natural-language task instructions.
18+
pub task: String,
19+
/// Settings used for this task.
20+
#[serde(default)]
21+
pub settings: AgentSettings,
22+
}
23+
24+
impl AgentTask {
25+
/// Creates a task with default settings and a fresh id.
26+
#[must_use]
27+
pub fn new(task: impl Into<String>) -> Self {
28+
Self {
29+
id: new_agent_id(),
30+
task: task.into(),
31+
settings: AgentSettings::default(),
32+
}
33+
}
34+
}
35+
36+
/// Error returned by agent construction, stepping, and running.
37+
#[derive(Debug, Error)]
38+
pub enum AgentRunError {
39+
/// Browser/session error.
40+
#[error(transparent)]
41+
Browser(#[from] BrowserError),
42+
/// LLM/provider error.
43+
#[error(transparent)]
44+
Llm(#[from] LlmError),
45+
/// Model output did not match the expected schema.
46+
#[error("invalid agent output: {0}")]
47+
InvalidOutput(String),
48+
/// LLM call exceeded its timeout.
49+
#[error("LLM call timed out after {seconds} seconds")]
50+
LlmTimedOut {
51+
/// Timeout seconds.
52+
seconds: u64,
53+
},
54+
/// Complete agent step exceeded its timeout.
55+
#[error("agent step timed out after {seconds} seconds")]
56+
StepTimedOut {
57+
/// Timeout seconds.
58+
seconds: u64,
59+
},
60+
/// Run exhausted the configured step budget.
61+
#[error("agent reached max steps ({max_steps}) without completing")]
62+
StepLimitReached {
63+
/// Maximum steps requested by the caller.
64+
max_steps: usize,
65+
},
66+
/// Too many consecutive step/action failures occurred.
67+
#[error("agent stopped after {failures} consecutive failures")]
68+
MaxFailuresExceeded {
69+
/// Consecutive failure count.
70+
failures: u32,
71+
},
72+
/// Repeated-action loop detection fired.
73+
#[error("agent repeated the same action sequence for {window} steps")]
74+
LoopDetected {
75+
/// Detection window size.
76+
window: usize,
77+
},
78+
/// Stop was requested before a step.
79+
#[error("agent stopped before the next step: {reason}")]
80+
Stopped {
81+
/// Stop reason.
82+
reason: String,
83+
},
84+
/// Agent is paused.
85+
#[error("agent paused before the next step")]
86+
Paused,
87+
/// External status callback interrupted the run.
88+
#[error("agent interrupted by external status callback")]
89+
ExternalStatusInterrupted,
90+
/// User-provided callback failed.
91+
#[error("agent callback {callback} failed: {message}")]
92+
Callback {
93+
/// Callback name.
94+
callback: &'static str,
95+
/// Callback error message.
96+
message: String,
97+
},
98+
/// Conversation transcript could not be saved.
99+
#[error("failed to save conversation to {path}: {source}")]
100+
ConversationSave {
101+
/// Output path.
102+
path: String,
103+
/// I/O source error.
104+
#[source]
105+
source: std::io::Error,
106+
},
107+
/// Requested transcript encoding is unknown.
108+
#[error("unsupported conversation transcript encoding {encoding:?}")]
109+
ConversationEncoding {
110+
/// Requested encoding.
111+
encoding: String,
112+
},
113+
/// Transcript text cannot be represented in the requested encoding.
114+
#[error("conversation transcript encoding {encoding:?} cannot represent the transcript text")]
115+
ConversationEncodingLossy {
116+
/// Requested encoding.
117+
encoding: String,
118+
},
119+
/// GIF history artifact could not be written.
120+
#[error("failed to save agent GIF at {path}: {message}")]
121+
GifSave {
122+
/// Output path.
123+
path: String,
124+
/// Error message.
125+
message: String,
126+
},
127+
}
128+
129+
/// Serializable snapshot for pausing and resuming an agent run.
130+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
131+
pub struct AgentCheckpoint {
132+
/// Agent id.
133+
#[serde(default = "new_agent_id")]
134+
pub id: Uuid,
135+
/// Current task text, including follow-up requests.
136+
pub task: String,
137+
/// Runtime settings.
138+
pub settings: AgentSettings,
139+
/// Durable history so far.
140+
pub history: AgentHistory,
141+
/// Whether initial actions have already run.
142+
pub initial_actions_executed: bool,
143+
/// Whether stop has been requested.
144+
#[serde(default, skip_serializing_if = "is_false")]
145+
pub stopped: bool,
146+
/// Whether the agent is paused.
147+
#[serde(default, skip_serializing_if = "is_false")]
148+
pub paused: bool,
149+
/// Managed file-system snapshot.
150+
pub file_system_state: FileSystemState,
151+
}
152+
153+
fn is_false(value: &bool) -> bool {
154+
!*value
155+
}
156+
157+
pub(crate) fn new_agent_id() -> Uuid {
158+
Uuid::now_v7()
159+
}
160+
161+
/// Boxed future returned by async agent callbacks.
162+
pub type AgentCallbackFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, String>> + Send + 'a>>;
163+
/// Callback invoked after a new step model output is accepted.
164+
pub type AgentStepCallback = Box<
165+
dyn for<'a> FnMut(
166+
&'a BrowserStateSummary,
167+
&'a AgentOutput,
168+
usize,
169+
) -> AgentCallbackFuture<'a, ()>
170+
+ Send
171+
+ 'static,
172+
>;
173+
/// Callback invoked after the agent completes successfully.
174+
pub type AgentDoneCallback =
175+
Box<dyn for<'a> FnMut(&'a AgentHistory) -> AgentCallbackFuture<'a, ()> + Send + 'static>;
176+
/// Callback polled before steps to request a graceful stop.
177+
pub type AgentShouldStopCallback =
178+
Box<dyn FnMut() -> AgentCallbackFuture<'static, bool> + Send + 'static>;
179+
/// Callback polled before steps to report external interruption status.
180+
pub type AgentExternalStatusCallback =
181+
Box<dyn FnMut() -> AgentCallbackFuture<'static, bool> + Send + 'static>;

0 commit comments

Comments
 (0)