Skip to content

Latest commit

 

History

History
353 lines (275 loc) · 14.8 KB

File metadata and controls

353 lines (275 loc) · 14.8 KB

REPL Overview

llammer repl starts an interactive read–eval–print loop for correcting text one line at a time. This document describes the REPL as built: a shared BaseRepl driver parameterised by a ReplRole strategy, the four selectable modes, the exact command set, and — in a clearly marked Planned section — the scaffolding that is present in the source but not yet wired into the running program.

Two facts govern everything below and correct long-standing misconceptions:

  • The REPL is local and single-process. No mode opens a socket; there is no networking anywhere in llammer (std::net / tokio::net do not appear in the source). The agent and customer modes differ from standalone only in prompt labels, colours, and static banner text — the "Customer connected" line is a printed string, not a connection event.
  • Corrections are stateless. Each input line is corrected on its own by pipeline.correct(text); the conversation transcript is recorded only for /history, /save, and /load. It is never fed back into the corrector.

Launch a mode with -m/--mode:

$ llammer repl                     # standalone (default)
$ llammer repl --mode agent
$ llammer repl --mode customer
$ llammer repl --mode rag --index ./index

Logging note. main.rs installs a tracing subscriber that writes to stdout with the default filter llammer=info,…. The agent, customer, and rag launches therefore print a Starting … REPL INFO line before the welcome banner (the standalone path emits none). Set RUST_LOG=off to silence it; the transcripts below omit that line for clarity.


1. What the REPL Does

On each iteration the REPL reads a line with rustyline, decides whether it is a slash-command or text to correct, acts, and loops. Non-command input is passed to the correction pipeline; when auto_correct is on (the default) and the line changes, the REPL prints the original and the corrected form plus a per-word breakdown, then records the turn in the in-memory Conversation.

Because the REPL builds its pipeline with LatticePipelineConfig { language, ..Default::default() }, it uses the same embedded 363-word dictionary as llammer correct and the same default parameters (max_edit_distance = 2, enable_phonetic = true). Corrections are therefore limited to that vocabulary — see the Pipeline Overview for the algorithm and the Correction Model for the theory.


2. Architecture: BaseRepl + ReplRole

The four modes share one loop. BaseRepl (src/repl/base.rs) owns the runtime state and drives the read–eval–print cycle; a ReplRole implementation supplies the mode-specific decisions (prompt, banner, which TurnRole to tag input with, optional system prompt, history styling). This is the strategy pattern: one driver, several interchangeable roles.

REPL architecture: a shared BaseRepl driver parameterised by the ReplRole strategy trait, with StandaloneRole, AgentRole, and CustomerRole riding on BaseRepl and a separate RagRepl placeholder

BaseRepl holds:

Field Type Purpose
config ReplConfig mode, language, address, index_path, history_path, context_window
pipeline LatticeCorrectionPipeline the correction engine
conversation Conversation recorded turns (for /history, /save, /load)
colors Colors the styling scheme (always Colors::default())
auto_correct bool whether input lines are corrected (toggled by /autocorrect)
term console::Term used by /clear to clear the screen

The ReplRole trait (implemented by StandaloneRole, AgentRole, and CustomerRole) provides:

pub trait ReplRole {
    fn prompt(&self, colors: &Colors) -> String;
    fn welcome_title(&self) -> &str;
    fn turn_role_for_input(&self) -> TurnRole { TurnRole::User }
    fn system_prompt(&self) -> Option<String> { None }
    fn extra_help(&self) -> Option<&str> { None }
    fn clear_history_message(&self) -> &str { "Conversation history cleared." }
    fn eof_message(&self) -> &str { "Goodbye!" }
    fn on_connect(&self, colors: &Colors) -> Option<String> { None }
    fn on_disconnect(&self, colors: &Colors) -> Option<String> { None }
    fn echo_label(&self, colors: &Colors) -> Option<String> { None }
    fn history_role(&self, colors: &Colors, role: TurnRole) -> (String, Style);
}

