lithe-cli 0.5.0__tar.gz → 0.6.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.
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/PKG-INFO +35 -20
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/README.md +34 -19
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli/__init__.py +1 -1
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli/agent.py +18 -25
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli/main.py +9 -0
- lithe_cli-0.6.0/lithe_cli/tui.py +512 -0
- lithe_cli-0.6.0/lithe_cli/ui.py +268 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli.egg-info/PKG-INFO +35 -20
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli.egg-info/SOURCES.txt +1 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/tests/test_cli.py +52 -25
- lithe_cli-0.5.0/lithe_cli/ui.py +0 -486
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/LICENSE +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli/__main__.py +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli/config.py +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli/prompts.py +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli/py.typed +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli/setup.py +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli.egg-info/dependency_links.txt +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli.egg-info/entry_points.txt +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli.egg-info/requires.txt +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/lithe_cli.egg-info/top_level.txt +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/pyproject.toml +0 -0
- {lithe_cli-0.5.0 → lithe_cli-0.6.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lithe-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Command-line interface for the lithe agent kernel: chat, one-shot runs, undo, and run inspection.
|
|
5
5
|
License: MIT License
|
|
6
6
|
|
|
@@ -113,27 +113,42 @@ $ lithe run "总结 README.md 的要点,存到 SUMMARY.md"
|
|
|
113
113
|
usage/context gauges; `--max-steps` caps the tool loop;
|
|
114
114
|
`--context-window` enables fullness gauges.
|
|
115
115
|
|
|
116
|
-
###
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
116
|
+
### Full-screen interface
|
|
117
|
+
|
|
118
|
+
On an interactive terminal, `lithe chat` and `lithe run TASK` open a
|
|
119
|
+
persistent full-screen interface instead of scribbling one-line events
|
|
120
|
+
into the console:
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
lithe 0.6.0 · your-model · /home/me/my-project ● 完成 · 0.2s
|
|
124
|
+
┌─ 对话 ──────────────────────────────┐┌─ 运行状态 ─────────┐
|
|
125
|
+
│ 把 a.txt 改成三行待办清单 ││ ● 完成 · 0.2s │
|
|
126
|
+
│ ⚒ update_todos {"todos": [...]} ││ 步骤 2/35 · 0.2s │
|
|
127
|
+
│ ✓ 任务清单已更新(3 条) 0.0s ││ ✓ update_todos 0.0s│
|
|
128
|
+
│ ⚒ write_file {"path": "a.txt"} ││ ✓ write_file 0.0s │
|
|
129
|
+
│ ✓ 写入 a.txt 0.0s ││ ── 待办 1/3 │
|
|
130
|
+
│ 已完成。 ││ [~] 修改 a.txt │
|
|
131
|
+
│ ││ ── 用量 │
|
|
132
|
+
│ ││ tokens 1,240 │
|
|
133
|
+
└─────────────────────────────────────┘└────────────────────┘
|
|
134
|
+
lithe ❯ _
|
|
135
|
+
● 完成 · step 2/35 · 1,240 tok · $0.0021 Enter 发送 · /help 命令
|
|
132
136
|
```
|
|
133
137
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
The left pane is the conversation (task, tool calls and outcomes, the
|
|
139
|
+
streaming assistant reply); the right sidebar shows run status, step
|
|
140
|
+
budget and elapsed time, recent tool calls with duration, the agent's
|
|
141
|
+
todo list (updated live as the agent rewrites it), and running token /
|
|
142
|
+
cost / context totals. The screen stays up between turns — a finished
|
|
143
|
+
run does not dump you back into the raw console. `Ctrl+C` cancels the
|
|
144
|
+
current turn while running and exits when idle; in `lithe run` mode the
|
|
145
|
+
result stays on screen until you press `q`. Layout, wrapping and
|
|
146
|
+
alignment are East-Asian-width aware; narrower terminals stack the two
|
|
147
|
+
panes vertically. Pipes and CI keep the plain per-line output unchanged.
|
|
148
|
+
|
|
149
|
+
History carries across turns within a session (each turn is its own run
|
|
150
|
+
in the store, replayed as context for the next). `/new` clears the
|
|
151
|
+
session, `/tools` lists the registered tools, `/help` lists the commands.
|
|
137
152
|
|
|
138
153
|
### Extra capabilities
|
|
139
154
|
|
|
@@ -65,27 +65,42 @@ $ lithe run "总结 README.md 的要点,存到 SUMMARY.md"
|
|
|
65
65
|
usage/context gauges; `--max-steps` caps the tool loop;
|
|
66
66
|
`--context-window` enables fullness gauges.
|
|
67
67
|
|
|
68
|
-
###
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
68
|
+
### Full-screen interface
|
|
69
|
+
|
|
70
|
+
On an interactive terminal, `lithe chat` and `lithe run TASK` open a
|
|
71
|
+
persistent full-screen interface instead of scribbling one-line events
|
|
72
|
+
into the console:
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
lithe 0.6.0 · your-model · /home/me/my-project ● 完成 · 0.2s
|
|
76
|
+
┌─ 对话 ──────────────────────────────┐┌─ 运行状态 ─────────┐
|
|
77
|
+
│ 把 a.txt 改成三行待办清单 ││ ● 完成 · 0.2s │
|
|
78
|
+
│ ⚒ update_todos {"todos": [...]} ││ 步骤 2/35 · 0.2s │
|
|
79
|
+
│ ✓ 任务清单已更新(3 条) 0.0s ││ ✓ update_todos 0.0s│
|
|
80
|
+
│ ⚒ write_file {"path": "a.txt"} ││ ✓ write_file 0.0s │
|
|
81
|
+
│ ✓ 写入 a.txt 0.0s ││ ── 待办 1/3 │
|
|
82
|
+
│ 已完成。 ││ [~] 修改 a.txt │
|
|
83
|
+
│ ││ ── 用量 │
|
|
84
|
+
│ ││ tokens 1,240 │
|
|
85
|
+
└─────────────────────────────────────┘└────────────────────┘
|
|
86
|
+
lithe ❯ _
|
|
87
|
+
● 完成 · step 2/35 · 1,240 tok · $0.0021 Enter 发送 · /help 命令
|
|
84
88
|
```
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
The left pane is the conversation (task, tool calls and outcomes, the
|
|
91
|
+
streaming assistant reply); the right sidebar shows run status, step
|
|
92
|
+
budget and elapsed time, recent tool calls with duration, the agent's
|
|
93
|
+
todo list (updated live as the agent rewrites it), and running token /
|
|
94
|
+
cost / context totals. The screen stays up between turns — a finished
|
|
95
|
+
run does not dump you back into the raw console. `Ctrl+C` cancels the
|
|
96
|
+
current turn while running and exits when idle; in `lithe run` mode the
|
|
97
|
+
result stays on screen until you press `q`. Layout, wrapping and
|
|
98
|
+
alignment are East-Asian-width aware; narrower terminals stack the two
|
|
99
|
+
panes vertically. Pipes and CI keep the plain per-line output unchanged.
|
|
100
|
+
|
|
101
|
+
History carries across turns within a session (each turn is its own run
|
|
102
|
+
in the store, replayed as context for the next). `/new` clears the
|
|
103
|
+
session, `/tools` lists the registered tools, `/help` lists the commands.
|
|
89
104
|
|
|
90
105
|
### Extra capabilities
|
|
91
106
|
|
|
@@ -135,7 +135,6 @@ def render_event(
|
|
|
135
135
|
verbose: bool = False,
|
|
136
136
|
stream: bool = False,
|
|
137
137
|
pending: dict | None = None,
|
|
138
|
-
dashboard=None,
|
|
139
138
|
) -> None:
|
|
140
139
|
"""Render one runtime event onto the terminal.
|
|
141
140
|
|
|
@@ -143,9 +142,6 @@ def render_event(
|
|
|
143
142
|
elapsed seconds. ``stream`` suppresses the full-text echo of the final
|
|
144
143
|
answer when its tokens were already streamed.
|
|
145
144
|
"""
|
|
146
|
-
if dashboard is not None:
|
|
147
|
-
dashboard.update(ev, verbose=verbose)
|
|
148
|
-
return
|
|
149
145
|
t = ev.get("type")
|
|
150
146
|
pending = pending if pending is not None else {}
|
|
151
147
|
if t == "assistant_delta":
|
|
@@ -191,8 +187,17 @@ async def execute(
|
|
|
191
187
|
task: str,
|
|
192
188
|
history: list[dict] | None = None,
|
|
193
189
|
run_id: str | None = None,
|
|
190
|
+
on_event=None,
|
|
191
|
+
stop=None,
|
|
194
192
|
) -> tuple[str, dict, Any]:
|
|
195
|
-
"""Run one task end-to-end; returns (run_id, done_event, host).
|
|
193
|
+
"""Run one task end-to-end; returns (run_id, done_event, host).
|
|
194
|
+
|
|
195
|
+
``on_event`` (the full-screen TUI supplies one) receives every kernel
|
|
196
|
+
event and silences the line-oriented printing below, including the
|
|
197
|
+
footer — the caller renders from the events instead. ``stop`` is the
|
|
198
|
+
kernel's cancellation handle, surfaced so Ctrl+C can cancel a turn
|
|
199
|
+
without killing the process.
|
|
200
|
+
"""
|
|
196
201
|
reg = build_registry(cfg)
|
|
197
202
|
host = build_host(cfg, reg)
|
|
198
203
|
rid = run_id or uuid.uuid4().hex[:12]
|
|
@@ -214,29 +219,17 @@ async def execute(
|
|
|
214
219
|
ui.error(f"MCP {name}: {res}")
|
|
215
220
|
ev: dict = {}
|
|
216
221
|
pending: dict[str, float] = {}
|
|
217
|
-
todo_path = cfg.store_dir / f"todos-{cfg.user_id}.json"
|
|
218
|
-
dashboard = ui.dashboard(
|
|
219
|
-
cfg.model or "(scripted)",
|
|
220
|
-
str(cfg.workspace_dir.resolve()),
|
|
221
|
-
rid,
|
|
222
|
-
task,
|
|
223
|
-
cfg.max_steps,
|
|
224
|
-
JsonTodoStore(todo_path).list(),
|
|
225
|
-
)
|
|
226
222
|
try:
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
print()
|
|
223
|
+
async for ev in host.run(ctx, task, history=history, stop=stop):
|
|
224
|
+
if on_event is not None:
|
|
225
|
+
on_event(ev)
|
|
226
|
+
else:
|
|
227
|
+
render_event(ev, cfg.verbose, cfg.stream, pending)
|
|
228
|
+
if ev.get("type") == "done" and on_event is None:
|
|
229
|
+
if cfg.stream and pending.get("_deltas"):
|
|
230
|
+
print() # close the streaming line before the footer
|
|
236
231
|
ui.footer(ev)
|
|
237
232
|
finally:
|
|
238
|
-
if dashboard is not None:
|
|
239
|
-
dashboard.close()
|
|
240
233
|
if manager is not None:
|
|
241
234
|
await manager.close()
|
|
242
235
|
return rid, ev, host
|
|
@@ -33,6 +33,7 @@ from . import prompts
|
|
|
33
33
|
from .agent import build_registry, execute, sandbox_backend, undo
|
|
34
34
|
from .config import config_file, load_config, require_endpoint
|
|
35
35
|
from .prompts import open_history
|
|
36
|
+
from .tui import screen_supported
|
|
36
37
|
from .ui import BOLD, CYAN, GREEN, RED, YELLOW, configure, truncate, ui
|
|
37
38
|
|
|
38
39
|
|
|
@@ -397,9 +398,17 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
397
398
|
configure(cfg.color)
|
|
398
399
|
if args.command == "run":
|
|
399
400
|
require_endpoint(cfg, interactive=not args.no_setup)
|
|
401
|
+
if screen_supported():
|
|
402
|
+
from .tui import run_screen
|
|
403
|
+
|
|
404
|
+
return asyncio.run(run_screen(cfg, args.task, "run"))
|
|
400
405
|
return _cmd_run(cfg, args.task)
|
|
401
406
|
if args.command == "chat":
|
|
402
407
|
require_endpoint(cfg, interactive=not args.no_setup)
|
|
408
|
+
if screen_supported():
|
|
409
|
+
from .tui import run_screen
|
|
410
|
+
|
|
411
|
+
return asyncio.run(run_screen(cfg, None, "chat"))
|
|
403
412
|
return _chat_loop(cfg)
|
|
404
413
|
if args.command == "tools":
|
|
405
414
|
return _cmd_tools(cfg)
|