Skip to content

Upstream auto approval review - #45

Merged
JMAN730 merged 2 commits into
mainfrom
fix/upstream-auto-approval-review
Jul 29, 2026
Merged

Upstream auto approval review#45
JMAN730 merged 2 commits into
mainfrom
fix/upstream-auto-approval-review

Conversation

@JMAN730

@JMAN730 JMAN730 commented Jul 29, 2026

Copy link
Copy Markdown
Owner

No description provided.

@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review


P1 Badge Enforce the computed LiteRT output limit

When the prompt leaves fewer tokens than maxTokens (for example, a Qwen prompt occupying 1,000 of its 1,280 tokens), checkPromptFits correctly returns a reduced output budget, but this call discards it and the subsequent ConversationConfig receives no output limit. The request's maxTokens is therefore no longer enforced, so generation can run past the calculated remaining capacity and reach the native overflow this change is intended to prevent; preserve the returned value and apply it to inference.


fun estimateTokens(text: String): Int =
(text.length + CHARS_PER_TOKEN - 1) / CHARS_PER_TOKEN

P1 Badge Avoid undercounting multilingual prompt tokens

For prompts containing CJK text, emoji, or token-dense JSON, dividing UTF-16 character count by four substantially underestimates the tokenizer output—for example, 1,000 CJK characters are reported as only 250 tokens. Such a prompt can pass checkPromptFits even when its real token count exceeds the 1,280-token Qwen cache, still causing the documented native abort; use the model tokenizer or a genuinely conservative upper bound for the safety check.


try {
androidx.core.app.ServiceCompat.startForeground(this, NOTIFICATION_ID, notification, type)
} catch (e: SecurityException) {

P1 Badge Handle Android 15's boot-start exception

When BootReceiver starts this service on Android 15 and RECORD_AUDIO is granted, the code selects the microphone type, but boot-launched microphone foreground services are rejected with ForegroundServiceStartNotAllowedException, which derives from IllegalStateException rather than SecurityException. Consequently this catch never reaches the advertised specialUse fallback and the assistant service fails after reboot; handle the boot-start exception or select specialUse based on the launch source before requesting the microphone type.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@greptile-apps

greptile-apps Bot commented Jul 29, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

Safe to merge — the checkbox key fix is a targeted correctness improvement with no behaviour change elsewhere, and the new test documents existing behaviour without modifying any production logic.

Both changes are small and well-scoped. The remember dual-key in ProposedPlanPrompt correctly prevents grant state from leaking across plans that share the same blocked action list. The new test adds coverage for an already-handled edge case without touching production code. No regressions are expected.

Files Needing Attention: No files require special attention. The only open question is whether a plan composed entirely of blank-action steps should auto-approve or be held for manual review, but this is a pre-existing design decision that the PR merely documents with a test.

Important Files Changed

Filename Overview
app/src/main/java/com/opendroid/ai/ui/screens/ChatScreen.kt Adds planId parameter to ProposedPlanPrompt and uses it as a remember key alongside blockedActions to prevent checkbox state from leaking between plans that share the same blocked action list.
app/src/test/java/com/opendroid/ai/core/agent/AutoApprovalPolicyTest.kt Adds a test asserting a step with a blank primary action is auto-approved with an empty granted set; the assertion is technically correct but documents a subtle edge case where a fully-blank-action plan is treated as having no blocked actions and thus auto-approves.

Sequence Diagram

sequenceDiagram
    participant VM as ViewModel
    participant CS as ChatScreen
    participant APP as AutoApprovalPolicy
    participant PPP as ProposedPlanPrompt

    VM->>CS: AgentState.PlanProposed(plan)
    CS->>APP: blockedActions(granted, plan.steps)
    APP-->>CS: "blocked: List<String>"
    CS->>PPP: "planId, goal, blockedActions=blocked, ..."
    Note over PPP: remember(planId, blockedActions)<br/>resets checkedGrants when<br/>either key changes
    PPP-->>CS: onApprove(grants) / onReject()
    CS->>VM: approvePlan(grants) / rejectPlan()
Loading

Reviews (2): Last reviewed commit: "Merge branch 'main' into fix/upstream-au..." | Re-trigger Greptile

One conflict, in ProposedPlanPrompt's checkedGrants state. Both sides
replaced the same unkeyed `remember { }`: main keyed it on
`blockedActions`, this branch keyed it on the newly threaded `planId`.

Resolved by keying on both. `planId` is the identity key — two different
plans that happen to block the same actions must not share ticked
grants, which keying on `blockedActions` alone would allow. But the
checkboxes are rendered from `blockedActions`, so a change to that list
also has to clear ticks that now refer to rows which are gone. Neither
key subsumes the other.
@JMAN730

JMAN730 commented Jul 29, 2026

Copy link
Copy Markdown
Owner Author

Merged main into this branch in 74d02e7 to clear the conflict.

One conflict, in ProposedPlanPrompt's checkedGrants. Both sides had replaced the same unkeyed remember { }: main keyed it on blockedActions, this branch keyed it on the newly threaded planId.

Resolved by keying on both, because neither key subsumes the other. planId is the identity key — two different plans that happen to block the same set of actions must not share ticked grants, which keying on blockedActions alone would allow. But the checkboxes are rendered from blockedActions, so a change to that list also has to clear ticks referring to rows that no longer exist.

var checkedGrants by remember(planId, blockedActions) { mutableStateOf(setOf<String>()) }

Verified locally before pushing: ./gradlew :app:testDebugUnitTest → 185 tests, 0 failures, 0 errors; :app:assembleDebug succeeds. CI green on both checks.

@JMAN730
JMAN730 merged commit 75b2041 into main Jul 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant