Skip to content

Commit b2e94a3

Browse files
VyasGurusanchitmonga22
authored andcommitted
Thinking mode in rag plus audio, also fixed camera
1 parent 7e5720a commit b2e94a3

15 files changed

Lines changed: 137 additions & 42 deletions

File tree

examples/ios/RunAnywhereAI/RunAnywhereAI/App/RunAnywhereAIApp.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ struct RunAnywhereAIApp: App {
6464
}
6565
}
6666
.task {
67+
_ = SettingsViewModel.shared
6768
logger.info("🏁 App launched, initializing SDK...")
6869
await initializeSDK()
6970
}

examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Chat/ViewModels/LLMViewModel+Generation.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ extension LLMViewModel {
2424

2525
for try await token in stream {
2626
fullResponse += token
27-
await updateMessageContent(at: messageIndex, content: fullResponse)
27+
let displayText = Self.stripThinkTags(from: fullResponse)
28+
await updateMessageContent(at: messageIndex, content: displayText)
2829
NotificationCenter.default.post(
2930
name: Notification.Name("MessageContentUpdated"),
3031
object: nil

examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Chat/ViewModels/LLMViewModel.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,4 +574,19 @@ final class LLMViewModel {
574574
loadConversation(conversation)
575575
}
576576
}
577+
578+
static func stripThinkTags(from text: String) -> String {
579+
var result = text
580+
// Remove complete <think>...</think> blocks
581+
while let startRange = result.range(of: "<think>"),
582+
let endRange = result.range(of: "</think>"),
583+
startRange.upperBound <= endRange.lowerBound {
584+
result.removeSubrange(startRange.lowerBound..<endRange.upperBound)
585+
}
586+
if let trailingStart = result.range(of: "<think>", options: .backwards),
587+
result.range(of: "</think>", range: trailingStart.upperBound..<result.endIndex) == nil {
588+
result = String(result[result.startIndex..<trailingStart.lowerBound])
589+
}
590+
return result.trimmingCharacters(in: .whitespacesAndNewlines)
591+
}
577592
}

examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Chat/Views/ChatInterfaceView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,8 @@ extension ChatInterfaceView {
370370
.onReceive(
371371
NotificationCenter.default.publisher(for: Notification.Name("MessageContentUpdated"))
372372
) { _ in
373-
if viewModel.isGenerating {
374-
proxy.scrollTo("typing", anchor: .bottom)
373+
if viewModel.isGenerating, let lastMessage = viewModel.messages.last {
374+
proxy.scrollTo(lastMessage.id, anchor: .bottom)
375375
}
376376
}
377377
}
@@ -413,7 +413,7 @@ extension ChatInterfaceView {
413413
.animation(nil, value: message.content)
414414
}
415415

416-
if viewModel.isGenerating {
416+
if viewModel.isGenerating, viewModel.messages.last?.content.isEmpty == true {
417417
TypingIndicatorView()
418418
.id("typing")
419419
.transition(typingTransition)

examples/ios/RunAnywhereAI/RunAnywhereAI/Features/RAG/ViewModels/RAGViewModel.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,16 @@ final class RAGViewModel {
107107
}
108108

109109
do {
110+
let settings = SettingsViewModel.shared
111+
let effectiveQuestion: String
112+
if settings.loadedModelSupportsThinking && !settings.thinkingModeEnabled {
113+
effectiveQuestion = "/no_think\n\(question)"
114+
} else {
115+
effectiveQuestion = question
116+
}
117+
110118
logger.info("Querying RAG pipeline: \(question)")
111-
let result = try await RunAnywhere.ragQuery(question: question)
119+
let result = try await RunAnywhere.ragQuery(question: effectiveQuestion)
112120
messages.append((role: .assistant, text: result.answer))
113121
logger.info("Query complete (\(result.totalTimeMs, format: .fixed(precision: 0))ms)")
114122
} catch {

examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Settings/SettingsViewModel.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ class SettingsViewModel: ObservableObject {
194194

195195
// Load system prompt — fall back to the default when the key has never been set
196196
systemPrompt = UserDefaults.standard.string(forKey: systemPromptDefaultsKey) ?? "You are a helpful, concise AI assistant."
197+
// Persist the default so that other ViewModels reading UserDefaults directly always find a value
198+
if UserDefaults.standard.string(forKey: systemPromptDefaultsKey) == nil {
199+
UserDefaults.standard.set(systemPrompt, forKey: systemPromptDefaultsKey)
200+
}
197201

198202
// Load thinking mode
199203
thinkingModeEnabled = UserDefaults.standard.bool(forKey: thinkingModeKey)

examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Settings/ToolSettingsView.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,12 @@ class ToolSettingsViewModel: ObservableObject {
8484
category: "Utility"
8585
),
8686
executor: { args in
87-
let expression = args["expression"]?.stringValue ?? args["input"]?.stringValue ?? "0"
87+
let expression = args["expression"]?.stringValue
88+
?? args["input"]?.stringValue
89+
?? args["expr"]?.stringValue
90+
?? args.values.compactMap(\.stringValue).first
91+
?? "0"
92+
print("Calculator received args: \(args), using expression: '\(expression)'")
8893
// Clean the expression - remove any non-math characters
8994
let cleanedExpression = expression
9095
.replacingOccurrences(of: "=", with: "")

examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Vision/VLMCameraView.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,10 @@ struct VLMCameraView: View {
296296
private func setupCameraIfNeeded() {
297297
Task {
298298
await viewModel.checkCameraAuthorization()
299-
if viewModel.isCameraAuthorized && viewModel.captureSession == nil {
300-
viewModel.setupCamera()
299+
if viewModel.isCameraAuthorized {
300+
if viewModel.captureSession == nil {
301+
viewModel.setupCamera()
302+
}
301303
viewModel.startCamera()
302304
}
303305
}

examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Voice/VoiceAgentViewModel.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,11 @@ final class VoiceAgentViewModel: ObservableObject {
387387
assistantResponse = ""
388388

389389
do {
390-
session = try await RunAnywhere.startVoiceSession()
390+
let settings = SettingsViewModel.shared
391+
let voiceConfig = VoiceSessionConfig(
392+
thinkingModeEnabled: settings.loadedModelSupportsThinking && settings.thinkingModeEnabled
393+
)
394+
session = try await RunAnywhere.startVoiceSession(config: voiceConfig)
391395
sessionState = .listening
392396
currentStatus = "Listening..."
393397
eventTask = Task { [weak self] in
@@ -419,6 +423,10 @@ final class VoiceAgentViewModel: ObservableObject {
419423
logger.info("Voice session stopped")
420424
}
421425

426+
func interruptSpeaking() async {
427+
await session?.interruptPlayback()
428+
}
429+
422430
/// Force send current audio buffer (for push-to-talk mode)
423431
func sendAudioNow() async {
424432
await session?.sendNow()
@@ -434,9 +442,9 @@ final class VoiceAgentViewModel: ObservableObject {
434442
case .speechStarted: isSpeechDetected = true; currentStatus = "Listening..."
435443
case .processing: sessionState = .processing; currentStatus = "Processing..."; isSpeechDetected = false
436444
case .transcribed(let text): currentTranscript = text
437-
case .responded(let text): assistantResponse = text
445+
case .responded(let text, _): assistantResponse = text
438446
case .speaking: sessionState = .speaking; currentStatus = "Speaking..."
439-
case let .turnCompleted(transcript, response, _):
447+
case let .turnCompleted(transcript, response, _, _):
440448
currentTranscript = transcript; assistantResponse = response
441449
sessionState = .listening; currentStatus = "Listening..."
442450
case .stopped: sessionState = .disconnected; currentStatus = "Ready"

examples/ios/RunAnywhereAI/RunAnywhereAI/Features/Voice/VoiceAssistantView.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,9 @@ extension VoiceAssistantView {
421421
icon: viewModel.micButtonIcon
422422
) {
423423
Task {
424-
if viewModel.isActive {
424+
if viewModel.isSpeaking {
425+
await viewModel.interruptSpeaking()
426+
} else if viewModel.isActive {
425427
await viewModel.stopConversation()
426428
} else {
427429
await viewModel.startConversation()

0 commit comments

Comments
 (0)