pub struct App {Show 78 fields
pub db: Db,
pub space: Space,
pub backends: Backends,
pub saved: SavedCreds,
pub active_space: Space,
pub memory_model: String,
pub transcriber_model: String,
pub ocr_model: String,
pub ocr_engine: String,
pub local_ocr_model: String,
pub embedding_model: String,
pub image_gen_model: String,
pub video_gen_model: String,
pub searxng_url: String,
pub langsearch_key: String,
pub search_provider: String,
pub base_system_prompt: String,
pub verbosity: String,
pub memory_rx: Option<UnboundedReceiver<(String, Vec<MemoryOp>)>>,
pub compact_rx: Option<UnboundedReceiver<(String, String, i64, u64)>>,
pub compacting_session_id: Option<String>,
pub skills: Vec<Skill>,
pub forced_skill: Option<String>,
pub web_mode: bool,
pub incognito: bool,
pub incognito_img_dir: Option<PathBuf>,
pub survey_gate: Option<SurveyGate>,
pub survey_reply_tx: Option<UnboundedSender<String>>,
pub research_steer_log: Vec<(usize, String)>,
pub research_steer_acked: HashSet<usize>,
pub research_stage_rows: Vec<String>,
pub research_incognito: bool,
pub research_steer_tx: Option<UnboundedSender<String>>,
pub research_topic_rx: Option<UnboundedReceiver<Result<String, String>>>,
pub research_live_input: String,
pub toolbox: Arc<dyn ToolExecutor>,
pub app_server: Option<AppServer>,
pub skills_rx: Option<UnboundedReceiver<Result<String, String>>>,
pub ocr_rx: Option<UnboundedReceiver<(String, String, OcrUpdate)>>,
pub embed_rx: Option<UnboundedReceiver<EmbedMsg>>,
pub ocr_pull_rx: Option<UnboundedReceiver<Result<String, String>>>,
pub research_rx: Option<UnboundedReceiver<ResearchMsg>>,
pub research_abort: Option<AbortHandle>,
pub login_rx: Option<UnboundedReceiver<LoginMsg>>,
pub update_rx: Option<UnboundedReceiver<Option<String>>>,
pub swarm_rx: Option<UnboundedReceiver<(String, SwarmUpdate)>>,
pub swarm_abort: Option<AbortHandle>,
pub swarm_session: Option<String>,
pub swarm_cache: Vec<Persona>,
pub research_running: Option<(String, String)>,
pub files_cache: Vec<FileRow>,
pub apps_cache: Vec<String>,
pub images_cache: Vec<ImageMeta>,
pub scripts_cache: Vec<ScriptMeta>,
pub watches_cache: Vec<Watch>,
pub usage_range: UsageRange,
pub models: Vec<Model>,
pub current_model: Option<String>,
pub models_rx: Option<UnboundedReceiver<Result<Vec<Model>, String>>>,
pub favorites: HashSet<String>,
pub last_used: HashMap<String, String>,
pub reasoning: HashMap<String, String>,
pub session: Option<Session>,
pub messages: Vec<Message>,
pub chat_event_tx: UnboundedSender<ChatEvent>,
pub chat_event_rx: UnboundedReceiver<ChatEvent>,
pub chat_tasks: HashMap<ChatTaskId, ChatTask>,
pub next_chat_task_id: ChatTaskId,
pub notifications: VecDeque<ChatNotification>,
pub unread: HashSet<String>,
pub context_total: Option<u64>,
pub last_cache_rate: Option<f64>,
pub settings: Settings,
pub model_pick_target: ModelPickTarget,
pub spinner_frame: usize,
pub thinking_idx: usize,
pub spinner_color: SpinnerColor,
pub sessions_cache: Vec<Session>,
/* private fields */
}Fields§
§db: Db§space: Space§backends: BackendsEvery backend currently logged into. /model merges all of their
catalogs into one list; picking a model resolves back to the right
one here.
saved: SavedCredsEvery credential configured on disk, kept in sync with backends.
active_space: SpaceThe space the current/next session belongs to.
memory_model: StringModel used for background memory extraction (empty = disabled).
transcriber_model: StringModel used for image transcription (empty = disabled).
ocr_model: StringVision model for scanned-PDF OCR (empty = tesseract only).
ocr_engine: StringOCR engine choice: “auto” (vlm when ocr_model set), “tesseract”,
“vlm”, or “local” (Ollama on 127.0.0.1:11434, set up by cycling to it in /config).
local_ocr_model: StringOllama model name for the “local” OCR engine.
embedding_model: StringEmbedding model for semantic file search (empty = keyword FTS only).
image_gen_model: StringModel used for AI image generation (empty = disabled).
video_gen_model: StringModel used for AI video generation (empty = disabled).
searxng_url: StringBase URL of a SearXNG instance for the web-search tool, or empty to
disable it. Configured in-app (Ctrl+O settings), not a config file.
langsearch_key: StringLangSearch API key (free tier), or empty to disable it.
search_provider: StringWhich web-search backend to prefer: “auto”/“langsearch”/“searxng”/“duckduckgo”.
base_system_prompt: StringRaw contents of system_prompt.md (with an unresolved {{verbosity}}
placeholder) — the app’s own base system prompt, $EDITOR-editable.
verbosity: StringAnswer-length preference woven into the system prompt: “normal”, “concise” (default), or “caveman”.
memory_rx: Option<UnboundedReceiver<(String, Vec<MemoryOp>)>>§compact_rx: Option<UnboundedReceiver<(String, String, i64, u64)>>Background compaction result: (session id, digest, messages-covered, pre-compaction %).
compacting_session_id: Option<String>Session currently being compacted. Kept separately from compact_rx so
the TUI can mark the right row while the job is still in flight.
skills: Vec<Skill>Discovered skills (name/description only — bodies are read from disk on invocation, so this list is cheap and reloaded whenever it changes).
forced_skill: Option<String>A skill armed by /<skill-name>, injected into the next message only.
web_mode: bool/web answer mode for the active session (or the next one created).
incognito: bool§incognito_img_dir: Option<PathBuf>Temp directory for incognito image files, cleaned up on toggle.
survey_gate: Option<SurveyGate>A parked conversation’s chat-reply gate (clarifying questions or an approval) — armed only while a reply is actually pending, so a gate in another session can never swallow typing.
survey_reply_tx: Option<UnboundedSender<String>>Sender half of the reply channel into a parked gate. Created at the owning job’s start; the gate itself arms/disarms as pending-section updates arrive.
research_steer_log: Vec<(usize, String)>Every /steer queued during the current job, as (queue position, text) — position 1-based, assigned in queue order. Entries are
dropped once the pipeline acknowledges them (research_steer_acked),
and the whole log is cleared when the job stops or its channel
closes, so retained steer text stays bounded per job.
research_steer_acked: HashSet<usize>Steer positions (steer #N) the pipeline has drained and persisted —
parsed from Stage updates in on_research_done, so the live popup
knows what’s picked up even when opened from another session, and the
retained log can drop acknowledged entries.
research_stage_rows: Vec<String>The running job’s stage rows (label: detail content strings), kept
in sync by mirror_stage regardless of which session is viewed — the
live popup renders from here instead of re-reading the db per frame.
research_incognito: boolIncognito mode captured when the job started: artifact persistence
(plan files, and the plan message itself, which folds in survey
replies) is decided by this, never by toggling incognito mid-job.
research_steer_tx: Option<UnboundedSender<String>>Queues /steer instructions into the currently running research job’s
round-boundary check. None when no research job is running.
research_topic_rx: Option<UnboundedReceiver<Result<String, String>>>In-progress /research (no args) topic distillation from recent chat.
research_live_input: StringComposer buffer for the live research-activity view’s steer input.
toolbox: Arc<dyn ToolExecutor>§app_server: Option<AppServer>Local static server for model-created apps (None if it failed to bind).
skills_rx: Option<UnboundedReceiver<Result<String, String>>>§ocr_rx: Option<UnboundedReceiver<(String, String, OcrUpdate)>>Background OCR updates: (space_id, file name, progress or final result).
embed_rx: Option<UnboundedReceiver<EmbedMsg>>One in-flight chunk-embedding job: (space id, file id, vectors or error).
ocr_pull_rx: Option<UnboundedReceiver<Result<String, String>>>A running local-OCR-model pull: model name on success, error text on failure.
research_rx: Option<UnboundedReceiver<ResearchMsg>>A running /research job’s channel and cancellation handle.
research_abort: Option<AbortHandle>§login_rx: Option<UnboundedReceiver<LoginMsg>>§update_rx: Option<UnboundedReceiver<Option<String>>>Startup update check result (newest published version, or None on failure).
swarm_rx: Option<UnboundedReceiver<(String, SwarmUpdate)>>A running /swarm discussion’s channel, cancellation handle, and
origin session id (used for targeting the correct progress row).
swarm_abort: Option<AbortHandle>§swarm_session: Option<String>§swarm_cache: Vec<Persona>The active session’s /swarm roster, cached for the popup (kept in
sync by on_swarm_update while a turn runs; the view owns the cursor).
research_running: Option<(String, String)>(session id, topic) of the /research job currently running, if any —
cleared when its channel closes.
files_cache: Vec<FileRow>The active space’s imported files (refreshed by rescan_files).
apps_cache: Vec<String>The space’s apps (/apps popup): names, cursor, and mode.
images_cache: Vec<ImageMeta>The space’s images (/image popup): cache and cursor.
scripts_cache: Vec<ScriptMeta>The space’s scripts (/script popup): cache, cursor, and edit buffer.
watches_cache: Vec<Watch>The space’s standing research watches (/watch picker): cache + cursor.
usage_range: UsageRangeTime window the /usage dashboard aggregates (24h/7d/30d/all) — a
persisted preference, applied by apply_setting on load.
models: Vec<Model>Live model catalog (fetched on demand, never hardcoded).
current_model: Option<String>§models_rx: Option<UnboundedReceiver<Result<Vec<Model>, String>>>§favorites: HashSet<String>Model ids marked favorite, and when each model was last used (rfc3339).
last_used: HashMap<String, String>§reasoning: HashMap<String, String>Per-model reasoning effort (wire string from ReasoningEffort::as_str,
e.g. “minimal” / “low” / “high” / “xhigh” / “max” / “none”).
session: Option<Session>§messages: Vec<Message>§chat_event_tx: UnboundedSender<ChatEvent>Central event channel for all in-flight chat tasks.
chat_event_rx: UnboundedReceiver<ChatEvent>§chat_tasks: HashMap<ChatTaskId, ChatTask>§next_chat_task_id: ChatTaskId§notifications: VecDeque<ChatNotification>Completed task notifications, kept independently of the one-line status.
unread: HashSet<String>Sessions holding a response that finished while the user was elsewhere.
context_total: Option<u64>Exact conversation token total from the last completed response.
last_cache_rate: Option<f64>Cache hit rate of the most recent completed request (0..=1), shown
next to the context window. Transient — not persisted here; the
per-request numbers live in usage_log.
settings: Settings§model_pick_target: ModelPickTargetWhat a confirmed model-picker selection is currently for (the active
session’s model, a feature model from /config, or a swarm persona).
spinner_frame: usizeAnimated “thinking” indicator shown while a response streams.
thinking_idx: usize§spinner_color: SpinnerColor§sessions_cache: Vec<Session>Implementations§
Source§impl App
impl App
Sourcepub fn send_message(&mut self, text: String) -> Result<()>
pub fn send_message(&mut self, text: String) -> Result<()>
Send one chat message. AppView::submit is the composer front — it
reads the TextArea and routes through run_command / Send — so this
is the domain half: validation, session auto-creation, persistence.
Sourcepub fn build_history(&mut self) -> Vec<ChatMessage>
pub fn build_history(&mut self) -> Vec<ChatMessage>
The exact message list a completion request will carry: system prompt, compaction digest, forced skill, then the effective conversation tail. User messages with images become multimodal parts for vision models, or get their stored descriptions appended as text for everything else.
Sourcepub fn start_stream(&mut self) -> Result<()>
pub fn start_stream(&mut self) -> Result<()>
Build history and fire one independently-routed streaming request.
pub fn on_chat_event( &mut self, task_id: ChatTaskId, ev: StreamEvent, ) -> Result<()>
Sourcepub fn cancel_chat_task(&mut self, task_id: ChatTaskId) -> Result<()>
pub fn cancel_chat_task(&mut self, task_id: ChatTaskId) -> Result<()>
Cancel one in-flight chat task by id (kills any in-flight request and tool loop) and keep whatever text already arrived.
Sourcepub fn stop_stream(&mut self) -> Result<()>
pub fn stop_stream(&mut self) -> Result<()>
Esc while a response streams: abort the background chat task (kills any in-flight request and tool loop) and keep whatever text already arrived.
pub fn discard_chat_task(&mut self, session_id: &str)
Sourcepub fn maybe_generate_title(&mut self)
pub fn maybe_generate_title(&mut self)
After the first exchange of a session, ask the model for a short topic and
slug in the background. Runs once per session (guarded by slug.is_none()).
Sourcepub fn on_title_result(&mut self, result: Option<(String, String, String)>)
pub fn on_title_result(&mut self, result: Option<(String, String, String)>)
Apply a generated topic/slug to the matching session (in memory + db).
Sourcepub fn system_prompt(&self) -> String
pub fn system_prompt(&self) -> String
Instructions + the active session’s memory snapshot, combined into one
system message. The full system prompt puts the app’s own base prompt
(identity/formatting rules, $EDITOR-editable) first, then space
instructions, skills, and the frozen memory snapshot layered on top.
Unlike those three, the base prompt is never empty — it’s the app
speaking, not per-space configuration.
Sourcepub fn open_session_link(&mut self, owner: Option<usize>)
pub fn open_session_link(&mut self, owner: Option<usize>)
o in the history pane: open the [n] citation under the current
text selection (via the open crate), resolved against the Sources
list of the message the selection belongs to. Every miss surfaces as
a status message rather than doing nothing silently.
owner is the message index at the selection start, computed by the
view layer from its HistorySel state.
Ctrl+O: navigate to the session linked in a session_link message
under the text selection. Expects the message content’s first line to
be the target session id.
Sourcepub fn flag_source_under_selection(
&mut self,
flag: Option<&str>,
selected: Option<String>,
owner: Option<usize>,
)
pub fn flag_source_under_selection( &mut self, flag: Option<&str>, selected: Option<String>, owner: Option<usize>, )
Pin or discard the [n] source under the current history selection
(same selection→citation resolution as open_citation_under_selection).
Flags are keyed by the message’s normalized URL, session-scoped.
selected/owner come from the view’s HistorySel state.
Sourcepub fn toggle_web_mode(&mut self)
pub fn toggle_web_mode(&mut self)
/web: flip web answer mode for the active (or about-to-be-created)
session. Persisted immediately if a session already exists; otherwise
applied to the session created by the next message.
pub fn toggle_incognito(&mut self) -> Result<()>
Sourcepub fn resolved_base_system_prompt(&self) -> String
pub fn resolved_base_system_prompt(&self) -> String
base_system_prompt (raw, as read from system_prompt.md) with the
{{verbosity}} placeholder swapped for the level the user picked.
Sourcepub fn reload_base_system_prompt(&mut self)
pub fn reload_base_system_prompt(&mut self)
Re-read system_prompt.md after a Ctrl+E hand-edit.
Source§impl App
impl App
Sourcepub fn parse_command(&self, cmd: &str) -> Result<AppCommand, String>
pub fn parse_command(&self, cmd: &str) -> Result<AppCommand, String>
Parse a /-command line (without the leading slash) into the command
seam. Resolves aliases via the COMMANDS catalog and recognizes
/<skill-name> arms. Err carries a status-line message for unknown
commands — the TUI shows it without failing the key handler.
Sourcepub fn execute(&mut self, cmd: AppCommand) -> Result<()>
pub fn execute(&mut self, cmd: AppCommand) -> Result<()>
Run one parsed command — the mutation path for domain intents. The
TUI’s AppView::execute intercepts the view-only commands (quit,
popup opens, the watch picker) before delegating here; headless
consumers only ever send domain commands. run_command is the
/-string parse front.
Sourcepub fn run_command(&mut self, cmd: &str) -> Result<()>
pub fn run_command(&mut self, cmd: &str) -> Result<()>
The /-string front: parse into the seam, then execute. Unknown
commands surface as a status line rather than an error.
Source§impl App
impl App
Sourcepub fn excluded_from_model_history(m: &Message) -> bool
pub fn excluded_from_model_history(m: &Message) -> bool
Rows that must never reach a model — neither in the raw history
(build_history) nor in a compaction digest: background-job scratch
(research stage/plan/survey rows), transport failures, session links,
per-persona swarm round replies (the turn’s synthesis carries the
context), gate replies — the survey/plan sections they answer are
excluded too, so a bare “drop Q2” must not leak into later turns via
a digest — and the compaction digest row itself (the digest is
already fed to the model via compact_summary, so a transcript row
must never be sent twice).
Sourcepub fn effective_messages(&self) -> &[Message]
pub fn effective_messages(&self) -> &[Message]
The messages actually sent on the next turn: everything after the
session’s compaction boundary, or all of them if it hasn’t compacted
(yet). The full, uncompacted history stays in self.messages/the db
for scrollback — only what’s sent shrinks.
Sourcepub fn is_compacting_session(&self, id: &str) -> bool
pub fn is_compacting_session(&self, id: &str) -> bool
Whether id is the session whose background compaction is still running.
Sourcepub fn is_compacting_current_session(&self) -> bool
pub fn is_compacting_current_session(&self) -> bool
Whether the session currently on screen is being compacted.
Sourcepub fn maybe_compact(&mut self)
pub fn maybe_compact(&mut self)
After a reply, auto-compact once context usage crosses the configured threshold (0 disables it).
Sourcepub fn force_compact(&mut self)
pub fn force_compact(&mut self)
Manually trigger compaction right now (/compact), ignoring the
threshold. No-ops with a status message if there’s nothing to compact.
Sourcepub fn on_compact_result(&mut self, result: Option<(String, String, i64, u64)>)
pub fn on_compact_result(&mut self, result: Option<(String, String, i64, u64)>)
Apply a compaction digest to the matching session (in memory + db):
the digest itself becomes a visible compaction transcript row at the
compaction boundary, so what was folded away is shown in the chat
instead of being reachable only through the context popup’s editor.
A later compaction updates that row in place (one digest row per
session, at the same boundary). Clears the exact usage total — it
reflects the pre-compaction request, so context_used should fall
back to the (now accurate) estimate until the next real response
reports fresh usage.
Sourcepub fn backfill_compaction_row(&mut self)
pub fn backfill_compaction_row(&mut self)
Sessions compacted before compaction rows existed (or loaded from a
db written by such a version) carry the digest only in
compact_summary. Surface it as a transcript row at the boundary,
exactly like a fresh compaction would, so the digest is never hidden
behind the context popup. Idempotent: no-ops once a compaction row
exists. Called after every session load.
Sourcepub fn context_breakdown(&self) -> ContextBreakdown
pub fn context_breakdown(&self) -> ContextBreakdown
System/memory/conversation token estimate for the context breakdown
popup (Ctrl+I). Each bucket is a ~4-chars/token estimate, same method
context_used falls back to, so the parts add up to (roughly) the whole.
Sourcepub fn compact_summary_path(&self) -> Option<PathBuf>
pub fn compact_summary_path(&self) -> Option<PathBuf>
Path to a temp file holding the active session’s compaction digest, so
it can be viewed/edited in $EDITOR from the context popup (Ctrl+G, v).
None if the session hasn’t been compacted yet.
Sourcepub fn reload_compact_summary(&mut self, path: &Path) -> Result<()>
pub fn reload_compact_summary(&mut self, path: &Path) -> Result<()>
Read path (from compact_summary_path) back after $EDITOR closes —
hand-edits to the digest persist (db + in-memory), same as any other
file-backed edit in the app.
Source§impl App
impl App
Sourcepub fn export_report(&mut self) -> Result<()>
pub fn export_report(&mut self) -> Result<()>
/export: write the active session’s latest research report (the
most recent assistant message) plus its citations to
<space>/files/reports/<session-slug>.md, overwriting any earlier
export of the same session. No-op with a status message if the
session has no research report yet.
Source§impl App
impl App
Sourcepub fn rescan_files(&mut self)
pub fn rescan_files(&mut self)
Sync the active space’s files directory with the db: new or changed
files (by sha256) are re-extracted and re-indexed, rows for deleted
files are dropped, and files_cache is refreshed. Best-effort: a
single bad file gets an “error: …” status instead of failing the scan.
ponytail: runs synchronously on the UI task — extraction of a huge PDF
blocks a beat; move to a blocking task if that ever hurts.
Sourcepub fn start_ocr(&mut self, jobs: Vec<(String, String, PathBuf)>)
pub fn start_ocr(&mut self, jobs: Vec<(String, String, PathBuf)>)
OCR queued scanned PDFs sequentially off the UI thread. One batch at a time: jobs arriving while a batch runs stay at “ocr…” and re-queue on a later rescan.
Sourcepub fn ocr_backend(&self) -> Option<OcrBackend>
pub fn ocr_backend(&self) -> Option<OcrBackend>
The vision backend scanned PDFs OCR through, or None for tesseract:
“local” → Ollama; “vlm”/“auto” with an OCR model + provider → OpenRouter.
Sourcepub fn ocr_local_install(&mut self, arg: &str)
pub fn ocr_local_install(&mut self, arg: &str)
Cycling the OCR engine to “local” (in /config) pulls a local OCR model through Ollama in the background and switches the engine to it when the pull succeeds. Defaults to glm-ocr (0.9B — the current open OCR benchmark leader).
Sourcepub fn on_ocr_pull(&mut self, r: Option<Result<String, String>>)
pub fn on_ocr_pull(&mut self, r: Option<Result<String, String>>)
The local-OCR-model pull finished: point the OCR engine at the local model.
Sourcepub fn reextract_file(&mut self, name: &str)
pub fn reextract_file(&mut self, name: &str)
The reextract/reocr/delete popup flows live in the view layer;
this is the re-extract half: zero the selected file’s chunks and
hash/size so the next rescan re-indexes from disk.
Sourcepub fn reocr_file(&mut self, name: &str)
pub fn reocr_file(&mut self, name: &str)
The reocr popup flow lives in the view layer; this is the OCR half:
force an OCR pass on one file, bypassing text extraction entirely.
Useful when pdf_extract gives unreliable text and you want VLM OCR
output instead.
Sourcepub fn start_embedding(&mut self)
pub fn start_embedding(&mut self)
Embed the next imported file whose chunks lack vectors, one file per job (the done-handler chains the next). Files with no extractable text receive a small filename metadata chunk so they are still searchable. No-op without a provider, without an embedding model, or while a job is already in flight.
Sourcepub fn on_embed_done(&mut self, r: Option<EmbedMsg>)
pub fn on_embed_done(&mut self, r: Option<EmbedMsg>)
One embedding job finished: store vectors and chain the next file, or surface the error and stop (a dead endpoint shouldn’t be hammered — the next rescan retries). Search falls back to keywords while vectors are missing.
Sourcepub fn on_ocr_done(&mut self, r: Option<(String, String, OcrUpdate)>)
pub fn on_ocr_done(&mut self, r: Option<(String, String, OcrUpdate)>)
A finished OCR job: persist chunks/status, refresh the cache only if the
file’s space is still active. None = batch done (channel closed).
Sourcepub fn import_file(&mut self, path: &Path) -> Result<String>
pub fn import_file(&mut self, path: &Path) -> Result<String>
Copy path into the active space’s files dir and index it. Returns
the imported file’s name. An existing file with the same name is
overwritten (the rescan re-extracts it).
Sourcepub fn delete_file(&mut self, name: &str) -> Result<()>
pub fn delete_file(&mut self, name: &str) -> Result<()>
Domain half of the files popup’s delete: remove the disk copy and index rows, refresh the cache. The view owns the mode/selection state.
Sourcepub fn rename_file(&mut self, name: &str, new: &str) -> Result<()>
pub fn rename_file(&mut self, name: &str, new: &str) -> Result<()>
Domain half of the files popup’s rename: move the file on disk; the rescan swaps the index rows (old name dropped, new name re-extracted). Returns an error message string when the target already exists or the name is invalid; the view turns it into a status line.
Source§impl App
impl App
Sourcepub fn switch_space_cli(&mut self, name: &str) -> Result<()>
pub fn switch_space_cli(&mut self, name: &str) -> Result<()>
Switch the active space by name (--space). Bails on an unknown
name; no-op when it’s already the active space.
Sourcepub async fn run_turn(
&mut self,
prompt: String,
opts: TurnOpts,
) -> Result<(String, Option<Usage>)>
pub async fn run_turn( &mut self, prompt: String, opts: TurnOpts, ) -> Result<(String, Option<Usage>)>
Drive one non-interactive turn: send prompt, drain stream events
until the response finishes, and (unless opts.stream) collect the
answer. Tool status lines and the token summary go to stderr unless
opts.quiet. Returns the final answer text and merged usage.
Sourcepub async fn ask_headless(
&mut self,
prompt: String,
opts: TurnOpts,
) -> Result<AskOutcome>
pub async fn ask_headless( &mut self, prompt: String, opts: TurnOpts, ) -> Result<AskOutcome>
nexus ask: one turn, then a short wait for the model-generated
session title so nexus sessions shows a real name instead of the
prompt prefix. A slow title must never hold the ask hostage — capped.
Sourcepub async fn chat_headless(&mut self, quiet: bool) -> Result<()>
pub async fn chat_headless(&mut self, quiet: bool) -> Result<()>
nexus chat: a bare REPL — prompt on stderr, one turn per line,
all turns in the one session the first turn creates.
Sourcepub async fn research_headless(
&mut self,
topic: String,
approve: bool,
opts: TurnOpts,
) -> Result<ResearchOutcome>
pub async fn research_headless( &mut self, topic: String, approve: bool, opts: TurnOpts, ) -> Result<ResearchOutcome>
nexus research <topic>: run the full deep-research pipeline headless.
Gate policy: with approve the pipeline runs ungated (survey and
plan-approval are skipped entirely, like /research!). Without it,
a gated run parks at each SurveyReady/PlanReady: when stdin is a
terminal the prompt is printed and a reply is read from the line
(empty reply skips the survey round; approve approves the plan);
otherwise the run bails rather than hang.
Sourcepub async fn watch_run_headless(
&mut self,
watch_ref: Option<&str>,
all: bool,
quiet: bool,
) -> Result<Vec<(String, ResearchOutcome)>>
pub async fn watch_run_headless( &mut self, watch_ref: Option<&str>, all: bool, quiet: bool, ) -> Result<Vec<(String, ResearchOutcome)>>
nexus watch run: run one watch (by id or topic prefix), all watches
(--all), or the due ones (default). Each run drives its research
job to completion before the next starts. Returns the reports, keyed
by watch topic, for the caller to print.
Source§impl App
impl App
Sourcepub fn refresh_images(&mut self)
pub fn refresh_images(&mut self)
Read the space’s images dir and populate images_cache (name, size,
modified) with image files only — the Files tab owns everything
else. A missing or empty dir produces an empty cache, never an error.
Sourcepub fn delete_image_file(&mut self, name: &str) -> Result<bool>
pub fn delete_image_file(&mut self, name: &str) -> Result<bool>
The popup’s confirm-delete lives in the view; this is the disk half:
remove the file (if any) and refresh the cache. Returns whether a row
existed. images_mode reset is the view’s job.
Source§impl App
impl App
Sourcepub fn read_memory(&self) -> String
pub fn read_memory(&self) -> String
Raw contents of the active space’s memory file, capped to ~120k chars (~30k tokens — headroom is cheap on 1M-context models; this just stops a runaway file from eating the whole budget).
Sourcepub fn refresh_memory_snapshot(&mut self)
pub fn refresh_memory_snapshot(&mut self)
Reload the active session’s memory snapshot and begin a new prompt-cache epoch. New inferred facts normally do not call this while a session is active; switching sessions or an explicit refresh does.
Sourcepub fn memory_snapshot(&self) -> &str
pub fn memory_snapshot(&self) -> &str
Return the memory text that is stable for the active cache epoch.
Sourcepub fn maybe_extract_memory(&mut self)
pub fn maybe_extract_memory(&mut self)
After an assistant reply, ask the memory model for ADD/UPDATE/DELETE ops against the space’s fact file. No-op if extraction is disabled or the last exchange is unavailable.
Source§impl App
impl App
Sourcepub fn rebuild_all_backends(&mut self)
pub fn rebuild_all_backends(&mut self)
Rebuild every backend from the on-disk saved credentials (after boot,
or after a settings change). Keeps saved and backends in sync.
pub fn resolve_model_backend(&self, id: &str) -> Option<(OpenRouter, String)>
Sourcepub fn resolve_utility_model_backend(
&self,
configured_id: &str,
) -> Option<(OpenRouter, String)>
pub fn resolve_utility_model_backend( &self, configured_id: &str, ) -> Option<(OpenRouter, String)>
Resolve a feature (non-session) model that may be a bare wire id or a composite id. Feature models default to the session provider’s research-class default; a composite id picks its own backend.
Sourcepub fn resolve_feature_model_backend(
&self,
configured_id: &str,
default: fn(&OpenRouter) -> &'static str,
) -> Option<(OpenRouter, String)>
pub fn resolve_feature_model_backend( &self, configured_id: &str, default: fn(&OpenRouter) -> &'static str, ) -> Option<(OpenRouter, String)>
Resolve a feature model by name for a backend that may not be
OpenRouter (used for image/video gen where the user may have picked a
non-OpenRouter model).
Sourcepub fn fetch_models(&mut self)
pub fn fetch_models(&mut self)
Fetch every configured backend’s catalog concurrently and merge them into one list. A backend that fails is dropped from the merge (its error is only surfaced if every backend failed) — one flaky login shouldn’t blank out the models of the others. Public so the view layer can re-trigger a fetch from the model picker.
Sourcepub fn context_limit(&self) -> Option<u64>
pub fn context_limit(&self) -> Option<u64>
Context window of the active model, if known.
Sourcepub fn context_used(&self) -> u64
pub fn context_used(&self) -> u64
Tokens used by the current session. Exact (from the provider’s usage on the last response) when idle; a ~4-chars/token estimate while streaming or before the first response. Estimate is what would actually be sent — system/memory prompt, the compaction digest (if any), and only the tail after it, not the full (possibly much larger) on-screen scrollback.
Sourcepub fn current_model_supports_images(&self) -> bool
pub fn current_model_supports_images(&self) -> bool
Whether the active model accepts image input (unknown model → false).
pub fn reasoning_of(&self, id: &str) -> Option<&str>
Sourcepub fn effort_accepted(&self, model: &str, effort: &str) -> bool
pub fn effort_accepted(&self, model: &str, effort: &str) -> bool
Whether effort is in model’s accepted reasoning set, so a stored
value is only sent when the model actually accepts it. Unknown models
(not in the loaded catalog) accept anything — never silently drop a
stored value just because the catalog isn’t fetched yet.
Sourcepub fn pick_model(&mut self, id: &str) -> Result<()>
pub fn pick_model(&mut self, id: &str) -> Result<()>
Set the active model (or a feature model, per the pick target). The view layer owns the popup routing; this is the domain half.
Sourcepub fn popup_after_pick(target: ModelPickTarget) -> Popup
pub fn popup_after_pick(target: ModelPickTarget) -> Popup
The popup a confirmed pick should return to, given the pick target —
view-layer helper (the picker opens from /config for feature models).
Sourcepub fn clear_memory_model(&mut self) -> Result<()>
pub fn clear_memory_model(&mut self) -> Result<()>
Disable memory extraction entirely (Backspace on the memory-model row
in /config).
Sourcepub fn clear_transcriber_model(&mut self) -> Result<()>
pub fn clear_transcriber_model(&mut self) -> Result<()>
Disable image transcription entirely (Backspace on the
transcriber-model row in /config).
Sourcepub fn clear_ocr_model(&mut self) -> Result<()>
pub fn clear_ocr_model(&mut self) -> Result<()>
Disable VLM OCR (Backspace on the OCR-model row in /config).
Sourcepub fn clear_image_gen_model(&mut self) -> Result<()>
pub fn clear_image_gen_model(&mut self) -> Result<()>
Disable image generation (Backspace on the image gen model row in /config).
Sourcepub fn clear_video_gen_model(&mut self) -> Result<()>
pub fn clear_video_gen_model(&mut self) -> Result<()>
Disable video generation (Backspace on the video gen model row in /config).
Sourcepub fn start_codex_login(&mut self)
pub fn start_codex_login(&mut self)
/login: start the OpenAI Codex device-code login (the only backend
without a plain API key). Domain side: spawns the task and owns the
result channel; the view layer shows the selector.
pub fn on_login_result(&mut self, msg: Option<LoginMsg>)
Source§impl App
impl App
Sourcepub fn start_research(&mut self, topic: &str)
pub fn start_research(&mut self, topic: &str)
/research <topic>: run the multi-agent research pipeline in a new
background session. One job at a time. /research! <topic> skips the
plan-approval gate.
Sourcepub fn steer_research(&mut self, text: &str)
pub fn steer_research(&mut self, text: &str)
/steer <text>: queue an extra instruction for the running research
job, picked up at the next round boundary. No-op with a status message
if no research job is running.
Sourcepub fn start_research_from_chat(&mut self)
pub fn start_research_from_chat(&mut self)
/research with no topic: distill one from the last ~20 chat turns
(one cheap completion, same background-channel shape as
maybe_generate_title) then hand it to start_research_with_gate
exactly as if it had been typed — the existing plan-approval gate
still lets you bail or edit before searchers run.
Sourcepub fn on_research_topic_derived(&mut self, r: Option<Result<String, String>>)
pub fn on_research_topic_derived(&mut self, r: Option<Result<String, String>>)
The topic-distillation job finished: start research with it, or
report the failure. None = channel closed without a result.
pub fn start_research_with_gate(&mut self, topic: &str, gated: bool)
Sourcepub fn stop_research(&mut self)
pub fn stop_research(&mut self)
Abort the active research pipeline, including survey/searcher/tool streams spawned under its orchestration task.
Sourcepub fn survey_gate_targets_current_session(&self) -> bool
pub fn survey_gate_targets_current_session(&self) -> bool
Whether the survey gate (clarifying questions or plan approval) is armed for the currently viewed session — the only case where Enter is intercepted and routed to the pipeline instead of a normal chat send. A gate in another session must never swallow typing (the old cross-session hijack).
Sourcepub fn restore_survey_gate_prompt(&mut self)
pub fn restore_survey_gate_prompt(&mut self)
Restore an actionable gate row after loading its session. Normal jobs
already load the persisted row, while incognito jobs recover it from
SurveyGate without writing private content to the database.
Sourcepub fn set_survey_gate(&mut self, gate: Option<SurveyGate>)
pub fn set_survey_gate(&mut self, gate: Option<SurveyGate>)
Route a chat reply into the parked survey gate (survey answer or plan
approval/edit). Records the reply as a gate_reply in the session —
it renders in the transcript like a user message but is never replayed
to the model, since the survey/plan rows it answers are excluded too:
a bare “the second option” or “drop Q2” must not leak into model
history without its context.
Arm or clear the parked gate, emitting a Gate event either way.
The event carries the session id so consumers can compare it against
the viewed session — a gate in another session must never swallow
typing.
pub fn reply_to_survey_gate(&mut self, text: &str)
Sourcepub fn on_research_done(&mut self, r: Option<ResearchMsg>)
pub fn on_research_done(&mut self, r: Option<ResearchMsg>)
A research pipeline update: a stage label, or the final report/error.
None = the job’s channel closed (fires once, right after Done).
Source§impl App
impl App
Sourcepub fn refresh_scripts(&mut self)
pub fn refresh_scripts(&mut self)
Read the space’s scripts dir and populate scripts_cache. A missing or
empty dir produces an empty cache, never an error. The scripts popup’s
flow (selection/edit state, $EDITOR handoff) lives in the view layer.
Sourcepub fn ensure_script_file(&mut self, name: &str) -> Result<PathBuf>
pub fn ensure_script_file(&mut self, name: &str) -> Result<PathBuf>
Domain half of script create: touch the file (if absent) and refresh the cache. Returns the created path. The view owns the edit buffer and the $EDITOR handoff.
Sourcepub fn rename_script_file(&mut self, from: &str, to: &str) -> Result<()>
pub fn rename_script_file(&mut self, from: &str, to: &str) -> Result<()>
Domain half of script rename: move the file on disk. Returns an error message string when the target already exists (the view turns it into a status line); Ok otherwise.
Sourcepub fn delete_script_file(&mut self, name: &str) -> Result<bool>
pub fn delete_script_file(&mut self, name: &str) -> Result<bool>
Domain half of script delete: remove the file from disk and refresh. Returns whether a row existed.
Source§impl App
impl App
pub fn activate_notification(&mut self, index: usize) -> Result<()>
Sourcepub fn new_session(&mut self)
pub fn new_session(&mut self)
Clear back to a blank conversation. Doesn’t touch the db — a session
row is only created lazily on the first message actually sent (same as
the very first message of the app), so /new without typing anything
doesn’t leave an empty “new chat” behind in the session list.
Sourcepub fn switch_to_session_by_id(&mut self, id: &str) -> Result<()>
pub fn switch_to_session_by_id(&mut self, id: &str) -> Result<()>
Switch to a session by its id. Used by session-link navigation (Ctrl+O),
notification clicks, the ResolveSession command, and the session
picker’s confirm (via the view layer).
Source§impl App
impl App
Sourcepub fn cycle_ocr_engine(&mut self) -> Result<()>
pub fn cycle_ocr_engine(&mut self) -> Result<()>
Advance the OCR engine auto → tesseract → vlm → local → auto,
persisted. Cycling into “local” pulls the configured model via ollama
in the background (formerly the separate /ocr-local command) —
ocr_local_install itself flips the engine to “local” and persists it
once the pull actually succeeds, so a failed pull doesn’t leave the
engine silently pointed at a model that was never fetched.
Sourcepub fn set_setting(&mut self, key: &str, value: &str) -> Result<()>
pub fn set_setting(&mut self, key: &str, value: &str) -> Result<()>
Set one named setting by key, persisting it and applying it live —
the SetSetting command the host (and later the TUI) uses. Unlike
load_settings (which ignores unknown persisted rows), this fails
fast: an unknown key or an invalid value for a constrained key is an
error, never a silent no-op reported as success.
Source§impl App
impl App
Sourcepub fn reload_skills(&mut self)
pub fn reload_skills(&mut self)
Re-read discovered skills from disk (after an install/remove, an
external Agent Skills change, or a Ctrl+E hand-edit of SKILL.md).
The view re-clamps its cursor after calling this.
Sourcepub fn skill_is_app_managed(&self, skill: &Skill) -> bool
pub fn skill_is_app_managed(&self, skill: &Skill) -> bool
Whether the selected skill belongs to Nexus’s writable skill root.
Skills discovered from Agent Skills roots are intentionally read-only
to the remove action; editing them remains possible through $EDITOR.
Sourcepub fn start_skill_install(&mut self, spec: &str)
pub fn start_skill_install(&mut self, spec: &str)
Domain half of /skills install: parse the typed owner/repo/path
(or owner/repo) and kick off the background GitHub fetch. Same
bg-task shape as memory extraction. The view owns the edit buffer and
mode; Ok(()) means the task started (or the spec was invalid — the
message is pushed as a status line).
pub fn on_skill_install_result( &mut self, result: Option<Result<String, String>>, )
Source§impl App
impl App
Sourcepub fn snapshot(&self) -> Result<CoreSnapshot>
pub fn snapshot(&self) -> Result<CoreSnapshot>
Serde-shaped state for API consumers (the Phase 4 host). Sessions come from the picker cache when loaded, else a fresh db read — a failed read is an error, never a silently-empty session list.
Source§impl App
impl App
Sourcepub fn switch_to_default_space(&mut self) -> Result<()>
pub fn switch_to_default_space(&mut self) -> Result<()>
Switch back to the default space (used when the active space is deleted from the picker — view layer calls this, so it’s pub).
Sourcepub fn set_active_space(&mut self, row: SpaceRow)
pub fn set_active_space(&mut self, row: SpaceRow)
Switch the active space, clearing the open conversation (a session belongs to exactly one space). The space picker’s confirm (view layer) calls this after closing its popup.
Sourcepub fn instructions_path_for_space(&self, name: &str) -> Option<PathBuf>
pub fn instructions_path_for_space(&self, name: &str) -> Option<PathBuf>
Path to the highlighted space’s instructions file, creating a stub with a short header comment if it doesn’t exist yet (so $EDITOR has something to open). The picker cursor lives in the view layer; callers pass the selected space’s name.
Sourcepub fn memory_path_for_space(&self, name: &str) -> Option<PathBuf>
pub fn memory_path_for_space(&self, name: &str) -> Option<PathBuf>
Path to the highlighted space’s memory file (the numbered facts a conversation in that space has accumulated), creating an empty stub with a header comment if nothing’s been extracted yet.
Source§impl App
impl App
Sourcepub fn toggle_swarm_mode(&mut self) -> Result<()>
pub fn toggle_swarm_mode(&mut self) -> Result<()>
Flip swarm mode for the active session.
Sourcepub fn start_swarm_turn(&mut self)
pub fn start_swarm_turn(&mut self)
Start a swarm turn for the just-sent message (already pushed to
self.messages/the db by send_message). No-op if one’s running.
Sourcepub fn save_swarm_roster(&mut self) -> Result<()>
pub fn save_swarm_roster(&mut self) -> Result<()>
Domain half of the roster save: drop blank rows and persist. The view clamps its cursor after calling this.
Sourcepub fn stop_swarm(&mut self)
pub fn stop_swarm(&mut self)
Stop the running swarm immediately. Persona model/tool streams are children of the aborted orchestration task and are dropped with it. The view closes its popup after calling this.
Sourcepub fn on_swarm_update(&mut self, r: Option<(String, SwarmUpdate)>)
pub fn on_swarm_update(&mut self, r: Option<(String, SwarmUpdate)>)
A swarm turn update: persist it, and mirror it into the live
transcript if the session it belongs to is the one being viewed.
None = the job’s channel closed (fires once, right after the last update).
Source§impl App
impl App
Sourcepub fn save_clipboard_image(
&mut self,
width: usize,
height: usize,
bytes: &[u8],
) -> Option<String>
pub fn save_clipboard_image( &mut self, width: usize, height: usize, bytes: &[u8], ) -> Option<String>
Save a clipboard image to the space’s images dir and return a markdown
snippet  that can be inserted into the
composer text.
Sourcepub fn cleanup_incognito_images(&mut self)
pub fn cleanup_incognito_images(&mut self)
Remove the incognito temp image directory if it exists.
Source§impl App
impl App
Sourcepub fn load_usage(&self) -> UsageData
pub fn load_usage(&self) -> UsageData
Load the aggregates for the currently selected range (the view owns the cursor; the range is a persisted core preference).
Sourcepub fn persist_usage_range(&mut self)
pub fn persist_usage_range(&mut self)
Domain half of the range cycle: persist the choice (the view switches
usage_range and reloads).
Sourcepub fn backfill_usage_costs(&mut self)
pub fn backfill_usage_costs(&mut self)
Recompute historical costs from the current catalog before rendering — rows logged before pricing existed stay accurate. Called on popup open and refresh.
Source§impl App
impl App
Sourcepub fn create_watch(&mut self, topic: &str)
pub fn create_watch(&mut self, topic: &str)
/watch <topic> with no existing watch of that exact topic in this
space: create one (fixed 24h interval) plus its own research
session, and kick off the first run immediately (ungated).
Sourcepub fn delete_watch(&mut self, id: &str) -> Result<bool>
pub fn delete_watch(&mut self, id: &str) -> Result<bool>
The watch picker’s confirm/delete flows live in the view layer; this is the delete half: drop the row from the db and refresh the cache. Returns whether a row existed.
Sourcepub fn run_due_watches(&mut self)
pub fn run_due_watches(&mut self)
Startup hook: re-run every due watch (across all spaces) in the
background, ungated. Best-effort — a watch whose research job can’t
start (e.g. no model configured) is silently skipped; it’ll be
retried on the next app open since last_run_at isn’t touched.
Sourcepub fn run_one_watch(&mut self, w: &Watch) -> bool
pub fn run_one_watch(&mut self, w: &Watch) -> bool
Start one watch’s research job (due or not — nexus watch run <id>
force-runs). A watch may belong to a space other than whatever’s
currently active — start_research_with_gate reads self.active_space
for the toolbox/file paths and save_research_report’s destination,
so it must be switched to the watch’s own space for the run, same as
its session. Returns whether a job actually started.
Sourcepub fn previous_citations_for_watch_session(
&self,
session_id: &str,
space_id: &str,
) -> Result<Option<Vec<String>>>
pub fn previous_citations_for_watch_session( &self, session_id: &str, space_id: &str, ) -> Result<Option<Vec<String>>>
Some(urls) if session_id is a watch’s session and it has a prior
run (citations already indexed from an earlier save_research_report
call); Ok(None) for a first run or a non-watch session — either way
means “no diff section”. Takes the report’s own space_id rather than
reading self.active_space: this runs from on_research_done, which
fires asynchronously and may land well after the user (or
run_due_watches, which restores it right after spawning the job) has
switched the active space away from the one this job actually ran in.
Source§impl App
impl App
pub fn new(db: Db, key: Option<&str>, space: Space) -> Self
Sourcepub fn refresh_toolbox(&mut self)
pub fn refresh_toolbox(&mut self)
Rebuild the toolbox from the current searxng_url, so a settings
change takes effect immediately (no restart). Web search tries the
configured backends first and has keyless HTML fallbacks.
Sourcepub fn is_research_session(&self) -> bool
pub fn is_research_session(&self) -> bool
Whether the active session is a research session.
Sourcepub fn blocked_domains(&self) -> Vec<String>
pub fn blocked_domains(&self) -> Vec<String>
The active space’s always-excluded search domains, from its
blocked_domains.txt (comma-separated; missing file = none).
Sourcepub fn init(&mut self)
pub fn init(&mut self)
Kick off the initial model fetch if a key is already present. Call once after construction, from within the tokio runtime.
Sourcepub fn spawn_update_check(&mut self)
pub fn spawn_update_check(&mut self)
Kick off the startup update check: once per day, compare the newest
published version against this build and auto-install it when a
newer release exists. Best-effort — offline or a failed fetch is
silent. Spawned before the event loop starts; the result arrives as
AppEvent::UpdateCheck.
Sourcepub fn on_update_check(&mut self, latest: Option<String>)
pub fn on_update_check(&mut self, latest: Option<String>)
Handle the startup update check result: when a newer version is
published, auto-install it via cargo in a detached background
process when the environment allows (dev builds, missing cargo, and
opted-out installs fall back to a plain notice). None (failed
check) and same/older versions are silent — the check is a
courtesy, not a nag.
pub fn is_streaming(&self) -> bool
pub fn chat_task_count(&self) -> usize
pub fn chat_task_for_session(&self, session_id: &str) -> Option<&ChatTask>
pub fn active_chat_task(&self) -> Option<&ChatTask>
pub fn active_streaming_text(&self) -> Option<&str>
Sourcepub fn viewing_stream(&self) -> bool
pub fn viewing_stream(&self) -> bool
True when the in-flight stream belongs to the active session (every
stream carries its origin session_id, so this is exact).
Sourcepub fn is_welcome(&self) -> bool
pub fn is_welcome(&self) -> bool
The empty start screen (banner + greeting + clock) shows when there’s no conversation yet — a stream running in another session doesn’t hide it.
Sourcepub const fn tick_spinner(&mut self)
pub const fn tick_spinner(&mut self)
Advance the spinner one frame (called on the animation tick).
Sourcepub const fn spinner_char(&self) -> &'static str
pub const fn spinner_char(&self) -> &'static str
Current spinner glyph.
Sourcepub fn spinner_color(&self) -> SpinnerColor
pub fn spinner_color(&self) -> SpinnerColor
Randomly-chosen spinner colour for the current response.
Sourcepub fn thinking_phrase(&self) -> &'static str
pub fn thinking_phrase(&self) -> &'static str
Present-tense phrase for the in-progress response (“Vibing”).
Sourcepub fn thinking_text(&self) -> Option<&str>
pub fn thinking_text(&self) -> Option<&str>
Reasoning tokens accumulated so far this stream, if any.
Sourcepub fn push_status(&mut self, s: impl Into<String>)
pub fn push_status(&mut self, s: impl Into<String>)
Queue a one-line status update as AppEvent::Status. The 2e view
layer keeps its own status field, fed by these events; headless
consumers track them locally.
Sourcepub fn push_composer_set(&mut self, text: impl Into<String>)
pub fn push_composer_set(&mut self, text: impl Into<String>)
Ask the view to replace its composer contents (a send-failure path restoring the user’s message, a gate reply rolled back, …).
Sourcepub fn push_composer_clear(&mut self)
pub fn push_composer_clear(&mut self)
Ask the view to clear its composer.
Sourcepub fn push_viewport_reset(&mut self)
pub fn push_viewport_reset(&mut self)
Ask the view to reset its viewport state (scroll, selection, pinning baseline) — pushed wherever domain code switches sessions, starts a stream, or otherwise invalidates the rendered conversation.
Sourcepub fn push_history_invalidated(&mut self)
pub fn push_history_invalidated(&mut self)
Ask the view to rebuild its wrapped-history render cache (in-place message edits would otherwise leave stale wrapped content).
Sourcepub fn pop_pending_event(&mut self) -> Option<AppEvent>
pub fn pop_pending_event(&mut self) -> Option<AppEvent>
Pop one locally-queued event (status lines, gate arming, composer
feedback). The view drains these before every draw so status changes
land on the same frame as the action that caused them; next_event
drains any remainder before blocking on the channel sources.
Sourcepub async fn next_event(&mut self) -> AppEvent
pub async fn next_event(&mut self) -> AppEvent
Next background event from either the streaming task or a model fetch. Pends on an idle source, so it only resolves when something happens.
pub fn on_models_result(&mut self, result: Option<Result<Vec<Model>, String>>)
Sourcepub fn vlm_ocr_enabled(&self) -> bool
pub fn vlm_ocr_enabled(&self) -> bool
Whether scanned PDFs should OCR through the OpenRouter vision model:
explicit “vlm”, or “auto” with an OCR model configured. (“local” and
“tesseract” route elsewhere.)
Source§impl App
impl App
Sourcepub fn cancel_chat_tasks(&mut self)
pub fn cancel_chat_tasks(&mut self)
Abort every interactive chat task before the TUI exits. Chat streams are intentionally not persisted or resumed across process restarts.
Auto Trait Implementations§
impl !Freeze for App
impl !RefUnwindSafe for App
impl !Sync for App
impl !UnwindSafe for App
impl Send for App
impl Unpin for App
impl UnsafeUnpin for App
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.