Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
- **User Profile & Identity**: Name and background provided at session start; agents treat the user as an equal room participant.
- **Global Orchestrator**: A designated room moderator that fires every N turns to summarize or redirect agents, with no runaway loop risk.
- **Timestamped Session Memory**: All turns, messages, and system events are tagged with precise timestamps for full auditability.
- **Optional Skillware Integration**: Assign skills per agent, execute tools lazily, and keep user-facing replies natural.

## Framework Capabilities

Expand All @@ -54,9 +55,10 @@ The framework allows extreme granularity in handling session configurations:

For deeper insights into how to leverage and modify the framework, please refer to our dedicated documentation guides:

- [Architecture & LiteLLM Guide](docs/ARCHITECTURE.md) - Understand how local API routing, session memory, and agent selection work.
- [Architecture & LiteLLM Guide](docs/ARCHITECTURE.md) - Understand local API routing, session memory, orchestration, and tool logging.
- [Use Cases, Examples & Best Practices](docs/EXAMPLES.md) - Parameter cheat sheet, deep persona guide, scenario walkthroughs, and an edge case reference table.
- [Testing Strategy](docs/TESTING.md) - How to write and run deterministic tests for multi-agent logic.
- [Skillware Integration Guide](docs/SKILLWARE.md) - Skills CLI commands, wizard assignment flow, and optional dependency behavior.
- [Testing Strategy](docs/TESTING.md) - How to write and run deterministic tests for multi-agent and skills logic.
- [Contributing Guide](CONTRIBUTING.md) - Learn how to contribute to the project, report bugs, and follow our design philosophy.
- [Project Changelog](CHANGELOG.md) - Track all notable updates, fixes, and pre-release changes to the framework.

Expand All @@ -69,7 +71,7 @@ Rooms/
│ ├── config.py # Pydantic Configuration Models
│ ├── agent.py # Agent & LiteLLM/Custom Logic
│ ├── session.py # Turn Orchestration & Memory
│ ├── settings.py # YAML settings loader (#26, #27)
│ ├── settings.py # YAML settings loader
│ └── storage.py # Secure Log Serialization
├── tests/ # Unit Tests
│ └── test_session.py # Logic Verification
Expand Down Expand Up @@ -99,7 +101,7 @@ venv\Scripts\activate # Windows: venv\Scripts\activate | Unix: source venv/bin/
pip install -r requirements.txt
```
#### Optional: Long-Term Memory & RAG Support
If you plan to use vector memory features (such as long-term agent memory across sessions (#13)), you will need to install the heavier machine learning dependencies separately:
If you plan to use vector memory features, install the heavier machine learning dependencies separately:
```bash
pip install -r requirements-memory.txt
```
Expand Down Expand Up @@ -131,10 +133,13 @@ The wizard will step you through:
- Setting your user profile (name and background)
- Defining the session topic and turn limits
- Inviting default or custom agents with individual temperatures and system prompts
- Optionally assigning Skillware skills (and per-skill overrides) to custom agents
- Optionally assigning a Global Orchestrator

During a session, type `@AgentName` in any user input to force a specific agent to respond next.

For skills-specific commands and usage, see `docs/SKILLWARE.md`.

**Run Tests**
```bash
# Always run via pytest with PYTHONPATH set:
Expand All @@ -145,10 +150,6 @@ $env:PYTHONPATH="."; python -m pytest tests/ -v

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Roadmap & Progress

