Files
openclaw/apps/macos/Sources/OpenClaw/SystemAgentSettings.swift
Peter Steinberger 9b556bcd5e feat(system-agent): auto-hatch into the agent after fresh setup (#110331)
* feat(system-agent): hatch into the agent after a fresh setup applies

The hatch is a ceremony: a fresh-install setup apply now announces the hatch
and hands straight off (open-tui in the terminal, open-agent for gateway
clients); the web custodian page lands in agent chat with the birth-sequence
opener prefilled as a draft so one Send wakes the seeded BOOTSTRAP. Non-setup
persistent operations keep their in-place replies.

* fix(system-agent): hatch only on clean post-write verification

* fix(ui): scope hatch draft to setup handoffs

* fix(onboarding): seed hatch handoffs across clients

* fix(i18n): refresh native hatch inventory

* fix(onboarding): seed remote gateway hatch handoff

* fix(macos): localize hatch draft

* fix(onboarding): gate hatch on pending bootstrap

* fix(i18n): sync hatch source to ios catalog

* fix(onboarding): gate hatch on canonical pending state
2026-07-18 03:32:15 -04:00

57 lines
1.9 KiB
Swift

import SwiftUI
enum SystemAgentAvailability {
static func shouldShow(configuredModel: String?) -> Bool {
!(configuredModel?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)
}
}
/// Settings pane hosting the OpenClaw setup/repair chat.
///
/// The parent settings view exposes this pane only after inference is configured.
struct SystemAgentSettings: View {
let isActive: Bool
let onReplyReceived: () -> Void
@State private var chat = SystemAgentOnboardingChatModel(
welcomeVariant: nil,
sessionPrefix: "mac-settings-openclaw")
var body: some View {
VStack(alignment: .leading, spacing: 20) {
SettingsPageHeader(
title: "OpenClaw",
subtitle: "Your AI-powered setup helper. It can check status, fix config, " +
"switch models, and connect channels.")
SettingsCardGroup("Chat") {
SystemAgentOnboardingChatView(model: self.chat)
.frame(maxWidth: .infinity, minHeight: 320, maxHeight: .infinity)
}
.frame(maxHeight: .infinity)
Text("Tip: try “status”, “doctor”, “set default model …”, or “connect telegram”.")
.font(.caption)
.foregroundStyle(.secondary)
}
.settingsDetailContent()
.task(id: self.isActive) {
guard self.isActive else { return }
Self.configureChatCallbacks(
for: self.chat,
onReplyReceived: self.onReplyReceived)
await self.chat.startIfNeeded()
}
}
@MainActor
static func configureChatCallbacks(
for chat: SystemAgentOnboardingChatModel,
onReplyReceived: @escaping () -> Void)
{
chat.onAgentHandoff = { agentDraft in
AppNavigationActions.openChat(draft: agentDraft?.composerValue)
}
chat.onReplyReceived = onReplyReceived
}
}