Files
agentic-mobile-control/tests/test_ai_planner_integration.py
q792602257andClaude Sonnet 5 61ff3b425d feat(agent-runtime): add LLM-driven AI Planner with dual-provider tool calling
Replaces the stub Planner's fixed describe_screen/[] behavior with a real
decision-maker: AIPlanner uses native tool/function calling (Anthropic or
OpenAI, pluggable via AI_PLANNER_PROVIDER) to select exactly one grounded
action per turn, with an explicit finish_task(success, reason) tool for
completion/failure instead of an ambiguous "no tool call" signal. Default
disabled (AI_PLANNER_ENABLED=false) and additive; TaskRunner falls back to
the existing stub Planner unchanged when disabled.

Amends CONSTITUTION.md's Perception Boundary with one narrow exception:
only the AI Planner may receive the current step's raw screenshot bytes
alongside Scene, for vision-grounded coordinate grounding. Also fixes a
latent gap in TaskRunner.run(): observe/plan exceptions are now caught per
iteration and turned into a failed task with a failure_reason, instead of
propagating uncaught.

openspec change: ai-planner-runtime.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 13:48:50 +08:00

57 lines
1.7 KiB
Python

from __future__ import annotations
import os
import pytest
from core.models import Bounds, Scene, SceneElement
from runtime.ai_planner import AIPlanner
from runtime.context import TaskContext
from runtime.planner_config import PlannerConfig
def _scene() -> Scene:
return Scene(
width=390,
height=844,
elements=[
SceneElement(id="send", type="button", text="Send", bounds=Bounds(300, 800, 60, 30)),
],
)
@pytest.mark.integration
def test_real_anthropic_ai_planner_selects_a_tool() -> None:
if not os.environ.get("ANTHROPIC_API_KEY"):
pytest.skip("ANTHROPIC_API_KEY is required for AI planner integration test")
try:
import anthropic # noqa: F401
except ImportError:
pytest.skip("anthropic SDK is not installed")
planner = AIPlanner(config=PlannerConfig(enabled=True, provider="anthropic", timeout=15.0))
context = TaskContext(task_id="task", goal="tap the send button")
steps = planner.plan(goal="tap the send button", scene=_scene(), context=context)
assert isinstance(steps, list)
assert len(steps) <= 1
@pytest.mark.integration
def test_real_openai_ai_planner_selects_a_tool() -> None:
if not os.environ.get("OPENAI_API_KEY"):
pytest.skip("OPENAI_API_KEY is required for AI planner integration test")
try:
import openai # noqa: F401
except ImportError:
pytest.skip("openai SDK is not installed")
planner = AIPlanner(config=PlannerConfig(enabled=True, provider="openai", timeout=15.0))
context = TaskContext(task_id="task", goal="tap the send button")
steps = planner.plan(goal="tap the send button", scene=_scene(), context=context)
assert isinstance(steps, list)
assert len(steps) <= 1