fix: normalize Pro action targets and bound no-progress recovery

This commit is contained in:
chenmingxuan committed 2026-09-23 01:34:10 +08:00
1 parent 2ec563c079
commit 9d6833f092
7 files changed
+225 -20

No files matched your search

+45 -3
View File
@@ -19,8 +19,10 @@ from uuid import uuid4
from langchain_core.messages import SystemMessage, ToolMessage
from langchain_core.tools import BaseTool
from artemis.core.tool_failure import is_tool_failure
from artemis.agents.validator.tool_declarations import normalize_coordinate_target
from artemis.config.settings import settings
from artemis.context import ArtemisContext
from artemis.core.tool_failure import is_tool_failure
from artemis.data_engine.trace import (
TraceSpan,
trace,
@@ -57,6 +59,11 @@ from artemis.utils.visualization import format_minimal_list_with_elements
logger = get_logger(__name__)
class OperatorNoProgressError(RuntimeError):
"""The model repeatedly returned no usable tool call; stop without device actions."""
DEFERRING_TOOLS = {
"ask_diagnoser",
"video_analyzer",
@@ -485,6 +492,8 @@ class OperatorNode:
native_thoughts = []
tool_limit_exceeded = False
plan_gate_bounced = False
no_progress_attempts = 0
no_progress_limit = settings.ARTEMIS_OPERATOR_MAX_NO_PROGRESS_ATTEMPTS
for iteration in range(max_iterations):
if iteration == max_iterations - 1:
@@ -568,8 +577,27 @@ class OperatorNode:
logger.error(f"Failed to parse function_call fallback: {e}")
if not response.tool_calls:
logger.warning("LLM stopped without calling any tool. Encouraging action.")
break
no_progress_attempts += 1
if no_progress_attempts >= no_progress_limit:
raise OperatorNoProgressError(
f"模型连续 {no_progress_attempts} 次未提供可执行的工具调用,"
"已停止任务以避免空转;未执行新的设备动作。"
)
logger.warning("LLM returned no tool call; requesting a concrete tool call.")
current_messages.append(response)
current_messages.append(
SystemMessage(
content=(
"No tool call was returned, so no device action occurred. "
"Use the available tool interface now, not a prose promise or JSON "
"inside text. Use an index from the current element list or "
"normalized coordinates with target_description. If blocked, "
"use an observation/diagnostic tool; do not invent a click or "
"claim success. This recovery has a limited retry budget."
)
)
)
continue
current_messages.append(response)
@@ -840,9 +868,20 @@ class OperatorNode:
break
if validation_errors:
no_progress_attempts += 1
if no_progress_attempts >= no_progress_limit:
raise OperatorNoProgressError(
f"模型连续 {no_progress_attempts} 次未提供可执行的工具调用,"
"工具参数校验仍失败;已停止任务,未执行被拒绝的设备动作。"
)
logger.warning("Some action calls failed validation. Feeding back to LLM.")
continue
no_progress_attempts = 0
else:
if no_progress_attempts:
raise OperatorNoProgressError(
"模型在本轮工具调用预算内未恢复有效调用,已停止任务以避免空转。"
)
tool_limit_exceeded = True
raw_thinking = "\n".join(raw_thoughts) if raw_thoughts else None
@@ -1122,6 +1161,9 @@ class OperatorNode:
straight from the indexed list); a coordinate pair carries only the
model's own ``target_description``. The two never mix.
"""
target = normalize_coordinate_target(target)
if isinstance(target, bool):
return None, "Error: Boolean values are not valid target indices."
if isinstance(target, (int, float)):
try:
target_int = int(target)
+2
View File
@@ -111,6 +111,8 @@ class Settings(BaseSettings):
ARTEMIS_VIDEO_ENABLED: bool = False
ARTEMIS_OUTPUTTER_ENABLED: bool = True
ARTEMIS_STEP_SUMMARIZER_ENABLED: bool = True
# Consecutive Pro responses without a valid tool call before failing the task.
ARTEMIS_OPERATOR_MAX_NO_PROGRESS_ATTEMPTS: int = Field(default=3, ge=1, le=20)
# Android ADB Connectivity
ADB_HOST: str | None = Field(default=DEFAULT_ADB_HOST)