Repository navigation
Expand file tree
/
Copy pathChatView.swift
More file actions
92 lines (84 loc) · 2.97 KB
/
Copy pathChatView.swift
File metadata and controls
92 lines (84 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import SwiftUI
import CodexKitUI
@MainActor
struct ChatView: View {
@State private var model = ChatViewModel()
var body: some View {
Group {
if let store = model.store {
content(store: store)
} else if let error = model.setupError {
Text(error)
Button("Retry") { Task { await model.start() } }
} else {
ProgressView("Preparing chat…")
}
}
.task { await model.start() }
}
private func content(store: AgentRuntimeStore) -> some View {
VStack(alignment: .leading, spacing: 12) {
if store.session == nil {
Button("Sign in with ChatGPT") {
model.signIn()
}
.disabled(model.isBusy)
} else {
HStack {
Button("New conversation") {
model.newConversation()
}
Button("Sign out") { model.signOut() }
}
.disabled(model.isBusy)
Menu("Saved conversations") {
ForEach(store.threads) { thread in
Button(thread.title ?? "Conversation") {
model.selectConversation(id: thread.id)
}
}
}
.disabled(model.isBusy)
}
if let prompt = store.deviceCodeCoordinator?.currentPrompt {
Text("Enter this code: \(prompt.userCode)")
.textSelection(.enabled)
Link("Continue ChatGPT sign-in", destination: prompt.verificationURL)
}
ScrollView {
VStack(alignment: .leading, spacing: 12) {
ForEach(store.messages) { message in
Text(message.displayText)
}
if !store.streamingText.isEmpty {
Text(store.streamingText)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}
if let approval = store.approvalInbox?.currentRequest {
Text(approval.title).bold()
Text(approval.message)
HStack {
Button("Approve") { model.approveTool() }
Button("Deny") { model.denyTool() }
}
}
HStack {
TextField("Message", text: $model.draft)
Button("Send") {
model.send()
}
.disabled(!model.canSend)
if model.isSending {
Button("Stop") { model.stop() }
}
}
if let error = store.lastError {
Text(error).foregroundStyle(.red)
Button("Dismiss error") { model.dismissError() }
}
}
.padding()
}
}