LazyBoy2/README.md

153 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# LazyBoy
A local, general-purpose **GrokBot-like CLI agent**. It observes the environment, chooses tools, adapts to results, and verifies its work. Uses your existing xAI/OpenAI-compatible model configuration; no separate search API key.
For action tasks the agent briefly explains its approach, then starts. Multi-stage tasks get a short live plan. You can add instructions while it works, answer a question, or interrupt and resume. Simple questions remain simple answers.
## Remote computer controls
右側電腦採用 Grok 風格的螢幕卡片按「放大」可開啟全頁操作。桌面版不顯示手機控制列直接使用滑鼠鍵盤Ctrl+Alt+ 可縮放Ctrl+Alt+0 重設Ctrl+Alt+B 開啟文字剪貼簿面板。
手機沿用 LazyBoy 的獨立觸控板滑動移動游標、輕點左鍵、雙指捲動輕點右鍵也可按左右鍵、捲動與「拖曳」再按一次放開。可切換直接點選模式。直向控制區在下方橫向在左側鍵盤、常用按鍵、14 倍縮放、移動畫面與雙向文字剪貼簿都在手機控制區。若區網 HTTP 或瀏覽器限制剪貼簿權限,可在面板長按貼上/複製。
## Start
```bash
# 可設項目與說明:複製 .env.example 成 .env 後填 LAZYBOY_API_KEY
# make start / restart 會載入 .env
make build # API + 正式 UIweb/dist手機走 :8787 需要這步)
make start # 每次重建 API + UI再啟動預設綁定 0.0.0.0
make restart # 停止後重建並啟動
make box # 第一次/改 box/ 之後Docker 電腦映像 lazyboy-box:local
make stop
export LAZYBOY_API_KEY=your_key # or XAI_API_KEY
cargo run -p lazyboy -- agent
# API daemon (named Agents) + HTTP on :8787
cargo run -p lazyboy -- serve
# 開發前端使用 HTTP不會因本機殘留憑證自動切換 HTTPS。
# 本機http://127.0.0.1:5173其他裝置http://本機區網IP:5173或 :8787
# Independent frontend:
cd web && npm install && npm run dev
# Production UI: npm run build then lazyboy serve hosts web/dist
# Phone: same Wi-Fi, open the printed LAN URL, Add to Home Screen
# One-shot:
cargo run -p lazyboy -- run "整理目前目錄的資料,產生報告並讀回驗證"
# Resume:
cargo run -p lazyboy -- agent --session <id>
cargo run -p lazyboy -- run --session <id> "繼續"
```
While running, enter additional instructions to steer the next step. **Ctrl-C** or **`/stop`** stops the turn and saves its state. In the REPL, `/plan` shows the current plan, `/session` shows its ID, and `/exit` or `/quit` exits when idle. During work `/exit` and `/quit` stop the current turn first. At an explicit question, new text answers that question. Already queued idle inputs remain separate tasks.
Progress, plans and questions go to stderr; final answers go to stdout. `lazyboy chat` remains streaming chat without tools. `lazyboy web` serves the Grok Bot-shaped conversation UI (sidebar, bubbles, composer, **我的電腦** overlay) as a phone-installable PWA. `lazyboy help` lists commands and settings.
## Persistent agents and background work
Run `lazyboy serve` in one terminal, then create identities with `lazyboy agents create <name>` and open separate chats with `lazyboy agent --name <name>`. Agents learn private memories and public expertise from their conversations. They can delegate to an existing agent or create a temporary worker while you keep chatting.
In named-agent mode, ordinary text is new chat. Use `/tasks` and `/task <id> say|stop|resume` to manage background work. Closing a chat leaves the service and its tasks running. Agent identity and task ownership are separate: one agent can help another without losing its own conversation.
See [team setup and behavior](docs/TEAM.md) for commands, budgets, privacy boundaries and recovery. `LAZYBOY_DATA_DIR` defaults to `~/.lazyboy/team`; existing single-session commands keep their original behavior.
## Tools
| Capability | Tools |
| --- | --- |
| Voice | `send_message` (only user-visible channel; widget asks a question) |
| Progress and planning | `report_progress` (alias of send_message text), `update_plan` |
| Human interaction | `request_user_input`, `request_user_confirm`, `browser_handoff` |
| Completion | No-tool response ends the turn. `report_done` is optional. `report_blocked` when stuck. |
| Explicit local commands | `external_exec_command` (backgrounds after `block_until_ms`, default 30s), `external_await_command`, `external_write_stdin`, `external_shell` |
| Explicit local files | `external_list_dir`, `external_read_file`, `external_edit_file`, `external_write_file`, `external_grep` (regex), `external_glob`, `external_search_files` (literal) |
| Web | `web_fetch` (direct anonymous HTTP GET, HTML → text, short cache), `web_search` (remote search service); no browser login; Docker browser for login-gated pages |
| Background | `spawn_subagent` (returns immediately; `kind=computerUse` for desktop GUI), `check_subagent`, `message_subagent`, `stop_subagent`. Subagents and external command completion revive the turn; observe detached box commands with `await_shell`. |
| Desktop GUI | Parent: `screenshot` (read-only). Clicks: `spawn_subagent kind=computerUse`, which gets `computer` (screenshot/snapshot/click/move/drag/type/key/scroll/wait via xdotool on `DISPLAY=:1`; `snapshot` lists on-screen elements with centre coordinates from the AT-SPI accessibility tree). One computerUse per agent computer. Passwords still `request_box_help`. |
| MCP | `get_mcp_tools`, `call_mcp_tool`, `get_mcp_server_status`, `add_mcp_server`, `remove_mcp_server`. Config: `~/.lazyboy/mcp.json` (or `LAZYBOY_MCP_CONFIG`). Prefer a connector over the browser for that service. |
| My computer (box) | Docker Linux desktop (TigerVNC + minimal XFCE in lazyBoy's Arc-Dark/粉圓 look, zh-TW/Asia/Taipei, **Chromium** + 終端機 + xdotool + AT-SPI). Named agents each get their own container; opening an agent starts it and the UI confirms ready/error. Session CLI keeps `lazyboy-box`. Default tools: `shell`, `read`, `await_shell`, `screenshot`. Profile: `/home/box/chrome-profile` on that seat. Viewer`lazyboy computer` or the agent overlay. |
| Browser observation | `browser_navigate`, `browser_snapshot`, `browser_read_page`, `browser_tabs` |
| Browser actions | `browser_click`, `browser_type`, `browser_press`, `browser_select`, `browser_scroll`, `browser_wait` |
| Browser file exchange | `browser_upload`, `browser_download` |
| Browser fallback | `browser_eval` |
Long commands return a session ID and incremental output; `external_write_stdin` polls, sends input, closes stdin or terminates the command. One foreground command at a time, piped I/O, default ten-minute deadline. The explicit local `external_shell` retains its 30-second limit. Default `shell` runs on the box and continues in the background when its foreground wait expires; use `await_shell` to observe it. Full command output is saved under `.lazyboy-output/`; large tool results are also stored there with a readable preview and path.
`external_read_file` accepts a zero-based line `offset` and line `limit`; `external_search_files` searches names or literal content; `external_edit_file` requires one unique exact match. File tools and browser file exchange check workspace paths and symlinks. Only `external_*` tools operate on the local machine; `shell` and `read` use the box.
## Browser surfaces
Docker mode includes Node, Playwright and Chromium in the image. The following setup is only for the explicit legacy local browser:
```bash
export LAZYBOY_BROWSER_SURFACE=local
cd tools/playwright
npm install
npx playwright install chromium
cd ../..
export LAZYBOY_BROWSER_HEADED=1 # visible browser, convenient for login handoff
cargo run -p lazyboy -- agent
```
Browser tools now default to **Docker Chromium**, attached to the desktop browser at `/home/box/chrome-profile`. Automation and human login share this profile; browser uploads/downloads use `/workspace` paths and explicit `copy_to_box`/`copy_from_box` transfer files. `browser_release` disconnects automation without closing the desktop. The old local browser is available only with `LAZYBOY_BROWSER_SURFACE=local`; its owner profiles are preserved and are not merged into Docker. See [surface comparison](docs/SURFACES.md) for differences and configuration.
`web_fetch` is a direct anonymous HTTP GET from the host: browser-like headers, no cookies, public hosts only (redirects are re-checked), body capped at 2 MiB, HTML reduced to readable text with link footnotes, non-UTF-8 charsets decoded, and results cached for ten minutes per URL. Only when a site refuses plain HTTP (401/403/429/503, or an empty JavaScript shell) and the model configuration is official xAI does it fall back to xAI native browsing; that result is marked `content_kind=model_rendered_web_content` and carries `fallback_reason`. `web_search` uses a remote search service with no browser cookies: official xAI configuration reuses the existing model API key for native web search; for the reconstructed AiService contract, set `LAZYBOY_WEB_BACKEND_URL` and, when required, `LAZYBOY_WEB_TOKEN`. That gateway must provide the reconstructed `RunWebSearch` JSON contract; a normal OpenAI-compatible chat endpoint alone does not provide it. Missing search configuration produces an explicit error, never a hidden browser fallback.
For login, OTP or captcha, `browser_handoff` shows the Docker viewer URL and parks the turn until you reply. For irreversible public actions, the agent follows the existing explicit-approval rule; plans themselves do not require approval.
## Settings
| Environment variable | Default / meaning |
| --- | --- |
| `LAZYBOY_API_KEY` | Falls back to `XAI_API_KEY`, then `OPENAI_API_KEY` |
| `LAZYBOY_BASE_URL` | `https://api.x.ai/v1`; fallback `OPENAI_BASE_URL` |
| `LAZYBOY_MODEL` | `grok-4.6` |
| `LAZYBOY_MAX_ROUNDS_TOTAL` | 5000 model steps **per user turn** (Grok Bot Sand-style). A step with no tool calls ends the turn. |
| `LAZYBOY_MAX_ROUNDS` | 12; local progress interval, no extra model calls |
| `LAZYBOY_CONTEXT_CHARS` | 100000 approximate UTF-8 bytes; legacy name |
| `LAZYBOY_SESSIONS_DIR` | `~/.lazyboy/sessions` |
| `LAZYBOY_PROGRESS` | `0` silences progress, but not questions |
| `LAZYBOY_BROWSER_HEADED` | `1` launches visible Chromium |
| `LAZYBOY_CONFIRM_AUTO` | Test-only approval/denial override; falls back to `LAZYBOY_HANDOFF_AUTO` |
| `LAZYBOY_HANDOFF_AUTO` | Test-only handoff override: `1` resume, `abort` deny |
Session stop reasons: `answer` (no tool calls — the Grok Bot end condition), `done` (optional `report_done`), `blocked`, `budget_exhausted`, `failed`, `cancelled`. One-shot exits 0 for answer/done, 1 for blocked/budget/failed, 130 for cancellation. The REPL remains usable after any turn outcome. Delivery is `send_message`; a no-tool response is not independent proof of arbitrary task correctness.
## Latency diagnostics
Set `LAZYBOY_TIMING=1` when starting the process to print elapsed milliseconds to
stderr for request preparation, model-slot queues, model rounds (including queue
wait), tool execution, and whole agent turns. These nested measurements must not
be added together. They contain no prompts, tool arguments, or credentials;
concurrent turns can interleave. Compare the same task and session length, and
count model rounds as well as wall time. This does not enable extra model calls.
Memory extraction starts only when no foreground chat is active and both
background slots are free; it acquires capacity without queuing. Deferred memory
remains durable and is retried by the scheduler. Already-running extraction is
allowed to finish, and continuous activity can delay memory updates. Work and
completion rules are unchanged: acknowledgement is not completion, required
results must still be observed, and sending a message alone does not end a turn.
## Validation
```bash
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo build -p lazyboy
python3 tests/cli_flow.py
python3 tests/runtime_flow.py # includes a real 31-second command + local Chromium
python3 tests/browser_flow.py # headless Chromium, local fixture only
python3 tests/team_flow.py # daemon, two CLI clients, mock API + Chromium
cargo run -p lazyboy -- smoke
# Opt-in: uses your existing paid model configuration, max 12 requests:
python3 tests/live_cli.py
python3 tests/live_team.py # opt-in team workflow, root task ceiling 16
```
Design and Codex references: [CLI flow](docs/CLI-FLOW.md). Product scope: [PRODUCT](docs/PRODUCT.md). Acceptance scenarios: [ACCEPTANCE](docs/ACCEPTANCE.md). Older scenario playbooks remain optional examples, not hardcoded workflows: [scenarios](docs/scenarios/README.md).
### Memory and long-running UI
`make start` rebuilds both services and reapplies computer limits to existing containers. Each computer is limited to 1536 MiB RAM (no additional swap), 2 CPUs and 512 processes; new containers use 256 MiB shared memory. The default maximum is three running computers, including computers recovered from previous server runs. Idle computers are stopped when a slot is needed; their workspace and browser profile volumes are retained. Busy computers are not evicted. `LAZYBOY_COMPUTER_MAX` overrides the running count.
Chat history scrolls continuously and only mounts nearby messages. Desktop chrome is hidden by CSS without a DOM mutation feedback loop. Regression checks: `node tests/novnc_memory_ui.mjs` and `node tests/history_memory_ui.mjs` (with the frontend running).