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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lithe-cli
3
- Version: 0.5.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
- ### Interactive chat
117
-
118
- ```bash
119
- $ lithe chat
120
- ╭──────────────────────────────────────╮
121
- │ lithe 0.4.0 │
122
- │ model your-model │
123
- │ workdir /home/me/my-project │
124
- │ /help 查看会话命令,/exit 退出 │
125
- ╰──────────────────────────────────────╯
126
- lithe ❯ 把 a.txt 改成三行待办清单
127
- ⚒ write_file {"path": "a.txt", ...}
128
- ✓ 写入 a.txt 0.0s
129
- 已完成。
130
- ── done · steps 2 · tokens 180
131
- lithe ❯ /exit
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
- History carries across turns within a session (each turn is its own run in
135
- the store, replayed as context for the next). `/new` clears the session,
136
- `/tools` lists the registered tools, `/help` lists the commands.
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
- ### Interactive chat
69
-
70
- ```bash
71
- $ lithe chat
72
- ╭──────────────────────────────────────╮
73
- │ lithe 0.4.0 │
74
- │ model your-model │
75
- │ workdir /home/me/my-project │
76
- │ /help 查看会话命令,/exit 退出 │
77
- ╰──────────────────────────────────────╯
78
- lithe ❯ 把 a.txt 改成三行待办清单
79
- ⚒ write_file {"path": "a.txt", ...}
80
- ✓ 写入 a.txt 0.0s
81
- 已完成。
82
- ── done · steps 2 · tokens 180
83
- lithe ❯ /exit
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
- History carries across turns within a session (each turn is its own run in
87
- the store, replayed as context for the next). `/new` clears the session,
88
- `/tools` lists the registered tools, `/help` lists the commands.
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
 
@@ -1,3 +1,3 @@
1
1
  """lithe-cli: the command-line interface for the lithe agent kernel."""
2
2
 
3
- __version__ = "0.5.0"
3
+ __version__ = "0.6.0"
@@ -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
- if dashboard is not None:
228
- dashboard.start()
229
- async for ev in host.run(ctx, task, history=history):
230
- render_event(ev, cfg.verbose, cfg.stream, pending, dashboard)
231
- if ev.get("type") == "done":
232
- if dashboard is not None:
233
- dashboard.finish(ev)
234
- elif cfg.stream and pending.get("_deltas"):
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)