fix(replay): câblage execution_mode supervised + seuil large fallback heartbeat
Deux corrections liées au scenario démo Urgence GHT (workflow lecture
multi-onglets + t2a_decision + pause_for_human + saisies dans Codage) :
1. Mode supervised propagé jusqu'au pipeline replay
---------------------------------------------------
Symptôme constaté ce 7 mai : Léa lit les onglets, t2a_decision tourne
(variable `dec` présente avec decision="FORFAIT_URGENCE"), mais la
pause_for_human est SKIPPÉE silencieusement et les saisies type_text
s'enchaînent dans le mauvais écran.
Cause : api_stream.py:2140 passait `params={}` codé en dur lors de la
création du replay_state. Conséquence : le code en aval qui lit
`replay_state.params.execution_mode` (api_stream.py:2964) avait toujours
le défaut "autonomous" → branche QW4 :
# Mode autonome sans safety_checks → skip (comportement legacy)
logger.info("pause_for_human ignorée (mode autonome)")
Modifications :
- RawReplayRequest gagne un champ `params: Optional[Dict[str, Any]]`
- start_raw_replay propage `request.params or {}` à _create_replay_state
- dag_execute.execute_windows force par défaut
`data['params']['execution_mode'] = 'supervised'` quand le frontend
ne précise rien (cas démo VWB → Windows). Override possible.
Conséquence : la pause_for_human du workflow Urgence déclenche bien la
PauseDialog VWB ("Décision : {{dec.decision_court}}"). Le médecin valide
ou annule avant que les saisies type_text ne s'exécutent dans Codage.
Note pour la démo réelle (post-aujourd'hui) : le scénario crédible
veut que Léa soit déclenchée depuis SON chat (port 5004), pas depuis
VWB. C'est un autre commit à venir — pour l'instant VWB suffit pour
le développement (cf. handoff session).
2. Seuil détection image tronquée élargi
----------------------------------------
Le seuil initial (height < 200 OR width < 400) ne capturait que les
cas extrêmes 2560x60 / 600x72. Mais le client envoie aussi 622x856
(Edge en fenêtre réduite ?) qui passait sous le radar. Élargi à
height < 800 OR width < 1200 — un écran moderne fait toujours ≥
1920x1080, donc le seuil est sain.
Sans ce fallback élargi, _resolve_target_sync recevait une image
trop petite pour matcher l'anchor → cascade VLM hallucinante.
This commit is contained in:
@@ -563,6 +563,11 @@ class RawReplayRequest(BaseModel):
|
|||||||
session_id: str = ""
|
session_id: str = ""
|
||||||
machine_id: Optional[str] = None # Machine cible (multi-machine)
|
machine_id: Optional[str] = None # Machine cible (multi-machine)
|
||||||
task_description: str = ""
|
task_description: str = ""
|
||||||
|
# Paramètres runtime du replay (lus dans replay_state.params côté pipeline).
|
||||||
|
# Notamment execution_mode : "autonomous" (défaut, pause_for_human skippée)
|
||||||
|
# ou "supervised" (pause_for_human bloque jusqu'à validation humaine via
|
||||||
|
# PauseDialog VWB). Cf. replay_engine.py / api_stream.py:2964.
|
||||||
|
params: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
|
|
||||||
class SingleActionRequest(BaseModel):
|
class SingleActionRequest(BaseModel):
|
||||||
@@ -2137,7 +2142,7 @@ async def start_raw_replay(request: RawReplayRequest):
|
|||||||
workflow_id=f"free_task:{task[:50]}",
|
workflow_id=f"free_task:{task[:50]}",
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
total_actions=len(actions),
|
total_actions=len(actions),
|
||||||
params={},
|
params=dict(request.params or {}),
|
||||||
machine_id=resolved_machine_id,
|
machine_id=resolved_machine_id,
|
||||||
actions=actions,
|
actions=actions,
|
||||||
)
|
)
|
||||||
@@ -4411,7 +4416,10 @@ async def resolve_target(request: ResolveTargetRequest):
|
|||||||
# par le dernier heartbeat avant la cascade _resolve_target_sync.
|
# par le dernier heartbeat avant la cascade _resolve_target_sync.
|
||||||
effective_w = request.screen_width
|
effective_w = request.screen_width
|
||||||
effective_h = request.screen_height
|
effective_h = request.screen_height
|
||||||
if img.height < 200 or img.width < 400:
|
# Seuil large : un écran moderne fait 2560x1600 ou plus. Tout en dessous
|
||||||
|
# de 1200x800 est suspect — bug client mss.monitors[1] qui crop sur
|
||||||
|
# barre des tâches (2560x60), Edge fenêtré (622x856), etc.
|
||||||
|
if img.height < 800 or img.width < 1200:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[RESOLVE_TARGET] Image client tronquée %dx%d (declared %dx%d) — "
|
"[RESOLVE_TARGET] Image client tronquée %dx%d (declared %dx%d) — "
|
||||||
"fallback heartbeat full screen",
|
"fallback heartbeat full screen",
|
||||||
|
|||||||
@@ -1082,6 +1082,15 @@ def execute_windows():
|
|||||||
if not data.get('session_id'):
|
if not data.get('session_id'):
|
||||||
data['session_id'] = 'agent_demo_user'
|
data['session_id'] = 'agent_demo_user'
|
||||||
|
|
||||||
|
# Forcer le mode supervisé : pause_for_human DÉCLENCHE au lieu d'être
|
||||||
|
# skippée. Le médecin valide la décision Léa avant que les saisies
|
||||||
|
# type_text ne s'exécutent dans l'onglet Codage. Crucial pour la démo
|
||||||
|
# GHT : Léa propose, humain valide, Léa finalise (cf. workflow Urgence).
|
||||||
|
# Sans ça, mode "autonomous" par défaut → pause skippée → saisies
|
||||||
|
# tentées sans validation → désordre visuel.
|
||||||
|
data.setdefault('params', {})
|
||||||
|
data['params'].setdefault('execution_mode', 'supervised')
|
||||||
|
|
||||||
# Injecter le machine_id pour le ciblage multi-machine.
|
# Injecter le machine_id pour le ciblage multi-machine.
|
||||||
# Cibler la machine Windows la plus récemment active (heartbeat last_activity)
|
# Cibler la machine Windows la plus récemment active (heartbeat last_activity)
|
||||||
# plutôt que la première dans l'ordre arbitraire renvoyé par /machines :
|
# plutôt que la première dans l'ordre arbitraire renvoyé par /machines :
|
||||||
|
|||||||
Reference in New Issue
Block a user