Skip to content

ADFA-3016 | Queue model loading while inference engine initializes#991

Merged
jatezzz merged 2 commits intostagefrom
fix/ADFA-3016-queue-model-loading
Feb 19, 2026
Merged

ADFA-3016 | Queue model loading while inference engine initializes#991
jatezzz merged 2 commits intostagefrom
fix/ADFA-3016-queue-model-loading

Conversation

@jatezzz
Copy link
Copy Markdown
Collaborator

@jatezzz jatezzz commented Feb 18, 2026

Description

This PR introduces a queuing mechanism for model loading in the AiSettingsViewModel. If a user selects a model URI while the LLM inference engine is still initializing (which often happens on slower devices due to process death during the file picker intent), the path is temporarily stored in pendingModelUri. Once the engine completes its initialization successfully, the queued model is automatically loaded.

Details

Logic-related change:

  1. _modelLoadingState transitions to Loading and pendingModelUri is set if _engineState is Uninitialized or Initializing.
  2. Upon successful engine initialization, loadModelFromUri is called with the queued path, and pendingModelUri is cleared.

Before changes

Screen.Recording.2026-02-18.at.1.32.36.PM.mov

After changes

Screen.Recording.2026-02-18.at.3.12.06.PM.mov

Ticket

ADFA-3016

Observation

This fix resolves the race condition caused by Android's aggressive memory management, where the ViewModel is recreated and the engine begins initialization at the exact moment the file picker returns the selected model URI.

Stores the selected model path temporarily if the engine is not ready, processing it upon successful initialization
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 18, 2026

📝 Walkthrough

Release Notes

Features

  • Model URI Queuing During Engine Initialization: Added a queuing mechanism that stores model URI selections when the LLM inference engine is not yet initialized (Uninitialized or Initializing states). Once the engine successfully initializes, any queued model path is automatically loaded without requiring user re-selection.
  • Engine State Tracking: Introduced EngineState sealed class with states (Uninitialized, Initializing, Initialized, Error) to provide visibility into the inference engine lifecycle.
  • Improved User Experience: Addresses the race condition on slower devices where the file-picker return coincides with Android process death and ViewModel recreation, preventing model loading failures.

Implementation Details

  • Adds pendingModelUri field to store the queued model path
  • Guards loadModelFromUri() to detect uninitialized/initializing engine states and defer loading
  • Processes queued URI automatically upon successful engine initialization
  • Uses thread-safe state snapshot via local variable to prevent state-check-to-action race conditions

⚠️ Risks and Best Practice Violations

  • Single Queue Limitation: Only one pending model URI can be queued. Rapid successive model selections before initialization completes will overwrite the previous selection—only the final selection will be processed. Consider using a queue data structure if multiple selections need to be preserved.
  • No Timeout or Failure Recovery: If engine initialization fails or takes excessive time, the queued URI is permanently lost with no fallback or notification mechanism. The pending URI is not automatically retried or cleared on error states.
  • Thread Safety Assumption: The pendingModelUri mutable var relies on viewModelScope coroutine confinement for thread safety. While appropriate for this pattern, explicit synchronization or use of atomic operations would be more defensive.
  • Silent Queueing in Error State: When engine state is Error, loadModelFromUri() rejects the load but does not queue it. Users may expect the operation to eventually succeed after recovery, but no such mechanism exists.

Walkthrough

Adds a queuing mechanism to AiSettingsViewModel that defers model loading requests until the AI engine is initialized. When a model load is requested before engine readiness, the URI is stored and processed automatically after initialization completes.

Changes

Cohort / File(s) Summary
Engine initialization state management
app/src/main/java/com/itsaky/androidide/agent/viewmodel/AiSettingsViewModel.kt
Added pendingModelUri field to queue model load requests when engine is not ready. Modified loadModelFromUri to detect uninitialized/initializing engine state and defer the request. After engine initialization, automatically processes queued model URIs.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A model waits in queue so neat,
While engines start their init beat,
No rush, no crash—just poised and cool,
When ready comes, we load our fuel! 🚀

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: introducing a queuing mechanism for model loading during engine initialization.
Description check ✅ Passed The description is well-related to the changeset, explaining the queuing mechanism, its purpose, implementation details, and the race condition it addresses.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/ADFA-3016-queue-model-loading

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/itsaky/androidide/agent/viewmodel/AiSettingsViewModel.kt (1)

70-82: ⚠️ Potential issue | 🟠 Major

Engine-error path leaves _modelLoadingState stuck in Loading with pendingModelUri un-cleared.

When success == false (lines 79-82), _engineState is updated to Error, but:

  1. pendingModelUri is never nulled out.
  2. _modelLoadingState, which was set to Loading at line 95 when the path was queued, is never updated to an error state.

The result is a permanent loading spinner with no error message for the model-load operation, even though the engine has definitively failed. Additionally, a stale pendingModelUri could interfere if initialization is ever retried.

