feat(compression): make Lite tool-result truncation length configurable (#13915)

* feat(compression): make Lite tool-result truncation length configurable

Lite truncated tool results at a hardcoded 2000 characters. Coding-agent
payloads (file reads, crash dumps) lost the middle of the content with no
supported way to raise the cap.

Honor lite.maxToolLength from settings, then OMNIROUTE_LITE_MAX_TOOL_LENGTH,
then 2000. Existing installs keep the old length.

Related to #13178.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
#13178 stays open.

* compression/lite: keep a stored cap when a step or toggle write is incomplete

An out-of-range step maxToolLength was still a number, so it hid a valid
global cap and fell through to env. A toggle-only settings PUT replaced
the whole lite row and dropped the stored cap. Save treated an out-of-range
number like a cleared field. Reject the bad Save, merge omitted caps, and
use null to clear.

Related to #13178.

Signed-off-by: Minxi Hou <houminxi@gmail.com>

* compression/lite: stop dashboard copy from hard-coding a 2000-char cap

The page overlays schema descriptions from i18n. Updating only
LITE_SCHEMA left operators seeing "over 2,000 characters" after the
cap became configurable. Also assert the Save error string, not the
Save button.

Related to #13178.

Signed-off-by: Minxi Hou <houminxi@gmail.com>

* chore(changelog): move #13915 entry to a changelog.d fragment

---------

Signed-off-by: Minxi Hou <houminxi@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
Bob.Hou
2026-09-17 17:46:45 -04:00
committed by GitHub
parent e7872e57c3
commit ec780ef2dc
82 changed files with 1004 additions and 80 deletions

View File

@@ -23,10 +23,22 @@ export function EngineConfigForm({ schema, value, onChange }: EngineConfigFormPr
{f.type === "number" && (
<input
type="number"
value={v as number}
value={
f.key === "maxToolLength" &&
!(typeof v === "number" && Number.isFinite(v))
? ""
: (v as number)
}
min={f.min}
max={f.max}
onChange={(e) => set(f.key, Number(e.target.value))}
onChange={(e) =>
set(
f.key,
f.key === "maxToolLength" && e.target.value === ""
? Number.NaN
: Number(e.target.value)
)
}
className="border border-border rounded px-2 py-1"
/>
)}

View File

@@ -178,6 +178,12 @@ export function EngineConfigPage({ engineId }: { engineId: string }) {
for (const field of foundEngine?.configSchema ?? []) {
defaults[field.key] = field.defaultValue;
}
// Do not seed lite.maxToolLength from the schema default. Persisting 2000
// would freeze the cap in settings and hide OMNIROUTE_LITE_MAX_TOOL_LENGTH.
// The form still shows 2000 via field.defaultValue until the operator edits it.
if (engineId === "lite" && currentConfig.maxToolLength === undefined) {
delete defaults.maxToolLength;
}
setConfigState({ ...defaults, ...currentConfig });
setLoading(false);
}
@@ -204,10 +210,23 @@ export function EngineConfigPage({ engineId }: { engineId: string }) {
// Strip the `enabled` key — engine on/off is the panel's responsibility.
const { enabled: _ignored, ...formDetail } = configState;
void _ignored;
const detail =
engineId === "lite"
? { compressToolResults: formDetail.compressToolResults !== false }
: formDetail;
let detail: Record<string, unknown> = formDetail;
if (engineId === "lite") {
const raw = formDetail.maxToolLength;
const compressToolResults = formDetail.compressToolResults !== false;
if (!Object.prototype.hasOwnProperty.call(formDetail, "maxToolLength")) {
detail = { compressToolResults };
} else if (typeof raw === "number" && Number.isFinite(raw)) {
const n = Math.floor(raw);
if (n < 256 || n > 1_000_000) {
setSaveError(t("saveFailed"));
return;
}
detail = { compressToolResults, maxToolLength: n };
} else {
detail = { compressToolResults, maxToolLength: null };
}
}
setSaving(true);
setSaveError(null);
try {