diff --git a/vps_opencode_bot/opencode_bot.py b/vps_opencode_bot/opencode_bot.py index 4c8ec80..5d669e6 100644 --- a/vps_opencode_bot/opencode_bot.py +++ b/vps_opencode_bot/opencode_bot.py @@ -376,6 +376,8 @@ def ok_sesion(chat): def procesar_texto(chat, texto): + """Envia la peticion de forma asincrona y entrega el resultado por partes + (streaming), para que el usuario vea progreso como en el terminal.""" sid, err = ok_sesion(chat) if not sid: enviar(chat, f"❌ No hay sesión OpenCode disponible: {err}") @@ -384,15 +386,68 @@ def procesar_texto(chat, texto): modelo = st.get("model") stop = typing(chat) t0 = int(time.time() * 1000) - try: - data, err = enviar_mensaje(sid, texto, modelo=modelo) - finally: + + payload = {"parts": [{"type": "text", "text": texto}]} + if modelo: + payload["model"] = { + "providerID": modelo.get("providerID"), + "modelID": modelo.get("id"), + } + code, resp = oc_post(f"/session/{sid}/prompt_async", payload, timeout=40) + if code not in (200, 204): stop.set() - if data is None: - enviar(chat, f"❌ Error del servidor OpenCode: {err}") + enviar(chat, f"❌ Error al lanzar OpenCode: {resp}") return - rtexto, _ = extraer_respuesta(data) - # ficheros tocados en este turno + + vistos_texto = set() + vistos_tool = set() + comienzo = time.time() + terminado = False + while time.time() - comienzo < 900: + time.sleep(3) + code, hist = oc_get(f"/session/{sid}/message?limit=4") + if code == 200 and isinstance(hist, list): + for item in reversed(hist[-4:]): + info = item.get("info") or {} + if info.get("role") != "assistant": + continue + for p in item.get("parts") or []: + t = p.get("type") + pid = p.get("id") or "" + if t == "text" and p.get("text") and pid not in vistos_texto: + vistos_texto.add(pid) + enviar(chat, formatear_html(p["text"])) + elif t == "tool" and pid not in vistos_tool: + vistos_tool.add(pid) + comando = ((p.get("state") or {}).get("input") + or {}).get("command") + if comando: + corto = comando.strip().replace("\n", " ")[:90] + try: + import requests as _rq + _rq.post(f"{API}/sendMessage", + data={"chat_id": chat, "text": + f"⚙️ {html.escape(corto)}", + "parse_mode": "HTML"}, + timeout=10) + except Exception: + pass + # fin del turno: la sesion deja de estar busy (tras un margen inicial) + code2, sts = oc_get("/session/status", timeout=10) + transcurrido = time.time() - comienzo + if (code2 == 200 and isinstance(sts, dict) + and sts.get(sid, {}).get("type") != "busy" + and transcurrido >= 5): + terminado = True + break + + stop.set() + if not terminado: + enviar(chat, "⏰ La tarea está tardando demasiado. Usa /salir " + "para cortarla y empezar de nuevo.") + return + + # ficheros tocados en el turno adjuntos = [] try: code, hist = oc_get(f"/session/{sid}/message?limit=8") @@ -401,14 +456,10 @@ def procesar_texto(chat, texto): if os.path.isfile(r)] except Exception as e: log(f"adjuntos error: {e}") - if rtexto: - enviar(chat, formatear_html(rtexto)) if adjuntos: enviar(chat, f"📎 {len(adjuntos)} fichero(s) del turno:") for ruta in adjuntos[:6]: enviar_doc(chat, ruta) - if not rtexto and not adjuntos: - enviar(chat, "🤔 (sin respuesta de texto. Revisa la sesión en el TUI)") def cambiar_repo(chat, slug):