log_context.py 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. from __future__ import annotations
  2. import re
  3. from typing import Any
  4. _ANCHOR_RE = re.compile(
  5. r"^\[(?:MSG|TOOL)_ANCHOR:msg_id=([^:\]]+):seq=(\d+)(?::[^\]]+)?\]\s*$",
  6. re.MULTILINE,
  7. )
  8. _BLOCK_START_RE = re.compile(r"^\[(?:AGENT_TASK|FOLD):[^\]]+\]\s*$", re.MULTILINE)
  9. def locate_log_module(log_content: str | None, event: dict[str, Any]) -> dict[str, Any] | None:
  10. """Return only the anchored log module associated with an event."""
  11. if not log_content:
  12. return None
  13. msg_id = str(event.get("msg_id") or "").strip()
  14. if not msg_id:
  15. return None
  16. anchors = list(_ANCHOR_RE.finditer(log_content))
  17. matched = next(
  18. (
  19. match
  20. for match in anchors
  21. if match.group(1) == msg_id
  22. ),
  23. None,
  24. )
  25. if matched is None:
  26. return None
  27. previous_starts = [
  28. item
  29. for item in _BLOCK_START_RE.finditer(log_content, max(0, matched.start() - 2_000), matched.start())
  30. ]
  31. start = previous_starts[-1].start() if previous_starts else matched.start()
  32. next_anchor = next((item for item in anchors if item.start() > matched.start()), None)
  33. end = next_anchor.start() if next_anchor else len(log_content)
  34. content = log_content[start:end].strip()
  35. return {
  36. "anchor": matched.group(0),
  37. "msgId": matched.group(1),
  38. "sequence": int(matched.group(2)),
  39. "content": content,
  40. "characters": len(content),
  41. }
  42. def _integer(value: Any) -> int | None:
  43. try:
  44. return int(value) if value is not None else None
  45. except (TypeError, ValueError):
  46. return None