fix(stream): robustesse proxy VWB→streaming + ciblage textuel pour démo UHCD

dag_execute.py /execute-windows :
- Bearer token sur appels VWB→streaming (machines, replay/raw).
  Sans cela : 401 Unauthorized et le workflow ne démarre pas.
- Auto-injection session_id='agent_demo_user' si absent.
  Sans cela : /replay/raw bascule sur l'auto-détection sess_* et lève
  "Aucune session Agent V1 active" après tout restart du streaming server.
- Propagation by_text dans target_spec pour ciblage textuel
  (résolution hybrid_text_direct côté executor) — utile quand
  deux numéros se ressemblent visuellement (ex 25003284 vs 2500341).

t2a_decision.py : prompt enrichi avec decision_court (UHCD / Forfait
Urgences) + 3 critères PMSI (preuve_critereN + critereN_valide booléen)
pour piloter case-à-cocher dans l'arbre décisionnel. num_predict=1500,
num_ctx=16384.

resolve_engine.py : un drift trop grand bascule sur les coords
enregistrées (fallback_recorded_coords, resolved=True) au lieu de
rejeter la résolution. Permet au replay de continuer en cas de scroll
plutôt que de s'arrêter net.

workflows.db : by_text='25003284' sur le step de sélection patient
du workflow Urgence (démo GHT Sud 95).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dom
2026-05-01 15:52:22 +02:00
parent 8817f527e7
commit b584bbabc3
4 changed files with 39 additions and 15 deletions

View File

@@ -972,6 +972,13 @@ def execute_windows():
anchor_id,
)
# Propagation du by_text (ciblage textuel prioritaire sur template)
_by_text = params.get('by_text', '')
if _by_text:
action['by_text'] = _by_text
if 'target_spec' in action:
action['target_spec']['by_text'] = _by_text
# Mapper le bouton selon le type de clic VWB
if vwb_type == 'double_click_anchor':
action['button'] = 'double'
@@ -1043,11 +1050,26 @@ def execute_windows():
# Sinon, retirer les actions fichiers du flux principal
data['actions'] = non_file_actions
# Token Bearer pour le streaming server (auth obligatoire)
_stream_token = os.environ.get('RPA_API_TOKEN', '')
_stream_headers = {'Authorization': f'Bearer {_stream_token}'} if _stream_token else {}
# L'agent Windows poll sous session "agent_demo_user" (= agent_{user_id}, user_id="demo_user")
# On injecte directement dans cette session pour éviter le transfer cross-session
# et pour que /replay/raw ne tente pas l'auto-détection d'une session "sess_*"
# (qui échoue avec "Aucune session Agent V1 active" si l'agent n'a pas créé de session V1).
if not data.get('session_id'):
data['session_id'] = 'agent_demo_user'
# Injecter le machine_id pour le ciblage multi-machine
# Chercher la première machine Windows connectée si pas spécifié
if 'machine_id' not in data or not data.get('machine_id'):
try:
machines_resp = req.get('http://localhost:5005/api/v1/traces/stream/machines', timeout=3)
machines_resp = req.get(
'http://localhost:5005/api/v1/traces/stream/machines',
headers=_stream_headers,
timeout=3,
)
if machines_resp.ok:
machines = machines_resp.json().get('machines', [])
for m in machines:
@@ -1062,6 +1084,7 @@ def execute_windows():
resp = req.post(
'http://localhost:5005/api/v1/traces/stream/replay/raw',
json=data,
headers=_stream_headers,
timeout=30,
)
return jsonify(resp.json()), resp.status_code