StandaloneRepl, AgentRepl, and CustomerRepl are thin wrappers: each holds a BaseRepl plus its role and delegates run() to BaseRepl::run(&role). The rag mode is the exception — RagRepl is a separate struct with its own loop and its own command enum (see §6).

Why on_connect is not a network event. on_connect/on_disconnect return strings that BaseRepl prints once at start-up and once on /exit. AgentRole returns "Customer connected to chat session"; CustomerRole returns "Connected to support agent". No connection occurs — the roles run in a single local process. The names are aspirational labels for a planned networked mode.


3. The Read–Eval–Print Loop

REPL loop: read a line, parse it as a slash-command or as input, correct input and print the original plus corrected forms, record the turn, and repeat

BaseRepl::run (literate summary of src/repl/base.rs):

  1. Build a rustyline editor: Editor<(), DefaultHistory> with auto_add_history(true). The () helper type means no completer and no highlighter are attached (see §7).
  2. Load history_path if configured; print the welcome banner; print the role's on_connect message if any.
  3. Loop:
    • readline(prompt) — on Ctrl-C print ^C and continue; on Ctrl-D/EOF print the role's eof_message and break.
    • ReplCommand::parse(line) — dispatch a slash-command, or treat the line as Input(text).
    • For Input, call process_input: if auto_correct is on, run pipeline.correct(text); if the result changed, print the [original]/[corrected] lines and the per-word breakdown; then conversation.add_turn(role.turn_role_for_input(), text) and update_correction(...).
  4. On exit, save history_path if configured.

The correction call receives only the current line — the conversation is not passed to correct. This is the concrete meaning of "stateless corrections."


4. Commands

ReplCommand::parse (src/repl/mod.rs) recognises the following in every BaseRepl mode (standalone, agent, customer). Anything not beginning with / is treated as text to correct.

