perf(console): tail-cap large RPC results without a full copy

A large RPC result was fully split into lines and copied before being
handed to the console, even though only the last few lines could survive
the model's line cap.

- The formatter now takes a line cap and keeps only the last N lines,
  located by a backward newline scan, so a huge result is never fully
  split or copied. JSON classification still keys off the first
  character of the whole result.
- It works over a string view and moves line text through, and fold
  spans are computed over the formatted lines directly instead of a
  separate vector of copies.
- getline semantics are preserved: a trailing newline adds no empty
  line and an empty result yields no lines.

Tests: getline parity for empty, trailing-newline and blank-line inputs,
the backward tail cap, and JSON classification and fold spans over a
capped result.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-13 08:23:30 -05:00
co-authored by Claude Opus 4.8
parent 116a997a3a
commit f7ed1ae115
5 changed files with 104 additions and 31 deletions
+10 -2
View File
@@ -3,6 +3,7 @@
#include <cstddef>
#include <nlohmann/json.hpp>
#include <string>
#include <string_view>
#include <vector>
namespace dragonx {
@@ -55,8 +56,13 @@ struct ConsoleArg {
std::vector<ConsoleArg> ParseConsoleCommandArgsTagged(const std::string& command);
std::vector<std::string> ParseConsoleCommandArgs(const std::string& command);
ConsoleRpcCall BuildConsoleRpcCall(const std::string& command);
std::vector<ConsoleResultLine> FormatConsoleRpcResultLines(const std::string& result,
bool isError);
// Splits an RPC result into classified lines (std::getline semantics: a trailing '\n' adds no
// empty line, an empty result yields none). `maxLines` > 0 keeps only the LAST maxLines lines,
// found by a backward newline scan so a huge result is never fully split/copied. The JSON
// classification still keys off the first char of the whole result. 0 = no cap.
std::vector<ConsoleResultLine> FormatConsoleRpcResultLines(std::string_view result,
bool isError,
std::size_t maxLines = 0);
// For a block of pretty-printed JSON lines, return a per-line fold span: for a line that
// opens a collapsible block (its last non-space char is '{' or '[') the value is the offset
@@ -64,6 +70,8 @@ std::vector<ConsoleResultLine> FormatConsoleRpcResultLines(const std::string& re
// for empty/one-line blocks not worth folding (span < 2). Pure; used to drive console
// JSON folding.
std::vector<int> ComputeConsoleFoldSpans(const std::vector<std::string>& lines);
// Same as ComputeConsoleFoldSpans, over formatted result lines directly (no text copies).
std::vector<int> ComputeConsoleResultFoldSpans(const std::vector<ConsoleResultLine>& lines);
} // namespace ui
} // namespace dragonx