Coverage for src / lilbee / cli / tui / messages.py: 100%

328 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-06-28 01:01 +0000

1"""Centralized user-facing messages for the TUI. 

2 

3ALL user-facing text MUST be defined here. Inline strings in 

4screens and widgets are forbidden -- this enables future i18n 

5and ensures consistent messaging. 

6""" 

7 

8from __future__ import annotations 

9 

10from lilbee.core.config import cfg 

11from lilbee.wiki.shared import WIKI_TYPE_HEADINGS as _WIKI_TYPE_HEADINGS 

12 

13CMD_UNKNOWN = "Unknown command: {cmd}" 

14CMD_ADD_NOT_FOUND = "Not found: {path}" 

15CMD_ADD_SUCCESS = "Added {count} file(s), syncing..." 

16CMD_ADD_DUPLICATE_TITLE = "File already in knowledge base" 

17CMD_ADD_DUPLICATE_MESSAGE = "{name} is already in the knowledge base. Overwrite and re-sync?" 

18CMD_ADD_SKIPPED_DUPLICATE = "Kept existing copy of {name}." 

19CMD_ADD_ERROR = "Error: {error}" 

20CMD_CRAWL_USAGE = "Usage: /crawl <url> [--depth N] [--max-pages N]" 

21CMD_CRAWL_STARTED = "Crawling {url}..." 

22CMD_CRAWL_PAGE = "Crawling [{current}/{total}]: {url}" 

23CMD_CRAWL_PAGE_INDETERMINATE = "Crawling... ({current} pages so far): {url}" 

24MODEL_REASON_DEFAULT = "it could not be resolved" 

25MODEL_FALLBACK_NOTICE = ( 

26 "{label} model {original!r} is unavailable ({reason}); using {effective!r} for this session. " 

27 "Pick a different model or restore the original to clear this notice." 

28) 

29MODEL_FALLBACK_FAILED = ( 

30 "{label} model {original!r} is unavailable ({reason}) and the fallback {effective!r} was " 

31 "rejected; keeping {original!r}. Pick a working {label} model in settings." 

32) 

33MODEL_UNUSABLE_OPENING_SETUP = ( 

34 "{label} model {original!r} is unavailable ({reason}) and nothing is installed to fall back " 

35 "to. Opening setup so you can pick one." 

36) 

37CMD_CRAWL_SUCCESS = "Crawled {count} page(s) from {url}" 

38CMD_CRAWL_FAILED = "Crawl failed: {error}" 

39CMD_CRAWL_SYNCING = "Syncing crawled pages..." 

40SETUP_CHROMIUM_NAME = "Install Chromium browser" 

41SETUP_CHROMIUM_FAILED = "Chromium install failed: {error}" 

42SETUP_CHROMIUM_DETAIL = "chromium: {done}/{total} MB" 

43SETUP_CHROMIUM_DETAIL_UNKNOWN = "chromium: {done} MB" 

44SETUP_CHROMIUM_CLI_PROGRESS = " chromium: {pct}%" 

45SYNC_FAILED_FILES = "Sync failed for {files}" 

46SYNC_SKIPPED_NO_VISION = ( 

47 "Skipped (no text extracted): {files}. " 

48 "Configure a vision_model in Settings to OCR scanned PDFs." 

49) 

50SYNC_SKIPPED_VISION_FAILED = ( 

51 "Skipped (vision OCR returned no text): {files}. " 

52 "See ~/Library/Application Support/lilbee/logs/worker-vision.log " 

53 "for the underlying error." 

54) 

55CMD_RETRY_SKIPPED_NONE = "No skipped files to retry; running a normal sync." 

56CMD_RETRY_SKIPPED_SOME = "Cleared {count} skip marker(s); retrying those files." 

57 

58 

59def sync_skipped_message(files: str) -> str: 

60 """Pick the right skipped-files message based on whether vision_model is set. 

61 

62 When the user has no vision_model configured the actionable advice is 

63 'go set one'; when one IS configured the OCR failed at runtime, so the 

64 message points the user at the worker log instead of telling them to 

65 do something they have already done. 

66 """ 

67 if cfg.vision_model: 

68 return SYNC_SKIPPED_VISION_FAILED.format(files=files) 

69 return SYNC_SKIPPED_NO_VISION.format(files=files) 

70 

71 

72def retry_skipped_message(count: int) -> str: 

