Skip to content

Commit 0f0952f

Browse files
Merge pull request #30 from browser-use/subagents-codex-runtime-parity
Much better subagent system
2 parents 7f2ef3c + dce5d11 commit 0f0952f

29 files changed

Lines changed: 1592 additions & 138 deletions

File tree

crates/browser-use-agent/src/compact/tests.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ impl SamplingDriver for LoopSampler {
433433
.unwrap_or_else(|| SamplingOutcome {
434434
model_needs_follow_up: false,
435435
last_agent_message: Some("end".to_string()),
436+
defers_mailbox_delivery_to_next_turn: true,
436437
finish_reason: None,
437438
}))
438439
}
@@ -481,13 +482,15 @@ fn follow_up(msg: &str) -> SamplingOutcome {
481482
SamplingOutcome {
482483
model_needs_follow_up: true,
483484
last_agent_message: Some(msg.to_string()),
485+
defers_mailbox_delivery_to_next_turn: false,
484486
finish_reason: None,
485487
}
486488
}
487489
fn complete(msg: &str) -> SamplingOutcome {
488490
SamplingOutcome {
489491
model_needs_follow_up: false,
490492
last_agent_message: Some(msg.to_string()),
493+
defers_mailbox_delivery_to_next_turn: true,
491494
finish_reason: None,
492495
}
493496
}

crates/browser-use-agent/src/compact/threshold_tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ fn follow_up(msg: &str) -> SamplingOutcome {
264264
SamplingOutcome {
265265
model_needs_follow_up: true,
266266
last_agent_message: Some(msg.to_string()),
267+
defers_mailbox_delivery_to_next_turn: false,
267268
finish_reason: None,
268269
}
269270
}
@@ -272,6 +273,7 @@ fn complete(msg: &str) -> SamplingOutcome {
272273
SamplingOutcome {
273274
model_needs_follow_up: false,
274275
last_agent_message: Some(msg.to_string()),
276+
defers_mailbox_delivery_to_next_turn: true,
275277
finish_reason: None,
276278
}
277279
}

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

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,53 @@ impl ProviderRunConfig {
714714
}
715715
}
716716

717+
/// Re-apply runtime options that were snapshotted into a
718+
/// [`ChildAgentRunRequest`]. Child wake/resume paths may run under a different
719+
/// parent process/config than the original spawn, so these values must travel
720+
/// with the child run marker rather than relying on the current parent config.
721+
pub fn apply_child_request_runtime_config(
722+
config: &mut ProviderRunConfig,
723+
request: &ChildAgentRunRequest,
724+
) -> Result<()> {
725+
let overrides = &request.config_overrides;
726+
if let Some(value) = config_override_str(overrides, "browser_mode") {
727+
config.options.browser_mode = Some(value);
728+
}
729+
if let Some(value) = config_override_str(overrides, "base_instructions") {
730+
config.options.base_instructions = Some(value);
731+
}
732+
if let Some(value) = config_override_str(overrides, "developer_instructions") {
733+
config.options.developer_instructions = Some(value);
734+
}
735+
if let Some(value) = config_override_str(overrides, "compact_prompt") {
736+
config.options.compact_prompt = Some(value);
737+
}
738+
if let Some(value) = config_override_u64(overrides, "python_tool_timeout_seconds") {
739+
config.options.python_tool_timeout_seconds = value;
740+
}
741+
if let Some(value) = config_override_bool(overrides, "model_compaction_enabled") {
742+
config.options.model_compaction_enabled = value;
743+
}
744+
if let Some(value) = config_override_i64(overrides, "model_auto_compact_token_limit") {
745+
config.options.model_auto_compact_token_limit = Some(value);
746+
}
747+
if let Some(value) = config_override_str(overrides, "model_auto_compact_token_limit_scope") {
748+
config.options.model_auto_compact_token_limit_scope =
749+
parse_auto_compact_token_limit_scope(&value)?;
750+
}
751+
if let Some(value) = config_override_str(overrides, "approval_policy")
752+
.or_else(|| config_override_str(overrides, "ask_for_approval"))
753+
{
754+
config.options.approval_policy = parse_approval_policy(&value)?;
755+
}
756+
if let Some(value) = config_override_bool(overrides, "use_guardian")
757+
.or_else(|| config_override_bool(overrides, "guardian"))
758+
{
759+
config.options.use_guardian = value;
760+
}
761+
Ok(())
762+
}
763+
717764
/// Parse raw `key=value` override strings into an ordered [`ConfigOverrides`].
718765
///
719766
/// Behavior is byte-identical to `browser-use-core::parse_config_overrides`
@@ -1484,6 +1531,28 @@ fn config_override_bool(overrides: &ConfigOverrides, key: &str) -> Option<bool>
14841531
.and_then(|(_, value)| value.as_bool())
14851532
}
14861533

1534+
fn config_override_i64(overrides: &ConfigOverrides, key: &str) -> Option<i64> {
1535+
overrides
1536+
.iter()
1537+
.rev()
1538+
.find(|(candidate, _)| candidate == key)
1539+
.and_then(|(_, value)| value.as_integer())
1540+
}
1541+
1542+
fn config_override_u64(overrides: &ConfigOverrides, key: &str) -> Option<u64> {
1543+
config_override_i64(overrides, key).and_then(|value| u64::try_from(value).ok())
1544+
}
1545+
1546+
fn parse_auto_compact_token_limit_scope(raw: &str) -> Result<AutoCompactTokenLimitScope> {
1547+
match raw.trim().to_ascii_lowercase().replace('-', "_").as_str() {
1548+
"total" => Ok(AutoCompactTokenLimitScope::Total),
1549+
"body_after_prefix" | "bodyafterprefix" => Ok(AutoCompactTokenLimitScope::BodyAfterPrefix),
1550+
other => bail!(
1551+
"invalid model_auto_compact_token_limit_scope {other:?}; expected total or body_after_prefix"
1552+
),
1553+
}
1554+
}
1555+
14871556
/// Mirrors `browser-use-core::canonicalize_config_override_key`
14881557
/// (`config_overrides.rs:35`).
14891558
fn canonicalize_config_override_key(key: &str) -> String {

crates/browser-use-agent/src/decision/loop_decision.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ pub struct SamplingOutcome {
1818
/// `turn.rs:250`.
1919
pub model_needs_follow_up: bool,
2020
pub last_agent_message: Option<String>,
21+
/// Codex defers inter-agent mailbox delivery only after output that closes a
22+
/// turn boundary, such as final assistant text. Commentary text remains a
23+
/// current-turn preemption/drain point.
24+
pub defers_mailbox_delivery_to_next_turn: bool,
2125
pub finish_reason: Option<FinishReason>,
2226
}
2327

@@ -198,6 +202,7 @@ mod tests {
198202
SamplingOutcome {
199203
model_needs_follow_up: model_nfu,
200204
last_agent_message: None,
205+
defers_mailbox_delivery_to_next_turn: false,
201206
finish_reason: None,
202207
}
203208
}

0 commit comments

Comments
 (0)