mirror of
https://github.com/myronblair/jarvis
synced 2026-07-28 00:34:35 -05:00
reactor.py: fix llm_call() silently skipping fallback for explicit provider requests, add /comms/sent/{id}/send endpoint for approving queued drafts
This commit is contained in:
+49
-10
@@ -130,18 +130,29 @@ async def handle_shell(payload: dict) -> dict:
|
|||||||
# ═══════════════════════════════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
async def llm_call(messages: list, provider: str = "claude", system: str = "") -> str:
|
async def llm_call(messages: list, provider: str = "claude", system: str = "") -> str:
|
||||||
if provider == "claude" and CLAUDE_API_KEY:
|
# Fixed 2026-07-07: previously, an explicitly-requested provider (e.g. "claude")
|
||||||
return await _claude_call(messages, system)
|
# called its API directly with no exception handling, so any failure (rate limit,
|
||||||
elif provider == "groq" and GROQ_API_KEY:
|
# depleted credits, outage) raised straight up instead of falling back to the other
|
||||||
return await _groq_call(messages, system)
|
# providers below. The fallback loop only ever ran for an unrecognized provider
|
||||||
elif provider == "ollama":
|
# string, which never happens in practice — so callers requesting "claude" got zero
|
||||||
return await _ollama_call(messages, system)
|
# real resilience. Now every explicit request tries its provider first, then falls
|
||||||
for p in ["groq", "ollama"]:
|
# through the remaining ones in order before giving up.
|
||||||
|
order = {"claude": ["claude", "groq", "ollama"],
|
||||||
|
"groq": ["groq", "ollama"],
|
||||||
|
"ollama": ["ollama"]}.get(provider, ["claude", "groq", "ollama"])
|
||||||
|
last_err = None
|
||||||
|
for p in order:
|
||||||
try:
|
try:
|
||||||
return await llm_call(messages, p, system)
|
if p == "claude" and CLAUDE_API_KEY:
|
||||||
except Exception:
|
return await _claude_call(messages, system)
|
||||||
|
elif p == "groq" and GROQ_API_KEY:
|
||||||
|
return await _groq_call(messages, system)
|
||||||
|
elif p == "ollama":
|
||||||
|
return await _ollama_call(messages, system)
|
||||||
|
except Exception as e:
|
||||||
|
last_err = e
|
||||||
continue
|
continue
|
||||||
raise RuntimeError("All LLM providers failed")
|
raise RuntimeError(f"All LLM providers failed (last error: {last_err})")
|
||||||
|
|
||||||
async def _claude_call(messages: list, system: str = "") -> str:
|
async def _claude_call(messages: list, system: str = "") -> str:
|
||||||
payload = {"model": CLAUDE_MODEL, "max_tokens": 4096, "messages": messages}
|
payload = {"model": CLAUDE_MODEL, "max_tokens": 4096, "messages": messages}
|
||||||
@@ -2785,5 +2796,33 @@ async def comms_sent_delete(sent_id: int):
|
|||||||
await db_execute("DELETE FROM email_sent WHERE id=%s", (sent_id,))
|
await db_execute("DELETE FROM email_sent WHERE id=%s", (sent_id,))
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
@app.post("/comms/sent/{sent_id}/send")
|
||||||
|
async def comms_sent_send(sent_id: int):
|
||||||
|
"""
|
||||||
|
Added 2026-07-07: sends a previously-composed queued draft. Compose always
|
||||||
|
created a draft (status='queued') for review, but there was no action anywhere
|
||||||
|
to actually send one — this closes that gap. handle_send_email() records its own
|
||||||
|
fresh row in email_sent (sent/failed), so the original queued draft row is removed
|
||||||
|
here once we've handed its content off, rather than leaving a stale duplicate.
|
||||||
|
"""
|
||||||
|
row = await db_fetchone(
|
||||||
|
"SELECT account, to_email, to_name, subject, body, triage_id FROM email_sent WHERE id=%s AND status='queued'",
|
||||||
|
(sent_id,)
|
||||||
|
)
|
||||||
|
if not row:
|
||||||
|
raise HTTPException(status_code=404, detail="Queued draft not found")
|
||||||
|
|
||||||
|
result = await handle_send_email({
|
||||||
|
"account": row["account"],
|
||||||
|
"to_email": row["to_email"],
|
||||||
|
"to_name": row["to_name"],
|
||||||
|
"subject": row["subject"],
|
||||||
|
"body": row["body"],
|
||||||
|
"triage_id": row["triage_id"],
|
||||||
|
})
|
||||||
|
|
||||||
|
await db_execute("DELETE FROM email_sent WHERE id=%s", (sent_id,))
|
||||||
|
return result
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
uvicorn.run("reactor:app", host=HOST, port=PORT, log_level="info", access_log=False)
|
uvicorn.run("reactor:app", host=HOST, port=PORT, log_level="info", access_log=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user