diff --git a/src/openjarvis/server/webhook_routes.py b/src/openjarvis/server/webhook_routes.py index 0c3db1da..845abce9 100644 --- a/src/openjarvis/server/webhook_routes.py +++ b/src/openjarvis/server/webhook_routes.py @@ -111,15 +111,114 @@ def create_webhook_router( from_number = params.get("From", "") body = params.get("Body", "") - # Dispatch to background — return TwiML immediately - task = asyncio.create_task( - asyncio.to_thread( - bridge.handle_incoming, - from_number, - body, - "twilio", - max_length=1600, + if not from_number or not body: + return Response( + content="", + media_type="application/xml", ) + + # Use bridge or app.state.channel_bridge + active_bridge = bridge or getattr( + request.app.state, "channel_bridge", None, + ) + + def _handle_twilio() -> None: + + # Send ack via Twilio API + try: + from twilio.rest import Client + + # Get creds from app state bindings + mgr = getattr( + request.app.state, "agent_manager", None, + ) + twilio_client = None + twilio_from = "" + if mgr: + for agent in mgr.list_agents(): + aid = agent.get("id", "") + for b in mgr.list_channel_bindings(aid): + if b.get("channel_type") == "twilio": + cfg = b.get("config", {}) + sid = cfg.get("account_sid", "") + tok = cfg.get("auth_token", "") + twilio_from = cfg.get( + "phone_number", "", + ) + if sid and tok: + twilio_client = Client( + sid, tok, + ) + break + + if twilio_client and twilio_from: + twilio_client.messages.create( + body=( + "Message received! " + "Working on it now..." + ), + from_=twilio_from, + to=from_number, + ) + except Exception as _e: + logger.warning("Twilio ack failed: %s", _e) + + # Process via bridge or agent directly + response = "" + if active_bridge: + response = active_bridge.handle_incoming( + from_number, body, "twilio", + max_length=1600, + ) + else: + # Direct agent fallback + try: + from openjarvis.agents.deep_research import ( + DeepResearchAgent, + ) + from openjarvis.server.agent_manager_routes import ( + _build_deep_research_tools, + ) + + engine = getattr( + request.app.state, "engine", None, + ) + if engine: + tools = _build_deep_research_tools( + engine=engine, model="", + ) + agent = DeepResearchAgent( + engine=engine, + model=getattr( + engine, "_model", "", + ), + tools=tools, + max_turns=5, + ) + result = agent.run(body) + response = result.content or "" + except Exception as _exc: + response = f"Error: {_exc}" + + # Send response via Twilio + if response and twilio_client and twilio_from: + try: + clean = _format_for_sms(response) + # Twilio SMS limit is 1600 chars + if len(clean) > 1500: + clean = clean[:1500] + "\n\n(truncated)" + twilio_client.messages.create( + body=clean, + from_=twilio_from, + to=from_number, + ) + except Exception as _e: + logger.warning( + "Twilio reply failed: %s", _e, + ) + + task = asyncio.create_task( + asyncio.to_thread(_handle_twilio), ) task.add_done_callback(_log_task_exception)