Initial ForgeLM import

This commit is contained in:
Evandro Fonseca Junior committed 2026-03-29 19:10:57 -03:00
commit a392b9dc60
4296 files changed
+1212675

No files matched your search

@@ -0,0 +1,124 @@
# Plan 04-01: Source-Mode Validation Contract
**Wave:** 1
**Phase:** 4
**Requirements addressed:** MODL-01, MODL-02
---
## Objective
Add source-mode compatibility validation to the runtime config so that selecting an invalid combination of connection mode and model/source settings is detected before saving.
---
## Read First
- `tauri-app/src/features/runtime/types.ts` — RuntimeConfig, RuntimeDraftFieldMeta, RuntimeDraftFieldState
- `tauri-app/src/features/runtime/runtime-settings-form.ts` — createRuntimeConfigPatch, resolveDraftModelSelection
- `tauri-app/src/features/runtime/runtime-utils.ts` — RESTART_REQUIRED_FIELDS, draft utilities
- `tauri-app/src/features/runtime/useRuntimeManager.ts` — draft state management
- `.planning/phases/04-model-source-validation/04-RESEARCH.md` — validation patterns research
---
## Action
1. **Add validation types** in `runtime-utils.ts`:
```typescript
export type ValidationSeverity = "error" | "warning";
export interface FieldValidation {
valid: boolean;
severity: ValidationSeverity;
message: string | null;
}
export interface SourceModeValidation {
mode: ConnectionMode;
valid: boolean;
fieldValidations: Record<string, FieldValidation>;
}
```
2. **Create validation functions** in `runtime-utils.ts`:
```typescript
export function validateSourceMode(config: RuntimeConfig): SourceModeValidation {
const fieldValidations: Record<string, FieldValidation> = {};
let valid = true;
if (config.connection_mode === "local") {
// Validate local mode requirements
if (!config.model_path) {
fieldValidations.model_path = {
valid: false,
severity: "error",
message: "Select a model file for local runtime"
};
valid = false;
}
// models_dir is optional for local mode
} else if (config.connection_mode === "remote") {
// Validate remote mode requirements
if (!config.server_url) {
fieldValidations.server_url = {
valid: false,
severity: "error",
message: "Server URL is required for remote runtime"
};
valid = false;
}
}
return {
mode: config.connection_mode,
valid,
fieldValidations
};
}
```
3. **Add path validation helper** that checks if model files exist (calls backend or uses frontend check):
```typescript
export interface PathValidation {
path: string;
exists: boolean;
isValid: boolean;
message: string | null;
}
export function validateModelPath(path: string | null): PathValidation {
if (!path) {
return { path: "", exists: false, isValid: false, message: null };
}
// For now, return pending - actual existence check happens via scan
return { path, exists: true, isValid: true, message: null };
}
```
4. **Integrate into draft field state** in `useRuntimeManager.ts`:
- Import `validateSourceMode` from runtime-utils
- In `updateDraftField`, run source-mode validation after field update
- Store validation results in `draftState.fields` using existing RuntimeDraftFieldMeta
---
## Acceptance Criteria
- [ ] `runtime-utils.ts` exports `validateSourceMode(config)` returning SourceModeValidation
- [ ] `runtime-utils.ts` exports `validateModelPath(path)` returning PathValidation
- [ ] `useRuntimeManager.ts` calls validation on field updates in updateDraftField
- [ ] Invalid source-mode combinations produce field-level validation messages
- [ ] Validation state is stored in draftState.fields and reflected in UI
---
## Notes
- Reuse existing RuntimeDraftFieldMeta structure for validation messages
- Keep validation functions pure where possible for testability
- Path existence validation will be enhanced in plan 04-02 with actual filesystem checks
@@ -0,0 +1,124 @@
# Plan 04-02: Path and Model File Validation
**Wave:** 1
**Phase:** 4
**Requirements addressed:** MODL-02
---
## Objective
Add path existence validation and model file scanning integration so users receive immediate feedback when their selected model path or models directory is invalid.
---
## Read First
- `tauri-app/src-tauri/src/model_files.rs` — scan_models, pick_models_dir commands
- `tauri-app/src/features/runtime/api.ts` — invoke wrappers for Tauri commands
- `tauri-app/src/features/runtime/runtime-settings-form.ts` — RuntimeSettingsFormState, scanned models
- `tauri-app/src/features/runtime/types.ts` — RuntimeModelFile, RuntimePickDirResult
- `.planning/phases/04-model-source-validation/04-RESEARCH.md` — path validation patterns
---
## Action
1. **Add Tauri command wrappers** in `api.ts`:
```typescript
export interface ScannedModelsResult {
dir: string;
models: RuntimeModelFile[];
}
export async function scanModelsDir(dirPath: string): Promise<RuntimeModelFile[]> {
return await invoke<RuntimeModelFile[]>("scan_models", { dir: dirPath });
}
export async function pickModelsDirectory(): Promise<ScannedModelsResult> {
return await invoke<ScannedModelsResult>("pick_models_dir");
}
```
2. **Extend runtime-utils.ts with path validation**:
```typescript
import { scanModelsDir } from "./api";
export async function validateModelsDirectory(
path: string | null
): Promise<{ valid: boolean; modelCount: number; error: string | null }> {
if (!path) {
return { valid: false, modelCount: 0, error: "No models directory selected" };
}
try {
const models = await scanModelsDir(path);
return {
valid: true,
modelCount: models.length,
error: null
};
} catch (e) {
return {
valid: false,
modelCount: 0,
error: e instanceof Error ? e.message : String(e)
};
}
}
export async function validateModelFile(
path: string | null,
scannedModels: RuntimeModelFile[]
): Promise<{ valid: boolean; exists: boolean; error: string | null }> {
if (!path) {
return { valid: false, exists: false, error: "No model selected" };
}
const exists = scannedModels.some(m => m.path === path);
return {
valid: exists,
exists,
error: exists ? null : "Model file not found in current models directory"
};
}
```
3. **Add model scanning to runtime-settings-form.ts**:
- Add `scannedModels: RuntimeModelFile[]` to RuntimeSettingsFormState
- Add `scanModels(dir: string)` function that calls api.scanModelsDir
- Update `resolveDraftModelSelection` to use scanned models for validation
4. **Integrate into useRuntimeManager.ts**:
- Add `scannedModels` to draft state
- When `models_dir` field changes, trigger rescan
- When rescan completes, validate `model_path` against new scan results
- Update field validation state with path-specific errors
5. **Add validation display in UI components**:
- In runtime settings form, show validation message when models_dir is invalid
- Show "X models found" when scan succeeds
- Show "Model not in directory" when selected model is invalid after scan
---
## Acceptance Criteria
- [ ] `api.ts` exports `scanModelsDir(path)` and `pickModelsDirectory()`
- [ ] `runtime-utils.ts` exports async validators that check directory and file existence
- [ ] Changing `models_dir` triggers rescan and updates validation state
- [ ] Selected model is validated against scanned models list
- [ ] Invalid paths show clear error messages in the UI
- [ ] User can see "X models found" feedback after scanning
---
## Notes
- Reuse existing scan_models Rust command - no backend changes needed
- Keep validation async to support filesystem checks
- Show appropriate loading state during scan
- Handle scan errors gracefully (directory not found, permission denied)
@@ -0,0 +1,104 @@
# Plan 04-03: Validation UI and Recovery Experience
**Wave:** 2
**Phase:** 4
**Requirements addressed:** MODL-01, MODL-02
---
## Objective
Implement inline validation UI and recovery guidance so users can understand and fix invalid model-source combinations before applying changes.
---
## Read First
- `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx` — settings form UI
- `tauri-app/src/features/runtime/runtime-settings-form.ts` — form state and validation
- `tauri-app/src/features/runtime/types.ts` — RuntimeDraftFieldMeta, RuntimeWorkspaceHealth
- `.planning/phases/04-model-source-validation/04-RESEARCH.md` — recovery guidance patterns
---
## Action
1. **Add validation message component** in the settings drawer:
Create or extend a validation message display:
```typescript
interface ValidationMessageProps {
field: RuntimeDraftFieldKey;
fieldState: RuntimeDraftFieldMeta;
tone?: "warning" | "danger";
}
// Render below the relevant form field when fieldState.invalid is true
// Show icon + message text
// Use danger tone for errors, warning for recoverable issues
```
2. **Show validation state in form fields**:
- Add visual indicator (red border) to invalid fields
- Add validation message below each invalid field
- Disable or warn when saving with invalid fields
3. **Add recovery guidance for common issues**:
a) **Model not in directory**:
```
"model_path" is not in the current models folder.
Options:
- Select a model from the list below
- Browse to select a different model file
- Change the models folder
```
b) **Models folder empty**:
```
No models found in this folder.
Options:
- Select a different folder
- Add .gguf files to this folder
- Import models from HuggingFace
```
c) **Invalid URL format**:
```
"server_url" must be a valid URL (https://...)
```
4. **Integrate with lifecycle apply flow** (from Phase 2):
- Check field validation before allowing save/apply
- Show "Cannot apply: fix validation errors first" if fields are invalid
- Use applyImpact to determine if restart is needed after validation passes
5. **Add model count badge** in models dir field:
- Show "📁 {dirName} ({count} models)" when scanned
- Show "📁 {dirName} (scanning...)" during scan
- Show "📁 {dirName} (no models)" when empty
---
## Acceptance Criteria
- [ ] Invalid fields show red border and error message
- [ ] Validation messages appear below the relevant form field
- [ ] Recovery guidance provides clear next steps
- [ ] User cannot apply/save when critical fields are invalid
- [ ] Model count is displayed after successful scan
- [ ] Scanning shows loading state
---
## Notes
- Reuse existing form field styling patterns
- Keep validation messages concise but actionable
- Consider accessibility (color-blind users should understand errors)
- Link to relevant documentation or help if needed
- Test with various invalid states: missing dir, invalid path, wrong mode
@@ -0,0 +1,162 @@
# Phase 4: Model Source Validation - Research
**Gathered:** 2026-03-29
**Status:** Complete
---
## Domain Analysis
### Current Model Source System
The app supports two connection modes:
1. **Local Mode** (`connection_mode: "local"`)
- Uses local GGUF model files
- Requires: `model_path`, `models_dir`, `addr`, `gpu_layers`, `ctx_size`
- Supports `extra_model_paths` for additional search paths
2. **Remote Mode** (`connection_mode: "remote"`)
- Uses remote API endpoints (OpenAI, OpenRouter, Anthropic, Custom)
- Requires: `server_url`, `api_key`, `remote_presets`
- Does NOT use local model files
### Existing Model Selection Components
- **RuntimeConfig** (types.ts): Contains `model_path`, `models_dir`, `selected_model_id`, `remote_presets`
- **scan_models** (Rust): Scans directory for .gguf files
- **pick_models_dir** (Rust): Opens folder picker, returns dir + scanned models
- **createRuntimeConfigPatch** (runtime-settings-form.ts): Creates config from form state
- **resolveDraftModelSelection**: Validates selected model against scanned choices
### Draft Field Tracking
Currently tracked draft fields (from Phase 1):
- `models_dir`
- `model_path`
- `selected_model_id`
- `server_url`
- `api_key`
---
## Source Types
### Local Source
- **Models directory**: User-selected folder containing .gguf files
- **Model path**: Specific .gguf file selected from directory
- **Extra model paths**: Additional directories to scan
### Remote Presets
- OpenAI, OpenRouter, Anthropic, Custom, Unknown
- Each has: `id`, `label`, `provider`, `base_url`, `default_model`
### Model Library (Future - implied by MODL-02)
- `ModelLibraryEntry`: `{id, label, source, path}`
- `ModelLibraryState`: `{entries, managed_dir}`
---
## Validation Patterns Needed
### 1. Source-Mode Compatibility
- When `connection_mode` is "local": require valid `model_path` pointing to existing .gguf file
- When `connection_mode` is "remote": require valid `server_url` and optionally `api_key`
- Switching modes should validate the target configuration before allowing save
### 2. Path Validation
- `models_dir`: Must be an existing, readable directory
- `model_path`: Must be an existing .gguf file (if set)
- `server_url`: Must be valid URL format for remote mode
### 3. Model-Source Validation
- A model selection is only valid if:
- It exists in the scanned models from current `models_dir`, OR
- It's in `extra_model_paths` scan results, OR
- It's a manually entered path that exists on filesystem
### 4. Invalid Selection Recovery
- When scanned models change (user picks new folder), detect if current `model_path` is no longer valid
- Show inline validation message: "This draft model is no longer available in the current library or folder scan."
- Provide clear guidance: "Select a model from the list or enter a valid path"
---
## Draft Integration
The existing draft ownership model from Phases 1-3 must be extended:
1. **Field validation state** (`RuntimeDraftFieldMeta`): Already exists with `invalid`, `pending`, `message`
2. **Validation on models_dir change**: When user changes `models_dir`, re-scan and validate `model_path`
3. **Validation on mode switch**: Clear/invalidate fields that don't apply to new mode
### Validation Flow
```
User changes models_dir → scan new directory →
if model_path invalid → set field.invalid=true, field.message="..." →
User sees inline error → User selects valid model or clears path →
field.invalid=false
```
---
## UI/UX Considerations
### Invalid Selection Display
- Show validation message below the model dropdown/input
- Use warning/danger tone based on severity
- Disable save/apply if critical fields are invalid
### Recovery Guidance
- "Model not found in current folder"
- "Select from available models or enter a valid file path"
- "Click 'Scan' to refresh model list"
### Path Selection UX
- Use folder picker dialog for `models_dir`
- Show scanned model count after scan
- Display "No models found" if directory is empty
---
## Dependencies to Reuse
### Existing Patterns
1. **RuntimeDraftFieldState** - Field-level validation tracking
2. **createRuntimeDraftFieldState()** - Initialize field meta
3. **resolveDraftModelSelection()** - Already validates model availability
4. **scan_models** Rust command - Directory scanning
5. **pick_models_dir** Rust command - Folder picker integration
### Types to Extend
- `RuntimeConfig`: Add validation-specific fields if needed
- `RuntimeDraftFieldMeta`: Already sufficient for validation state
### Files to Modify
- `runtime-settings-form.ts`: Add validation functions
- `useRuntimeManager.ts`: Integrate validation into draft flow
- `runtime-utils.ts`: Add source-specific validation helpers
- UI components for validation message display
---
## Technical Approach Summary
1. **Source-Mode Validation**: Add validation functions that check config based on `connection_mode`
2. **Path Existence**: Use backend `scan_models` to verify paths, or add file existence check
3. **Model Availability**: Reuse `resolveDraftModelSelection` pattern for validation
4. **Inline Errors**: Display validation messages in form using existing field meta
5. **Recovery**: Clear guidance on how to fix invalid selections
---
## Open Questions for Planning
1. Should we validate remote preset selections (e.g., check if API key is present)?
2. Do we need to support model compatibility hints (e.g., "this model requires 8GB VRAM")?
3. Should managed library (MODL-02) include model metadata beyond path/name?
4. How do we handle validation during the "save before apply" flow?
---
*Research complete: 2026-03-29*