composer changes
This commit is contained in:
@@ -18,7 +18,7 @@ struct StartChatComposer: View {
|
||||
/// project page's "+", so the chat always lands in that project.
|
||||
var lockedProject: WireProject? = nil
|
||||
@State private var projectID: ProjectID?
|
||||
@State private var auto = false
|
||||
@State private var autoOverride: Bool?
|
||||
@State private var model: String?
|
||||
@State private var effort = MobileEfforts.fallback
|
||||
// Advanced options (the Mac new-session sheet's base branch + worktree fields).
|
||||
@@ -31,6 +31,11 @@ struct StartChatComposer: View {
|
||||
lockedProject ?? (projects.first { $0.id == projectID } ?? projects.first)
|
||||
}
|
||||
private var controlled: Bool { selected?.isNucleicControlled ?? false }
|
||||
/// Auto-approve for the chat about to start: the user's choice off-control, but forced on for a
|
||||
/// Nucleic Control project. The host locks Auto on for those chats regardless of what the phone
|
||||
/// sends (they run autonomously — nvrsion needs it: see `AppStore.createSession`), so the
|
||||
/// composer shows it locked on to match the Mac rather than offering a toggle that wouldn't take.
|
||||
private var effectiveAuto: Bool { controlled || (autoOverride ?? false) }
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
@@ -51,12 +56,17 @@ struct StartChatComposer: View {
|
||||
.font(.subheadline).foregroundStyle(.secondary)
|
||||
}
|
||||
Spacer()
|
||||
Toggle(isOn: $auto) {
|
||||
Label("Auto", systemImage: auto ? "bolt.fill" : "bolt.slash")
|
||||
Toggle(isOn: Binding(get: { effectiveAuto }, set: { autoOverride = $0 })) {
|
||||
Label("Auto", systemImage: effectiveAuto ? "bolt.fill" : "bolt.slash")
|
||||
}
|
||||
.toggleStyle(.button)
|
||||
.tint(Palette.accent)
|
||||
.font(.caption)
|
||||
// Locked on for a Nucleic Control project — those chats always run autonomously.
|
||||
.disabled(controlled)
|
||||
.help(controlled
|
||||
? "Auto-approve is always on for Nucleic Control chats — they run autonomously."
|
||||
: "Auto-approve safe actions; destructive ones still ask.")
|
||||
}
|
||||
HStack {
|
||||
ModelMenu(model: $model, catalog: store.modelCatalog, backend: nil)
|
||||
@@ -104,7 +114,7 @@ struct StartChatComposer: View {
|
||||
store.startChat(
|
||||
in: project.id, message: draft, model: model, effort: effort,
|
||||
baseBranch: branch.isEmpty ? nil : branch,
|
||||
useWorktree: useWorktree, auto: auto)
|
||||
useWorktree: useWorktree, auto: effectiveAuto)
|
||||
draft = ""
|
||||
onStart?()
|
||||
}
|
||||
@@ -123,6 +133,10 @@ struct StartChatComposer: View {
|
||||
.padding(.horizontal, 14)
|
||||
.padding(.vertical, 12)
|
||||
.glassSurface(cornerRadius: 26)
|
||||
// Prefill the base branch with the project's default so it actually appears (mirroring the
|
||||
// Mac composer's `effectiveBranch`), rather than sitting as an empty placeholder.
|
||||
.onAppear(perform: syncToProject)
|
||||
.onChange(of: projectID) { _, _ in syncToProject() }
|
||||
// Switching to a model with a lower effort cap can't leave an unsupported level selected.
|
||||
.onChange(of: model) { _, newModel in
|
||||
let levels = store.modelCatalog.offeredEfforts(forModel: newModel)
|
||||
@@ -132,6 +146,16 @@ struct StartChatComposer: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sync the composer to the freshly-selected project: show its default branch as the base, and
|
||||
/// resolve a carried-over Orchestra selection down to a real level when the new project isn't
|
||||
/// under Nucleic Control (Orchestra can't run there — mirrors the Mac's `effectiveEffort`).
|
||||
private func syncToProject() {
|
||||
baseBranch = selected?.defaultBranch ?? ""
|
||||
if MobileEfforts.isOrchestra(effort), !controlled {
|
||||
effort = store.modelCatalog.offeredEfforts(forModel: model).last ?? MobileEfforts.fallback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The floating "+" start-chat affordance: a Liquid Glass circle in the lower-right that reveals
|
||||
|
||||
Reference in New Issue
Block a user