fix(perception): complete bug 5,6,7,8,10 fixes
- Resolved Bug #5: Fixed list vs str parsing in ResonanceEvaluator - Resolved Bug #6: Use 'should_like' key for vibe score - Resolved Bug #7: Guard TelepathicEngine against 'Follow' nodes for post media - Resolved Bug #8: Implemented failed_bounds exclusion loop breaker in PerfectSnapping - Resolved Bug #10: Corrected available_actions string parsing - Validated with E2E regression suite (100% green)
This commit is contained in:
@@ -49,16 +49,26 @@ class ResonanceEvaluatorPlugin(BehaviorPlugin):
|
||||
tele = ctx.cognitive_stack.get("telepathic")
|
||||
if tele:
|
||||
logger.info("✨ [Resonance] Performing visual vibe check...")
|
||||
persona_interests = getattr(ctx.configs.args, "persona_interests", [])
|
||||
|
||||
# BUG 5 Fix: Read target_audience or persona_interests
|
||||
raw_interests = getattr(ctx.configs.args, "persona_interests", "")
|
||||
if not raw_interests:
|
||||
raw_interests = getattr(ctx.configs.args, "target_audience", "")
|
||||
|
||||
if isinstance(raw_interests, list):
|
||||
persona_interests = [str(i).strip() for i in raw_interests if str(i).strip()]
|
||||
else:
|
||||
persona_interests = [i.strip() for i in str(raw_interests).split(",") if i.strip()]
|
||||
|
||||
vibe = tele.evaluate_post_vibe(ctx.device, persona_interests)
|
||||
if vibe is None:
|
||||
logger.warning(
|
||||
"✨ [Resonance] VLM vibe check returned None (truncated JSON?). Keeping neutral score."
|
||||
)
|
||||
else:
|
||||
vibe_score = vibe.get("quality_score", 5) / 10.0
|
||||
if vibe.get("matches_niche"):
|
||||
vibe_score = min(1.0, vibe_score + 0.2)
|
||||
# BUG 6 Fix: VLM returns {"should_like": true/false}, not "quality_score"
|
||||
should_like = vibe.get("should_like", False)
|
||||
vibe_score = 1.0 if should_like else 0.2
|
||||
res_score = (res_score * 0.3) + (vibe_score * 0.7)
|
||||
|
||||
ctx.shared_state["res_score"] = res_score
|
||||
|
||||
@@ -310,7 +310,7 @@ class ScreenIdentity:
|
||||
if "back" in desc_lower:
|
||||
actions.append("tap back button")
|
||||
if any("follow" in e.get("text", "").lower() for e in clickable_elements):
|
||||
actions.append("tap 'Follow' button")
|
||||
actions.append("tap follow button")
|
||||
|
||||
if screen_type == ScreenType.OWN_PROFILE or screen_type == ScreenType.OTHER_PROFILE:
|
||||
if "message" in desc_lower or "nachricht" in desc_lower:
|
||||
|
||||
@@ -136,6 +136,7 @@ def align_active_post(device):
|
||||
aligned = False
|
||||
attempts = 0
|
||||
max_attempts = 5 # Increased for structural retry loop
|
||||
failed_bounds = set()
|
||||
|
||||
# Intents for structural discovery
|
||||
intents = [
|
||||
@@ -156,7 +157,9 @@ def align_active_post(device):
|
||||
|
||||
target_node = None
|
||||
for intent in intents:
|
||||
target_node = telepath.find_best_node(xml, intent, min_confidence=0.35, device=device, track=False)
|
||||
target_node = telepath.find_best_node(
|
||||
xml, intent, min_confidence=0.35, device=device, track=False, exclude_bounds=list(failed_bounds)
|
||||
)
|
||||
if target_node:
|
||||
break
|
||||
|
||||
@@ -164,9 +167,11 @@ def align_active_post(device):
|
||||
original_attribs = target_node.get("original_attribs", {})
|
||||
bounds = original_attribs.get("bounds")
|
||||
|
||||
bounds_str = ""
|
||||
# If bounds is a tuple from SpatialNode.to_dict()
|
||||
if isinstance(bounds, (tuple, list)) and len(bounds) == 4:
|
||||
left, t, r, b = bounds
|
||||
bounds_str = f"[{left},{t}][{r},{b}]"
|
||||
else:
|
||||
# Fallback to string parsing
|
||||
if not bounds:
|
||||
@@ -174,6 +179,7 @@ def align_active_post(device):
|
||||
m = re.match(r"\[(\d+),(\d+)\]\[(\d+),(\d+)\]", str(bounds))
|
||||
if m:
|
||||
left, t, r, b = map(int, m.groups())
|
||||
bounds_str = f"[{left},{t}][{r},{b}]"
|
||||
else:
|
||||
logger.warning(f"📐 [Alignment] Could not parse bounds: {bounds}")
|
||||
continue
|
||||
@@ -184,6 +190,7 @@ def align_active_post(device):
|
||||
h = info.get("displayHeight", 2400)
|
||||
if t > h * 0.85:
|
||||
logger.debug(f"📐 [Alignment] Rejecting node at y={t} (too low, likely bottom bar)")
|
||||
failed_bounds.add(bounds_str)
|
||||
continue
|
||||
|
||||
header_y = (t + b) // 2
|
||||
|
||||
@@ -54,10 +54,14 @@ class TelepathicEngine:
|
||||
# ──────────────────────────────────────────────
|
||||
|
||||
def find_best_node(
|
||||
self, xml_string: str, intent_description: str, device=None, track: bool = True, **kwargs
|
||||
self,
|
||||
xml_string: str,
|
||||
intent_description: str,
|
||||
device=None,
|
||||
track: bool = True,
|
||||
exclude_bounds: list[str] = None,
|
||||
**kwargs,
|
||||
) -> Optional[dict]:
|
||||
print("FIND_BEST_NODE CALLED")
|
||||
|
||||
"""
|
||||
Public facade for resolving a node.
|
||||
Translates Android UI bounds into standard GramAddict node dicts.
|
||||
@@ -73,6 +77,14 @@ class TelepathicEngine:
|
||||
# 2. Extract interactable candidates
|
||||
candidates = self._parser.get_clickable_nodes(root)
|
||||
|
||||
if exclude_bounds:
|
||||
filtered_candidates = []
|
||||
for c in candidates:
|
||||
bounds_str = f"[{c.x1},{c.y1}][{c.x2},{c.y2}]"
|
||||
if bounds_str not in exclude_bounds:
|
||||
filtered_candidates.append(c)
|
||||
candidates = filtered_candidates
|
||||
|
||||
# 3. Resolve intent against candidates
|
||||
best_node = self._resolver.resolve(intent_description, candidates, device=device)
|
||||
|
||||
@@ -80,6 +92,16 @@ class TelepathicEngine:
|
||||
logger.warning(f"No viable nodes found for intent: '{intent_description}'")
|
||||
return None
|
||||
|
||||
# 3.1 BUG 7 Fix: Semantic Guard for 'post media content'
|
||||
intent_lower = intent_description.lower()
|
||||
semantic_str = (
|
||||
(best_node.text or "") + " " + (best_node.content_desc or "") + " " + (best_node.resource_id or "")
|
||||
).lower()
|
||||
if "post media content" in intent_lower:
|
||||
if "follow" in semantic_str.replace("_", " "):
|
||||
logger.warning("🚫 [SpatialEngine] VLM selected a 'Follow' button for 'post media content'. Blocked.")
|
||||
return None
|
||||
|
||||
# 3.5 Following Button Guard
|
||||
if "follow" in intent_description.lower() and "unfollow" not in intent_description.lower():
|
||||
semantic = (
|
||||
|
||||
Reference in New Issue
Block a user