tpmjs/apps/omega-mac/OmegaMac/Views/ContentView.swift
Thomas Davis 1cd44b4e97 feat: add Omega Mac native macOS SwiftUI chat app
Native macOS counterpart to the web Omega agent, connecting directly
to the OpenAI API and TPMJS tool registry (1M+ AI-ready tools).

- SwiftUI app targeting macOS 15+ with dark theme
- Full agentic loop: auto-discover tools via BM25, stream OpenAI
  responses, execute tools via remote sandbox, loop up to 10x
- SwiftData persistence for conversations, messages, tool runs
- Keychain storage for API keys and environment variables
- SSE streaming via URLSession.bytes with custom parser
- Actor-based services (OpenAIService, TPMJSRegistryService)
- NavigationSplitView layout with sidebar + chat detail
- MarkdownUI for rendering assistant responses
- Settings: API key, model picker, env vars, custom system prompt
- Keyboard shortcuts: Cmd+N new chat, Cmd+, settings, Enter send

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 21:29:39 +10:00

39 lines
1.3 KiB
Swift

import SwiftData
import SwiftUI
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@State private var selectedConversation: Conversation?
@State private var orchestrator = ChatOrchestrator()
var body: some View {
NavigationSplitView {
SidebarView(
selectedConversation: $selectedConversation,
onNewConversation: createNewConversation
)
.navigationSplitViewColumnWidth(min: 220, ideal: 260, max: 340)
} detail: {
if let conversation = selectedConversation {
ChatView(conversation: conversation, orchestrator: orchestrator)
} else {
EmptyStateView(onNewConversation: createNewConversation)
}
}
.navigationSplitViewStyle(.balanced)
.onChange(of: selectedConversation) {
orchestrator.resetConversation()
}
.onReceive(NotificationCenter.default.publisher(for: .newConversation)) { _ in
createNewConversation()
}
}
private func createNewConversation() {
let conversation = Conversation()
modelContext.insert(conversation)
try? modelContext.save()
selectedConversation = conversation
orchestrator.resetConversation()
}
}