Files
next-tjwater-agent/src/routes/response-input-routes.ts
T
jiang 6a49d2209e feat(agent): unify MCP tools and adopt Responses delivery
Move project and host queries into native MCP with host-owned OAuth/context,
while retaining memory, skills, actions and publication plugins. Add nearby-model
queries and explicit chat/task/learning model defaults.

Adopt Responses HTTP/SSE and native steer/queue inbox delivery, preserving scoped
session ownership, pending input edits and investigation communication.

Disable local-provider discovery: Server /health allowed native vLLM to probe
/v1/models on port 8000. A native before/after regression prevents recurrence.

Validation: 170 focused Bun tests; service/plugin typechecks; native discovery,
provider-discovery and input-inbox smoke checks; no paid model inference.
2026-10-19 18:46:58 +08:00

38 lines
2.1 KiB
TypeScript

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<string, string>).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" });
}
});
}
}