Files
hyungi_document_server/clients/ds-app/Sources/AI/Composition.swift
T

83 lines
4.0 KiB
Swift

// Composition.swift S2 S3 ( b) + config.
//
// INTEGRATION ( b): (S3) `AIFabric` product ** SwiftPM ** ,
// Sources/AI ( / ). S3 makeDefaultRouter(...)
// MockAIProvider . DSAskClient(HTTP) = S3 .
//
// (S2-Fa): raw URL swap
// (2026-05-17 Hermes incident ). env override . ([[feedback_hermes_config_single_source_envvar]])
import Foundation
import os
public struct AIProviderConfiguration: Sendable {
/// llm-router base (trailing slash base; provider append).
public var localMLXBaseURL: URL
/// llm-router ( 2026-06-05: 'mac-mini-default' gemma-4-26b resolve).
public var localMLXModel: String
/// DS API base S3 DSAskClient . https://document.hyungi.net/api · http://100.110.63.63:8000/api.
/// : DS `/search/ask` **trailing slash **( S3 client ).
public var dsBaseURL: URL
public var requestTimeout: TimeInterval
public var probeTimeout: TimeInterval
public init(
localMLXBaseURL: URL,
localMLXModel: String = "mac-mini-default",
dsBaseURL: URL,
requestTimeout: TimeInterval = 60,
probeTimeout: TimeInterval = 2
) {
self.localMLXBaseURL = localMLXBaseURL
self.localMLXModel = localMLXModel
self.dsBaseURL = dsBaseURL
self.requestTimeout = requestTimeout
self.probeTimeout = probeTimeout
}
/// override ( source). .
public static func resolved(
environment: [String: String] = ProcessInfo.processInfo.environment
) -> AIProviderConfiguration {
let localMLX = environment["AIFABRIC_LOCALMLX_URL"].flatMap(URL.init(string:))
?? URL(string: "http://100.76.254.116:8890")!
let model = environment["AIFABRIC_LOCALMLX_MODEL"] ?? "mac-mini-default"
let ds = environment["AIFABRIC_DS_URL"].flatMap(URL.init(string:))
?? URL(string: "https://document.hyungi.net/api")!
return AIProviderConfiguration(localMLXBaseURL: localMLX, localMLXModel: model, dsBaseURL: ds)
}
}
/// OSLog / (silent ). S3 (public).
public enum AIFabricLog {
static let router = Logger(subsystem: "ds-app.AIFabric", category: "AIRouter")
public static let routerHook: @Sendable (String) -> Void = { msg in
router.info("\(msg, privacy: .public)")
}
}
/// S3 S2 . 4 provider (vision ) + + log .
/// - client: S3 DS ask client(HTTP).
/// - config: ( = env override ).
/// - session: LocalMLX URLSession( .shared; mock ).
public func makeDefaultRouter(
client: DSAskClient,
config: AIProviderConfiguration = .resolved(),
session: URLSession = .shared,
policy: AIRoutingPolicy = .default,
log: @escaping @Sendable (String) -> Void = AIFabricLog.routerHook
) -> AIRouter {
let providers: [AIProviderID: any AIProvider] = [
.remoteDS: RemoteDSProvider(client: client),
.localMLX: LocalMLXProvider(
baseURL: config.localMLXBaseURL,
model: config.localMLXModel,
session: session,
requestTimeout: config.requestTimeout,
probeTimeout: config.probeTimeout
),
.onDevice: OnDeviceProvider(),
.specialized: SpecializedProvider(), // scaffold() vision
]
return AIRouter(providers: providers, policy: policy, log: log)
}