The Friday Assistant Runtime
Project description
Friday Framework CLI
Rich-based terminal interface components for the Friday Framework.
Version: 0.1.0
Overview
Friday CLI provides professional terminal interface components using the Rich and Prompt Toolkit libraries, including:
- Display: Status messages, tables, syntax highlighting, progress indicators
- Input: Readline-style editing, command history, auto-completion
Installation
# From the monorepo root
uv sync
# Or install directly from PyPI
pip install friday-framework-cli
Quick Start
from friday_cli import (
display_error,
display_success,
display_table,
spinner,
)
# Status messages
display_success("Task completed")
display_error("Something went wrong", exception=ValueError("details"))
# Tables
data = [{"name": "Alice", "role": "Admin"}, {"name": "Bob", "role": "User"}]
display_table(data, title="Users")
# Progress spinner
with spinner("Processing...") as status:
# do work
status.update("Almost done...")
API Reference
Console Management
get_console() -> Console
Returns the shared Rich Console instance (singleton pattern).
set_console(console: Console) -> None
Sets a custom console instance. Useful for testing or custom output destinations.
from rich.console import Console
from friday_cli import set_console, get_console
# For testing - capture output
import io
string_io = io.StringIO()
test_console = Console(file=string_io, force_terminal=True)
set_console(test_console)
# Reset to default
set_console(None)
Status Messages
All status functions display styled messages with icons.
display_error(message: str, exception: Exception | None = None, show_traceback: bool = False) -> None
Display an error message with red styling and X icon.
display_error("Operation failed")
# With exception details
try:
raise ValueError("Invalid input")
except ValueError as e:
display_error("Validation error", exception=e)
# With full traceback
display_error("Critical failure", exception=e, show_traceback=True)
display_warning(message: str) -> None
Display a warning message with yellow styling and warning icon.
display_warning("Configuration not found, using defaults")
display_success(message: str) -> None
Display a success message with green styling and checkmark icon.
display_success("File saved successfully")
display_info(message: str) -> None
Display an info message with blue styling and info icon.
display_info("Processing 42 items...")
Structured Data Display
display_json(data: Any, title: str | None = None, indent: int = 2) -> None
Display JSON data with syntax highlighting.
data = {"status": "ok", "count": 42, "items": ["a", "b", "c"]}
display_json(data, title="API Response")
display_code(code: str, language: str = "python", line_numbers: bool = True, title: str | None = None) -> None
Display code with syntax highlighting.
code = '''
def greet(name: str) -> str:
return f"Hello, {name}!"
'''
display_code(code, language="python", title="greeting.py")
display_table(data: list[dict], title: str | None = None, columns: list[str] | None = None, show_header: bool = True, box_style: str = "rounded") -> None
Display data as a formatted table.
users = [
{"name": "Alice", "age": "30", "role": "Admin"},
{"name": "Bob", "age": "25", "role": "User"},
]
display_table(users, title="Team Members")
# Custom columns (subset or reorder)
display_table(users, columns=["name", "role"])
# Box styles: "rounded", "simple", "square"
display_table(users, box_style="simple")
Progress Indicators
spinner(message: str, spinner_type: str = "dots") -> Iterator[Status]
Context manager for displaying a spinner during long-running operations.
from friday_cli import spinner
with spinner("Loading data..."):
# do work
time.sleep(2)
# With status updates
with spinner("Processing...") as status:
status.update("Step 1: Loading...")
# step 1
status.update("Step 2: Transforming...")
# step 2
progress_bar(total: int, description: str = "Processing", show_speed: bool = False) -> Iterator[Progress]
Context manager for displaying a progress bar.
from friday_cli import progress_bar
with progress_bar(100, "Downloading") as progress:
task = progress.add_task("file.zip", total=100)
for i in range(100):
# do work
progress.update(task, advance=1)
ProgressTracker
Helper class for tracking multi-step progress.
from friday_cli import ProgressTracker
tracker = ProgressTracker(
steps=["Load", "Process", "Save"],
title="Data Pipeline"
)
with tracker:
tracker.advance("Loading data...")
# load step
tracker.advance("Processing...")
# process step
tracker.advance("Saving results...")
# save step
tracker.complete()
Banners and Panels
display_banner(title: str, subtitle: str | None = None, version: str | None = None) -> None
Display a welcome banner.
display_banner(
"Friday CLI",
subtitle="Rich terminal interface",
version="0.1.0"
)
display_panel(content: str, title: str | None = None, style: str = "default") -> None
Display content in a styled panel.
display_panel("Important information here", title="Notice", style="info")
# Styles: "default", "info", "warning", "error", "success"
display_panel("Operation completed", style="success")
display_separator(char: str = "─", style: str = "muted") -> None
Display a horizontal separator line.
display_separator()
display_separator(char="=", style="cyan")
Domain-Specific Displays
These functions are designed for the Friday agent framework's specific use cases.
display_help(commands: dict[str, str], tips: list[str] | None = None, title: str = "Available Commands") -> None
Display help information with command descriptions.
commands = {
"/help": "Show this help message",
"/history": "Show conversation history",
"/exit": "Exit the program",
}
tips = [
"Use Tab for command completion",
"Type /clear to reset the session",
]
display_help(commands, tips=tips)
display_tool_budget(tools: list[dict], circuit_states: dict[str, str] | None = None) -> None
Display tool execution statistics and circuit breaker states.
tools = [
{"name": "web_search", "calls": 5, "tokens": 1200, "avg_time": 0.8},
{"name": "file_read", "calls": 12, "tokens": 800, "avg_time": 0.1},
]
circuit_states = {"web_search": "CLOSED", "file_read": "CLOSED"}
display_tool_budget(tools, circuit_states)
display_memory_stats(stats: dict[str, Any]) -> None
Display memory system statistics.
stats = {
"entities": 42,
"facts": 156,
"insights": 23,
"summaries": 8,
"history_turns": 50,
"sessions": 5,
"lifecycle": {
"ACTIVE": 30,
"CONSOLIDATED": 10,
"ARCHIVED": 2,
}
}
display_memory_stats(stats)
display_entities(entities: list[dict], relationships: list[str] | None = None) -> None
Display graph entities and their relationships.
entities = [
{"id": "abc123", "type": "Person", "label": "Alice", "hit_count": 5},
{"id": "def456", "type": "Project", "label": "Friday", "hit_count": 12},
]
relationships = [
"Alice --[WORKS_ON]--> Friday",
"Alice --[KNOWS]--> Bob",
]
display_entities(entities, relationships)
display_history(turns: list[dict], prior_turns: list[dict] | None = None, user_name: str = "User", assistant_name: str = "Assistant") -> None
Display conversation history.
turns = [
{
"timestamp": "2024-01-15 10:30",
"user_message": "Hello!",
"assistant_message": "Hi there! How can I help?"
},
]
prior_turns = [
{
"timestamp": "2024-01-14 15:00",
"user_message": "Previous question",
"assistant_message": "Previous answer"
},
]
display_history(turns, prior_turns=prior_turns)
display_context_payload(payload: dict[str, Any], token_counts: dict[str, int] | None = None) -> None
Display the assembled context payload.
payload = {
"history": [{"user": "hi", "assistant": "hello"}],
"prior_history": [],
"insights": [{"text": "User prefers concise answers"}],
"summaries": ["Previous session summary"],
"key_facts": ["Fact 1", "Fact 2"],
"entities": [{"label": "Project X"}],
}
token_counts = {
"history": 500,
"insights": 200,
"summaries": 300,
}
display_context_payload(payload, token_counts)
Input Handling
Advanced input handling with Prompt Toolkit for readline-style editing.
InputHandler
Full-featured input handler with history, completion, and styling.
from friday_cli import InputHandler
handler = InputHandler(
prompt_name="User",
commands=["help", "history", "exit"],
command_descriptions={"help": "Show help", "exit": "Quit"},
history_file="~/.friday_history",
multiline=False,
enable_auto_suggest=True,
)
# Synchronous input
text = handler.get_input()
# Async input (for async contexts)
text = await handler.get_input_async()
Features:
- Readline-style editing (Ctrl+A, Ctrl+E, Ctrl+K, etc.)
- Up/down arrows for history navigation
- Tab completion for slash commands
- Auto-suggestions from history (grayed out text)
- Persistent history to file
- Alt+Enter for newline in multi-line mode
create_friday_input_handler()
Create a pre-configured handler with Friday CLI commands.
from friday_cli import create_friday_input_handler
handler = create_friday_input_handler(
user_name="Alice",
history_file="/path/to/history",
multiline=False,
)
# All Friday commands are pre-loaded for completion
# /help, /history, /entities, /tools, etc.
CommandCompleter
Standalone completer for slash commands.
from friday_cli import CommandCompleter
from prompt_toolkit import PromptSession
completer = CommandCompleter(
commands=["help", "search", "quit"],
meta_dict={"help": "Show help"},
)
session = PromptSession(completer=completer)
Constants
from friday_cli import FRIDAY_COMMANDS, FRIDAY_COMMAND_DESCRIPTIONS
# FRIDAY_COMMANDS: list of all Friday CLI command names
# FRIDAY_COMMAND_DESCRIPTIONS: dict of command -> description
Command Registry
Decorator-based command registration with argument parsing, aliasing, and help generation.
CommandRegistry
Registry for CLI commands with dispatch and execution.
from friday_cli import CommandRegistry, arg
registry = CommandRegistry()
@registry.command("greet", aliases=["g", "hello"])
def cmd_greet(ctx, name="World"):
"""Greet someone by name."""
return f"Hello, {name}!"
@registry.command(
"export",
arguments=[arg("format", default="json", choices=["json", "csv"])],
category="data",
)
async def cmd_export(ctx, format="json"):
"""Export data in the specified format."""
return f"Exported as {format}"
# Execute commands
was_command, result = await registry.execute("/greet Alice", context)
# was_command=True, result="Hello, Alice!"
was_command, result = await registry.execute("/g Bob", context)
# was_command=True, result="Hello, Bob!" (alias)
was_command, result = await registry.execute("not a command", context)
# was_command=False, result=None
Features:
- Decorator-based registration with
@registry.command() - Programmatic registration with
registry.register() - Command aliases for shortcuts (
/hfor/history) - Argument parsing with defaults and choices
- Async and sync command support
- Help text from docstrings
- Category grouping for organized help
arg() Helper
Create argument specifications for commands.
from friday_cli import arg
# Required argument
arg("name", required=True, description="User name")
# Optional with default
arg("format", default="json", choices=["json", "csv", "xml"])
Help Generation
# Get help as dict
help_dict = registry.get_help()
# {"/greet (/g, /hello)": "Greet someone by name.", ...}
# Get help grouped by category
by_category = registry.get_help_by_category()
# {"general": {...}, "data": {...}}
# Get data for InputHandler completion
names, descriptions = registry.get_command_for_completion()
Integration Pattern
class MySession:
def __init__(self):
self.registry = CommandRegistry()
self._register_commands()
def _register_commands(self):
self.registry.register("help", self.cmd_help, aliases=["?"])
self.registry.register("exit", lambda ctx: "EXIT", aliases=["quit"])
async def handle_input(self, user_input):
# Try registry first
was_cmd, result = await self.registry.execute(user_input, self)
if was_cmd:
return result
# Fall back to other handling
return await self.process_chat(user_input)
Session Management
Configuration loading, lifecycle management, and graceful shutdown for CLI applications.
SessionConfig
Configuration container that loads from YAML files and provides typed access.
from friday_cli import SessionConfig, load_config
# Load from YAML file
config = SessionConfig.from_yaml("config.yaml")
# Or create from dict
config = SessionConfig.from_dict({"llm": {"model": "gpt-4"}})
# Typed access to common values
print(config.user_name) # "User" (default)
print(config.assistant_name) # "Assistant" (default)
print(config.system_prompt) # "You are a helpful assistant."
print(config.persist_dir) # Path or None
# Access any configuration section
print(config.llm["model"])
print(config.memory.get("persist_directory"))
# Nested access with defaults
enabled = config.get_nested("memory", "priming", "enabled", default=True)
Configuration Sections:
llm- LLM configuration (model, api_key, temperature)embedding- Embedding model configurationmemory- Memory system settingschat- Chat display settings (user_name, assistant_name, system_prompt)logging- Logging configurationextraction- Entity/fact extraction settingstranscript- Transcript storage settingsmaintenance- Maintenance task settingslifecycle- Memory lifecycle settingstools- Tool configuration
SessionManager
Async context manager for session lifecycle with signal handling.
from friday_cli import SessionManager, SessionConfig
config = SessionConfig.from_yaml("config.yaml")
# Basic usage
async with SessionManager(config=config) as ctx:
print(f"User: {ctx.config.user_name}")
# ctx.session is None without factory
# With session factory
async def create_session(config):
return MySession(config)
manager = SessionManager(
config=config,
session_factory=create_session,
on_shutdown=lambda ctx: print("Cleaning up..."),
)
async with manager as ctx:
session = ctx.session # Created by factory
# Use session...
# on_shutdown called automatically
Features:
- Async context manager (
async with) - Signal handling (SIGINT, SIGTERM) for graceful shutdown
- Session factory support (sync or async)
- Shutdown callback for cleanup
- Resource management via SessionContext
SessionContext
Container for an active session with its resources.
from friday_cli import SessionContext
# Created by SessionManager
ctx = SessionContext(session=my_session, config=config)
# Store resources for cleanup
ctx.set_resource("db", database_connection)
ctx.set_resource("cache", cache_instance)
# Retrieve resources
db = ctx.get_resource("db")
managed_session
Convenience async context manager for simple cases.
from friday_cli import managed_session
async with managed_session(config_path="config.yaml") as ctx:
print(f"User: {ctx.config.user_name}")
# Or with config object
async with managed_session(config=config, session_factory=factory) as ctx:
session = ctx.session
validate_config
Validate configuration and return list of errors.
from friday_cli import SessionConfig, validate_config
config = SessionConfig.from_yaml("config.yaml")
# Default validation (requires llm section with model)
errors = validate_config(config)
if errors:
for error in errors:
print(f"Config error: {error}")
# Custom required sections
errors = validate_config(config, required_sections=["llm", "memory"])
Integration Pattern
import asyncio
from friday_cli import SessionManager, SessionConfig, validate_config, display_error
async def main():
# Load and validate config
config = SessionConfig.from_yaml("config.yaml")
errors = validate_config(config, required_sections=["llm"])
if errors:
for error in errors:
display_error(error)
return
# Run with session management
async with SessionManager(
config=config,
session_factory=create_my_session,
on_shutdown=cleanup_resources,
) as ctx:
await run_chat_loop(ctx.session, ctx.config)
if __name__ == "__main__":
asyncio.run(main())
Testing
# Run all tests
uv run pytest apps/friday-cli/tests/ -v
# Run with coverage
uv run pytest apps/friday-cli/tests/ --cov=friday_cli
Testing with Captured Output
import io
from rich.console import Console
from friday_cli import set_console, display_success
def test_display_success():
string_io = io.StringIO()
console = Console(file=string_io, force_terminal=True)
set_console(console)
display_success("Test passed")
output = string_io.getvalue()
assert "Test passed" in output
assert "✓" in output
set_console(None) # Reset
CLI Configuration
Friday CLI supports optional theming via a cli-config.yaml file. If present, it customizes colors, icons, and prompt styling. If absent, sensible defaults are used.
Configuration File Location
Place cli-config.yaml in the same directory as your main config.yaml:
your-project/
├── config.yaml # Main application config
└── cli-config.yaml # Optional CLI theming
Loading Configuration
from friday_cli import load_cli_config, reset_console
# Load CLI config (looks for cli-config.yaml next to config.yaml)
load_cli_config("path/to/config.yaml")
reset_console() # Rebuild console with new theme
Configuration Options
# cli-config.yaml
# Theme colors (Rich style format)
theme:
error: "bold red"
warning: "bold yellow"
success: "bold green"
info: "bold blue"
muted: "dim"
highlight: "bold cyan"
# Status message icons
icons:
error: "✗" # or "[X]" for ASCII
warning: "⚠" # or "[!]" for ASCII
success: "✓" # or "[OK]" for ASCII
info: "ℹ" # or "[i]" for ASCII
# Input prompt styling
prompt:
style: "bold cyan"
name_style: "bold cyan"
separator_style: "white"
continuation_style: "gray"
Default Theme
| Style | Default | Usage |
|---|---|---|
error |
Bold red | Error messages |
warning |
Bold yellow | Warning messages |
success |
Bold green | Success messages |
info |
Bold blue | Info messages |
muted |
Dim | Secondary text |
highlight |
Bold cyan | Emphasized text |
Programmatic Configuration
from friday_cli import CLIConfig, ThemeConfig, set_cli_config, reset_console
# Create custom config
config = CLIConfig(
theme=ThemeConfig(error="magenta", success="bright_green"),
)
set_cli_config(config)
reset_console()
# Or load from dict
config = CLIConfig.from_dict({
"theme": {"error": "red"},
"icons": {"success": "[DONE]"},
})
Dependencies
rich>=13.0.0- Terminal formatting libraryprompt_toolkit>=3.0.0- Input handling with readline-style editingpyyaml>=6.0.0- YAML configuration loading
License
Part of the Friday Framework. See root LICENSE file.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file friday_framework_cli-0.1.0a0.tar.gz.
File metadata
- Download URL: friday_framework_cli-0.1.0a0.tar.gz
- Upload date:
- Size: 42.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0ddda2a152cf164078ac243a2b0929ab28d6744a359af402a8d80642798eee3
|
|
| MD5 |
5bec7658ef6a26fd2529bd307a8c74ca
|
|
| BLAKE2b-256 |
d9ac1990d3b479445e4372332df1fd79f98ec6514a9746bc653ef313681ebb7c
|
File details
Details for the file friday_framework_cli-0.1.0a0-py3-none-any.whl.
File metadata
- Download URL: friday_framework_cli-0.1.0a0-py3-none-any.whl
- Upload date:
- Size: 38.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11169c7f2e801749814545d39e5ac98686894ba59a83f6904b97df17a9bc0cfa
|
|
| MD5 |
ca89777fa6009071e73c0f612f191600
|
|
| BLAKE2b-256 |
1177bed3e6a4a31379a0d12e323b9bd7ad433c568e69e0a965c532d2ab24f123
|