73 """Toast for the 'Retry skipped documents' command.""" 

74 return CMD_RETRY_SKIPPED_NONE if count == 0 else CMD_RETRY_SKIPPED_SOME.format(count=count) 

75 

76 

77CMD_DELETE_NO_DOCS = "No documents indexed" 

78CMD_DELETE_USAGE = "Documents: {names}\nUsage: /delete <filename>" 

79CMD_DELETE_NOT_FOUND = "Not found: {name}" 

80CMD_DELETE_SUCCESS = "Deleted {name}" 

81CMD_REMEMBER_USAGE = "Usage: /remember <text> (prefix with 'pref:' for a preference)" 

82CMD_REMEMBER_SUCCESS = "Remembered ({kind})." 

83CMD_REMEMBER_NO_EMBED = "Set an embedding model before saving memories." 

84MEMORY_AUTO_EXTRACTED = "Noted {count} memory(s) to review in /memories" 

85CMD_EXPORT_USAGE = "Usage: /export <path.parquet|path.jsonl>" 

86CMD_EXPORT_SUCCESS = "Exported {pages} page(s) to {output}" 

87CMD_IMPORT_USAGE = "Usage: /import <path.parquet|path.jsonl>" 

88CMD_IMPORT_SUCCESS = "Imported {sources} source(s) ({pages} pages, {chunks} chunks)" 

89CMD_RESET_SUCCESS = "Knowledge base reset" 

90CMD_RESET_PARTIAL = "Knowledge base reset ({skipped} item(s) could not be deleted)" 

91CMD_RESET_FAILED = "Reset failed: {error}" 

92CMD_RESET_CONFIRM_TITLE = "Reset the knowledge base?" 

93CMD_RESET_CONFIRM_MESSAGE = "This permanently deletes all indexed data." 

94CMD_REBUILD_CONFIRM_TITLE = "Rebuild the index?" 

95CMD_REBUILD_CONFIRM_MESSAGE = ( 

96 "Drops every chunk and re-embeds the documents directory from " 

97 "scratch. Takes minutes on large libraries. Source files on disk " 

98 "are left alone." 

99) 

100TASK_NAME_SYNC = "Sync documents" 

101TASK_NAME_REBUILD = "Rebuild index" 

102CMD_SET_UNKNOWN = "Unknown setting: {key}" 

103CMD_SET_SUCCESS = "{key} = {value}" 

104CMD_SET_INVALID = "Invalid value for {key}: {error}" 

105CMD_SET_READONLY = "{key} is read-only; use the Models screen" 

106CMD_MODEL_SET = "Model set to {name}" 

107CMD_REMOVE_USAGE = "Usage: /remove <model_name>" 

108CMD_REMOVE_NOT_FOUND = "{name} is not installed" 

109CMD_REMOVE_SUCCESS = "Removed {name}" 

110CMD_REMOVE_FAILED = "Failed to remove {name}" 

111CMD_CANCEL = "Cancelled active operations" 

112CMD_CLEAR = "Conversation cleared" 

113CMD_THEME_LIST = "Themes: {names}" 

114CMD_WIKI_DISABLED = "Wiki is disabled (set wiki = true in settings)" 

115TASK_NAME_CRAWL = "Crawl {url}" 

116STREAM_ERROR = "\n\n*Error: {error}*" 

117SYNC_STATUS_SYNCING = "Syncing..." 

118SYNC_STATUS_DONE = "Synced ({count} docs)" 

119SYNC_STATUS_FAILED = "Sync failed" 

120SYNC_FILE_PROGRESS = "Syncing [{current}/{total}]: {file}" 

121SYNC_ALREADY_ACTIVE = "Sync in progress, please wait" 

122EMBEDDING_SET = "Embedding model: {name}" 

123CMD_CRAWL_UNAVAILABLE = "Web crawling is not available. Run 'uv sync --extra crawler' to enable it." 

124CRAWL_DIALOG_TITLE = "Crawl a URL" 

125CRAWL_DIALOG_URL_PLACEHOLDER = "example.com (https:// added automatically)" 

126CRAWL_DIALOG_DEPTH_PLACEHOLDER = "blank = no limit" 

127CRAWL_DIALOG_MAX_PAGES_PLACEHOLDER = "clear for unlimited" 

128CRAWL_DIALOG_URL_LABEL = "URL" 

129CRAWL_DIALOG_RECURSIVE_LABEL = "Recursive (crawl whole site)" 