🐛 Proposed fix — clear pending state in the error branch
             } else {
                 _engineState.value = EngineState.Error("Failed to load inference library. Please ensure it's installed.")
+                pendingModelUri?.let {
+                    pendingModelUri = null
+                    _modelLoadingState.value = ModelLoadingState.Error("Inference engine initialization failed.")
+                }
                 Log.e("AiSettingsViewModel", "LLM Inference Engine initialization failed.")
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/itsaky/androidide/agent/viewmodel/AiSettingsViewModel.kt`
around lines 70 - 82, The engine-error branch in AiSettingsViewModel currently
sets _engineState to EngineState.Error but fails to clear pendingModelUri and
update _modelLoadingState, leaving the UI stuck in Loading; modify the failure
branch (where success == false) to set pendingModelUri = null and update
_modelLoadingState to a terminal error state (e.g., ModelLoadingState.Error with
an explanatory message) alongside the existing _engineState update and Log.e
call so the UI shows an error and the queued path is cleared; reference the
symbols _engineState, pendingModelUri, _modelLoadingState, EngineState.Error,
ModelLoadingState (or whatever concrete error enum/class is used) and the
AiSettingsViewModel initialization/error handling block to locate the change.
🧹 Nitpick comments (1)
app/src/main/java/com/itsaky/androidide/agent/viewmodel/AiSettingsViewModel.kt (1)

91-97: ModelLoadingState.Loading at line 95 is slightly misleading; also note silent last-write-wins for multiple rapid selections.

Two minor observations on the queuing guard:

  1. Setting _modelLoadingState.value = ModelLoadingState.Loading (line 95) when the model is only queued (not yet being copied/loaded) may cause the UI to show a loading indicator that begins before any real I/O starts. Consider whether a distinct Queued state or a guarded state (e.g., not setting Loading until the deferred loadModelFromUri actually starts) is more accurate — though the current behaviour is tolerable.

  2. If the user selects a second (or third) model URI while the engine is still initialising, pendingModelUri is silently overwritten (line 94). Only the last selection is processed; earlier ones are discarded without any notification. This is a reasonable "last write wins" policy, but is worth a brief comment for future maintainers.

📝 Suggested documentation comment
         if (currentState is EngineState.Uninitialized || currentState is EngineState.Initializing) {
+            // Only the most recent selection is retained; earlier calls while initializing are discarded.
             pendingModelUri = path
             _modelLoadingState.value = ModelLoadingState.Loading
             return
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/itsaky/androidide/agent/viewmodel/AiSettingsViewModel.kt`
around lines 91 - 97, The current guard sets _modelLoadingState.value =
ModelLoadingState.Loading and overwrites pendingModelUri when the engine is
still initializing; change this by either (a) introducing a distinct queued
state (e.g., ModelLoadingState.Queued) or deferring setting
ModelLoadingState.Loading until loadModelFromUri actually begins, and add a
short comment on the last-write-wins behavior; specifically update the logic
around _engineState checks (EngineState.Uninitialized /
EngineState.Initializing), pendingModelUri, and where _modelLoadingState is
assigned so that the UI only shows Loading when loadModelFromUri starts, and
document that subsequent selections while initializing overwrite pendingModelUri
intentionally.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@app/src/main/java/com/itsaky/androidide/agent/viewmodel/AiSettingsViewModel.kt`:
- Around line 70-82: The engine-error branch in AiSettingsViewModel currently
sets _engineState to EngineState.Error but fails to clear pendingModelUri and
update _modelLoadingState, leaving the UI stuck in Loading; modify the failure
branch (where success == false) to set pendingModelUri = null and update
_modelLoadingState to a terminal error state (e.g., ModelLoadingState.Error with
an explanatory message) alongside the existing _engineState update and Log.e
call so the UI shows an error and the queued path is cleared; reference the
symbols _engineState, pendingModelUri, _modelLoadingState, EngineState.Error,
ModelLoadingState (or whatever concrete error enum/class is used) and the
AiSettingsViewModel initialization/error handling block to locate the change.

---

Nitpick comments:
In
`@app/src/main/java/com/itsaky/androidide/agent/viewmodel/AiSettingsViewModel.kt`:
- Around line 91-97: The current guard sets _modelLoadingState.value =
ModelLoadingState.Loading and overwrites pendingModelUri when the engine is
still initializing; change this by either (a) introducing a distinct queued
state (e.g., ModelLoadingState.Queued) or deferring setting
ModelLoadingState.Loading until loadModelFromUri actually begins, and add a
short comment on the last-write-wins behavior; specifically update the logic
around _engineState checks (EngineState.Uninitialized /
EngineState.Initializing), pendingModelUri, and where _modelLoadingState is
assigned so that the UI only shows Loading when loadModelFromUri starts, and
document that subsequent selections while initializing overwrite pendingModelUri
intentionally.

@jatezzz jatezzz requested a review from a team February 18, 2026 20:50
Copy link
Copy Markdown
Collaborator

@hal-eisen-adfa hal-eisen-adfa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jatezzz jatezzz merged commit b984dc8 into stage Feb 19, 2026
2 checks passed
@jatezzz jatezzz deleted the fix/ADFA-3016-queue-model-loading branch February 19, 2026 20:48
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.

2 participants