Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions .github/workflows/reborn-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,7 @@ jobs:
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
cache: pip
cache-dependency-path: tests/e2e/pyproject.toml

- name: Cache Playwright browsers
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('tests/e2e/pyproject.toml') }}
restore-keys: ${{ runner.os }}-playwright-
- name: Install E2E dependencies
run: |
cd tests/e2e
Expand Down Expand Up @@ -155,23 +147,39 @@ jobs:
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
cache: pip
cache-dependency-path: tests/e2e/pyproject.toml

- name: Cache Playwright browsers
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('tests/e2e/pyproject.toml') }}
restore-keys: ${{ runner.os }}-playwright-
- name: Install E2E dependencies
run: |
cd tests/e2e
pip install -e .
playwright install --with-deps chromium

- name: Run Reborn WebUI v2 smoke
run: pytest tests/e2e/scenarios/test_reborn_webui_v2_smoke.py -v --timeout=120
- name: Run Reborn WebUI v2 Playwright smoke
run: >
pytest
tests/e2e/scenarios/test_reborn_webui_v2_smoke.py
tests/e2e/scenarios/test_reborn_v2_file_download.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_core.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_chat_actions.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_approval.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_auth_flows.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_channel_connect.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_attachments.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_rendering.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_csp.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_sse_history.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_dom_resource_limits.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_message_persistence.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_tool_execution.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_skills.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_extensions.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_automations.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_pending_messages.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_projects.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_responses_api.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_settings_search.py
tests/e2e/scenarios/test_reborn_webui_v2_legacy_tool_permissions.py
-v --timeout=180

- name: Upload screenshots on failure
if: failure()
Expand Down
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22
25 changes: 25 additions & 0 deletions crates/ironclaw_agent_loop/src/families/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::sync::Arc;
use crate::default_planner::DefaultPlanner;
use crate::family::{ComponentDigest, LoopFamily};
use crate::planner::AgentLoopPlanner;
use crate::strategies::DefaultBudgetStrategy;

mod subagent;

Expand Down Expand Up @@ -47,6 +48,21 @@ pub fn default() -> LoopFamily {
LoopFamily::new(id, version, Arc::new(planner))
}

/// The default loop family with a caller-supplied iteration limit.
///
/// Intended for test and local harnesses that need to exercise the hard budget
/// path without waiting for the production default of 32 iterations.
pub fn default_with_iteration_limit(iteration_limit: u32) -> LoopFamily {
let planner = DefaultPlanner::compose_default().with_budget(Arc::new(DefaultBudgetStrategy {
iteration_limit,
wall_clock_limit: None,
}));
let id = planner.id().clone();
let version = planner.version().clone();

LoopFamily::new(id, version, Arc::new(planner))
}

#[cfg(test)]
mod tests {
use crate::family::LoopFamilyId;
Expand All @@ -63,6 +79,15 @@ mod tests {
assert_eq!(family.version().digest, DEFAULT_FAMILY_DIGEST);
}

#[test]
fn default_family_iteration_limit_can_be_overridden_for_harnesses() {
let family = default_with_iteration_limit(5);
let context = crate::test_support::test_run_context("default-family-budget-override");
let state = crate::state::LoopExecutionState::initial_for_run(&context);

assert_eq!(family.planner().budget().iteration_limit(&state), 5);
}

#[test]
fn default_family_digest_matches_blake3_fingerprint() {
assert_eq!(
Expand Down
12 changes: 11 additions & 1 deletion crates/ironclaw_reborn/src/app_loop_family.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,18 @@ use ironclaw_agent_loop::{
/// Builtin family means adding its factory here; the framework crate exports
/// family factories but does not decide which ones are bound in production.
pub fn build_loop_family_registry() -> Result<Arc<LoopFamilyRegistry>, LoopFamilyRegistryError> {
build_loop_family_registry_with_default_iteration_limit(None)
}

pub fn build_loop_family_registry_with_default_iteration_limit(
default_iteration_limit: Option<u32>,
) -> Result<Arc<LoopFamilyRegistry>, LoopFamilyRegistryError> {
let default_family = match default_iteration_limit {
Some(iteration_limit) => families::default_with_iteration_limit(iteration_limit),
None => families::default(),
};
LoopFamilyRegistry::with_families(vec![
Arc::new(families::default()),
Arc::new(default_family),
Arc::new(families::subagent()),
])
}
Expand Down
9 changes: 7 additions & 2 deletions crates/ironclaw_reborn/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use ironclaw_host_runtime::{
};

use crate::{
app_loop_family::build_loop_family_registry,
app_loop_family::build_loop_family_registry_with_default_iteration_limit,
driver_registry::{DriverRegistry, DriverRegistryError},
loop_driver_host::{
HookDispatcherBuilderFactory, RebornLoopDriverHostFactory, TextOnlyLoopHostConfig,
Expand Down Expand Up @@ -99,6 +99,7 @@ pub struct DefaultPlannedRuntimeConfig {
pub worker_count: std::num::NonZeroUsize,
pub text_only_driver: TextOnlyModelReplyDriverConfig,
pub host: TextOnlyLoopHostConfig,
pub planned_default_iteration_limit: Option<u32>,
}

impl Default for DefaultPlannedRuntimeConfig {
Expand All @@ -109,6 +110,7 @@ impl Default for DefaultPlannedRuntimeConfig {
worker_count: DEFAULT_TURN_RUNNER_WORKER_COUNT,
text_only_driver: TextOnlyModelReplyDriverConfig::default(),
host: TextOnlyLoopHostConfig::default(),
planned_default_iteration_limit: None,
}
}
}
Expand Down Expand Up @@ -463,7 +465,10 @@ where
{
let mut registry = DriverRegistry::new();
register_default_text_only_driver(&mut registry, parts.config.text_only_driver)?;
let family_registry = build_loop_family_registry().map_err(|error| {
let family_registry = build_loop_family_registry_with_default_iteration_limit(
parts.config.planned_default_iteration_limit,
)
.map_err(|error| {
DefaultPlannedRuntimeBuildError::PlannedDriver(
DefaultPlannedDriverRegistrationError::DriverBuild(
AgentLoopDriverError::InvalidRequest {
Expand Down
Loading
Loading