130CRAWL_DIALOG_BROWSER_LABEL = "Use browser (enables JavaScript, uses more memory)" 

131CRAWL_DIALOG_DEPTH_LABEL = "Depth cap" 

132CRAWL_DIALOG_MAX_PAGES_LABEL = "Max pages (clear for unlimited)" 

133CRAWL_DIALOG_SUBMIT = "Crawl" 

134CRAWL_DIALOG_CANCEL = "Cancel" 

135CRAWL_DIALOG_URL_REQUIRED = "URL is required" 

136CRAWL_DIALOG_INVALID_URL = "Invalid URL: {error}" 

137CRAWL_DIALOG_INVALID_NUMBER = "{field} must be a positive integer or blank" 

138EMBEDDING_MISSING = ( 

139 "No embedding model, search disabled. " 

140 "Run /pull to install one, or: lilbee model pull nomic-ai/nomic-embed-text-v1.5-GGUF" 

141) 

142THEME_SET = "Theme: {name}" 

143HEADING_INSTALLED = "Installed" 

144CATALOG_TAB_LOCAL = "Local" 

145CATALOG_TAB_FRONTIER = "Frontier" 

146CATALOG_TAB_DISCOVER = "Discover" 

147CATALOG_TAB_CHAT = "Chat" 

148CATALOG_TAB_EMBED = "Embed" 

149CATALOG_TAB_VISION = "Vision" 

150CATALOG_TAB_RERANK = "Rerank" 

151CATALOG_TAB_LIBRARY = "Library" 

152CATALOG_FRONTIER_SUMMARY = "{count} cloud models across {providers} providers" 

153CATALOG_GRID_OVERFLOW = "+{count} more on HF. Press v for the full list view" 

154CATALOG_GRID_LOAD_MORE = "{count} loaded · keep scrolling for more" 

155CATALOG_GRID_ALL_LOADED = "All {count} models loaded" 

156CATALOG_GRID_LOADING_MORE = "{frame} loading more models…" 

157CATALOG_USING_FRONTIER = "Using {name} via the {provider} API" 

158CATALOG_NEEDS_KEY = "{provider} needs an API key. Set {key_field} in Settings to enable this model." 

159CATALOG_USING_REMOTE = "Using {name} (remote)" 

160CATALOG_ALREADY_INSTALLED = "{name} is already installed" 

161CATALOG_QUEUED_DOWNLOAD = "Queued download: {name}" 

162CATALOG_INSTALLED_OK = "{name} installed" 

163CATALOG_GATED_REPO = "{name} requires login, run /login or lilbee login" 

164CATALOG_DOWNLOAD_FAILED = "{name}: download failed" 

165CATALOG_SELECT_FOR_INFO = "Select a model to view info" 

166CATALOG_FRONTIER_NO_INFO = "Info modal is for downloadable models only" 

167MODEL_INFO_HINT = "Esc / i / q to close" 

168MODEL_INFO_HF_LINK = "View on HuggingFace: https://huggingface.co/{repo}" 

169CATALOG_SELECT_TO_DELETE = "Select a model to delete" 

170CATALOG_NOT_INSTALLED = "{name} is not installed" 

171CATALOG_CONFIRM_DELETE = "Delete {name}? Press d again to confirm" 

172CATALOG_DELETED = "Deleted {name}" 

173CATALOG_DELETE_FAILED = "Delete failed: {error}" 

174CATALOG_NO_MATCH = "No models match your filters." 

175CATALOG_FILTER_PLACEHOLDER = "Filter models..." 

176CATALOG_VIEW_TOGGLE_GRID = "Press v for full list view · / to search" 

177CATALOG_VIEW_TOGGLE_LIST = "Press v for card view · s to sort" 

178CATALOG_VIEW_GRID = "Grid" 

179CATALOG_VIEW_LIST = "List" 

180CATALOG_SORT_LIST_ONLY = "Sort is available in list view (press v)" 

181CATALOG_SEARCHING_HF = "Searching HuggingFace…" 

182CATALOG_SEARCH_HF_CTA = '→ Search HuggingFace for "{query}"' 

183CHAT_INPUT_PLACEHOLDER_DEFAULT = "Ask… / commands F1 keys F2 all commands" 

184SLASH_CATALOG_TITLE = "Slash Commands" 

