Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions tests/unit/agents/test_flash_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@
from artemis.context import ArtemisContext


@pytest.fixture(autouse=True)
def isolate_summarizer_model(monkeypatch):
"""Keep real summarizer behavior without constructing a provider client."""
model = Mock()
model.ainvoke = AsyncMock(
side_effect=AssertionError("Configure a model response before invoking the summarizer")
)
factory = Mock(return_value=model)
monkeypatch.setattr("artemis.agents.flash.summarizer.get_llm", factory)
monkeypatch.setattr("artemis.agents.flash.summarizer.get_google_llm", factory)


@pytest.fixture
def mock_context():
ctx = Mock(spec=ArtemisContext)
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/agents/test_flash_runner_ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@
)


@pytest.fixture(autouse=True)
def isolate_summarizer_model(monkeypatch):
"""Keep real summarizer behavior without constructing a provider client."""
model = Mock()
model.ainvoke = AsyncMock(
side_effect=AssertionError("Configure a model response before invoking the summarizer")
)
factory = Mock(return_value=model)
monkeypatch.setattr("artemis.agents.flash.summarizer.get_llm", factory)
monkeypatch.setattr("artemis.agents.flash.summarizer.get_google_llm", factory)


@pytest.fixture
def mock_context():
ctx = Mock(spec=ArtemisContext)
Expand Down
14 changes: 13 additions & 1 deletion tests/unit/agents/test_flash_scrub_edge.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"""

import json
from unittest.mock import Mock
from unittest.mock import AsyncMock, Mock

import pytest
from langchain_core.messages import AIMessage, HumanMessage, ToolMessage
Expand All @@ -30,6 +30,18 @@
from artemis.context import ArtemisContext


@pytest.fixture(autouse=True)
def isolate_summarizer_model(monkeypatch):
"""Keep real summarizer behavior without constructing a provider client."""
model = Mock()
model.ainvoke = AsyncMock(
side_effect=AssertionError("Configure a model response before invoking the summarizer")
)
factory = Mock(return_value=model)
monkeypatch.setattr("artemis.agents.flash.summarizer.get_llm", factory)
monkeypatch.setattr("artemis.agents.flash.summarizer.get_google_llm", factory)


@pytest.fixture
def mock_context():
ctx = Mock(spec=ArtemisContext)
Expand Down
15 changes: 14 additions & 1 deletion tests/unit/agents/test_flash_step_summarizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@
from artemis.sdk.builders import Builders


@pytest.fixture(autouse=True)
def isolate_summarizer_model(monkeypatch):
"""Keep real summarizer behavior without constructing a provider client."""
model = Mock()
model.ainvoke = AsyncMock(
side_effect=AssertionError("Configure a model response before invoking the summarizer")
)
factory = Mock(return_value=model)
monkeypatch.setattr("artemis.agents.flash.summarizer.get_llm", factory)
monkeypatch.setattr("artemis.agents.flash.summarizer.get_google_llm", factory)


@pytest.fixture
def mock_context():
ctx = Mock(spec=ArtemisContext)
Expand Down Expand Up @@ -834,13 +846,14 @@ def test_build_focus_context_drops_blank_fields_and_caps_reasoning_tail_intact()

def test_flash_config_and_builder():
"""Verify Flash profile configuration model and SDK builder fluent API."""
# This checks configuration values, not external provider credentials.
cfg = Builders.AgentConfig.with_flash_config(
max_turns=25,
explorer_mode="flash",
step_summarizer=True,
step_summarizer_model="gemini-2.5-flash-lite",
prune_history_xml=True,
).build()
).build(validate_profiles=False)

assert cfg.flash.max_turns == 25
assert cfg.flash.explorer_mode == "flash"
Expand Down
25 changes: 22 additions & 3 deletions tests/unit/mcp/test_mcp_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import json
import os
import shutil
import sqlite3
import tempfile
from types import SimpleNamespace
import uuid
Expand All @@ -34,6 +35,14 @@
from artemis.runtime import trace_store


@pytest.fixture(autouse=True)
def mock_spawn_watchdog(monkeypatch):
"""Fake runner processes must not leave live watchdogs after fixture teardown."""
watchdog = MagicMock()
monkeypatch.setattr("mcp_server.tools.task_runner._start_spawn_watchdog", watchdog)
return watchdog


@pytest.fixture
def temp_trace_env(monkeypatch):
temp_dir = tempfile.mkdtemp()
Expand Down Expand Up @@ -88,7 +97,9 @@ def test_mobile_run_task_invalid_model():
mobile_run_task(task_desc="test", conversation_id="conv-1", model="invalid_model")


def test_mobile_run_task_reserves_and_passes_global_queue_ticket(temp_trace_env):
def test_mobile_run_task_reserves_and_passes_global_queue_ticket(
temp_trace_env, mock_spawn_watchdog
):
process = MagicMock(pid=43210)
with (
patch(
Expand Down Expand Up @@ -117,11 +128,14 @@ def test_mobile_run_task_reserves_and_passes_global_queue_ticket(temp_trace_env)
assert popen.call_args.kwargs["env"]["ARTEMIS_DEVICE_QUEUE_TICKET"] == "queue-ticket-1"
assert popen.call_args.kwargs["env"]["ARTEMIS_TASK_INGRESS"] == "mcp"
status = trace_store.read_status(result["trace_id"])
mock_spawn_watchdog.assert_called_once_with(
result["trace_id"], 43210, "queue-ticket-1", "conv-1"
)
assert status["queue_ticket"] == "queue-ticket-1"
assert status["device_serial"] is None


def test_mobile_run_task_with_device_serial(temp_trace_env):
def test_mobile_run_task_with_device_serial(temp_trace_env, mock_spawn_watchdog):
process = MagicMock(pid=54321)
with (
patch(
Expand Down Expand Up @@ -158,6 +172,9 @@ def test_mobile_run_task_with_device_serial(temp_trace_env):
ingress="mcp",
device_id="pixel-11-pro-001",
)
mock_spawn_watchdog.assert_called_once_with(
result["trace_id"], 54321, "queue-ticket-dev", "conv-2"
)
assert result["device_serial"] == "pixel-11-pro-001"
cmd = popen.call_args.args[0]
assert "--device-serial" in cmd
Expand Down Expand Up @@ -370,7 +387,9 @@ async def test_mobile_get_device_state_hierarchy_without_ocr():


@pytest.mark.asyncio
async def test_mobile_inspect_trace_invalid_action():
async def test_mobile_inspect_trace_invalid_action(temp_trace_env):
# The database precondition must not depend on a previous local task run.
sqlite3.connect(os.path.join(temp_trace_env, "data_engine.db")).close()
res = await mobile_inspect_trace(action="invalid_action", trace_id="trace-123")
assert "error" in res
assert "not supported" in res["message"]
Expand Down