Skip to content

Commit 389a544

Browse files
isaacbowenclaude
andcommitted
Fix phoropter-to-chat transition and show "just talk" earlier
- Move chat initiation to onAppear (fires when view is actually visible) - Add error display in chat view so API failures aren't silent - Add diagnostic logging for stream lifecycle - Show "just talk" after first AI-generated pair (not second) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent cb2a792 commit 389a544

4 files changed

Lines changed: 36 additions & 13 deletions

File tree

Lightward/Chat/ChatView.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ struct ChatView: View {
2626
StreamingIndicator()
2727
}
2828

29+
if let error = vm.error {
30+
VStack(alignment: .leading, spacing: 8) {
31+
Text(error)
32+
.font(.caption)
33+
.foregroundStyle(.red.opacity(0.7))
34+
35+
Button(action: { vm.initiateIfNeeded() }) {
36+
Text("→ try again")
37+
.font(.body)
38+
.foregroundStyle(.warmAccent)
39+
}
40+
}
41+
}
42+
2943
Spacer().frame(height: 80)
3044
.id("bottom")
3145
}
@@ -84,6 +98,9 @@ struct ChatView: View {
8498
.padding(.horizontal, 24)
8599
.padding(.bottom, 8)
86100
}
101+
.onAppear {
102+
vm.initiateIfNeeded()
103+
}
87104
}
88105
}
89106

Lightward/Chat/ChatViewModel.swift

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ final class ChatViewModel {
99
var inputText = ""
1010
var streaming = false
1111
var streamingText = ""
12+
var error: String?
1213

1314
private let store: Store
1415
private let phoropterTrail: [String]
@@ -24,12 +25,13 @@ final class ChatViewModel {
2425
}
2526

2627
/// Initiates the conversation with the phoropter trajectory as context.
28+
/// Called from ChatView.onAppear so it fires when the view is actually visible.
2729
func initiateIfNeeded() {
28-
guard !hasInitiated, messages.isEmpty else {
29-
hasInitiated = true
30-
return
31-
}
30+
guard !hasInitiated else { return }
3231
hasInitiated = true
32+
guard messages.isEmpty else { return }
33+
34+
print("ChatViewModel: Initiating with trail: \(phoropterTrail)")
3335
streamResponse(chatLog: LightwardAPI.buildTransitionChatLog(trajectory: phoropterTrail))
3436
}
3537

@@ -38,6 +40,7 @@ final class ChatViewModel {
3840
guard !text.isEmpty, !streaming else { return }
3941

4042
inputText = ""
43+
error = nil
4144

4245
let userMessage = ChatMessage(role: .user, text: text)
4346
messages.append(userMessage)
@@ -51,42 +54,46 @@ final class ChatViewModel {
5154
currentTask?.cancel()
5255
streaming = true
5356
streamingText = ""
57+
error = nil
5458

5559
// Add placeholder assistant message
5660
let placeholder = ChatMessage(role: .assistant, text: "")
5761
messages.append(placeholder)
5862

59-
currentTask = Task { @MainActor in
63+
currentTask = Task {
6064
do {
65+
print("ChatViewModel: Starting stream request...")
6166
for try await event in LightwardAPI.stream(chatLog: chatLog) {
6267
switch event {
6368
case .text(let chunk):
6469
streamingText += chunk
65-
// Update the last message in place
6670
if let last = messages.indices.last {
6771
messages[last].text = streamingText
6872
}
6973

7074
case .started:
71-
break
75+
print("ChatViewModel: Stream started")
7276

7377
case .finished:
74-
break
78+
print("ChatViewModel: Stream finished")
7579
}
7680
}
7781

7882
streaming = false
7983
// Save the completed message
80-
if let last = messages.last {
84+
if let last = messages.last, !last.text.isEmpty {
8185
store.appendMessage(last)
8286
}
87+
print("ChatViewModel: Stream complete, message length: \(messages.last?.text.count ?? 0)")
8388
} catch {
89+
print("ChatViewModel: Stream error: \(error)")
8490
streaming = false
8591
if !Task.isCancelled {
86-
// Remove placeholder on error
92+
// Remove empty placeholder on error
8793
if messages.last?.text.isEmpty == true {
8894
messages.removeLast()
8995
}
96+
self.error = error.localizedDescription
9097
}
9198
}
9299
}

Lightward/Phoropter/PhoropterView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ struct PhoropterView: View {
7171
.foregroundStyle(.warmText.opacity(0.4))
7272
}
7373

74-
// Show "just talk" after second AI response
75-
if vm.aiResponseCount >= 2 {
74+
// Show "just talk" once the first AI-generated pair arrives
75+
if vm.aiResponseCount >= 1 {
7676
Button(action: onDropToChat) {
7777
Text("→ just talk")
7878
.font(.body)

Lightward/RootView.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ struct RootView: View {
5252
withAnimation(.easeInOut(duration: 0.3)) {
5353
phase = .chat
5454
}
55-
chatVM?.initiateIfNeeded()
5655
}
5756

5857
private func startOver() {

0 commit comments

Comments
 (0)