From 38fa155e66eb5a7e5299f0ca562599db8d7f4760 Mon Sep 17 00:00:00 2001 From: HAL9000 Date: Tue, 28 Apr 2026 10:42:53 +0000 Subject: [PATCH 1/7] fix(actor): Get responses from actor-run Built-in actors generated from the provider registry have a config_blob with provider and model fields but no type field. When this raw blob is serialised to YAML and fed to ReactiveConfigParser, the parser produces an empty ReactiveConfig with no agents and no routes, causing run_single_shot() to return empty string (bug #10861). Fix: resolve_config_files now synthesises a minimal v3 type: llm YAML when the actor has no yaml_text and the config_blob has provider and model but no type field. This allows the reactive config parser to create a working agent and graph route, enabling the LLM to be invoked and its response returned to the caller. ISSUES CLOSED: #10861 --- .../steps/tdd_actor_run_response_steps.py | 148 ++++++++++++++++++ features/tdd_actor_run_response.feature | 30 ++++ .../cli/commands/_resolve_actor.py | 70 +++++++-- 3 files changed, 239 insertions(+), 9 deletions(-) create mode 100644 features/steps/tdd_actor_run_response_steps.py create mode 100644 features/tdd_actor_run_response.feature diff --git a/features/steps/tdd_actor_run_response_steps.py b/features/steps/tdd_actor_run_response_steps.py new file mode 100644 index 000000000..85c840611 --- /dev/null +++ b/features/steps/tdd_actor_run_response_steps.py @@ -0,0 +1,148 @@ +"""Step definitions for TDD Bug #10861 - agents actor run returns nothing. + +These steps verify that resolve_config_files synthesises a v3 type: llm YAML +when the actor has a built-in config_blob with provider and model but no type +field. This is the regression guard for bug #10861. +""" + +from __future__ import annotations + +import yaml +from pathlib import Path +from unittest.mock import MagicMock, patch + +from behave import given, then, when # type: ignore[import-untyped] +from behave.runner import Context # type: ignore[import-untyped] + +from cleveragents.cli.commands._resolve_actor import resolve_config_files + + +@given("a built-in actor with provider and model but no type field for tdd-10861") +def step_given_builtin_actor(context: Context) -> None: + """Set up a mock built-in actor with provider/model but no type field.""" + mock_actor = MagicMock() + mock_actor.name = "anthropic/claude-sonnet-4-20250514" + mock_actor.yaml_text = "" + mock_actor.config_blob = { + "provider": "anthropic", + "model": "claude-sonnet-4-20250514", + "capabilities": {}, + "unsafe": False, + "source": "provider-registry", + } + mock_registry = MagicMock() + mock_registry.get.return_value = mock_actor + mock_container = MagicMock() + mock_container.actor_registry.return_value = mock_registry + context.mock_actor = mock_actor + context.mock_container = mock_container + + +@given("an actor with existing yaml_text for tdd-10861") +def step_given_actor_with_yaml_text(context: Context) -> None: + """Set up a mock actor that already has yaml_text.""" + mock_actor = MagicMock() + mock_actor.name = "local/my-custom-actor" + mock_actor.yaml_text = "name: local/my-custom-actor\ntype: llm\nprovider: openai\nmodel: gpt-4\n" + mock_actor.config_blob = None + mock_registry = MagicMock() + mock_registry.get.return_value = mock_actor + mock_container = MagicMock() + mock_container.actor_registry.return_value = mock_registry + context.mock_actor = mock_actor + context.mock_container = mock_container + + +@when("resolve_config_files is called with the built-in actor name for tdd-10861") +def step_when_resolve_builtin(context: Context) -> None: + """Call resolve_config_files with the built-in actor name.""" + with patch( + "cleveragents.cli.commands._resolve_actor.get_container", + return_value=context.mock_container, + ): + context.result_paths = resolve_config_files( + "anthropic/claude-sonnet-4-20250514", [] + ) + context.add_cleanup( + lambda: [p.unlink(missing_ok=True) for p in context.result_paths] + ) + + +@when("resolve_config_files is called with the actor name for tdd-10861") +def step_when_resolve_actor(context: Context) -> None: + """Call resolve_config_files with the actor name.""" + with patch( + "cleveragents.cli.commands._resolve_actor.get_container", + return_value=context.mock_container, + ): + context.result_paths = resolve_config_files("local/my-custom-actor", []) + context.add_cleanup( + lambda: [p.unlink(missing_ok=True) for p in context.result_paths] + ) + + +@then("the resulting YAML file contains type llm for tdd-10861") +def step_then_yaml_contains_type_llm(context: Context) -> None: + """Assert the synthesised YAML contains type: llm.""" + assert len(context.result_paths) == 1 + tmp_path: Path = context.result_paths[0] + assert tmp_path.exists(), f"Temp file does not exist: {tmp_path}" + content = tmp_path.read_text(encoding="utf-8") + parsed = yaml.safe_load(content) + assert isinstance(parsed, dict), f"Expected dict, got {type(parsed)}" + assert parsed.get("type") == "llm", ( + "Expected type: llm in synthesised YAML, got: " + + str(parsed.get("type")) + + "\nFull content:\n" + + content + ) + + +@then("the resulting YAML file contains the provider and model for tdd-10861") +def step_then_yaml_contains_provider_model(context: Context) -> None: + """Assert the synthesised YAML contains the correct provider and model.""" + tmp_path: Path = context.result_paths[0] + content = tmp_path.read_text(encoding="utf-8") + parsed = yaml.safe_load(content) + assert parsed.get("provider") == "anthropic", ( + "Expected provider: anthropic, got: " + str(parsed.get("provider")) + ) + assert parsed.get("model") == "claude-sonnet-4-20250514", ( + "Expected model: claude-sonnet-4-20250514, got: " + str(parsed.get("model")) + ) + + +@then("the resulting YAML file is parseable as a v3 llm actor config for tdd-10861") +def step_then_yaml_parseable_as_v3(context: Context) -> None: + """Assert the synthesised YAML is parseable by ReactiveConfigParser.""" + from cleveragents.reactive.config_parser import ReactiveConfigParser + + tmp_path: Path = context.result_paths[0] + parser = ReactiveConfigParser() + rc = parser.parse_files([tmp_path]) + + assert rc.agents, ( + "ReactiveConfigParser produced no agents from synthesised YAML. " + "This means run_single_shot() would return empty string (bug #10861)." + ) + assert rc.routes, ( + "ReactiveConfigParser produced no routes from synthesised YAML. " + "This means run_single_shot() would return empty string (bug #10861)." + ) + + +@then("the original yaml_text is used without modification for tdd-10861") +def step_then_original_yaml_used(context: Context) -> None: + """Assert that actors with existing yaml_text are not affected by the fix.""" + tmp_path: Path = context.result_paths[0] + assert tmp_path.exists(), f"Temp file does not exist: {tmp_path}" + content = tmp_path.read_text(encoding="utf-8") + assert "local/my-custom-actor" in content, ( + "Expected original yaml_text content, got: " + content + ) + assert "type: llm" in content, ( + "Expected type: llm from original yaml_text, got: " + content + ) + assert "provider: openai" in content, ( + "Expected provider: openai from original yaml_text, got: " + content + ) diff --git a/features/tdd_actor_run_response.feature b/features/tdd_actor_run_response.feature new file mode 100644 index 000000000..c42ad24e8 --- /dev/null +++ b/features/tdd_actor_run_response.feature @@ -0,0 +1,30 @@ +@tdd_issue @tdd_issue_10861 +Feature: TDD Bug #10861 - agents actor run returns nothing for built-in LLM actors + + Bug #10861 reports that running agents actor run with a built-in LLM actor + returns nothing instead of a response from the LLM. + + Root cause: built-in actors have a config_blob with provider and model + fields but no type field. When serialised to YAML and fed to + ReactiveConfigParser, the parser produces an empty ReactiveConfig with no + agents and no routes, causing run_single_shot() to return empty string. + + Fix: resolve_config_files now synthesises a minimal v3 type: llm YAML + when the actor has no yaml_text and the config_blob has provider and model + but no type field. + + Scenario: resolve_config_files synthesises v3 llm YAML for built-in actor + Given a built-in actor with provider and model but no type field for tdd-10861 + When resolve_config_files is called with the built-in actor name for tdd-10861 + Then the resulting YAML file contains type llm for tdd-10861 + And the resulting YAML file contains the provider and model for tdd-10861 + + Scenario: synthesised YAML is parseable by ReactiveConfigParser for tdd-10861 + Given a built-in actor with provider and model but no type field for tdd-10861 + When resolve_config_files is called with the built-in actor name for tdd-10861 + Then the resulting YAML file is parseable as a v3 llm actor config for tdd-10861 + + Scenario: actor with existing yaml_text is not affected by the fix for tdd-10861 + Given an actor with existing yaml_text for tdd-10861 + When resolve_config_files is called with the actor name for tdd-10861 + Then the original yaml_text is used without modification for tdd-10861 diff --git a/src/cleveragents/cli/commands/_resolve_actor.py b/src/cleveragents/cli/commands/_resolve_actor.py index a78259e07..9a7f0b343 100644 --- a/src/cleveragents/cli/commands/_resolve_actor.py +++ b/src/cleveragents/cli/commands/_resolve_actor.py @@ -19,6 +19,7 @@ from __future__ import annotations import atexit import tempfile from pathlib import Path +from typing import Any import typer import yaml @@ -52,6 +53,44 @@ def _sanitize_name(name: str) -> str: return "".join(c for c in name if c.isprintable()) + + +def _synthesize_llm_yaml(actor_name: str, config_blob: dict[str, Any]) -> str: + """Synthesize a v3 type: llm YAML from a built-in actor config blob. + + Built-in actors generated from the provider registry have a config_blob + with provider and model fields but no type field. When this raw blob is + serialised to YAML and fed to ReactiveConfigParser, the parser finds no + type, no agents/actors map, and no routes key so it produces an empty + ReactiveConfig with no agents and no routes. run_single_shot() then + returns empty string because there is nothing to execute (fix #10861). + + Args: + actor_name: The namespaced actor name. + config_blob: The actor canonical configuration blob from the registry. + + Returns: + A YAML string in v3 type: llm format that the reactive config + parser can consume to produce a working single-agent graph route. + """ + provider = str(config_blob.get("provider") or "") + model = str(config_blob.get("model") or "") + + v3_blob: dict[str, Any] = { + "name": actor_name, + "type": "llm", + "description": f"Built-in LLM actor for {provider}/{model}", + "provider": provider, + "model": model, + } + + system_prompt = config_blob.get("system_prompt") + if system_prompt: + v3_blob["system_prompt"] = system_prompt + + return yaml.safe_dump(v3_blob, default_flow_style=False, sort_keys=False) + + def resolve_config_files(name: str, config: list[Path]) -> list[Path]: """Return config file paths, resolving *name* from the actor registry when *config* is empty. @@ -102,15 +141,28 @@ def resolve_config_files(name: str, config: list[Path]) -> list[Path]: err=True, ) raise typer.Exit(code=2) - try: - yaml_text = yaml.safe_dump(config_blob, default_flow_style=False) - except yaml.YAMLError: - typer.echo( - f"Error: Actor '{safe_name}' config_blob could not be " - "serialised to YAML.", - err=True, - ) - raise typer.Exit(code=2) from None + # Fix #10861: built-in actors have a config_blob with provider + # and model but no type field. Serialising this blob as-is + # produces YAML that the reactive config parser cannot interpret + # (no agents, no routes -> empty ReactiveConfig -> empty response). + # Synthesise a v3 type: llm YAML so the parser can create a + # working agent and graph route. + if ( + config_blob.get("provider") + and config_blob.get("model") + and not config_blob.get("type") + ): + yaml_text = _synthesize_llm_yaml(actor.name, config_blob) + else: + try: + yaml_text = yaml.safe_dump(config_blob, default_flow_style=False) + except yaml.YAMLError: + typer.echo( + f"Error: Actor '{safe_name}' config_blob could not be " + "serialised to YAML.", + err=True, + ) + raise typer.Exit(code=2) from None with tempfile.NamedTemporaryFile( delete=False, suffix=".yaml", mode="w", encoding="utf-8" -- 2.52.0 From 0b2c32cc543e75d61e889d3fc840133f1f245f5d Mon Sep 17 00:00:00 2001 From: CleverThis Date: Tue, 28 Apr 2026 13:03:42 +0000 Subject: [PATCH 2/7] style(actor): fix ruff format violations in actor-run fix Apply ruff format to resolve CI lint failures: - Remove extra blank lines in _resolve_actor.py - Reformat long string literal in tdd_actor_run_response_steps.py ISSUES CLOSED: #10861 --- features/steps/tdd_actor_run_response_steps.py | 4 +++- src/cleveragents/cli/commands/_resolve_actor.py | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/features/steps/tdd_actor_run_response_steps.py b/features/steps/tdd_actor_run_response_steps.py index 85c840611..e1601a260 100644 --- a/features/steps/tdd_actor_run_response_steps.py +++ b/features/steps/tdd_actor_run_response_steps.py @@ -43,7 +43,9 @@ def step_given_actor_with_yaml_text(context: Context) -> None: """Set up a mock actor that already has yaml_text.""" mock_actor = MagicMock() mock_actor.name = "local/my-custom-actor" - mock_actor.yaml_text = "name: local/my-custom-actor\ntype: llm\nprovider: openai\nmodel: gpt-4\n" + mock_actor.yaml_text = ( + "name: local/my-custom-actor\ntype: llm\nprovider: openai\nmodel: gpt-4\n" + ) mock_actor.config_blob = None mock_registry = MagicMock() mock_registry.get.return_value = mock_actor diff --git a/src/cleveragents/cli/commands/_resolve_actor.py b/src/cleveragents/cli/commands/_resolve_actor.py index 9a7f0b343..b34d004b8 100644 --- a/src/cleveragents/cli/commands/_resolve_actor.py +++ b/src/cleveragents/cli/commands/_resolve_actor.py @@ -53,8 +53,6 @@ def _sanitize_name(name: str) -> str: return "".join(c for c in name if c.isprintable()) - - def _synthesize_llm_yaml(actor_name: str, config_blob: dict[str, Any]) -> str: """Synthesize a v3 type: llm YAML from a built-in actor config blob. -- 2.52.0 From b9eebb6c10c4093ff5052ffc81f5eba8bcbfff45 Mon Sep 17 00:00:00 2001 From: CleverThis Date: Tue, 28 Apr 2026 14:30:22 +0000 Subject: [PATCH 3/7] docs(changelog): add entry for fix(actor): Get responses from actor-run (#10861) --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b34b5ec4a..6cb621ce5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,19 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). validate-then-write approach: all model validation occurs in Phase 1, and state mutations only happen in Phase 2 after all validations succeed. +- **`agents actor run` empty response for built-in LLM actors** (#10861): Fixed + `resolve_config_files` in `cli/commands/_resolve_actor.py` silently returning + empty output when invoked with a built-in actor name (e.g. + `anthropic/claude-sonnet-4-20250514`). Built-in actors generated from the + provider registry have a `config_blob` with `provider` and `model` fields but + no `type` field. Serialising this blob as-is produced YAML that + `ReactiveConfigParser` could not interpret (no agents, no routes → empty + `ReactiveConfig` → empty response). Fix: `_synthesize_llm_yaml()` now + synthesises a minimal v3 `type: llm` YAML when the actor has no `yaml_text` + and the `config_blob` has `provider` and `model` but no `type` field, allowing + the reactive config parser to create a working agent and graph route. BDD + regression coverage in `features/tdd_actor_run_response.feature`. + - **ReactiveConfigParser route synthesis for v3 actors** (#10807): Fixed `agents actor run` silently returning empty output for v3 `type:llm` actors. `_build_from_v3()` and `_build()` now synthesise a default single-node -- 2.52.0 From e249afa30e5b5320465e61e95dd57100f18d7df5 Mon Sep 17 00:00:00 2001 From: "Brent E. Edwards" Date: Mon, 4 May 2026 22:51:39 +0000 Subject: [PATCH 4/7] fix(wf10_batch): fix add/add conflict Closes: #10861 --- .forgejo/workflows/ci.yml | 6 ++++-- robot/e2e/wf10_batch.robot | 24 +++++++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 57ef6794d..40acf9eb1 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -327,11 +327,13 @@ jobs: GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} - name: Upload E2E tests log artifact - if: always() + if: failure() uses: actions/upload-artifact@v3 with: name: ci-logs-e2e-tests - path: build/nox-e2e-tests-output.log + path: | + build/nox-e2e-tests-output.log + build/reports/robot-e2e/ retention-days: 30 coverage: diff --git a/robot/e2e/wf10_batch.robot b/robot/e2e/wf10_batch.robot index 8786a0568..f8441ba2a 100644 --- a/robot/e2e/wf10_batch.robot +++ b/robot/e2e/wf10_batch.robot @@ -92,6 +92,23 @@ Write Action Config Create File ${yaml_path} ${config}\n RETURN ${yaml_path} +Clean Workspace Template Files + [Documentation] Remove template files from the workspace that the LLM + ... may regenerate during formatting, to prevent add/add + ... merge conflicts during plan apply. + @{conflicting}= Create List + ... .pre-commit-config.yaml + ... pyproject.toml + ... requirements-dev.txt + ... requirements.txt + ... setup.py + ... setup.cfg + ... tox.ini + FOR ${file} IN @{conflicting} + ${path}= Set Variable ${SUITE_HOME}${/}${file} + Run Keyword And Ignore Error Remove File ${path} + END + 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 @@ -226,7 +243,8 @@ Apply Batch Plans ... 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}): ${apply.stderr} WARN + 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} @@ -253,6 +271,10 @@ Workflow 10 Full-Auto Batch Formatting [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}) -- 2.52.0 From 61d00ef037f96f5f3476433dcebbc66081084598 Mon Sep 17 00:00:00 2001 From: "Brent E. Edwards" Date: Mon, 4 May 2026 23:09:47 +0000 Subject: [PATCH 5/7] fix(forgejo): changing from "uv=0.8.0" to "uv==0.8.0" --- .forgejo/workflows/benchmark-scheduled.yml | 4 ++-- .forgejo/workflows/master.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/benchmark-scheduled.yml b/.forgejo/workflows/benchmark-scheduled.yml index 04f7de49f..8a19081c5 100644 --- a/.forgejo/workflows/benchmark-scheduled.yml +++ b/.forgejo/workflows/benchmark-scheduled.yml @@ -41,7 +41,7 @@ jobs: - name: Install uv and nox run: | - pip install -q uv=${{ env.UV_VERSION }} nox + pip install -q uv==${{ env.UV_VERSION }} nox - name: Cache uv packages uses: actions/cache@v3 @@ -126,7 +126,7 @@ jobs: - name: Install uv and nox run: | - pip install -q uv=${{ env.UV_VERSION }} nox + pip install -q uv==${{ env.UV_VERSION }} nox - name: Cache uv packages uses: actions/cache@v3 diff --git a/.forgejo/workflows/master.yml b/.forgejo/workflows/master.yml index 522496ddd..7c959ba40 100644 --- a/.forgejo/workflows/master.yml +++ b/.forgejo/workflows/master.yml @@ -92,7 +92,7 @@ jobs: - name: Install dependencies run: | python -m pip install -U pip - python -m pip install asv virtualenv uv=${{ env.UV_VERSION }} nox + python -m pip install asv virtualenv uv==${{ env.UV_VERSION }} nox - name: Sync prior benchmark results from S3 env: -- 2.52.0 From 1932bed2a85f7632fe71503ee2bc871206782a91 Mon Sep 17 00:00:00 2001 From: "Brent E. Edwards" Date: Mon, 4 May 2026 23:41:51 +0000 Subject: [PATCH 6/7] fix(forgejo): remove `harbor.cleverthis.com` from `docker:dind` Fixes: #10861 --- .forgejo/workflows/ci.yml | 2 +- .forgejo/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 40acf9eb1..ab6842d8e 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -446,7 +446,7 @@ jobs: needs: [lint, typecheck, security, quality, unit_tests] runs-on: docker container: - image: ${{vars.docker_prefix}}docker:dind + image: docker:dind options: --privileged steps: - name: Start Docker daemon and install dependencies diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index fef31e6bb..ed4ac7289 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -45,7 +45,7 @@ jobs: build-docker: runs-on: docker container: - image: ${{vars.docker_prefix}}docker:dind + image: docker:dind options: --privileged needs: [build-wheel] steps: -- 2.52.0 From 57930c9fb3a594728aee3488ae8ac7bc87519957 Mon Sep 17 00:00:00 2001 From: "Brent E. Edwards" Date: Tue, 5 May 2026 00:38:44 +0000 Subject: [PATCH 7/7] fix(wf10): fixing more of the add/add problems Closes #10861 --- robot/e2e/wf10_batch.robot | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/robot/e2e/wf10_batch.robot b/robot/e2e/wf10_batch.robot index f8441ba2a..94d2e2fa0 100644 --- a/robot/e2e/wf10_batch.robot +++ b/robot/e2e/wf10_batch.robot @@ -93,10 +93,18 @@ Write Action Config RETURN ${yaml_path} Clean Workspace Template Files - [Documentation] Remove template files from the workspace that the LLM - ... may regenerate during formatting, to prevent add/add - ... merge conflicts during plan apply. + [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 @@ -105,9 +113,13 @@ Clean Workspace Template Files ... setup.cfg ... tox.ini FOR ${file} IN @{conflicting} - ${path}= Set Variable ${SUITE_HOME}${/}${file} + ${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 @@ -301,6 +313,10 @@ Workflow 10 Full-Auto Batch Formatting # --- 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} -- 2.52.0