qet MCP: keep the edit script's report lines when cutting long output

_run_qet() kept only the last 400 000 characters of a run's output. A
large qet_edit (a whole multi-folio drawing in one call, some 2000 ops)
logs more than that, and the cut took the capability report the script
makes first: the tool then answered "the binary never ran the script"
although QElectroTech had run it and saved the result.

Lines the script reports through its marker are now kept whole wherever
they stand; only the other output is cut to the tail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DaTweety
2026-10-17 21:35:07 +02:00
parent 8c5a16d50e
commit 1ff2fa5dcf
2 changed files with 35 additions and 1 deletions
+18 -1
View File
@@ -1072,6 +1072,23 @@ def _user_collections() -> dict:
return found
def _keep_tail(text: str, tail: int) -> str:
"""The last `tail` characters of a run's output, but every line an edit
script reported through its marker kept whole, wherever it stands.
A large qet_edit logs far more than `tail` characters; cut from the
front, it lost the capability report the script makes first, and the
tool then said the binary had never run the script."""
if len(text) <= tail:
return text
marked = [ln for ln in text.splitlines() if "QETEDIT " in ln]
rest = text[-tail:]
if not marked:
return rest
kept = set(rest.splitlines())
return "\n".join([ln for ln in marked if ln not in kept] + [rest])
def _run_qet(binary: str, args: list[str], timeout: int = 180,
elements_dir: str | None = None,
script: str | None = None, tail: int = 4000,
@@ -1150,7 +1167,7 @@ def _run_qet(binary: str, args: list[str], timeout: int = 180,
"hint": "a modal dialog during load will hang a headless "
"run; check the project's format version"}
result = {"ok": p.returncode == 0, "exit_code": p.returncode,
"stdout": p.stdout[-tail:], "stderr": p.stderr[-tail:]}
"stdout": _keep_tail(p.stdout, tail), "stderr": _keep_tail(p.stderr, tail)}
# QElectroTech refuses --run when scripting is switched off, which
# it is by default. Its own message is clear but French, and it
# names a settings dialog that nobody driving this server is
+17
View File
@@ -6626,6 +6626,23 @@ class ZippedProjects(unittest.TestCase):
self.assertNotEqual(*rotated[0]["orientation"])
class TestKeepTail(unittest.TestCase):
"""A large edit logs more than the kept tail; the script's own report
lines must survive the cut, or qet_edit says the script never ran."""
def test_short_output_is_untouched(self):
self.assertEqual(m._keep_tail("a\nb", 100), "a\nb")
def test_marker_lines_survive_the_cut(self):
first = 'QETEDIT {"kind": "capabilities", "missing": []}'
text = first + "\n" + "x" * 1000 + "\n" + 'QETEDIT {"kind": "save", "result": true}'
kept = m._keep_tail(text, 100)
self.assertIn(first, kept)
self.assertIn('"kind": "save"', kept)
self.assertEqual(kept.count('"kind": "save"'), 1)
self.assertEqual(m._parse_script_output(kept).get("missing_methods"), [])
if __name__ == "__main__":
print(f"binary : {BINARY or '(none: integration tests skipped)'}")
print(f"elements : {ELEMENTS or '(none)'}")