Track our active progress on the [GitHub Issues](https://github.com/arpahls/Rooms/issues) board.

<br>
<div align="center">
<img src="https://raw.githubusercontent.com/arpahls/cfd/main/assets/arpalogo26.png" width="50" alt="ARPA Logo">
Expand Down
123 changes: 123 additions & 0 deletions cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from rooms.agent import Agent
from rooms.session import Session
from rooms.storage import save_transcript
from rooms.skills_cli import list_skills, inspect_skill, suggest_skills
from rooms.settings import (
RoomsSettings,
SettingsError,
Expand Down Expand Up @@ -92,9 +93,52 @@ def create_custom_agent_wizard(settings: RoomsSettings, tracked_env_keys: Option

config.color = Prompt.ask("CLI output color (e.g. red, green, blue, cyan, magenta, yellow)", default="blue")
config.temperature = float(Prompt.ask("Generation Temperature", default=str(defaults.temperature)))
_assign_skills_in_wizard(config)
return config


def _assign_skills_in_wizard(config: AgentConfig) -> None:
"""Optional skill assignment step for custom agents."""
if not Confirm.ask("Assign Skillware skills to this agent?", default=False):
return

skills, err = list_skills()
if err:
console.print(f"[yellow]{err}[/yellow]")
if not Confirm.ask("Continue with manual skill IDs anyway?", default=False):
return

if skills:
console.print("\n[bold green]Available Skills[/bold green]")
for item in skills:
desc = item.get("description", "").strip()
suffix = f" - {desc}" if desc else ""
console.print(f"- {item['id']}{suffix}")

raw = Prompt.ask(
"Skill IDs to assign (comma separated, leave blank to skip)",
default="",
).strip()
if not raw:
return
config.skills = [item.strip() for item in raw.split(",") if item.strip()]

for skill_id in config.skills:
if Confirm.ask(f"Add runtime config overrides for {skill_id}?", default=False):
cfg_raw = Prompt.ask(
f"Enter {skill_id} overrides as key=value pairs (comma separated)",
default="",
).strip()
overrides = {}
if cfg_raw:
for pair in [p.strip() for p in cfg_raw.split(",") if p.strip()]:
if "=" in pair:
key, value = pair.split("=", 1)
overrides[key.strip()] = value.strip()
if overrides:
config.skill_settings[skill_id] = overrides


def main_menu(settings: RoomsSettings):
console.print(Panel.fit("[bold magenta]Multi-Agent Room Framework[/bold magenta]", subtitle="Advanced Scenario Wizard"))
default_personas = get_default_personas(settings)
Expand Down Expand Up @@ -286,6 +330,65 @@ def cmd_config_reset(args: argparse.Namespace) -> int:
return 0


def cmd_skills_list(_args: argparse.Namespace) -> int:
skills, err = list_skills()
if err:
console.print(f"[yellow]{err}[/yellow]")
return 0
if not skills:
console.print("[yellow]No skills discovered.[/yellow]")
return 0

console.print("[bold green]Available Skills[/bold green]")
for item in skills:
desc = item.get("description", "").strip()
suffix = f" - {desc}" if desc else ""
console.print(f"- {item['id']}{suffix}")
return 0


def cmd_skills_inspect(args: argparse.Namespace) -> int:
payload, err = inspect_skill(args.skill_id)
if err:
console.print(f"[yellow]{err}[/yellow]")
return 1

console.print(Panel.fit(f"[bold]{payload['id']}[/bold]", title="Skill"))
if payload.get("version"):
console.print(f"[cyan]Version:[/cyan] {payload['version']}")
if payload.get("description"):
console.print(f"[cyan]Description:[/cyan] {payload['description']}")
if payload.get("inputs"):
console.print(f"[cyan]Inputs:[/cyan] {payload['inputs']}")
if payload.get("instructions"):
console.print(Rule("Skill Instructions"))
console.print(payload["instructions"])
return 0


def cmd_skills_suggest(args: argparse.Namespace) -> int:
expertise = [item.strip() for item in args.expertise.split(",") if item.strip()]
if not expertise:
console.print("[yellow]No expertise keywords provided.[/yellow]")
return 1
skills, err = list_skills()
if err:
console.print(f"[yellow]{err}[/yellow]")
return 0

suggested = suggest_skills(skills, expertise)
if not suggested:
console.print("[yellow]No suggested skills matched your expertise keywords.[/yellow]")
return 0

console.print("[bold green]Suggested Skills[/bold green]")
for item in suggested:
desc = item.get("description", "").strip()
suffix = f" - {desc}" if desc else ""
console.print(f"- {item['id']}{suffix}")
return 0


def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Multi-Agent Room Framework")
parser.add_argument(
Expand All @@ -303,6 +406,18 @@ def build_parser() -> argparse.ArgumentParser:
reset_p.add_argument("--path", help="Specific settings file to remove")
reset_p.add_argument("-y", "--yes", action="store_true", help="Skip confirmation")

skills_parser = sub.add_parser("skills", help="Rooms-native Skillware discovery and inspection")
skills_sub = skills_parser.add_subparsers(dest="skills_cmd", required=True)
skills_sub.add_parser("list", help="List available skills")
inspect_p = skills_sub.add_parser("inspect", help="Inspect a specific skill")
inspect_p.add_argument("skill_id", help="Skill ID, e.g. finance/wallet_screening")
suggest_p = skills_sub.add_parser("suggest", help="Suggest skills from expertise keywords")
suggest_p.add_argument(
"--expertise",
required=True,
help="Comma-separated keywords, e.g. finance,risk,compliance",
)

parser.add_argument(
"--skip-preflight",
action="store_true",
Expand Down Expand Up @@ -330,6 +445,14 @@ def main(argv: Optional[List[str]] = None) -> int:
if args.config_cmd == "reset":
return cmd_config_reset(args)
return 1
if args.command == "skills":
if args.skills_cmd == "list":
return cmd_skills_list(args)
if args.skills_cmd == "inspect":
return cmd_skills_inspect(args)
if args.skills_cmd == "suggest":
return cmd_skills_suggest(args)
return 1

try:
settings = load_settings(args.config, required=bool(args.config))
Expand Down
15 changes: 15 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ At the end of a session, the user is prompted to optionally save. Two formats ar

The filename is auto-suggested from a short slug of the session topic (e.g. `bioethics_of_designer_babies.md`). System bootstrap messages are excluded from saved output.

For skill-enabled agents, transcript exports also include structured skill execution events (`role: skill`) with tool name, arguments, status, and result payload for auditability.

## User Profile & Participant Identity
The wizard captures a **user name and background** before the session starts. This is injected into the global session introduction, so all agents are explicitly informed of who the human participant is and can treat them as an equal voice in the room.

Expand Down Expand Up @@ -99,6 +101,19 @@ If you do not want to use LiteLLM at all, the framework allows you to inject any

The framework will dynamically import your file at runtime and use it exclusively for that agent's turns. Note that custom functions are executed with a timeout boundary (using the agent's configured `timeout` setting) to prevent infinite UI hangups.

## Skillware Integration

Rooms includes optional Skillware support through native CLI and wizard flows.

The integration is designed to:

- preserve Rooms terminal UX and styling
- fail gracefully when Skillware is unavailable
- keep skill loading lazy and per-agent
- keep user-facing answers natural while logging structured tool events

For command usage and setup, see `docs/SKILLWARE.md`.

## CI/CD and Robustness
To ensure the framework remains stable as it grows, we maintain a comprehensive CI/CD pipeline using **GitHub Actions**. Every contribution is automatically tested against Python 3.13 for:
- **Linting**: High-standard code hygiene via `flake8`.
Expand Down
12 changes: 12 additions & 0 deletions docs/EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,15 @@ If you are running the application in a CI/CD automation environment, running au
```bash
python cli.py --skip-preflight
```

### Skills in Real Sessions

You can assign optional skills to custom agents during wizard setup.

Recommended flow:

- start with one focused skill per agent
- keep expertise keywords aligned with expected tool usage
- use per-skill overrides only when needed

For complete command reference and setup, see `docs/SKILLWARE.md`.
58 changes: 58 additions & 0 deletions docs/SKILLWARE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Skillware Integration

Rooms supports optional Skillware-based tool use for agents.

## Design Principles

- Skills are assigned per agent, not globally.
- Skillware is loaded lazily only when an agent has configured skills.
- Agent replies remain human-readable even when tools are used.
- Skill execution metadata is logged as structured session events.

## Install (Optional)

```bash
pip install skillware
```

Rooms works normally without Skillware. Skill commands and wizard steps fail gracefully with guidance.

## Skills CLI Commands

```bash
python cli.py skills list
python cli.py skills inspect finance/wallet_screening
python cli.py skills suggest --expertise finance,risk,compliance
```

## Wizard Assignment Flow

When creating a custom agent, you can optionally:

- assign one or more skill IDs
- add per-skill override settings (`key=value` pairs)
- skip skills entirely

Assigned skills are stored in agent config:

- `skills`
- `skill_settings`

## Runtime Behavior

- Tools are exposed to the model only for agents with configured skills.
- Skill calls are guarded by per-turn and per-session limits.
- Tool results are passed back to the model for second-pass synthesis.
- Final user-visible output remains a normal agent message, not raw JSON.

## Session Logging and Transcripts

Skill calls are recorded as structured `role: skill` events in session history.

Saved transcripts include those events with:

- agent name
- tool name
- arguments
- status
- result payload
14 changes: 12 additions & 2 deletions docs/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ PYTHONPATH=. python -m pytest tests/ -v

## Settings / CLI smoke (no Ollama)

Fast checks for [#26](https://github.com/ARPAHLS/rooms/issues/26) / [#27](https://github.com/ARPAHLS/rooms/issues/27) — no interactive wizard, no live inference:
Fast checks for settings and CLI behavior with no interactive wizard and no live inference:

```bash
# Windows (PowerShell)
Expand All @@ -36,7 +36,8 @@ $env:PYTHONPATH="."; python -m pytest tests/test_settings.py tests/test_cli_sett
|---|---|
| `tests/test_settings.py` | YAML load/validation, personas, builtin defaults; asserts `rooms.settings.example.yaml` exists in repo |
| `tests/test_cli_settings_smoke.py` | `cli.py config init`, `config reset`, `--config` wiring |
| `tests/test_cli.py` | Wizard API-key env cleanup (#5) |
| `tests/test_cli.py` | Wizard env cleanup, Skills CLI command behavior, wizard skill assignment flow |
| `tests/test_skills_cli.py` | Skillware wrapper discovery/inspect normalization and suggestion matching |

## Session logic coverage

Expand All @@ -57,6 +58,15 @@ $env:PYTHONPATH="."; python -m pytest tests/test_settings.py tests/test_cli_sett

Run the full suite with `python -m pytest tests/ -v` (see **Running Tests** above).

## Skillware UX coverage

Rooms includes tests for native Skillware UX:

- `skills list` command output path (and graceful no-Skillware path)
- `skills inspect <skill_id>` rendering
- `skills suggest --expertise ...` keyword matching behavior
- custom-agent wizard optional skill assignment and per-skill overrides

## How to Write Custom Tests

### Step 1: Define a Mock Configuration
Expand Down
Loading
Loading