feat: add AI proxy routes to Workers and Vercel entry points
- Add /v1/chat/completions, /v1/messages, /v1/models routes to src/worker.ts (Cloudflare Workers) and api/relay.ts (Vercel) - Import handleChatCompletion, handleAnthropicMessages handlers - Using the same backend routing as the standalone server Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
4168a087a0
commit
38d7a83fe9
@@ -27,6 +27,8 @@ import {
|
|||||||
import { checkBodySize } from "../src/middleware/body-limiter";
|
import { checkBodySize } from "../src/middleware/body-limiter";
|
||||||
import { createRateLimiter } from "../src/middleware/rate-limiter";
|
import { createRateLimiter } from "../src/middleware/rate-limiter";
|
||||||
import { logRelayEvent } from "../src/middleware/logger";
|
import { logRelayEvent } from "../src/middleware/logger";
|
||||||
|
import { handleChatCompletion, listModels } from "../src/lib/ai-proxy";
|
||||||
|
import { handleAnthropicMessages, listAnthropicModels } from "../src/lib/anthropic-proxy";
|
||||||
|
|
||||||
// ─── Configuration ──────────────────────────────────────────────────────────────
|
// ─── Configuration ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -394,6 +396,50 @@ export default {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AI proxy routes — OpenAI-compatible
|
||||||
|
if (url.pathname === "/v1/chat/completions") {
|
||||||
|
if (req.method === "OPTIONS") return createCorsPreflightResponse();
|
||||||
|
if (req.method !== "POST") return new Response("Method Not Allowed", { status: 405 });
|
||||||
|
try {
|
||||||
|
const body = await req.json();
|
||||||
|
return handleChatCompletion(body);
|
||||||
|
} catch {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: { message: "Invalid JSON body", type: "invalid_request_error" } }),
|
||||||
|
{ status: 400, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AI proxy routes — Anthropic-compatible
|
||||||
|
if (url.pathname === "/v1/messages") {
|
||||||
|
if (req.method === "OPTIONS") return createCorsPreflightResponse();
|
||||||
|
if (req.method !== "POST") return new Response("Method Not Allowed", { status: 405 });
|
||||||
|
try {
|
||||||
|
const body = await req.json();
|
||||||
|
return handleAnthropicMessages(body);
|
||||||
|
} catch {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: { message: "Invalid JSON body", type: "invalid_request_error" } }),
|
||||||
|
{ status: 400, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Models list
|
||||||
|
if (url.pathname === "/v1/models" && req.method === "GET") {
|
||||||
|
const models = [...listModels(), ...listAnthropicModels()].map((id) => ({
|
||||||
|
id,
|
||||||
|
object: "model",
|
||||||
|
created: Math.floor(Date.now() / 1000),
|
||||||
|
owned_by: "proxy",
|
||||||
|
}));
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ object: "list", data: models }),
|
||||||
|
{ status: 200, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Generic HTTP relay
|
// Generic HTTP relay
|
||||||
return handleRelay(req);
|
return handleRelay(req);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import {
|
|||||||
import { checkBodySize } from "./middleware/body-limiter";
|
import { checkBodySize } from "./middleware/body-limiter";
|
||||||
import { createRateLimiter } from "./middleware/rate-limiter";
|
import { createRateLimiter } from "./middleware/rate-limiter";
|
||||||
import { logRelayEvent } from "./middleware/logger";
|
import { logRelayEvent } from "./middleware/logger";
|
||||||
|
import { handleChatCompletion, listModels } from "./lib/ai-proxy";
|
||||||
|
import { handleAnthropicMessages, listAnthropicModels } from "./lib/anthropic-proxy";
|
||||||
|
|
||||||
// ─── Types ───────────────────────────────────────────────────────────────────────
|
// ─── Types ───────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -390,6 +392,50 @@ export default {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AI proxy routes — OpenAI-compatible
|
||||||
|
if (url.pathname === "/v1/chat/completions") {
|
||||||
|
if (req.method === "OPTIONS") return createCorsPreflightResponse();
|
||||||
|
if (req.method !== "POST") return new Response("Method Not Allowed", { status: 405 });
|
||||||
|
try {
|
||||||
|
const body = await req.json();
|
||||||
|
return handleChatCompletion(body);
|
||||||
|
} catch {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: { message: "Invalid JSON body", type: "invalid_request_error" } }),
|
||||||
|
{ status: 400, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AI proxy routes — Anthropic-compatible
|
||||||
|
if (url.pathname === "/v1/messages") {
|
||||||
|
if (req.method === "OPTIONS") return createCorsPreflightResponse();
|
||||||
|
if (req.method !== "POST") return new Response("Method Not Allowed", { status: 405 });
|
||||||
|
try {
|
||||||
|
const body = await req.json();
|
||||||
|
return handleAnthropicMessages(body);
|
||||||
|
} catch {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: { message: "Invalid JSON body", type: "invalid_request_error" } }),
|
||||||
|
{ status: 400, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Models list
|
||||||
|
if (url.pathname === "/v1/models" && req.method === "GET") {
|
||||||
|
const models = [...listModels(), ...listAnthropicModels()].map((id) => ({
|
||||||
|
id,
|
||||||
|
object: "model",
|
||||||
|
created: Math.floor(Date.now() / 1000),
|
||||||
|
owned_by: "proxy",
|
||||||
|
}));
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ object: "list", data: models }),
|
||||||
|
{ status: 200, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Generic HTTP relay
|
// Generic HTTP relay
|
||||||
return handleRelay(req, env);
|
return handleRelay(req, env);
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user