New version v2.3.6

This commit is contained in:
2026-03-04 10:19:16 +01:00
parent 65a35cd508
commit 49f842f119
52 changed files with 14034 additions and 358 deletions

View File

@@ -34,6 +34,7 @@ struct MessageRow: View {
private let settings = SettingsService.shared
@State private var isExpanded = false
@State private var isThinkingExpanded = true // auto-expand while streaming, collapse after
#if os(macOS)
@State private var isHovering = false
@@ -107,6 +108,27 @@ struct MessageRow: View {
.foregroundColor(.oaiSecondary)
}
// Thinking / reasoning block (collapsible)
if let thinking = message.thinkingContent, !thinking.isEmpty {
thinkingBlock(thinking)
.onChange(of: message.content) { _, newContent in
// Auto-collapse when response content starts arriving
if !newContent.isEmpty && isThinkingExpanded && !message.isStreaming {
withAnimation(.easeInOut(duration: 0.2)) {
isThinkingExpanded = false
}
}
}
.onChange(of: message.isStreaming) { _, streaming in
// Collapse when streaming finishes
if !streaming && !message.content.isEmpty {
withAnimation(.easeInOut(duration: 0.3)) {
isThinkingExpanded = false
}
}
}
}
// Content
if !message.content.isEmpty {
messageContent
@@ -186,6 +208,64 @@ struct MessageRow: View {
// Close standardMessageLayout - the above closing braces close it
// The body: some View now handles the split between compact and standard
// MARK: - Thinking Block
@ViewBuilder
private func thinkingBlock(_ thinking: String) -> some View {
VStack(alignment: .leading, spacing: 0) {
// Header button
Button(action: {
withAnimation(.easeInOut(duration: 0.18)) { isThinkingExpanded.toggle() }
}) {
HStack(spacing: 6) {
if message.isStreaming && message.content.isEmpty {
ProgressView()
.scaleEffect(0.5)
.frame(width: 12, height: 12)
Text("Thinking…")
.font(.system(size: 11))
.foregroundStyle(.secondary)
} else {
Image(systemName: "brain")
.font(.system(size: 11))
.foregroundStyle(.secondary)
Text("Reasoning")
.font(.system(size: 11))
.foregroundStyle(.secondary)
}
Spacer()
Image(systemName: isThinkingExpanded ? "chevron.up" : "chevron.down")
.font(.system(size: 9, weight: .medium))
.foregroundStyle(.secondary.opacity(0.5))
}
.padding(.horizontal, 10)
.padding(.vertical, 6)
.contentShape(Rectangle())
}
.buttonStyle(.plain)
if isThinkingExpanded {
Divider()
.padding(.horizontal, 6)
ScrollView {
Text(thinking)
.font(.system(size: 12))
.foregroundStyle(.secondary)
.textSelection(.enabled)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(10)
}
.frame(maxHeight: 220)
}
}
.background(Color.secondary.opacity(0.07))
.cornerRadius(6)
.overlay(
RoundedRectangle(cornerRadius: 6)
.strokeBorder(Color.secondary.opacity(0.15), lineWidth: 1)
)
}
// MARK: - Compact System Message
@ViewBuilder