Files
meow/AGENTS.md
T
MangoFanFanw ebc20e0013 fix: SSE line buffering, provider trait plumbing, streaming safety, session resume, code block boxes, markdown improvements
Bug fixes:
- Fix SSE chunk parsing: buffer partial lines across network boundaries (openai.rs)
- Use Arc<dyn Provider> so send_message calls through the trait and reuses the HTTP connection pool, instead of hardcoding OpenAICompatibleProvider per request (app.rs)
- Fix Ctrl+Q during streaming: persist partial response before quitting (app.rs)
- Fix Ctrl+N duplicate JSONL messages: remove redundant save_current_session call and guard against new session while streaming (app.rs)
- Fix code block content never rendered: text was accumulated into the wrong variable (markdown.rs)
- Fix status bar stuck on 'Loading models...' after closing model selector (app.rs)
- Fix CJK character panic in session title truncation: use char-level slicing (storage.rs)

New features:
- Session resume with Ctrl+O: list, browse, and load past chat sessions (app.rs, storage.rs)
- Code block boxes: full-border rendering (top/left/right/bottom) with solid background for acrylic/transparent terminals (markdown.rs)
- Code blocks fill chat area width with CJK-aware display width padding (markdown.rs, app.rs)
- Markdown: add heading support (H1-H6), strikethrough, fix bold+italic by combining style stack layers (markdown.rs)

Docs:
- Replace CLAUDE.md with AGENTS.md containing repo-specific agent guidance
2026-05-12 23:25:17 +08:00

57 lines
3.0 KiB
Markdown

# Meow - Agent Notes
Rust terminal AI chat client (TUI). Single crate, no workspace.
## Build & Run
```bash
cargo build --release
# binary: target/release/meow
```
No tests, no lint/typecheck tooling configured. Just `cargo build` / `cargo run`.
## Architecture (Single Crate)
| File | Responsibility |
|------|---------------|
| `src/main.rs` | `tokio::main`, event loop (100ms tick), dispatches to `App` |
| `src/app.rs` | State machine: `Chat` / `ModelSelect` / `ProviderConfig`; draws all UI; spawns stream task |
| `src/config.rs` | `Config` / `ProviderConfig`; loads/saves `~/.meow/config.toml` via `dirs` |
| `src/message.rs` | `Role`, `Message`, `ChatSession` with `uuid` + `chrono` |
| `src/storage.rs` | JSON Lines persistence at `~/.meow/data/sessions/<uuid>.jsonl` |
| `src/providers/mod.rs` | `Provider` trait (`async_trait`), `Model`, `ProviderError` |
| `src/providers/openai.rs` | `OpenAICompatibleProvider`: `/v1/models`, `/v1/chat/completions` SSE |
| `src/tui/mod.rs` | `Tui`: raw mode, alternate screen, mouse capture, panic hook restore |
| `src/tui/input.rs` | Multi-line `InputState` with cursor movement; `Shift+Enter` newline, `Enter` submit |
| `src/tui/markdown.rs` | `pulldown-cmark``ratatui::Line` + `syntect` highlighting (`base16-ocean.dark`) |
## Key Conventions
- **Streaming protocol**: `Provider::chat_stream` returns `BoxStream<Result<String>>`. The spawned tokio task sends chunks through an `mpsc::unbounded_channel`. Sentinel `__STREAM_END__` marks completion; `App::poll_stream()` drains the channel on each tick.
- **Provider rebuild**: After saving config, `App::rebuild_providers()` reconstructs the `Vec<Box<dyn Provider>>` from `config.providers`. Always call this after mutating providers.
- **First-run behavior**: If `config.providers` is empty, app boots into `ProviderConfig` state. `Esc` in that state quits the app instead of returning to chat.
- **Ctrl+C while streaming**: Stops stream and calls `finish_stream_message()` to persist partial response. Do NOT treat as app quit during streaming.
- **Session persistence**: `Storage::append_message` is append-only JSON Lines. `save_current_session()` iterates messages and appends each (safe to call multiple times; duplicates are harmless in current design).
- **Syntax highlighting**: `syntect` uses `regex-fancy` backend (not `onig`). Theme hardcoded to `base16-ocean.dark`.
## Runtime Data Paths
- Config: `~/.meow/config.toml`
- Sessions: `~/.meow/data/sessions/<uuid>.jsonl`
## Dependencies to Know
- `reqwest` with `rustls-tls`, `stream` — SSE via `bytes_stream()`
- `ratatui` 0.29 + `crossterm` 0.28 — all TUI rendering
- `syntect` with `default-themes`, `default-syntaxes`, `regex-fancy`
- `pulldown-cmark` 0.12 — markdown parser
## Adding a New Provider
Only `OpenAICompatibleProvider` exists. To add a non-OpenAI provider:
1. Implement `Provider` trait in `src/providers/<name>.rs`
2. Register in `src/providers/mod.rs`
3. Wire instantiation in `App::new()` and `App::rebuild_providers()`