feat(workflow): variables runtime + extract_text serveur + t2a_decision LLM
Pipeline streaming étendu pour supporter des actions exécutées entièrement
côté serveur (jamais transmises à l'Agent V1) qui produisent des variables
réutilisables dans les steps suivants via templating {{var}} ou {{var.field}}.
== Variables d'exécution ==
- replay_state["variables"] : Dict[str, Any] initialisé vide à la création
- _resolve_runtime_vars() : résout {{var}} et {{var.field}} récursivement
dans str/dict/list. Variables absentes laissées intactes.
- /replay/next applique la résolution sur l'action AVANT toute interception
ou envoi à l'Agent V1.
== Boucle d'exécution serveur ==
- _SERVER_SIDE_ACTION_TYPES = {"extract_text", "t2a_decision"}
- /replay/next pop+execute en boucle ces actions jusqu'à trouver une action
visuelle (à transmettre Agent V1) ou un pause_for_human (qui bloque).
- Latence acceptable : t2a_decision = 5-10s côté serveur, l'Agent V1 attend
la réponse HTTP.
== Action extract_text ==
- Handler côté serveur réutilisant le dernier heartbeat (max 5s d'âge)
- core/llm/ocr_extractor.py : EasyOCR fr+en singleton + extract_text_from_image
- Stockage dans replay_state["variables"][output_var]
- Robuste : pas de heartbeat → variable = "" + log warning, pipeline continue
== Action t2a_decision ==
- core/llm/t2a_decision.py : refactor de demo_app.py query_model en module
importable. Prompt expert DIM T2A/PMSI, qwen2.5:7b par défaut (100% bench).
- Handler côté serveur appelle analyze_dpi(input_template_resolved)
- Stockage du JSON décision dans replay_state["variables"][output_var]
- Erreurs (Ollama down, parse) → variable = INDETERMINE + _error, pipeline continue
== VWB UI ==
- types.ts : nouveau type 't2a_decision' (icône 🧠 catégorie logic)
- extract_text refondu : needsAnchor=false, paramètre output_var (au lieu de
variable_name legacy — bridge accepte les deux pour compat)
- Bridge VWB→core : passthrough des deux types + paramètres préservés
== Tests ==
- tests/integration/test_t2a_extract.py : 25 tests verts
- templating runtime (8 tests)
- handler extract_text (3 tests, OCR mocké)
- handler t2a_decision (3 tests, analyze_dpi mocké)
- edge → action normalisée (2 tests)
- bridge VWB → core (5 tests)
- workflow chain extract→t2a→pause→clic (1 test)
Total branche : 82/82 verts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,8 +57,9 @@ VWB_ACTION_TO_CORE = {
|
||||
"scroll_to_anchor": "scroll",
|
||||
"visual_condition": "evaluate_condition",
|
||||
"screenshot_evidence": "screenshot",
|
||||
"extract_text": "extract_data",
|
||||
"pause_for_human": "pause_for_human", # passthrough — intercepté par api_stream /replay/next
|
||||
"extract_text": "extract_text", # passthrough — handler serveur OCR + variable
|
||||
"pause_for_human": "pause_for_human", # passthrough — intercepté par api_stream /replay/next
|
||||
"t2a_decision": "t2a_decision", # passthrough — handler serveur LLM T2A + variable
|
||||
}
|
||||
|
||||
|
||||
@@ -664,6 +665,20 @@ def _vwb_params_to_core(action_type: str, params: Dict[str, Any]) -> Dict[str, A
|
||||
elif action_type == "pause_for_human":
|
||||
core_params["message"] = params.get("message", "Validation requise")
|
||||
|
||||
elif action_type == "extract_text":
|
||||
# variable_name côté VWB → output_var côté core (compat avec
|
||||
# le catalogue VWB existant qui utilise variable_name)
|
||||
var = params.get("output_var") or params.get("variable_name") or "extracted_text"
|
||||
core_params["output_var"] = var
|
||||
if "paragraph" in params:
|
||||
core_params["paragraph"] = bool(params["paragraph"])
|
||||
|
||||
elif action_type == "t2a_decision":
|
||||
core_params["input_template"] = params.get("input_template", "")
|
||||
core_params["output_var"] = params.get("output_var", "t2a_result")
|
||||
if params.get("model"):
|
||||
core_params["model"] = params["model"]
|
||||
|
||||
return core_params
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user