File size: 4,196 Bytes
38cf36c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package com.blaze.agent

import android.content.Context
import android.util.Log
import com.blaze.agent.ai.LLMRouter
import com.blaze.agent.state.AppState
import com.blaze.agent.state.AppStateManager
import com.blaze.agent.task.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch

class AgentOrchestrator(
    private val context: Context,
    private val llmRouter: LLMRouter,
    private val getScreenContent: () -> String,
    private val executeAction: suspend (String) -> Unit
) {
    companion object {
        private const val TAG = "BlazeOrchestrator"
    }

    private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
    private val classifier = TaskClassifier(llmRouter)
    private val taskManager = BackgroundTaskManager(
        context = context,
        llmRouter = llmRouter,
        getScreenContent = getScreenContent,
        executeAgentAction = executeAction
    )

    fun handleCommand(userCommand: String) {
        scope.launch {
            try {
                AppStateManager.transitionTo(AppState.ACTIVE)
                Log.d(TAG, "Handling command: $userCommand")

                if (isStopCommand(userCommand)) {
                    handleStopCommand(userCommand)
                    return@launch
                }

                val classification = classifier.classify(userCommand)
                Log.d(TAG, "Classification: ${classification.taskType}${classification.reasoning}")

                when (classification.taskType) {
                    TaskType.ONE_SHOT -> {
                        executeAction(userCommand)
                        AppStateManager.transitionTo(AppState.SLEEP)
                    }
                    TaskType.MONITORING -> {
                        val task = MonitoringTask(
                            description = userCommand,
                            triggerCondition = classification.triggerCondition ?: "The condition described in the task",
                            actionToExecute = classification.actionToExecute ?: userCommand,
                            isRecurring = classification.isRecurring,
                            checkIntervalMs = classification.checkIntervalMs
                        )
                        taskManager.startTask(task)
                        speakConfirmation(userCommand, classification)
                    }
                }
            } catch (e: Exception) {
                Log.e(TAG, "Failed to handle command: $userCommand", e)
                AppStateManager.transitionTo(AppState.SLEEP)
            }
        }
    }

    private fun isStopCommand(command: String): Boolean {
        val lower = command.lowercase()
        return lower.contains("stop") || lower.contains("cancel") ||
                lower.contains("stop monitoring") || lower.contains("stop watching")
    }

    private fun handleStopCommand(command: String) {
        val lower = command.lowercase()
        when {
            lower.contains("all") || lower.contains("everything") -> taskManager.stopAllTasks()
            else -> {
                val active = taskManager.getActiveTasks()
                val match = active.firstOrNull { task ->
                    command.lowercase().split(" ").any { word ->
                        word.length > 3 && task.description.lowercase().contains(word)
                    }
                }
                if (match != null) taskManager.stopTask(match.id)
                else active.lastOrNull()?.let { taskManager.stopTask(it.id) }
            }
        }
        if (!taskManager.hasActiveTasks()) AppStateManager.transitionTo(AppState.SLEEP)
    }

    private fun speakConfirmation(command: String, classification: TaskClassification) {
        val interval = classification.checkIntervalMs / 1000
        val type = if (classification.isRecurring) "continuously" else "until first match"
        Log.d(TAG, "Monitoring started: checking every ${interval}s, $type")
    }

    fun getActiveTasks(): List<MonitoringTask> = taskManager.getActiveTasks()
    fun stopAllMonitoring() = taskManager.stopAllTasks()
}