Files
UHD_Media_Tool/apps/server/src/modules/websearch/routes.ts
T
rootandClaude Opus 5.5 d53df25fc8 feat(agent): web.search / web.fetch via Brave Search (WEB-1)
- adapters/websearch: Brave client (X-Subscription-Token, error classes),
  result normalization with redaction/truncation, SSRF guard, HTML→text fetch
  (10s, 512KB, text/html|text/plain only)
- modules/websearch: 10-min PG cache (region websearch), cross-process
  per-minute limit, web.fetch allowlist = URLs from the caller's latest
  web.search; POST /websearch/test
- settings.agent.webSearch (key write-only → secret_ref); settings card
  under Agent; web.* offered to the model only when enabled, plus a system
  prompt rule; outputs marked untrusted
- capability count 27 → 29; e2e E13; runbook docs/runbook/websearch.md

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 00:14:08 +08:00

30 lines
1.3 KiB
TypeScript

import { createRoute } from "@hono/zod-openapi";
import { Api, apiResponse } from "@umt/contracts";
import { requireScope } from "../../http/auth.ts";
import type { ModuleApp } from "../types.ts";
import type { WebSearchService } from "./service.ts";
// POST /websearch/test:设置页「测试」按钮,用已保存的 Key 查一次;失败不抛 4xx,结果里给 ok=false 与原因
export function registerWebSearchRoutes(app: ModuleApp, svc: () => WebSearchService) {
const def = Api.websearch.test;
const r = createRoute({
method: def.method,
path: def.path,
summary: def.summary,
tags: ["websearch"],
middleware: [requireScope(def.scope)] as never,
request: { body: { content: { "application/json": { schema: def.body as never } }, required: true } },
responses: {
200: { description: def.summary, content: { "application/json": { schema: apiResponse(def.response) } } },
},
});
// biome-ignore lint/suspicious/noExplicitAny: 路由泛型在封装里擦除,入参已由 zod-openapi 校验
app.openapi(r, (async (c: any) => {
const body = c.req.valid("json") as { query?: string };
const data = def.response.parse(await svc().test(body.query));
return c.json({ ok: true, data }, 200);
// biome-ignore lint/suspicious/noExplicitAny: 同上
}) as any);
}