Add image model (regolo-qwen-image) to modelSpecs, enabling UI image‑generation button

This commit is contained in:
Nathan Schneider committed 2026-10-18 16:51:36 -06:00
commit b2badebad6
4 files changed
+283

No files matched your search

+76
View File
@@ -0,0 +1,76 @@
/**
* Key broker sync — automatically provision a member's gateway key at SSO login.
*
* Inference Cooperative patch (MIT, same as LibreChat). When KEY_BROKER_URL is
* set, an OpenID (Cloudron SSO) login fetches-or-creates the member's chat key
* via the member portal's broker and stores it as the user's LibreChat key for
* the configured endpoint — so members never paste a key and all usage bills
* to their own LiteLLM team/budget.
*
* Env:
* KEY_BROKER_URL e.g. https://portal.inference.coop
* KEY_BROKER_SECRET the portal's BROKER_SECRET (x-broker-secret header)
* KEY_BROKER_KEY_NAME portal-side key name, default "chat"
* KEY_BROKER_ENDPOINT LibreChat endpoint (user-key) name, default "Inference Co-op"
*
* Semantics: create-on-first-login. If the member already has a portal-side
* "chat" key but LibreChat lost its stored copy, we deliberately do NOT rotate
* (rotation would silently break the member's own API scripts); they can
* rotate from the dashboard and log in again.
*/
const { updateUserKey, getUserKeyExpiry } = require('~/models');
const { logger } = require('@librechat/data-schemas');
async function syncBrokerUserKey(user) {
const base = process.env.KEY_BROKER_URL;
const secret = process.env.KEY_BROKER_SECRET;
const userId = user?._id?.toString?.() || user?.id;
if (!base || !secret || !userId || !user?.email) return;
const keyName = process.env.KEY_BROKER_KEY_NAME || 'chat';
const endpointName = process.env.KEY_BROKER_ENDPOINT || 'Inference Co-op';
const headers = {
'x-broker-secret': secret,
'x-member-email': user.email,
};
// Does the member already have a portal-side chat key?
const listRes = await fetch(`${base}/broker/keys`, { headers });
if (!listRes.ok) throw new Error(`broker list ${listRes.status}`);
const list = await listRes.json();
const exists = (list.keys || []).some((k) => k.name === keyName);
if (!exists) {
const createRes = await fetch(`${base}/broker/keys`, {
method: 'POST',
headers: { ...headers, 'content-type': 'application/json' },
body: JSON.stringify({ name: keyName }),
});
if (!createRes.ok) throw new Error(`broker create ${createRes.status}`);
const created = await createRes.json();
if (!created.sk_token) throw new Error('broker returned no sk_token');
// Store the key in LibreChat (JSON string as required by LibreChat storage)
await updateUserKey({
userId: userId,
name: endpointName,
value: JSON.stringify({ apiKey: created.sk_token }),
expiresAt: null,
});
logger.info(`[KeyBroker] provisioned "${keyName}" key for ${user.email} (endpoint: ${endpointName})`);
return;
}
// Portal-side key exists — check whether LibreChat still holds a stored copy.
try {
const stored = await getUserKeyExpiry({ userId: user.id, name: endpointName });
if (!stored) {
logger.warn(
`[KeyBroker] ${user.email} has a portal "${keyName}" key but no stored copy for endpoint "${endpointName}". ` +
'Rotate the key on the dashboard and log in again (manual rotation avoids breaking their API scripts).',
);
}
} catch (e) {
logger.warn(`[KeyBroker] stored-key check failed for ${user.email}: ${e.message}`);
}
}
module.exports = { syncBrokerUserKey };