Flash model quota exhaustion prevents fallback to available Pro model quota

## Issue Description

### Problem Summary

Users are experiencing failures when Flash model quota is exhausted, even when Pro model quota remains available. The current fallback system is hardcoded to only fall back to Flash models, creating a situation where the system cannot utilize available Pro quota when Flash is exhausted.

### Current Behavior

1. **Model Router preferentially routes to Flash**: The `ClassifierStrategy` routes simpler requests to Flash model for efficiency
2. **Flash quota exhausts first**: Due to routing preferences, Flash quota often exhausts before Pro quota
3. **Fallback fails**: When Flash quota is exhausted, the system attempts to fall back but:
   - The fallback handler (`packages/core/src/fallback/handler.ts`) is hardcoded to use `DEFAULT_GEMINI_FLASH_MODEL`
   - If the failed model IS Flash, the handler returns `null` (no fallback)
   - Users get quota errors despite Pro model having available quota

### Root Cause Analysis

#### 1. Hardcoded Fallback Logic
```typescript
// packages/core/src/fallback/handler.ts
export async function handleFallback(
  config: Config,
  failedModel: string,
  authType?: string,
  error?: unknown,
): Promise<string | boolean | null> {
  // ...
  const fallbackModel = DEFAULT_GEMINI_FLASH_MODEL; // Always Flash!

  if (failedModel === fallbackModel) return null; // Can't fallback from Flash
  // ...
}
```

#### 2. Binary Fallback State
```typescript
// packages/core/src/config/config.ts
private inFallbackMode = false; // Single boolean for all models
```
The config tracks fallback as a binary state rather than per-model, preventing intelligent routing between multiple models.

#### 3. Limited Error Detection
```typescript
// packages/core/src/utils/quotaErrorDetection.ts
export function isProQuotaExceededError(error: unknown): boolean { /*...*/ }
export function isGenericQuotaExceededError(error: unknown): boolean { /*...*/ }
// Missing: isFlashQuotaExceededError()
```
The system can detect Pro quota errors but not Flash-specific quota errors, making it impossible to differentiate which model's quota is exhausted.

### User Impact

- **Service interruption**: Users receive quota errors and cannot continue work despite having available quota in Pro model
- **Poor user experience**: Confusing error messages that don't explain why fallback isn't working
- **Wasted resources**: Available Pro model quota goes unutilized
- **Manual workaround required**: Users must manually switch models or change authentication

### Reproduction Steps

1. Use OAuth authentication (LOGIN_WITH_GOOGLE)
2. Make requests that get routed to Flash model (simpler tasks)
3. Continue until Flash daily quota is exhausted
4. Observe that subsequent requests fail with quota errors
5. Manually check that Pro model still has available quota

### Proposed Solution (Immediate Fix)

> [!NOTE]
> This solution is a suggestion from some initial investigation conducted by a LLM. It is not a set design, but rather a possible solution to address this issue.

Implement model-specific quota tracking and intelligent fallback routing:

#### 1. Add Flash Quota Detection
```typescript
// packages/core/src/utils/quotaErrorDetection.ts
export function isFlashQuotaExceededError(error: unknown): boolean {
  // Detect Flash-specific quota exhaustion
}

export function extractModelFromQuotaError(error: unknown): string | null {
  // Extract which model's quota is exhausted from error message
}
```

#### 2. Track Per-Model Exhaustion
```typescript
// packages/core/src/config/config.ts
private exhaustedModels = new Set<string>(); // Track each model separately

setModelExhausted(model: string): void { /*...*/ }
isModelExhausted(model: string): boolean { /*...*/ }
```

#### 3. Implement Intelligent Fallback Strategy
```typescript
// packages/core/src/routing/strategies/fallbackStrategy.ts
private selectFallbackModel(exhaustedModel: string, config: Config): string | null {
  // Define fallback chains
  const fallbackChains = {
    'gemini-2.5-flash': [
      'gemini-2.5-pro',        // Try Pro first when Flash exhausted
      'gemini-2.5-flash-lite'
    ],
    'gemini-2.5-pro': [
      'gemini-2.5-flash',
      'gemini-2.5-flash-lite'
    ]
  };

  // Find first non-exhausted model in chain
  for (const fallback of fallbackChains[exhaustedModel]) {
    if (!config.isModelExhausted(fallback)) {
      return fallback;
    }
  }
  return null;
}
```

### Acceptance Criteria

- [ ] Flash quota exhaustion correctly detected from error messages
- [ ] System can fall back from Flash to Pro when Flash quota exhausted
- [ ] System can fall back from Pro to Flash when Pro quota exhausted
- [ ] Model-specific exhaustion tracked independently
- [ ] Fallback strategy respects model availability
- [ ] All existing tests pass
- [ ] New tests cover fallback scenarios

Labels: priority/p1
State: closed