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
- Add RED normalized-equivalence, different-ID coalescing, cross-round stale replay, concurrent in-flight replay, and scope cleanup tests.
- Add RED sibling-timeout/terminal-grace and blocking-sync-handler timeout tests.
- Add RED tool-call-only terminate farewell and direct/dual search two-answer tests.
- Implement canonical keys, atomic in-flight sharing, bounded cleanup, terminal grace, async sync-handler dispatch, and policy-owned farewell.
- 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