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
+4 -4
View File
@@ -99,10 +99,10 @@ void FullNodeConsoleExecutor::submit(const std::string& cmd)
is_error = true;
}
scrubParamStrings(params);
return [this, result_str, is_error]() {
return [this, result_str = std::move(result_str), is_error]() mutable {
if (app_) app_->noteWalletMutation();
std::lock_guard<std::mutex> lk(results_mutex_);
results_.push_back({result_str, is_error});
results_.push_back({std::move(result_str), is_error});
};
});
if (refused) why = "A key import or rescan is still running. Try again when it finishes.";
@@ -142,7 +142,7 @@ void FullNodeConsoleExecutor::submit(const std::string& cmd)
{
// Publish the result before the gate drops, so a non-busy console always has it queued.
std::lock_guard<std::mutex> lk(results_mutex_);
results_.push_back({result_str, is_error});
results_.push_back({std::move(result_str), is_error});
}
return [this]() {
// A Console command may have changed the wallet (a send, an import, a new address): the
@@ -162,7 +162,7 @@ void FullNodeConsoleExecutor::submit(const std::string& cmd)
}
if (app_) app_->noteWalletMutation();
std::lock_guard<std::mutex> lk(results_mutex_);
results_.push_back({result_str, is_error});
results_.push_back({std::move(result_str), is_error});
}
}