diff --git a/scripts/course-matchmaking-routes.test.ts b/scripts/course-matchmaking-routes.test.ts index b7129d4..5252db2 100644 --- a/scripts/course-matchmaking-routes.test.ts +++ b/scripts/course-matchmaking-routes.test.ts @@ -10,6 +10,9 @@ globalThis.fetch = (async (input, init) => { if (body.action === "force_forbidden") { return new Response(JSON.stringify({ detail: "Invalid A2A auth token" }), { status: 403, headers: { "content-type": "application/json" } }); } + if (body.action === "agent_error") { + return new Response(JSON.stringify({ task_id: "a2a-task", status: "completed", messages: [{ type: "agent_error", action: "search_failed", data: { code: "job_boards_unavailable" } }] }), { status: 200, headers: { "content-type": "application/json" } }); + } return new Response(JSON.stringify({ task_id: "a2a-task", status: "completed", messages: [] }), { status: 200, headers: { "content-type": "application/json" } }); }) as typeof fetch; const app = serviceRoutes({ skipAuth: true }); @@ -33,6 +36,10 @@ try { const forbiddenResponse = await app.request("http://backend.test/matchmaking/a2a", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: "force_forbidden" }) }); assert.equal(forbiddenResponse.status, 502); assert.match(await forbiddenResponse.text(), /matchmaking service authentication failed/); + + const agentErrorResponse = await app.request("http://backend.test/matchmaking/a2a", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ action: "agent_error" }) }); + assert.equal(agentErrorResponse.status, 502); + assert.match(await agentErrorResponse.text(), /could not complete the search/); } finally { globalThis.fetch = originalFetch; } diff --git a/src/routes/services.ts b/src/routes/services.ts index 320ec87..65ffafc 100644 --- a/src/routes/services.ts +++ b/src/routes/services.ts @@ -1258,6 +1258,10 @@ export function serviceRoutes(options: { skipAuth?: boolean } = {}) { const userId = c.get("userId"); const body = await c.req.json().catch((): JsonObject => ({})); const { result } = await callMatchmakingA2a({ ...body, user_id: userId }, userId); + if (resultHasAgentError(result)) { + log.warn({ service: "matchmaking", action: body.action, userId }, "matchmaking agent reported task failure"); + throw new HTTPException(502, { message: "matchmaking service could not complete the search" }); + } // matchmaking-service emits canonical GrowEvents itself. The gateway is a // transport proxy only, avoiding a second event for the same action. return c.json(result);