185SLASH_CATALOG_FILTER_PLACEHOLDER = "Filter commands..." 

186SLASH_CATALOG_FOOTER_HINT = "↑↓ select Enter run Esc close" 

187SLASH_CATALOG_NO_MATCH = "No commands match" 

188HELP_HINT_COMMANDS = "type / for commands" 

189HELP_HINT_KEYS = "F1 for keys" 

190HELP_HINT_SEPARATOR = " · " 

191SCOPE_PILL_BOTH = "Both" 

192SCOPE_PILL_WIKI = "Wiki" 

193SCOPE_PILL_RAW = "Raw" 

194CHAT_BUSY = "Already answering. Press Ctrl+C to cancel, then submit your next prompt." 

195CHAT_MODEL_DOWNLOADING = "{name} is still downloading. Wait for it to finish, then submit." 

196MODEL_BEING_DOWNLOADED = ( 

197 "{name} is still downloading. Wait for it to finish before setting it active." 

198) 

199CHAT_WELCOME_TITLE = "lilbee" 

200CHAT_WELCOME_TAGLINE = "your local search engine and personal encyclopedia." 

201CHAT_WELCOME_HINT = "Press / for commands, or just ask." 

202CHAT_LOGIN_PROMPT = "Paste your token with /login <token>" 

203CHAT_LOGGED_IN = "Logged in to HuggingFace" 

204CHAT_LOGIN_FAILED = "Login failed: {error}" 

205CHAT_VERSION = "lilbee {version}" 

206CHAT_RENDERING = "Rendering: {label}" 

207SETTINGS_READ_ONLY = "read-only" 

208SETTINGS_INVALID_VALUE = "Invalid value: {error}" 

209SETTINGS_RESET_TO_DEFAULT_TOOLTIP = "Reset to default" 

210 

211EMBED_SWAP_CONFIRM_TITLE = "Switch embedding model?" 

212EMBED_SWAP_CONFIRM_MESSAGE = ( 

213 "The vector store was built under a different embedder. " 

214 "Switching invalidates it: search and ingest are disabled until you rebuild. " 

215 "Run `lilbee rebuild` afterward (or press S to sync) to re-embed every document. " 

216 "Continue?" 

217) 

218EMBED_SWAP_CANCELLED = "Embedding model swap cancelled" 

219MODEL_ASSIGN_REJECTED = "Model not set: {error}" 

220 

221EMBED_ADOPT_CONFIRM_TITLE = "Use this index's embedder?" 

222EMBED_ADOPT_CONFIRM_MESSAGE = ( 

223 "This index was built with embedding model '{model}'. Use it for this vault? " 

224 "lilbee will download it if needed and switch to it. No rebuild is required." 

225) 

226EMBED_ADOPT_NOTICE = "This index was built with a different embedder ('{model}')." 

227EMBED_ADOPT_REBUILD_NOTICE = ( 

228 "This index needs a {dim}-dim embedder. Rebuild it (press S to sync, or run " 

229 "`lilbee rebuild`) to use your current model." 

230) 

231EMBED_ADOPTING = "Switching to embedder '{model}'..." 

232EMBED_ADOPTED = "Now embedding with '{model}'." 

233EMBED_ADOPT_FAILED = "Could not adopt embedder: {error}" 

234EMBED_ADOPT_CANCELLED = "Kept the current embedder." 

235 

236SETTINGS_RESET_ALL_LABEL = "Reset all defaults" 

237SETTINGS_RESET_ALL_CONFIRM_TITLE = "Reset all settings?" 

238SETTINGS_RESET_ALL_CONFIRM_MESSAGE = ( 

239 "Every writable setting will be restored to its built-in default. " 

240 "Readonly fields (like installed models) are not affected." 

241) 

242SETTINGS_RESET_ALL_SUCCESS = "All settings reset to defaults" 

243SETTINGS_LIST_EDITOR_TITLE = "{key} ({count} lines)" 

244SETTINGS_LIST_EDITOR_INVALID_REGEX = "Invalid regex on line {n}: {error}" 

245SETTINGS_LIST_EDITOR_RESTORE_DEFAULTS = "Restore defaults" 

246WIKI_EMPTY_STATE = "No wiki pages found" 

247WIKI_EMPTY_NEEDS_SPACY_LEAF = "spaCy not installed (see right pane)" 

