Files
tai/README.md
T

199 lines
9.3 KiB
Markdown

retoor <retoor@molodetz.nl>
# tai
tai is a single-file autonomous AI agent written in Python. The entire
implementation lives in `tai.py` (about 2000 lines) and uses only the Python
standard library: no dependencies, no install step, no build system.
The agent runs as an interactive REPL or as a one-shot command. It reasons
through an OpenAI-compatible backend, acts through fourteen tools, keeps
per-profile memory, seals its stored state at rest, and can isolate shell and
file operations inside a container sandbox.
## Requirements
- Python 3.10 or newer, no third-party packages.
- Optional: `podman` or `docker` for the sandbox and Telegram voice notes.
- Optional: `tmux` for terminal content capture.
## Quick start
./tai.py
./tai.py --profile work
./tai.py --yes
./tai.py --version
./tai.py what is 2+3, use the shell
Trailing arguments form a one-shot prompt: the agent answers once and exits
with code 0. Without arguments, tai starts an interactive session.
## REPL commands
| Command | Effect |
|-------------------|---------------------------------------------------|
| `/profile [name]` | Show the current profile or switch to it |
| `/profiles` | List all profiles, current marked with `*` |
| `/env [target]` | Show or switch execution environment |
| `/skills` | List loaded skill files |
| `/fork <task>` | Spawn a background subagent, REPL stays free |
| `/agents` | List background subagents |
| `/agent <id>` | Show one subagent result |
| `/agent clear` | Purge finished subagents |
| `/compact` | Compress history into a summary |
| `/clear` | Drop history, keep the system message |
| `/help` | Show the command overview |
| `/quit` | Exit |
Any other input is sent to the agent.
## Installation
./tai.py --install
This copies `tai.py` to `~/.local/bin/tai.py` as an executable and registers
a guarded `command_not_found_handle` block in `~/.bashrc` (backed up once to
`~/.bashrc.bak-tai`, idempotent), so unknown shell commands are answered by
the agent instead of failing.
## Backends
The primary backend is `model.cloud.pravda.education`, an OpenAI-compatible
gateway that needs no API key and selects a free model per request. If a
request fails, tai retries it on `devplace.net/openai/v1`, which requires
`DEVPLACE_API_KEY`. Both endpoints speak `/chat/completions`, including
native tool calls and streaming.
## Orchestration
`/fork <task>` spawns a background subagent with its own context while the
REPL stays free (the prompt shows a `+N` counter). `/agents` lists workers,
`/agent <id>` shows a result, `/agent clear` purges finished ones.
The model itself orchestrates through the `fork` tool (task, timeout up to
one hour, profile) and the `poll` tool (id, wait up to two minutes). Workers
get 12 steps, a cooperative deadline, no session writes, and no interactive
approval prompts. Nesting is capped at two levels. Timeouts and errors
surface as statuses, never silently.
## Tools
| Tool | Purpose |
|------------------------------|------------------------------------------------------|
| `shell` | Run a shell command, output truncated |
| `read_file` | Read a text file, large files truncated |
| `write_file` | Write content to a file, creating parent directories |
| `edit_file` | Replace one unique exact text match in a file |
| `web_search` | Search the web, optionally images or page content |
| `web_fetch` | Fetch a URL and return its text content |
| `speak` | Synthesize speech, save MP3, play when possible |
| `listen` | Record from the microphone and transcribe it |
| `remember` | Merge knowledge into the profile system message |
| `recall` | Search past session memory by keyword |
| `load_skill` | Load a skill file by name |
| `get_current_terminal_content` | Capture the current tmux pane with scrollback |
| `fork` | Spawn a background subagent |
| `poll` | Collect a background subagent result |
Web search runs on `rsearch.app.molodetz.nl`. Destructive shell commands ask
for confirmation unless `--yes` is given; read-only commands run directly.
## Skills
Standard agent skill files (`SKILL.md` with `name` plus `description`
frontmatter, optional `scripts/`, `references/`, `assets/`, per the Agent
Skills open format) are discovered in `~/.tai/skills/*/` and
`./.tai/skills/*/` (project wins on name collisions). Descriptions stay in
context; the agent loads full instructions through `load_skill` only when
needed. `/skills` lists what is available.
## Sandbox
`/env` shows the execution environment, `/env sandbox` switches shell and
file tools into an isolated `tai-box` container (podman or docker, no mounts,
no shared filesystem), `/env home` switches back. The image is built
automatically on first use from an embedded Containerfile; every pip
requirement (`faster-whisper`, `edge-tts`) lives inside the image while
`tai.py` itself stays dependency-free. Sandbox commands need no approval
because the container is disposable.
## Telegram
./tai.py --install-telegram
./tai.py --uninstall-telegram
Install asks for the bot token up front, verifies it against `getMe`, stores
it in `~/.tai/telegram.env` (0600), builds the sandbox container (used for
voice transcription), and registers a `tai-telegram.service` systemd user
unit with linger enabled (failures ignored). The bot long-polls, answers
text, transcribes voice notes, and understands `/new`. It runs without
`--yes`, so destructive shell commands are denied. Uninstall stops and
removes the service and purges the container and image; the token file and
data stay.
## Profiles and memory
Each profile owns a system message plus session history under
`~/.tai/profiles`, stored with mode 0600.
/profile show current profile
/profile [name] switch profile, creating it when missing
/profiles list all profiles
The `remember` tool merges an instruction into the current profile system
message through the model itself: it adds facts, updates behavior, or removes
forgotten items while preserving the rest. It fires by default on new
passwords and behavior changes. `recall` searches the per-profile episodic
log in `~/.tai/memory.db` (SQLite). Context is budgeted at roughly 32k
tokens with automatic compaction at 80 percent.
## Sealed storage
Storage is sealed by default with a built-in key, which stops casual reads
but not a determined attacker, since the key ships in the source. Set
`TAI_PASSPHRASE` for real protection: a home sealed with the default key is
re-sealed to your passphrase automatically on first boot, with a notice.
The key comes from PBKDF2-SHA256 (200k rounds) over a random salt in
`~/.tai/.seal`; values use a per-value nonce with HMAC-SHA256 encrypt-then-
MAC. SQLite access goes through custom `tai_enc`/`tai_dec` functions
registered with `create_function`, so inserts encrypt inline and recall
decrypts before matching. Existing plaintext data is sealed automatically on
first sealed start. A wrong passphrase refuses to start with exit code 2.
Set the variable empty for plaintext storage.
This construction uses only the standard library and is honest file-theft
protection, not audited cryptography; high-value secrets still belong in a
dedicated manager.
## Voice
`speak` synthesizes free neural speech via the Microsoft Edge Read Aloud
protocol, implemented with `socket` and `ssl` from the standard library. No
key, no package. MP3 files land in `~/.tai/audio` and play when an OS player
exists. `listen` records and transcribes when a recorder (`arecord`, `sox`,
`ffmpeg`) and a transcriber (`whisper-cpp`, `whisper`) are installed, and
reports exactly what is missing otherwise.
## Configuration
| Variable | Purpose | Default |
|---------------------|--------------------------------------|--------------------------------------------|
| `TAI_HOME` | State directory | `~/.tai` |
| `TAI_MODEL` | Model id, ignored by primary gateway | `openrouter/free` |
| `DEVPLACE_API_KEY` | Fallback backend credential | Empty, fallback disabled |
| `TAI_VOICE` | Edge voice name | `en-US-EmmaMultilingualNeural` |
| `TAI_PASSPHRASE` | Personal seal key | Unset: built-in key; empty: plaintext |
| `TELEGRAM_BOT_TOKEN`| Bot token, or set during install | Empty |
## Testing
python3 test_seal.py
python3 test_tai.py
## Layout
tai.py the entire agent
test_seal.py seal regression tests
test_tai.py skills, telegram, install, and parser tests