open-agents-ai 0.184.54 → 0.184.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +151 -54
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -62035,6 +62035,110 @@ function getVersion3() {
|
|
|
62035
62035
|
}
|
|
62036
62036
|
return "0.0.0";
|
|
62037
62037
|
}
|
|
62038
|
+
async function refreshEndpointRegistry() {
|
|
62039
|
+
endpointRegistry.length = 0;
|
|
62040
|
+
modelRouteMap.clear();
|
|
62041
|
+
const config = loadConfig();
|
|
62042
|
+
const primaryLabel = (() => {
|
|
62043
|
+
if (config.backendUrl.includes("127.0.0.1") || config.backendUrl.includes("localhost"))
|
|
62044
|
+
return "local";
|
|
62045
|
+
try {
|
|
62046
|
+
return new URL(config.backendUrl).hostname.split(".")[0];
|
|
62047
|
+
} catch {
|
|
62048
|
+
return "primary";
|
|
62049
|
+
}
|
|
62050
|
+
})();
|
|
62051
|
+
endpointRegistry.push({
|
|
62052
|
+
label: primaryLabel,
|
|
62053
|
+
url: config.backendUrl,
|
|
62054
|
+
type: config.backendType || "ollama",
|
|
62055
|
+
authKey: config.apiKey
|
|
62056
|
+
});
|
|
62057
|
+
try {
|
|
62058
|
+
const resp = await fetch("https://openagents.nexus/api/v1/sponsors", {
|
|
62059
|
+
signal: AbortSignal.timeout(5e3)
|
|
62060
|
+
});
|
|
62061
|
+
if (resp.ok) {
|
|
62062
|
+
const data = await resp.json();
|
|
62063
|
+
for (const sp of (data.sponsors || []).filter((s) => s.status === "active" && s.tunnelUrl)) {
|
|
62064
|
+
if (sp.tunnelUrl === config.backendUrl)
|
|
62065
|
+
continue;
|
|
62066
|
+
const label = sp.name.replace(/[^a-zA-Z0-9]/g, "").slice(0, 12).toLowerCase() || "sponsor";
|
|
62067
|
+
endpointRegistry.push({
|
|
62068
|
+
label,
|
|
62069
|
+
url: sp.tunnelUrl,
|
|
62070
|
+
type: "vllm",
|
|
62071
|
+
authKey: sp.authKey
|
|
62072
|
+
});
|
|
62073
|
+
}
|
|
62074
|
+
}
|
|
62075
|
+
} catch {
|
|
62076
|
+
}
|
|
62077
|
+
}
|
|
62078
|
+
async function fetchAggregatedModels() {
|
|
62079
|
+
const allModels = [];
|
|
62080
|
+
modelRouteMap.clear();
|
|
62081
|
+
const fetches = endpointRegistry.map(async (ep) => {
|
|
62082
|
+
try {
|
|
62083
|
+
const isOllama = ep.type === "ollama";
|
|
62084
|
+
const modelsPath = isOllama ? "/api/tags" : "/v1/models";
|
|
62085
|
+
const result = await ollamaRequest(ep.url, modelsPath, "GET");
|
|
62086
|
+
if (result.status !== 200)
|
|
62087
|
+
return;
|
|
62088
|
+
const body = JSON.parse(result.body);
|
|
62089
|
+
if (isOllama) {
|
|
62090
|
+
const models = body.models ?? [];
|
|
62091
|
+
for (const m of models) {
|
|
62092
|
+
const prefixed = `${ep.label}/${m.name}`;
|
|
62093
|
+
modelRouteMap.set(prefixed, { endpoint: ep, originalId: m.name });
|
|
62094
|
+
allModels.push({
|
|
62095
|
+
id: prefixed,
|
|
62096
|
+
object: "model",
|
|
62097
|
+
created: m.modified_at ? Math.floor(new Date(m.modified_at).getTime() / 1e3) : 0,
|
|
62098
|
+
owned_by: ep.label
|
|
62099
|
+
});
|
|
62100
|
+
}
|
|
62101
|
+
} else {
|
|
62102
|
+
const models = body.data ?? [];
|
|
62103
|
+
for (const m of models) {
|
|
62104
|
+
const originalId = m.id || m.name;
|
|
62105
|
+
const prefixed = `${ep.label}/${originalId}`;
|
|
62106
|
+
modelRouteMap.set(prefixed, { endpoint: ep, originalId });
|
|
62107
|
+
allModels.push({
|
|
62108
|
+
id: prefixed,
|
|
62109
|
+
object: "model",
|
|
62110
|
+
created: m.created || 0,
|
|
62111
|
+
owned_by: ep.label
|
|
62112
|
+
});
|
|
62113
|
+
}
|
|
62114
|
+
}
|
|
62115
|
+
} catch {
|
|
62116
|
+
}
|
|
62117
|
+
});
|
|
62118
|
+
await Promise.allSettled(fetches);
|
|
62119
|
+
return allModels.sort((a, b) => a.id.localeCompare(b.id));
|
|
62120
|
+
}
|
|
62121
|
+
function resolveModelEndpoint(modelId) {
|
|
62122
|
+
const exact = modelRouteMap.get(modelId);
|
|
62123
|
+
if (exact)
|
|
62124
|
+
return exact;
|
|
62125
|
+
for (const [, route] of modelRouteMap) {
|
|
62126
|
+
if (route.originalId === modelId)
|
|
62127
|
+
return route;
|
|
62128
|
+
}
|
|
62129
|
+
const slashIdx = modelId.indexOf("/");
|
|
62130
|
+
if (slashIdx > 0) {
|
|
62131
|
+
const prefix = modelId.slice(0, slashIdx);
|
|
62132
|
+
const rest = modelId.slice(slashIdx + 1);
|
|
62133
|
+
const ep = endpointRegistry.find((e) => e.label === prefix);
|
|
62134
|
+
if (ep)
|
|
62135
|
+
return { endpoint: ep, originalId: rest };
|
|
62136
|
+
}
|
|
62137
|
+
if (endpointRegistry.length > 0) {
|
|
62138
|
+
return { endpoint: endpointRegistry[0], originalId: modelId };
|
|
62139
|
+
}
|
|
62140
|
+
return null;
|
|
62141
|
+
}
|
|
62038
62142
|
function recordMetric(method, path, status) {
|
|
62039
62143
|
const key = `${method}|${path}|${status}`;
|
|
62040
62144
|
const existing = metrics.requests.get(key);
|
|
@@ -62104,10 +62208,10 @@ async function parseJsonBody(req) {
|
|
|
62104
62208
|
return null;
|
|
62105
62209
|
}
|
|
62106
62210
|
}
|
|
62107
|
-
function backendAuthHeaders() {
|
|
62108
|
-
const
|
|
62109
|
-
if (
|
|
62110
|
-
return { Authorization: `Bearer ${
|
|
62211
|
+
function backendAuthHeaders(endpoint) {
|
|
62212
|
+
const key = endpoint?.authKey ?? loadConfig().apiKey;
|
|
62213
|
+
if (key)
|
|
62214
|
+
return { Authorization: `Bearer ${key}` };
|
|
62111
62215
|
return {};
|
|
62112
62216
|
}
|
|
62113
62217
|
function ollamaRequest(ollamaUrl, path, method, body) {
|
|
@@ -62285,33 +62389,15 @@ function handleMetrics(res) {
|
|
|
62285
62389
|
}
|
|
62286
62390
|
async function handleV1Models(res, ollamaUrl) {
|
|
62287
62391
|
try {
|
|
62288
|
-
const
|
|
62289
|
-
|
|
62290
|
-
|
|
62291
|
-
|
|
62292
|
-
|
|
62293
|
-
|
|
62294
|
-
return;
|
|
62295
|
-
}
|
|
62296
|
-
jsonResponse(res, 200, JSON.parse(result2.body));
|
|
62297
|
-
return;
|
|
62298
|
-
}
|
|
62299
|
-
const result = await ollamaRequest(ollamaUrl, "/api/tags", "GET");
|
|
62300
|
-
if (result.status !== 200) {
|
|
62301
|
-
jsonResponse(res, result.status, { error: "Failed to fetch models from backend" });
|
|
62302
|
-
return;
|
|
62303
|
-
}
|
|
62304
|
-
const ollamaBody = JSON.parse(result.body);
|
|
62305
|
-
const models = (ollamaBody.models ?? []).map((m) => ({
|
|
62306
|
-
id: m.name,
|
|
62307
|
-
object: "model",
|
|
62308
|
-
created: m.modified_at ? Math.floor(new Date(m.modified_at).getTime() / 1e3) : 0,
|
|
62309
|
-
owned_by: "local"
|
|
62310
|
-
}));
|
|
62311
|
-
jsonResponse(res, 200, { object: "list", data: models });
|
|
62392
|
+
const models = await fetchAggregatedModels();
|
|
62393
|
+
jsonResponse(res, 200, {
|
|
62394
|
+
object: "list",
|
|
62395
|
+
data: models,
|
|
62396
|
+
_endpoints: endpointRegistry.map((e) => ({ label: e.label, url: e.url, type: e.type }))
|
|
62397
|
+
});
|
|
62312
62398
|
} catch (err) {
|
|
62313
62399
|
jsonResponse(res, 502, {
|
|
62314
|
-
error: "Failed to
|
|
62400
|
+
error: "Failed to fetch models",
|
|
62315
62401
|
message: err instanceof Error ? err.message : String(err)
|
|
62316
62402
|
});
|
|
62317
62403
|
}
|
|
@@ -62325,10 +62411,13 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
|
|
|
62325
62411
|
const requestBody = body;
|
|
62326
62412
|
const stream = requestBody["stream"] === true;
|
|
62327
62413
|
const model = requestBody["model"] || "unknown";
|
|
62328
|
-
const
|
|
62329
|
-
const
|
|
62330
|
-
|
|
62331
|
-
|
|
62414
|
+
const route = resolveModelEndpoint(model);
|
|
62415
|
+
const targetUrl = route?.endpoint.url ?? ollamaUrl;
|
|
62416
|
+
const targetType = route?.endpoint.type ?? loadConfig().backendType ?? "ollama";
|
|
62417
|
+
const originalModel = route?.originalId ?? model;
|
|
62418
|
+
const routedBody = { ...requestBody, model: originalModel };
|
|
62419
|
+
if (targetType === "vllm" || targetType === "openai") {
|
|
62420
|
+
const payload = JSON.stringify(routedBody);
|
|
62332
62421
|
if (stream) {
|
|
62333
62422
|
res.writeHead(200, {
|
|
62334
62423
|
"Content-Type": "text/event-stream",
|
|
@@ -62338,7 +62427,7 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
|
|
|
62338
62427
|
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
|
|
62339
62428
|
"Access-Control-Allow-Headers": "Content-Type, Authorization"
|
|
62340
62429
|
});
|
|
62341
|
-
ollamaStream(
|
|
62430
|
+
ollamaStream(targetUrl, "/v1/chat/completions", "POST", payload, (chunk) => {
|
|
62342
62431
|
res.write(chunk);
|
|
62343
62432
|
}, () => {
|
|
62344
62433
|
res.end();
|
|
@@ -62353,7 +62442,7 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
|
|
|
62353
62442
|
});
|
|
62354
62443
|
} else {
|
|
62355
62444
|
try {
|
|
62356
|
-
const result = await ollamaRequest(
|
|
62445
|
+
const result = await ollamaRequest(targetUrl, "/v1/chat/completions", "POST", payload);
|
|
62357
62446
|
if (result.status !== 200) {
|
|
62358
62447
|
jsonResponse(res, result.status, { error: "Backend request failed", details: result.body });
|
|
62359
62448
|
return;
|
|
@@ -62371,7 +62460,7 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
|
|
|
62371
62460
|
return;
|
|
62372
62461
|
}
|
|
62373
62462
|
const ollamaPayload = JSON.stringify({
|
|
62374
|
-
...
|
|
62463
|
+
...routedBody,
|
|
62375
62464
|
stream,
|
|
62376
62465
|
think: false
|
|
62377
62466
|
});
|
|
@@ -62386,7 +62475,7 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
|
|
|
62386
62475
|
});
|
|
62387
62476
|
const chatId = `chatcmpl-${randomBytes16(12).toString("hex")}`;
|
|
62388
62477
|
let buffer = "";
|
|
62389
|
-
ollamaStream(
|
|
62478
|
+
ollamaStream(targetUrl, "/api/chat", "POST", ollamaPayload, (chunk) => {
|
|
62390
62479
|
buffer += chunk;
|
|
62391
62480
|
const lines = buffer.split("\n");
|
|
62392
62481
|
buffer = lines.pop() ?? "";
|
|
@@ -62476,7 +62565,7 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
|
|
|
62476
62565
|
});
|
|
62477
62566
|
} else {
|
|
62478
62567
|
try {
|
|
62479
|
-
const result = await ollamaRequest(
|
|
62568
|
+
const result = await ollamaRequest(targetUrl, "/api/chat", "POST", ollamaPayload);
|
|
62480
62569
|
if (result.status !== 200) {
|
|
62481
62570
|
jsonResponse(res, result.status, {
|
|
62482
62571
|
error: "Ollama request failed",
|
|
@@ -63149,29 +63238,35 @@ function startApiServer(options = {}) {
|
|
|
63149
63238
|
`);
|
|
63150
63239
|
}
|
|
63151
63240
|
});
|
|
63152
|
-
|
|
63153
|
-
|
|
63154
|
-
|
|
63241
|
+
refreshEndpointRegistry().catch(() => {
|
|
63242
|
+
}).then(() => {
|
|
63243
|
+
server.listen(port, host, () => {
|
|
63244
|
+
const version = getVersion3();
|
|
63245
|
+
process.stderr.write(`
|
|
63155
63246
|
open-agents API server v${version}
|
|
63156
63247
|
`);
|
|
63157
|
-
|
|
63248
|
+
process.stderr.write(` Listening on http://${host}:${port}
|
|
63158
63249
|
`);
|
|
63159
|
-
|
|
63160
|
-
process.stderr.write(` Backend (${beType}): ${ollamaUrl}
|
|
63250
|
+
process.stderr.write(` Endpoints: ${endpointRegistry.length} registered
|
|
63161
63251
|
`);
|
|
63162
|
-
|
|
63163
|
-
|
|
63164
|
-
process.stderr.write(` Auth: ${keyCount} scoped key(s) (read/run/admin)
|
|
63252
|
+
for (const ep of endpointRegistry) {
|
|
63253
|
+
process.stderr.write(` ${ep.label}: ${ep.url} (${ep.type})${ep.authKey ? " [auth]" : ""}
|
|
63165
63254
|
`);
|
|
63166
|
-
|
|
63167
|
-
process.
|
|
63255
|
+
}
|
|
63256
|
+
if (process.env["OA_API_KEYS"]) {
|
|
63257
|
+
const keyCount = process.env["OA_API_KEYS"].split(",").length;
|
|
63258
|
+
process.stderr.write(` Auth: ${keyCount} scoped key(s) (read/run/admin)
|
|
63168
63259
|
`);
|
|
63169
|
-
|
|
63170
|
-
|
|
63260
|
+
} else if (process.env["OA_API_KEY"]) {
|
|
63261
|
+
process.stderr.write(` Auth: single Bearer token (admin scope)
|
|
63171
63262
|
`);
|
|
63172
|
-
|
|
63173
|
-
|
|
63263
|
+
} else {
|
|
63264
|
+
process.stderr.write(` Auth: disabled (set OA_API_KEY or OA_API_KEYS to enable)
|
|
63265
|
+
`);
|
|
63266
|
+
}
|
|
63267
|
+
process.stderr.write(`
|
|
63174
63268
|
`);
|
|
63269
|
+
});
|
|
63175
63270
|
});
|
|
63176
63271
|
const shutdown = () => {
|
|
63177
63272
|
process.stderr.write("\n Shutting down API server...\n");
|
|
@@ -63201,7 +63296,7 @@ async function apiServeCommand(opts, config) {
|
|
|
63201
63296
|
server.on("close", resolve36);
|
|
63202
63297
|
});
|
|
63203
63298
|
}
|
|
63204
|
-
var metrics, startedAt, runningProcesses;
|
|
63299
|
+
var endpointRegistry, modelRouteMap, metrics, startedAt, runningProcesses;
|
|
63205
63300
|
var init_serve = __esm({
|
|
63206
63301
|
"packages/cli/dist/api/serve.js"() {
|
|
63207
63302
|
"use strict";
|
|
@@ -63209,6 +63304,8 @@ var init_serve = __esm({
|
|
|
63209
63304
|
init_oa_directory();
|
|
63210
63305
|
init_render();
|
|
63211
63306
|
init_profiles();
|
|
63307
|
+
endpointRegistry = [];
|
|
63308
|
+
modelRouteMap = /* @__PURE__ */ new Map();
|
|
63212
63309
|
metrics = {
|
|
63213
63310
|
requests: /* @__PURE__ */ new Map(),
|
|
63214
63311
|
totalTokensIn: 0,
|
package/package.json
CHANGED