refactor: Route async task mode through TaskExecutionService (#95) - #162
refactor: Route async task mode through TaskExecutionService (#95)#162AndriiPasternak31 wants to merge 6 commits into
Conversation
vybe
left a comment
There was a problem hiding this comment.
Thanks for the clean refactor! The delegation pattern is solid and the 5 new tests are a great addition. A few items before merge:
Required
-
execution_time_msregression in_save_to_chat_session()— The old_execute_task_background()passedexecution_time_mstodb.add_chat_message(). The new helper omits it becauseTaskExecutionResulthas no such field. Async chat sessions will now always storeNULLfor execution time. Either addexecution_time_ms: Optional[int]toTaskExecutionResultand populate it in the service, or explicitly accept this loss and document it. -
context_usedguard dropped — Old:context_used if context_used > 0 else None. New: storesresult.context_useddirectly (could persist0instead ofNULL). Small behavior change worth preserving for consistency. -
Please rebase onto
mainbefore merge — the branch has a merge commit (merge: resolve changelog conflict with upstream/main) that should be cleaned up.
Minor
- Issue #95 is missing the
type-refactorlabel. - Confirm
public.py's_execute_public_chat_background()(line 775) is considered resolved — it appears to already delegate toTaskExecutionService, but the issue's "Files to Change" section lists it. Either close the loop in the PR description or follow up in a separate issue. - Add
## Security Considerationssection totask-execution-service.md(even a brief "N/A — service layer, no direct auth or user input" is sufficient to satisfy the flow format spec).
Please address the required items and request re-review.
1d4236f to
2344f31
Compare
…xecutionResult - Add execution_time_ms field to TaskExecutionResult dataclass and populate it in execute_task() so callers (including _save_to_chat_session) can persist it to chat messages - Pass execution_time_ms in _save_to_chat_session() assistant message call - Update coverage table: async parallel task now uses TaskExecutionService - Add Security Considerations section to task-execution-service.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addressed review feedbackRequired items
Minor items
Additional improvements merged from main
|
vybe
left a comment
There was a problem hiding this comment.
Please rebase this branch onto main to resolve any conflicts and incorporate recent changes.
Once rebased, request re-review.
e713535 to
1f48311
Compare
|
Rebased onto
These cover behaviors not exercised by the upstream
No production code changes. Dropped:
Let me know if you'd prefer this closed as superseded instead of merged as a test-only follow-up. |
|
🤖 PR Reviewer (Trinity) PR Review — refactor: Route async task mode through TaskExecutionService (#95)Overall: Straightforward refactor with good intent. The diff is limited to Scope mismatchThe PR description says:
But
This should be resolved before merge. If the core refactor of Test-only concerns
Missing No functional/security concernsThe added tests are read-only API interactions (GET sessions, GET activities, GET executions). No new write paths, no injection risks. |
Adds three test classes covering behaviors not exercised by the upstream TestAsyncModeUnifiedExecutor (landed via Abilityai#320): - TestAsyncSessionPersistence (3 tests) — save_to_session creates user+assistant messages, explicit session_id is respected, WebSocket chat_response_ready fires. - TestAsyncCollaborationActivity (1 test) — agent-to-agent async task completes the collaboration activity end-to-end. - TestAsyncSafetyNet (1 test) — execution record is created before the background task is spawned (no silent launch failure). Closes Abilityai#95 test coverage gaps. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shared helper in tests/testing_utils/assertions.py to remove duplicated polling loops across the async task tests added in the previous commit. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace fixed time.sleep(1) in TestAsyncCollaborationActivity with a bounded retry loop on /api/activities/timeline so the assertion is not fragile when the activity write lags the execution finish. - Document poll_execution_until_done as @pytest.mark.slow-only and warn against use from non-slow contexts (busy-poll with time.sleep). - Mark TestAsyncSafetyNet test with @pytest.mark.requires_agent so it is gated correctly by the integration runner. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- poll_execution_until_done: include CANCELLED and SKIPPED in the terminal set per TaskExecutionStatus (models.py). Previously polled to timeout whenever an execution was cancelled or skipped. - TestAsyncSessionPersistence: replace silent `if status_code == 200` guards with assert_status(...) so a backend regression on the sessions endpoint fails the test instead of passing without assertions. - TestAsyncSessionPersistence (websocket test): require the helper to return a terminal status; skip explicitly when the execution did not succeed (broadcast only fires on success). - TestAsyncSafetyNet: tighten the "execution exists immediately" status check to an explicit allow-list (queued/running/success) — the prior `not in ["cancelled"]` permitted failed/skipped too. - Drop one extra blank line between top-level class definitions (PEP 8). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3e154d4 to
9bb3426
Compare
The /api/agents/{name}/chat/sessions endpoint returns
{agent_name, session_count, sessions: [...]} (a wrapped object), not a
bare list. Two of the three TestAsyncSessionPersistence tests treated it
as a bare list:
- test_async_save_to_session_creates_chat_messages was a false positive:
iterating the dict yielded 3 keys, so len(sessions) > 0 was always
true regardless of whether any session existed.
- test_async_save_to_session_with_explicit_session_id raised
AttributeError when calling .get('id') on a string (dict key) instead
of a session dict.
Both now extract sessions_resp.json()['sessions'] before iterating, so
the assertions actually verify session presence.
The original TestAsyncCollaborationActivity test used the literal string 'test-source-agent' as the X-Source-Agent header value. That fails against a real backend for two compounding reasons: 1. /api/activities/timeline filters activities by accessible-agent ownership (routers/activities.py:47-50). Activities owned by a non-existent source agent are silently hidden, so the test could never observe the collaboration activity it created. 2. Even if the source name resolved, using the same name as the target would trigger the SELF-EXEC-001 short-circuit in chat.py:790 that classifies the call as activity_type=self_task instead of agent_collaboration, so the agent_collaboration filter would still match nothing. The test now picks the first real agent from /api/agents that is not the target, and pytest.skips when no second agent is available. The production constraints are documented inline so this doesn't get re-broken.
|
Pushed
The endpoint returns
Both now extract
The test now picks the first real agent from Live result: |
|
Please either:
See |
|
Hey @AndriiPasternak31 — this PR is targeting |
|
Closing as superseded by #320. After the second rebase, this branch carried only test-only follow-up against the unified async path that #320 shipped. On reflection:
Closing without merge. |
Summary
Test-only follow-up to #320, which superseded the original
chat.pyrefactor.After #320 landed the unified async path with a different implementation (
_run_async_task_with_persistence+slot_already_held=True), the production code changes originally on this branch were dropped during the second rebase. What remains on top ofmainis a small set of parity tests plus one shared helper that cover behaviors not exercised byTestAsyncModeUnifiedExecutorfrom #320.Scope
Production code: none. (
grep "_execute_task_background" src/returns zero hits as of #320.)Tests added (
tests/test_parallel_task.py):TestAsyncSessionPersistence(3 tests) — asyncsave_to_session=Truecreates user+assistant messages, explicitchat_session_idis honored, andchat_response_readyis broadcast (verified via session existence).TestAsyncCollaborationActivity(1 test) — async task withX-Source-Agentheader creates and completes the collaboration activity end-to-end. Polls/api/activities/timelinewith a bounded retry instead of a fixed sleep.TestAsyncSafetyNet(1 test) — execution record is created before the background task is spawned (no silent launch failure). Marked@pytest.mark.requires_agent.Helper added (
tests/testing_utils/assertions.py):poll_execution_until_done(...)— shared polling helper for execution terminal status, used by the five new tests above. Documented as@pytest.mark.slow-only.Review feedback addressed
time.sleep(1)magic number inTestAsyncCollaborationActivity→ replaced with a bounded retry loop on the timeline endpoint (10s deadline, 0.5s interval).poll_execution_until_donebusy-poll concern → docstring now flags it as@pytest.mark.slow-only and warns against use from non-slow tests.TestAsyncSafetyNetmissing@pytest.mark.requires_agent→ added.execution_time_msregression andcontext_usedguard from the earlier review are no longer applicable — those lived in the droppedchat.pychanges; refactor(exec): route async /task through TaskExecutionService (#95) #320 handles both inTaskExecutionService.Test plan
pytest tests/test_parallel_task.py::TestAsyncSessionPersistence -vpytest tests/test_parallel_task.py::TestAsyncCollaborationActivity -vpytest tests/test_parallel_task.py::TestAsyncSafetyNet -vpytest tests/test_parallel_task.py::TestAsyncMode -v(regression — should still pass)Follow-up to #95 (closed by #320).