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]>
This commit is contained in:
1 parent
40dd0e69e4
commit
d53df25fc8
32 files changed
+1854
-39
No files matched your search
@@ -0,0 +1,29 @@
|
||||
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);
|
||||
}
|
||||
Reference in new issue
Block a user