Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ jobs:
uses: dtolnay/rust-toolchain@1.95.0

- name: Install cargo-audit
run: cargo install cargo-audit
# `--locked` uses cargo-audit's own pinned lockfile so a freshly
# published transitive dep can't raise the tool's MSRV above the
# toolchain pinned above (e.g. kstring 2.0.4 requiring rustc 1.96).
run: cargo install cargo-audit --locked

- name: Run cargo-audit
run: cargo audit
Expand All @@ -120,7 +123,9 @@ jobs:
uses: dtolnay/rust-toolchain@1.95.0

- name: Install cargo-deny
run: cargo install cargo-deny
# See the cargo-audit note above: pin to the tool's own lockfile so a
# transitive MSRV bump can't break the install on the pinned toolchain.
run: cargo install cargo-deny --locked

- name: Run cargo-deny
run: cargo deny check
Expand Down
17 changes: 13 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,11 @@ server = ["tokens", "dep:axum", "dep:tower-http"]
cli = ["server", "dep:clap", "dep:tracing-subscriber"]

# Real-time stats dashboard (`llmsim serve --tui`); only reachable via the
# binary, so it implies `cli`.
tui = ["cli", "dep:crossterm", "dep:ratatui", "tokio/io-util"]
# binary, so it implies `cli`. The dashboard is composed with `tuika` (flexbox
# layout, alt-screen host, focus, live redraw) and renders its data panels
# through `tuika`'s safe ratatui interop, so `ratatui` stays a direct dep for
# the widget code while `tuika` owns the layout/host/event loop.
tui = ["cli", "dep:tuika", "tuika/async", "dep:ratatui", "tokio/io-util"]

[dependencies]
# Async runtime
Expand Down Expand Up @@ -75,9 +78,15 @@ futures-util = { version = "0.3", default-features = false, features = ["sink",
async-stream = "0.3"
thiserror = "2.0"

# TUI
# TUI. `tuika` is a composable terminal UI toolkit over ratatui (flexbox
# layout, overlays, focus, alt-screen host, live redraw) that pins ratatui
# 0.30.2; keeping `ratatui = "0.30"` here unifies onto that same version so the
# `Buffer`/`Rect` types line up across the `RatatuiView` interop boundary. The
# host machinery (crossterm, alt-screen, async event loop) now lives inside
# `tuika`; its `async` feature (enabled via the `tui` feature) is what brings in
# the `AsyncRunner`.
ratatui = { version = "0.30", optional = true }
crossterm = { version = "0.29", optional = true }
tuika = { version = "0.4", optional = true }

[dev-dependencies]
tokio-test = "0.4"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ what they use. The defaults (`["cli"]`) give the full binary, so `cargo build`,
| `tokens` | `tokens` module (token counting) | `tiktoken-rs` |
| `server` | `cli` module (axum router, handlers, websockets); implies `tokens` | `axum`, `tower-http` |
| `cli` | the `llmsim` binary; implies `server` | `clap`, `tracing-subscriber` |
| `tui` | `serve --tui` dashboard; implies `cli` | `ratatui`, `crossterm` |
| `tui` | `serve --tui` dashboard; implies `cli` | `tuika`, `ratatui` |

To embed only the core library modules (types, generators, latency,
streaming, stats, scripts) and shed `axum`, `tower-http`, `tiktoken-rs`,
Expand Down
20 changes: 13 additions & 7 deletions specs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ llmsim/
│ │ └── state.rs # Application state (config + stats)
│ ├── tui/ # Terminal UI dashboard
│ │ ├── mod.rs # TUI module entry point
│ │ ├── app.rs # Application state and event loop
│ │ └── ui.rs # Ratatui widget rendering
│ │ ├── app.rs # Application state and tuika host loop
│ │ └── ui.rs # tuika view tree (ratatui widgets via RatatuiView)
│ ├── openai/ # OpenAI API types
│ │ ├── mod.rs
│ │ ├── types.rs
Expand Down Expand Up @@ -129,7 +129,7 @@ them. The features form a chain, each enabling the previous one:
| `tokens` | `tokens` | `tiktoken-rs` |
| `server` | `cli` (router/handlers) + `tokens` | `axum`, `tower-http` (+ axum `ws`) |
| `cli` | binary + `server` | `clap`, `tracing-subscriber` |
| `tui` | `tui` dashboard + `cli` | `ratatui`, `crossterm` |
| `tui` | `tui` dashboard + `cli` | `tuika`, `ratatui` |

`server` implies `tokens` because the handlers count tokens for usage
accounting. `cli` implies `server` because the binary's job is to run the
Expand Down Expand Up @@ -204,7 +204,7 @@ See `specs/anthropic-api.md` for detailed Anthropic API specification.
- **Public modules** (`openai`, `openresponses`, `anthropic`, `generator`, `latency`, `stream`, `responses_stream`, `imagegen`, `image_stream`, `errors`, `stats`): Core library functionality, re-exported from `lib.rs`, always available
- **Token module** (`tokens`): Token counting behind the `tokens` feature (tiktoken-rs)
- **CLI modules** (`cli/*`): Server-specific code, HTTP handlers and configuration, behind the `server` feature
- **TUI modules** (`tui/*`): Optional terminal dashboard behind the `tui` feature, built with Ratatui
- **TUI modules** (`tui/*`): Optional terminal dashboard behind the `tui` feature, built with tuika (flexbox layout, alt-screen host, live redraw) over Ratatui widgets

### API Support

Expand Down Expand Up @@ -245,10 +245,16 @@ Stats are exposed via `/llmsim/stats` endpoint and consumed by the optional TUI

### TUI Module

The `tui` feature enables a real-time terminal dashboard built with [Ratatui](https://ratatui.rs/):
The `tui` feature enables a real-time terminal dashboard built with
[tuika](https://crates.io/crates/tuika) — a composable toolkit over
[Ratatui](https://ratatui.rs/) providing flexbox layout, an alternate-screen
host, focus, and live redraw:

- **app.rs**: Event loop, state management, HTTP polling
- **ui.rs**: Widget layout and rendering (tables, sparklines, bar charts)
- **app.rs**: tuika `AsyncRunner` host loop on the caller's Tokio runtime; the
dashboard state is a plain local value the loop owns, with stats polled inline
on each tick (and on manual `r` refresh)
- **ui.rs**: tuika `Flex` view tree; data panels (tables, sparklines, bar
charts) are Ratatui widgets rendered through `RatatuiView` interop

## Model Profiles

Expand Down
Loading
Loading