mirror of
https://github.com/hanzoai/chat.git
synced 2026-09-30 20:51:17 +00:00
The guest model was a paid house SKU (zen5-flash) that draws on the deployment balance, so with the balance overdrawn a guest's first message returned 402 and signed-out chat did not work at all. Pin the guest to a free route (nvidia/nemotron-nano-9b-v2:free) — the same free id @hanzo/ai names for a signed-in fallback — so a guest is served at zero cost regardless of balance. Guest scope now overrides the endpoint/model to the free one rather than rejecting a mismatch, so a stale client model can never leave a guest unable to send, while a guest still can never reach a paid route. The free guest model and endpoint are published in startup config so the client can open and name the conversation on it. Bumps @hanzo/ai to 0.3.4.
56 lines
1.8 KiB
JavaScript
56 lines
1.8 KiB
JavaScript
const { logger } = require('@hanzochat/data-schemas');
|
|
const { EModelEndpoint } = require('@hanzochat/data-provider');
|
|
const { getGuestConfig } = require('~/server/services/guestConfig');
|
|
|
|
/**
|
|
* Server-side capability scope for guest principals.
|
|
*
|
|
* Runs after guest authentication and before `buildEndpointOption`. For guest
|
|
* requests it pins the endpoint and model to the configured free model and strips
|
|
* every capability a guest must not reach (paid models, agents, tools, files,
|
|
* model specs, presets). The client is never trusted: whatever endpoint or model
|
|
* it names is overridden to the free one, so a guest is served free no matter
|
|
* what they send and can never reach a paid route.
|
|
*
|
|
* Non-guest requests pass through untouched.
|
|
*
|
|
* @param {ServerRequest} req
|
|
* @param {ServerResponse} res
|
|
* @param {import('express').NextFunction} next
|
|
*/
|
|
const enforceGuestScope = (req, res, next) => {
|
|
if (req.user?.guest !== true) {
|
|
return next();
|
|
}
|
|
|
|
const config = getGuestConfig();
|
|
if (!config.enabled) {
|
|
return res.status(404).json({ message: 'Guest chat is not enabled' });
|
|
}
|
|
|
|
const body = req.body || {};
|
|
const { endpoint, model } = body;
|
|
if ((endpoint != null && endpoint !== config.endpoint) || (model != null && model !== config.model)) {
|
|
logger.warn(`[enforceGuestScope] Guest ${req.user.id} pinned to the free model from ${endpoint}/${model}`);
|
|
}
|
|
|
|
body.endpoint = config.endpoint;
|
|
body.endpointType = EModelEndpoint.custom;
|
|
body.model = config.model;
|
|
|
|
delete body.agent_id;
|
|
delete body.spec;
|
|
delete body.preset;
|
|
delete body.files;
|
|
delete body.tools;
|
|
delete body.tool_resources;
|
|
delete body.resendFiles;
|
|
delete body.promptPrefix;
|
|
delete body.web_search;
|
|
|
|
req.body = body;
|
|
return next();
|
|
};
|
|
|
|
module.exports = enforceGuestScope;
|