248WIKI_EMPTY_NEEDS_SPACY_DETAIL = ( 

249 "## Wiki entity extraction needs spaCy\n\n" 

250 "Install it then re-ingest documents:\n\n" 

251 "```sh\n" 

252 "uv pip install spacy\n" 

253 "python -m spacy download en_core_web_sm\n" 

254 "```" 

255) 

256 

257 

258def wiki_empty_state_leaf() -> str: 

259 """Single-line sidebar tree leaf for the empty-wiki state.""" 

260 if not _spacy_available(): 

261 return WIKI_EMPTY_NEEDS_SPACY_LEAF 

262 return WIKI_EMPTY_STATE 

263 

264 

265def wiki_empty_state_detail() -> str: 

266 """Right-pane markdown body for the empty-wiki state.""" 

267 if not _spacy_available(): 

268 return WIKI_EMPTY_NEEDS_SPACY_DETAIL 

269 return WIKI_NO_CONTENT 

270 

271 

272def _spacy_available() -> bool: 

273 try: 

274 from lilbee.retrieval.concepts.nlp import load_spacy_pipeline 

275 

276 load_spacy_pipeline() 

277 except (ImportError, OSError): 

278 return False 

279 except Exception: 

280 return True 

281 return True 

282 

283 

284WIKI_SEARCH_PLACEHOLDER = "Filter pages..." 

285WIKI_NO_CONTENT = "Select a page to view" 

286WIKI_INDEX_LABEL = "Index" 

287WIKI_LOG_LABEL = "Log" 

288WIKI_DRAFTS_TITLE = "Wiki Drafts" 

289WIKI_DRAFTS_EMPTY = "No drafts pending review" 

290WIKI_DRAFTS_LOAD_FAILED = "Failed to load drafts: {error}" 

291WIKI_DRAFTS_COLUMN_SLUG = "Slug" 

292WIKI_DRAFTS_COLUMN_KIND = "Kind" 

293WIKI_DRAFTS_COLUMN_DRIFT = "Drift" 

294WIKI_DRAFTS_COLUMN_FAITHFULNESS = "Faithfulness" 

295WIKI_DRAFTS_COLUMN_PUBLISHED = "Published?" 

296WIKI_DRAFTS_KIND_DRIFT = "drift" 

297WIKI_DRAFTS_DIFF_EMPTY = "Select a draft to view its diff" 

298WIKI_DRAFTS_DIFF_NONE = "(no differences)" 

299WIKI_DRAFTS_DIFF_FAILED = "Failed to load diff: {error}" 

300WIKI_DRAFTS_ACCEPT_CONFIRM_TITLE = "Accept draft?" 

301WIKI_DRAFTS_ACCEPT_CONFIRM_MESSAGE = ( 

302 "Overwrite the published page with {slug} and re-index? This cannot be undone." 

303) 

304WIKI_DRAFTS_REJECT_CONFIRM_TITLE = "Reject draft?" 

305WIKI_DRAFTS_REJECT_CONFIRM_MESSAGE = "Delete draft {slug}? The published page will not change." 

306WIKI_DRAFTS_ACCEPTED = "Accepted {slug}" 

307WIKI_DRAFTS_REJECTED = "Rejected {slug}" 

308WIKI_DRAFTS_ACCEPT_FAILED = "Accept failed: {error}" 

309WIKI_DRAFTS_REJECT_FAILED = "Reject failed: {error}" 

310WIKI_DRAFTS_PUBLISHED_YES = "yes" 

311WIKI_DRAFTS_PUBLISHED_NO = "no" 

312WIKI_DRAFTS_SEARCH_PLACEHOLDER = "Filter drafts..." 

313MEMORIES_EMPTY = "No memories stored. Use /remember to add one." 

314MEMORIES_DISABLED = "Memory is off. Enable it with /set memory_enabled true." 

315MEMORIES_LOAD_FAILED = "Failed to load memories: {error}" 

316MEMORIES_COLUMN_KIND = "Kind" 

317MEMORIES_COLUMN_SHARED = "Shared" 

318MEMORIES_COLUMN_TEXT = "Memory" 

319MEMORIES_FLAG_YES = "yes" 

320MEMORIES_FLAG_NO = "no" 

321MEMORIES_SEARCH_PLACEHOLDER = "Filter memories..." 

322MEMORIES_DELETE_CONFIRM_TITLE = "Delete memory?" 

323MEMORIES_DELETE_CONFIRM_MESSAGE = "Delete this memory? This cannot be undone." 

