Add dedicated quick question API
TestFlight / Build and upload (push) Successful in 1m42s

This commit is contained in:
2026-08-27 19:31:23 -07:00
parent 5f9fc82b86
commit 922172fc60
13 changed files with 269 additions and 44 deletions
+33 -1
View File
@@ -11,6 +11,7 @@ import { runMultiplex } from "./llm/multiplexer.js";
import { runMultiplexStream, type StreamEvent } from "./llm/streaming.js";
import { getAvailableChatTools, normalizeEnabledChatTools } from "./llm/chat-tools.js";
import { getModelCatalogSnapshot } from "./llm/model-catalog.js";
import { buildQuickQuestionMultiplexRequest } from "./llm/quick-question.js";
import { openaiClient } from "./llm/providers.js";
import { serializeProviderFields, toPrismaProvider } from "./llm/provider-ids.js";
import { exaClient } from "./search/exa.js";
@@ -205,6 +206,16 @@ const CompletionStreamBody = z
}
});
const QuickQuestionStreamBody = z.object({
provider: ProviderSchema,
model: z.string().min(1),
question: z.string().trim().min(1),
enabledTools: EnabledToolsSchema.optional(),
userLocation: z.string().trim().min(1).max(200).optional(),
temperature: z.number().min(0).max(2).optional(),
maxTokens: z.number().int().positive().optional(),
});
function mergeAttachmentsIntoMetadata(metadata: unknown, attachments?: ChatAttachment[]) {
if (!attachments?.length) return metadata as any;
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
@@ -1564,7 +1575,28 @@ export async function registerRoutes(app: FastifyInstance) {
};
});
// Streaming SSE endpoint.
// One-shot, non-persistent Quick Question SSE endpoint.
app.post("/v1/quick-questions/stream", async (req, reply) => {
requireAdmin(req);
const parsed = QuickQuestionStreamBody.safeParse(req.body);
if (!parsed.success) return app.httpErrors.badRequest(parsed.error.message);
const body = withRequestUserLocation(parsed.data, req);
reply.raw.writeHead(200, buildSseHeaders(typeof req.headers.origin === "string" ? req.headers.origin : undefined));
reply.raw.flushHeaders();
for await (const ev of runMultiplexStream(buildQuickQuestionMultiplexRequest(body))) {
writeSseEvent(reply, mapChatStreamEvent(ev));
}
if (!reply.raw.destroyed && !reply.raw.writableEnded) {
reply.raw.end();
}
return reply;
});
// General chat completion SSE endpoint.
app.post("/v1/chat-completions/stream", async (req, reply) => {
requireAdmin(req);