upivia-tui 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- upivia_tui-0.1.0/.gitignore +7 -0
- upivia_tui-0.1.0/FEATURE-PARITY.md +83 -0
- upivia_tui-0.1.0/LICENSE +21 -0
- upivia_tui-0.1.0/PKG-INFO +227 -0
- upivia_tui-0.1.0/README.md +196 -0
- upivia_tui-0.1.0/pyproject.toml +55 -0
- upivia_tui-0.1.0/src/upivia_tui/__init__.py +11 -0
- upivia_tui-0.1.0/src/upivia_tui/__main__.py +138 -0
- upivia_tui-0.1.0/src/upivia_tui/app.py +1080 -0
- upivia_tui-0.1.0/src/upivia_tui/app.tcss +388 -0
- upivia_tui-0.1.0/src/upivia_tui/background.py +180 -0
- upivia_tui-0.1.0/src/upivia_tui/browsertools.py +871 -0
- upivia_tui-0.1.0/src/upivia_tui/client.py +359 -0
- upivia_tui-0.1.0/src/upivia_tui/commands.py +131 -0
- upivia_tui-0.1.0/src/upivia_tui/config.py +117 -0
- upivia_tui-0.1.0/src/upivia_tui/localtools.py +888 -0
- upivia_tui-0.1.0/src/upivia_tui/models.py +92 -0
- upivia_tui-0.1.0/src/upivia_tui/screens.py +396 -0
- upivia_tui-0.1.0/src/upivia_tui/version.py +1 -0
- upivia_tui-0.1.0/src/upivia_tui/widgets.py +417 -0
- upivia_tui-0.1.0/src/upivia_tui/wsclient.py +233 -0
- upivia_tui-0.1.0/tests/test_app_features.py +149 -0
- upivia_tui-0.1.0/tests/test_browsertools.py +268 -0
- upivia_tui-0.1.0/tests/test_client.py +120 -0
- upivia_tui-0.1.0/tests/test_config.py +52 -0
- upivia_tui-0.1.0/tests/test_cwd.py +54 -0
- upivia_tui-0.1.0/tests/test_diff.py +39 -0
- upivia_tui-0.1.0/tests/test_localtools.py +191 -0
- upivia_tui-0.1.0/tests/test_models.py +32 -0
- upivia_tui-0.1.0/tests/test_nav.py +76 -0
- upivia_tui-0.1.0/tests/test_trust_boundary.py +327 -0
- upivia_tui-0.1.0/tests/test_ws.py +297 -0
- upivia_tui-0.1.0/uv.lock +539 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Feature Parity: (removed) Node CLI (OpenTUI) โ Textual TUI
|
|
2
|
+
|
|
3
|
+
> The Node/OpenTUI CLI was **removed** (DEC-119). The Textual TUI is now the
|
|
4
|
+
> canonical Upivia terminal. This table records what carried over.
|
|
5
|
+
|
|
6
|
+
Tracks every meaningful feature of `packages/upivia-cli` so nothing is lost in
|
|
7
|
+
the Python/Textual client (`packages/upivia-tui`). Status legend:
|
|
8
|
+
โ
done ยท ๐ถ partial ยท โ intentionally dropped ยท โณ planned.
|
|
9
|
+
|
|
10
|
+
## Core chat
|
|
11
|
+
| Feature | Node CLI | Textual | Notes |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| Streaming chat (SSE) | โ
| โ
| `client.stream_turn` |
|
|
14
|
+
| Boxed message cards | (borderless) | โ
| OpenCode-style borders |
|
|
15
|
+
| Markdown rendering | ๐ถ custom | โ
| native Textual `Markdown` (tables, code, lists) |
|
|
16
|
+
| Thinking/reasoning display | โ
| ๐ถ | suppressed in main thread (kept quiet) |
|
|
17
|
+
| Tool call status lines | โ
| โ
| `tool_planned`/`executing`/`done` |
|
|
18
|
+
| Inline approval prompt | โ
| ๐ถ | shows notice; resolve via web/`requests` |
|
|
19
|
+
| Copy text | ๐ถ Ctrl+Y | โ
| auto-copy on drag-select + Ctrl+Y (OSC52); DEC-119 |
|
|
20
|
+
|
|
21
|
+
## Local tools (on-disk)
|
|
22
|
+
| Feature | Node CLI | Textual | Notes |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| read/write/edit/list/search/run | โ
| โ
| `localtools.py`, CWD sandbox |
|
|
25
|
+
| Diff rendering for writes/edits | โ
| โ
| line-numbered, syntax-highlighted |
|
|
26
|
+
| Command permission policy | โ
ask-once | โ
| `CommandPolicyScreen` |
|
|
27
|
+
| code graph (graphify) | โ
| โ
| `local_code_graph` auto-build+query, graceful fallback (DEC-118) |
|
|
28
|
+
| MCP tools | โ
| โ | out of scope for thin client |
|
|
29
|
+
|
|
30
|
+
## Multi-agent
|
|
31
|
+
| Feature | Node CLI | Textual | Notes |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| Delegate-by-default orchestration | โ
| โ
| server prompt (DEC-114) |
|
|
34
|
+
| Live worker panes | โ
| โ
| `TeamPanel` from `agent_event` |
|
|
35
|
+
| Worker detail view | โ
| โ
| click worker / `/worker` โ full activity stream (DEC-118) |
|
|
36
|
+
| Spawn/delegate visibility | โ
| โ
| status + spend + log |
|
|
37
|
+
|
|
38
|
+
## Sessions
|
|
39
|
+
| Feature | Node CLI | Textual | Notes |
|
|
40
|
+
|---|---|---|---|
|
|
41
|
+
| New session | โ
| โ
| `/new`, Ctrl+L |
|
|
42
|
+
| List sessions | โ
| โ
| `/sessions`, palette |
|
|
43
|
+
| Switch session (+history) | โ
| โ
| picker loads history |
|
|
44
|
+
| Rename session | โ
| โ
| `/rename` |
|
|
45
|
+
| Delete session | โ
| โ
| `/delete` |
|
|
46
|
+
|
|
47
|
+
## Navigation / control
|
|
48
|
+
| Feature | Node CLI | Textual | Notes |
|
|
49
|
+
|---|---|---|---|
|
|
50
|
+
| Command palette (Ctrl+P) | โ
| โ
| fuzzy command menu |
|
|
51
|
+
| Agent switcher | โ
| โ
| Ctrl+T / `/agent` |
|
|
52
|
+
| Model picker | โ
| โ
| Ctrl+O / `/models`, curated + live catalog |
|
|
53
|
+
| Team switch | โ
| โ | uses config team; switch in Node CLI/web |
|
|
54
|
+
| Plan/Build mode | โ
| โ
| Tab / `/mode` |
|
|
55
|
+
| Autonomy toggle | โ
| โ
| `/autonomy` |
|
|
56
|
+
| Question/answer modal | โ
| โ
| options/multiselect/free-text |
|
|
57
|
+
|
|
58
|
+
## Utilities
|
|
59
|
+
| Feature | Node CLI | Textual | Notes |
|
|
60
|
+
|---|---|---|---|
|
|
61
|
+
| Export to markdown | โ
| โ
| `/export` |
|
|
62
|
+
| Compact session | โ
| โ
| `/compact` |
|
|
63
|
+
| Pending requests + resolve/reject | โ
| โ
| `/requests` |
|
|
64
|
+
| Undo/redo | โ
| โ | VCS-style undo is CLI-specific |
|
|
65
|
+
| Session-local VCS / branches | โ
| โ | out of scope |
|
|
66
|
+
| Allocate budget (manager) | โ
| โณ | `/allocate` (low priority) |
|
|
67
|
+
| @file mentions | โ
| โ
| composer dropdown, Tab/Enter accept (DEC-118) |
|
|
68
|
+
| Slash-command autocomplete | โ
| โ
| `/` dropdown, fuzzy (DEC-118) |
|
|
69
|
+
| Background/device mode | โ
| โ
| `upivia-tui --background` headless daemon (DEC-116) |
|
|
70
|
+
|
|
71
|
+
## Realtime / device
|
|
72
|
+
| Feature | Node CLI | Textual | Notes |
|
|
73
|
+
|---|---|---|---|
|
|
74
|
+
| WebSocket realtime sync | โ
| โ
| chat turns over WS, webโTUI fan-out, SSE fallback (DEC-116) |
|
|
75
|
+
| Live device (web edits this machine) | โ
| โ
| TUI open OR `--background`; any attached web session edits files here |
|
|
76
|
+
| Set working dir from web (cd + browse) | โ | โ
| subtle cwd chip in web Sessions, tab-complete dirs (DEC-117) |
|
|
77
|
+
| attach_session (web drives device) | โ
| โ
| reattach over WS |
|
|
78
|
+
|
|
79
|
+
## Auth / CLI
|
|
80
|
+
| Feature | Node CLI | Textual | Notes |
|
|
81
|
+
|---|---|---|---|
|
|
82
|
+
| First-run auth (`init`) | โ
| โ
| `upivia-tui init` writes shared config (DEC-119) |
|
|
83
|
+
| `whoami` | โ
| โ
| `upivia-tui whoami` (DEC-119) |
|
upivia_tui-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Upivia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: upivia-tui
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Upivia Textual TUI โ chat with Yupi, watch multi-agent delegation, reuse the platform's governed orchestration.
|
|
5
|
+
Project-URL: Homepage, https://www.upivia.com
|
|
6
|
+
Project-URL: Documentation, https://www.upivia.com/docs
|
|
7
|
+
Author: Upivia
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agents,ai-agents,cli,governance,terminal,tui,upivia
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Terminals
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: httpx>=0.27.0
|
|
24
|
+
Requires-Dist: playwright>=1.45
|
|
25
|
+
Requires-Dist: textual>=0.80.0
|
|
26
|
+
Requires-Dist: upivia>=0.2.0
|
|
27
|
+
Requires-Dist: websockets>=12.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# upivia-tui
|
|
33
|
+
|
|
34
|
+
The **Upivia terminal** โ a [Textual](https://textual.textualize.io/) TUI and the
|
|
35
|
+
canonical CLI for Upivia (it replaced the older Node/OpenTUI CLI). It is a thin
|
|
36
|
+
presentation layer over the platform's governed chat-turn pipeline โ all
|
|
37
|
+
orchestration, budgets, approvals, memory, and multi-agent delegation happen
|
|
38
|
+
server-side.
|
|
39
|
+
|
|
40
|
+
## What it does
|
|
41
|
+
|
|
42
|
+
- renders messages as bordered cards (OpenCode-style)
|
|
43
|
+
- renders markdown with Textual's native widget (clean tables/code/bold/italic)
|
|
44
|
+
- visualises multi-agent delegation in a live Team panel (+ worker detail view)
|
|
45
|
+
- lets the agent **read/write/edit/run** files in your launch directory, with
|
|
46
|
+
per-session command permissions and inline +/- diff cards
|
|
47
|
+
- syncs in realtime with the web app over WebSocket, and can run headless
|
|
48
|
+
(`--background`) so the web app edits files on this machine
|
|
49
|
+
|
|
50
|
+
## Install & authenticate
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv tool install upivia-tui # or: pipx install upivia-tui (Python 3.10+)
|
|
54
|
+
upivia-tui init # authenticate (writes ~/.upivia/config.json)
|
|
55
|
+
upivia-tui # launch
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Keyboard & commands
|
|
59
|
+
|
|
60
|
+
| Key | Action |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `Ctrl+P` | Command palette (fuzzy) |
|
|
63
|
+
| `Ctrl+O` | Switch model (curated + full OpenRouter catalog) |
|
|
64
|
+
| `Ctrl+T` | Switch agent |
|
|
65
|
+
| `Ctrl+B` | Switch session (loads history) |
|
|
66
|
+
| `Ctrl+G` | Toggle Build / Plan mode |
|
|
67
|
+
| `Ctrl+L` | New / clear session |
|
|
68
|
+
| `Ctrl+Y` | Copy (selection, or last reply) โ also drag-to-copy |
|
|
69
|
+
| `Ctrl+C` / `Ctrl+Q` | Quit |
|
|
70
|
+
|
|
71
|
+
All shortcuts work even while typing in the composer (priority bindings).
|
|
72
|
+
`Ctrl+S` is intentionally avoided (it triggers terminal flow-control on many
|
|
73
|
+
terminals).
|
|
74
|
+
|
|
75
|
+
Slash commands: `/models` `/model <id>` `/agent` `/sessions` `/session`
|
|
76
|
+
`/new` `/rename <title>` `/delete` `/mode` `/autonomy` `/requests` `/worker`
|
|
77
|
+
`/export` `/compact` `/clear` `/help`. The model picker and command palette
|
|
78
|
+
mirror the Node CLI; selecting a new model or agent starts a fresh session so
|
|
79
|
+
history stays consistent.
|
|
80
|
+
|
|
81
|
+
### Autocomplete & worker detail
|
|
82
|
+
|
|
83
|
+
- Type `@` in the composer to autocomplete **project files** (Tab/Enter to
|
|
84
|
+
accept); mentioned files are read by the agent first.
|
|
85
|
+
- Type `/` to autocomplete **slash commands** from a fuzzy dropdown.
|
|
86
|
+
- Click a worker in the Team panel (or run `/worker`) to open its **full
|
|
87
|
+
activity stream** โ every thinking step, tool call, file write, and result.
|
|
88
|
+
- The agent can navigate large codebases with `local_code_graph` (Graphify);
|
|
89
|
+
install with `uv tool install graphifyy`. It falls back to `local_search`
|
|
90
|
+
when graphify isn't present.
|
|
91
|
+
|
|
92
|
+
## Copy & select
|
|
93
|
+
|
|
94
|
+
Textual runs in mouse-tracking mode, so the app handles selection itself:
|
|
95
|
+
|
|
96
|
+
- **Drag** with the mouse to select text โ it **auto-copies on release** (via
|
|
97
|
+
OSC 52, so it works over SSH and writes the system clipboard where available).
|
|
98
|
+
This is the reliable path and needs no key.
|
|
99
|
+
- **Ctrl+Y** copies the current selection, or the last assistant reply if
|
|
100
|
+
nothing is selected.
|
|
101
|
+
- `Ctrl+Shift+C` also works *where the terminal forwards it* โ but many
|
|
102
|
+
terminals intercept it for their own copy, which is why drag-to-copy and
|
|
103
|
+
Ctrl+Y are the primary paths.
|
|
104
|
+
- Your terminal's native selection still works too: hold **Shift** (most
|
|
105
|
+
terminals) or **Option/Alt** (iTerm2/macOS) while dragging.
|
|
106
|
+
|
|
107
|
+
## Local file editing
|
|
108
|
+
When the agent calls a local tool, the server pauses the turn with
|
|
109
|
+
`local_tools_pending`; this client executes it on disk and resumes. Supported
|
|
110
|
+
tools: `local_read_file`, `local_write_file`, `local_edit_file`,
|
|
111
|
+
`local_list_dir`, `local_search`, `local_run_command`.
|
|
112
|
+
|
|
113
|
+
- **Sandbox:** every path resolves under the directory you launched
|
|
114
|
+
`upivia-tui` from and can never escape it.
|
|
115
|
+
- **Command gating:** the first time the agent wants to run a shell command,
|
|
116
|
+
you're asked once which categories it may use (shell / install / servers /
|
|
117
|
+
git / delete); the choice is enforced for the rest of the session.
|
|
118
|
+
- **Diffs:** writes and edits render a colorised +/- diff card inline.
|
|
119
|
+
|
|
120
|
+
## Local browser automation
|
|
121
|
+
|
|
122
|
+
The TUI ships with **built-in Playwright browser tools** โ install the TUI and
|
|
123
|
+
the agent can pilot a real local Chromium with zero manual setup. On the very
|
|
124
|
+
first browser call, the Chromium engine is auto-installed (one-time,
|
|
125
|
+
`python -m playwright install chromium`, with a "Installing local browser
|
|
126
|
+
engine (one-time setup)โฆ" status line); after that it's instant. One persistent
|
|
127
|
+
headless browser/page is kept alive across tool calls for the session.
|
|
128
|
+
|
|
129
|
+
Tools: `local_browser_open`, `local_browser_snapshot`, `local_browser_click`,
|
|
130
|
+
`local_browser_type`, `local_browser_press`, `local_browser_select`,
|
|
131
|
+
`local_browser_wait`, `local_browser_extract`, `local_browser_screenshot`,
|
|
132
|
+
`local_browser_close`, `local_browser_health`.
|
|
133
|
+
|
|
134
|
+
**Ref-based interaction contract:** the agent calls `local_browser_snapshot`
|
|
135
|
+
first (or reads the snapshot embedded in `open`/`click`/`type` results), which
|
|
136
|
+
tags interactive elements with stable refs like `e12` and returns them in an
|
|
137
|
+
LLM-friendly digest (role, name, text, visibility, links, forms, console
|
|
138
|
+
errors). Clicks/typing then target those refs, with visible-text and CSS
|
|
139
|
+
selectors as fallbacks. Refs refresh automatically after every action, so they
|
|
140
|
+
never go stale silently.
|
|
141
|
+
|
|
142
|
+
Safety notes:
|
|
143
|
+
|
|
144
|
+
- no tool ever returns cookies, localStorage, or other secrets
|
|
145
|
+
- downloads are disabled (`accept_downloads=False`)
|
|
146
|
+
- screenshots are saved as PNG files under `.upivia-screenshots/` in your
|
|
147
|
+
project directory โ only the file path is returned, never inline image data
|
|
148
|
+
- navigating to banking/payment-looking hosts attaches a warning to the result
|
|
149
|
+
- every failure returns a structured error with suggestions (valid refs,
|
|
150
|
+
repair hints) instead of crashing the turn
|
|
151
|
+
|
|
152
|
+
## Auth
|
|
153
|
+
|
|
154
|
+
It reads the **same** `~/.upivia/config.json` that `upivia init` (the Node CLI)
|
|
155
|
+
writes. If you've authenticated the Node CLI, you're authenticated here.
|
|
156
|
+
|
|
157
|
+
Override for dev:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
export UPIVIA_BASE_URL=http://localhost:3000
|
|
161
|
+
export UPIVIA_PAT=upivia_pat_...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Run
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
cd packages/upivia-tui
|
|
168
|
+
uv run upivia-tui # full TUI in the current directory
|
|
169
|
+
uv run upivia-tui --dir PATH # full TUI rooted at PATH
|
|
170
|
+
uv run upivia-tui --background # headless device daemon (no UI)
|
|
171
|
+
uv run upivia-tui --browser-headful # show the built-in browser window
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Built-in local browser: headless vs headful
|
|
175
|
+
|
|
176
|
+
The `local_browser_*` tools drive a local Chromium that is **headless by
|
|
177
|
+
default**. To watch the agent work (or complete a login/captcha yourself),
|
|
178
|
+
opt in to a visible window with any of:
|
|
179
|
+
|
|
180
|
+
- `--browser-headful` CLI flag
|
|
181
|
+
- `UPIVIA_BROWSER_HEADFUL=1` environment variable
|
|
182
|
+
- `"browserHeadful": true` in `~/.upivia/config.json`
|
|
183
|
+
|
|
184
|
+
## Realtime sync + machine-wide device
|
|
185
|
+
|
|
186
|
+
The TUI connects to the platform's WebSocket companion (`wss://โฆ/ws`) and
|
|
187
|
+
registers as a **live device**:
|
|
188
|
+
|
|
189
|
+
- Chat turns flow over WS, so the **web app and the TUI share one live
|
|
190
|
+
session** โ messages and tool calls appear in both in real time (SSE fallback
|
|
191
|
+
if the socket can't connect).
|
|
192
|
+
- While the TUI is open **or** `upivia-tui --background` is running, **any web
|
|
193
|
+
session attached to this device can read/write/edit/run files on this
|
|
194
|
+
machine** through the governed `local_tools_pending` โ execute โ
|
|
195
|
+
`tool_result` loop. Attach a device from the web app's Sessions view.
|
|
196
|
+
- The TopBar shows `โ live` (WS connected / device online) or `โ local`.
|
|
197
|
+
|
|
198
|
+
### Set the working directory from the web app
|
|
199
|
+
|
|
200
|
+
When a device is live, the web Sessions header shows a subtle folder chip. Click
|
|
201
|
+
it to browse the device's directories and `cd` into one โ type a path (Tab
|
|
202
|
+
completes against available sub-directories, Enter applies) or click a listed
|
|
203
|
+
folder. This rebases the directory the agent reads/writes/runs in, sandboxed to
|
|
204
|
+
the chosen root.
|
|
205
|
+
|
|
206
|
+
## How it talks to the platform
|
|
207
|
+
|
|
208
|
+
REST + SSE go through the official Python SDK (`upivia`,
|
|
209
|
+
`packages/sdk-py`): `upivia_tui/client.py` is a thin adapter over
|
|
210
|
+
`upivia.AsyncUpiviaClient` (PAT auth). The realtime WebSocket
|
|
211
|
+
device link (`upivia_tui/wsclient.py`) speaks to the WS companion directly.
|
|
212
|
+
|
|
213
|
+
| Action | Endpoint |
|
|
214
|
+
|-------------------|-------------------------------------------|
|
|
215
|
+
| List agents | `GET /api/v1/agents` |
|
|
216
|
+
| Balance | `GET /api/v1/balance` |
|
|
217
|
+
| Create session | `POST /api/v1/chat/sessions` |
|
|
218
|
+
| Stream a turn | `POST /api/v1/chat/turn` (SSE) |
|
|
219
|
+
|
|
220
|
+
Delegation is driven by the `delegation_started` and `agent_event` SSE events
|
|
221
|
+
emitted by the chat route when Yupi spawns/delegates to worker agents.
|
|
222
|
+
|
|
223
|
+
## Yupi delegates by default
|
|
224
|
+
|
|
225
|
+
The orchestration system prompt in `app/api/v1/chat/turn/route.ts` instructs
|
|
226
|
+
Yupi to delegate any non-trivial or multi-step work to specialist agents, only
|
|
227
|
+
working solo for genuinely trivial single-step actions.
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# upivia-tui
|
|
2
|
+
|
|
3
|
+
The **Upivia terminal** โ a [Textual](https://textual.textualize.io/) TUI and the
|
|
4
|
+
canonical CLI for Upivia (it replaced the older Node/OpenTUI CLI). It is a thin
|
|
5
|
+
presentation layer over the platform's governed chat-turn pipeline โ all
|
|
6
|
+
orchestration, budgets, approvals, memory, and multi-agent delegation happen
|
|
7
|
+
server-side.
|
|
8
|
+
|
|
9
|
+
## What it does
|
|
10
|
+
|
|
11
|
+
- renders messages as bordered cards (OpenCode-style)
|
|
12
|
+
- renders markdown with Textual's native widget (clean tables/code/bold/italic)
|
|
13
|
+
- visualises multi-agent delegation in a live Team panel (+ worker detail view)
|
|
14
|
+
- lets the agent **read/write/edit/run** files in your launch directory, with
|
|
15
|
+
per-session command permissions and inline +/- diff cards
|
|
16
|
+
- syncs in realtime with the web app over WebSocket, and can run headless
|
|
17
|
+
(`--background`) so the web app edits files on this machine
|
|
18
|
+
|
|
19
|
+
## Install & authenticate
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv tool install upivia-tui # or: pipx install upivia-tui (Python 3.10+)
|
|
23
|
+
upivia-tui init # authenticate (writes ~/.upivia/config.json)
|
|
24
|
+
upivia-tui # launch
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Keyboard & commands
|
|
28
|
+
|
|
29
|
+
| Key | Action |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `Ctrl+P` | Command palette (fuzzy) |
|
|
32
|
+
| `Ctrl+O` | Switch model (curated + full OpenRouter catalog) |
|
|
33
|
+
| `Ctrl+T` | Switch agent |
|
|
34
|
+
| `Ctrl+B` | Switch session (loads history) |
|
|
35
|
+
| `Ctrl+G` | Toggle Build / Plan mode |
|
|
36
|
+
| `Ctrl+L` | New / clear session |
|
|
37
|
+
| `Ctrl+Y` | Copy (selection, or last reply) โ also drag-to-copy |
|
|
38
|
+
| `Ctrl+C` / `Ctrl+Q` | Quit |
|
|
39
|
+
|
|
40
|
+
All shortcuts work even while typing in the composer (priority bindings).
|
|
41
|
+
`Ctrl+S` is intentionally avoided (it triggers terminal flow-control on many
|
|
42
|
+
terminals).
|
|
43
|
+
|
|
44
|
+
Slash commands: `/models` `/model <id>` `/agent` `/sessions` `/session`
|
|
45
|
+
`/new` `/rename <title>` `/delete` `/mode` `/autonomy` `/requests` `/worker`
|
|
46
|
+
`/export` `/compact` `/clear` `/help`. The model picker and command palette
|
|
47
|
+
mirror the Node CLI; selecting a new model or agent starts a fresh session so
|
|
48
|
+
history stays consistent.
|
|
49
|
+
|
|
50
|
+
### Autocomplete & worker detail
|
|
51
|
+
|
|
52
|
+
- Type `@` in the composer to autocomplete **project files** (Tab/Enter to
|
|
53
|
+
accept); mentioned files are read by the agent first.
|
|
54
|
+
- Type `/` to autocomplete **slash commands** from a fuzzy dropdown.
|
|
55
|
+
- Click a worker in the Team panel (or run `/worker`) to open its **full
|
|
56
|
+
activity stream** โ every thinking step, tool call, file write, and result.
|
|
57
|
+
- The agent can navigate large codebases with `local_code_graph` (Graphify);
|
|
58
|
+
install with `uv tool install graphifyy`. It falls back to `local_search`
|
|
59
|
+
when graphify isn't present.
|
|
60
|
+
|
|
61
|
+
## Copy & select
|
|
62
|
+
|
|
63
|
+
Textual runs in mouse-tracking mode, so the app handles selection itself:
|
|
64
|
+
|
|
65
|
+
- **Drag** with the mouse to select text โ it **auto-copies on release** (via
|
|
66
|
+
OSC 52, so it works over SSH and writes the system clipboard where available).
|
|
67
|
+
This is the reliable path and needs no key.
|
|
68
|
+
- **Ctrl+Y** copies the current selection, or the last assistant reply if
|
|
69
|
+
nothing is selected.
|
|
70
|
+
- `Ctrl+Shift+C` also works *where the terminal forwards it* โ but many
|
|
71
|
+
terminals intercept it for their own copy, which is why drag-to-copy and
|
|
72
|
+
Ctrl+Y are the primary paths.
|
|
73
|
+
- Your terminal's native selection still works too: hold **Shift** (most
|
|
74
|
+
terminals) or **Option/Alt** (iTerm2/macOS) while dragging.
|
|
75
|
+
|
|
76
|
+
## Local file editing
|
|
77
|
+
When the agent calls a local tool, the server pauses the turn with
|
|
78
|
+
`local_tools_pending`; this client executes it on disk and resumes. Supported
|
|
79
|
+
tools: `local_read_file`, `local_write_file`, `local_edit_file`,
|
|
80
|
+
`local_list_dir`, `local_search`, `local_run_command`.
|
|
81
|
+
|
|
82
|
+
- **Sandbox:** every path resolves under the directory you launched
|
|
83
|
+
`upivia-tui` from and can never escape it.
|
|
84
|
+
- **Command gating:** the first time the agent wants to run a shell command,
|
|
85
|
+
you're asked once which categories it may use (shell / install / servers /
|
|
86
|
+
git / delete); the choice is enforced for the rest of the session.
|
|
87
|
+
- **Diffs:** writes and edits render a colorised +/- diff card inline.
|
|
88
|
+
|
|
89
|
+
## Local browser automation
|
|
90
|
+
|
|
91
|
+
The TUI ships with **built-in Playwright browser tools** โ install the TUI and
|
|
92
|
+
the agent can pilot a real local Chromium with zero manual setup. On the very
|
|
93
|
+
first browser call, the Chromium engine is auto-installed (one-time,
|
|
94
|
+
`python -m playwright install chromium`, with a "Installing local browser
|
|
95
|
+
engine (one-time setup)โฆ" status line); after that it's instant. One persistent
|
|
96
|
+
headless browser/page is kept alive across tool calls for the session.
|
|
97
|
+
|
|
98
|
+
Tools: `local_browser_open`, `local_browser_snapshot`, `local_browser_click`,
|
|
99
|
+
`local_browser_type`, `local_browser_press`, `local_browser_select`,
|
|
100
|
+
`local_browser_wait`, `local_browser_extract`, `local_browser_screenshot`,
|
|
101
|
+
`local_browser_close`, `local_browser_health`.
|
|
102
|
+
|
|
103
|
+
**Ref-based interaction contract:** the agent calls `local_browser_snapshot`
|
|
104
|
+
first (or reads the snapshot embedded in `open`/`click`/`type` results), which
|
|
105
|
+
tags interactive elements with stable refs like `e12` and returns them in an
|
|
106
|
+
LLM-friendly digest (role, name, text, visibility, links, forms, console
|
|
107
|
+
errors). Clicks/typing then target those refs, with visible-text and CSS
|
|
108
|
+
selectors as fallbacks. Refs refresh automatically after every action, so they
|
|
109
|
+
never go stale silently.
|
|
110
|
+
|
|
111
|
+
Safety notes:
|
|
112
|
+
|
|
113
|
+
- no tool ever returns cookies, localStorage, or other secrets
|
|
114
|
+
- downloads are disabled (`accept_downloads=False`)
|
|
115
|
+
- screenshots are saved as PNG files under `.upivia-screenshots/` in your
|
|
116
|
+
project directory โ only the file path is returned, never inline image data
|
|
117
|
+
- navigating to banking/payment-looking hosts attaches a warning to the result
|
|
118
|
+
- every failure returns a structured error with suggestions (valid refs,
|
|
119
|
+
repair hints) instead of crashing the turn
|
|
120
|
+
|
|
121
|
+
## Auth
|
|
122
|
+
|
|
123
|
+
It reads the **same** `~/.upivia/config.json` that `upivia init` (the Node CLI)
|
|
124
|
+
writes. If you've authenticated the Node CLI, you're authenticated here.
|
|
125
|
+
|
|
126
|
+
Override for dev:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
export UPIVIA_BASE_URL=http://localhost:3000
|
|
130
|
+
export UPIVIA_PAT=upivia_pat_...
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Run
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
cd packages/upivia-tui
|
|
137
|
+
uv run upivia-tui # full TUI in the current directory
|
|
138
|
+
uv run upivia-tui --dir PATH # full TUI rooted at PATH
|
|
139
|
+
uv run upivia-tui --background # headless device daemon (no UI)
|
|
140
|
+
uv run upivia-tui --browser-headful # show the built-in browser window
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Built-in local browser: headless vs headful
|
|
144
|
+
|
|
145
|
+
The `local_browser_*` tools drive a local Chromium that is **headless by
|
|
146
|
+
default**. To watch the agent work (or complete a login/captcha yourself),
|
|
147
|
+
opt in to a visible window with any of:
|
|
148
|
+
|
|
149
|
+
- `--browser-headful` CLI flag
|
|
150
|
+
- `UPIVIA_BROWSER_HEADFUL=1` environment variable
|
|
151
|
+
- `"browserHeadful": true` in `~/.upivia/config.json`
|
|
152
|
+
|
|
153
|
+
## Realtime sync + machine-wide device
|
|
154
|
+
|
|
155
|
+
The TUI connects to the platform's WebSocket companion (`wss://โฆ/ws`) and
|
|
156
|
+
registers as a **live device**:
|
|
157
|
+
|
|
158
|
+
- Chat turns flow over WS, so the **web app and the TUI share one live
|
|
159
|
+
session** โ messages and tool calls appear in both in real time (SSE fallback
|
|
160
|
+
if the socket can't connect).
|
|
161
|
+
- While the TUI is open **or** `upivia-tui --background` is running, **any web
|
|
162
|
+
session attached to this device can read/write/edit/run files on this
|
|
163
|
+
machine** through the governed `local_tools_pending` โ execute โ
|
|
164
|
+
`tool_result` loop. Attach a device from the web app's Sessions view.
|
|
165
|
+
- The TopBar shows `โ live` (WS connected / device online) or `โ local`.
|
|
166
|
+
|
|
167
|
+
### Set the working directory from the web app
|
|
168
|
+
|
|
169
|
+
When a device is live, the web Sessions header shows a subtle folder chip. Click
|
|
170
|
+
it to browse the device's directories and `cd` into one โ type a path (Tab
|
|
171
|
+
completes against available sub-directories, Enter applies) or click a listed
|
|
172
|
+
folder. This rebases the directory the agent reads/writes/runs in, sandboxed to
|
|
173
|
+
the chosen root.
|
|
174
|
+
|
|
175
|
+
## How it talks to the platform
|
|
176
|
+
|
|
177
|
+
REST + SSE go through the official Python SDK (`upivia`,
|
|
178
|
+
`packages/sdk-py`): `upivia_tui/client.py` is a thin adapter over
|
|
179
|
+
`upivia.AsyncUpiviaClient` (PAT auth). The realtime WebSocket
|
|
180
|
+
device link (`upivia_tui/wsclient.py`) speaks to the WS companion directly.
|
|
181
|
+
|
|
182
|
+
| Action | Endpoint |
|
|
183
|
+
|-------------------|-------------------------------------------|
|
|
184
|
+
| List agents | `GET /api/v1/agents` |
|
|
185
|
+
| Balance | `GET /api/v1/balance` |
|
|
186
|
+
| Create session | `POST /api/v1/chat/sessions` |
|
|
187
|
+
| Stream a turn | `POST /api/v1/chat/turn` (SSE) |
|
|
188
|
+
|
|
189
|
+
Delegation is driven by the `delegation_started` and `agent_event` SSE events
|
|
190
|
+
emitted by the chat route when Yupi spawns/delegates to worker agents.
|
|
191
|
+
|
|
192
|
+
## Yupi delegates by default
|
|
193
|
+
|
|
194
|
+
The orchestration system prompt in `app/api/v1/chat/turn/route.ts` instructs
|
|
195
|
+
Yupi to delegate any non-trivial or multi-step work to specialist agents, only
|
|
196
|
+
working solo for genuinely trivial single-step actions.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "upivia-tui"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Upivia Textual TUI โ chat with Yupi, watch multi-agent delegation, reuse the platform's governed orchestration."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "Upivia" }]
|
|
9
|
+
keywords = ["upivia", "ai-agents", "tui", "terminal", "cli", "agents", "governance"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
|
+
"Environment :: Console",
|
|
13
|
+
"Intended Audience :: Developers",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Topic :: Terminals",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"textual>=0.80.0",
|
|
25
|
+
"httpx>=0.27.0",
|
|
26
|
+
"websockets>=12.0",
|
|
27
|
+
"playwright>=1.45",
|
|
28
|
+
"upivia>=0.2.0",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[tool.uv.sources]
|
|
32
|
+
upivia = { path = "../sdk-py", editable = true }
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://www.upivia.com"
|
|
36
|
+
Documentation = "https://www.upivia.com/docs"
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
dev = [
|
|
40
|
+
"pytest>=8.0",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
upivia-tui = "upivia_tui.__main__:main"
|
|
45
|
+
upivia = "upivia_tui.__main__:main"
|
|
46
|
+
|
|
47
|
+
[build-system]
|
|
48
|
+
requires = ["hatchling"]
|
|
49
|
+
build-backend = "hatchling.build"
|
|
50
|
+
|
|
51
|
+
[tool.hatch.build.targets.wheel]
|
|
52
|
+
packages = ["src/upivia_tui"]
|
|
53
|
+
|
|
54
|
+
[tool.pytest.ini_options]
|
|
55
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Upivia Textual TUI.
|
|
2
|
+
|
|
3
|
+
A thin Python client that reuses the platform's governed chat-turn pipeline
|
|
4
|
+
(`POST /api/v1/chat/turn`, SSE streaming). All orchestration, budgets,
|
|
5
|
+
approvals, memory, and multi-agent delegation happen server-side โ this is a
|
|
6
|
+
presentation layer only.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .version import __version__
|
|
10
|
+
|
|
11
|
+
__all__ = ["__version__"]
|