test_observation_events_and_traces.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. from datetime import datetime, timedelta
  2. import json
  3. from types import SimpleNamespace
  4. import pytest
  5. from agent.orchestration.store import FileSystemArtifactStore, FileSystemTaskStore
  6. from agent.orchestration.wiring import wire_orchestration
  7. from agent.trace.models import Trace
  8. from agent.trace.store import FileSystemTraceStore
  9. from test_coordinator_integration import FakeExecutor, ROOT_TASK_SPEC, make_coordinator
  10. @pytest.mark.asyncio
  11. async def test_event_v2_payloads_are_refs_and_noop_stage_start_is_silent(tmp_path):
  12. coordinator, store, _ = await make_coordinator(tmp_path, FakeExecutor([]))
  13. root_id = (await store.load("root")).root_task_id
  14. reserved = await coordinator._create_attempt("root", root_id, "worker", None)
  15. attempt_id = reserved["attempt_id"]
  16. await coordinator._mark_stage_started("root", None, 0, attempt_id=attempt_id)
  17. before = await store.load("root")
  18. page_before = await store.list_events("root", limit=1000)
  19. await coordinator._mark_stage_started("root", None, 0, attempt_id=attempt_id)
  20. after = await store.load("root")
  21. page_after = await store.list_events("root", limit=1000)
  22. assert after.revision == before.revision
  23. assert len(page_after.events) == len(page_before.events)
  24. attempt_event = next(
  25. event for event in page_after.events if event.event_type == "attempt_created"
  26. )
  27. assert attempt_event.schema_version == 2
  28. assert attempt_event.payload == {"task_id": root_id, "attempt_id": attempt_id}
  29. stage_event = next(
  30. event for event in page_after.events if event.event_type == "stage_started"
  31. )
  32. assert stage_event.payload == {"task_id": root_id, "attempt_id": attempt_id}
  33. mirrored = [
  34. json.loads(line)
  35. for line in (
  36. tmp_path / "root" / "orchestration" / "events.jsonl"
  37. ).read_text(encoding="utf-8").splitlines()
  38. ]
  39. assert mirrored[-1]["event_id"] == stage_event.event_id
  40. assert mirrored[-1]["schema_version"] == 2
  41. @pytest.mark.asyncio
  42. async def test_default_wiring_keeps_durable_journal_without_legacy_mirror(tmp_path):
  43. trace_store = FileSystemTraceStore(str(tmp_path))
  44. runner = SimpleNamespace(trace_store=trace_store, task_coordinator=None)
  45. task_store = FileSystemTaskStore(str(tmp_path))
  46. coordinator = wire_orchestration(
  47. runner,
  48. task_store,
  49. FileSystemArtifactStore(str(tmp_path)),
  50. )
  51. await coordinator.ensure_ledger("root", ROOT_TASK_SPEC)
  52. assert task_store.ledger_path("root").exists()
  53. assert not (tmp_path / "root" / "orchestration" / "events.jsonl").exists()
  54. @pytest.mark.asyncio
  55. async def test_trace_correlation_filters_apply_before_limit(tmp_path):
  56. store = FileSystemTraceStore(str(tmp_path))
  57. target_time = datetime(2020, 1, 1)
  58. await store.create_trace(
  59. Trace(
  60. trace_id="target",
  61. mode="agent",
  62. agent_role="validator",
  63. parent_trace_id="parent",
  64. created_at=target_time,
  65. context={
  66. "root_trace_id": "root",
  67. "task_id": "task",
  68. "attempt_id": "attempt",
  69. "validation_id": "validation",
  70. "operation_id": "operation",
  71. },
  72. )
  73. )
  74. for index in range(1001):
  75. await store.create_trace(
  76. Trace(
  77. trace_id=f"unrelated-{index:04d}",
  78. mode="agent",
  79. created_at=target_time + timedelta(days=1, seconds=index),
  80. )
  81. )
  82. filters = {
  83. "agent_role": "validator",
  84. "parent_trace_id": "parent",
  85. "root_trace_id": "root",
  86. "task_id": "task",
  87. "attempt_id": "attempt",
  88. "validation_id": "validation",
  89. "operation_id": "operation",
  90. }
  91. for key, value in filters.items():
  92. traces = await store.list_traces(limit=1, **{key: value})
  93. assert [trace.trace_id for trace in traces] == ["target"]
  94. await store.create_trace(
  95. Trace(trace_id="root", mode="agent", agent_role="planner")
  96. )
  97. assert {
  98. trace.trace_id
  99. for trace in await store.list_traces(root_trace_id="root", limit=10)
  100. } == {"root", "target"}