diff --git a/app/src/main/java/com/opendroid/ai/ui/screens/ChatScreen.kt b/app/src/main/java/com/opendroid/ai/ui/screens/ChatScreen.kt index 9b9b13a..d368c33 100644 --- a/app/src/main/java/com/opendroid/ai/ui/screens/ChatScreen.kt +++ b/app/src/main/java/com/opendroid/ai/ui/screens/ChatScreen.kt @@ -389,6 +389,7 @@ fun ChatScreen( ) } else emptyList() ProposedPlanPrompt( + planId = proposedPlan.planId, goal = proposedPlan.goal, stepsCount = proposedPlan.estimatedSteps, blockedActions = blocked, @@ -838,6 +839,7 @@ fun ThinkingBubble() { @Composable fun ProposedPlanPrompt( + planId: String, goal: String, stepsCount: Int, blockedActions: List = emptyList(), @@ -845,7 +847,11 @@ fun ProposedPlanPrompt( onApprove: (Set) -> Unit, onReject: () -> Unit ) { - var checkedGrants by remember(blockedActions) { mutableStateOf(setOf()) } + // Keyed on both: `planId` because a new plan must not inherit the previous + // plan's ticked grants even when the two happen to block the same actions, + // and `blockedActions` because the checkboxes are drawn from that list, so a + // change to it would otherwise leave ticks referring to rows that are gone. + var checkedGrants by remember(planId, blockedActions) { mutableStateOf(setOf()) } Card( modifier = Modifier .fillMaxWidth() diff --git a/app/src/test/java/com/opendroid/ai/core/agent/AutoApprovalPolicyTest.kt b/app/src/test/java/com/opendroid/ai/core/agent/AutoApprovalPolicyTest.kt index 2368318..421bbd0 100644 --- a/app/src/test/java/com/opendroid/ai/core/agent/AutoApprovalPolicyTest.kt +++ b/app/src/test/java/com/opendroid/ai/core/agent/AutoApprovalPolicyTest.kt @@ -98,4 +98,13 @@ class AutoApprovalPolicyTest { AutoApprovalPolicy.shouldAutoApprove(AutoMode.AUTO, granted, Plan("p1", "test", "1m", 1, steps)) ) } + + @Test + fun `blank primary action is ignored`() { + val steps = listOf(step("s0", " ")) + assertTrue( + AutoApprovalPolicy.shouldAutoApprove(AutoMode.AUTO, emptySet(), Plan("p1", "test", "1m", 1, steps)) + ) + assertEquals(emptyList(), AutoApprovalPolicy.blockedActions(emptySet(), steps)) + } }