Skip to content

Commit

Permalink
Add failed conversation state
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeLyon committed Nov 15, 2024
1 parent ea917df commit 563a6cb
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "6eb4723ca729b176127a880db635eeb2659e75c35074edf1379ffd16cca71188",
"originHash" : "6aa168046c20ee6b7aa56c4a49ce37013c5549ba737cd0fddd5900d5dc7919c2",
"pins" : [
{
"identity" : "swift-async-algorithms",
Expand Down Expand Up @@ -42,8 +42,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/GeorgeLyon/SwiftClaude",
"state" : {
"branch" : "main",
"revision" : "9533601800d179e885fd666e6e1432530f12d582"
"branch" : "dev/george/conversation",
"revision" : "f4899c7118a6028160953f20bff796cc6feab80f"
}
}
],
Expand Down
5 changes: 4 additions & 1 deletion .xcode/SwiftProjectTemplateAppPackage/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ let package = Package(
],
dependencies: [
.package(name: "SwiftProjectTemplate", path: "../SwiftProjectTemplate"),
.package(url: "https://github.com/GeorgeLyon/SwiftClaude", branch: "main")
.package(
url: "https://github.com/GeorgeLyon/SwiftClaude",
branch: "dev/george/conversation"
)
],
targets: [
.target(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import SwiftUI
struct App: SwiftUI.App {
var body: some Scene {
WindowGroup {
ContentView()
ClaudeProvider(
defaultModel: .claude35Sonnet20241022
) { claude in
ContentView(claude: claude)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,31 @@ public struct ClaudeProvider<Content: View>: View {
public var body: some View {
switch authenticator.authenticationState {
case .authenticated(let summary):
ClaudeProviderContentWrapper(
authenticator: authenticator,
defaultModel: defaultModel,
content: content
)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.overlay(alignment: .topTrailing) {
Button {
_ = try? authenticator.deleteApiKey()
} label: {
Image(systemName: "key")
.help("Clear Current API Key (\(summary))")
NavigationStack {
ClaudeProviderContentWrapper(
authenticator: authenticator,
defaultModel: defaultModel,
content: content
)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.navigationTitle("SwiftProjectTemplate")
.toolbar {
ToolbarItem(placement: .destructiveAction) {
Button {
isClearAPIKeyAlertPresented = true
} label: {
Image(systemName: "key")
.help("Clear Current API Key (\(summary))")
}
}
}
.padding()
}
.alert(isPresented: $isClearAPIKeyAlertPresented) {
Alert(
title: Text("Current API Key:\n\(summary)"),
primaryButton: .destructive(Text("Clear")),
secondaryButton: .default(Text("OK"))
)
}
case .unauthenticated:
SetAPIKeyView(authenticator: authenticator)
Expand All @@ -39,6 +50,9 @@ public struct ClaudeProvider<Content: View>: View {
}
}

@State
private var isClearAPIKeyAlertPresented = false

@State
private var authenticator = Claude.KeychainAuthenticator(
namespace: "com.github.georgelyon.SwiftProjectTemplate",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,89 @@
import SwiftUI
import Claude

struct ContentView: View {

let claude: Claude

var body: some View {
ClaudeProvider(
defaultModel: .claude35Sonnet20241022
) { claude in
Text("Authenticated!")
ScrollView {
LazyVStack(alignment: .leading) {
ForEach(conversation.messages) { message in
switch message {
case .user(let message):
Text("USER:")
Text("\(message.text)")
case .assistant(let message):
Text("ASSISTANT:")
ForEach(message.currentContentBlocks) { contentBlock in
switch contentBlock {
case .textBlock(let textBlock):
Text(textBlock.currentText)
}
}
}
}

switch conversation.state {
case .idle:
HStack(alignment: .bottom) {
TextEditor(text: $text)
.onSubmit {
send(text)
}
.focused($isTextEditorFocused)
Button("Send") {
send(text)
}
}
case .streaming, .waitingForToolInvocationResults:
ProgressView()
case .toolInvocationResultsAvailable:
Button("Provide tool invocation results") {
send()
}
}
}
}
.padding()
.onAppear {
isTextEditorFocused = true
}
}

private func send(_ message: String? = nil) {
text = ""
if let message {
conversation.messages.append(.user(.init(text: message)))
}
let message = claude.nextMessage(in: conversation)
conversation.messages.append(.assistant(message))
}

@State
private var conversation = Conversation()

@State
private var text = ""

@FocusState
private var isTextEditorFocused

}

#Preview {
ContentView()
private struct Conversation: Claude.Conversation {

var messages: [Message] = []

final class UserMessage: Identifiable {
init(text: String) {
self.text = text
}
let text: String
}

static func userMessageContent(for message: UserMessage) -> Claude.UserMessageContent {
.init(message.text)
}

}
7 changes: 5 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ let package = Package(
targets: ["SwiftProjectTemplate"])
],
dependencies: [
.package(url: "https://github.com/GeorgeLyon/SwiftClaude", branch: "main")
.package(
url: "https://github.com/GeorgeLyon/SwiftClaude",
branch: "dev/george/conversation"
)
],
targets: [
.target(
name: "SwiftProjectTemplate",
dependencies: [
"SwiftClaude",
"SwiftClaude"
]
),
.testTarget(
Expand Down

0 comments on commit 563a6cb

Please sign in to comment.