This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Timmy-time-dashboard/src/timmy/cli.py

140 lines
4.1 KiB
Python

import subprocess
from typing import Optional
import typer
from timmy.agent import create_timmy
from timmy.prompts import STATUS_PROMPT
app = typer.Typer(help="Timmy — sovereign AI agent")
# Shared option definitions (reused across commands for consistency).
_BACKEND_OPTION = typer.Option(
None,
"--backend",
"-b",
help="Inference backend: 'ollama' (default) | 'airllm' | 'auto'",
)
_MODEL_SIZE_OPTION = typer.Option(
None,
"--model-size",
"-s",
help="AirLLM model size when --backend airllm: '8b' | '70b' | '405b'",
)
@app.command()
def tick():
"""Run one autonomous thinking cycle (used by systemd timer)."""
import asyncio
from timmy.thinking import thinking_engine
thought = asyncio.run(thinking_engine.think_once())
if thought:
typer.echo(f"[{thought.seed_type}] {thought.content}")
else:
typer.echo("No thought produced (thinking disabled or Ollama down).")
@app.command()
def think(
topic: str = typer.Argument(..., help="Topic to reason about"),
backend: Optional[str] = _BACKEND_OPTION,
model_size: Optional[str] = _MODEL_SIZE_OPTION,
):
"""Ask Timmy to think carefully about a topic."""
timmy = create_timmy(backend=backend, model_size=model_size)
timmy.print_response(f"Think carefully about: {topic}", stream=True)
@app.command()
def chat(
message: str = typer.Argument(..., help="Message to send"),
backend: Optional[str] = _BACKEND_OPTION,
model_size: Optional[str] = _MODEL_SIZE_OPTION,
):
"""Send a message to Timmy."""
timmy = create_timmy(backend=backend, model_size=model_size)
timmy.print_response(message, stream=True)
@app.command()
def status(
backend: Optional[str] = _BACKEND_OPTION,
model_size: Optional[str] = _MODEL_SIZE_OPTION,
):
"""Print Timmy's operational status."""
timmy = create_timmy(backend=backend, model_size=model_size)
timmy.print_response(STATUS_PROMPT, stream=False)
@app.command()
def interview(
backend: Optional[str] = _BACKEND_OPTION,
model_size: Optional[str] = _MODEL_SIZE_OPTION,
):
"""Initialize Timmy and run a structured interview.
Asks Timmy a series of questions about his identity, capabilities,
values, and operation to verify he is working correctly.
"""
from timmy.interview import InterviewEntry, format_transcript, run_interview
from timmy.session import chat
typer.echo("Initializing Timmy for interview...\n")
# Force agent creation by calling chat once with a warm-up prompt
try:
chat("Hello, Timmy. We're about to start your interview.", session_id="interview")
except Exception as exc:
typer.echo(f"Warning: Initialization issue — {exc}", err=True)
def _on_answer(entry: InterviewEntry) -> None:
typer.echo(f"[{entry.category}]")
typer.echo(f" Q: {entry.question}")
typer.echo(f" A: {entry.answer}")
typer.echo()
typer.echo("Starting interview...\n")
transcript = run_interview(
chat_fn=lambda msg: chat(msg, session_id="interview"),
on_answer=_on_answer,
)
# Print full transcript at the end
typer.echo("\n" + format_transcript(transcript))
@app.command()
def up(
dev: bool = typer.Option(False, "--dev", help="Enable hot-reload for development"),
build: bool = typer.Option(True, "--build/--no-build", help="Rebuild images before starting"),
):
"""Start Timmy Time in Docker (dashboard + agents)."""
cmd = ["docker", "compose"]
if dev:
cmd += ["-f", "docker-compose.yml", "-f", "docker-compose.dev.yml"]
cmd += ["up", "-d"]
if build:
cmd.append("--build")
mode = "dev mode (hot-reload active)" if dev else "production mode"
typer.echo(f"Starting Timmy Time in {mode}...")
result = subprocess.run(cmd)
if result.returncode == 0:
typer.echo(f"\n Timmy Time running at http://localhost:8000 ({mode})\n")
else:
typer.echo("Failed to start. Is Docker running?", err=True)
raise typer.Exit(1)
@app.command()
def down():
"""Stop all Timmy Time Docker containers."""
subprocess.run(["docker", "compose", "down"], check=True)
def main():
app()