Skip to content

Commit 90b8769

Browse files
authored
🚀 feat: Use Model Specs + Specific Endpoints, Limit Providers for Agents (danny-avila#6650)
* 🔧 refactor: Remove modelSpecs prop from ModelSelector and related components * fix: Update submission.conversationId references in SSE hooks and data types as was incorrectly typed * feat: Allow showing specific endpoints alongside model specs via `addedEndpoints` field * feat: allowed agents providers via `agents.allowedProviders` field * fix: bump dicebear/sharp dependencies to resolve CVE-2024-12905 and improve avatar gen logic * fix: rename variable for clarity in loadDefaultInterface function * fix: add keepAddedConvos option to newConversation calls for modular chat support * fix: include model information in endpoint selection for improved context * fix: update data-provider version to 0.7.78 and increment config version to 1.2.4
1 parent cd7cdaa commit 90b8769

File tree

27 files changed

+905
-777
lines changed

27 files changed

+905
-777
lines changed

‎api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
"passport-ldapauth": "^3.0.1",
105105
"passport-local": "^1.0.0",
106106
"rate-limit-redis": "^4.2.0",
107-
"sharp": "^0.32.6",
107+
"sharp": "^0.33.5",
108108
"tiktoken": "^1.0.15",
109109
"traverse": "^0.6.7",
110110
"ua-parser-js": "^1.0.36",

‎api/server/services/AppService.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ const AppService = async (app) => {
146146
...defaultLocals,
147147
fileConfig: config?.fileConfig,
148148
secureImageLinks: config?.secureImageLinks,
149-
modelSpecs: processModelSpecs(endpoints, config.modelSpecs),
149+
modelSpecs: processModelSpecs(endpoints, config.modelSpecs, interfaceConfig),
150150
...endpointLocals,
151151
};
152152
};

