Files
2026-07-13 13:12:00 +08:00

58 lines
2.8 KiB
Python

"""
Tests for :func:`omnigent.runtime.tool_output.cap_tool_output` — the canonical
size cap applied to every ``function_call_output`` producer's ``output`` field.
Each assertion is chosen so the corresponding production breakage turns it red.
"""
from __future__ import annotations
from omnigent.runtime.tool_output import MAX_TOOL_OUTPUT_BYTES, cap_tool_output
_TRUNCATION_MARKER = "[output truncated by omnigent:"
def test_cap_tool_output_passes_through_when_within_cap() -> None:
"""A tool result at or under the cap is returned unchanged (same object)."""
small = "hello world"
# `is` (not just ==) proves no re-encode/copy on the common path.
assert cap_tool_output(small) is small
# Exactly at the cap is still within bounds — the check is `<=`, so a
# full-size-but-not-over result must hit the same no-copy passthrough
# (`is`), not fall into the truncation branch (which builds a new string).
at_cap = "x" * MAX_TOOL_OUTPUT_BYTES
assert cap_tool_output(at_cap) is at_cap
assert _TRUNCATION_MARKER not in cap_tool_output(at_cap)
def test_cap_tool_output_truncates_when_over_cap() -> None:
"""An over-cap result is truncated to the cap plus a byte-accurate notice."""
over = 50_000
big = "x" * (MAX_TOOL_OUTPUT_BYTES + over)
capped = cap_tool_output(big)
# The kept prefix is exactly the first MAX_TOOL_OUTPUT_BYTES bytes...
assert capped.startswith("x" * MAX_TOOL_OUTPUT_BYTES)
# ...followed by the notice naming how many bytes were dropped. If `over`
# is reported wrong, the byte arithmetic in cap_tool_output regressed.
assert _TRUNCATION_MARKER in capped
assert f"{over} of {MAX_TOOL_OUTPUT_BYTES + over} bytes omitted" in capped
# The whole capped string stays bounded: kept bytes + the short notice,
# never the multi-MB original. A failure here means truncation didn't fire.
assert len(capped.encode("utf-8")) < MAX_TOOL_OUTPUT_BYTES + over
def test_cap_tool_output_truncates_on_a_character_boundary() -> None:
"""Truncation never splits a multibyte UTF-8 char (no decode error / U+FFFD)."""
# "€" is 3 UTF-8 bytes. Sizing the string so the byte cap lands mid-char
# forces the boundary logic: cap+1 chars => 3*(cap+1) bytes, well over cap,
# and MAX_TOOL_OUTPUT_BYTES is not a multiple of 3, so the cap splits a char.
euros = "€" * (MAX_TOOL_OUTPUT_BYTES + 1)
capped = cap_tool_output(euros)
# decode("utf-8") on the kept prefix would have raised / inserted U+FFFD if
# a partial char survived; assert clean euros only before the notice.
kept = capped.split("\n\n" + _TRUNCATION_MARKER)[0]
assert "" not in kept
assert set(kept) == {"€"}
# The kept prefix is the largest whole-char run within the byte cap.
assert len(kept.encode("utf-8")) <= MAX_TOOL_OUTPUT_BYTES
assert len(kept.encode("utf-8")) > MAX_TOOL_OUTPUT_BYTES - 3