Spaces:
Paused
Paused
File size: 3,479 Bytes
5d0a52f 5f8456f 5d0a52f 5f8456f fce5280 5d0a52f ab21b87 5d0a52f ab21b87 5d0a52f 8b777a2 5f8456f 8b777a2 5f8456f 8b777a2 5d0a52f 2b84f47 8b777a2 5f8456f 5d0a52f 8b777a2 5f8456f 8b777a2 5d0a52f 8b777a2 5f8456f 8b777a2 5d0a52f 8b777a2 5d0a52f 8b777a2 5f8456f 8b777a2 5f8456f fce5280 8b777a2 | 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 | /**
* Model routes — pure route handlers reading from model-store singleton.
*/
import { Hono } from "hono";
import type { OpenAIModel, OpenAIModelList } from "../types/openai.js";
import {
getModelCatalog,
getModelAliases,
getModelInfo,
getModelStoreDebug,
type CodexModelInfo,
} from "../models/model-store.js";
import { triggerImmediateRefresh } from "../models/model-fetcher.js";
import { getConfig } from "../config.js";
// --- Routes ---
/** Stable timestamp used for all model `created` fields (2023-11-14T22:13:20Z). */
const MODEL_CREATED_TIMESTAMP = 1700000000;
function toOpenAIModel(info: CodexModelInfo): OpenAIModel {
return {
id: info.id,
object: "model",
created: MODEL_CREATED_TIMESTAMP,
owned_by: "openai",
};
}
export function createModelRoutes(): Hono {
const app = new Hono();
app.get("/v1/models", (c) => {
const catalog = getModelCatalog();
const aliases = getModelAliases();
// Include catalog models + aliases as separate entries
const models: OpenAIModel[] = catalog.map(toOpenAIModel);
for (const alias of Object.keys(aliases)) {
models.push({
id: alias,
object: "model",
created: MODEL_CREATED_TIMESTAMP,
owned_by: "openai",
});
}
const response: OpenAIModelList = { object: "list", data: models };
return c.json(response);
});
// Full catalog with reasoning efforts (for dashboard UI)
// Must be before :modelId to avoid being matched as a model ID
app.get("/v1/models/catalog", (c) => {
return c.json(getModelCatalog());
});
app.get("/v1/models/:modelId", (c) => {
const modelId = c.req.param("modelId");
const catalog = getModelCatalog();
const aliases = getModelAliases();
// Try direct match
const info = catalog.find((m) => m.id === modelId);
if (info) return c.json(toOpenAIModel(info));
// Try alias
const resolved = aliases[modelId];
if (resolved) {
return c.json({
id: modelId,
object: "model",
created: MODEL_CREATED_TIMESTAMP,
owned_by: "openai",
});
}
c.status(404);
return c.json({
error: {
message: `Model '${modelId}' not found`,
type: "invalid_request_error",
param: "model",
code: "model_not_found",
},
});
});
// Extended endpoint: model details with reasoning efforts
app.get("/v1/models/:modelId/info", (c) => {
const modelId = c.req.param("modelId");
const aliases = getModelAliases();
const resolved = aliases[modelId] ?? modelId;
const info = getModelInfo(resolved);
if (!info) {
c.status(404);
return c.json({ error: `Model '${modelId}' not found` });
}
return c.json(info);
});
// Debug endpoint: model store internals
app.get("/debug/models", (c) => {
return c.json(getModelStoreDebug());
});
// Admin endpoint: trigger immediate model refresh
app.post("/admin/refresh-models", (c) => {
const config = getConfig();
const configKey = config.server.proxy_api_key;
if (configKey) {
const authHeader = c.req.header("Authorization") ?? "";
const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7) : "";
if (token !== configKey) {
c.status(401);
return c.json({ error: "Unauthorized" });
}
}
triggerImmediateRefresh();
return c.json({ ok: true, message: "Model refresh triggered" });
});
return app;
}
|