mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-14 18:18:08 +00:00
Add the per-request trace recorder
docsgpt.tracing records agent, LLM, tool, retrieval and embedding spans in memory and writes the finished trace once. Container spans nest by a per-thread stack so suspended generators cannot corrupt the tree; open spans are cancelled at flush and previews are bounded and redacted.
This commit is contained in:
1 parent
f3f817b1e8
commit
3f45d019b0
6 files changed
+1124
No files matched your search
@@ -0,0 +1,58 @@
|
||||
"""Bounded, secret-redacted content previews stored with a trace span."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from docsgpt.core.settings import settings
|
||||
from docsgpt.storage.db.redaction import redact_secrets
|
||||
from docsgpt.utils import strip_null_bytes
|
||||
|
||||
_ELLIPSIS = "…"
|
||||
# A list longer than this keeps its head only; the preview is for reading,
|
||||
# not for reconstructing the payload.
|
||||
_MAX_LIST_ITEMS = 50
|
||||
|
||||
|
||||
def _bound(value: Any, limit: int) -> Any:
|
||||
"""Truncate strings and long lists inside ``value``; stringify unknown objects."""
|
||||
if isinstance(value, str):
|
||||
return value if len(value) <= limit else value[:limit] + _ELLIPSIS
|
||||
if isinstance(value, dict):
|
||||
return {str(k): _bound(v, limit) for k, v in value.items()}
|
||||
if isinstance(value, (list, tuple)):
|
||||
items = [_bound(v, limit) for v in list(value)[:_MAX_LIST_ITEMS]]
|
||||
if len(value) > _MAX_LIST_ITEMS:
|
||||
items.append(f"{_ELLIPSIS} {len(value) - _MAX_LIST_ITEMS} more")
|
||||
return items
|
||||
if value is None or isinstance(value, (bool, int, float)):
|
||||
return value
|
||||
return _bound(str(value), limit)
|
||||
|
||||
|
||||
def make_preview(value: Any, limit: int | None = None) -> Any:
|
||||
"""Return a storable preview of ``value``.
|
||||
|
||||
Secret-keyed fields are redacted, NUL bytes stripped and every string
|
||||
truncated to ``limit`` (``TRACES_PREVIEW_CHARS`` by default). A structure
|
||||
whose JSON form is still far larger than ``limit`` collapses to a
|
||||
truncated JSON string so one huge tool result cannot bloat the row.
|
||||
|
||||
Args:
|
||||
value: Any JSON-like value (tool arguments, a result, a query string).
|
||||
limit: Maximum characters per string; defaults to the setting.
|
||||
|
||||
Returns:
|
||||
A JSON-serializable preview.
|
||||
"""
|
||||
limit = limit or settings.TRACES_PREVIEW_CHARS
|
||||
bounded = strip_null_bytes(_bound(redact_secrets(value), limit))
|
||||
if isinstance(bounded, (dict, list)):
|
||||
try:
|
||||
encoded = json.dumps(bounded, ensure_ascii=False, default=str)
|
||||
except (TypeError, ValueError):
|
||||
encoded = str(bounded)
|
||||
if len(encoded) > limit * 4:
|
||||
return encoded[:limit] + _ELLIPSIS
|
||||
return bounded
|
||||
Reference in new issue
Block a user