Command Aliases Effect
/help /h, /? Print the command list (help_text()), plus the role's extra_help if any
/exit /quit, /q Leave the REPL (prints the role's disconnect/eof message)
/clear /cls Clear the screen (term.clear_screen()) — it does not clear history
/history Print the recorded conversation turns
/clearhistory Clear the conversation (conversation.clear())
/autocorrect /ac Toggle auto-correction on/off (takes no argument)
/lang <code> /language <code> Set the language tag; prints Language set to: <tag>
/save <path> Write the conversation as JSON to <path>
/load <path> Replace the conversation with JSON read from <path>

There is intentionally no /topics, /topic, /open, /list, /switch, /broadcast, /kick, /reconnect, /status, or /shutdown — those appeared in older documentation but were never implemented. Note that /clear clears the screen, not the conversation; use /clearhistory for the latter, and /autocorrect is a toggle (there is no on/off argument).


5. The BaseRepl Modes

5.1 Standalone (--mode standalone, default)

The basic correction REPL. Prompt > , welcome title "llammer - Grammatical Correction REPL", input tagged TurnRole::User, no echo line, no system prompt.

$ llammer repl
llammer - Grammatical Correction REPL
Language: en-US
Type /help for commands, /exit to quit

> thier problm
  [original] thier problm
[corrected] their problem

  thier → their (confidence: 67%)
  problm → problem (confidence: 67%)
> /exit
Goodbye!

5.2 Agent (--mode agent)

Styled as the agent side of a support chat, but local. Prompt agent> (magenta), title "llammer - Agent Mode REPL". Input is tagged TurnRole::Assistant, the conversation is seeded with the system prompt "You are a helpful customer service agent.", and each corrected message is echoed after a [you] label. /history renders User turns as [customer] and Assistant turns as [you].

$ RUST_LOG=off llammer repl --mode agent
llammer - Agent Mode REPL
Language: en-US
Type /help for commands, /exit to quit

Customer connected to chat session

agent> custmer servce is our priority
  [original] custmer servce is our priority
[corrected] customer service is our priority

  custmer → customer (confidence: 67%)
  servce → service (confidence: 67%)
[you] customer service is our priority
agent> /exit

Customer disconnected from chat session

The banner lines are static text; no customer is connected.

5.3 Customer (--mode customer)

The mirror image, again local. Prompt you> (cyan), title "llammer - Customer Chat", input tagged TurnRole::User, [you] echo. /history renders User as [you] and Assistant as [agent].

$ RUST_LOG=off llammer repl --mode customer
llammer - Customer Chat
Language: en-US
Type /help for commands, /exit to quit

Connected to support agent
Your messages will be spell-checked automatically

you> thier problm
  [original] thier problm
[corrected] their problem

  thier → their (confidence: 67%)
  problm → problem (confidence: 67%)
[you] their problem
you> /exit

Chat session ended

5.4 Comparison

standalone agent customer
Prompt > agent> you>
Input TurnRole User Assistant User
System prompt "helpful … agent"
Echo line [you] … [you] …
Start/exit banner static "Customer connected / disconnected" static "Connected to support agent / Chat session ended"
Networked no no no

6. RAG Mode (Placeholder)

--mode rag runs RagRepl (src/repl/rag.rs), a separate loop that is an explicit demo/placeholder — it corrects the query but does not actually search an index. Prompt query> , title "llammer - RAG Query REPL". Its command set differs from the BaseRepl modes:

Command Aliases Effect
/help /h, /? Print RAG REPL help
/exit /quit, /q Exit
/clear /cls Clear the screen
/load <path> Record an index path (checks it exists; does not load it)
/info Print index info (placeholder)
/topk <n> /k <n> Set the number of results
/autocorrect /ac Toggle query auto-correction
/history Show query history
$ RUST_LOG=off llammer repl --mode rag --index ./index
llammer - RAG Query REPL
Language: en-US, Top-k: 10
Type /help for commands, /exit to quit

query> custmer servce
  [original query] custmer servce
[corrected query] customer service

Searching for: "customer service" (top 10)

No results (index not implemented in demo)

The execute_query method prints "No results (index not implemented in demo)"; the comment in the source reads "in real implementation, would use libgrammstein::rag". For the working, non-interactive retrieval path, use llammer rag query (see the RAG Overview). Wiring the RAG REPL to a real index is a roadmap item.


7. Planned / Not Yet Implemented

The REPL source carries several complete-but-unwired components. They compile and, in some cases, are unit-tested, but nothing invokes them today.

Networking & the wire protocol. src/repl/protocol.rs defines a full newline-delimited-JSON protocol — Message { id, message_type, sender, original_text, text, timestamp, was_corrected, confidence, metadata }, MessageType { Chat, System, Correction, Typing, Connected, Disconnected, Ping, Pong, Error }, and a Protocol handler with encode/decode (version "1.0") — plus unit tests. No code sends or receives a Message. The repl --address <ADDR> flag is parsed and stored in ReplConfig but never read. Networked agent/customer sessions are planned; today those modes are local.

Tab completion & syntax highlighting. ReplCompleter (src/repl/completer.rs) and ReplHighlighter (src/repl/highlighter.rs) are implemented and exported, but the editors are constructed as Editor<(), DefaultHistory> — the () helper means neither is attached. Pressing Tab does not complete, and input is not syntax-highlighted.

Context-aware correction. The conversation is recorded but never fed back into correct. llammer-pipeline provides LatticeContextualCorrector, but it is not used by any REPL, and even when used it only reweights confidence rather than changing the selected correction. See Contextual Correction.

Selectable colour schemes. Colors::minimal() (accessibility) and Colors::high_contrast() are defined but never selected — every mode uses Colors::default(). There is no flag to choose a scheme.

All of these are catalogued, with the code that would need wiring, in the Roadmap.


8. A Note on Correction Quality

Because the REPL uses the embedded 363-word dictionary and no active language model, some corrections are surprising (for example helo → help rather than hello, or thnak yuo → thank do). Edit-distance ties are currently broken without linguistic context; the planned language-model reranking layer is what would prefer hello over help or you over do. This is honest as-built behaviour — see the Correction Model and the Roadmap.


See Also