Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 16 additions & 17 deletions clients/shared/App/Auth/AuthService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,25 @@ import os

private let log = Logger(subsystem: Bundle.main.bundleIdentifier ?? "com.vellum.vellum-assistant", category: "AuthService")

// MARK: - Thread-safe configuredBaseURL storage (module-private)
// These live outside the @MainActor class so they are nonisolated by default.
// GatewayHTTPClient (nonisolated) reads via AuthService.currentConfiguredBaseURL;
// SettingsStore (@MainActor) writes via AuthService.shared.configuredBaseURL.
// MARK: - Module-private constants and storage (nonisolated by default)
// These live outside the @MainActor class so nonisolated static functions
// (resolveBaseURL, normalizedBaseURL) can reference them without crossing
// into @MainActor isolation — which is an error in Swift 6 language mode.
private let _configuredBaseURLLock = NSLock()
private var _configuredBaseURLValue: String = ""
private let _platformURLOverrideEnvironmentKey = "VELLUM_PLATFORM_URL"
private let _authServiceBaseURLDefaultsName = "authServiceBaseURL"
private let _defaultBaseURL: String = {
#if DEBUG && os(macOS)
return "http://localhost:8000"
#else
return "https://platform.vellum.ai"
#endif
}()

@MainActor
public final class AuthService {
public static let shared = AuthService()
private static let platformURLOverrideEnvironmentKey = "VELLUM_PLATFORM_URL"
private static let authServiceBaseURLDefaultsName = "authServiceBaseURL"

private static let defaultBaseURL: String = {
#if DEBUG && os(macOS)
return "http://localhost:8000"
#else
return "https://platform.vellum.ai"
#endif
}()

/// Platform base URL from daemon config. Set by SettingsStore when the
/// `platform_config_response` arrives. When non-empty, takes precedence
Expand Down Expand Up @@ -68,19 +67,19 @@ public final class AuthService {
environment: [String: String],
userDefaults: UserDefaults
) -> String {
if let override = normalizedBaseURL(environment[platformURLOverrideEnvironmentKey]) {
if let override = normalizedBaseURL(environment[_platformURLOverrideEnvironmentKey]) {
return override
}
if let configured = normalizedBaseURL(configuredBaseURL) {
return configured
}
#if DEBUG
// Keep the UserDefaults override as a fallback for direct debug sessions.
if let override = normalizedBaseURL(userDefaults.string(forKey: authServiceBaseURLDefaultsName)) {
if let override = normalizedBaseURL(userDefaults.string(forKey: _authServiceBaseURLDefaultsName)) {
return override
}
#endif
return defaultBaseURL
return _defaultBaseURL
}

nonisolated private static func normalizedBaseURL(_ raw: String?) -> String? {
Expand Down
2 changes: 1 addition & 1 deletion clients/shared/Network/BtwClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public struct BtwClient: BtwClientProtocol {
/// Returns an `AsyncThrowingStream` that yields text deltas from SSE `btw_text_delta` events.
public func sendMessage(content: String, conversationKey: String) -> AsyncThrowingStream<String, Error> {
return AsyncThrowingStream { continuation in
let task = Task { @MainActor in
let task = Task {
do {
try await Self.streamBtw(content: content, conversationKey: conversationKey, continuation: continuation)
} catch {
Expand Down