diff --git a/CHANGELOG.md b/CHANGELOG.md index 5511f6e3c..e8cbb7463 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,96 @@ # Changelog -## Unreleased +All notable changes to this project will be documented in this file. +The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). + +## [Unreleased] + +## [3.7.0] — 2026-04-02 + +### Added + +- **TUI — Interactive Terminal UI** (`agents tui`): Full-screen Textual-based + application with multi-session tabs, real-time plan monitoring, and rich + conversation with actors. Requires the optional `cleveragents[tui]` extra. + ([ADR-044](docs/adr/ADR-044-tui-architecture-and-framework.md)) + +- **TUI — Persona system**: YAML-backed personas stored in + `~/.config/cleveragents/personas/`. Each persona binds an actor, optional + argument presets, and scope references to a named identity. Personas are + managed via `/persona:*` slash commands or the `PersonaRegistry` API. + Per-session state (active persona, active preset) is tracked in memory and + the last-used persona is persisted to `tui-state.yaml`. + ([ADR-045](docs/adr/ADR-045-tui-persona-system.md)) + +- **TUI — Input mode routing**: The prompt auto-detects three input modes from + the first character — Normal (message + `@reference` expansion), Command + (`/` slash commands), and Shell (`!` subprocess passthrough). The + `InputModeRouter` dispatches each mode to the appropriate handler. + ([ADR-046](docs/adr/ADR-046-tui-reference-and-command-system.md)) + +- **TUI — Slash command catalog**: 67 slash commands across 14 groups + (Session, Persona, Scope, Plan, Project, Actor, Resource, Config, Tool, + Skill, Invariant, Profile, Context, Utility) exposed via the + `SlashCommandOverlay` widget and `SLASH_COMMAND_SPECS` catalog. + +- **TUI — Context-sensitive help panel (F1)**: `HelpPanelOverlay` toggled by + `F1` with content that adapts to the current prompt context (Main Screen, + Slash Commands, Reference Picker, Shell Mode). Global key bindings are + always shown alongside context-specific shortcuts. (#1013) + +- **TUI — Persona bar**: Bottom status bar (`PersonaBar`) displaying the + active persona name, bound actor, current argument preset, and scope + reference count. Cycle presets with `Ctrl+T`. + +- **Session management**: `agents session` command group with `create`, + `list`, `show`, `delete`, `export`, `import`, and `tell` subcommands. + Sessions are persisted via the DI-wired `SessionService` and routed through + the A2A local facade. Fixed DI container wiring (`session_service` provider) + that previously caused `AttributeError` on all session commands. (#554, #570) + +- **Server mode**: `agents server connect` persists server URL and token to + configuration. `agents server status` reports connection state. Kubernetes + Helm chart added in `k8s/` for production deployment with Deployment, + Service, Ingress (TLS), ConfigMap, ServiceAccount, Secrets, and optional + Redis subchart for multi-instance session affinity. `Dockerfile.server` + provides a multi-stage ASGI container image. (#928) + +- **A2A integration**: A2A local facade handlers wired to live application + services — `session.create`/`close`, `plan.create`/`execute`/`status`/ + `diff`/`apply`, `registry.list_tools`/`list_resources`, `event.subscribe`. + Domain-to-A2A error code mapping (`NOT_FOUND`, `VALIDATION_ERROR`, + `INVALID_STATE`, `PLAN_ERROR`). (#501) + +### Changed + +- `agents actor run` now takes positional `` and `` arguments, + aligning with the specification. The previous `--prompt/-p` option is + removed. (#901) + +- `resource_selection` decision type reclassified from Execute-only to + phase-agnostic (valid in both Strategize and Execute), aligning with + ADR-007 and ADR-033. (#931) + +- `SandboxManager.commit_all()` is now an all-or-nothing atomic operation. + On partial failure, already-committed sandboxes are rolled back in reverse + (LIFO) order. (#925) + +### Fixed + +- `agents session list`, `session create`, and other session subcommands no + longer raise `AttributeError: 'DynamicContainer' object has no attribute + 'db'` after `agents init`. (#554, #570, #680) + +- `plan execute` no longer fails with stale-cache state when run in a + separate CLI process from `plan use`. (#960) + +- `project context set` now commits changes via `session.commit()` instead + of `session.flush()`, preventing silently lost data. (#745) + +- `agents action create` now accepts `--format`/`-f` flag, matching all + other action subcommands. (#959) + +## Unreleased (pre-3.7.0) - Added a context-sensitive TUI help panel overlay toggled by `F1`, with help content that varies for main-screen, slash-command, reference, and diff --git a/README.md b/README.md index db49367ee..4f6253dbe 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,22 @@ # CleverAgents Core -CleverAgents is a Python-first automation platform. It provides a unified `agents` CLI, embedded runtime, and service orchestration tools while embracing modern Python tooling. +CleverAgents is a Python-first automation platform. It provides a unified `agents` CLI, +an interactive Textual TUI, embedded runtime, and service orchestration tools while +embracing modern Python tooling. ## Highlights - Unified CLI entry points: `cleveragents` and `agents` +- **Interactive TUI** (`agents tui`) — full-screen Textual app with multi-session tabs, + persona switching, slash commands, reference picker, and context-sensitive F1 help +- **Persona system** — YAML-backed personas bind actors, argument presets, and scope + references to named identities; persisted in `~/.config/cleveragents/personas/` +- **Session management** — create, list, export, and import conversation sessions; + full JSON export/import for portability +- **Server mode** — `agents server connect` configures a remote CleverAgents server; + Kubernetes Helm chart in `k8s/` for production deployment +- **A2A integration** — Agent-to-Agent protocol facade wires CLI and TUI to live + application services (session, plan, registry, event) - Fast Typer/Click-based interface with parity for help/version behavior - Behavior-driven coverage via Behave and Robot Framework - Nox automation for linting, typing, testing, docs, builds, and benchmarks @@ -30,6 +42,45 @@ agents --help agents --version ``` +### Launch the TUI + +```bash +# install TUI extra +pip install -e ".[tui]" + +# launch the interactive terminal UI +agents tui +``` + +Inside the TUI: + +- Type a message and press `Enter` to chat with the active actor +- Press `/` to open the slash command overlay (67 commands across 14 groups) +- Press `@` to open the reference picker and insert file/resource references +- Press `!` to enter shell mode and run a subprocess command +- Press `F1` to toggle the context-sensitive help panel +- Press `Ctrl+T` to cycle through argument presets for the active persona +- Press `Ctrl+Q` to quit + +### Session management + +```bash +agents session create --actor openai/gpt-4o +agents session list +agents session export --session-id --output session.json +agents session import --input session.json +``` + +### Server mode + +```bash +# connect to a remote CleverAgents server +agents server connect --url https://my-server.example.com --token + +# check connection status +agents server status +``` + ## Developing Pre-commit hooks run automatically on every `git commit` (formatting, linting, type diff --git a/docs/reference/persona.md b/docs/reference/persona.md new file mode 100644 index 000000000..98b706420 --- /dev/null +++ b/docs/reference/persona.md @@ -0,0 +1,153 @@ +# Persona System + +The **persona system** is a TUI-specific feature that lets users define named +identities, each binding an actor, argument presets, and project/plan scope +references. Personas are stored as YAML files and managed through the TUI or +the `PersonaRegistry` Python API. + +## Overview + +A persona answers the question: *"Who am I talking to, and with what +configuration?"* Each persona captures: + +- **Actor** — the LLM actor to use (e.g. `openai/gpt-4o`) +- **Base arguments** — default arguments merged into every request +- **Argument presets** — named override sets cycled with `Ctrl+T` in the TUI +- **Scope references** — projects and plans always in context +- **Display metadata** — name, description, icon, color, greeting + +## Storage + +Personas are stored as YAML files in: + +``` +~/.config/cleveragents/personas/.yaml +``` + +Override the directory with `CLEVERAGENTS_CONFIG_DIR`. + +The last-used persona name is persisted to: + +``` +~/.config/cleveragents/tui-state.yaml +``` + +## Persona Schema + +```yaml +name: my-persona # Required. No path separators or control chars. +actor: openai/gpt-4o # Required. Must be namespaced (namespace/name). +description: "My persona" # Optional description. +icon: "" # Optional display icon character. +color: null # Optional terminal color string. +base_arguments: {} # Arguments merged into every request. +scoped_projects: # Projects always in scope for this persona. + - local/my-project +scoped_plans: [] # Plan IDs always in scope. +cycle_order: 1 # Position in Ctrl+T cycle (0 = excluded from cycle). +greeting: "Hello!" # Optional greeting shown on activation. +argument_presets: + - name: default # Required. Must have empty overrides. + display: default + overrides: {} + - name: concise + display: Concise + overrides: + max_tokens: 256 + temperature: 0.3 +``` + +### Validation rules + +| Field | Rule | +|-------|------| +| `name` | No `/`, `\`, `..`, null bytes, or ASCII control characters | +| `actor` | Must contain `/` (namespaced) | +| `argument_presets` | Must contain exactly one `default` preset with empty `overrides` | +| `cycle_order` | Must be unique across all personas when greater than zero | + +## Argument Presets + +Presets provide named argument override sets. The `default` preset is always +present and has empty overrides. Additional presets shallow-merge their +`overrides` on top of `base_arguments` when computing effective arguments. + +```python +persona.effective_arguments("concise") +# → {**base_arguments, **concise.overrides} +``` + +In the TUI, press `Ctrl+T` to cycle through presets in `cycle_order` sequence. + +## Python API + +### `PersonaRegistry` + +```python +from cleveragents.tui.persona.registry import PersonaRegistry +from pathlib import Path + +registry = PersonaRegistry() # uses ~/.config/cleveragents +registry = PersonaRegistry(config_dir=Path("/custom/dir")) + +# List all personas +personas = registry.list_personas() + +# Get a single persona +persona = registry.get("my-persona") # returns None if not found + +# Save (create or update) +registry.save(persona) + +# Delete +registry.delete("my-persona") # returns True if deleted + +# Export / import +registry.export_persona("my-persona", Path("export.yaml")) +imported = registry.import_persona(Path("export.yaml")) + +# Ensure a default persona exists +registry.ensure_default(actor="openai/gpt-4o") +``` + +### `PersonaState` + +`PersonaState` tracks the active persona and current preset per TUI session: + +```python +from cleveragents.tui.persona.state import PersonaState +from cleveragents.tui.persona.registry import PersonaRegistry + +state = PersonaState(registry=PersonaRegistry()) + +# Get active persona for a session +persona = state.active_persona("session-123") + +# Switch persona +state.set_active_persona("session-123", "my-persona") + +# Get / cycle preset +current = state.current_preset("session-123") +next_preset = state.cycle_preset("session-123") + +# Compute effective arguments +args = state.effective_arguments("session-123") +``` + +## TUI Slash Commands + +| Command | Description | +|---------|-------------| +| `/persona:list` | List all personas | +| `/persona:set` | Switch the active persona | +| `/persona:create` | Create a new persona | +| `/persona:edit` | Edit an existing persona | +| `/persona:delete` | Delete a persona | +| `/persona:export` | Export persona YAML to a file | +| `/persona:import` | Import persona YAML from a file | + +## Related Documentation + +- [TUI Reference](tui.md) +- [ADR-045: TUI Persona System](../adr/ADR-045-tui-persona-system.md) +- [ADR-044: TUI Architecture and Framework](../adr/ADR-044-tui-architecture-and-framework.md) diff --git a/docs/reference/tui.md b/docs/reference/tui.md new file mode 100644 index 000000000..84b172487 --- /dev/null +++ b/docs/reference/tui.md @@ -0,0 +1,359 @@ +# TUI Reference + +The `agents tui` command launches the **CleverAgents Terminal User Interface** — a +full-screen, interactive application built on [Textual](https://textual.textualize.io/). +The TUI provides real-time plan monitoring, multi-session management, persona switching, +and rich conversation with actors in a single terminal window. + +## Installation + +The TUI requires the optional `tui` extra: + +```bash +pip install 'cleveragents[tui]' +``` + +Without this extra, `agents tui` raises an actionable error: + +``` +RuntimeError: Textual dependency missing. Install with: pip install 'cleveragents[tui]' +``` + +## Launching the TUI + +```bash +agents tui +``` + +### Options + +| Flag | Description | +|------|-------------| +| `--headless` | Run a one-shot startup check without opening the full UI loop (useful for CI smoke tests) | + +## Layout + +The TUI is composed of the following regions, rendered top-to-bottom: + +``` +┌─────────────────────────────────────────────────────┐ +│ Header (clock) │ +├─────────────────────────────────────────────────────┤ +│ Conversation area │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ Help Panel Overlay (F1, hidden by default) │ │ +│ └─────────────────────────────────────────────┘ │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ Reference Picker Overlay (@) │ │ +│ └─────────────────────────────────────────────┘ │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ Slash Command Overlay (/) │ │ +│ └─────────────────────────────────────────────┘ │ +│ Prompt Input │ +│ Persona Bar │ +├─────────────────────────────────────────────────────┤ +│ Footer (key bindings) │ +└─────────────────────────────────────────────────────┘ +``` + +## Global Key Bindings + +| Key | Action | +|-----|--------| +| `Ctrl+Q` | Quit the TUI immediately | +| `F1` | Toggle the context-sensitive help panel | +| `Ctrl+T` | Cycle to the next argument preset for the active persona | +| `Escape` | Close the current overlay and return to the prompt | + +## Input Modes + +The prompt detects the input mode from the first character of the text: + +| Prefix | Mode | Behaviour | +|--------|------|-----------| +| *(none)* | **Normal** | Message text with optional `@reference` expansion | +| `/` | **Command** | Slash command dispatched to the command router | +| `!` or `$` | **Shell** | Shell command executed via subprocess | + +### Normal Mode + +Type a message and press `Enter` to submit. Use `@` to open the Reference Picker +overlay and insert file, resource, or plan references inline. + +### Command Mode (`/`) + +Type `/` to open the Slash Command overlay. A filtered list of matching commands +appears as you type. Press `Enter` to dispatch the selected command. + +See [Slash Commands](#slash-commands) for the full catalog. + +### Shell Mode (`!`) + +Type `!` followed by a shell command to execute it in a subprocess. Output is +captured and displayed in the conversation area. + +!!! warning "Shell mode safety" + Shell execution is gated by the `CLEVERAGENTS_ALLOW_DANGEROUS_SHELL` + environment variable. Set it to `1` or `true` to permit shell commands. + When unset, shell commands are blocked. + +## Help Panel (F1) + +Press `F1` at any time to toggle the context-sensitive help panel. The panel +content adapts to the current prompt context: + +| Context | Triggered when | +|---------|---------------| +| **Main Screen** | Prompt is empty or contains normal text | +| **Slash Commands** | Prompt starts with `/` | +| **Reference Picker** | Prompt contains `@` | +| **Shell Mode** | Prompt starts with `!` or `$` | + +Each context shows global key bindings plus context-specific shortcuts. + +## Persona Bar + +The status bar at the bottom of the conversation area displays: + +``` + | | | scope refs +``` + +- **persona_name** — the active persona (e.g. `default`) +- **actor_name** — the actor bound to the persona (e.g. `openai/gpt-4o`) +- **preset_name** — the active argument preset (e.g. `default`) +- **scope refs** — count of scoped projects and plans + +Use `Ctrl+T` to cycle through the argument presets defined in the active persona. + +## Slash Commands + +The TUI ships with **67 slash commands** across **14 groups**. Type `/` in the +prompt to open the overlay and filter by name. + +### Session + +| Command | Description | +|---------|-------------| +| `/session:create` | Create a new session tab | +| `/session:list` | Display all sessions | +| `/session:show` | Show session details | +| `/session:switch` | Switch to a session | +| `/session:close` | Close the current session | +| `/session:delete` | Delete a saved session | +| `/session:rename` | Rename current session | +| `/session:export` | Export session to JSON | +| `/session:import` | Import session from JSON | + +### Persona + +| Command | Description | +|---------|-------------| +| `/persona:list` | Display all personas | +| `/persona:set` | Switch active persona | +| `/persona:create` | Create a persona | +| `/persona:edit` | Edit a persona | +| `/persona:delete` | Delete a persona | +| `/persona:export` | Export persona YAML | +| `/persona:import` | Import persona YAML | + +### Scope + +| Command | Description | +|---------|-------------| +| `/scope:add` | Add scope reference | +| `/scope:remove` | Remove scope reference | +| `/scope:clear` | Clear session scope additions | +| `/scope:show` | Show effective scope | + +### Plan + +| Command | Description | +|---------|-------------| +| `/plan:use` | Start a new plan | +| `/plan:list` | List plans | +| `/plan:status` | Show plan status | +| `/plan:tree` | Show decision tree | +| `/plan:execute` | Execute a plan | +| `/plan:apply` | Apply a completed plan | +| `/plan:cancel` | Cancel a plan | +| `/plan:diff` | Show plan diff | +| `/plan:correct` | Correct a decision | +| `/plan:resume` | Resume a plan | +| `/plan:revert` | Revert plan state | +| `/plan:rollback` | Rollback to checkpoint | +| `/plan:explain` | Explain a decision | +| `/plan:errors` | Show plan errors | +| `/plan:artifacts` | Show plan artifacts | +| `/plan:inspect` | Inspect plan details | + +### Project + +| Command | Description | +|---------|-------------| +| `/project:list` | List projects | +| `/project:create` | Create project | +| `/project:show` | Show project details | +| `/project:delete` | Delete project | +| `/project:inspect` | Inspect project details | +| `/project:context:show` | Show project context policy | + +### Actor + +| Command | Description | +|---------|-------------| +| `/actor:list` | List actors | +| `/actor:show` | Show actor details | +| `/actor:set-default` | Set default actor | + +### Resource + +| Command | Description | +|---------|-------------| +| `/resource:list` | List resources | +| `/resource:show` | Show resource details | +| `/resource:tree` | Show resource tree | +| `/resource:inspect` | Inspect resource details | + +### Config + +| Command | Description | +|---------|-------------| +| `/config:list` | List config entries | +| `/config:get` | Get config value | +| `/config:set` | Set config value | + +### Tool + +| Command | Description | +|---------|-------------| +| `/tool:list` | List tools | +| `/tool:show` | Show tool details | + +### Skill + +| Command | Description | +|---------|-------------| +| `/skill:list` | List skills | +| `/skill:show` | Show skill details | + +### Invariant + +| Command | Description | +|---------|-------------| +| `/invariant:list` | List invariants | +| `/invariant:add` | Add invariant | +| `/invariant:remove` | Remove invariant | + +### Profile + +| Command | Description | +|---------|-------------| +| `/profile:list` | List automation profiles | +| `/profile:show` | Show automation profile | + +### Context + +| Command | Description | +|---------|-------------| +| `/context:inspect` | Inspect context state | +| `/context:set` | Set context policy | +| `/context:simulate` | Simulate context assembly | + +### Utility + +| Command | Description | +|---------|-------------| +| `/clear` | Clear conversation display | +| `/theme` | Switch color theme | +| `/settings` | Open settings | +| `/help` | Show help | +| `/about` | Show version information | +| `/debug` | Toggle debug mode | + +## Persona System + +Personas are YAML configuration files stored in `~/.config/cleveragents/personas/` +(overridable via `CLEVERAGENTS_CONFIG_DIR`). Each persona binds an actor, optional +argument presets, and scope references to a named identity. + +### Persona YAML Schema + +```yaml +name: my-persona # Required. Must not contain path separators. +actor: openai/gpt-4o # Required. Must be namespaced (namespace/name). +description: "My persona" # Optional. +icon: "" # Optional display icon. +color: null # Optional terminal color. +base_arguments: {} # Default arguments merged into every request. +scoped_projects: [] # Project names always in scope. +scoped_plans: [] # Plan IDs always in scope. +cycle_order: 0 # Position in Ctrl+T cycle (0 = excluded). +greeting: "" # Optional greeting message on activation. +argument_presets: # Named argument override sets. + - name: default # Required. Must have empty overrides. + display: default + overrides: {} + - name: verbose + display: Verbose + overrides: + verbosity: high +``` + +### Rules + +- Every persona must contain exactly one `default` preset with empty `overrides`. +- `cycle_order` values must be unique when greater than zero. +- `actor` must be namespaced: `namespace/name`. +- `name` must not contain `/`, `\`, `..`, null bytes, or control characters. + +### Persona State + +The TUI tracks the active persona and current preset per session in memory. +The last-used persona name is persisted to `~/.config/cleveragents/tui-state.yaml` +and restored on the next launch. + +### Import / Export + +```bash +# Export a persona to a file +/persona:export # then provide name and output path + +# Import a persona from a file +/persona:import # then provide the YAML file path +``` + +Export and import paths must be relative to the current working directory. + +## Architecture + +The TUI is implemented as a Textual `App` subclass (`CleverAgentsTuiApp`) in +`src/cleveragents/tui/app.py`. It communicates with the application layer +exclusively through the A2A local facade — the same protocol used by the CLI. + +Key modules: + +| Module | Purpose | +|--------|---------| +| `tui/app.py` | Main Textual app, widget composition, key bindings | +| `tui/persona/schema.py` | `Persona` and `PersonaPreset` Pydantic models | +| `tui/persona/registry.py` | YAML-backed persona storage with file locking | +| `tui/persona/state.py` | In-memory session-to-persona mapping | +| `tui/input/modes.py` | `InputModeRouter` — normal / command / shell dispatch | +| `tui/input/reference_parser.py` | `@reference` expansion and fuzzy suggestions | +| `tui/input/shell_exec.py` | Subprocess shell execution with safety gate | +| `tui/slash_catalog.py` | `SLASH_COMMAND_SPECS` — 67-command catalog | +| `tui/widgets/help_panel_overlay.py` | Context-sensitive F1 help panel | +| `tui/widgets/persona_bar.py` | Bottom status bar showing active persona | +| `tui/widgets/prompt.py` | Prompt input widget | +| `tui/widgets/reference_picker.py` | `@reference` picker overlay | +| `tui/widgets/slash_command_overlay.py` | `/command` picker overlay | + +## Related Documentation + +- [ADR-044: TUI Architecture and Framework](../adr/ADR-044-tui-architecture-and-framework.md) +- [ADR-045: TUI Persona System](../adr/ADR-045-tui-persona-system.md) +- [ADR-046: TUI Reference and Command System](../adr/ADR-046-tui-reference-and-command-system.md) +- [Session CLI Reference](session_cli.md) +- [Output Rendering Framework](output_rendering.md) +- [REPL Reference](repl.md)