@ubiquity-os/plugin-sdk
Version:
SDK for plugin support.
210 lines (206 loc) • 7.86 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/helpers/index.ts
var helpers_exports = {};
__export(helpers_exports, {
checkLlmRetryableState: () => checkLlmRetryableState,
getOpenRouterModelTokenLimits: () => getOpenRouterModelTokenLimits,
getOpenRouterModels: () => getOpenRouterModels,
retry: () => retry
});
module.exports = __toCommonJS(helpers_exports);
// src/helpers/openrouter.ts
async function getOpenRouterModels() {
const response = await fetch("https://openrouter.ai/api/v1/models");
if (!response.ok) {
throw new Error("Failed to fetch models");
}
const result = await response.json();
return result.data;
}
async function getOpenRouterModelTokenLimits(modelId) {
const models = await getOpenRouterModels();
const model = models.find((m) => m.id === modelId);
if (!model) {
return null;
}
return {
contextLength: model.context_length,
maxCompletionTokens: model.top_provider.max_completion_tokens || model.context_length
};
}
// src/helpers/retry.ts
var import_typebox = require("@sinclair/typebox");
var import_ubiquity_os_logger = require("@ubiquity-os/ubiquity-os-logger");
var import_ms = __toESM(require("ms"));
function sleep(ms2) {
return new Promise((resolve) => setTimeout(resolve, ms2));
}
async function handleRetryError(err, delay, options, isLastLoop) {
const lastError = err;
if (options.onError) {
await options.onError(err);
}
let shouldRetry;
if (options.isErrorRetryable) {
shouldRetry = await options.isErrorRetryable(err);
}
if (shouldRetry === false || isLastLoop) {
throw lastError;
}
if (typeof shouldRetry === "number" && Number.isFinite(shouldRetry)) {
await sleep(shouldRetry);
} else {
await sleep(delay);
delay *= 2;
}
return { delay, lastError };
}
async function retry(fn, options) {
let delay = 1e3;
let lastError = null;
for (let i = 0; i < options.maxRetries + 1; i++) {
try {
return await fn();
} catch (err) {
const result = await handleRetryError(err, delay, options, i >= options.maxRetries);
delay = result.delay;
lastError = result.lastError;
}
}
throw lastError;
}
function checkLlmRetryableState(error) {
if (error instanceof SyntaxError || error instanceof import_typebox.TypeBoxError || error instanceof import_ubiquity_os_logger.LogReturn) {
return true;
}
const status = extractStatus(error) ?? extractStatusFromMessage(error);
if (!status) return false;
if (status === 429) {
const headers = extractHeaders(error);
const tokenDelay = parseRetryAfter(headers, "x-ratelimit-reset-tokens");
const requestDelay = parseRetryAfter(headers, "x-ratelimit-reset-requests");
const retryAfter = parseRetryAfter(headers, "retry-after");
const delays = [tokenDelay, requestDelay, retryAfter].filter((value) => Number.isFinite(value));
if (!delays.length) return true;
return Math.max(...delays);
}
return status >= 500;
}
function extractStatus(error) {
const direct = getStatusFromSource(error);
if (direct !== null) return direct;
if (typeof error !== "object" || error === null || !("cause" in error)) return null;
return getStatusFromSource(error.cause);
}
function getStatusFromSource(source) {
if (typeof source !== "object" || source === null) return null;
const maybeError = source;
const candidates = [maybeError.status, maybeError.statusCode, maybeError.response?.status];
for (const candidate of candidates) {
if (typeof candidate === "number") return candidate;
if (typeof candidate === "string" && candidate.trim()) {
const parsed = Number.parseInt(candidate, 10);
if (Number.isFinite(parsed)) return parsed;
}
}
return null;
}
function extractStatusFromMessage(error) {
const message = extractMessage(error);
if (!message) return null;
const match = STATUS_FROM_MESSAGE_REGEX.exec(message);
if (!match) return null;
const status = Number(match[1]);
return Number.isFinite(status) ? status : null;
}
function extractMessage(error) {
if (typeof error === "string") return error;
if (typeof error !== "object" || error === null || !("message" in error)) return void 0;
const maybeMessage = error.message;
return typeof maybeMessage === "string" ? maybeMessage : void 0;
}
function extractHeaders(error) {
if (typeof error !== "object" || error === null) return void 0;
const maybeError = error;
if (maybeError.headers) return maybeError.headers;
if (maybeError.response?.headers) return maybeError.response.headers;
const maybeCause = maybeError.cause;
if (typeof maybeCause === "object" && maybeCause !== null) {
const cause = maybeCause;
if (cause.headers) return cause.headers;
if (cause.response?.headers) return cause.response.headers;
}
return void 0;
}
function parseRetryAfter(headers, headerName) {
const value = getHeaderValue(headers, headerName);
if (!value) return null;
const delay = parseDelayMs(value, headerName.toLowerCase() === "retry-after");
return Number.isFinite(delay) ? delay : null;
}
function getHeaderValue(headers, headerName) {
if (!headers || typeof headers !== "object") return void 0;
const maybeHeaders = headers;
if (typeof maybeHeaders.get === "function") {
const value = maybeHeaders.get(headerName);
return typeof value === "string" ? value : void 0;
}
const direct = maybeHeaders[headerName] ?? maybeHeaders[headerName.toLowerCase()] ?? maybeHeaders[headerName.toUpperCase()];
return typeof direct === "string" ? direct : void 0;
}
var STATUS_FROM_MESSAGE_REGEX = /\b(?:status(?: code)?|http|error)\b\D*(\d{3})(?!\d)/i;
function parseDelayMs(value, numericIsSeconds) {
const trimmed = value.trim();
if (!trimmed) return null;
if (isNumericString(trimmed)) {
const numeric = Number(trimmed);
if (!Number.isFinite(numeric)) return null;
return numericIsSeconds ? numeric * 1e3 : numeric;
}
const duration = (0, import_ms.default)(trimmed);
if (Number.isFinite(duration)) return duration;
return parseDateDelay(trimmed);
}
function parseDateDelay(value) {
const parsedDate = Date.parse(value);
if (Number.isNaN(parsedDate)) return null;
const delay = parsedDate - Date.now();
return delay > 0 ? delay : 0;
}
function isNumericString(value) {
return /^\d+(?:\.\d+)?$/.test(value);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
checkLlmRetryableState,
getOpenRouterModelTokenLimits,
getOpenRouterModels,
retry
});