324MEMORIES_DELETED = "Deleted memory" 

325MEMORIES_DELETE_FAILED = "Delete failed: {error}" 

326MEMORIES_SHARED_ON = "Shared with agents" 

327MEMORIES_SHARED_OFF = "No longer shared with agents" 

328MEMORIES_FLAG_FAILED = "Update failed: {error}" 

329# Re-export the shared heading map with string keys so callers can 

330# look up by raw ``page_type`` string without coercion. 

331WIKI_TYPE_HEADINGS: dict[str, str] = { 

332 kind.value: label for kind, label in _WIKI_TYPE_HEADINGS.items() 

333} 

334APP_CANCELLED = "Cancelled" 

335SETUP_WELCOME = "Welcome to lilbee" 

336SETUP_SUBTITLE = "Pick a chat model and an embedding model to get started." 

337SETUP_INTRO = ( 

338 "lilbee needs two models to work: one for chat and one for search. " 

339 "Pick one of each below: highlight a card and press [b]Enter[/b] to install. " 

340 "Downloads continue in the background, so you can keep picking or press [b]Esc[/b] when done." 

341) 

342SETUP_HEADING_CHAT = "Chat Models" 

343SETUP_HEADING_EMBED = "Embedding Models" 

344SETUP_ENTER_HINT = "Enter on a card to install · Esc when done" 

345SETUP_RETURN_HINT = "Your existing models are ready · Esc to return" 

346SETUP_CARD_HINT = "↵ Enter to install" 

347INSTALLED_CARD_HINT = "D / ⌫ to delete" 

348 

349# Architecture compatibility pill labels (catalog row). 

350# SUPPORTED renders nothing to keep the row visually quiet for the common case. 

351COMPAT_PILL_UNSUPPORTED = "unsupported" 

352COMPAT_PILL_UNKNOWN = "?" 

353 

354# Architecture compatibility copy for the catalog detail view + confirm modal. 

355COMPAT_DETAIL_SENTENCE_SUPPORTED = "Supported by your llama.cpp build." 

356COMPAT_DETAIL_SENTENCE_UNSUPPORTED = ( 

357 "Architecture {arch} is not in the supported set. Pull may fail at load." 

358) 

359COMPAT_DETAIL_SENTENCE_UNKNOWN = ( 

360 "Architecture unknown until download. Pull will probe the header first." 

361) 

362COMPAT_MODAL_TITLE = "Architecture not supported" 

363COMPAT_MODAL_BODY = ( 

364 "This model uses architecture {arch}. Your lilbee build doesn't support it, " 

365 "so loading after download will probably fail. Pull anyway?" 

366) 

367DEFAULT_VIEW = "Chat" 

368_BASE_NAV_VIEWS: tuple[str, ...] = (DEFAULT_VIEW, "Catalog", "Status", "Settings", "Tasks") 

369 

370 

371def get_nav_views() -> list[str]: 

372 """Return the active nav view names, including Wiki when enabled.""" 

373 views = list(_BASE_NAV_VIEWS) 

374 if cfg.wiki: 

375 views.append("Wiki") 

376 return views 

377 

378 

379MODE_NORMAL = "NORMAL" 

380MODE_INSERT = "INSERT" 

381TASKBAR_HINT = "Press t for Tasks" 

382TASKBAR_HINT_INPUT = "Esc then t for Tasks" 

383CHAT_REASONING_FINISHED = "reasoning · {tokens} tokens" 

384CHAT_SOURCES_LABEL = "sources" 

385 

386STATUS_DOCS_LOAD_FAILED = "(unable to read store)" 

387STATUS_DOCS_EMPTY = "(no documents yet)" 

388STATUS_DOCS_TITLE = "Documents" 

389TASKBAR_STARTING_WORKER = "Starting {labels} worker..." 

390TASKBAR_STARTING_WORKERS = "Starting {labels} workers..." 

391 

392TASK_CENTER_TITLE = "Background Tasks" 

393TASK_CENTER_COUNTS = "{active} running · {queued} queued · {done} done" 

394TASK_CENTER_HINT = "r refresh c cancel C clear done q back j/k navigate" 

395TASK_CENTER_EMPTY_HEADLINE = "✓ all caught up" 

396TASK_CENTER_EMPTY_DETAIL = "no background tasks" 

