*** Settings *** Documentation E2E test for Workflow Example 10: Full-Auto Batch Operations. ... ... A team reformats packages in a monorepo using the ``full-auto`` ... automation profile. Multiple plans run without human ... intervention (strategize → execute → apply automatically). ... Includes a deliberately broken action (non-existent LLM actor) ... to demonstrate batch error handling. ... ... Requires real LLM API keys — zero mocking. Library Collections Resource common_e2e.resource Suite Setup WF10 Suite Setup Suite Teardown E2E Suite Teardown *** Variables *** @{PACKAGE_NAMES} pkg_auth pkg_common pkg_billing ${ACTION_NAME} local/format-codebase ${PLAN_TIMEOUT} 180s *** Keywords *** WF10 Suite Setup [Documentation] E2E Suite Setup plus database initialisation. E2E Suite Setup # Initialise the database so CLI commands work in all tests. ${init}= Run CleverAgents Command init --force --yes Should Be Equal As Integers ${init.rc} 0 Create Package Directory [Documentation] Create a single package with badly-formatted Python files. [Arguments] ${monorepo} ${pkg_name} ${pkg_dir}= Set Variable ${monorepo}${/}${pkg_name} Create Directory ${pkg_dir}${/}src # __init__.py with extra blank lines and bad spacing ${init_content}= Set Variable ... \n\n\n"""${pkg_name} package."""\n\n\nimport os\nimport sys\nimport json\n\n\n__all__=["main"]\n Create File ${pkg_dir}${/}src${/}__init__.py ${init_content} # main.py with intentionally bad formatting: unsorted imports, extra spaces, long lines ${main_content}= Set Variable ... import json\nimport os\nimport sys\nfrom pathlib import Path\nimport re\n\n\ndef main( ):\n """Entry point with bad formatting."""\n x=1\n y = 2\n z=x+y\n data = {"key": "value", "another": "item"}\n return z\n\nif __name__=="__main__":\n main( )\n Create File ${pkg_dir}${/}src${/}main.py ${main_content} RETURN ${pkg_dir} Create Temp Monorepo [Documentation] Create a temporary monorepo with multiple badly-formatted packages. ... ... Each healthy package contains ``src/__init__.py`` and ``src/main.py`` ... with intentionally poor formatting (extra spaces, unsorted imports). ... Returns the path to the monorepo root and the detected branch name. ${monorepo}= Create Temp Git Repo wf10-monorepo FOR ${pkg_name} IN @{PACKAGE_NAMES} Create Package Directory ${monorepo} ${pkg_name} END # Commit all packages so git-checkout resources have content ${add_res}= Run Process git add . cwd=${monorepo} timeout=60s on_timeout=kill Should Be Equal As Integers ${add_res.rc} 0 git add failed: ${add_res.stderr} ${commit_res}= Run Process git commit -m Add packages with bad formatting cwd=${monorepo} timeout=60s on_timeout=kill Should Be Equal As Integers ${commit_res.rc} 0 git commit failed: ${commit_res.stderr} # Detect the actual default branch name (may be main or master) ${branch_result}= Run Process git rev-parse --abbrev-ref HEAD cwd=${monorepo} timeout=60s on_timeout=kill Should Be Equal As Integers ${branch_result.rc} 0 git rev-parse failed: ${branch_result.stderr} ${branch}= Strip String ${branch_result.stdout} Log Detected monorepo branch: ${branch} RETURN ${monorepo} ${branch} Write Action Config [Documentation] Write a formatting action YAML config with full-auto profile. ... ... Uses dynamic actor selection based on available API keys. ... Returns the path to the YAML file. # Pick an actor that matches the available API key ${has_anthropic}= Evaluate bool(__import__('os').environ.get('ANTHROPIC_API_KEY', '')) IF ${has_anthropic} ${actor}= Set Variable anthropic/claude-sonnet-4-20250514 ELSE ${actor}= Set Variable openai/gpt-4o END ${yaml_path}= Set Variable ${SUITE_HOME}${/}format_action.yaml ${config}= Catenate SEPARATOR=\n ... name: ${ACTION_NAME} ... description: "Reformat Python source files for consistent style" ... strategy_actor: ${actor} ... execution_actor: ${actor} ... definition_of_done: > ... All Python files are consistently formatted without creating new files. ... Creating .flake8, .pre-commit-config.yaml or a new pyproject.toml ... file is forbidden. ... automation_profile: full-auto ... reusable: true ... state: available ... read_only: false ... invariants: ... ${SPACE}${SPACE}- "Changes must be whitespace-only (no semantic modifications)" ... ${SPACE}${SPACE}- "Every package must pass its own test suite after formatting" Create File ${yaml_path} ${config}\n RETURN ${yaml_path} Clean Workspace Template Files [Documentation] Remove template files from the workspace and monorepo ... that the LLM may regenerate during formatting, to prevent ... add/add merge conflicts during plan apply. ... ... CleverAgents copies workspace template files into project ... directories during ``project create``, so this keyword ... must run **after** project registration and **before** ... plan launch. It also runs ``git clean -fd`` in the ... monorepo to remove any untracked files that were copied. [Arguments] ${target_dir}=${SUITE_HOME} @{conflicting}= Create List ... .flake8 ... .pre-commit-config.yaml ... pyproject.toml ... requirements-dev.txt ... requirements.txt ... setup.py ... setup.cfg ... tox.ini FOR ${file} IN @{conflicting} ${path}= Set Variable ${target_dir}${/}${file} Run Keyword And Ignore Error Remove File ${path} END # Also run git clean to remove any untracked files/directories that # the workspace template may have deposited in the monorepo. ${git_clean}= Run Process git clean -fd cwd=${target_dir} timeout=60s on_timeout=kill Log git clean in ${target_dir}: rc=${git_clean.rc} level=DEBUG Write Broken Action Config [Documentation] Write a deliberately broken action YAML that uses a non-existent ... LLM actor. Plans created with this action will fail during ... execution when the strategy/execution actor cannot be resolved. ${yaml_path}= Set Variable ${SUITE_HOME}${/}broken_action.yaml ${config}= Catenate SEPARATOR=\n ... name: local/broken-format ... description: "Deliberately broken action for error handling testing" ... strategy_actor: nonexistent/model-xyz-404 ... execution_actor: nonexistent/model-xyz-404 ... definition_of_done: "This action should always fail" ... automation_profile: full-auto ... reusable: true ... state: available ... read_only: false ... invariants: ... ${SPACE}${SPACE}- "No changes expected — action is broken" Create File ${yaml_path} ${config}\n RETURN ${yaml_path} Register Package Resources And Projects [Documentation] Register git-checkout resources and create projects for the ... specified packages. ... ... Error handling is tested separately via a broken action ... (non-existent LLM actor), not via missing resources. ... ... Resource/project names use fixed ``local/`` prefixes without ... UUID suffixes — safe because ``init --force --yes`` in suite setup ... resets the workspace database before each run. [Arguments] ${monorepo} ${branch} @{healthy_packages} FOR ${pkg_name} IN @{healthy_packages} # Register git-checkout resource pointing to the monorepo root ${res_result}= Run CleverAgents Command ... resource add git-checkout local/${pkg_name} ... --path ${monorepo} --branch ${branch} Log Resource ${pkg_name}: ${res_result.stdout} Should Not Contain ${res_result.stderr} Traceback ... Resource registration for ${pkg_name} produced Traceback:\n${res_result.stderr} # Create project linked to resource — must succeed WITHOUT Traceback. ${proj_result}= Run CleverAgents Command ... project create local/${pkg_name} ... --resource local/${pkg_name} Log Project ${pkg_name}: ${proj_result.stdout} Should Not Contain ${proj_result.stderr} Traceback ... Project creation for ${pkg_name} produced Traceback:\n${proj_result.stderr} END Launch Batch Plans [Documentation] Launch a plan for each package in full-auto mode. ... ... Returns a list of plan identifiers extracted from output. ... Uses ``expected_rc=None`` because broken packages may fail ... during plan use (which is expected behaviour). [Arguments] @{all_packages} @{plan_ids}= Create List FOR ${pkg_name} IN @{all_packages} ${result}= Run CleverAgents Command ... plan use ${ACTION_NAME} local/${pkg_name} ... --automation-profile full-auto --format plain ... timeout=${PLAN_TIMEOUT} expected_rc=None Log Plan use ${pkg_name} stdout: ${result.stdout} Log Plan use ${pkg_name} stderr: ${result.stderr} Should Not Contain ${result.stderr} Traceback ... plan use for ${pkg_name} produced Traceback:\n${result.stderr} # Extract plan ID from output — must find a valid ULID (Crockford Base32) ${combined}= Set Variable ${result.stdout} ${result.stderr} ${match}= Get Regexp Matches ${combined} ([0-9A-HJKMNP-TV-Z]{26}) flags=IGNORECASE ${match_count}= Get Length ${match} IF ${match_count} > 0 ${plan_id}= Set Variable ${match}[0] Append To List ${plan_ids} ${plan_id} Log Captured plan ID for ${pkg_name}: ${plan_id} ELSE Log No plan ID extracted for ${pkg_name} (rc=${result.rc}) — plan creation may have failed WARN END END RETURN @{plan_ids} Execute Batch Plans [Documentation] Execute each plan through the strategize→execute pipeline. ... ... ``plan execute`` runs the current plan phase synchronously. ... With the full-auto automation profile, a single ``plan execute`` ... call auto-advances through both strategize and execute phases, ... leaving the plan ready for ``plan apply --yes``. ... ... Plans that fail during execution (e.g. broken action with ... non-existent actor) are logged but do not abort the batch — ... the batch continues with remaining plans. ... ... Returns a list of plan IDs that completed execution ... successfully (candidates for apply). [Arguments] @{plan_ids} @{executed_ids}= Create List FOR ${plan_id} IN @{plan_ids} Log Executing plan ${plan_id} (strategize + execute via full-auto) ${exec}= Run CleverAgents Command ... plan execute ${plan_id} --format plain ... timeout=${PLAN_TIMEOUT} expected_rc=None Log Execute ${plan_id} rc=${exec.rc}: ${exec.stdout} IF ${exec.rc} != 0 Log Plan ${plan_id} failed during execution (rc=${exec.rc}): ${exec.stderr} WARN CONTINUE END Append To List ${executed_ids} ${plan_id} END RETURN @{executed_ids} Apply Batch Plans [Documentation] Apply each successfully-executed plan via ``plan apply --yes``. ... ... After ``plan execute`` with full-auto profile, plans are in ... the ``execute/complete`` state. ``plan apply --yes`` performs ... the actual application (e.g. committing changes to the repo) ... and completes the apply phase, transitioning the plan to the ... ``applied`` processing state. ... ... Note: ``plan lifecycle-apply`` only transitions the plan INTO ... the apply phase (``apply/queued``) without completing it. ... ``plan apply --yes`` is required to actually run and complete ... the apply step. ... ... Plans that fail during apply are logged but do not abort ... the batch. Returns a list of plan IDs that were applied. [Arguments] @{executed_ids} @{applied_ids}= Create List FOR ${plan_id} IN @{executed_ids} Log Applying plan ${plan_id} ${apply}= Run CleverAgents Command ... plan apply --yes ${plan_id} --format plain ... timeout=${PLAN_TIMEOUT} expected_rc=None Log Apply ${plan_id} rc=${apply.rc}: ${apply.stdout} IF ${apply.rc} != 0 Log Plan ${plan_id} failed during apply (rc=${apply.rc}) stdout: ${apply.stdout} WARN Log Plan ${plan_id} failed during apply (rc=${apply.rc}) stderr: ${apply.stderr} WARN CONTINUE END Append To List ${applied_ids} ${plan_id} END RETURN @{applied_ids} *** Test Cases *** Workflow 10 Full-Auto Batch Formatting [Documentation] End-to-end test for full-auto batch formatting across ... multiple packages in a monorepo, including error handling ... when one plan fails due to a broken action. ... ... 1. Creates a monorepo with 3 badly-formatted Python packages ... 2. Registers a reusable formatting action with full-auto profile ... 3. Registers a broken action (non-existent LLM actor) for error testing ... 4. Registers resources and projects for healthy packages ... 5. Creates plans in full-auto mode via ``plan use`` ... 6. Executes all plans via ``plan execute`` (strategize + execute) ... 7. Applies successful plans via ``plan apply --yes`` ... 8. Verifies batch results via ``plan list`` with state filters ... 9. Verifies error handling — broken action's plan fails during execution [Tags] E2E [Timeout] 25 minutes [Teardown] Run CleverAgents Command config set core.automation-profile manual expected_rc=None Skip If No LLM Keys # Prevent add/add merge conflicts during plan apply by removing workspace # template files that the LLM may regenerate. Clean Workspace Template Files # --- Step 1: Create temp monorepo with badly-formatted packages --- ${monorepo} ${branch}= Create Temp Monorepo Log Monorepo created at: ${monorepo} (branch: ${branch}) Directory Should Exist ${monorepo}${/}pkg_auth${/}src Directory Should Exist ${monorepo}${/}pkg_common${/}src Directory Should Exist ${monorepo}${/}pkg_billing${/}src # --- Step 2: Create the formatting action with full-auto profile --- ${yaml_path}= Write Action Config File Should Exist ${yaml_path} ${action_result}= Run CleverAgents Command ... action create --config ${yaml_path} Log Action create output: ${action_result.stdout} Should Not Contain ${action_result.stderr} Traceback Output Should Contain ${action_result} format-codebase # Also create a broken action with a non-existent actor for error handling ${broken_action}= Write Broken Action Config ${broken_action_result}= Run CleverAgents Command ... action create --config ${broken_action} Log Broken action create output: ${broken_action_result.stdout} Output Should Contain ${broken_action_result} broken-format # --- Step 3: Register resources and projects for all packages --- Register Package Resources And Projects ${monorepo} ${branch} @{PACKAGE_NAMES} # Clean workspace template files that were copied into the monorepo # during project creation, to prevent add/add merge conflicts during apply. Clean Workspace Template Files ${monorepo} # --- Step 4: Create plans — healthy + broken --- # 4a: Launch plans for healthy packages with the good action @{plan_ids}= Launch Batch Plans @{PACKAGE_NAMES} ${plan_count}= Get Length ${plan_ids} Log Healthy plan IDs (${plan_count}): @{plan_ids} Should Be True ${plan_count} == 3 ... Expected 3 healthy plan IDs but got ${plan_count} # 4b: Launch plan for first healthy package but with BROKEN action # (non-existent actor will cause execution to fail) ${broken_result}= Run CleverAgents Command ... plan use local/broken-format local/pkg_auth ... --automation-profile full-auto --format plain ... timeout=${PLAN_TIMEOUT} expected_rc=None Log Broken action plan use rc=${broken_result.rc}: ${broken_result.stdout} Log Broken action plan use stderr: ${broken_result.stderr} Should Not Contain ${broken_result.stderr} Traceback ${broken_plan_failed_at_creation}= Evaluate ${broken_result.rc} != 0 ${broken_plan_id}= Set Variable ${EMPTY} IF not ${broken_plan_failed_at_creation} # Extract plan ID for the broken plan ${combined}= Set Variable ${broken_result.stdout} ${broken_result.stderr} ${match}= Get Regexp Matches ${combined} ([0-9A-HJKMNP-TV-Z]{26}) flags=IGNORECASE ${match_count}= Get Length ${match} IF ${match_count} > 0 ${broken_plan_id}= Set Variable ${match}[0] Append To List ${plan_ids} ${broken_plan_id} Log Broken plan ID captured: ${broken_plan_id} END ELSE Log Broken plan failed at creation (rc=${broken_result.rc}) END # --- Step 5: Execute all plans (strategize + execute phases) --- @{executed_ids}= Execute Batch Plans @{plan_ids} ${executed_count}= Get Length ${executed_ids} ${total_plan_count_at_execute}= Get Length ${plan_ids} Log Plans that completed execution: ${executed_count} / ${total_plan_count_at_execute} # --- Step 6: Apply successfully-executed plans --- @{applied_ids}= Apply Batch Plans @{executed_ids} ${applied_count}= Get Length ${applied_ids} Log Plans that reached applied state: ${applied_count} / ${executed_count} # --- Step 7: Verify batch results via plan list --- # 7a: Unfiltered listing — smoke test and verify healthy plan IDs appear ${list_result}= Run CleverAgents Command ... plan list --format plain ... timeout=30s Log Final plan list stdout: ${list_result.stdout} Log Final plan list stderr: ${list_result.stderr} Should Not Contain ${list_result.stderr} Traceback FOR ${pid} IN @{applied_ids} Should Contain ${list_result.stdout} ${pid} ... Applied plan ID ${pid} not found in plan list output END # 7b: Filtered listing — verify --state applied returns successful plans ${applied_list}= Run CleverAgents Command ... plan list --state applied --format plain ... timeout=30s Log Applied plan list stdout: ${applied_list.stdout} ${applied_matches}= Get Regexp Matches ${applied_list.stdout} ... processing_state:\\s*applied ${success_count}= Get Length ${applied_matches} Log Plans in 'applied' state: ${success_count} # At least 2 of 3 healthy packages must reach 'applied' state. # Using >= 2 (not == 3) because LLM-generated changes can occasionally fail # during apply (e.g. merge conflicts, empty changesets from the LLM producing # no edits). Requiring >= 2 verifies the batch mechanism works while # tolerating one transient apply failure. Should Be True ${success_count} >= 2 ... Expected at least 2 plans (of 3 healthy) to reach 'applied' state but found ${success_count} # --- Step 8: Verify error handling for the broken action --- # Count how many plans failed during execution (didn't make it to executed_ids) ${total_plan_count}= Get Length ${plan_ids} ${failed_execution_count}= Evaluate ${total_plan_count} - ${executed_count} Log Plans that failed during execution: ${failed_execution_count} # Also check for errored plans via --state errored filter ${errored_list}= Run CleverAgents Command ... plan list --state errored --format plain ... timeout=30s Log Errored plan list stdout: ${errored_list.stdout} ${errored_matches}= Get Regexp Matches ${errored_list.stdout} ... processing_state:\\s*errored ${error_count}= Get Length ${errored_matches} Log Plans in 'errored' state: ${error_count} # The broken action (non-existent actor) should cause at least one failure. # Error handling is demonstrated if ANY of the following hold: # (a) broken action's plan use failed (rc != 0) # (b) the broken plan's ID is NOT in executed_ids (failed during execution) # (c) the broken plan's ID appears in the errored list IF ${broken_plan_failed_at_creation} Log Error handling demonstrated: broken plan failed at creation (rc != 0) ELSE IF "${broken_plan_id}" != "${EMPTY}" # Verify the specific broken plan ID either did NOT complete execution # or appears in the errored list ${broken_in_executed}= Evaluate """${broken_plan_id}""" in ${executed_ids} ${broken_in_errored}= Evaluate """${broken_plan_id}""" in """${errored_list.stdout}""" ${broken_failed}= Evaluate not ${broken_in_executed} or ${broken_in_errored} Should Be True ${broken_failed} ... Broken plan ${broken_plan_id} should have failed but was found in executed_ids and not in errored list Log Error handling demonstrated: broken plan ${broken_plan_id} failed (not in executed=${broken_in_executed}, in errored=${broken_in_errored}) ELSE # Fallback: general failure count check ${broken_demonstrated}= Evaluate ... ${error_count} >= 1 or ${failed_execution_count} >= 1 Should Be True ${broken_demonstrated} ... Error handling not demonstrated: 0 errored, 0 failed execution END