open-agents-ai 0.184.56 → 0.184.57

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.
Files changed (2) hide show
  1. package/dist/index.js +61 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -62035,6 +62035,38 @@ function getVersion3() {
62035
62035
  }
62036
62036
  return "0.0.0";
62037
62037
  }
62038
+ function getEndpointUsage(label) {
62039
+ let u = endpointUsage.get(label);
62040
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
62041
+ if (!u) {
62042
+ u = { requestTimestamps: [], tokensToday: 0, tokenDate: today };
62043
+ endpointUsage.set(label, u);
62044
+ }
62045
+ if (u.tokenDate !== today) {
62046
+ u.tokensToday = 0;
62047
+ u.tokenDate = today;
62048
+ }
62049
+ return u;
62050
+ }
62051
+ function checkEndpointRateLimit(ep, estimatedTokens) {
62052
+ const rpm = ep.limits?.maxRequestsPerMinute ?? 60;
62053
+ const tpd = ep.limits?.maxTokensPerDay ?? 1e5;
62054
+ const usage = getEndpointUsage(ep.label);
62055
+ const now = Date.now();
62056
+ usage.requestTimestamps = usage.requestTimestamps.filter((t) => now - t < 6e4);
62057
+ if (usage.requestTimestamps.length >= rpm) {
62058
+ return `Rate limit exceeded for ${ep.label}: ${rpm} requests/minute. Try again in ${Math.ceil((usage.requestTimestamps[0] + 6e4 - now) / 1e3)}s.`;
62059
+ }
62060
+ if (estimatedTokens && usage.tokensToday + estimatedTokens > tpd) {
62061
+ return `Daily token limit exceeded for ${ep.label}: ${usage.tokensToday}/${tpd} tokens today.`;
62062
+ }
62063
+ return null;
62064
+ }
62065
+ function recordEndpointUsage(label, tokens) {
62066
+ const usage = getEndpointUsage(label);
62067
+ usage.requestTimestamps.push(Date.now());
62068
+ usage.tokensToday += tokens;
62069
+ }
62038
62070
  async function refreshEndpointRegistry() {
62039
62071
  endpointRegistry.length = 0;
62040
62072
  modelRouteMap.clear();
@@ -62068,6 +62100,10 @@ async function refreshEndpointRegistry() {
62068
62100
  label,
62069
62101
  url: sp.tunnelUrl,
62070
62102
  type: "vllm",
62103
+ limits: {
62104
+ maxRequestsPerMinute: sp.limits?.maxRequestsPerMinute ?? 60,
62105
+ maxTokensPerDay: sp.limits?.maxTokensPerDay ?? 1e5
62106
+ },
62071
62107
  authKey: sp.authKey
62072
62108
  });
62073
62109
  }
@@ -62415,6 +62451,13 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
62415
62451
  const targetUrl = route?.endpoint.url ?? ollamaUrl;
62416
62452
  const targetType = route?.endpoint.type ?? loadConfig().backendType ?? "ollama";
62417
62453
  const originalModel = route?.originalId ?? model;
62454
+ if (route?.endpoint) {
62455
+ const limitErr = checkEndpointRateLimit(route.endpoint);
62456
+ if (limitErr) {
62457
+ jsonResponse(res, 429, { error: limitErr });
62458
+ return;
62459
+ }
62460
+ }
62418
62461
  const routedBody = { ...requestBody, model: originalModel };
62419
62462
  if (targetType === "vllm" || targetType === "openai") {
62420
62463
  const payload = JSON.stringify(routedBody);
@@ -62449,8 +62492,11 @@ async function handleV1ChatCompletions(req, res, ollamaUrl) {
62449
62492
  }
62450
62493
  const parsed = JSON.parse(result.body);
62451
62494
  if (parsed.usage) {
62495
+ const totalTok = (parsed.usage.prompt_tokens ?? 0) + (parsed.usage.completion_tokens ?? 0);
62452
62496
  metrics.totalTokensIn += parsed.usage.prompt_tokens ?? 0;
62453
62497
  metrics.totalTokensOut += parsed.usage.completion_tokens ?? 0;
62498
+ if (route?.endpoint)
62499
+ recordEndpointUsage(route.endpoint.label, totalTok);
62454
62500
  }
62455
62501
  jsonResponse(res, 200, parsed);
62456
62502
  } catch (err) {
@@ -63104,6 +63150,19 @@ async function handleRequest(req, res, ollamaUrl, verbose) {
63104
63150
  await handlePutConfigEndpoint(req, res);
63105
63151
  return;
63106
63152
  }
63153
+ if (pathname === "/v1/usage" && method === "GET") {
63154
+ const usageData = {};
63155
+ for (const ep of endpointRegistry) {
63156
+ const u = getEndpointUsage(ep.label);
63157
+ usageData[ep.label] = {
63158
+ requestsLastMinute: u.requestTimestamps.filter((t) => Date.now() - t < 6e4).length,
63159
+ tokensToday: u.tokensToday,
63160
+ limits: ep.limits ?? { maxRequestsPerMinute: "unlimited", maxTokensPerDay: "unlimited" }
63161
+ };
63162
+ }
63163
+ jsonResponse(res, 200, { usage: usageData, totalTokensIn: metrics.totalTokensIn, totalTokensOut: metrics.totalTokensOut });
63164
+ return;
63165
+ }
63107
63166
  if (pathname === "/v1/commands" && method === "GET") {
63108
63167
  handleGetCommands(res);
63109
63168
  return;
@@ -63296,7 +63355,7 @@ async function apiServeCommand(opts, config) {
63296
63355
  server.on("close", resolve36);
63297
63356
  });
63298
63357
  }
63299
- var endpointRegistry, modelRouteMap, metrics, startedAt, runningProcesses;
63358
+ var endpointRegistry, modelRouteMap, endpointUsage, metrics, startedAt, runningProcesses;
63300
63359
  var init_serve = __esm({
63301
63360
  "packages/cli/dist/api/serve.js"() {
63302
63361
  "use strict";
@@ -63306,6 +63365,7 @@ var init_serve = __esm({
63306
63365
  init_profiles();
63307
63366
  endpointRegistry = [];
63308
63367
  modelRouteMap = /* @__PURE__ */ new Map();
63368
+ endpointUsage = /* @__PURE__ */ new Map();
63309
63369
  metrics = {
63310
63370
  requests: /* @__PURE__ */ new Map(),
63311
63371
  totalTokensIn: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.184.56",
3
+ "version": "0.184.57",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",