Files
matchmaking-v2/app/a2a/tasks.py
raulgupta 89ca9ad647 Initial commit: matchmaking-v2 on-demand multi-board job-search agent
On-demand Scout service (replaces the nightly aggregator):
- FastAPI agent-mesh service; card name "matchmaking-service" (HTTP /a2a/tasks
  + Redis-stream worker matching the sibling-service pattern)
- run_search: parallel multi-board sweep (Naukri/blackfalcondata + Foundit +
  LinkedIn), city-filtered at the board, cheapest-per-result first
- per-board adapters + normalizers -> ScoutJob with rich read-only details and
  offsite apply links; recall mode + MVQ guard
- result cache for dev replay ($0); per-board cost knobs; retry-on-5xx
- research/: engine design, board cost economics, India-actor shortlist, POC
2026-06-18 19:22:03 +05:30

61 lines
2.0 KiB
Python

"""A2A task endpoint — the single HTTP entry the orchestrator calls per action.
Collects the messages a Session pushes and returns them; the orchestrator forwards
each to the frontend WebSocket. (Same proven adapter as the rest of the mesh.)
"""
import logging
from uuid import uuid4
from fastapi import APIRouter, Depends
from pydantic import BaseModel, Field
from app.a2a.auth import verify_a2a_key
from app.agent.session import MatchmakingAgentSession
logger = logging.getLogger(__name__)
router = APIRouter()
class TaskRequest(BaseModel):
task_id: str = Field(default_factory=lambda: str(uuid4()))
action: str = ""
params: dict = Field(default_factory=dict)
user_id: str = ""
user_context: dict | None = None
session_start: bool = False
class TaskCollector:
"""WebSocket-shaped sink that captures pushed messages into a list."""
def __init__(self):
self.messages: list[dict] = []
async def accept(self):
pass
async def send_json(self, data: dict):
self.messages.append(data)
@router.post("/a2a/tasks")
async def handle_a2a_task(req: TaskRequest, _token: str = Depends(verify_a2a_key)):
collector = TaskCollector()
session = MatchmakingAgentSession(websocket=collector, user_id=req.user_id)
params = {**req.params}
if req.user_context:
params["user_context"] = req.user_context
try:
if req.session_start:
await session.on_session_start(params)
elif req.action:
await session.on_user_action(req.action, params)
else:
return {"task_id": req.task_id, "status": "error", "messages": [], "error": "No action or session_start"}
return {"task_id": req.task_id, "status": "completed", "messages": collector.messages}
except Exception as e: # noqa: BLE001
logger.error("A2A task %s failed: %s", req.task_id, e, exc_info=True)
return {"task_id": req.task_id, "status": "error", "messages": collector.messages, "error": str(e)}