Handle large exec_command output and surface scan errors as TUI toasts#583
Handle large exec_command output and surface scan errors as TUI toasts#583mhspektr wants to merge 17 commits into
Conversation
- Change RuntimeError to TypeError for type validation in report/writer.py - Update pyupgrade to v3.21.2 for Python 3.14 compatibility
Mirror the layout introduced on feature/438-token_budget: pytest + pytest-asyncio dev deps, asyncio_mode auto, a tests.* mypy override, and pytest in the mypy pre-commit hook deps so the tests/ package type-checks.
…ix#492) Large local targets were copied into the sandbox file-by-file via the SDK LocalDir entry, which stalls on big repos and could leave /workspace empty. - --mount <path> bind-mounts a host directory read-only at /workspace/<subdir> instead of copying it, bypassing the per-file stream. - A size pre-flight (STRIX_MAX_LOCAL_COPY_MB, default 1024) fails fast with a clear message suggesting --mount when a non-mounted local target is too big.
An empty or whitespace-only --mount value resolves to the current working directory and would silently bind-mount it into the sandbox. Reject it.
If the same directory is passed via --target and --mount (or as duplicate values), it previously produced two targets — copied AND bind-mounted, and the copied one could trip the size pre-flight. Dedupe by resolved path, preferring the bind mount.
Previously a value of 0 (or negative) made every local target count as oversized, aborting all local scans. Now <= 0 disables the pre-flight.
os.walk silently swallowed directory-listing errors, so a permission-denied subtree could make a large repo under-count and slip past the pre-flight. Surface such omissions via an onerror warning.
Add CLI reference + example for --mount, document the size pre-flight env var, note the read-only-is-not-a-hard-boundary caveat and that remote repos are not size-checked, and clarify the backends docstring on when bind mounts apply.
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
ContextWindowExceededError carries status_code=400, which matched the _INPUT_REJECTION_CODES guard and triggered image-strip retry logic. Image stripping cannot reduce token count, so the agent wasted up to 3 retry cycles before parking as failed. Add an explicit isinstance check before the status-code guard to detect context-window overflow and park the agent as 'failed' immediately.
Scan errors were stored in _scan_error and re-raised only after the user closed the TUI, making the app appear stuck while producing a confusing post-exit traceback. Extract _notify_scan_error and call it from all three error branches in _start_scan_thread so a persistent Textual toast is shown immediately when the scan thread fails.
…missal Textual's Notification expires when raised_at + timeout - time() <= 0. With timeout=0 the toast expired immediately on mount, making the error notification invisible to users. Drop the timeout argument to use Textual's default display duration (~5 s).
exec_command output is now capped at STRIX_MAX_TOOL_OUTPUT_CHARS (default 65536). JSON arrays are parsed and trimmed to the first 50 records (valid JSON preserved); plain text keeps the first 300 lines. Both include a header showing the total size and record/line count so the agent retains full awareness of what was produced. A secondary character cap prevents single very long lines from bypassing the line limit. Set STRIX_MAX_TOOL_OUTPUT_CHARS=0 to disable.
Replaces plain truncation with a parallel summarisation pipeline when exec_command output exceeds STRIX_MAX_TOOL_OUTPUT_CHARS (default 65536). Output is split at JSON record or line boundaries; each chunk is summarised via litellm.acompletion; summaries are consolidated into a single result that fits the context window. Falls back to truncate_exec_result on any compression error. Closes usestrix#579
Code review findings: - factory._wrap_exec_command: add post-compression backstop that calls truncate_exec_result when compress_exec_result returns an oversized result (happens when _split produces 1 chunk, e.g. a single very large JSON record — compress_large_output correctly returns it unchanged, but the result was never guarded against threshold after). - tests/agents/test_factory_helpers.py (new): unit tests for _resolve_model (run_config vs settings fallback, None/whitespace error cases, non-string Model object guard) and _extract_task_hint (valid cmd, missing cmd, non-string cmd, invalid JSON, non-dict JSON).
Greptile SummaryThis PR adds three self-contained features on top of PR #577: structure-aware truncation and MapReduce LLM compression for oversized
Confidence Score: 5/5Safe to merge; all three feature areas are well-isolated with dedicated tests, and the fallback chains preserve session correctness. The truncation/compression pipeline has a solid backstop so oversized outputs cannot bypass the character cap. The ContextWindowExceededError handler is tested end-to-end including the non-retry assertion. The bind-mount wiring is straightforward. The two issues noted are a misleading log message in non-interactive mode and a deprecated asyncio.wait_for(coroutine) call pattern — neither affects correctness. No files require special attention; strix/core/execution.py has a misleading log message and strix/core/mapreduce_output.py has the deprecated asyncio.wait_for(coroutine) call, but neither introduces wrong behavior. Important Files Changed
Reviews (2): Last reviewed commit: "Fix review comment" | Re-trigger Greptile |
|
@greptile |
|
I suggest merging #577, updating this branch, and rerunning greptile before reviewing. |
NB: this builds on #577 and should be merged after
exec_commandresults are now capped atSTRIX_MAX_TOOL_OUTPUT_CHARS(default 65 536 chars). JSON arrays are trimmed to the first 50 records (valid JSON preserved); plain text keeps the first 300 lines. Both truncation paths include a header with total size and count so the agent retains full context awareness. SetSTRIX_MAX_TOOL_OUTPUT_CHARS=0to disable.timeout=0bug that caused the toast to expire on mount was also fixed (Textual's default ~5 sis now used).Closes #579