import type { Router } from "express"; import { z } from "zod"; import { getLocalAgentContext } from "../context/localContext.js"; import type { OpencodeRuntimeAdapter } from "../runtime/opencode.js"; import { readPurpose, type SessionMetadataStore } from "../sessions/metadataStore.js"; import type { ChatRunState } from "./chatRunState.js"; const id = z.string().regex(/^msg_[a-f0-9]{32}$/); const update = z.object({ delivery: z.enum(["steer", "queue"]) }).strict(); export function registerResponseInputRoutes(router: Router, options: { runtime: OpencodeRuntimeAdapter; sessionMetadataStore: SessionMetadataStore; runState: ChatRunState; }) { for (const method of ["get", "patch"] as const) { router[method](method === "get" ? "/session/:session_id/inputs" : "/session/:session_id/inputs/:input_id", async (req, res) => { const sessionId = String(req.params.session_id); try { const record = await options.sessionMetadataStore.get(getLocalAgentContext(req), sessionId); if (!record || readPurpose(record) === "task_execution") { res.status(404).json({ message: "session not found" }); return; } if (method === "get") { res.json({ items: await options.runtime.listPendingUserInputs(sessionId) }); return; } const inputId = id.parse((req.params as Record).input_id); const { delivery } = update.parse(req.body); const input = await options.runtime.updatePendingUserInput(sessionId, inputId, delivery); options.runState.activeRuns.get(sessionId)?.inputs?.observe("session.inbox.delivery.changed", { inboxID: inputId, delivery }); res.json(input); } catch (error) { if (error instanceof z.ZodError) { res.status(400).json({ message: "invalid input delivery" }); return; } const status = error && typeof error === "object" && "status" in error ? error.status : undefined; res.status(status === 404 || status === 409 ? 409 : 503).json({ message: status === 404 || status === 409 ? "Message has already been consumed or is unavailable" : "Input inbox is unavailable" }); } }); } }