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.
38 lines
2.1 KiB
TypeScript
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" });
|
|
}
|
|
});
|
|
}
|
|
}
|