Add user-scoped Hermes profile access

This commit is contained in:
ekko
2026-05-24 10:11:03 +08:00
committed by ekko
parent 56e7716302
commit 3f6a25d8f1
54 changed files with 2656 additions and 592 deletions
@@ -8,6 +8,7 @@ import { getCopilotModelsDetailed, resolveCopilotOAuthToken, type CopilotModelMe
import { readAppConfig, writeAppConfig, type ModelVisibilityRule } from '../../services/app-config'
import { getDb } from '../../db'
import { MODEL_CONTEXT_TABLE } from '../../db/hermes/schemas'
import { listUserProfiles } from '../../db/hermes/users-store'
const PROVIDER_MODEL_CATALOG = buildProviderModelMap()
@@ -194,6 +195,19 @@ function mergeAvailableGroups(groups: AvailableGroup[]): AvailableGroup[] {
type ProviderFetchCache = Map<string, Promise<string[]>>
function requestedProfileName(ctx: any): string {
const queryProfile = ctx.query?.profile
return typeof queryProfile === 'string' && queryProfile.trim() ? queryProfile.trim() : ''
}
function visibleProfileNamesForUser(ctx: any): string[] {
const diskProfiles = listProfileNamesFromDisk()
const user = ctx.state?.user
if (!user || user.role === 'super_admin') return diskProfiles
const allowed = new Set(listUserProfiles(user.id).map(profile => profile.profile_name))
return diskProfiles.filter(profile => allowed.has(profile))
}
function cachedProviderModels(
cache: ProviderFetchCache,
baseUrl: string,
@@ -379,17 +393,16 @@ async function buildAvailableForProfile(
export async function getAvailable(ctx: any) {
try {
const requestedProfile = typeof ctx.query.profile === 'string' && ctx.query.profile.trim()
? ctx.query.profile.trim()
: ''
const requestedProfile = requestedProfileName(ctx)
if (!requestedProfile) {
const appConfig = await readAppConfig()
const modelAliases = normalizeAliases(appConfig.modelAliases)
const modelVisibility = normalizeModelVisibility(appConfig.modelVisibility)
const customModels = normalizeCustomModels(appConfig.customModels)
const fetchCache: ProviderFetchCache = new Map()
const visibleProfiles = visibleProfileNamesForUser(ctx)
const profileResults = await Promise.all(
listProfileNamesFromDisk().map(profile => buildAvailableForProfile(profile, fetchCache, appConfig)),
visibleProfiles.map(profile => buildAvailableForProfile(profile, fetchCache, appConfig)),
)
const mergedGroups = mergeAvailableGroups(profileResults.flatMap(result => result.groups))
const groupsWithAliases = applyModelAliases(mergedGroups, modelAliases)