Initial ForgeLM import
This commit is contained in:
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*
|
||||
Reference in new issue
Block a user