From 1551c6e41d04b480b02772fe7b9402cb7d0940e8 Mon Sep 17 00:00:00 2001 From: Repository Isolator Date: Sun, 19 Apr 2026 02:52:57 +0000 Subject: [PATCH 1/4] docs(showcase): add REPL and actor run CLI showcase - Register REPL and actor run showcase in examples.json - Add BDD tests for showcase documentation structure - Verify markdown file exists and is properly formatted - Validate JSON metadata for showcase entry - Test documented commands and content sections Closes #7552 --- docs/showcase/examples.json | 21 ++ features/showcase_repl_actor_run.feature | 80 +++++++ .../steps/showcase_repl_actor_run_steps.py | 206 ++++++++++++++++++ 3 files changed, 307 insertions(+) create mode 100644 features/showcase_repl_actor_run.feature create mode 100644 features/steps/showcase_repl_actor_run_steps.py diff --git a/docs/showcase/examples.json b/docs/showcase/examples.json index bb3d9b77f..1af8e11d9 100644 --- a/docs/showcase/examples.json +++ b/docs/showcase/examples.json @@ -21,6 +21,27 @@ "generated_by": "uat-tester", "generated_at": "2026-04-07" }, + { + "title": "REPL and Actor Run: Interactive AI Sessions from the Terminal", + "category": "cli-tools", + "path": "cli-tools/repl-and-actor-run.md", + "feature": "Interactive REPL and single-shot actor run commands", + "commands": [ + "agents repl", + "agents repl --help", + "agents actor run openai/gpt-4o \"Say hello\"", + "agents actor run --help", + "agents actor run local/demo-assistant \"What is the capital of France?\" --config my-assistant.yaml", + "agents actor run local/demo-assistant \"What is the capital of France?\" --config my-assistant.yaml --output answer.txt", + "agents actor run local/demo-assistant \"Write a haiku about mountains\" --config my-assistant.yaml --temperature 0.9", + "agents actor run local/demo-assistant \"I'm working on a Python project\" --config my-assistant.yaml --context my-session --context-dir /tmp/my-contexts", + "agents actor run local/demo-assistant \"What are best practices for error handling?\" --config my-assistant.yaml --context my-session --context-dir /tmp/my-contexts" + ], + "complexity": "intermediate", + "educational_value": "high", + "generated_by": "uat-tester", + "generated_at": "2026-04-07" + }, { "title": "Managing AI Actors with the CleverAgents CLI", "category": "cli-tools", diff --git a/features/showcase_repl_actor_run.feature b/features/showcase_repl_actor_run.feature new file mode 100644 index 000000000..d608d098e --- /dev/null +++ b/features/showcase_repl_actor_run.feature @@ -0,0 +1,80 @@ +Feature: REPL and Actor Run CLI Showcase Documentation + The showcase documentation for REPL and actor run CLI commands + should be properly registered and accessible. + + Scenario: Showcase markdown file exists + Given the showcase directory exists + When I check for the REPL and actor run showcase file + Then the file should exist at "docs/showcase/cli-tools/repl-and-actor-run.md" + + Scenario: Showcase is registered in examples.json + Given the examples.json file exists + When I check for the REPL and actor run showcase entry + Then the entry should have title "REPL and Actor Run: Interactive AI Sessions from the Terminal" + And the entry should have category "cli-tools" + And the entry should have path "cli-tools/repl-and-actor-run.md" + And the entry should have complexity "intermediate" + + Scenario: Showcase has required commands documented + Given the showcase markdown file exists + When I check the documented commands + Then the file should contain "agents repl" + And the file should contain "agents actor run" + And the file should contain "agents repl --help" + And the file should contain "agents actor run --help" + + Scenario: Showcase has REPL section + Given the showcase markdown file exists + When I check the content structure + Then the file should contain "Part 1: The Interactive REPL" + And the file should contain ":help" + And the file should contain ":exit" + And the file should contain "!!" + + Scenario: Showcase has Actor Run section + Given the showcase markdown file exists + When I check the content structure + Then the file should contain "Part 2: Single-Shot Actor Run" + And the file should contain "--config" + And the file should contain "--output" + And the file should contain "--temperature" + And the file should contain "--context" + + Scenario: Showcase has real output examples + Given the showcase markdown file exists + When I check for verified output + Then the file should contain "Actual Output:" + And the file should contain "verified" + + Scenario: Examples.json has valid JSON structure + Given the examples.json file exists + When I parse the JSON + Then the JSON should be valid + And the JSON should have "examples" key + And the JSON should have "categories" key + + Scenario: Showcase entry has all required fields + Given the examples.json file exists + When I check the REPL and actor run entry + Then the entry should have "title" field + And the entry should have "category" field + And the entry should have "path" field + And the entry should have "feature" field + And the entry should have "commands" field + And the entry should have "complexity" field + And the entry should have "educational_value" field + + Scenario: Showcase commands list is not empty + Given the examples.json file exists + When I check the REPL and actor run entry + Then the commands list should have at least 5 items + And the commands should include "agents repl" + And the commands should include "agents actor run" + + Scenario: Showcase file has proper markdown formatting + Given the showcase markdown file exists + When I check the markdown structure + Then the file should start with a heading + And the file should have multiple sections + And the file should have code blocks + And the file should have proper link formatting diff --git a/features/steps/showcase_repl_actor_run_steps.py b/features/steps/showcase_repl_actor_run_steps.py new file mode 100644 index 000000000..f5cb1c17e --- /dev/null +++ b/features/steps/showcase_repl_actor_run_steps.py @@ -0,0 +1,206 @@ +"""Steps for REPL and Actor Run CLI Showcase Documentation tests.""" + +import json +import os +from pathlib import Path +from typing import Any + +from behave import given, when, then + + +@given("the showcase directory exists") +def step_showcase_directory_exists(context: Any) -> None: + """Verify the showcase directory exists.""" + showcase_dir = Path("docs/showcase") + assert showcase_dir.exists(), f"Showcase directory not found at {showcase_dir}" + context.showcase_dir = showcase_dir + + +@given("the examples.json file exists") +def step_examples_json_exists(context: Any) -> None: + """Verify examples.json exists.""" + examples_file = Path("docs/showcase/examples.json") + assert examples_file.exists(), f"examples.json not found at {examples_file}" + context.examples_file = examples_file + + # Load the JSON for later use + with open(examples_file, "r") as f: + context.examples_data = json.load(f) + + +@given("the showcase markdown file exists") +def step_showcase_markdown_exists(context: Any) -> None: + """Verify the showcase markdown file exists.""" + markdown_file = Path("docs/showcase/cli-tools/repl-and-actor-run.md") + assert markdown_file.exists(), f"Showcase markdown not found at {markdown_file}" + context.markdown_file = markdown_file + + # Load the content for later use + with open(markdown_file, "r") as f: + context.markdown_content = f.read() + + +@when("I check for the REPL and actor run showcase file") +def step_check_showcase_file(context: Any) -> None: + """Check for the showcase file.""" + context.file_path = Path("docs/showcase/cli-tools/repl-and-actor-run.md") + + +@then('the file should exist at "{path}"') +def step_file_exists_at_path(context: Any, path: str) -> None: + """Verify file exists at the given path.""" + file_path = Path(path) + assert file_path.exists(), f"File not found at {path}" + + +@when("I check for the REPL and actor run showcase entry") +def step_check_showcase_entry(context: Any) -> None: + """Check for the showcase entry in examples.json.""" + examples = context.examples_data.get("examples", []) + + # Find the REPL and actor run entry + context.repl_entry = None + for example in examples: + if "repl-and-actor-run" in example.get("path", ""): + context.repl_entry = example + break + + assert context.repl_entry is not None, "REPL and actor run entry not found in examples.json" + + +@then('the entry should have title "{title}"') +def step_entry_has_title(context: Any, title: str) -> None: + """Verify entry has the expected title.""" + assert context.repl_entry["title"] == title, \ + f"Expected title '{title}', got '{context.repl_entry['title']}'" + + +@then('the entry should have category "{category}"') +def step_entry_has_category(context: Any, category: str) -> None: + """Verify entry has the expected category.""" + assert context.repl_entry["category"] == category, \ + f"Expected category '{category}', got '{context.repl_entry['category']}'" + + +@then('the entry should have path "{path}"') +def step_entry_has_path(context: Any, path: str) -> None: + """Verify entry has the expected path.""" + assert context.repl_entry["path"] == path, \ + f"Expected path '{path}', got '{context.repl_entry['path']}'" + + +@then('the entry should have complexity "{complexity}"') +def step_entry_has_complexity(context: Any, complexity: str) -> None: + """Verify entry has the expected complexity.""" + assert context.repl_entry["complexity"] == complexity, \ + f"Expected complexity '{complexity}', got '{context.repl_entry['complexity']}'" + + +@when("I check the documented commands") +def step_check_documented_commands(context: Any) -> None: + """Check the documented commands in the markdown.""" + pass # Content is already loaded in context.markdown_content + + +@then('the file should contain "{text}"') +def step_file_contains_text(context: Any, text: str) -> None: + """Verify the file contains the given text.""" + assert text in context.markdown_content, \ + f"Text '{text}' not found in markdown file" + + +@when("I check the content structure") +def step_check_content_structure(context: Any) -> None: + """Check the content structure.""" + pass # Content is already loaded + + +@when("I check for verified output") +def step_check_verified_output(context: Any) -> None: + """Check for verified output in the markdown.""" + pass # Content is already loaded + + +@when("I parse the JSON") +def step_parse_json(context: Any) -> None: + """Parse the JSON file.""" + # Already parsed in the given step + pass + + +@then("the JSON should be valid") +def step_json_is_valid(context: Any) -> None: + """Verify the JSON is valid.""" + assert isinstance(context.examples_data, dict), "JSON is not a valid dictionary" + + +@then('the JSON should have "{key}" key') +def step_json_has_key(context: Any, key: str) -> None: + """Verify the JSON has the given key.""" + assert key in context.examples_data, f"Key '{key}' not found in JSON" + + +@when("I check the REPL and actor run entry") +def step_check_repl_entry(context: Any) -> None: + """Check the REPL and actor run entry.""" + # Already done in previous step + pass + + +@then('the entry should have "{field}" field') +def step_entry_has_field(context: Any, field: str) -> None: + """Verify entry has the given field.""" + assert field in context.repl_entry, \ + f"Field '{field}' not found in entry" + + +@then("the commands list should have at least {count:d} items") +def step_commands_list_has_items(context: Any, count: int) -> None: + """Verify the commands list has at least the given number of items.""" + commands = context.repl_entry.get("commands", []) + assert len(commands) >= count, \ + f"Expected at least {count} commands, got {len(commands)}" + + +@then('the commands should include "{command}"') +def step_commands_include(context: Any, command: str) -> None: + """Verify the commands list includes the given command.""" + commands = context.repl_entry.get("commands", []) + assert command in commands, \ + f"Command '{command}' not found in commands list" + + +@when("I check the markdown structure") +def step_check_markdown_structure(context: Any) -> None: + """Check the markdown structure.""" + pass # Content is already loaded + + +@then("the file should start with a heading") +def step_file_starts_with_heading(context: Any) -> None: + """Verify the file starts with a heading.""" + assert context.markdown_content.startswith("#"), \ + "Markdown file should start with a heading" + + +@then("the file should have multiple sections") +def step_file_has_multiple_sections(context: Any) -> None: + """Verify the file has multiple sections.""" + heading_count = context.markdown_content.count("\n#") + assert heading_count >= 3, \ + f"Expected at least 3 sections, found {heading_count}" + + +@then("the file should have code blocks") +def step_file_has_code_blocks(context: Any) -> None: + """Verify the file has code blocks.""" + assert "```" in context.markdown_content, \ + "Markdown file should have code blocks" + + +@then("the file should have proper link formatting") +def step_file_has_proper_links(context: Any) -> None: + """Verify the file has proper link formatting.""" + # Check for markdown link format [text](url) + assert "[" in context.markdown_content and "](" in context.markdown_content, \ + "Markdown file should have proper link formatting" -- 2.52.0 From 97617b30c82436269a6002be9e7bd71136676443 Mon Sep 17 00:00:00 2001 From: HAL9000 Date: Fri, 24 Apr 2026 04:50:59 +0000 Subject: [PATCH 2/4] fix(showcase): fix lint errors and step logic in REPL actor run showcase tests - Remove unused import os from showcase_repl_actor_run_steps.py - Fix import order (given, then, when) per ruff I001 - Remove unnecessary "r" mode argument from open() calls (UP015) - Fix step_check_repl_entry to actually find the REPL entry in examples.json (was a no-op pass that left context.repl_entry unset, causing test failures) --- .../steps/showcase_repl_actor_run_steps.py | 69 +++++++++++-------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/features/steps/showcase_repl_actor_run_steps.py b/features/steps/showcase_repl_actor_run_steps.py index f5cb1c17e..72768aabf 100644 --- a/features/steps/showcase_repl_actor_run_steps.py +++ b/features/steps/showcase_repl_actor_run_steps.py @@ -1,11 +1,10 @@ """Steps for REPL and Actor Run CLI Showcase Documentation tests.""" import json -import os from pathlib import Path from typing import Any -from behave import given, when, then +from behave import given, then, when @given("the showcase directory exists") @@ -22,9 +21,9 @@ def step_examples_json_exists(context: Any) -> None: examples_file = Path("docs/showcase/examples.json") assert examples_file.exists(), f"examples.json not found at {examples_file}" context.examples_file = examples_file - + # Load the JSON for later use - with open(examples_file, "r") as f: + with open(examples_file) as f: context.examples_data = json.load(f) @@ -34,9 +33,9 @@ def step_showcase_markdown_exists(context: Any) -> None: markdown_file = Path("docs/showcase/cli-tools/repl-and-actor-run.md") assert markdown_file.exists(), f"Showcase markdown not found at {markdown_file}" context.markdown_file = markdown_file - + # Load the content for later use - with open(markdown_file, "r") as f: + with open(markdown_file) as f: context.markdown_content = f.read() @@ -57,43 +56,49 @@ def step_file_exists_at_path(context: Any, path: str) -> None: def step_check_showcase_entry(context: Any) -> None: """Check for the showcase entry in examples.json.""" examples = context.examples_data.get("examples", []) - + # Find the REPL and actor run entry context.repl_entry = None for example in examples: if "repl-and-actor-run" in example.get("path", ""): context.repl_entry = example break - - assert context.repl_entry is not None, "REPL and actor run entry not found in examples.json" + + assert context.repl_entry is not None, ( + "REPL and actor run entry not found in examples.json" + ) @then('the entry should have title "{title}"') def step_entry_has_title(context: Any, title: str) -> None: """Verify entry has the expected title.""" - assert context.repl_entry["title"] == title, \ + assert context.repl_entry["title"] == title, ( f"Expected title '{title}', got '{context.repl_entry['title']}'" + ) @then('the entry should have category "{category}"') def step_entry_has_category(context: Any, category: str) -> None: """Verify entry has the expected category.""" - assert context.repl_entry["category"] == category, \ + assert context.repl_entry["category"] == category, ( f"Expected category '{category}', got '{context.repl_entry['category']}'" + ) @then('the entry should have path "{path}"') def step_entry_has_path(context: Any, path: str) -> None: """Verify entry has the expected path.""" - assert context.repl_entry["path"] == path, \ + assert context.repl_entry["path"] == path, ( f"Expected path '{path}', got '{context.repl_entry['path']}'" + ) @then('the entry should have complexity "{complexity}"') def step_entry_has_complexity(context: Any, complexity: str) -> None: """Verify entry has the expected complexity.""" - assert context.repl_entry["complexity"] == complexity, \ + assert context.repl_entry["complexity"] == complexity, ( f"Expected complexity '{complexity}', got '{context.repl_entry['complexity']}'" + ) @when("I check the documented commands") @@ -105,8 +110,7 @@ def step_check_documented_commands(context: Any) -> None: @then('the file should contain "{text}"') def step_file_contains_text(context: Any, text: str) -> None: """Verify the file contains the given text.""" - assert text in context.markdown_content, \ - f"Text '{text}' not found in markdown file" + assert text in context.markdown_content, f"Text '{text}' not found in markdown file" @when("I check the content structure") @@ -143,31 +147,40 @@ def step_json_has_key(context: Any, key: str) -> None: @when("I check the REPL and actor run entry") def step_check_repl_entry(context: Any) -> None: """Check the REPL and actor run entry.""" - # Already done in previous step - pass + examples = context.examples_data.get("examples", []) + + # Find the REPL and actor run entry + context.repl_entry = None + for example in examples: + if "repl-and-actor-run" in example.get("path", ""): + context.repl_entry = example + break + + assert context.repl_entry is not None, ( + "REPL and actor run entry not found in examples.json" + ) @then('the entry should have "{field}" field') def step_entry_has_field(context: Any, field: str) -> None: """Verify entry has the given field.""" - assert field in context.repl_entry, \ - f"Field '{field}' not found in entry" + assert field in context.repl_entry, f"Field '{field}' not found in entry" @then("the commands list should have at least {count:d} items") def step_commands_list_has_items(context: Any, count: int) -> None: """Verify the commands list has at least the given number of items.""" commands = context.repl_entry.get("commands", []) - assert len(commands) >= count, \ + assert len(commands) >= count, ( f"Expected at least {count} commands, got {len(commands)}" + ) @then('the commands should include "{command}"') def step_commands_include(context: Any, command: str) -> None: """Verify the commands list includes the given command.""" commands = context.repl_entry.get("commands", []) - assert command in commands, \ - f"Command '{command}' not found in commands list" + assert command in commands, f"Command '{command}' not found in commands list" @when("I check the markdown structure") @@ -179,28 +192,28 @@ def step_check_markdown_structure(context: Any) -> None: @then("the file should start with a heading") def step_file_starts_with_heading(context: Any) -> None: """Verify the file starts with a heading.""" - assert context.markdown_content.startswith("#"), \ + assert context.markdown_content.startswith("#"), ( "Markdown file should start with a heading" + ) @then("the file should have multiple sections") def step_file_has_multiple_sections(context: Any) -> None: """Verify the file has multiple sections.""" heading_count = context.markdown_content.count("\n#") - assert heading_count >= 3, \ - f"Expected at least 3 sections, found {heading_count}" + assert heading_count >= 3, f"Expected at least 3 sections, found {heading_count}" @then("the file should have code blocks") def step_file_has_code_blocks(context: Any) -> None: """Verify the file has code blocks.""" - assert "```" in context.markdown_content, \ - "Markdown file should have code blocks" + assert "```" in context.markdown_content, "Markdown file should have code blocks" @then("the file should have proper link formatting") def step_file_has_proper_links(context: Any) -> None: """Verify the file has proper link formatting.""" # Check for markdown link format [text](url) - assert "[" in context.markdown_content and "](" in context.markdown_content, \ + assert "[" in context.markdown_content and "](" in context.markdown_content, ( "Markdown file should have proper link formatting" + ) -- 2.52.0 From c0ca2746912dfbe7bc8c502bb536f068956347b8 Mon Sep 17 00:00:00 2001 From: CleverThis Date: Fri, 24 Apr 2026 14:51:56 +0000 Subject: [PATCH 3/4] fix(showcase): add "agents actor run" to commands list in examples.json The BDD test step_commands_include checks for exact list membership. "agents actor run" was missing from the commands list, causing the "Showcase commands list is not empty" scenario to fail with: AssertionError: Command 'agents actor run' not found in commands list --- docs/showcase/examples.json | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/showcase/examples.json b/docs/showcase/examples.json index 1af8e11d9..280d0087e 100644 --- a/docs/showcase/examples.json +++ b/docs/showcase/examples.json @@ -29,6 +29,7 @@ "commands": [ "agents repl", "agents repl --help", + "agents actor run", "agents actor run openai/gpt-4o \"Say hello\"", "agents actor run --help", "agents actor run local/demo-assistant \"What is the capital of France?\" --config my-assistant.yaml", -- 2.52.0 From 61bdc4bd276b16c103d74f53735d06c100851f97 Mon Sep 17 00:00:00 2001 From: CleverThis Date: Sat, 6 Jun 2026 02:52:27 -0400 Subject: [PATCH 4/4] fix(showcase): resolve AmbiguousStep for 'the JSON should be valid' Rename the step decorator in showcase_repl_actor_run_steps.py from 'the JSON should be valid' to 'the examples JSON content is valid' to avoid collision with the identical step already defined in aimodelsproviders_steps.py (which uses a different context variable). Update the matching step text in showcase_repl_actor_run.feature. ISSUES CLOSED: #7552 --- features/showcase_repl_actor_run.feature | 2 +- features/steps/showcase_repl_actor_run_steps.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/showcase_repl_actor_run.feature b/features/showcase_repl_actor_run.feature index d608d098e..bfd5964b7 100644 --- a/features/showcase_repl_actor_run.feature +++ b/features/showcase_repl_actor_run.feature @@ -49,7 +49,7 @@ Feature: REPL and Actor Run CLI Showcase Documentation Scenario: Examples.json has valid JSON structure Given the examples.json file exists When I parse the JSON - Then the JSON should be valid + Then the examples JSON content is valid And the JSON should have "examples" key And the JSON should have "categories" key diff --git a/features/steps/showcase_repl_actor_run_steps.py b/features/steps/showcase_repl_actor_run_steps.py index 72768aabf..64fe35a5e 100644 --- a/features/steps/showcase_repl_actor_run_steps.py +++ b/features/steps/showcase_repl_actor_run_steps.py @@ -132,7 +132,7 @@ def step_parse_json(context: Any) -> None: pass -@then("the JSON should be valid") +@then("the examples JSON content is valid") def step_json_is_valid(context: Any) -> None: """Verify the JSON is valid.""" assert isinstance(context.examples_data, dict), "JSON is not a valid dictionary" -- 2.52.0