mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-08 17:36:45 +08:00
* MUL-7166 MUL-7167 feat(transcript): tell the reader when a tool output is incomplete A tool_result preview is cut at 8 KiB and the remainder is never uploaded. Nothing recorded that, so the run transcript rendered a truncated preview exactly like a complete one — a reader checking what an agent did could take the first 8 KiB of a 300 KB log for the whole thing. The daemon now reports whether the preview dropped bytes, and the viewer says so. Two separate claims, kept separate: - Per step: a "truncated" badge next to the tool name when the record provably lost bytes. - Per run, once: a caveat when the run contains output whose completeness nobody measured. The flag is tri-state end to end (NULL/absent = unknown, false = complete, true = truncated) and `output_truncated` is nullable with no default and no backfill. Historical rows cannot be reconstructed, so they stay unknown; the same applies to messages from an older installed daemon, which is why the batch insert carries the value through the query's text[]/NULLIF encoding rather than a []bool that cannot express the third state. Display clipping is now worded as what it is. The inspector's 8000-character clip said "... (truncated)", the same word the badge uses for bytes that are gone, when copy still yields the whole stored text. Verified: go test ./internal/handler ./internal/daemon ./internal/util ./internal/migrations, pnpm test (4981 views + core), typecheck, lint. Both states captured in a local environment against real API + DB rows. Co-authored-by: multica-agent <[email protected]> * refactor(transcript): move the completeness note to the end of the output The truncation indicator was a warning badge beside the tool name and a run-level banner above the step list. Both announced the caveat before the reader had a reason to care, and the badge's colour gave a routine 8 KiB cut the weight of a failure. "Was that all of it?" is a question you only have once you reach the bottom of an output, so the answer goes there: one muted line at the end of the body, in the same place the display-clip line already sits. The unknown case follows the same rule rather than keeping its own banner — the inspector shows one step at a time, so a note there appears once per opened step, not once per turn in a list. That was the whole objection to the per-turn disclaimer this design replaced; a run-level bar was one way to avoid it, and putting the note where the evidence is another. `outputCompleteness` replaces `hasUnknownOutputCompleteness`: the same rules (tool results only, empty output excluded, false is a measurement) now answer per item instead of per run. Co-authored-by: multica-agent <[email protected]> * fix(transcript): stop the display-clip line promising the whole output "copy to get the whole record" reads as "the full output is in the database". It is not: the daemon cuts at 8 KiB before reporting, and copy returns the stored record — the same bytes, minus the 8000-character render clip. The first reader of this string took it the other way, which is the whole reason the truncation note exists. Says what copy actually returns: everything that was saved. Co-authored-by: multica-agent <[email protected]> * fix(transcript): leave a stored tool result with one remark, not two The render clip cut at 8000 characters, but a stored tool result is already capped at 8192 bytes upstream — so on an ASCII output the clip could only ever shave a further ~190 characters, and it did so under a note that already said the rest was not saved. Two grey lines, the second reporting a rounding error on the first. The clip now sits above the source budget, where a tool result cannot reach it. Tool input keeps it: input is persisted whole and has no server-side budget, so it is the body that actually needs bounding — and it never carries a completeness note, so that path stays a single remark too. The marker also stops mentioning copy. It described the clip's reversibility, which is only interesting next to a truncation note that is no longer beside it. Co-authored-by: multica-agent <[email protected]> * fix(transcript): say why the output is short, not where it stops "Output ends here" reads two ways: the command produced this much, or we cut it. Those are opposite facts about the agent's run, and the note exists to settle exactly that question. States the cause instead: the output was too long, so only the beginning was kept. "Kept" rather than "shown" — the rest was never uploaded, and wording it as a display limit invites the assumption that the whole output is in the database and merely hidden. The unknown note loses the same phrase for the same reason. Co-authored-by: multica-agent <[email protected]> * fix(transcript): address review on the completeness note Three fixes from review of #8212, plus the frequency question it reopened. A malformed `output_truncated` deleted the whole run from the screen. The field parsed with `z.boolean().optional()`, so a string or a number failed its row, the row failed the array, and `parseWithFallback` handed the viewer an empty transcript. It now catches at the field, degrading to unknown. The old test claimed this but passed a malformed top-level object, which exercised a different path; the replacements fail without the catch. The note appeared before the reader could have wanted it. `ToolDetailSurface` collapses its own body, so a footer rendered outside it sat over a faded, half-shown output — answering "was that all of it?" to someone still reading. The surface now owns the note and withholds it until the body is revealed. The render clip went back to 8000 characters for tool input. Raising it to 20000 was collateral: the goal was to stop re-clipping a tool result, which is already capped at 8192 bytes upstream, and skipping the clip for `tool_result` alone does that without touching how an unbounded input renders. Unknown-ness moves back to the run. One daemon produces every message in a run, so either it measured that run's outputs or it measured none of them — a fact about the run, stated once, rather than a remark repeated on each step opened. Co-authored-by: multica-agent <[email protected]> * fix(transcript): drop the notice for records that predate the flag A record from before the flag existed now says nothing. The viewer speaks only when a daemon measured an output and found bytes missing. The column stays tri-state. Nothing renders differently for NULL and false today, but they are not the same fact, and defaulting NULL to false would write "this daemon measured the output and stored all of it" onto rows where nobody measured anything. The original lengths are gone, so that claim could never be corrected — a lie the schema would keep telling long after this UI changed again. Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: J <[email protected]> Co-authored-by: multica-agent <[email protected]>