lithe-cli 0.5.0__tar.gz → 0.6.1__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.1}/PKG-INFO +44 -29
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/README.md +41 -21
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli/__init__.py +1 -1
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli/agent.py +21 -28
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli/main.py +9 -0
- lithe-cli-0.6.1/lithe_cli/tui.py +588 -0
- lithe-cli-0.6.1/lithe_cli/ui.py +290 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli.egg-info/PKG-INFO +44 -29
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli.egg-info/SOURCES.txt +1 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/tests/test_cli.py +127 -24
- lithe_cli-0.5.0/lithe_cli/ui.py +0 -486
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/LICENSE +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli/__main__.py +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli/config.py +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli/prompts.py +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli/py.typed +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli/setup.py +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli.egg-info/dependency_links.txt +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli.egg-info/entry_points.txt +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli.egg-info/requires.txt +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/lithe_cli.egg-info/top_level.txt +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/pyproject.toml +0 -0
- {lithe_cli-0.5.0 → lithe-cli-0.6.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: lithe-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
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
|
|
|
@@ -38,13 +38,8 @@ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
|
38
38
|
Classifier: Typing :: Typed
|
|
39
39
|
Requires-Python: >=3.10
|
|
40
40
|
Description-Content-Type: text/markdown
|
|
41
|
-
License-File: LICENSE
|
|
42
|
-
Requires-Dist: lithe>=0.9.8
|
|
43
|
-
Requires-Dist: prompt-toolkit>=3.0.38
|
|
44
41
|
Provides-Extra: dev
|
|
45
|
-
|
|
46
|
-
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
47
|
-
Dynamic: license-file
|
|
42
|
+
License-File: LICENSE
|
|
48
43
|
|
|
49
44
|
# lithe-cli
|
|
50
45
|
|
|
@@ -101,39 +96,59 @@ servers — so you can see what a run would use before starting one.
|
|
|
101
96
|
```bash
|
|
102
97
|
$ cd my-project
|
|
103
98
|
$ lithe run "总结 README.md 的要点,存到 SUMMARY.md"
|
|
104
|
-
⚒ read_file
|
|
99
|
+
⚒ read_file 读取 README.md
|
|
105
100
|
✓ 已读取 README.md(120 行) 0.1s
|
|
106
|
-
⚒ write_file
|
|
101
|
+
⚒ write_file 写入 SUMMARY.md
|
|
107
102
|
✓ 写入 SUMMARY.md 0.0s
|
|
108
103
|
已把要点写入 SUMMARY.md。
|
|
109
104
|
── done · steps 3 · tokens 2100 · cost 0.0042
|
|
110
105
|
```
|
|
111
106
|
|
|
107
|
+
修改已有文件时,助手优先调用 `edit_file` 或 `apply_patch` 做局部更新;只有新建文件或需要整体替换时才使用 `write_file`。工具调用界面只显示工具名、文件路径等摘要,不再展开完整参数。
|
|
108
|
+
|
|
112
109
|
`--stream` streams tokens as they generate; `-v` adds per-call
|
|
113
110
|
usage/context gauges; `--max-steps` caps the tool loop;
|
|
114
111
|
`--context-window` enables fullness gauges.
|
|
115
112
|
|
|
116
|
-
###
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
113
|
+
### Full-screen interface
|
|
114
|
+
|
|
115
|
+
On an interactive terminal, `lithe chat` and `lithe run TASK` open a
|
|
116
|
+
persistent full-screen interface instead of scribbling one-line events
|
|
117
|
+
into the console:
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
lithe 0.6.1 · your-model · /home/me/my-project ● 完成 · 0.2s
|
|
121
|
+
╭─ 对话 ──────────────────────────────╮╭─ 运行状态 ─────────╮
|
|
122
|
+
│ 把 a.txt 改成三行待办清单 ││ ● 完成 · 0.2s │
|
|
123
|
+
│ ◆ update_todos ││ 步骤 2/35 · 0.2s │
|
|
124
|
+
│ ✓ 任务清单已更新(3 条) 0.0s ││ ✓ update_todos 0.0s│
|
|
125
|
+
│ ◆ edit_file · 局部修改 a.txt ││ ✓ edit_file 0.0s │
|
|
126
|
+
│ ✓ 已修改 a.txt 0.0s ││ ◆ 待办 1/3 │
|
|
127
|
+
│ 已完成。 ││ [~] 修改 a.txt │
|
|
128
|
+
│ ││ ◆ 会话用量 │
|
|
129
|
+
│ ││ 输入 1,024 · 输出 216│
|
|
130
|
+
│ ││ 缓存输入 768 │
|
|
131
|
+
│ ││ 合计 1,240 · $0.0021│
|
|
132
|
+
│ ││ 上下文 1,024 / 128,000 (0.8%)│
|
|
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, compact tool-call summaries
|
|
139
|
+
and outcomes, and the streaming assistant reply). The right sidebar shows
|
|
140
|
+
run status, recent tools, todos, session-wide cumulative input/output/
|
|
141
|
+
cached tokens and cost, plus the latest model-call context length and
|
|
142
|
+
window percentage. The screen stays up between turns; `Ctrl+C` cancels
|
|
143
|
+
the current turn while running and exits when idle. In `lithe run` mode
|
|
144
|
+
the result stays on screen until you press `q`. Layout, wrapping and
|
|
145
|
+
alignment are East-Asian-width aware; narrower terminals stack the two
|
|
146
|
+
panes vertically. Pipes and CI keep the plain per-line output unchanged.
|
|
147
|
+
|
|
148
|
+
History carries across turns within a session (each turn is its own run
|
|
149
|
+
in the store, replayed as context for the next). `/new` clears the
|
|
150
|
+
conversation history and session usage totals; `/tools` lists the
|
|
151
|
+
registered tools, `/help` lists the commands.
|
|
137
152
|
|
|
138
153
|
### Extra capabilities
|
|
139
154
|
|
|
@@ -53,39 +53,59 @@ servers — so you can see what a run would use before starting one.
|
|
|
53
53
|
```bash
|
|
54
54
|
$ cd my-project
|
|
55
55
|
$ lithe run "总结 README.md 的要点,存到 SUMMARY.md"
|
|
56
|
-
⚒ read_file
|
|
56
|
+
⚒ read_file 读取 README.md
|
|
57
57
|
✓ 已读取 README.md(120 行) 0.1s
|
|
58
|
-
⚒ write_file
|
|
58
|
+
⚒ write_file 写入 SUMMARY.md
|
|
59
59
|
✓ 写入 SUMMARY.md 0.0s
|
|
60
60
|
已把要点写入 SUMMARY.md。
|
|
61
61
|
── done · steps 3 · tokens 2100 · cost 0.0042
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
修改已有文件时,助手优先调用 `edit_file` 或 `apply_patch` 做局部更新;只有新建文件或需要整体替换时才使用 `write_file`。工具调用界面只显示工具名、文件路径等摘要,不再展开完整参数。
|
|
65
|
+
|
|
64
66
|
`--stream` streams tokens as they generate; `-v` adds per-call
|
|
65
67
|
usage/context gauges; `--max-steps` caps the tool loop;
|
|
66
68
|
`--context-window` enables fullness gauges.
|
|
67
69
|
|
|
68
|
-
###
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
### Full-screen interface
|
|
71
|
+
|
|
72
|
+
On an interactive terminal, `lithe chat` and `lithe run TASK` open a
|
|
73
|
+
persistent full-screen interface instead of scribbling one-line events
|
|
74
|
+
into the console:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
lithe 0.6.1 · your-model · /home/me/my-project ● 完成 · 0.2s
|
|
78
|
+
╭─ 对话 ──────────────────────────────╮╭─ 运行状态 ─────────╮
|
|
79
|
+
│ 把 a.txt 改成三行待办清单 ││ ● 完成 · 0.2s │
|
|
80
|
+
│ ◆ update_todos ││ 步骤 2/35 · 0.2s │
|
|
81
|
+
│ ✓ 任务清单已更新(3 条) 0.0s ││ ✓ update_todos 0.0s│
|
|
82
|
+
│ ◆ edit_file · 局部修改 a.txt ││ ✓ edit_file 0.0s │
|
|
83
|
+
│ ✓ 已修改 a.txt 0.0s ││ ◆ 待办 1/3 │
|
|
84
|
+
│ 已完成。 ││ [~] 修改 a.txt │
|
|
85
|
+
│ ││ ◆ 会话用量 │
|
|
86
|
+
│ ││ 输入 1,024 · 输出 216│
|
|
87
|
+
│ ││ 缓存输入 768 │
|
|
88
|
+
│ ││ 合计 1,240 · $0.0021│
|
|
89
|
+
│ ││ 上下文 1,024 / 128,000 (0.8%)│
|
|
90
|
+
╰─────────────────────────────────────╯╰────────────────────╯
|
|
91
|
+
lithe ❯ _
|
|
92
|
+
● 完成 · step 2/35 · 1,240 tok · $0.0021 Enter 发送 · /help 命令
|
|
84
93
|
```
|
|
85
94
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
95
|
+
The left pane is the conversation (task, compact tool-call summaries
|
|
96
|
+
and outcomes, and the streaming assistant reply). The right sidebar shows
|
|
97
|
+
run status, recent tools, todos, session-wide cumulative input/output/
|
|
98
|
+
cached tokens and cost, plus the latest model-call context length and
|
|
99
|
+
window percentage. The screen stays up between turns; `Ctrl+C` cancels
|
|
100
|
+
the current turn while running and exits when idle. In `lithe run` mode
|
|
101
|
+
the result stays on screen until you press `q`. Layout, wrapping and
|
|
102
|
+
alignment are East-Asian-width aware; narrower terminals stack the two
|
|
103
|
+
panes vertically. Pipes and CI keep the plain per-line output unchanged.
|
|
104
|
+
|
|
105
|
+
History carries across turns within a session (each turn is its own run
|
|
106
|
+
in the store, replayed as context for the next). `/new` clears the
|
|
107
|
+
conversation history and session usage totals; `/tools` lists the
|
|
108
|
+
registered tools, `/help` lists the commands.
|
|
89
109
|
|
|
90
110
|
### Extra capabilities
|
|
91
111
|
|
|
@@ -17,7 +17,6 @@ Everything here maps lithe's host contract onto CLI defaults:
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
-
import json
|
|
21
20
|
import shutil
|
|
22
21
|
import sys
|
|
23
22
|
import time
|
|
@@ -43,7 +42,8 @@ from .ui import CYAN, GREEN, YELLOW, ui
|
|
|
43
42
|
|
|
44
43
|
SYSTEM_PROMPT_BASE = (
|
|
45
44
|
"你是运行在命令行里的助理,工作区是用户的当前目录。"
|
|
46
|
-
"
|
|
45
|
+
"用提供的文件工具完成任务(读写前先读、谨慎修改);修改已有文件时优先用 edit_file 或 apply_patch 做局部修改,"
|
|
46
|
+
"仅在新建文件或确需整体重写时使用 write_file。"
|
|
47
47
|
"需要多步任务时先用 update_todos 列出计划,最后用简洁中文汇报结果。"
|
|
48
48
|
)
|
|
49
49
|
|
|
@@ -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":
|
|
@@ -158,7 +154,7 @@ def render_event(
|
|
|
158
154
|
if text and not (stream and pending.get("_deltas")):
|
|
159
155
|
ui.assistant(text)
|
|
160
156
|
elif t == "tool_call":
|
|
161
|
-
args =
|
|
157
|
+
args = ev.get("args") or {}
|
|
162
158
|
ui.tool_call(str(ev.get("name")), args)
|
|
163
159
|
if ev.get("id") is not None:
|
|
164
160
|
pending[ev["id"]] = time.monotonic()
|
|
@@ -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)
|