feat: cap telemetry bodies at a configurable length
Chat rows stored full message and response text with no upper bound, so downstream contracts and tenders lived in llm_calls indefinitely. Add _cap_text/_cap_messages in the single telemetry exit (_record), applied after digest_messages and before json.dumps, plus to response/thinking. Capping is per text, not over the serialized JSON: cutting the whole string would emit invalid JSON into an unvalidated TEXT column. The cap builds new dicts and never mutates in place — digest_messages passes non-list content straight through as the same object, so an in-place cut would silently poison the caller's messages and the cache key. text_cap is required on TelemetryEmitter (internal class, three known construction sites) and defaults to None on the three public clients, so the default behaviour stays byte-for-byte identical. Settings wiring lands separately.
This commit is contained in:
@@ -109,6 +109,7 @@ class OcrClient:
|
||||
backpressure: BackpressurePolicy,
|
||||
quota_full: str = "wait",
|
||||
telemetry: TelemetryRecorder | None = None,
|
||||
text_cap: int | None = None,
|
||||
now: Callable[[], float] = time.monotonic,
|
||||
sleep: Callable[[float], Awaitable[None]] = asyncio.sleep,
|
||||
rng: Callable[[], float] = random.random,
|
||||
@@ -127,7 +128,7 @@ class OcrClient:
|
||||
self._retry = retry
|
||||
self._bp = backpressure
|
||||
self._quota_full = quota_full
|
||||
self._emitter = TelemetryEmitter(telemetry) if telemetry else None
|
||||
self._emitter = TelemetryEmitter(telemetry, text_cap=text_cap) if telemetry else None
|
||||
self._telemetry = telemetry
|
||||
self._memo = SourceCooldownMemo(now=now)
|
||||
self._now = now
|
||||
|
||||
Reference in New Issue
Block a user