397TASKBAR_SINGLE = "{name} [b]{pct:.1f}%[/b]" 

398TASKBAR_MULTIPLE = "[b]{count} tasks running[/b]" 

399TASKBAR_ONE = "[b]1 task running[/b]" 

400TASKBAR_QUEUED_COUNT = "{count} queued" 

401TASKBAR_ALL_DONE = "[b]Done[/b]" 

402TASKBAR_FAILED = "[b]{count} task failed[/b]" 

403TASKBAR_FAILED_PLURAL = "[b]{count} tasks failed[/b]" 

404TASKBAR_SYNC_PENDING_ONE = "[b]1 doc to sync[/b] · S to sync" 

405TASKBAR_SYNC_PENDING_PLURAL = "[b]{count} docs to sync[/b] · S to sync" 

406TASKBAR_SYNC_PENDING_ONE_INPUT = "[b]1 doc to sync[/b] · Esc then S to sync" 

407TASKBAR_SYNC_PENDING_PLURAL_INPUT = "[b]{count} docs to sync[/b] · Esc then S to sync" 

408SYNC_CANCELLED_RESUME = "Sync cancelled. Press S to resume." 

409SYNC_EMBEDDING = "Embedding {file}" 

410SYNC_FILE_DONE = "Done: {file}" 

411ADD_SYNCING_FILE = "Syncing {file}..." 

412ADD_PAGE_PROGRESS = "{status} page {current} of {total}" 

413ADD_FILE_DONE = "Done {file}" 

414 

415SETTINGS_API_KEYS_WARNING = ( 

416 "These keys are stored in plain text at {path}. " 

417 "Anything you send to these providers leaves your machine. " 

418 "Do not route sensitive documents from lilbee through them." 

419) 

420MODEL_BAR_CLOUD_PROVIDER_WARNING = ( 

421 "Chat prompts are being sent to {provider}. Do not share sensitive data." 

422) 

423CHAT_MODE_SEARCH_LABEL = "Search" 

424CHAT_MODE_CHAT_LABEL = "Chat" 

425CHAT_MODE_TOGGLE_TOOLTIP = ( 

426 "Search runs your question through document retrieval. " 

427 "Chat skips retrieval and answers directly. Click or press F3 to flip." 

428) 

429CHAT_MODE_TOGGLE_DISABLED_TOOLTIP = ( 

430 "Search needs an embedding model. Install one to enable Search mode." 

431) 

432CHAT_MODE_SEARCH_NO_RESULTS = "Search returned 0 results, falling back to chat for this turn." 

433CHAT_MODE_SET = "Mode: {label}" 

434MODEL_PICKER_TITLE_CHAT = "Pick a chat model" 

435MODEL_PICKER_TITLE_EMBED = "Pick an embedding model" 

436MODEL_PICKER_TITLE_VISION = "Pick a vision model" 

437MODEL_PICKER_TITLE_RERANK = "Pick a reranker model" 

438MODEL_VALUE_NONE = "(none)" 

439MODEL_PICKER_DISABLE_LABEL = "(disabled, no model)" 

440MODEL_PICKER_CHAT_TOOLTIP = "Model used to answer your questions. Click to pick a different one." 

441MODEL_PICKER_EMBED_TOOLTIP = ( 

442 "Model used to vectorize search queries (Search mode). Click to pick a different one." 

443) 

444MODEL_PICKER_VISION_TOOLTIP = ( 

445 "Optional. Model used to read scanned PDFs and images. Click to pick one or browse the catalog." 

446) 

447MODEL_PICKER_RERANK_TOOLTIP = ( 

448 "Optional. Model used to sharpen search results. Click to pick one or browse the catalog." 

449) 

450MODEL_PICKER_BROWSE_CATALOG = "Browse catalog to download..." 

451MODEL_PICKER_SEARCH_PLACEHOLDER = "Search models..." 

452 

453# Model bar (chat-screen, below the input) 

454MODEL_BAR_CHAT_LABEL = "Chat" 

455MODEL_BAR_EMBED_LABEL = "Embed" 

456MODEL_BAR_VISION_LABEL = "Vision" 

457MODEL_BAR_RERANK_LABEL = "Rerank" 

458MODEL_BAR_DISABLED = "disabled" 

459MODEL_PICKER_TURN_OFF = "Turn off this model" 

460MODEL_PICKER_HINT = "Enter to pick · Esc to cancel · / to search"