Add runtime provider controls and searchable AI routing
CI / verify (push) Has been cancelled
CI / publish (push) Has been cancelled

Manage provider keys at runtime, route current-information questions through server-side search with safe fallback, and scope OOBE usage claims to grants.
This commit is contained in:
Rocky
2026-08-22 16:33:17 +08:00
parent f8fa93dc48
commit 9fb947aa7d
43 changed files with 2079 additions and 80 deletions
@@ -88,6 +88,12 @@ import com.osglab.account.features.gateway.adapters.CreditReservationAdapter
import com.osglab.account.features.gateway.adapters.SessionIdentityAdapter
import com.osglab.account.features.gateway.GatewaySettings
import com.osglab.account.features.gateway.asr.AsrStreamingService
import com.osglab.account.features.gateway.credentials.DatabaseProviderApiKeyResolver
import com.osglab.account.features.gateway.credentials.EnvironmentProviderCredentials
import com.osglab.account.features.gateway.credentials.ExposedGatewayCredentialRepository
import com.osglab.account.features.gateway.credentials.GatewayCredentialRepository
import com.osglab.account.features.gateway.credentials.GatewayCredentialService
import com.osglab.account.features.gateway.credentials.ProviderApiKeyResolver
import com.osglab.account.features.gateway.ports.CreditReservationPort
import com.osglab.account.features.gateway.ports.ComplimentaryRequestPort
import com.osglab.account.features.gateway.ports.GatewayAccessTokenPort
@@ -272,7 +278,11 @@ fun Application.module() {
val providerConfig = appConfig.providers.volcengine.toProviderConfig()
AsrStreamingService(
gateway = koin.get(),
upstream = KtorVolcengineAsrTransport(koin.get(), providerConfig),
upstream = KtorVolcengineAsrTransport(
client = koin.get(),
config = providerConfig,
credentialResolver = koin.get(),
),
scope = this,
)
} else {
@@ -367,6 +377,7 @@ fun Application.module() {
grantService = koin.get(),
operatorService = koin.get(),
auditService = koin.get(),
credentialService = koin.get(),
contentService = koin.get(),
hintFeedService = koin.get(),
)
@@ -399,6 +410,19 @@ fun accountServerModule(config: AppConfig): Module = module {
single { SessionJwt(config.session) }
single { FieldEncryptor(config.encryption.key) }
single { IdentityFingerprint(config.antiAbuse.identityHmacKey) }
single<GatewayCredentialRepository> { ExposedGatewayCredentialRepository(get()) }
single {
EnvironmentProviderCredentials(
deepSeekApiKey = config.providers.deepSeek.apiKey,
volcengineApiKey = config.providers.volcengine.apiKey,
volcengineLegacyConfigured =
!config.providers.volcengine.appId.isNullOrBlank() &&
!config.providers.volcengine.accessToken.isNullOrBlank(),
)
}
single { DatabaseProviderApiKeyResolver(get(), get(), get()) }
single<ProviderApiKeyResolver> { get<DatabaseProviderApiKeyResolver>() }
single { GatewayCredentialService(get(), get(), get()) }
single<AdminRepository> { ExposedAdminRepository(get()) }
single<AdminPasswordHasher> { BouncyCastleArgon2idPasswordHasher() }
single<AdminTotpVerifier> { HmacTotpVerifier() }
@@ -667,7 +691,7 @@ fun accountServerModule(config: AppConfig): Module = module {
)
}
single {
ProviderCatalog(configuredProviders(config, get()))
ProviderCatalog(configuredProviders(config, get(), get()))
}
single { GatewayService(get(), get(), get(), get(), get(), get()) }
single { GatewayReconciliationService(get(), get()) }
@@ -680,7 +704,11 @@ fun accountServerModule(config: AppConfig): Module = module {
}
}
private fun configuredProviders(config: AppConfig, client: HttpClient): List<GatewayProvider> =
private fun configuredProviders(
config: AppConfig,
client: HttpClient,
credentialResolver: ProviderApiKeyResolver,
): List<GatewayProvider> =
buildList {
config.providers.deepSeek.apiKey?.let { apiKey ->
add(
@@ -692,12 +720,21 @@ private fun configuredProviders(config: AppConfig, client: HttpClient): List<Gat
model = config.providers.deepSeek.model,
reasoningModel = config.providers.deepSeek.reasoningModel,
),
credentialResolver = credentialResolver,
),
)
}
if (config.providers.volcengine.credentialsAvailable) {
val providerConfig = config.providers.volcengine.toProviderConfig()
add(VolcengineAsrProvider(KtorVolcengineAsrTransport(client, providerConfig)))
add(
VolcengineAsrProvider(
KtorVolcengineAsrTransport(
client = client,
config = providerConfig,
credentialResolver = credentialResolver,
),
),
)
}
}