‎api/server/services/Config/getEndpointsConfig.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ async function getEndpointsConfig(req) {
3333
};
3434
}
3535
if (mergedConfig[EModelEndpoint.agents] && req.app.locals?.[EModelEndpoint.agents]) {
36-
const { disableBuilder, capabilities, ..._rest } = req.app.locals[EModelEndpoint.agents];
36+
const { disableBuilder, capabilities, allowedProviders, ..._rest } =
37+
req.app.locals[EModelEndpoint.agents];
3738

3839
mergedConfig[EModelEndpoint.agents] = {
3940
...mergedConfig[EModelEndpoint.agents],
41+
allowedProviders,
4042
disableBuilder,
4143
capabilities,
4244
};

‎api/server/services/Endpoints/agents/initialize.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const { createContentAggregator, Providers } = require('@librechat/agents');
22
const {
3+
ErrorTypes,
34
EModelEndpoint,
45
getResponseSender,
56
AgentCapabilities,
@@ -117,6 +118,7 @@ function optionalChainWithEmptyCheck(...values) {
117118
* @param {ServerRequest} params.req
118119
* @param {ServerResponse} params.res
119120
* @param {Agent} params.agent
121+
* @param {Set<string>} [params.allowedProviders]
120122
* @param {object} [params.endpointOption]
121123
* @param {boolean} [params.isInitialAgent]
122124
* @returns {Promise<Agent>}
@@ -126,8 +128,14 @@ const initializeAgentOptions = async ({
126128
res,
127129
agent,
128130
endpointOption,
131+
allowedProviders,
129132
isInitialAgent = false,
130133
}) => {
134+
if (allowedProviders.size > 0 && !allowedProviders.has(agent.provider)) {
135+
throw new Error(
136+
`{ "type": "${ErrorTypes.INVALID_AGENT_PROVIDER}", "info": "${agent.provider}" }`,
137+
);
138+
}
131139
let currentFiles;
132140
/** @type {Array<MongoFile>} */
133141
const requestFiles = req.body.files ?? [];
@@ -263,13 +271,16 @@ const initializeClient = async ({ req, res, endpointOption }) => {
263271
}
264272

265273
const agentConfigs = new Map();
274+
/** @type {Set<string>} */
275+
const allowedProviders = new Set(req?.app?.locals?.[EModelEndpoint.agents]?.allowedProviders);
266276

267277
// Handle primary agent
268278
const primaryConfig = await initializeAgentOptions({
269279
req,
270280
res,
271281
agent: primaryAgent,
272282
endpointOption,
283+
allowedProviders,
273284
isInitialAgent: true,
274285
});
275286

@@ -285,6 +296,7 @@ const initializeClient = async ({ req, res, endpointOption }) => {
285296
res,
286297
agent,
287298
endpointOption,
299+
allowedProviders,
288300
});
289301
agentConfigs.set(agentId, config);
290302
}

‎api/server/services/start/interface.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@ async function loadDefaultInterface(config, configDefaults, roleName = SystemRol
1818
const { interface: interfaceConfig } = config ?? {};
1919
const { interface: defaults } = configDefaults;
2020
const hasModelSpecs = config?.modelSpecs?.list?.length > 0;
21+
const includesAddedEndpoints = config?.modelSpecs?.addedEndpoints?.length > 0;
2122

2223
/** @type {TCustomConfig['interface']} */
2324
const loadedInterface = removeNullishValues({
2425
endpointsMenu:
2526
interfaceConfig?.endpointsMenu ?? (hasModelSpecs ? false : defaults.endpointsMenu),
26-
modelSelect: interfaceConfig?.modelSelect ?? (hasModelSpecs ? false : defaults.modelSelect),
27+
modelSelect:
28+
interfaceConfig?.modelSelect ??
29+
(hasModelSpecs ? includesAddedEndpoints : defaults.modelSelect),
2730
parameters: interfaceConfig?.parameters ?? (hasModelSpecs ? false : defaults.parameters),
2831
presets: interfaceConfig?.presets ?? (hasModelSpecs ? false : defaults.presets),
2932
sidePanel: interfaceConfig?.sidePanel ?? defaults.sidePanel,

‎api/server/services/start/modelSpecs.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ const { logger } = require('~/config');
66
* Sets up Model Specs from the config (`librechat.yaml`) file.
77
* @param {TCustomConfig['endpoints']} [endpoints] - The loaded custom configuration for endpoints.
88
* @param {TCustomConfig['modelSpecs'] | undefined} [modelSpecs] - The loaded custom configuration for model specs.
9+
* @param {TCustomConfig['interface'] | undefined} [interfaceConfig] - The loaded interface configuration.
910
* @returns {TCustomConfig['modelSpecs'] | undefined} The processed model specs, if any.
1011
*/
11-
function processModelSpecs(endpoints, _modelSpecs) {
12+
function processModelSpecs(endpoints, _modelSpecs, interfaceConfig) {
1213
if (!_modelSpecs) {
1314
return undefined;
1415
}
@@ -20,6 +21,19 @@ function processModelSpecs(endpoints, _modelSpecs) {
2021

2122
const customEndpoints = endpoints?.[EModelEndpoint.custom] ?? [];
2223

24+
if (interfaceConfig.modelSelect !== true && _modelSpecs.addedEndpoints.length > 0) {
25+
logger.warn(
26+
`To utilize \`addedEndpoints\`, which allows provider/model selections alongside model specs, set \`modelSelect: true\` in the interface configuration.
27+
28+
Example:
29+
\`\`\`yaml
30+
interface:
31+
modelSelect: true
32+
\`\`\`
33+
`,
34+
);
35+
}
36+
2337
for (const spec of list) {
2438
if (EModelEndpoint[spec.preset.endpoint] && spec.preset.endpoint !== EModelEndpoint.custom) {
2539
modelSpecs.push(spec);

‎client/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
"@ariakit/react": "^0.4.15",
3232
"@ariakit/react-core": "^0.4.15",
3333
"@codesandbox/sandpack-react": "^2.19.10",
34-
"@dicebear/collection": "^7.0.4",
35-
"@dicebear/core": "^7.0.4",
34+
"@dicebear/collection": "^9.2.2",
35+
"@dicebear/core": "^9.2.2",
3636
"@headlessui/react": "^2.1.2",
3737
"@radix-ui/react-accordion": "^1.1.2",
3838
"@radix-ui/react-alert-dialog": "^1.0.2",

‎client/src/common/selector.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,4 @@ export interface SelectedValues {
2020

2121
export interface ModelSelectorProps {
2222
startupConfig: TStartupConfig | undefined;
23-
modelSpecs: TModelSpec[];
2423
}

‎client/src/components/Chat/Header.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ const defaultInterface = getConfigDefaults().interface;
1616
export default function Header() {
1717
const { data: startupConfig } = useGetStartupConfig();
1818
const { navVisible } = useOutletContext<ContextType>();
19-
const modelSpecs = useMemo(() => startupConfig?.modelSpecs?.list ?? [], [startupConfig]);
2019
const interfaceConfig = useMemo(
2120
() => startupConfig?.interface ?? defaultInterface,
2221
[startupConfig],
@@ -39,7 +38,7 @@ export default function Header() {
3938
<div className="hide-scrollbar flex w-full items-center justify-between gap-2 overflow-x-auto">
4039
<div className="mx-2 flex items-center gap-2">
4140
{!navVisible && <HeaderNewChat />}
42-
{<ModelSelector startupConfig={startupConfig} modelSpecs={modelSpecs} />}
41+
{<ModelSelector startupConfig={startupConfig} />}
4342
{interfaceConfig.presets === true && interfaceConfig.modelSelect && <PresetsMenu />}
4443
{hasAccessToBookmarks === true && <BookmarkMenu />}
4544
{hasAccessToMultiConvo === true && <AddMultiConvo />}

‎client/src/components/Chat/Menus/Endpoints/ModelSelector.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ function ModelSelectorContent() {
9898
);
9999
}
100100

101-
export default function ModelSelector({ startupConfig, modelSpecs }: ModelSelectorProps) {
101+
export default function ModelSelector({ startupConfig }: ModelSelectorProps) {
102102
return (
103-
<ModelSelectorProvider modelSpecs={modelSpecs} startupConfig={startupConfig}>
103+
<ModelSelectorProvider startupConfig={startupConfig}>
104104
<ModelSelectorContent />
105105
</ModelSelectorProvider>
106106
);

0 commit comments

Comments
 (0)