Description
The LoopLog viewer writes stderr from every agent into the run log (always as a direct child of <agent>, core/engine.py:1144). That output is often the only way to diagnose a failure, but in normal operation it is noise the user does not want to read at all.
Today only --hide-system-tags exists, and it is purely a navigation toggle: system tags disappear from the treeview (except the first/last boundary sections per run root), but their content is still shown in the preview when a parent node is selected. This new feature behaves differently:
--omit-stderr removes stderr from both the treeview and the preview pane.
- Even when a parent section (e.g. the
agent) is selected, its stderr content is completely absent from the displayed text.
The verbs are intentionally different so the semantics stay distinguishable:
| Flag |
Effect |
Semantics |
--hide-system-tags |
treeview only |
"hide" = navigation (content still reachable via parent) |
--omit-stderr |
treeview + preview |
"omit" = content is removed from the output |
No boundary exception is needed for stderr: the engine always writes <stderr> nested inside <agent>, never at root level, so all stderr sections can be removed without losing header/summary information.
Scope
- In: GUI checkbox, CLI
--omit-stderr flag, preview stripping across all display paths, filter-dropdown handling.
- Out: renaming the existing
--hide-system-tags flag (name stays established), GUI toolbar button changes in ui/app.py (it still launches the viewer with --watch --wrap-lines only), any stderr boundary exception (not needed).
Preview paths that must become stderr-free
- Single-selection preview (
_display_sections, len(secs) == 1)
- Multi-selection preview (parts loop)
- Filter view (matches loop)
- "Show entire file" mode (
_on_show_all and the _rebuild_tree show-all path) — also stripped, confirmed with the user
Implementation plan
tools/looplog.py
-
Parser (LogParser)
parse() caches self.sections and additionally collects self._stderr_ranges — the list of (start, end) line ranges of every stderr section.
get_raw_text(start, end, strip_markers=True, omit_stderr=False) gains an omit_stderr parameter; when True, lines falling inside any cached stderr range are skipped.
get_full_text(strip_markers=True, omit_stderr=False) passes the flag through.
-
LoopLogApp
- Constructor gains
omit_stderr: bool = False; store self._start_omit_stderr.
_build_ui: add a checkbox "Omit stderr output" next to "Hide system tags" (reuse the BooleanVar + command pattern).
_insert_node: when omit is active and sec.tag == "stderr", skip the node (return ""). Use defensive getattr(self, "_omit_stderr", ...) so existing object.__new__-based tests keep working.
_display_sections, _on_show_all, and _rebuild_tree: pass omit_stderr=self._omit_stderr.get() to the text extraction calls.
_update_filter_options: when omit is active, remove "stderr" from the dropdown values and reset a set "stderr" filter to "all" — mirroring the existing system logic.
-
CLI entry point (main)
- Add
--omit-stderr argparse flag (action="store_true").
- Pass
omit_stderr=args.omit_stderr to LoopLogApp(...).
- Update the module usage docstring at the top of the file and the
--help text.
tests/test_all.py (new tests)
- Parser:
get_raw_text(..., omit_stderr=True) removes stderr lines but keeps stdout.
_insert_node skips stderr nodes when omit is active; includes them when not.
_update_filter_options removes stderr from the dropdown and resets a stderr filter when omit is active.
_display_sections strips stderr from the preview text (single selection and multi-selection).
- "Show entire file" path also strips stderr when omit is active.
Explicitly NOT changed
--hide-system-tags (name and behavior remain)
ui/app.py toolbar button (still launches viewer with --watch --wrap-lines)
- Any stderr boundary exception (stderr is never root-level)
Verification
python -m pytest tests\test_all.py -q — existing 251 tests plus the new ones must pass.
python -m py_compile tools\looplog.py tests\test_all.py
- Manual smoke: run the viewer on a real log with both checkboxes and confirm stderr appears in the tree+preview with neither active, disappears from both with "Omit stderr output" active, and that "Show entire file" also becomes stderr-free.
Description
The LoopLog viewer writes
stderrfrom every agent into the run log (always as a direct child of<agent>,core/engine.py:1144). That output is often the only way to diagnose a failure, but in normal operation it is noise the user does not want to read at all.Today only
--hide-system-tagsexists, and it is purely a navigation toggle: system tags disappear from the treeview (except the first/last boundary sections per run root), but their content is still shown in the preview when a parent node is selected. This new feature behaves differently:--omit-stderrremoves stderr from both the treeview and the preview pane.agent) is selected, its stderr content is completely absent from the displayed text.The verbs are intentionally different so the semantics stay distinguishable:
--hide-system-tags--omit-stderrNo boundary exception is needed for stderr: the engine always writes
<stderr>nested inside<agent>, never at root level, so all stderr sections can be removed without losing header/summary information.Scope
--omit-stderrflag, preview stripping across all display paths, filter-dropdown handling.--hide-system-tagsflag (name stays established), GUI toolbar button changes inui/app.py(it still launches the viewer with--watch --wrap-linesonly), anystderrboundary exception (not needed).Preview paths that must become stderr-free
_display_sections,len(secs) == 1)_on_show_alland the_rebuild_treeshow-all path) — also stripped, confirmed with the userImplementation plan
tools/looplog.pyParser (
LogParser)parse()cachesself.sectionsand additionally collectsself._stderr_ranges— the list of(start, end)line ranges of everystderrsection.get_raw_text(start, end, strip_markers=True, omit_stderr=False)gains anomit_stderrparameter; whenTrue, lines falling inside any cached stderr range are skipped.get_full_text(strip_markers=True, omit_stderr=False)passes the flag through.LoopLogAppomit_stderr: bool = False; storeself._start_omit_stderr._build_ui: add a checkbox "Omit stderr output" next to "Hide system tags" (reuse theBooleanVar+commandpattern)._insert_node: when omit is active andsec.tag == "stderr", skip the node (return""). Use defensivegetattr(self, "_omit_stderr", ...)so existingobject.__new__-based tests keep working._display_sections,_on_show_all, and_rebuild_tree: passomit_stderr=self._omit_stderr.get()to the text extraction calls._update_filter_options: when omit is active, remove"stderr"from the dropdown values and reset a set"stderr"filter to"all"— mirroring the existingsystemlogic.CLI entry point (
main)--omit-stderrargparse flag (action="store_true").omit_stderr=args.omit_stderrtoLoopLogApp(...).--helptext.tests/test_all.py(new tests)get_raw_text(..., omit_stderr=True)removes stderr lines but keeps stdout._insert_nodeskips stderr nodes when omit is active; includes them when not._update_filter_optionsremovesstderrfrom the dropdown and resets astderrfilter when omit is active._display_sectionsstrips stderr from the preview text (single selection and multi-selection).Explicitly NOT changed
--hide-system-tags(name and behavior remain)ui/app.pytoolbar button (still launches viewer with--watch --wrap-lines)Verification
python -m pytest tests\test_all.py -q— existing 251 tests plus the new ones must pass.python -m py_compile tools\looplog.py tests\test_all.py