feat: agent authoring & doc generation (WP-0007, v1.4.0)
New authoring tooling and a fix for the doc-regeneration defect it exposed. Added: - src/kaizen_agentic/agent_docs.py — render + idempotent upsert of the CLAUDE.md "## Installed Agents" section (shared by installer and CLI) - `kaizen-agentic docs generate [--check]` — idempotent doc refresh / CI gate - `kaizen-agentic create-agent` — scaffold a schema-valid agent - Frontmatter schema validation in `kaizen-agentic validate` (required name/description/category, known category, valid memory/model) - tests: test_agent_docs, test_validate_schema, test_create_agent Fixed: - _update_documentation regex duplicated the Installed Agents block on every run (stopped at the first ### subheading) — now idempotent - declared frontmatter `category` is authoritative (heuristic is fallback) - list_installed_agents reads the frontmatter name, not the filename - renamed agent-project-management.md -> agent-project-assistant.md to satisfy the agent-<name>.md convention (eliminates a name/filename collision that caused install/update to write a divergent duplicate) - test_cli_error_handling no longer installs into the repo root (uses tmp) Version 1.4.0; CHANGELOG, CLI cheat sheet, agency-framework, TODO updated. Workplan KAIZEN-WP-0007 closed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
100
tests/test_create_agent.py
Normal file
100
tests/test_create_agent.py
Normal file
@@ -0,0 +1,100 @@
|
||||
"""Tests for the create-agent scaffold (WP-0007 T04)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from click.testing import CliRunner
|
||||
|
||||
from kaizen_agentic.cli import cli
|
||||
from kaizen_agentic.registry import AgentRegistry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def runner() -> CliRunner:
|
||||
return CliRunner()
|
||||
|
||||
|
||||
class TestCreateAgent:
|
||||
def test_scaffold_is_schema_valid_and_loads(
|
||||
self, runner: CliRunner, tmp_path: Path
|
||||
):
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
[
|
||||
"create-agent",
|
||||
"demo-helper",
|
||||
"-c",
|
||||
"testing",
|
||||
"-d",
|
||||
"Demo helper for tests",
|
||||
"--target",
|
||||
str(tmp_path),
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0, result.output
|
||||
agent_path = tmp_path / "agents" / "agent-demo-helper.md"
|
||||
assert agent_path.exists()
|
||||
|
||||
registry = AgentRegistry(tmp_path / "agents")
|
||||
# Passes the schema and is loadable by the registry.
|
||||
assert registry.validate_frontmatter_schema() == {}
|
||||
agent = registry.get_agent("demo-helper")
|
||||
assert agent is not None
|
||||
assert agent.category.value == "testing"
|
||||
assert agent.memory == "enabled"
|
||||
|
||||
def test_interactive_prompts_when_flags_missing(
|
||||
self, runner: CliRunner, tmp_path: Path
|
||||
):
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
["create-agent", "prompted", "--target", str(tmp_path)],
|
||||
input="testing\nA prompted agent\n",
|
||||
)
|
||||
assert result.exit_code == 0, result.output
|
||||
content = (tmp_path / "agents" / "agent-prompted.md").read_text()
|
||||
assert "category: testing" in content
|
||||
assert "description: A prompted agent" in content
|
||||
|
||||
def test_refuses_overwrite_without_force(self, runner: CliRunner, tmp_path: Path):
|
||||
args = [
|
||||
"create-agent",
|
||||
"dup",
|
||||
"-c",
|
||||
"meta",
|
||||
"-d",
|
||||
"first",
|
||||
"--target",
|
||||
str(tmp_path),
|
||||
]
|
||||
assert runner.invoke(cli, args).exit_code == 0
|
||||
second = runner.invoke(cli, args)
|
||||
assert second.exit_code == 1
|
||||
assert "already exists" in second.output
|
||||
|
||||
def test_force_overwrites(self, runner: CliRunner, tmp_path: Path):
|
||||
base = ["create-agent", "dup", "--target", str(tmp_path)]
|
||||
runner.invoke(cli, base + ["-c", "meta", "-d", "first"])
|
||||
result = runner.invoke(cli, base + ["-c", "meta", "-d", "second", "--force"])
|
||||
assert result.exit_code == 0
|
||||
assert (
|
||||
"description: second" in (tmp_path / "agents" / "agent-dup.md").read_text()
|
||||
)
|
||||
|
||||
def test_rejects_invalid_category(self, runner: CliRunner, tmp_path: Path):
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
[
|
||||
"create-agent",
|
||||
"x",
|
||||
"-c",
|
||||
"nonsense",
|
||||
"-d",
|
||||
"d",
|
||||
"--target",
|
||||
str(tmp_path),
|
||||
],
|
||||
)
|
||||
assert result.exit_code != 0
|
||||
Reference in New Issue
Block a user