| # AgentBridge Terminal UI — user guide |
|
|
| The console app of AgentBridge is an interactive terminal UI built on |
| [Terminal.Gui](https://github.com/tui-cs/Terminal.Gui) (v2, instance-based API), |
| modelled on [Qwen Code](https://github.com/QwenLM/qwen-code)'s TUI: a menu bar, |
| an AGENT logo panel, a streaming chat panel with an input line at the bottom, a |
| status bar, `/` slash commands with a **filterable command palette**, `@` file |
| attachments, keyboard shortcuts, mouse support and online help — while the HTTP |
| server keeps serving every other client on the same port. **CLI and API are the |
| same conversation**: messages you send from the UI go through the exact same |
| `POST /v1/chat/completions` endpoint that OpenAI-compatible clients use, while MCP |
| clients can control the same runtime via `POST /mcp`, so both can drive the agents |
| at the same time (the UI holds one session; other |
| clients create their own). |
|
|
| ## How Qwen Code's TUI works (the model we followed) |
|
|
| Qwen Code is a terminal-based agentic coding tool: you launch `qwen` in a |
| project and get a persistent TUI where: |
|
|
| - a **bottom input field** accepts plain-language prompts; a small **status |
| line** shows the model/provider and context usage; |
| - typing **`/`** opens a **slash-command palette** — a contextual help list |
| (name + one-line description per command) that **filters as you type**; |
| Enter runs the highlighted command, Tab completes it, Esc closes it; |
| - **`@`** opens file/context completion; |
| - a rich **keyboard-shortcut layer** covers editing (Ctrl+A/E/U/K/W, word |
| jumps), history (Up/Down, Ctrl+R reverse search), Ctrl+C cancel, Ctrl+L |
| clear screen, `?` shortcuts overlay, Tab ghost-text completion; |
| - **`/model`** switches the LLM on the fly, `/help` shows the command docs, |
| `/docs` opens the online documentation in the browser; |
| - agent replies **stream** into the conversation and can be cancelled. |
|
|
| ## What AgentBridge does better |
|
|
| | Qwen Code | AgentBridge (this app) | |
| |---|---| |
| | TUI is the only front-end | TUI **and** the OpenAI-compatible API simultaneously, same process — any SDK/script can keep driving the agents while you chat | |
| | Model switch is provider-side | `/model` switches LLM **with a context-window guard** — the server refuses (409) when the conversation overflows the target provider's window and explains why | |
| | Mouse: scroll + click | native cross-platform mouse (Terminal.Gui): **wheel** scrolls the conversation and menus, **click** positions the input cursor or selects a list row, **double-click** runs the selected item | |
| | Menus | pickers are drawn inside the TUI layout — **Esc always cancels** (`/model`, `/agent`, `/attach`) with a clean screen, no residue | |
| | No voice | `/voice` — dictation from the server microphone (Windows), `/tts` — Kokoro neural TTS speaks the replies and plays the WAV | |
| | File completion via `@` | `@` palette of **uploaded** files (server-side `/v1/files`), `/files add <path>` uploads and attaches; attachments ride along as `file_ids` | |
| | Status shows context | status bar also shows **history tokens / context window**, the active **tools** (readable names, e.g. `File, Web, Git`), TTS/mic availability | |
| | `/docs` opens docs site | `/docs` opens **this project's** online README; `/help` lists commands, shortcuts, API endpoints and links | |
| | — | `/agent` opens the tools checklist (presets + individual tools), `/features` toggles feature flags, `/health` pings the server, `/retry` resends the last prompt, `/web` opens the auto-connected web client | |
|
|
| ## Commands (type `/` for the live list) |
|
|
| | Command | What it does | |
| |---|---| |
| | `/help` · `/?` | Full help: commands, shortcuts, API endpoints, online docs | |
| | `/docs` | Open the online documentation in the browser | |
| | `/web` | Launch the Giraffe AI web client (auto-installed/updated), auto-connected to this server | |
| | `/modelsetup` | Configure LLM models & providers (add/edit/remove, active model, API keys) | |
| | `/model [name]` | Switch the LLM provider (menu when no name given; context-window checked) | |
| | `/agent [name]` | Choose the agent tools: quick presets or an individual-tool checklist (Space toggles; see below) | |
| | `/voice [lang]` | Dictate from the server microphone into the input | |
| | `/tts [text]` | Speak the last agent reply (or the given text) — Kokoro TTS, WAV playback | |
| | `/telegram status\|config [set <key> <value>\|reload]\|login-code <code>\|allow\|disallow <user>` | Telegram chat medium: bare `/telegram` opens the interactive panel (status, login code, allow-list, config), the subcommands cover the same actions (see [Telegram](#telegram-chat)) | |
| | `/features [name] [on\|off]` | Show or toggle session feature flags (voice, tts, ...) | |
| | `/new` · `/reset` | Start a new session (fresh conversation) | |
| | `/clear` | Reset the current session history (keeps the session) | |
| | `/status` | Session state + platform capabilities | |
| | `/files add <path>` · `/files rm <id>` · `/files` | Upload+attach a file, delete one, list uploads | |
| | `/attach [id]` | Toggle a file attachment for the chat (menu when no id) | |
| | `/shortcuts` · `/keys` | Keyboard shortcuts overlay (also press `?` on an empty input) | |
| | `/health` | Ping the server, report latency | |
| | `/retry` | Resend the last prompt (also Ctrl+Y) | |
| | `/exit` · `/quit` | Exit (also Ctrl+C twice, or Ctrl+D) | |
|
|
| ## Web GUI |
|
|
| `/web` (or the menu **Web → GUI**) opens the agents in your browser. The |
| [Giraffe AI](https://github.com/Graphene-Lab/GiraffeAI) client — a single static |
| `index.html` plus its own launcher — is **not part of this repository**: on startup the |
| server installs it next to the executable (`GiraffeAIWebClient\` folder, from the client's |
| latest GitHub release). The first install is unconditional; the automatic **update** check |
| follows the app's auto-update toggle (`--no-update` / **File → Auto-Update**). Then `/web` |
| runs the platform launcher (`start.bat` / `start.sh`), which serves the client on |
| `http://localhost:8000` and opens the browser. |
|
|
| The launch passes `--provider` with this server's endpoint, so the client **registers the |
| AgentBridge provider (if not already present) and selects it immediately** — no manual |
| configuration, just start typing. |
|
|
| - The first download needs an internet connection (GitHub); afterwards the client is fully local. |
| - The client runs in its own launcher window/process and keeps serving after the TUI exits. |
| - The browser talks straight to this server (`POST /v1/chat/completions`), so CORS is enabled |
| and no API key is needed for local use. |
|
|
| ## Agent tools |
|
|
| `/agent [name]` switches to a preset — full ids: `default-agent`, `web-agent`, |
| `search-agent`, `research-agent`, `document-files`, `spreadsheet-files`, `email-agent`, |
| `office-files`, `multi-files`, `all-files`. Bare `/agent` (or menu **Tools → Agent & Tools**) |
| opens the tool checklist dialog: |
|
|
| - **Core (always on)** — the first line lists the locked core tools (`FileTool`, `GitTool`): |
| always active, not toggleable; the only way to change their status is `tools.json` |
| (see [MANUAL.md](MANUAL.md) — the picker always reflects the effective state). |
| - **Active tools** below — every non-core tool actually loaded at runtime (core tools + |
| the plugins in `Tools/`), each with a one-line description. **Space** toggles a tool; |
| **Close/Esc** saves the marked set as a **custom combination** (sent to the server as |
| the additive `tools` field, which overrides the preset's `model`). The enabled core |
| tools are always part of the combination. |
|
|
| `all-files` is the dynamic all-in-one agent: every loaded tool the per-tool config leaves |
| enabled (class-A plugins ON by default; class-B `OfficeTool` OFF unless enabled in |
| `tools.json`). |
|
|
| The status bar shows the active tools with readable names (`tools: File, Web, Git`), so |
| you always know what the agent can do in this conversation. |
|
|
| ## Telegram chat |
|
|
| `/telegram` turns AgentBridge into a **Telegram chat client** (a userbot): people write to |
| the account in a **private chat**, the message (text and/or file attachments) goes through |
| the same per-user chat session as the TUI and the HTML client, and the reply — text plus |
| any files the agent attaches — comes back into the same chat. Text chat only: the Telegram |
| Client API has no audio-call support, so Telegram is **not** a voice medium (see |
| [docs/telegram.md](telegram.md)). |
|
|
| **Bare `/telegram`** (or menu **Tools → Telegram**) opens an interactive panel: live |
| status plus the first-login code field, allow/disallow user, config, reload and |
| enable/disable — no slash-command syntax to remember. The subcommands below drive the |
| same actions from the command line: |
|
|
| | Command | What it does | |
| |---|---| |
| | `/telegram status` | Live state: enabled, phase (`off`/`conn`/`code`/`2fa`/`on`/`err`), logged-in user, allow-list, agent | |
| | `/telegram config` | Show the effective configuration (phone, session, allow-list, agent) | |
| | `/telegram config set <key> <value>` | Change one config key and persist it to `telegram.json` (connection keys restart the bridge) | |
| | `/telegram config reload` | Re-read `telegram.json` (hand edits made outside the TUI) and apply them | |
| | `/telegram login-code <code>` | Complete the pending first login (verification code or 2FA password) | |
| | `/telegram allow <user>` · `/telegram disallow <user>` | Add / remove an allow-list entry (numeric id or `@username`) | |
|
|
| The **status bar** shows a `tg:` segment (`off`/`conn`/`code`/`2fa`/`on`/`err`), refreshed |
| by the same 3-second poll as SIP. When an agent reply carries attached files, the chat |
| history shows them as **`[attachment: <path>]`** lines — the files are saved under an |
| `attachments/` folder next to the executable. |
|
|
| The first login is TUI-guided: `/telegram status` shows `code` while the verification code |
| is pending, `/telegram login-code <code>` completes it (a 2FA password, if the account has |
| one, is submitted the same way), and the session persists in `telegram.session` — no code |
| is asked again. Configuration lives in `telegram.json` next to the executable (excluded |
| from updates); edit it by hand, with the setup scripts (`scripts/setup-telegram.bat` on |
| Windows, `scripts/setup-telegram.sh` on Linux/macOS), or with these commands. Full |
| reference: [docs/telegram.md](telegram.md). |
|
|
| ## Models & Providers setup |
|
|
| `/modelsetup` (or menu **File → Models & Providers**) opens a tabbed window that mirrors the |
| AIOffice settings panel: |
|
|
| | Tab | What you can edit | |
| |---|---| |
| | **LLM & Providers** | Active provider (dropdown, switches via the same path as `/model`) and a provider list with **Add… / Edit… / Remove** — the CRUD operations apply immediately and persist to `providers.json` (see below) | |
| | **Email (SMTP)** | SMTP server, port, user, password and the recipient email | |
| | **Mail (IMAP)** | IMAP server, port, user and password | |
| | **General** | Step logging on/off (`logs/` folder) and the documents path (re-indexed on change) | |
|
|
| - Field edits (email, general) apply when you press **Save**; **Close** discards them. |
| - Adding a provider opens a small form (name, protocol OpenAI/Gemini/Anthropic, interaction |
| mode Default/API/CLI, model, base address, endpoint path, **API key**, context window, |
| timeout). The API-key field serves every cloud provider — any provider whose endpoint is |
| **not** on loopback (`localhost` / `127.0.0.1`) needs one; local providers simply leave it |
| empty. Keys are stored per-provider in `providers.json` (masked on screen while typing). |
| Editing replaces the config in place; removing refuses to delete the last remaining |
| provider. The interaction mode is optional: `Default` (the initial choice) leaves the |
| decision to the model size — CLI for small models, API for large ones; `API`/`CLI` force |
| one of the two. The active mode appears on the status page and is reported by |
| `GET /v1/models` as `interaction_mode`. |
| - The provider list also stays in sync with `GET /v1/models`, so an added provider can be |
| switched to right away. |
|
|
| ## Auto-update |
|
|
| Menu **File → Auto-Update** toggles the automatic update check performed at startup |
| (checked = enabled, the default). The choice persists to the OS app-data folder |
| (`<AppData>\agent\autoupdate.json`), so it survives updates. When a newer release is |
| found, the app downloads it, swaps the files and restarts itself — see |
| [autoupdate.md](autoupdate.md) for the architecture and `--no-update` for services. |
|
|
| ## Keyboard shortcuts |
|
|
| | Shortcut | Action | |
| |---|---| |
| | `Enter` | Send the message / run the selected command | |
| | `/` | Open the slash-command palette (live, filters as you type) | |
| | `@` | Open the file palette (toggle chat attachments) | |
| | `?` | Shortcuts overlay (empty input) | |
| | `Tab` | Complete the selected command in the palette | |
| | `Esc` | Close dialog · clear input · twice: exit | |
| | `Ctrl+C` | Cancel the reply · clear input · twice: exit | |
| | `Ctrl+D` | Exit (empty input) | |
| | `Ctrl+L` | Clear the session history (menu bar too) | |
| | `Ctrl+R` | Reverse-search prompt history | |
| | `Ctrl+Y` | Retry the last prompt | |
| | `Up` / `Down` | Prompt history (also Ctrl+P / Ctrl+N) | |
| | `←` / `→` | Move the cursor (with Ctrl: by word) | |
| | `Ctrl+A` / `Ctrl+E` | Select all / jump to end of the input | |
| | `Ctrl+U` / `Ctrl+K` | Delete to start / to end of the line | |
| | `Ctrl+W` | Delete the word before the cursor (also Ctrl+Backspace) | |
| | `PgUp` / `PgDn` | Scroll the conversation history | |
| | `F1` | Full help page | |
| | `F10` | Activate the menu bar | |
|
|
| The conversation auto-follows the stream while you are at the bottom; scrolling up |
| (wheel or `PgUp`) pauses the follow so you can read, and scrolling down or sending a |
| message resumes it. |
|
|
| ## Mouse |
|
|
| Terminal.Gui provides native cross-platform mouse support: menus and dialogs are |
| rendered inside the layout and **Esc always cancels them** cleanly (`/model`, |
| `/agent`, `/attach`). |
|
|
| | Action | Effect | |
| |---|---| |
| | Mouse wheel (conversation) | Scroll the history | |
| | Mouse wheel (dialog/list) | Move the selection | |
| | Click the input line | Position the text cursor | |
| | Click a dialog/list row | Select it | |
| | Double-click a list row | Run it | |
|
|
| The terminal switches to the alternate screen buffer and restores it on exit. |
|
|
| ## Localisation |
|
|
| The TUI is fully localised for **EN, IT, FR, ES, DE, RU** using the standard .NET |
| resource-file approach (`Resources/Dictionary.resx` + per-language satellites). The app |
| runs in the **system language when supported, otherwise English** — the correct file is |
| selected automatically via `CultureInfo.CurrentUICulture` (a French system picks `fr`, a |
| German one `de`, any other culture falls back to the neutral English resource). |
|
|
| | File | Language | |
| |---|---| |
| | `Resources/Dictionary.resx` | English (neutral default) | |
| | `Resources/Dictionary.it.resx` | Italian | |
| | `Resources/Dictionary.fr.resx` | French | |
| | `Resources/Dictionary.es.resx` | Spanish | |
| | `Resources/Dictionary.de.resx` | German | |
| | `Resources/Dictionary.ru.resx` | Russian | |
|
|
| Rules and conventions: |
|
|
| - **Command names are never translated** — `/help`, `/model`, `/agent`, `/voice`, `/tts`, |
| `/files`, … keep their English names in every language (they are also the API contract). |
| Only the command *descriptions* shown in the palette/help are localised. |
| - All UI strings (menus, help pages, dialogs, status notes, picker hints) come from |
| `Dictionary.*` (the strongly typed Designer generated from the resx). New UI strings go |
| into the resx files, never hardcoded in `Tui.cs`. |
| - **System-generated agent results are localised too.** AIOrchestrator no longer returns |
| hardcoded English messages ("Max iterations reached", "LLM returned no response", the |
| "Done" fallback): it returns a locale-neutral `AgentResultCode` enum and AgentBridge maps |
| each code to the phrase in the dictionary for the current language (see |
| `AgentResult.cs` / `Program.cs` → `ResultText`). The agent's own LLM text passes through |
| untouched, since the model is instructed to reply in the language of the request. |
| - Voice/TTS languages (`/voice`, `/tts`) keep following `SystemLang` (machine `CurrentUICulture` |
| via `SystemLang.Get()`), independently of the UI dictionary. |
|
|
| To add a new language: copy `Resources/Dictionary.resx` to `Dictionary.XX.resx` |
| (XX = ISO 639-1 code), translate the values, and rebuild — the SDK picks the new satellite |
| up automatically. |
|
|
| ## Launch modes |
|
|
| How the app starts — terminal UI, server only, or forced UI — is covered in |
| [docs-dev/ARCHITECTURE.md](../docs-dev/ARCHITECTURE.md#launch-modes). |
|
|
| --- |
|
|
| See also: [README](../README.md) · [API reference](API.md) · [Architecture](../docs-dev/ARCHITECTURE.md) · [Developer guide](../docs-dev/TUI-DEVELOPMENT.md) (Terminal.Gui v2, for TUI code changes — developers, not shipped) |
|
|