Add image model (regolo-qwen-image) to modelSpecs, enabling UI image‑generation button
This commit is contained in:
commit
b2badebad6
4 files changed
+283
No files matched your search
@@ -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 };
|
||||
Reference in new issue
Block a user