refactor(perception): replace XML length heuristic with VLM screenshot verification

This commit is contained in:
2026-04-27 11:41:51 +02:00
parent 714c914432
commit a2a4a75603
3 changed files with 38 additions and 7 deletions

View File

@@ -381,7 +381,7 @@ class GoalExecutor:
else:
# For interactions (like, follow) or unknown goals, use XML delta + semantic verify
if ui_changed:
verification = engine.verify_success(action, post_xml)
verification = engine.verify_success(action, post_xml, device=self.device)
if verification is True:
action_success = True
logger.info(f"✅ [GOAP Step] Interaction '{action}' successful.")

View File

@@ -77,9 +77,9 @@ class ActionMemory:
self._last_click_context = None
def verify_success(self, intent: str, pre_click_xml: str, post_click_xml: str) -> Optional[bool]:
def verify_success(self, intent: str, pre_click_xml: str, post_click_xml: str, device=None) -> Optional[bool]:
"""
Structural verification: Did the UI actually change after the click?
Structural and Visual verification: Did the UI actually change after the click?
"""
# Specific check for explore grid
if "first image in explore grid" in intent or "grid item" in intent:
@@ -88,17 +88,48 @@ class ActionMemory:
if "explore_action_bar" in post_click_xml and "row_feed_button_like" not in post_click_xml:
return None # Still on grid, inconclusive
# State toggles (like, save, follow) rarely change XML length by > 50 chars
# State toggles (like, save, follow) rarely change XML length predictably
state_toggles = ["like", "save", "follow", "heart"]
if any(t in intent.lower() for t in state_toggles):
if device:
logger.info(f"👁️ [ActionMemory] Handing over verification for '{intent}' to VLM visual analysis...")
from GramAddict.core.perception.semantic_evaluator import SemanticEvaluator
evaluator = SemanticEvaluator()
# Ask VLM to be the absolute source of truth
prompt = (
f"The user just attempted to perform the action: '{intent}'. "
f"Look at the current screen carefully. Was the action successful? "
f"If the intent was 'follow', does the button now indicate 'Following' or 'Requested'? "
f"If it was 'like', is the heart icon clearly active/red? "
f"If the screen shifted completely to a profile when you just wanted to like/follow from a feed, it FAILED. "
f"Answer ONLY with the word YES or NO."
)
try:
screenshot = device.screenshot_b64()
response = evaluator._query_vlm(prompt, screenshot)
if response and "yes" in response.lower() and "no" not in response.lower():
logger.debug(f"🧠 [ActionMemory] VLM visually confirmed success for '{intent}'.")
return True
else:
logger.warning(f"⚠️ [ActionMemory] VLM visual verification FAILED for '{intent}'. VLM replied: '{response}'")
return False
except Exception as e:
logger.error(f"Failed to query VLM for visual verification: {e}")
# Fallthrough to structural delta if VLM crashes
# Fallback to structural delta if no device or VLM fails
diff = abs(len(pre_click_xml) - len(post_click_xml))
if diff > 1000:
logger.warning(f"⚠️ [ActionMemory] Massive structural shift ({diff} chars) for state-toggle '{intent}'. Navigated away by mistake? Verification FAIL.")
return False
if diff > 0:
logger.debug(f"🧠 [ActionMemory] State toggle detected for '{intent}'. Verification PASS.")
logger.debug(f"🧠 [ActionMemory] Structural delta detected for '{intent}'. Verification PASS.")
return True
if abs(len(pre_click_xml) - len(post_click_xml)) > 50:
logger.debug(f"🧠 [ActionMemory] Structural change detected for '{intent}'. Verification PASS.")
return True

View File

@@ -180,11 +180,11 @@ class TelepathicEngine:
def decay_click(self, intent: str = None):
self._memory.reject_click(intent) # Alias to reject
def verify_success(self, intent: str, post_click_xml: str) -> bool:
def verify_success(self, intent: str, post_click_xml: str, device=None) -> bool:
pre_click_xml = ""
if self._memory._last_click_context:
pre_click_xml = self._memory._last_click_context.get("xml_context", "")
return self._memory.verify_success(intent, pre_click_xml, post_click_xml)
return self._memory.verify_success(intent, pre_click_xml, post_click_xml, device=device)
# ──────────────────────────────────────────────
# Semantic Evaluator Delegation