Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,41 @@ public struct InferenceProfile: Hashable, Identifiable {
public var isDisabled: Bool { status == "disabled" }

/// Label for pickers and list rows. Prefers the explicit `label`
/// (e.g. "Quality") and falls back to `name`.
public var displayName: String { label ?? name }
/// (e.g. "Quality") and falls back to a title-cased rendering of
/// `name` when `label` is missing or blank.
///
/// Treating empty / whitespace-only `label` as missing — not just `nil`
/// — keeps the fallback robust against any code path that might set
/// `label = ""` without going through the JSON decoder's normalization.
/// The title-case step makes the fallback presentable since `name` is a
/// stable identifier and is typically kebab- or snake-cased
/// (e.g. `"quality-optimized"` → `"Quality Optimized"`).
public var displayName: String {
if let label, !label.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
return label
}
return Self.titleCased(name)
}

/// Renders a profile identifier as a human-readable label by splitting
/// on common separators (`-`, `_`, whitespace) and capitalising the
/// first character of each part. Returns the input unchanged when no
/// non-separator parts remain (e.g. an empty string or `"---"`).
///
/// Examples:
/// - `"balanced"` → `"Balanced"`
/// - `"quality-optimized"` → `"Quality Optimized"`
/// - `"custom_balanced"` → `"Custom Balanced"`
static func titleCased(_ identifier: String) -> String {
let separators = CharacterSet(charactersIn: "-_").union(.whitespacesAndNewlines)
let parts = identifier
.components(separatedBy: separators)
.filter { !$0.isEmpty }
guard !parts.isEmpty else { return identifier }
return parts
.map { $0.prefix(1).uppercased() + $0.dropFirst() }
.joined(separator: " ")
}

/// Optional secondary text for list row subtitles.
public var subtitle: String? { profileDescription }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ final class ChatProfilePickerTests: XCTestCase {
let profiles = [InferenceProfile(name: "balanced")]
XCTAssertEqual(
ChatProfilePicker.label(current: nil, profiles: profiles, activeProfile: "balanced"),
"Default (balanced)"
"Default (Balanced)"
)
}

Expand All @@ -23,15 +23,15 @@ final class ChatProfilePickerTests: XCTestCase {
]
XCTAssertEqual(
ChatProfilePicker.label(current: "quality-optimized", profiles: profiles, activeProfile: "balanced"),
"quality-optimized"
"Quality Optimized"
)
}

func testLabelReflectsActiveProfileChange() {
let profiles = [InferenceProfile(name: "cost-optimized")]
XCTAssertEqual(
ChatProfilePicker.label(current: nil, profiles: profiles, activeProfile: "cost-optimized"),
"Default (cost-optimized)"
"Default (Cost Optimized)"
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,29 @@ final class InferenceProfileTests: XCTestCase {
XCTAssertFalse(profile.isManaged)
}

func testDisplayNameFallsBackToNameWhenLabelIsNil() {
func testDisplayNameFallsBackToTitleCasedNameWhenLabelIsNil() {
let profile = InferenceProfile(name: "my-profile")
XCTAssertEqual(profile.displayName, "my-profile")
XCTAssertEqual(profile.displayName, "My Profile")
}

func testDisplayNameFallsBackToTitleCasedNameWhenLabelIsEmptyString() {
let profile = InferenceProfile(name: "quality-optimized", label: "")
XCTAssertEqual(profile.displayName, "Quality Optimized")
}

func testDisplayNameFallsBackToTitleCasedNameWhenLabelIsWhitespace() {
let profile = InferenceProfile(name: "custom-balanced", label: " ")
XCTAssertEqual(profile.displayName, "Custom Balanced")
}

func testTitleCasedHandlesCommonIdentifierShapes() {
XCTAssertEqual(InferenceProfile.titleCased("balanced"), "Balanced")
XCTAssertEqual(InferenceProfile.titleCased("quality-optimized"), "Quality Optimized")
XCTAssertEqual(InferenceProfile.titleCased("custom_balanced"), "Custom Balanced")
XCTAssertEqual(InferenceProfile.titleCased("custom-quality-optimized"), "Custom Quality Optimized")
XCTAssertEqual(InferenceProfile.titleCased(" spaced name "), "Spaced Name")
XCTAssertEqual(InferenceProfile.titleCased("---"), "---")
XCTAssertEqual(InferenceProfile.titleCased(""), "")
}

func testSubtitleIsNilWhenDescriptionIsNil() {
Expand Down