Complete implementation guide for the Smart Brain architecture.
- IntentRouter.swift — Finite intent lattice with hybrid classification
- SessionState.swift — Compact conversation state tracking
- OutputVerifier.swift — Two-pass generation with constraint checking
- QuestionGate — Question budget enforcement
- RetrievalFrame.swift — Structured retrieval frames
- TopicGraph.swift — Topic co-occurrence tracking
- SafeModeMonitor.swift — Memory pressure monitoring
- ProcessingIndicator.swift — Async processing UI feedback
- SmartBrain.swift — Main orchestrator
- Add
safeModeMonitorproperty - Add
sessionStateManagerproperty - Add
topicGraphproperty - Add
topicResolverproperty - Add
smartBrainproperty - Create
setupSmartBrain()method - Call
setupSmartBrain()in initialization
File: apps/ios/App/AppServices.swift
// Add properties
@MainActor
private(set) lazy var safeModeMonitor = SafeModeMonitor()
@MainActor
private(set) lazy var sessionStateManager = SessionStateManager()
private(set) lazy var topicGraph = TopicGraph(
storageRoot: storageRoot
)
private(set) lazy var topicResolver = TopicResolver(
topicGraph: topicGraph
)
@MainActor
private(set) var smartBrain: SmartBrain?
// Add setup method
@MainActor
func setupSmartBrain() async {
guard let llm = self.llm else { return }
self.smartBrain = SmartBrain(
llm: llm,
retrievalService: retrievalService,
memoryService: memoryService,
policyRouter: policyRouter,
topicGraph: topicGraph,
safeModeMonitor: safeModeMonitor
)
}
// Call in init
override init() {
super.init()
// ... existing init code ...
Task {
await setupSmartBrain()
}
}- Replace manual flow with
SmartBrain.processChatMessage() - Update message handling to use
SmartResponse - Add intent logging
- Add verification status tracking
- Update citation display
File: apps/ios/UI/Screens/ScreenChat.swift (ChatViewModel)
func send(text: String) async {
// ... validation code ...
guard let smartBrain = services.smartBrain else {
messages.append(ChatLogMessage(role: .system, content: "Smart Brain not initialized"))
return
}
// Add user message
messages.append(ChatLogMessage(role: .user, content: text))
userMessageCount += 1
do {
// Process through Smart Brain
let smartResponse = try await smartBrain.processChatMessage(
text: text,
battery: BatteryIndicator.load(),
styleScores: styleScores,
recentMessages: messages
)
// Add assistant response
messages.append(ChatLogMessage(
role: .assistant,
content: smartResponse.text,
citations: smartResponse.citations
))
lastResponseSpec = smartResponse.spec
// Persistence
try services.saveConversationTurn(
role: "assistant",
content: smartResponse.text,
citations: smartResponse.citations
)
// Telemetry
Diagnostics.shared.record(
component: "SmartBrain",
level: .info,
message: "Response generated",
metadata: [
"intent": smartResponse.intent.rawValue,
"confidence": "\(smartResponse.confidence)",
"verificationPassed": "\(smartResponse.verificationPassed)",
"mode": smartResponse.spec.mode.rawValue
]
)
} catch {
Diagnostics.shared.record(
component: "Chat",
level: .error,
message: "Smart Brain processing failed",
metadata: ["error": error.localizedDescription]
)
messages.append(ChatLogMessage(
role: .system,
content: "Failed to process message: \(error.localizedDescription)"
))
}
}- Add
ProcessingIndicatorManagerto note screens - Implement async processing with stages
- Add topic graph ingestion
- Show processing indicator overlay
- Display completion toast
Files:
apps/ios/UI/Screens/ScreenQuickNote.swiftapps/ios/Core/NoteProcessingPipeline.swift
@StateObject private var processingIndicator = ProcessingIndicatorManager()
// In save/capture flow
Task {
await processingIndicator.processNote(
stages: [.extracting, .embedding, .linking]
) { stage in
switch stage {
case .extracting:
let extraction = try summarizer.extract(from: text)
// Store extraction results
case .embedding:
if !services.safeModeMonitor.shouldDisableEmbeddings {
// Generate embeddings
}
case .linking:
// Update topic graph
await services.topicGraph.ingestNote(
id: noteId,
topics: extraction.properNouns,
projectId: nil,
createdAt: Date()
)
default:
break
}
}
}
// Add overlay to view
.overlay(alignment: .topTrailing) {
ProcessingIndicator(status: processingIndicator.status)
.padding()
}- Add Safe Mode status display
- Add manual reset button
- Show memory warning count
- Display current mode indicator
File: apps/ios/UI/Screens/ScreenSettings.swift
Section("Performance") {
// Current mode
HStack {
Label("Safe Mode", systemImage: "shield.fill")
Spacer()
Text(services.safeModeMonitor.currentMode.rawValue)
.foregroundStyle(modeColor(services.safeModeMonitor.currentMode))
.font(.caption.weight(.medium))
}
// Warning message
if services.safeModeMonitor.currentMode != .normal {
HStack(spacing: 6) {
Image(systemName: "info.circle")
.foregroundColor(.orange)
.font(.caption)
Text("AI is running in \(services.safeModeMonitor.currentMode.rawValue) to maintain stability")
.font(.caption)
.foregroundStyle(.secondary)
}
.padding(.vertical, 4)
}
// Reset button
Button("Reset to Normal Mode") {
services.safeModeMonitor.restoreNormalMode()
}
.disabled(services.safeModeMonitor.currentMode == .normal)
// Memory warnings info
if services.safeModeMonitor.memoryWarningCount > 0 {
Text("Memory warnings: \(services.safeModeMonitor.memoryWarningCount)")
.font(.caption)
.foregroundStyle(.secondary)
}
}
private func modeColor(_ mode: SafeModeMonitor.Mode) -> Color {
switch mode {
case .normal: return .green
case .batterySaver: return .yellow
case .safeMode: return .orange
}
}- Add frame builder integration
- Update context building to use frames
- Add frame formatting for prompts
- Preserve existing retrieval logic as fallback
File: apps/ios/Services/Memory/RetrievalService.swift
private let frameBuilder = RetrievalFrameBuilder()
func buildContextWithFrames(
for query: String,
topK: Int = 6,
maxTokens: Int = 800
) async throws -> RetrievalContextWithFrames {
// Get base context
let baseContext = try await buildContext(
for: query,
topK: topK,
maxTokens: maxTokens
)
// Build frames from snippets
var frameInputs: [(NoteRecord, String, String?)] = []
for snippet in baseContext.noteSnippets {
if let note = try? await notesRepository.note(id: snippet.noteId) {
frameInputs.append((note, snippet.snippetText, snippet.label))
}
}
let frames = frameBuilder.buildFrames(
from: frameInputs,
maxTokens: maxTokens
)
// Build memory fact frames
let factFrames = baseContext.memoryFacts.map { fact in
MemoryFactFrame(
kind: fact.kind.rawValue,
value: fact.value,
confidence: fact.confidence,
firstSeen: fact.firstSeenAt
)
}
return RetrievalContextWithFrames(
frames: frames,
factFrames: factFrames,
memoryFacts: baseContext.memoryFacts,
suggestedTimeRange: baseContext.suggestedTimeRange
)
}
struct RetrievalContextWithFrames {
let frames: [RetrievalFrame]
let factFrames: [MemoryFactFrame]
let memoryFacts: [MemoryFact]
let suggestedTimeRange: DateInterval?
}-
IntentRouterTests— Test classification accuracy -
SessionStateTests— Test state updates -
OutputVerifierTests— Test violation detection -
RetrievalFrameTests— Test frame building -
TopicGraphTests— Test co-occurrence tracking -
SafeModeMonitorTests— Test mode transitions
- End-to-end message flow
- Intent → Response mapping
- Verification → Regeneration
- Safe mode activation
- Topic graph updates
- Async processing completion
Intent Classification:
- "how do you work?" → META_EXPLAIN
- "find my note about fitness" → SEARCH_RECALL
- "i need to exercise more" → CAPTURE_TASK
- "what should i do next?" → PLAN_NEXT_STEPS
- "i feel overwhelmed" → REFLECT_JOURNAL
Session State:
- Send 3 messages, verify state persists
- Check state header in logs
- Verify question budget updates
Output Verification:
- Set questionBudget = 0, verify no questions in response
- Exceed token budget, verify regeneration
- Check repetition detection
Safe Mode:
- Trigger memory warning (simulator)
- Verify mode changes to Battery Saver
- Trigger 3 warnings, verify Safe Mode
- Wait 5 minutes, verify auto-restore
Topic Graph:
- Create notes with "AI", "fitness"
- Query relatedTopics("AI")
- Verify co-occurrence
Async Processing:
- Capture note
- Verify sparkle indicator
- Wait for completion toast
- Check topics were extracted
- Measure intent classification latency (target: <100ms)
- Measure retrieval frame building (target: <200ms)
- Measure full message processing (target: <3s)
- Check memory footprint in each mode
- Profile topic graph queries (target: <50ms)
- Cache intent classification results
- Precompute retrieval frames for recent notes
- Batch topic graph updates
- Optimize frame token estimation
- Reduce verification overhead for low-stakes responses
- Verify LLM unload on idle
- Check topic graph persistence frequency
- Monitor session state growth
- Profile embedding generation memory
- Add intent badge to messages (optional)
- Improve processing indicator animations
- Add Safe Mode banner
- Show topic connections in search
- Display verification status (debug mode)
- Help screen: "How ThoughtOS AI Works"
- Safe Mode explanation
- Intent system overview (simplified)
- Memory & privacy
- Architecture overview (✅ COMPLETE)
- Integration guide (✅ COMPLETE)
- Quick reference (✅ COMPLETE)
- API documentation
- Troubleshooting guide
- Intent classification accuracy
- Question rate per session
- Verification pass rate
- Safe mode activation frequency
- Processing latency percentiles
- User satisfaction (implicit/explicit)
- Compare with/without Smart Brain
- Test different intent thresholds
- Evaluate question budget policies
- Measure retrieval frame effectiveness
- Intent accuracy >85%
- Question rate <15%
- Verification pass >90%
- Safe mode <5% of sessions
- Processing <3s (p95)
- User satisfaction score >4.0/5.0
Functional:
- ✅ All intents correctly classified
- ✅ Session state persists across messages
- ✅ Output verification catches violations
- ✅ Safe mode activates on memory pressure
- ✅ Topic graph builds co-occurrence network
- ✅ Async processing completes with feedback
Performance:
- ✅ <100ms intent classification
- ✅ <3s end-to-end message processing
- ✅ <1GB memory footprint (normal mode)
- ✅ <500MB memory footprint (safe mode)
User Experience:
- ✅ Responses feel coherent and relevant
- ✅ AI doesn't ask excessive questions
- ✅ Memory retrieval is accurate
- ✅ No crashes from memory spikes
- ✅ Processing feedback is clear
Workaround: Warm up LLM on app launch with tiny classification task
Workaround: Implement periodic pruning of low-occurrence topics
Workaround: Adjust warning threshold from 3 to 4-5
Workaround: Reduce quote extraction to 1 per frame
- Edge Case Handling — Build test suite for edge cases
- Prompt Engineering — Iterate on system prompts based on real usage
- Model Upgrades — Test with larger/better models (2.5B, 3B)
- Feature Expansion — Add more intents as needed
- Cross-Platform — Port to other platforms (macOS, watchOS)