6Pure presentation helpers for terminal labels and tables.
10Format strings the user sees — byte-count → ``KB``/``MB``, token
11count → ``2.4K``/``1.20M``, model + capability → ``deepseek-v4-pro
12(thinking, high)``. These are a layer above the
13:class:`~oc_ui.presenter_base.Presenter` ABC: the presenters call
14``show_info`` / ``show_session_list`` / ``show_available_models``
15with strings produced here.
17Sub-agents that use :class:`LoggingPresenter` or no presenter at all
18never need these — that's why they live in ``oc_ui`` rather than
19next to the runtime objects they describe.
23- :func:`fmt_size_kb` — render a byte count compactly.
24- :func:`fmt_tokens_or_size` — pick the most informative chat-volume
25 label for the menu (token count when available, file size as a
27- :func:`fmt_model_caps` — format the model line with thinking /
28 reasoning capability hints in either compact (table) or verbose
29 (continue-prompt) form.
41- All three formatters are pure functions: same inputs → same string
43- :func:`fmt_size_kb` switches to ``MB`` at ``1_000_000`` bytes.
44- :func:`fmt_tokens_or_size` falls back to ``"empty"`` when neither
45 tokens nor bytes are recorded.
46- :func:`fmt_model_caps` returns the bare model name when the model
47 declares neither ``supports_thinking`` nor ``supports_reasoning``.
51- oc_diagnostics (structured debug logging via _dbg)
52- oc_chat.core.models (lazy; ModelManager type hint for fmt_model_caps)
53- oc_chat.core.session (lazy; TokenStats type hint for fmt_tokens_or_size)
55from __future__
import annotations
57from typing
import TYPE_CHECKING
59from oc_diagnostics
import _dbg
66_dbg(
"OC_UI.TERMINAL",
"module",
"loaded", 4)
70 """Render a byte count as ``NNN KB`` (or MB for >=1 MB)."""
71 if n_bytes >= 1_000_000:
72 return f
"{n_bytes / 1_000_000:.1f} MB"
73 return f
"{n_bytes / 1024:.0f} KB"
77 """Pick the most informative chat-volume label for the menu.
79 If usage tokens were recorded, display them. Otherwise fall back to
80 the chat log file size so the user has *something* to gauge volume by.
82 if stats.total_tokens > 0:
83 n = stats.total_tokens
85 return f
"tokens: {n / 1_000_000:.2f}M"
87 return f
"tokens: {n / 1_000:.1f}K"
90 return f
"size: {fmt_size_kb(size_bytes)}"
96 reasoning_effort: str,
97 model_manager:
"ModelManager | None",
99 verbose: bool =
False,
101 """Format the model line including thinking/reasoning capability hints.
103 *verbose* form: ``"deepseek-v4-pro (thinking, effort: high)"`` — fine
104 for the [1] continue-prompt where we have a whole line.
105 Default compact form: ``"deepseek-v4-pro (thinking, high)"`` — fits the
108 caps = model_manager.capabilities(model)
if model_manager
else {}
109 if caps.get(
"supports_thinking"):
111 elif caps.get(
"supports_reasoning"):
116 return f
"{model} ({kind}, effort: {reasoning_effort})"
117 return f
"{model} ({kind}, {reasoning_effort})"