fix: mission task execution fails with AgentEvent attribute error (#482)

* fix: mission executor treating AgentEvent as dict causing task failures

The MCTaskExecutor used .get() on AgentEvent objects yielded by
router.run(), but AgentEvent uses attributes (.type, .content, .metadata)
not dict access. This caused 'AgentEvent object has no attribute get'
errors when running mission tasks.

* style: fix import sorting and line length in test files

* fix: resolve ruff lint errors in tools/registry.py

Move DEFAULT_TOOL_TIMEOUT constant after imports to fix E402 and
replace asyncio.TimeoutError with builtin TimeoutError (UP041).

* style: format test_gchat_adapter.py
This commit is contained in:
Rohit Kushwaha
2026-03-07 20:22:43 +05:30
committed by GitHub
parent eaca6e6976
commit e0fbceff52
4 changed files with 16 additions and 17 deletions

View File

@@ -9,12 +9,12 @@ import asyncio
import logging
from typing import Any
DEFAULT_TOOL_TIMEOUT = 60 # seconds
from pocketpaw.security import AuditSeverity, get_audit_logger
from pocketpaw.tools.policy import ToolPolicy
from pocketpaw.tools.protocol import ToolProtocol
DEFAULT_TOOL_TIMEOUT = 60 # seconds
logger = logging.getLogger(__name__)
@@ -156,7 +156,7 @@ class ToolRegistry:
log_result = result[:200] + "..." if len(result) > 200 else result
logger.debug(f"🔧 {name} result: {log_result}")
return result
except asyncio.TimeoutError:
except TimeoutError:
audit.log_tool_use(name, params, severity=severity, status="timeout")
logger.error(f"🔧 {name} timed out after {timeout}s")
return f"Error: Tool '{name}' timed out after {timeout}s"

View File

@@ -227,9 +227,7 @@ class TestGoogleChatAdapterErrorRecovery:
"""Exceptions during send are caught and don't propagate."""
adapter = GoogleChatAdapter()
mock_service = MagicMock()
mock_service.spaces().messages().create().execute.side_effect = Exception(
"API error"
)
mock_service.spaces().messages().create().execute.side_effect = Exception("API error")
adapter._chat_service = mock_service
msg = OutboundMessage(

View File

@@ -1,8 +1,9 @@
"""Tests for Signal Channel Adapter — Sprint 20."""
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from pocketpaw.bus.adapters.signal_adapter import SignalAdapter
from pocketpaw.bus.events import Channel, OutboundMessage
@@ -224,9 +225,7 @@ class TestSignalAdapterErrorRecovery:
"""HTTP 401/403 auth errors are logged but don't raise."""
adapter = SignalAdapter(phone_number="+1234567890")
adapter._http = AsyncMock()
adapter._http.post = AsyncMock(
return_value=MagicMock(status_code=401, text="Unauthorized")
)
adapter._http.post = AsyncMock(return_value=MagicMock(status_code=401, text="Unauthorized"))
msg = OutboundMessage(
channel=Channel.SIGNAL,
@@ -240,9 +239,7 @@ class TestSignalAdapterErrorRecovery:
"""HTTP 429 rate limit errors are logged but don't raise."""
adapter = SignalAdapter(phone_number="+1234567890")
adapter._http = AsyncMock()
adapter._http.post = AsyncMock(
return_value=MagicMock(status_code=429, text="Rate limited")
)
adapter._http.post = AsyncMock(return_value=MagicMock(status_code=429, text="Rate limited"))
msg = OutboundMessage(
channel=Channel.SIGNAL,
@@ -403,8 +400,10 @@ class TestSignalAdapterLifecycle:
bus.unsubscribe_outbound = MagicMock()
mock_http_client = AsyncMock(spec=httpx.AsyncClient)
with patch("httpx.AsyncClient", return_value=mock_http_client), \
patch.object(adapter, "_poll_loop", new_callable=AsyncMock):
with (
patch("httpx.AsyncClient", return_value=mock_http_client),
patch.object(adapter, "_poll_loop", new_callable=AsyncMock),
):
await adapter.start(bus)
await adapter.stop()

View File

@@ -5,9 +5,10 @@ botbuilder-core is mocked since it's an optional dependency.
import sys
from types import SimpleNamespace
import pytest
from unittest.mock import AsyncMock, MagicMock
import pytest
# Mock botbuilder before importing the adapter
mock_bb_core = MagicMock()
mock_bb_schema = MagicMock()
@@ -244,7 +245,8 @@ class TestTeamsAdapterErrorRecovery:
)
turn_ctx = SimpleNamespace(activity=activity)
# Exception propagates from _process_activity; the webhook handler catches it at the outer level
# Exception propagates from _process_activity;
# the webhook handler catches it at the outer level
with pytest.raises(RuntimeError, match="Bus error"):
await adapter._process_activity(turn_ctx)