test_global_data_context.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. from __future__ import annotations
  2. import json
  3. from pathlib import Path
  4. from types import SimpleNamespace
  5. from obagent_sdk import observe
  6. from obagent_sdk.integrations import langgraph
  7. from production_build_agents.observability.global_data import (
  8. GlobalDataObservation,
  9. )
  10. class _RunHandle:
  11. def __init__(self) -> None:
  12. self.finished: list[dict] = []
  13. def finish(self, **payload) -> None:
  14. self.finished.append(payload)
  15. class _RunManager:
  16. def __init__(self, handle: _RunHandle) -> None:
  17. self.handle = handle
  18. self.exits: list[tuple] = []
  19. def __enter__(self) -> _RunHandle:
  20. return self.handle
  21. def __exit__(self, *args):
  22. self.exits.append(args)
  23. if args[1] is not None:
  24. raise args[1]
  25. return False
  26. def test_global_data_context_forces_sanitized_manual_collection(
  27. monkeypatch,
  28. tmp_path: Path,
  29. ) -> None:
  30. captured: dict = {}
  31. handle = _RunHandle()
  32. manager = _RunManager(handle)
  33. def fake_run(**kwargs):
  34. captured.update(kwargs)
  35. return manager
  36. monkeypatch.setattr(observe, "run", fake_run)
  37. monkeypatch.setattr(
  38. langgraph,
  39. "graph_spec",
  40. lambda _graph: {"nodes": [{"key": "preprocess"}], "edges": []},
  41. )
  42. settings = SimpleNamespace(
  43. configure_sdk=lambda: True,
  44. project="safe-project",
  45. project_name="安全项目",
  46. )
  47. result = {
  48. "run_id": "safe-run",
  49. "protocol_version": "0.3",
  50. "status": "COMPLETED",
  51. "phase": "FINALIZE",
  52. "input_path": "/private/客户标题.json",
  53. "output_dir": str(tmp_path),
  54. "event_log": ["客户正文"],
  55. }
  56. with GlobalDataObservation(
  57. project_root=tmp_path,
  58. thread_id="safe-run",
  59. input_sha256="a" * 64,
  60. protocol_version="0.3",
  61. execution_mode="fresh",
  62. graph=object(),
  63. settings=settings,
  64. ) as observation:
  65. observation.finish(result, graph_invoked=True)
  66. encoded = json.dumps(
  67. {"run": captured, "finish": handle.finished},
  68. ensure_ascii=False,
  69. )
  70. assert captured["auto_collect"] is False
  71. assert captured["payload"]["input_sha256"] == "a" * 64
  72. assert captured["meta"]["redaction_mode"] == "allowlist_v1"
  73. assert handle.finished[0]["ok"] is True
  74. assert "/private/客户标题.json" not in encoded
  75. assert "客户正文" not in encoded