spb/zyquo-cloud Public MIT
Native macOS AI chat client for 12 cloud providers — your keys, every cloud model, one beautiful chat.
Swift 97.4%
Shell 1.7%
Makefile 1%
1//2// ParametersEditorView.swift3// Zyquo Cloud4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// Per-conversation generation parameters. Only the controls the selected9// model actually supports are shown (ParameterSupport gates each row).10//1112import SwiftUI1314struct ParametersEditorView: View {15 @Binding var parameters: ChatParameters16 let support: ParameterSupport1718 var body: some View {19 VStack(alignment: .leading, spacing: ZyquoSpacing.sm) {20 Text("Parameters")21 .font(ZyquoFont.bodyEmphasis())22 .foregroundStyle(ZyquoColor.textPrimary)2324 if support.temperature {25 optionalSlider(26 "Temperature", value: $parameters.temperature,27 range: 0...2, defaultValue: 1, format: "%.2f"28 )29 }30 if support.topP {31 optionalSlider(32 "Top P", value: $parameters.topP,33 range: 0...1, defaultValue: 1, format: "%.2f"34 )35 }36 maxTokensRow37 if support.frequencyPenalty {38 optionalSlider(39 "Frequency penalty", value: $parameters.frequencyPenalty,40 range: -2...2, defaultValue: 0, format: "%.1f"41 )42 }43 if support.presencePenalty {44 optionalSlider(45 "Presence penalty", value: $parameters.presencePenalty,46 range: -2...2, defaultValue: 0, format: "%.1f"47 )48 }49 if support.reasoningEffort {50 reasoningEffortRow51 }52 if support.thinkingToggle {53 Toggle("Extended thinking", isOn: Binding(54 get: { parameters.thinkingEnabled ?? false },55 set: { parameters.thinkingEnabled = $0 }56 ))57 .font(ZyquoFont.body(size: 12.5))58 }59 }60 .padding(ZyquoSpacing.md)61 .frame(width: 300)62 }6364 private var maxTokensRow: some View {65 HStack {66 Text("Max tokens")67 .font(ZyquoFont.body(size: 12.5))68 Spacer()69 TextField(70 "default",71 value: Binding(72 get: { parameters.maxTokens },73 set: { parameters.maxTokens = $0 }74 ),75 format: .number76 )77 .textFieldStyle(.roundedBorder)78 .frame(width: 90)79 .font(ZyquoFont.body(size: 12))80 }81 }8283 private var reasoningEffortRow: some View {84 HStack {85 Text("Reasoning effort")86 .font(ZyquoFont.body(size: 12.5))87 Spacer()88 Picker("", selection: Binding(89 get: { parameters.reasoningEffort ?? "default" },90 set: { parameters.reasoningEffort = $0 == "default" ? nil : $0 }91 )) {92 Text("Default").tag("default")93 Text("Low").tag("low")94 Text("Medium").tag("medium")95 Text("High").tag("high")96 }97 .pickerStyle(.menu)98 .frame(width: 110)99 }100 }101102 /// A slider with an enable checkbox: unchecked = provider default (omitted).103 private func optionalSlider(104 _ title: String,105 value: Binding<Double?>,106 range: ClosedRange<Double>,107 defaultValue: Double,108 format: String109 ) -> some View {110 VStack(alignment: .leading, spacing: 2) {111 HStack {112 Toggle(isOn: Binding(113 get: { value.wrappedValue != nil },114 set: { value.wrappedValue = $0 ? defaultValue : nil }115 )) {116 Text(title).font(ZyquoFont.body(size: 12.5))117 }118 .toggleStyle(.checkbox)119 Spacer()120 Text(value.wrappedValue.map { String(format: format, $0) } ?? "default")121 .font(ZyquoFont.caption)122 .foregroundStyle(ZyquoColor.textTertiary)123 .monospacedDigit()124 }125 if let current = value.wrappedValue {126 Slider(127 value: Binding(get: { current }, set: { value.wrappedValue = $0 }),128 in: range129 )130 .controlSize(.small)131 }132 }133 }134}135