Spaces:
Paused
Paused
File size: 3,987 Bytes
5d0a52f 8b777a2 4ebb914 5d0a52f bc98e69 8b777a2 5d0a52f 7366e72 e25a730 7366e72 85aec43 5d0a52f 4ebb914 5d0a52f 8b777a2 5d0a52f 0be9bdf 5d0a52f e25a730 bc98e69 7366e72 22a7de1 8b777a2 bc98e69 8b777a2 e25a730 8b777a2 7366e72 4ebb914 5d0a52f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | import { Hono } from "hono";
import { ChatCompletionRequestSchema } from "../types/openai.js";
import type { AccountPool } from "../auth/account-pool.js";
import type { CookieJar } from "../proxy/cookie-jar.js";
import type { ProxyPool } from "../proxy/proxy-pool.js";
import { translateToCodexRequest } from "../translation/openai-to-codex.js";
import {
streamCodexToOpenAI,
collectCodexResponse,
} from "../translation/codex-to-openai.js";
import { getConfig } from "../config.js";
import { parseModelName, buildDisplayModelName } from "../models/model-store.js";
import {
handleProxyRequest,
type FormatAdapter,
} from "./shared/proxy-handler.js";
function makeOpenAIFormat(wantReasoning: boolean): FormatAdapter {
return {
tag: "Chat",
noAccountStatus: 503,
formatNoAccount: () => ({
error: {
message:
"No available accounts. All accounts are expired or rate-limited.",
type: "server_error",
param: null,
code: "no_available_accounts",
},
}),
format429: (msg) => ({
error: {
message: msg,
type: "rate_limit_error",
param: null,
code: "rate_limit_exceeded",
},
}),
formatError: (_status, msg) => ({
error: {
message: msg,
type: "server_error",
param: null,
code: "codex_api_error",
},
}),
streamTranslator: (api, response, model, onUsage, onResponseId, tupleSchema) =>
streamCodexToOpenAI(api, response, model, onUsage, onResponseId, wantReasoning, tupleSchema),
collectTranslator: (api, response, model, tupleSchema) =>
collectCodexResponse(api, response, model, wantReasoning, tupleSchema),
};
}
export function createChatRoutes(
accountPool: AccountPool,
cookieJar?: CookieJar,
proxyPool?: ProxyPool,
): Hono {
const app = new Hono();
app.post("/v1/chat/completions", async (c) => {
// Auth check
if (!accountPool.isAuthenticated()) {
c.status(401);
return c.json({
error: {
message: "Not authenticated. Please login first at /",
type: "invalid_request_error",
param: null,
code: "invalid_api_key",
},
});
}
// Optional proxy API key check
const config = getConfig();
if (config.server.proxy_api_key) {
const authHeader = c.req.header("Authorization");
const providedKey = authHeader?.replace("Bearer ", "");
if (
!providedKey ||
!accountPool.validateProxyApiKey(providedKey)
) {
c.status(401);
return c.json({
error: {
message: "Invalid proxy API key",
type: "invalid_request_error",
param: null,
code: "invalid_api_key",
},
});
}
}
// Parse request
let body: unknown;
try {
body = await c.req.json();
} catch {
c.status(400);
return c.json({
error: {
message: "Malformed JSON request body",
type: "invalid_request_error",
param: null,
code: "invalid_json",
},
});
}
const parsed = ChatCompletionRequestSchema.safeParse(body);
if (!parsed.success) {
c.status(400);
return c.json({
error: {
message: `Invalid request: ${parsed.error.message}`,
type: "invalid_request_error",
param: null,
code: "invalid_request",
},
});
}
const req = parsed.data;
const { codexRequest, tupleSchema } = translateToCodexRequest(req);
const displayModel = buildDisplayModelName(parseModelName(req.model));
const wantReasoning = !!req.reasoning_effort;
return handleProxyRequest(
c,
accountPool,
cookieJar,
{
codexRequest,
model: displayModel,
isStreaming: req.stream,
tupleSchema,
},
makeOpenAIFormat(wantReasoning),
proxyPool,
);
});
return app;
}
|