feat: Phase 1 apprentissage — greffe TargetMemoryStore sur V4
Greffe minimale du mécanisme d'apprentissage persistant (Fiche #18, target_memory_store.py) sur le pipeline streaming V4 sans toucher à V3. Architecture (docs/PLAN_APPRENTISSAGE_LEA.md) : - Lookup mémoire AVANT la cascade résolution coûteuse OCR/template/VLM dans _resolve_target_sync → hit = <10ms, miss = overhead zéro - Record APRÈS validation post-condition (title_match strict) dans /replay/result → 2 succès → cristallisation par répétition - Single source of truth : l'agent remplit report.actual_position avec les coords effectivement cliquées, le serveur les lit directement. Pas de cache intermédiaire (option C du plan). Signature écran V4 : sha256(normalize(window_title))[:16]. Robuste aux données variables, faux positifs rattrapés par le post-cond qui décrémente la fiabilité via record_failure(). Fichiers : - agent_v0/server_v1/replay_memory.py : nouveau wrapper 316 lignes exposant compute_screen_sig/memory_lookup/record_success/failure, lazy-init du store, normalisation texte stable, garde sanity coords - agent_v0/server_v1/resolve_engine.py : lookup mémoire en tête de _resolve_target_sync (30 lignes) - agent_v0/server_v1/replay_engine.py : _create_replay_state stocke une copie slim des actions (sans anchor base64) pour retrouver le target_spec par current_action_index - agent_v0/server_v1/api_stream.py : 4 callers passent actions=..., record success/failure dans /replay/result lit actual_position du rapport (click-only), correction du commentaire Pydantic - agent_v0/agent_v1/core/executor.py : remplit result["actual_position"] après self._click(), transmis dans le report de poll_and_execute Tests : 56 E2E + Phase0 passent, zéro régression. Cycle Phase 1 validé en simulation : miss → record → miss → record → HIT au 3ème passage. Le deploy copy executor.py a une divergence pré-existante de 1302 lignes non committées — traité séparément lors du cleanup prochain. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1558,6 +1558,36 @@ def _resolve_target_sync(
|
||||
"""
|
||||
anchor_image_b64 = target_spec.get("anchor_image_base64", "")
|
||||
|
||||
# ===================================================================
|
||||
# PHASE 1 APPRENTISSAGE : Lookup mémoire persistante (Fiche #18)
|
||||
# ===================================================================
|
||||
# Avant TOUTE résolution coûteuse (OCR/template/VLM), on consulte la
|
||||
# mémoire persistante (TargetMemoryStore). Si cette cible a été résolue
|
||||
# avec succès ≥2 fois sur cet écran (fail_ratio < 30%), on retourne
|
||||
# directement les coordonnées mémorisées.
|
||||
#
|
||||
# Hit mémoire : <10ms (vs 300ms-15s de résolution)
|
||||
# Miss mémoire : aucun overhead, on continue la cascade normale
|
||||
#
|
||||
# Les coords stockées sont celles qui ont PASSÉ la post-condition
|
||||
# (title_match strict) lors des replays précédents. C'est la
|
||||
# cristallisation par répétition : Léa = stagiaire qui apprend.
|
||||
try:
|
||||
from .replay_memory import memory_lookup
|
||||
|
||||
_window_title = target_spec.get("window_title", "") or ""
|
||||
if _window_title:
|
||||
_mem_result = memory_lookup(
|
||||
window_title=_window_title,
|
||||
target_spec=target_spec,
|
||||
)
|
||||
if _mem_result:
|
||||
# Hit mémoire : on skip toute la cascade.
|
||||
# Les coordonnées sont sanity-checked dans memory_lookup().
|
||||
return _mem_result
|
||||
except Exception as _exc:
|
||||
logger.debug("Memory lookup skipped : %s", _exc)
|
||||
|
||||
# ===================================================================
|
||||
# V4 : Résolution pilotée par le plan pré-compilé
|
||||
# ===================================================================
|
||||
|
||||
Reference in New Issue
Block a user