fix(ai): enable Anthropic browser-direct model access

This commit is contained in:
tianma-if committed 2026-10-20 01:16:48 +08:00
1 parent c25fdf68e5
commit b085599af2
4 files changed
+23 -1

No files matched your search

+1 -1
View File
@@ -23,7 +23,7 @@ export const createClientAiModel = (config: {
}) => {
switch (config.provider) {
case "anthropic":
return createAnthropic({ baseURL: config.baseUrl, apiKey: config.apiKey, fetch: config.fetch })(config.modelId);
return createAnthropic({ baseURL: config.baseUrl, apiKey: config.apiKey, fetch: config.fetch, headers: { "anthropic-dangerous-direct-browser-access": "true" } })(config.modelId);
case "google":
return createGoogle({ baseURL: config.baseUrl, apiKey: config.apiKey, fetch: config.fetch })(config.modelId);
default:
@@ -14,6 +14,7 @@ export const discoverAiModels = async (
if (config.provider === "anthropic") {
headers.set("x-api-key", config.apiKey);
headers.set("anthropic-version", "2023-06-01");
headers.set("anthropic-dangerous-direct-browser-access", "true");
} else if (config.provider === "google") {
headers.set("x-goog-api-key", config.apiKey);
} else {
@@ -54,3 +54,23 @@ test("infographic tools and model loop run on the client after credential prepar
expect(paths).toEqual(["/api/v1/ai/infographic-agent/prepare"]);expect(calls).toBe(2);
expect(events).toContainEqual({type:"proposal",...proposal});expect(events.at(-1)).toEqual({type:"finish"});
});
test("Anthropic client generation and model discovery opt in to browser-direct access", async () => {
const { buildAiDirectProviderRequest } = await import("@edgeever/shared/ai-generation");
const prepared = { ...credential, provider: "anthropic", baseUrl: "https://api.anthropic.com/v1", system: "Reply", prompt: "OK", maxOutputTokens: 16 };
const request = buildAiDirectProviderRequest(prepared);
expect(request.headers["anthropic-dangerous-direct-browser-access"]).toBe("true");
const { createClientAiModel } = await import("./ai-model.ts");
const { generateText } = await import("ai");
const paths = [];
const fetch = async (url, init) => {
paths.push(String(url));expect(new Headers(init.headers).get("anthropic-dangerous-direct-browser-access")).toBe("true");
if (String(url).endsWith("/models")) return Response.json({ data: [{ id: "claude-test" }] });
return Response.json({ id: "msg-1", type: "message", role: "assistant", model: "claude-test", content: [{ type: "text", text: "OK" }], stop_reason: "end_turn", usage: { input_tokens: 1, output_tokens: 1 } });
};
const result = await generateText({ model: createClientAiModel({ ...prepared, fetch }), prompt: "OK", maxRetries: 0 });
expect(result.text).toBe("OK");
const { discoverAiModels } = await import("./ai-provider-direct.ts");
expect(await discoverAiModels(prepared, fetch)).toEqual([{ modelId: "claude-test", displayName: "claude-test" }]);
expect(paths).toHaveLength(2);
});
+1
View File
@@ -209,6 +209,7 @@ export const buildAiDirectProviderRequest = (
accept: "text/event-stream",
"x-api-key": prepared.apiKey,
"anthropic-version": "2023-06-01",
"anthropic-dangerous-direct-browser-access": "true",
},
body: JSON.stringify({
model: prepared.modelId,