diff --git a/.github/scripts/pr_reviewer.py b/.github/scripts/pr_reviewer.py index 527d1cf..2fd043d 100755 --- a/.github/scripts/pr_reviewer.py +++ b/.github/scripts/pr_reviewer.py @@ -164,14 +164,16 @@ def generate_review(client: "genai.Client", primary_model: str, pr_info: dict, d Please execute your autonomous review following the specified criteria and formatting. """ - candidate_models = [primary_model] - for m in ["gemini-3.6-flash", "gemini-2.5-flash", "gemini-2.0-flash"]: + candidate_models = [] + if primary_model and primary_model not in candidate_models: + candidate_models.append(primary_model) + for m in ["gemini-3.6-flash", "gemini-2.5-flash"]: if m not in candidate_models: candidate_models.append(m) last_error = None for model_name in candidate_models: - for attempt in range(3): + for attempt in range(4): try: print(f"[*] Calling Gemini model '{model_name}' (attempt {attempt + 1})...") response = client.models.generate_content( @@ -190,10 +192,12 @@ def generate_review(client: "genai.Client", primary_model: str, pr_info: dict, d last_error = e print(f"[!] Model '{model_name}' (attempt {attempt + 1}) failed: {err_str}") if "503" in err_str or "UNAVAILABLE" in err_str or "429" in err_str: - time.sleep(2 * (attempt + 1)) + sleep_time = (2 ** attempt) * 2 + 1 + print(f"[*] Retrying in {sleep_time}s due to service load...") + time.sleep(sleep_time) continue else: - break # Non-transient error (e.g. 404), move to next candidate model + break # Non-transient error (e.g. 404), try next model return f"Error executing Gemini review: {last_error}", primary_model diff --git a/.github/scripts/repo_auditor.py b/.github/scripts/repo_auditor.py index 05e9701..aa2ba4d 100755 --- a/.github/scripts/repo_auditor.py +++ b/.github/scripts/repo_auditor.py @@ -165,14 +165,16 @@ def run_gemini_audit(client: "genai.Client", primary_model: str, subsystem_key: Please execute your thorough security, concurrency, memory, correctness, and architectural review now. """ - candidate_models = [primary_model] - for m in ["gemini-3.6-flash", "gemini-2.5-flash", "gemini-2.0-flash"]: + candidate_models = [] + if primary_model and primary_model not in candidate_models: + candidate_models.append(primary_model) + for m in ["gemini-3.6-flash", "gemini-2.5-flash"]: if m not in candidate_models: candidate_models.append(m) last_error = None for model_name in candidate_models: - for attempt in range(3): + for attempt in range(4): try: response = client.models.generate_content( model=model_name, @@ -190,7 +192,9 @@ def run_gemini_audit(client: "genai.Client", primary_model: str, subsystem_key: last_error = e print(f"[!] Model '{model_name}' (attempt {attempt + 1}) audit failed for subsystem {subsystem_key}: {err_str}") if "503" in err_str or "UNAVAILABLE" in err_str or "429" in err_str: - time.sleep(2 * (attempt + 1)) + sleep_time = (2 ** attempt) * 2 + 1 + print(f"[*] Retrying subsystem {subsystem_key} in {sleep_time}s due to service load...") + time.sleep(sleep_time) continue else: break diff --git a/.github/workflows/ai-pr-review.yml b/.github/workflows/ai-pr-review.yml index 00fb229..861c8cd 100644 --- a/.github/workflows/ai-pr-review.yml +++ b/.github/workflows/ai-pr-review.yml @@ -42,5 +42,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_EVENT_PATH: ${{ github.event_path }} + GEMINI_MODEL: "gemini-3.6-flash" run: | python3 .github/scripts/pr_reviewer.py diff --git a/.github/workflows/autonomous-audit.yml b/.github/workflows/autonomous-audit.yml index 08fdb30..17da869 100644 --- a/.github/workflows/autonomous-audit.yml +++ b/.github/workflows/autonomous-audit.yml @@ -55,6 +55,7 @@ jobs: GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} + GEMINI_MODEL: "gemini-3.6-flash" INPUT_SUBSYSTEMS: ${{ github.event.inputs.subsystems || 'all' }} INPUT_CREATE_ISSUE: ${{ github.event.inputs.create_issue }} INPUT_FAIL_ON_CRITICAL: ${{ github.event.inputs.fail_on_critical }} diff --git a/app/src/main/java/com/ashishsinghbora/flashcore/ui/FlasherViewModel.kt b/app/src/main/java/com/ashishsinghbora/flashcore/ui/FlasherViewModel.kt index fbeb066..b60a6aa 100644 --- a/app/src/main/java/com/ashishsinghbora/flashcore/ui/FlasherViewModel.kt +++ b/app/src/main/java/com/ashishsinghbora/flashcore/ui/FlasherViewModel.kt @@ -207,23 +207,42 @@ class FlasherViewModel( } } + fun isSameDevice(a: UsbDiskInfo, b: UsbDiskInfo): Boolean { + val serialA = a.serialNumber + val serialB = b.serialNumber + return when { + !serialA.isNullOrBlank() && !serialB.isNullOrBlank() -> serialA == serialB + a.device != null && b.device != null -> { + a.device.deviceId == b.device.deviceId && a.device.deviceName == b.device.deviceName + } + else -> a == b + } + } + val currentSelected = _uiState.value.selectedDevice val selected = when { autoSelectDevice != null -> diskList.find { it.device == autoSelectDevice } ?: diskList.firstOrNull() - currentSelected != null -> diskList.find { it.serialNumber == currentSelected.serialNumber } ?: if (currentSelected.device == null) currentSelected else diskList.firstOrNull() + currentSelected != null -> diskList.find { isSameDevice(it, currentSelected) } ?: if (currentSelected.device == null) currentSelected else diskList.firstOrNull() else -> diskList.firstOrNull() } if (diskList.isNotEmpty() && selected != null) { fsm.transition(FlasherEvent.DevicesUpdated(diskList, selected)) - } else { + } else if (currentSelected?.device != null) { fsm.transition(FlasherEvent.ResetToIdle) } - _uiState.update { - it.copy( + _uiState.update { current -> + val currentDev = current.selectedDevice + val activeSelected = when { + currentDev != null && currentDev.device == null -> currentDev + currentDev != null -> diskList.firstOrNull { isSameDevice(it, currentDev) } ?: selected + else -> selected + } + + current.copy( connectedDevices = diskList, - selectedDevice = selected, + selectedDevice = activeSelected, fsmState = fsm.state.value ) }