05-sep: [feat] streaming en bot OpenCode (prompt_async + entrega incremental como el terminal)
This commit is contained in:
@@ -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"⚙️ <i>{html.escape(corto)}</i>",
|
||||
"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 <code>/salir</code> "
|
||||
"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):
|
||||
|
||||
Reference in New Issue
Block a user