todo-48.1-batch-canonical-replay-and-terminal-safety.md 3.7 KB

Todo 48.1 Batch Canonical Replay and Terminal Safety Plan

Status: in_progress

Goal

Close review-confirmed batch correctness, lifecycle, timeout, and user-visible termination gaps while keeping the scheduler and policy layer generic.

Canonical Dedupe and Replay

  • Split canonical request identity from event ID:
    • batch coalescing uses event name, source, and deterministically normalized request arguments, excluding event ID;
    • replay identity additionally includes caller scope and event ID.
  • Apply definition normalizers before forming provider/structured request keys. Text name-only events may coalesce within one batch, but Runtime scopes must include round so parser-local IDs cannot replay stale results across rounds before resolution.
  • Clone coalesced/replayed EventResult correlation fields for each requested event ID while retaining explicit deduplication provenance.
  • Add an in-flight future map guarded atomically so concurrent identical replay keys execute one handler.
  • Add explicit scope release and a defensive capacity bound; Runtime/EventAgent release round scopes after results are delivered.

Terminal Deadline

  • Non-terminal siblings use the configured batch deadline.
  • After siblings finish or become timeout results, terminal events receive a short independent grace window bounded by their own timeout.
  • Mark deadline_exceeded=True for the sibling phase while still allowing terminal execution.
  • Preserve terminal-last order and failure isolation.

Sync Handler Timeout

  • Run synchronous handlers off the event loop in async kernel execution so event/batch timeout can return promptly and unrelated events/session work remain responsive.
  • Keep execute_sync() behavior unchanged.
  • Do not swallow cancellation/BaseException.
  • Document/test that timeout stops awaiting the worker; production side-effect ports should remain cancellation/idempotency aware.

Farewell and Search Acceptance

  • Give session.terminate a plugin-owned deterministic farewell factory.
  • When a successful terminal batch has no visible ChatAgent content, emit that deterministic farewell before ending one-shot/reusable sessions.
  • If ChatAgent already streamed a farewell, do not duplicate it.
  • Add dedicated knowledge.web.search two-answer regressions for both modes: first visible response, search/tool execution, one grounded second ChatAgent response.

Files

  • Modify: src/agent_lab/application/events/batch.py
  • Modify: src/agent_lab/application/events/kernel.py
  • Modify: src/agent_lab/application/events/models.py
  • Modify: src/agent_lab/application/events/builtin_plugins.py
  • Modify: src/agent_lab/application/tools.py
  • Modify: src/agent_lab/application/event_agent.py
  • Modify: src/agent_lab/application/runtime.py
  • Modify: tests/test_event_batch.py
  • Modify: tests/test_event_kernel.py
  • Modify: tests/test_debug_runtime.py

Requirement Execution Loop

Plan

  1. Add RED normalized-equivalence, different-ID coalescing, cross-round stale replay, concurrent in-flight replay, and scope cleanup tests.
  2. Add RED sibling-timeout/terminal-grace and blocking-sync-handler timeout tests.
  3. Add RED tool-call-only terminate farewell and direct/dual search two-answer tests.
  4. Implement canonical keys, atomic in-flight sharing, bounded cleanup, terminal grace, async sync-handler dispatch, and policy-owned farewell.
  5. Run focused/full verification and renewed bounded reviews.

Observe / Update

Close Todo 48 only when no Critical/Important findings remain and the named direct/dual user-visible flows are permanent regressions.

Verification

  • UV_CACHE_DIR=.uv-cache uv run pytest tests/test_event_batch.py tests/test_event_kernel.py tests/test_debug_runtime.py -q
  • UV_CACHE_DIR=.uv-cache uv run pytest
  • git diff --check