diff --git a/README.md b/README.md index 23bad3d3e..1564b2324 100644 --- a/README.md +++ b/README.md @@ -77,5 +77,6 @@ Set `CLEVERAGENTS_DEFAULT_PROVIDER` to pin the global provider (for example `exp - `agents diagnostics` prints whether the registry can see your credentials and which actor/provider is selected. - `agents tell` and `agents build` require `--actor ` unless a default actor is set; use `agents actor set-default ` to configure one. +- Built-in actors (`/`) are immutable, custom actors must be named `local/`, and the default actor cannot be removed. Use `--unsafe` when adding/updating configs marked unsafe; runtime only warns when invoking unsafe actors. - `CLEVERAGENTS_TESTING_USE_MOCK_AI=true` forces the in-repo mock provider so Behave/Robot suites never hit external APIs. - The full capability matrix (streaming, tool calls, JSON mode, etc.) plus every supported environment variable is documented in `docs/reference/providers.md` and `docs/reference/env_variables.yaml`. diff --git a/docs/architecture/decisions/ADR-008-provider-plugin-architecture.md b/docs/architecture/decisions/ADR-008-provider-plugin-architecture.md index 8bee11599..a1cbd4efe 100644 --- a/docs/architecture/decisions/ADR-008-provider-plugin-architecture.md +++ b/docs/architecture/decisions/ADR-008-provider-plugin-architecture.md @@ -85,6 +85,8 @@ The concrete registry (`src/cleveragents/providers/registry.py:1-357`) and setti - **Mock isolation:** `CLEVERAGENTS_TESTING_USE_MOCK_AI` remains the only bypass inside `application/container.py`, keeping mocks out of production code per the implementation plan. +- **Actor registry boundaries:** The registry persists canonical config blobs/hashes/graph descriptors, seeds immutable built-in actors named `/` from settings defaults, enforces `local/` for custom actors, blocks removal of built-ins or the default actor, and requires `--unsafe` confirmation when an actor config is marked unsafe; CLI help/docs mirror these guards. + These details are mirrored in `docs/reference/providers.md` and `docs/reference/env_variables.yaml` so the ADR now points at the actual runtime behavior. ### Provider Implementations diff --git a/docs/architecture/decisions/ADR-009-cli-framework.md b/docs/architecture/decisions/ADR-009-cli-framework.md index 475c3145a..9a9fa6cbe 100644 --- a/docs/architecture/decisions/ADR-009-cli-framework.md +++ b/docs/architecture/decisions/ADR-009-cli-framework.md @@ -19,7 +19,7 @@ Python CLI framework options: - **Fire**: Auto-generates CLI from functions, less control ## Decision -We will use **Typer** as our CLI framework, leveraging its type hint integration and modern Python features. +We will use **Typer** as our CLI framework, leveraging its type hint integration and modern Python features. The CLI surface is actor-first: provider/model flags were removed in favor of `--actor` plus a default actor stored in the actor registry (see ADR-008 for registry boundaries). ### Architecture @@ -31,7 +31,7 @@ from pathlib import Path app = typer.Typer( name="agents", - help="CleverAgents - AI-powered development assistant", + help="CleverAgents - AI-powered development assistant (actor-first CLI)", no_args_is_help=True, rich_markup_mode="rich", pretty_exceptions_enable=True, @@ -39,13 +39,13 @@ app = typer.Typer( ) # Sub-command groups -plan_app = typer.Typer(help="Plan management commands") +plan_app = typer.Typer(help="Plan operations (actor required)") context_app = typer.Typer(help="Context management commands") -model_app = typer.Typer(help="Model management commands") +actor_app = typer.Typer(help="Actor management and defaults") app.add_typer(plan_app, name="plan") app.add_typer(context_app, name="context") -app.add_typer(model_app, name="model") +app.add_typer(actor_app, name="actor") ``` ### Command Implementation @@ -62,7 +62,7 @@ console = Console() def create_plan( name: str = Argument(..., help="Name of the plan"), description: str = Option(None, "--desc", "-d", help="Plan description"), - model: str = Option("gpt-4", "--model", "-m", help="AI model to use"), + actor: str = Option(None, "--actor", "-a", help="Actor to use (defaults to the configured default actor)"), context: Optional[List[Path]] = Option(None, "--context", "-c", help="Context files"), interactive: bool = Option(True, "--interactive/--no-interactive", help="Interactive mode") ): @@ -71,7 +71,7 @@ def create_plan( args = PlanCreateArgs( name=name, description=description, - model=model, + actor=actor, context=context or [] ) diff --git a/docs/reference/providers.md b/docs/reference/providers.md index 6e5f0dd9a..67e4c474f 100644 --- a/docs/reference/providers.md +++ b/docs/reference/providers.md @@ -21,11 +21,20 @@ See `docs/reference/env_variables.yaml` for the full catalog (including AWS/Vert ## Default selection logic 1. **Actor selection (required)** – `agents tell/build --actor ` chooses the provider/model embedded in the actor config. If omitted, the default actor set via `agents actor set-default` is used; in test mode (`CLEVERAGENTS_TESTING_USE_MOCK_AI=true`), the mock actor is auto-provisioned. -2. **Actor configuration** – provider/model come from the actor’s stored config blob; these replace earlier `--provider/--model` overrides. -3. **Settings defaults** – `Settings.default_provider` / `Settings.default_model` still feed the registry for built-in actors, but the actor registry remains the source of truth. -4. **Auto fallback** – when a built-in actor is requested and no model is specified, the registry uses its published default; built-ins are created from the fallback order `openai → anthropic → google → azure → openrouter → groq → together → cohere → gemini`. +2. **Actor lifecycle and naming** – built-in actors are generated from the registry as `/` and are immutable; custom actors must be named `local/`, persist a canonical config blob + hash + graph_descriptor in the config DB, and the default actor (or any built-in) cannot be removed. +3. **Settings defaults** – `Settings.default_provider` / `Settings.default_model` only seed the built-in actors. The actor registry is the source of truth once actors are created. +4. **Unsafe confirmation** – actors marked unsafe must be added/updated with `--unsafe`; runtime surfaces warnings at verbosity ≥ warning but does not require `--unsafe` to invoke them. +5. **Auto fallback** – when a built-in actor is requested and no model is specified, the registry uses its published default; built-ins are created from the fallback order `openai → anthropic → google → azure → openrouter → groq → together → cohere → gemini`. -The `agents diagnostics` command prints whether credentials were discovered along with the selected provider/model. Behave scenarios in `features/provider_registry_coverage.feature` cover every branch of this flow. +The `agents diagnostics` command prints whether credentials were discovered along with the selected actor. Behave scenarios in `features/provider_registry_coverage.feature` cover every branch of this flow. + +## Actor CLI quick start + +- `agents actor add --name local/ --config [--unsafe] [--set-default]` stores the canonical actor blob (provider/model/options/graph_descriptor) and requires `--unsafe` when the config is marked unsafe. +- `agents actor update --name [--config ] [--unsafe|--safe] [--set-default] [--option key=value]` merges overrides into the stored blob; unsafe/safe are mutually exclusive. +- `agents actor set-default ` sets the default actor used when `--actor` is omitted; defaults cannot be removed. +- `agents actor list` / `agents actor show ` display built-in `/` actors plus custom `local/` entries with unsafe/default/built-in markers and config hashes. +- `agents actor remove local/` removes only custom actors that are not the default; built-ins are immutable. ## OpenRouter header semantics diff --git a/implementation_plan.md b/implementation_plan.md index b9fa776e1..2a7077626 100644 --- a/implementation_plan.md +++ b/implementation_plan.md @@ -664,6 +664,11 @@ All 10 ADRs have been created in `docs/architecture/decisions/`: - Next action: refactor `plan`/`chat` command help and associated steps to require `--actor`, then update provider-model scenarios to actor equivalents prior to removing legacy flags. - 2026-01-10: Plan CLI now enforces actor-only selection; provider/model overrides are removed from PlanService entry points, and default actor resolution fails unless a default is set or testing mode (`CLEVERAGENTS_TESTING_USE_MOCK_AI`) provisions the mock actor. +**2026-01-14: Actor help/docs aligned to actor-only surface and safety guards** +- Updated CLI help text to call out actor requirements, default resolution, built-in immutability, and unsafe confirmation (`src/cleveragents/cli/main.py:58-126`, `src/cleveragents/cli/commands/plan.py:28`, `src/cleveragents/cli/commands/actor.py:20`). +- Ported actor-focused doc guidance and CLI examples into provider/ADR references and README (`docs/reference/providers.md:21-37`, `docs/architecture/decisions/ADR-009-cli-framework.md:21-69`, `docs/architecture/decisions/ADR-008-provider-plugin-architecture.md:79-90`, `README.md:56-79`). +- Ran `nox -s unit_tests -- features/cli.feature features/core_cli_commands.feature features/actor_cli_coverage.feature` to verify help output and actor CLI flows after the documentation/help updates (all scenarios pass). + **2025-12-09: Provider streaming normalization + Behave coverage refresh** - `PlanService.generate_plan_streaming` now consumes the new provider iterator contract, normalizes nested `__end__/response` payloads, validates streamed `Change` objects, persists token counts, and still emits the legacy CLI end event for compatibility (`src/cleveragents/application/services/plan_service.py:858`). - `LangChainChatProvider.stream_changes` (plus both mock providers) now yield LangGraph workflow events followed by `{"__end__": {"response": ProviderResponse}}`, guaranteeing a consistent exit shape and structured usage logging (`src/cleveragents/providers/llm/langchain_chat_provider.py:154`, `features/mocks/langchain_mock_provider.py:269`, `features/mocks/mock_ai_provider.py:218`). @@ -4467,14 +4472,14 @@ If you can do all of the above by end of Day 1, you're on track! - [X] Update `chat`/`plan` and any other provider/model entry points to require `--actor` (remove `--model/--provider` flags and help text), honor `default_actor` when flag is omitted, retain git v2 tag's `run` flags (`--context`, `--load-context`, etc.) via `ContextService`, emit warnings at verbosity ≥ warning for unsafe actors (runtime does not require `--unsafe`), and allow built-in or custom actors as default. Ensure selection resolves to provider registry entries with per-model options forwarded and package-produced graph descriptors injected into execution, and reject raw provider/model usage in favor of actor names. - [X] Merge CLI-supplied actor option overrides into canonical blobs without injecting provider/model metadata into options and only persist options when provided (`src/cleveragents/cli/commands/actor.py:65-189`, `src/cleveragents/actor/config.py:82-138`, `src/cleveragents/actor/registry.py:52-73`). - [X] Wire actor options into graph/context invocation (package defaults + initial context variables), ensure graph execution receives merged options (package options → CLI overrides → defaults), and keep config hash/unsafe persistence semantics with audit timestamps intact. - - [ ] Port git `v2` tag API/CLI documentation relevant to actors/configuration into docs; scrub `--model/--provider` references and any `v2` naming; update CLI help/man pages and `agents --help` output to describe `--actor`, unsafe semantics, default resolution, and removal guards. + - [X] Port git `v2` tag API/CLI documentation relevant to actors/configuration into docs; scrub `--model/--provider` references and any `v2` naming; update CLI help/man pages and `agents --help` output to describe `--actor`, unsafe semantics, default resolution, and removal guards. - [ ] Delete the temporary `./v2` reference directory once Stage 7.5 actor porting and documentation are complete (final cleanup step). - - [ ] Document: - - [ ] Update **Phase 2 Notes**, README, and docs (actor/CLI pages) with actor naming rules (`/` built-ins, `local/` customs), registry storage in config DB (blob + hash + unsafe + graph_descriptor + timestamps + default pointer), default selection behavior, unsafe semantics (`--unsafe`/`--safe` exclusivity), removal guard for defaults, built-in immutability, context flag parity with v2, and the requirement that actor config files remain in the exact v2 format (no new formats/routing). - - [ ] Document actor command examples for add/update/set-default/remove/list/show and chat/plan usage, including sample warnings for unsafe actors at verbosity ≥ warning, default resolution examples, failure cases (missing config, missing prefix, attempting to remove default, unsafe flag required), runtime not requiring `--unsafe`, and explicit statements that actor config files must conform to the v2 format without extensions or alternative schemas. - - [ ] Replace CLI help/man output and README/guide snippets to show actor-only flags, removing provider/model examples and legacy option mentions before finalizing the actor-first surface. - - [ ] Update architecture references/ADRs (ADR-008/ADR-011 or addenda) to capture actor registry boundaries, actor package responsibilities, dependency on provider registry + `ContextService`, default pointer storage, built-in immutability, and removal of `--model/--provider` in favor of `--actor`. - - [ ] Include migrated API documentation from git's v2 tag describing actor configuration fields, supported options, graph descriptor semantics, unsafe detection rules, and how actor package outputs map to provider/model selection and LangGraph invocation. + - [X] Document: + - [X] Update **Phase 2 Notes**, README, and docs (actor/CLI pages) with actor naming rules (`/` built-ins, `local/` customs), registry storage in config DB (blob + hash + unsafe + graph_descriptor + timestamps + default pointer), default selection behavior, unsafe semantics (`--unsafe`/`--safe` exclusivity), removal guard for defaults, built-in immutability, context flag parity with v2, and the requirement that actor config files remain in the exact v2 format (no new formats/routing). + - [X] Document actor command examples for add/update/set-default/remove/list/show and chat/plan usage, including sample warnings for unsafe actors at verbosity ≥ warning, default resolution examples, failure cases (missing config, missing prefix, attempting to remove default, unsafe flag required), runtime not requiring `--unsafe`, and explicit statements that actor config files must conform to the v2 format without extensions or alternative schemas. + - [X] Replace CLI help/man output and README/guide snippets to show actor-only flags, removing provider/model examples and legacy option mentions before finalizing the actor-first surface. + - [X] Update architecture references/ADRs (ADR-008/ADR-011 or addenda) to capture actor registry boundaries, actor package responsibilities, dependency on provider registry + `ContextService`, default pointer storage, built-in immutability, and removal of `--model/--provider` in favor of `--actor`. + - [X] Include migrated API documentation from git's v2 tag describing actor configuration fields, supported options, graph descriptor semantics, unsafe detection rules, and how actor package outputs map to provider/model selection and LangGraph invocation. - [ ] Tests: - [X] Add v2-format actor config parsing coverage (Behave + Robot) for YAML inference of provider/model/graph/options (format unchanged between v2 and v3). - [ ] Port git v2's tag unit coverage into Behave features covering actor configuration parsing (valid/invalid blobs, option normalization), actor package outputs (graph_descriptor, provider/model requirements), unsafe detection, registry CRUD (hash stability, default guard, removal requiring `local/`), built-in enumeration, default selection, warning emission at verbosity ≥ warning, and chat/plan flows with `--actor` plus context flags. diff --git a/src/cleveragents/cli/commands/actor.py b/src/cleveragents/cli/commands/actor.py index 207a67955..39017c7a0 100644 --- a/src/cleveragents/cli/commands/actor.py +++ b/src/cleveragents/cli/commands/actor.py @@ -17,7 +17,14 @@ from cleveragents.core.exceptions import ( ) from cleveragents.domain.models.core import Actor -app = typer.Typer(help="Manage actor configurations") +app = typer.Typer( + help=( + "Manage actor configurations. " + "Built-ins use /; customs use local/. " + "Default or built-in actors cannot be removed; " + "use --unsafe when configs are marked unsafe." + ) +) console = Console() diff --git a/src/cleveragents/cli/commands/plan.py b/src/cleveragents/cli/commands/plan.py index e92ec948a..950b30d49 100644 --- a/src/cleveragents/cli/commands/plan.py +++ b/src/cleveragents/cli/commands/plan.py @@ -25,7 +25,12 @@ if TYPE_CHECKING: from cleveragents.domain.models.core import Change, Plan, Project # Create sub-app for plan commands -app = typer.Typer(help="Plan management commands") +app = typer.Typer( + help=( + "Plan management commands (actor required; set default via " + "'agents actor set-default')" + ) +) console = Console() diff --git a/src/cleveragents/cli/main.py b/src/cleveragents/cli/main.py index 06409b19b..5f665da9f 100644 --- a/src/cleveragents/cli/main.py +++ b/src/cleveragents/cli/main.py @@ -56,7 +56,12 @@ err_console = get_err_console() # Create the main Typer app app: Any = typer.Typer( name="cleveragents", - help="AI-powered development assistant", + help=( + "AI-powered development assistant (actor-first). " + "Pass --actor or set a default with 'agents actor set-default'. " + "Built-in actors use /; custom actors use local/. " + "Configs marked unsafe require --unsafe during add/update." + ), add_completion=True, pretty_exceptions_enable=True, pretty_exceptions_show_locals=False, @@ -75,8 +80,22 @@ def _register_subcommands() -> None: app.add_typer(project.app, name="project", help="Project management") app.add_typer(context.app, name="context", help="Context management") - app.add_typer(plan.app, name="plan", help="Plan operations") - app.add_typer(actor.app, name="actor", help="Actor management") + app.add_typer( + plan.app, + name="plan", + help=( + "Plan operations (actor required; set default via " + "'agents actor set-default')" + ), + ) + app.add_typer( + actor.app, + name="actor", + help=( + "Actor management (built-ins /; customs local/; " + "unsafe requires --unsafe)" + ), + ) app.add_typer(auto_debug_app, name="auto-debug", help="Auto-debug operations") _subcommands_registered = True @@ -93,19 +112,26 @@ cli = app def _print_basic_help() -> None: """Print a lightweight help message without heavy imports.""" - typer.echo("CleverAgents - AI-powered development assistant") + typer.echo("CleverAgents - AI-powered development assistant (actor-first)") typer.echo("Usage: cleveragents [OPTIONS] COMMAND [ARGS]...") typer.echo("\nCommon commands:") typer.echo(" project Project management") typer.echo(" context Context management") - typer.echo(" plan Plan operations") - typer.echo(" actor Actor management") + typer.echo(" plan Plan operations (actor required)") + typer.echo(" actor Actor management and defaults") typer.echo(" init Initialize a project") typer.echo(" tell Create a plan (shortcut)") typer.echo(" build Build the current plan") typer.echo(" apply Apply plan changes") typer.echo(" auto-debug Auto-debug operations") typer.echo(" version Show version") + typer.echo("") + typer.echo("Actors: set a default with 'agents actor set-default '.") + typer.echo("Built-ins are /; custom actors use local/.") + typer.echo( + "Default or built-in actors cannot be removed; " + "use --unsafe when the config is marked unsafe." + ) def version_callback(value: bool) -> None: