From 941d9427b656bbb199144fe58acddc1dd26c3b6a Mon Sep 17 00:00:00 2001 From: RadDad87 <142544102+RadDad87@users.noreply.github.com> Date: Mon, 30 Mar 2026 09:54:54 -0400 Subject: [PATCH 1/3] Define portable layout and %~dp0 launcher defaults for Task 10 --- PROJECT_BRIEF.md | 62 ++++++++++ README.md | 90 ++++++++++++++ TASKS.md | 67 ++++++++++ Z3R4H_CLEAN_ENV_CHECKLIST.md | 77 ++++++++++++ Z3R4H_PROGRESS_SUMMARY.md | 62 ++++++++++ backend/open_webui/static/site.webmanifest | 4 +- launch_z3r4h.bat | 116 ++++++++++++++++++ src/app.html | 2 +- src/lib/components/channel/Channel.svelte | 7 +- src/lib/components/chat/Chat.svelte | 81 ++++++++++-- src/lib/components/chat/Navbar.svelte | 23 ++-- .../components/chat/Z3R4HModeSelector.svelte | 25 ++++ src/lib/constants.ts | 2 +- src/lib/prompts/z3r4h/core_system.txt | 3 + src/lib/prompts/z3r4h/failure_behavior.txt | 3 + .../z3r4h/modes/engineering_repair.txt | 2 + .../prompts/z3r4h/modes/general_advisor.txt | 2 + .../prompts/z3r4h/modes/low_power_mode.txt | 2 + .../prompts/z3r4h/modes/medical_reference.txt | 3 + .../z3r4h/modes/navigation_terrain.txt | 2 + src/lib/utils/z3r4hModeRouting.ts | 46 +++++++ src/lib/utils/z3r4hPromptStack.ts | 20 +++ src/routes/+layout.svelte | 4 +- src/routes/auth/+page.svelte | 3 + static/opensearch.xml | 4 +- static/static/site.webmanifest | 4 +- 26 files changed, 683 insertions(+), 33 deletions(-) create mode 100644 PROJECT_BRIEF.md create mode 100644 TASKS.md create mode 100644 Z3R4H_CLEAN_ENV_CHECKLIST.md create mode 100644 Z3R4H_PROGRESS_SUMMARY.md create mode 100644 launch_z3r4h.bat create mode 100644 src/lib/components/chat/Z3R4HModeSelector.svelte create mode 100644 src/lib/prompts/z3r4h/core_system.txt create mode 100644 src/lib/prompts/z3r4h/failure_behavior.txt create mode 100644 src/lib/prompts/z3r4h/modes/engineering_repair.txt create mode 100644 src/lib/prompts/z3r4h/modes/general_advisor.txt create mode 100644 src/lib/prompts/z3r4h/modes/low_power_mode.txt create mode 100644 src/lib/prompts/z3r4h/modes/medical_reference.txt create mode 100644 src/lib/prompts/z3r4h/modes/navigation_terrain.txt create mode 100644 src/lib/utils/z3r4hModeRouting.ts create mode 100644 src/lib/utils/z3r4hPromptStack.ts diff --git a/PROJECT_BRIEF.md b/PROJECT_BRIEF.md new file mode 100644 index 00000000000..99e4ad982e1 --- /dev/null +++ b/PROJECT_BRIEF.md @@ -0,0 +1,62 @@ +# Z3R4H Project Brief + +## Product +Z3R4H is a custom-branded offline survival AI interface built on Open WebUI and powered by local GGUF models through llama.cpp. + +## Goal +Create a Windows-first, fully offline survival AI product that looks polished, launches simply, and uses custom Z3R4H modes and prompts. + +## Core Rules +- Fully offline operation for v1 +- No cloud APIs +- No OpenAI API dependency in product runtime +- No telemetry +- No login requirement for v1 +- No unnecessary frameworks or overengineering +- Keep implementation simple, stable, and portable +- Preserve Open WebUI where useful, but remove generic/cloud-first assumptions +- Brand name must appear as Z3R4H +- Interface language should emphasize: + - Offline Survival AI + - Local processing + - Knowledge when the grid falls + +## UI Direction +- Dark tactical / premium theme +- Custom Z3R4H branding +- Remove generic assistant wording +- Replace generic model language with Z3R4H mode language where appropriate + +## Z3R4H Modes +- General Advisor +- Medical Reference +- Engineering & Repair +- Navigation & Terrain +- Low Power Mode + +## Prompt Architecture +Each mode should eventually load: +- core_system.txt +- one mode-specific prompt +- failure_behavior.txt + +## Runtime Architecture +User +→ Z3R4H-branded Open WebUI +→ local llama.cpp server +→ local GGUF model + +## Priority Order +1. Reliable Windows launcher +2. Open WebUI connected to local llama.cpp +3. Z3R4H branding pass +4. Z3R4H modes +5. Prompt loading system +6. Packaging and documentation + +## Constraints +- Windows-first +- Offline-first +- Localhost-only for inference +- No unrelated refactors +- Keep edits narrowly scoped to the current task diff --git a/README.md b/README.md index a178b3271e8..2c15405c13e 100644 --- a/README.md +++ b/README.md @@ -237,3 +237,93 @@ If you have any questions, suggestions, or need assistance, please open an issue --- Created by [Timothy Jaeryang Baek](https://github.com/tjbck) - Let's make Open WebUI even more amazing together! 💪 + +## Z3R4H Windows Local Launcher (offline/localhost) + +For Z3R4H local development on Windows (no Docker), use `launch_z3r4h.bat` at the repo root. + +- Starts local `llama.cpp` server +- Starts Open WebUI with local OpenAI-compatible backend settings +- Waits for both services to become reachable +- Opens Open WebUI in the default browser +- Logs to `z3r4h_launcher.log` + +The launcher enforces localhost-only endpoints and uses verified Open WebUI environment variables from this codebase: +- `ENABLE_OPENAI_API=True` +- `OPENAI_API_BASE_URLS=http://127.0.0.1:/v1` +- `OPENAI_API_KEYS=` (empty) + +For Z3R4H offline/local startup, the launcher also applies: +- `OFFLINE_MODE=True` +- `WEBUI_AUTH=False` +- `ENABLE_LOGIN_FORM=False` +- `ENABLE_SIGNUP=False` +- `ENABLE_COMMUNITY_SHARING=False` +- `ENABLE_WEB_SEARCH=False` + +This reduces cloud-first/community surfaces in the Z3R4H launcher path while preserving local chat usage. + +Edit top variables in `launch_z3r4h.bat` before first run: +- `LLAMA_SERVER_EXE` +- `MODEL_PATH` +- `LLAMA_HOST` +- `LLAMA_PORT` +- `OPEN_WEBUI_START_CMD` +- `OPEN_WEBUI_URL` +- `LOG_FILE` + +### Portable Package Layout (Windows) + +```text +Z3R4H/ +├─ launch_z3r4h.bat +├─ models/ +│ └─ model.gguf +├─ runtime/ +│ └─ llama.cpp/ +│ └─ llama-server.exe +└─ z3r4h_launcher.log (created at runtime) +``` + +Launcher defaults are now relative to `%~dp0` (the launcher directory), so the package can be moved without editing absolute paths. + +Open WebUI startup options: +- **External CLI mode (default):** `open-webui serve` (requires `open-webui` in PATH) +- **Bundled runtime mode (optional):** point `OPEN_WEBUI_START_CMD` to a bundled executable path under `runtime/` + +Required at runtime: +- `launch_z3r4h.bat` +- `runtime/llama.cpp/llama-server.exe` (or equivalent configured path) +- `models/.gguf` +- Local port availability for llama.cpp + Open WebUI +- Write access for `z3r4h_launcher.log` + +### Z3R4H Windows-Local Verification Checklist + +1. Set launcher variables in `launch_z3r4h.bat` (`LLAMA_SERVER_EXE`, `MODEL_PATH`, ports/URL). +2. Run `launch_z3r4h.bat`. +3. Confirm launcher log shows: + - llama.cpp started and ready + - Open WebUI started and ready +4. Confirm browser opens the configured local URL. +5. Confirm Z3R4H Mode selector is visible in chat. +6. Send one local prompt and verify a response is returned. +7. Confirm offline-hardening behavior in launcher path: + - no login prompt + - community sharing disabled + - web search disabled + +### Troubleshooting (Windows Local) + +- **Missing llama.cpp executable/model:** verify `LLAMA_SERVER_EXE` and `MODEL_PATH`. +- **Startup timeout:** check `z3r4h_launcher.log`, then verify port availability and local endpoint values. +- **Open WebUI command not found:** ensure `open-webui` is installed and available in PATH. + + +### Clean-Environment Launch Review (Windows) + +Use `Z3R4H_CLEAN_ENV_CHECKLIST.md` for a clean-machine launch/readiness pass focused on: +- preflight requirements +- startup validation +- offline-hardening validation +- hidden assumptions and launch blockers diff --git a/TASKS.md b/TASKS.md new file mode 100644 index 00000000000..80694057e70 --- /dev/null +++ b/TASKS.md @@ -0,0 +1,67 @@ +# Z3R4H Tasks + +## Task 1 — Windows Launcher +Create a Windows launcher that: +- starts the local llama.cpp server +- waits for initialization +- opens the UI in the default browser +- shows clear logs/errors +- stays minimal and offline-only + +## Task 2 — Connect Open WebUI to local llama.cpp +Configure Open WebUI so it works cleanly with a local llama.cpp server and local models. + +## Task 3 — Rebrand Open WebUI as Z3R4H +Update visible branding: +- Z3R4H name +- offline survival positioning +- remove generic cloud AI wording +- dark tactical/premium visual identity + +## Task 4 — Add Z3R4H modes +Implement visible mode choices: +- General Advisor +- Medical Reference +- Engineering & Repair +- Navigation & Terrain +- Low Power Mode + +## Task 5 — Prompt system +Implement or prepare a prompt-loading structure using: +- core_system.txt +- mode-specific prompt files +- failure_behavior.txt + +## Task 6 — Offline hardening +Remove or disable: +- cloud dependencies +- telemetry +- login requirements for v1 +- unnecessary external integrations + +## Task 7 — Packaging and docs +Prepare: +- final folder structure +- run instructions +- troubleshooting notes +- offline usage notes + +## Completed (Tasks 1–5) +- Task 1 — Windows Launcher: completed in `ca715c0b` (initial launcher and local startup flow) +- Task 2 — Local llama.cpp connection: completed in `ca715c0b` (local OpenAI-compatible routing setup) +- Task 3 — Z3R4H rebrand pass: completed in `5b381011` +- Task 4 — Z3R4H mode selector UI: completed in `6c0ed902` +- Task 5 — Prompt stack binding by mode: completed in `76d6bb8a` + +## Completed (Task 7) +- Added concise Windows-local run, verification, and troubleshooting guidance in `README.md`. +- Updated progress tracking summary for packaging/readiness status in `Z3R4H_PROGRESS_SUMMARY.md`. + + +## Completed (Task 9) +- Added `Z3R4H_CLEAN_ENV_CHECKLIST.md` for clean Windows launch validation. +- Added focused pointers in `README.md` and summary status in `Z3R4H_PROGRESS_SUMMARY.md`. + +## Completed (Task 10) +- Documented portable Windows package layout and runtime requirements in `README.md`. +- Updated launcher defaults to `%~dp0`-relative paths for portability. diff --git a/Z3R4H_CLEAN_ENV_CHECKLIST.md b/Z3R4H_CLEAN_ENV_CHECKLIST.md new file mode 100644 index 00000000000..1dd3c300a0e --- /dev/null +++ b/Z3R4H_CLEAN_ENV_CHECKLIST.md @@ -0,0 +1,77 @@ +# Z3R4H Clean-Environment Validation Checklist (Windows Local) + +## Scope +This checklist validates launch readiness on a clean Windows machine for the current Z3R4H build, without changing product behavior. + +## 1) Machine Baseline +- Windows user profile is fresh or has no prior Open WebUI local config. +- Terminal used: Command Prompt or PowerShell. +- Local firewall/AV policies noted before test. + +## 2) Preflight Requirements +- `launch_z3r4h.bat` exists at repo root. +- `LLAMA_SERVER_EXE` path is valid. +- `MODEL_PATH` path is valid. +- `open-webui` command resolves in PATH. +- Local ports configured for llama.cpp and Open WebUI are available. + +## 2b) Portable Layout Preflight +- Confirm package root contains expected folders (`models/`, `runtime/llama.cpp/`). +- Confirm launcher defaults resolve correctly from `%~dp0` after moving package to a new directory. +- Confirm whether current build uses: + - external `open-webui` CLI in PATH, or + - bundled Open WebUI runtime command. + +## 3) Launcher Configuration Validation +- Confirm top variables in `launch_z3r4h.bat`: + - `LLAMA_SERVER_EXE` + - `MODEL_PATH` + - `LLAMA_HOST` + - `LLAMA_PORT` + - `OPEN_WEBUI_START_CMD` + - `OPEN_WEBUI_URL` + - `LOG_FILE` +- Confirm localhost-only settings remain unchanged. +- Confirm offline/local hardening defaults are active. + +## 4) Startup Validation +1. Run `launch_z3r4h.bat`. +2. Verify llama.cpp server process starts. +3. Verify Open WebUI process starts. +4. Verify readiness polling completes for both services. +5. Verify browser opens the local UI URL. +6. Verify `z3r4h_launcher.log` contains startup sequence and no fatal errors. + +## 5) UI/Runtime Validation +- Z3R4H branding appears in UI surfaces. +- Z3R4H mode selector is visible. +- One chat request returns a local response. +- Mode-to-model routing works; fallback warning appears if mapped model is missing. + +## 6) Offline-Hardening Validation +- No login prompt in launcher path. +- Community sharing surfaces disabled. +- Web search features disabled. +- No cloud endpoint configuration required for baseline chat. + +## 7) Negative/Failure Path Checks +- Missing `LLAMA_SERVER_EXE` -> clear error in console/log. +- Missing `MODEL_PATH` -> clear error in console/log. +- `open-webui` missing in PATH -> clear error in console/log. +- Port conflict -> timeout + likely conflict guidance. + +## 8) Hidden Assumptions Audit +- Hardcoded/default local paths may not match machine. +- PATH inheritance for spawned shell may differ by setup. +- PowerShell availability is assumed for readiness probes. +- Localhost binding and firewall behavior can block readiness checks. +- Runtime model list may not include mode-mapped IDs on first run. +- localStorage state (`z3r4h_mode`, `z3r4h_mode_model_map`) may be absent/corrupt on fresh profiles. + +## 9) Blocker Log Template +For each blocker, capture: +- Severity +- Repro steps +- Expected vs actual result +- Log snippet path/time +- Candidate fix (if known) diff --git a/Z3R4H_PROGRESS_SUMMARY.md b/Z3R4H_PROGRESS_SUMMARY.md new file mode 100644 index 00000000000..a032c59d27c --- /dev/null +++ b/Z3R4H_PROGRESS_SUMMARY.md @@ -0,0 +1,62 @@ +# Z3R4H Progress Summary + +## Completed Tasks (1–6) +- **Task 1 — Windows Launcher:** Added a Windows launcher to start local llama.cpp, wait for readiness, and open Open WebUI. +- **Task 2 — Local llama.cpp connection:** Configured launcher path to use local OpenAI-compatible endpoint for llama.cpp. +- **Task 3 — Z3R4H rebrand:** Updated visible app branding/text to Z3R4H AI in key UI surfaces. +- **Task 4 — Z3R4H modes UI:** Added visible mode selector with 5 modes in chat navbar. +- **Task 5 — Prompt binding:** Bound selected mode to deterministic local prompt stack (`core_system` + mode prompt + `failure_behavior`). +- **Task 6 — Offline hardening:** Added launcher defaults to reduce cloud/community/login/web-search features in Z3R4H local path. + +## Key Files Added/Changed +- `launch_z3r4h.bat` +- `PROJECT_BRIEF.md` +- `TASKS.md` +- `README.md` +- `src/lib/components/chat/Z3R4HModeSelector.svelte` +- `src/lib/components/chat/Navbar.svelte` +- `src/lib/components/chat/Chat.svelte` +- `src/lib/utils/z3r4hPromptStack.ts` +- `src/lib/prompts/z3r4h/core_system.txt` +- `src/lib/prompts/z3r4h/failure_behavior.txt` +- `src/lib/prompts/z3r4h/modes/general_advisor.txt` +- `src/lib/prompts/z3r4h/modes/medical_reference.txt` +- `src/lib/prompts/z3r4h/modes/engineering_repair.txt` +- `src/lib/prompts/z3r4h/modes/navigation_terrain.txt` +- `src/lib/prompts/z3r4h/modes/low_power_mode.txt` +- `src/lib/constants.ts` +- `src/app.html` +- `src/routes/+layout.svelte` +- `src/routes/auth/+page.svelte` +- `src/lib/components/channel/Channel.svelte` +- `static/opensearch.xml` +- `static/static/site.webmanifest` +- `backend/open_webui/static/site.webmanifest` + +## Important Commit SHAs +- `ca715c0b` — Windows launcher + local connection setup note +- `5b381011` — Task 3 rebrand updates +- `6c0ed902` — Task 4 mode selector UI +- `76d6bb8a` — Task 5 prompt-stack binding +- `071c41b8` — Task 6 offline hardening defaults +- `98379689` — TASKS.md completed section for Tasks 1–5 + +## Current Branch +- `work` + +## Task 7 Readiness Status +- Added Windows-local verification checklist and troubleshooting notes to `README.md`. +- Packaging readiness is currently documentation-focused (run/verify/package prep), with no installer generation. + +## Next Recommended Task +- Prepare release packaging artifacts/checklist (outside current scope), then validate on a clean Windows environment. + + +## Task 9 Readiness/Audit Status +- Added a clean-environment checklist for Windows-local validation and blocker capture (`Z3R4H_CLEAN_ENV_CHECKLIST.md`). +- Identified practical hidden assumptions in launcher/runtime path for clean-machine testing. + +## Task 10 Packaging/Portability Status +- Defined a portable Windows package layout in `README.md`. +- Updated launcher defaults to use `%~dp0`-anchored relative paths for llama.cpp server and model paths. +- Documented external Open WebUI CLI mode vs optional bundled runtime command mode. diff --git a/backend/open_webui/static/site.webmanifest b/backend/open_webui/static/site.webmanifest index 95915ae2bca..8a50c98a0bb 100644 --- a/backend/open_webui/static/site.webmanifest +++ b/backend/open_webui/static/site.webmanifest @@ -1,6 +1,6 @@ { - "name": "Open WebUI", - "short_name": "WebUI", + "name": "Z3R4H AI", + "short_name": "Z3R4H", "icons": [ { "src": "/static/web-app-manifest-192x192.png", diff --git a/launch_z3r4h.bat b/launch_z3r4h.bat new file mode 100644 index 00000000000..71c9a2c38bc --- /dev/null +++ b/launch_z3r4h.bat @@ -0,0 +1,116 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion + +REM Z3R4H Windows launcher (localhost/offline path) + +REM --- Config --- +set "PACKAGE_ROOT=%~dp0" +set "LLAMA_SERVER_EXE=%PACKAGE_ROOT%runtime\llama.cpp\llama-server.exe" +set "MODEL_PATH=%PACKAGE_ROOT%models\model.gguf" +set "LLAMA_HOST=127.0.0.1" +set "LLAMA_PORT=11434" + +REM Open WebUI startup modes: +REM 1) External CLI in PATH (default): +set "OPEN_WEBUI_START_CMD=open-webui serve" +REM 2) Bundled runtime example: +REM set "OPEN_WEBUI_START_CMD=\"%PACKAGE_ROOT%runtime\\open-webui\\open-webui.exe\" serve" + +set "OPEN_WEBUI_URL=http://localhost:8080" +set "LOG_FILE=%~dp0z3r4h_launcher.log" + +REM Verified Open WebUI env vars in this repo/version: +REM - ENABLE_OPENAI_API +REM - OPENAI_API_BASE_URLS +REM - OPENAI_API_KEYS +set "ENABLE_OPENAI_API=True" +set "OPENAI_API_BASE_URLS=http://127.0.0.1:%LLAMA_PORT%/v1" +set "OPENAI_API_KEYS=" + +REM Z3R4H offline/local hardening defaults (launcher path only) +set "OFFLINE_MODE=True" +set "WEBUI_AUTH=False" +set "ENABLE_LOGIN_FORM=False" +set "ENABLE_SIGNUP=False" +set "ENABLE_COMMUNITY_SHARING=False" +set "ENABLE_WEB_SEARCH=False" + +REM --- Timeouts --- +set "LLAMA_TIMEOUT=120" +set "WEBUI_TIMEOUT=180" +set "POLL_SECONDS=2" + +call :log "========================================" +call :log "Z3R4H launcher start" +call :log "llama endpoint: http://%LLAMA_HOST%:%LLAMA_PORT%" +call :log "webui url: %OPEN_WEBUI_URL%" +call :log "========================================" + +if /I not "%LLAMA_HOST%"=="127.0.0.1" call :fail "LLAMA_HOST must be 127.0.0.1 (localhost-only)." + +echo %OPEN_WEBUI_URL% | findstr /I /R "^http://localhost[:/]" >nul +if errorlevel 1 call :fail "OPEN_WEBUI_URL must be localhost-only (http://localhost:...)." + +if not exist "%LLAMA_SERVER_EXE%" call :fail "Missing llama.cpp executable: %LLAMA_SERVER_EXE%" +if not exist "%MODEL_PATH%" call :fail "Missing model file: %MODEL_PATH%" + +where open-webui >nul 2>&1 +if errorlevel 1 call :fail "Missing Open WebUI startup command/environment: open-webui not found in PATH." + +call :log "Starting llama.cpp..." +start "Z3R4H llama.cpp" /MIN cmd /c ""%LLAMA_SERVER_EXE%" -m "%MODEL_PATH%" --host %LLAMA_HOST% --port %LLAMA_PORT% >> "%LOG_FILE%" 2>&1" + +call :wait_llama +if errorlevel 1 call :fail "llama.cpp startup timeout or likely port conflict on %LLAMA_HOST%:%LLAMA_PORT%." + +call :log "Starting Open WebUI..." +start "Z3R4H Open WebUI" /MIN cmd /c "%OPEN_WEBUI_START_CMD% >> "%LOG_FILE%" 2>&1" + +call :wait_webui +if errorlevel 1 call :fail "Open WebUI startup timeout or likely port conflict at %OPEN_WEBUI_URL%." + +call :log "Services ready. Opening browser..." +start "" "%OPEN_WEBUI_URL%" +call :log "Launcher completed successfully." +echo [OK] Z3R4H ready. +exit /b 0 + +:wait_llama +set /a elapsed=0 +:wait_llama_loop +powershell -NoProfile -ExecutionPolicy Bypass -Command "$u='http://%LLAMA_HOST%:%LLAMA_PORT%/health'; try { $r=Invoke-WebRequest -UseBasicParsing -Uri $u -TimeoutSec 2; if($r.StatusCode -ge 200 -and $r.StatusCode -lt 500){exit 0}else{exit 1} } catch { exit 1 }" >nul 2>&1 +if not errorlevel 1 ( + call :log "llama.cpp is ready." + exit /b 0 +) +if %elapsed% GEQ %LLAMA_TIMEOUT% exit /b 1 +set /a elapsed+=POLL_SECONDS +call :log "Waiting for llama.cpp... %elapsed%s/%LLAMA_TIMEOUT%s" +timeout /t %POLL_SECONDS% /nobreak >nul +goto wait_llama_loop + +:wait_webui +set /a elapsed=0 +:wait_webui_loop +powershell -NoProfile -ExecutionPolicy Bypass -Command "$u='%OPEN_WEBUI_URL%'; try { $r=Invoke-WebRequest -UseBasicParsing -Uri $u -TimeoutSec 2; if($r.StatusCode -ge 200 -and $r.StatusCode -lt 500){exit 0}else{exit 1} } catch { exit 1 }" >nul 2>&1 +if not errorlevel 1 ( + call :log "Open WebUI is ready." + exit /b 0 +) +if %elapsed% GEQ %WEBUI_TIMEOUT% exit /b 1 +set /a elapsed+=POLL_SECONDS +call :log "Waiting for Open WebUI... %elapsed%s/%WEBUI_TIMEOUT%s" +timeout /t %POLL_SECONDS% /nobreak >nul +goto wait_webui_loop + +:log +set "ts=%date% %time%" +echo [%ts%] %~1 +>> "%LOG_FILE%" echo [%ts%] %~1 +exit /b 0 + +:fail +call :log "ERROR: %~1" +echo [ERROR] %~1 +echo See log: "%LOG_FILE%" +exit /b 1 diff --git a/src/app.html b/src/app.html index d75d1ead00d..cab39d56a22 100644 --- a/src/app.html +++ b/src/app.html @@ -103,7 +103,7 @@ })(); - Open WebUI + Z3R4H AI %sveltekit.head% diff --git a/src/lib/components/channel/Channel.svelte b/src/lib/components/channel/Channel.svelte index 77626a1016c..97f519e3376 100644 --- a/src/lib/components/channel/Channel.svelte +++ b/src/lib/components/channel/Channel.svelte @@ -12,7 +12,8 @@ channelId as _channelId, showSidebar, socket, - user + user, + WEBUI_NAME } from '$lib/stores'; import { getChannelById, getChannelMessages, sendMessage } from '$lib/apis/channels'; @@ -288,10 +289,10 @@ } else { return e.name; } - }, '')} • Open WebUI {:else} - #{channel?.name ?? 'Channel'} • Open WebUI + #{channel?.name ?? 'Channel'} • {$WEBUI_NAME} {/if} diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 45c2e01e2bc..2ac95161059 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -64,6 +64,8 @@ displayFileHandler } from '$lib/utils'; import { AudioQueue } from '$lib/utils/audio'; + import { composeZ3R4HPromptStack } from '$lib/utils/z3r4hPromptStack'; + import { resolveZ3R4HRoutedModelId, type Z3R4HModeModelMap } from '$lib/utils/z3r4hModeRouting'; import { archiveChatById, @@ -134,6 +136,8 @@ let eventCallback = null; let selectedModels = ['']; + let selectedZ3R4HMode = 'General Advisor'; + let z3r4hModeModelMap: Z3R4HModeModelMap = {}; let atSelectedModel: Model | undefined; let selectedModelIds = []; $: if (atSelectedModel !== undefined) { @@ -643,6 +647,26 @@ savedModelIds(); } + $: if (typeof window !== 'undefined') { + localStorage.setItem('z3r4h_mode', selectedZ3R4HMode); + } + + $: if (typeof window !== 'undefined') { + localStorage.setItem('z3r4h_mode_model_map', JSON.stringify(z3r4hModeModelMap)); + } + + $: { + const selectedId = atSelectedModel?.id ?? selectedModels.find((id) => !!id) ?? null; + if (selectedId && $models.some((m) => m.id === selectedId)) { + if (z3r4hModeModelMap[selectedZ3R4HMode] !== selectedId) { + z3r4hModeModelMap = { + ...z3r4hModeModelMap, + [selectedZ3R4HMode]: selectedId + }; + } + } + } + const stopAudio = () => { try { speechSynthesis.cancel(); @@ -658,6 +682,20 @@ $audioQueue?.destroy(); + const savedZ3R4HMode = localStorage.getItem('z3r4h_mode'); + if (savedZ3R4HMode) { + selectedZ3R4HMode = savedZ3R4HMode; + } + + const savedZ3R4HModeModelMap = localStorage.getItem('z3r4h_mode_model_map'); + if (savedZ3R4HModeModelMap) { + try { + z3r4hModeModelMap = JSON.parse(savedZ3R4HModeModelMap); + } catch (e) { + console.warn('Failed to parse z3r4h_mode_model_map'); + } + } + const audioQueueInstance = new AudioQueue(document.getElementById('audioElement')); audioQueue.set(audioQueueInstance); @@ -1916,12 +1954,28 @@ _history = structuredClone(_history); const responseMessageIds: Record = {}; - // If modelId is provided, use it, else use selected model + const availableModelIds = $models.map((m) => m.id); + + const routedModel = resolveZ3R4HRoutedModelId({ + mode: selectedZ3R4HMode, + modeModelMap: z3r4hModeModelMap, + availableModelIds, + selectedModelIds: selectedModels, + atSelectedModelId: atSelectedModel?.id + }); + + if (!modelId && routedModel.missingMappedModel) { + toast.warning($i18n.t('Routed mode model unavailable; using selected local model.')); + } + + // If modelId is provided, use it. Otherwise route by current Z3R4H mode. let selectedModelIds = modelId ? [modelId] - : atSelectedModel !== undefined - ? [atSelectedModel.id] - : selectedModels; + : routedModel.modelId + ? [routedModel.modelId] + : atSelectedModel !== undefined + ? [atSelectedModel.id] + : selectedModels; // Create response messages for each selected model for (const [_modelIdx, modelId] of selectedModelIds.entries()) { @@ -2123,11 +2177,15 @@ params?.stream_response ?? true; + const baseSystemPrompt = `${params?.system ?? $settings?.system ?? ''}`.trim(); + const z3r4hPromptStack = composeZ3R4HPromptStack(selectedZ3R4HMode); + const effectiveSystemPrompt = [baseSystemPrompt, z3r4hPromptStack].filter(Boolean).join('\n\n').trim(); + let messages = [ - params?.system || $settings.system + effectiveSystemPrompt ? { role: 'system', - content: `${params?.system ?? $settings?.system ?? ''}` + content: effectiveSystemPrompt } : undefined, ..._messages.map((message) => ({ @@ -2755,11 +2813,12 @@ timestamp: Date.now() } }} - {history} - title={$chatTitle} - bind:selectedModels - shareEnabled={!!history.currentId} - {initNewChat} + {history} + title={$chatTitle} + bind:selectedModels + bind:selectedZ3R4HMode + shareEnabled={!!history.currentId} + {initNewChat} {archiveChatHandler} {moveChatHandler} onSaveTempChat={async () => { diff --git a/src/lib/components/chat/Navbar.svelte b/src/lib/components/chat/Navbar.svelte index 5c4e1364b4d..6f589f7c43d 100644 --- a/src/lib/components/chat/Navbar.svelte +++ b/src/lib/components/chat/Navbar.svelte @@ -22,6 +22,7 @@ import ShareChatModal from '../chat/ShareChatModal.svelte'; import ModelSelector from '../chat/ModelSelector.svelte'; + import Z3R4HModeSelector from '../chat/Z3R4HModeSelector.svelte'; import Tooltip from '../common/Tooltip.svelte'; import Menu from '$lib/components/layout/Navbar/Menu.svelte'; import UserMenu from '$lib/components/layout/Sidebar/UserMenu.svelte'; @@ -50,6 +51,7 @@ export let history; export let selectedModels; export let showModelSelector = true; + export let selectedZ3R4HMode = 'General Advisor'; export let onSaveTempChat: () => {}; export let archiveChatHandler: (id: string) => void; @@ -106,15 +108,18 @@ {/if} -
- {#if showModelSelector} - - {/if} -
+
+ {#if showModelSelector} +
+ + +
+ {/if} +
diff --git a/src/lib/components/chat/Z3R4HModeSelector.svelte b/src/lib/components/chat/Z3R4HModeSelector.svelte new file mode 100644 index 00000000000..d83973585a9 --- /dev/null +++ b/src/lib/components/chat/Z3R4HModeSelector.svelte @@ -0,0 +1,25 @@ + + +
+ Z3R4H Mode + +
diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 006304bbb48..086223c288b 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,7 +1,7 @@ import { browser, dev } from '$app/environment'; // import { version } from '../../package.json'; -export const APP_NAME = 'Open WebUI'; +export const APP_NAME = 'Z3R4H AI'; export const WEBUI_HOSTNAME = browser ? (dev ? `${location.hostname}:8080` : ``) : ''; export const WEBUI_BASE_URL = browser ? (dev ? `http://${WEBUI_HOSTNAME}` : ``) : ``; diff --git a/src/lib/prompts/z3r4h/core_system.txt b/src/lib/prompts/z3r4h/core_system.txt new file mode 100644 index 00000000000..cdc00e1f924 --- /dev/null +++ b/src/lib/prompts/z3r4h/core_system.txt @@ -0,0 +1,3 @@ +You are Z3R4H AI, an offline survival assistant. +Prioritize practical, safety-aware guidance for low-resource scenarios. +Use clear, concise steps and note uncertainty when information is incomplete. diff --git a/src/lib/prompts/z3r4h/failure_behavior.txt b/src/lib/prompts/z3r4h/failure_behavior.txt new file mode 100644 index 00000000000..10ad3893e37 --- /dev/null +++ b/src/lib/prompts/z3r4h/failure_behavior.txt @@ -0,0 +1,3 @@ +If a request is unsafe, illegal, or unverifiable, refuse briefly and provide safer alternatives. +If critical facts are uncertain, state limits clearly and suggest local verification steps. +Never imply cloud lookup or external live access in offline mode. diff --git a/src/lib/prompts/z3r4h/modes/engineering_repair.txt b/src/lib/prompts/z3r4h/modes/engineering_repair.txt new file mode 100644 index 00000000000..8618d7c6095 --- /dev/null +++ b/src/lib/prompts/z3r4h/modes/engineering_repair.txt @@ -0,0 +1,2 @@ +Mode: Engineering & Repair +Focus on diagnosis, repair sequencing, and improvised maintenance with available tools. diff --git a/src/lib/prompts/z3r4h/modes/general_advisor.txt b/src/lib/prompts/z3r4h/modes/general_advisor.txt new file mode 100644 index 00000000000..1219554937a --- /dev/null +++ b/src/lib/prompts/z3r4h/modes/general_advisor.txt @@ -0,0 +1,2 @@ +Mode: General Advisor +Focus on broad survival decision support, prioritization, and practical next actions. diff --git a/src/lib/prompts/z3r4h/modes/low_power_mode.txt b/src/lib/prompts/z3r4h/modes/low_power_mode.txt new file mode 100644 index 00000000000..17670546e28 --- /dev/null +++ b/src/lib/prompts/z3r4h/modes/low_power_mode.txt @@ -0,0 +1,2 @@ +Mode: Low Power Mode +Respond with high-signal, minimal-token output optimized for constrained power and compute. diff --git a/src/lib/prompts/z3r4h/modes/medical_reference.txt b/src/lib/prompts/z3r4h/modes/medical_reference.txt new file mode 100644 index 00000000000..1a5d68c9f18 --- /dev/null +++ b/src/lib/prompts/z3r4h/modes/medical_reference.txt @@ -0,0 +1,3 @@ +Mode: Medical Reference +Provide conservative first-aid and medical reference guidance. +Flag emergencies, contraindications, and immediate escalation triggers. diff --git a/src/lib/prompts/z3r4h/modes/navigation_terrain.txt b/src/lib/prompts/z3r4h/modes/navigation_terrain.txt new file mode 100644 index 00000000000..7e75b6753b4 --- /dev/null +++ b/src/lib/prompts/z3r4h/modes/navigation_terrain.txt @@ -0,0 +1,2 @@ +Mode: Navigation & Terrain +Focus on route planning, terrain risk assessment, orientation, and movement safety. diff --git a/src/lib/utils/z3r4hModeRouting.ts b/src/lib/utils/z3r4hModeRouting.ts new file mode 100644 index 00000000000..6d8853d6049 --- /dev/null +++ b/src/lib/utils/z3r4hModeRouting.ts @@ -0,0 +1,46 @@ +export type Z3R4HModeModelMap = Record; + +export type RoutedModelResult = { + modelId: string | null; + reason: 'mode-mapped' | 'selected' | 'first-available' | 'none'; + missingMappedModel: boolean; +}; + +export const resolveZ3R4HRoutedModelId = ({ + mode, + modeModelMap, + availableModelIds, + selectedModelIds, + atSelectedModelId +}: { + mode: string; + modeModelMap: Z3R4HModeModelMap; + availableModelIds: string[]; + selectedModelIds: string[]; + atSelectedModelId?: string; +}): RoutedModelResult => { + const mappedId = modeModelMap?.[mode] ?? null; + + if (mappedId && availableModelIds.includes(mappedId)) { + return { modelId: mappedId, reason: 'mode-mapped', missingMappedModel: false }; + } + + const selectedId = atSelectedModelId || selectedModelIds.find((id) => !!id) || null; + if (selectedId && availableModelIds.includes(selectedId)) { + return { + modelId: selectedId, + reason: 'selected', + missingMappedModel: Boolean(mappedId && mappedId !== selectedId) + }; + } + + if (availableModelIds.length > 0) { + return { + modelId: availableModelIds[0], + reason: 'first-available', + missingMappedModel: Boolean(mappedId) + }; + } + + return { modelId: null, reason: 'none', missingMappedModel: Boolean(mappedId) }; +}; diff --git a/src/lib/utils/z3r4hPromptStack.ts b/src/lib/utils/z3r4hPromptStack.ts new file mode 100644 index 00000000000..1f0f16dffa2 --- /dev/null +++ b/src/lib/utils/z3r4hPromptStack.ts @@ -0,0 +1,20 @@ +import coreSystem from '$lib/prompts/z3r4h/core_system.txt?raw'; +import failureBehavior from '$lib/prompts/z3r4h/failure_behavior.txt?raw'; +import generalAdvisor from '$lib/prompts/z3r4h/modes/general_advisor.txt?raw'; +import medicalReference from '$lib/prompts/z3r4h/modes/medical_reference.txt?raw'; +import engineeringRepair from '$lib/prompts/z3r4h/modes/engineering_repair.txt?raw'; +import navigationTerrain from '$lib/prompts/z3r4h/modes/navigation_terrain.txt?raw'; +import lowPowerMode from '$lib/prompts/z3r4h/modes/low_power_mode.txt?raw'; + +export const Z3R4H_MODE_TO_PROMPT: Record = { + 'General Advisor': generalAdvisor, + 'Medical Reference': medicalReference, + 'Engineering & Repair': engineeringRepair, + 'Navigation & Terrain': navigationTerrain, + 'Low Power Mode': lowPowerMode +}; + +export const composeZ3R4HPromptStack = (mode: string): string => { + const modePrompt = Z3R4H_MODE_TO_PROMPT[mode] ?? generalAdvisor; + return [coreSystem.trim(), modePrompt.trim(), failureBehavior.trim()].join('\n\n'); +}; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 920e56f96bb..addd2ff96e9 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -454,7 +454,7 @@ if ($isLastActiveTab) { if ($settings?.notificationEnabled ?? false) { - new Notification(`${displayTitle} • Open WebUI`, { + new Notification(`${displayTitle} • ${$WEBUI_NAME}`, { body: content, icon: `${WEBUI_BASE_URL}/static/favicon.png` }); @@ -657,7 +657,7 @@ if ($isLastActiveTab) { if ($settings?.notificationEnabled ?? false) { - new Notification(`${title} • Open WebUI`, { + new Notification(`${title} • ${$WEBUI_NAME}`, { body: data?.content, icon: `${WEBUI_API_BASE_URL}/users/${data?.user?.id}/profile/image` }); diff --git a/src/routes/auth/+page.svelte b/src/routes/auth/+page.svelte index b11f85b7a53..0348daaf6ce 100644 --- a/src/routes/auth/+page.svelte +++ b/src/routes/auth/+page.svelte @@ -274,6 +274,9 @@ 'does not make any external connections, and your data stays securely on your locally hosted server.' )}
+
+ {$i18n.t('Offline Survival AI for local-first operation.')} +
{/if} diff --git a/static/opensearch.xml b/static/opensearch.xml index ce47e39ae98..41ca8c2f516 100644 --- a/static/opensearch.xml +++ b/static/opensearch.xml @@ -1,6 +1,6 @@ -Open WebUI -Search Open WebUI +Z3R4H AI +Search Z3R4H AI UTF-8 http://localhost:5137/favicon.png diff --git a/static/static/site.webmanifest b/static/static/site.webmanifest index 95915ae2bca..8a50c98a0bb 100644 --- a/static/static/site.webmanifest +++ b/static/static/site.webmanifest @@ -1,6 +1,6 @@ { - "name": "Open WebUI", - "short_name": "WebUI", + "name": "Z3R4H AI", + "short_name": "Z3R4H", "icons": [ { "src": "/static/web-app-manifest-192x192.png", From 5175aaa3bf78381958b0c8777aa4664258c2d8f3 Mon Sep 17 00:00:00 2001 From: RadDad87 <142544102+RadDad87@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:39:00 -0400 Subject: [PATCH 2/3] Implement Task 11 clean-machine validation flow and blocker triage docs --- README.md | 13 +++++++++++ TASKS.md | 12 ++++++++++ Z3R4H_CLEAN_ENV_CHECKLIST.md | 44 +++++++++++++++++++++++++++++++++++- Z3R4H_PROGRESS_SUMMARY.md | 19 ++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c15405c13e..9237e6db926 100644 --- a/README.md +++ b/README.md @@ -327,3 +327,16 @@ Use `Z3R4H_CLEAN_ENV_CHECKLIST.md` for a clean-machine launch/readiness pass foc - startup validation - offline-hardening validation - hidden assumptions and launch blockers + +### Task 11 Validation Focus (Windows Local) + +For Task 11, treat this as a **validation-only** pass (no behavior changes by default): +- run the execution-ready clean-machine flow in `Z3R4H_CLEAN_ENV_CHECKLIST.md` +- rank blockers as P0/P1/P2 for launch-readiness decisions +- record hidden assumptions with concrete repro evidence + +Highest-risk items to validate first: +- default external `open-webui` PATH dependency +- PowerShell readiness-probe assumptions +- local port conflicts (11434/8080) +- packaged model path/filename mismatch diff --git a/TASKS.md b/TASKS.md index 80694057e70..59ac82870f1 100644 --- a/TASKS.md +++ b/TASKS.md @@ -65,3 +65,15 @@ Prepare: ## Completed (Task 10) - Documented portable Windows package layout and runtime requirements in `README.md`. - Updated launcher defaults to `%~dp0`-relative paths for portability. + + +## Completed (Task 11) +- Converted clean-environment checklist into an execution-ready Windows clean-machine validation flow. +- Added highest-risk blocker candidates and P0/P1/P2 prioritization rules. +- Added blocker register fields for triage evidence and release-gate decisions. +- Kept scope documentation/review-only with no product/backend behavior changes. + +## Deferred (Beyond Task 11) +- Installer generation/signing +- CI/release automation +- Bundled Open WebUI runtime build/distribution workflow diff --git a/Z3R4H_CLEAN_ENV_CHECKLIST.md b/Z3R4H_CLEAN_ENV_CHECKLIST.md index 1dd3c300a0e..cd418a48363 100644 --- a/Z3R4H_CLEAN_ENV_CHECKLIST.md +++ b/Z3R4H_CLEAN_ENV_CHECKLIST.md @@ -12,7 +12,9 @@ This checklist validates launch readiness on a clean Windows machine for the cur - `launch_z3r4h.bat` exists at repo root. - `LLAMA_SERVER_EXE` path is valid. - `MODEL_PATH` path is valid. -- `open-webui` command resolves in PATH. +- Determine startup mode before launch: + - External CLI mode: `open-webui` command resolves in PATH. + - Bundled runtime mode: `OPEN_WEBUI_START_CMD` points to packaged executable. - Local ports configured for llama.cpp and Open WebUI are available. ## 2b) Portable Layout Preflight @@ -75,3 +77,43 @@ For each blocker, capture: - Expected vs actual result - Log snippet path/time - Candidate fix (if known) + + +## 10) Task 11 Execution Flow (Clean Machine, Windows) +1. Capture baseline: Windows version, shell (CMD/PowerShell), AV/firewall posture. +2. Verify portable layout from launcher directory (`%~dp0`) after moving package folder. +3. Run preflight gates: startup mode, paths, model artifact, ports, and PowerShell readiness-probe capability. +4. Execute cold launch (`launch_z3r4h.bat`) and capture first-failure stage if unsuccessful. +5. Validate readiness endpoints and browser open behavior; confirm startup sequence in `z3r4h_launcher.log`. +6. Execute UI/runtime smoke checks: mode selector present + one successful local response. +7. Execute negative-path checks: missing binary/model, missing PATH command, and port conflicts. +8. Record blockers into ranked register and assign release-gate status (P0/P1/P2). + +## 11) Highest-Risk Blockers (Packaging Readiness) +- **P0 candidate:** Default startup mode depends on `open-webui` in PATH (clean-machine failure risk). +- **P0/P1 candidate:** Readiness probes depend on PowerShell `Invoke-WebRequest` behavior/policy. +- **P1 candidate:** Port conflicts on `11434` (llama.cpp) or `8080` (Open WebUI) appear as startup timeout. +- **P1 candidate:** Default model path/file (`models\model.gguf`) may not match packaged artifact name. +- **P1/P2 candidate:** Fresh-profile localStorage state for mode routing may be absent/corrupt. + +## 12) Blocker Prioritization Rules +- **P0:** Prevents clean-machine launch in the intended default package flow. +- **P1:** Launch possible, but core local usability/hardening expectation fails. +- **P2:** Non-blocking friction or documentation clarity issue with workaround. + +## 13) Blocker Register (Task 11) +Capture each finding with: +- ID +- Severity (P0/P1/P2) +- Stage (preflight/startup/runtime) +- Repro reliability (always/intermittent) +- Expected vs actual +- Evidence (`z3r4h_launcher.log` timestamp + console symptom) +- Proposed next action (doc-only, launcher change, packaging change) +- Owner and status + +## 14) Deferred Beyond Task 11 +- Installer generation/signing +- CI/release automation +- Bundled Open WebUI runtime build/distribution workflow +- Product/backend behavior changes unless a verified P0 requires escalation diff --git a/Z3R4H_PROGRESS_SUMMARY.md b/Z3R4H_PROGRESS_SUMMARY.md index a032c59d27c..09fec7466bd 100644 --- a/Z3R4H_PROGRESS_SUMMARY.md +++ b/Z3R4H_PROGRESS_SUMMARY.md @@ -60,3 +60,22 @@ - Defined a portable Windows package layout in `README.md`. - Updated launcher defaults to use `%~dp0`-anchored relative paths for llama.cpp server and model paths. - Documented external Open WebUI CLI mode vs optional bundled runtime command mode. + + +## Task 11 Validation/Triage Status +- Expanded clean-machine checklist into an execution-ready Windows-local validation flow. +- Added ranked blocker candidates with launch-readiness prioritization (P0/P1/P2). +- Added structured blocker register fields (stage, repro reliability, evidence, action owner). +- Scope kept documentation/review-only; no backend/product behavior changes. + +### Task 11 Initial Risk Ranking +1. **P0 candidate:** External `open-webui` PATH dependency in default mode on clean machines. +2. **P0/P1 candidate:** PowerShell readiness-probe environment/policy assumptions. +3. **P1 candidate:** Port conflicts on 11434/8080 causing startup timeout symptoms. +4. **P1 candidate:** Packaged model path/filename mismatch vs launcher default. +5. **P1/P2 candidate:** Fresh-profile localStorage state assumptions for mode routing. + +### Still Deferred Beyond Task 11 +- Installer generation/signing +- CI/release automation +- Bundled Open WebUI runtime build/distribution workflow From 9096268d1f663e0702e02ff54e904ac8f7d3903a Mon Sep 17 00:00:00 2001 From: RadDad87 <142544102+RadDad87@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:39:45 -0400 Subject: [PATCH 3/3] Implement revised Task 8 local model-id routing and fallback docs --- TASKS.md | 6 ++++++ Z3R4H_PROGRESS_SUMMARY.md | 7 +++++++ src/lib/components/chat/Chat.svelte | 3 ++- src/lib/utils/z3r4hModeRouting.ts | 13 ++++++++----- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/TASKS.md b/TASKS.md index 59ac82870f1..11f44c973b7 100644 --- a/TASKS.md +++ b/TASKS.md @@ -77,3 +77,9 @@ Prepare: - Installer generation/signing - CI/release automation - Bundled Open WebUI runtime build/distribution workflow + + +## Completed (Task 8, Revised) +- Confirmed local mode-to-model routing resolves only against runtime `model.id` values. +- Kept routing deterministic with explicit fallback order: mode-mapped -> selected -> first-available -> none. +- Preserved existing prompt-stack behavior (no change to prompt composition). diff --git a/Z3R4H_PROGRESS_SUMMARY.md b/Z3R4H_PROGRESS_SUMMARY.md index 09fec7466bd..9b9a1965021 100644 --- a/Z3R4H_PROGRESS_SUMMARY.md +++ b/Z3R4H_PROGRESS_SUMMARY.md @@ -79,3 +79,10 @@ - Installer generation/signing - CI/release automation - Bundled Open WebUI runtime build/distribution workflow + + +## Task 8 Revised Routing Status +- Routing remains local-only and deterministic via `resolveZ3R4HRoutedModelId` in `src/lib/utils/z3r4hModeRouting.ts`. +- Effective model resolution in chat send path occurs in `src/lib/components/chat/Chat.svelte` (`sendMessage`, routedModel block). +- Fallback order is unchanged: mode-mapped -> selected -> first-available -> none; warning shown when mapped model is unavailable. +- Prompt-stack composition remains unchanged (`composeZ3R4HPromptStack`). diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 2ac95161059..872138b5aa0 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -1956,11 +1956,12 @@ const responseMessageIds: Record = {}; const availableModelIds = $models.map((m) => m.id); + // Resolve effective routed model strictly from current runtime model IDs. const routedModel = resolveZ3R4HRoutedModelId({ mode: selectedZ3R4HMode, modeModelMap: z3r4hModeModelMap, availableModelIds, - selectedModelIds: selectedModels, + selectedModelIds, atSelectedModelId: atSelectedModel?.id }); diff --git a/src/lib/utils/z3r4hModeRouting.ts b/src/lib/utils/z3r4hModeRouting.ts index 6d8853d6049..2bc0adfc5dc 100644 --- a/src/lib/utils/z3r4hModeRouting.ts +++ b/src/lib/utils/z3r4hModeRouting.ts @@ -19,14 +19,17 @@ export const resolveZ3R4HRoutedModelId = ({ selectedModelIds: string[]; atSelectedModelId?: string; }): RoutedModelResult => { + const normalizedAvailableIds = [...new Set((availableModelIds ?? []).filter((id) => typeof id === 'string' && id.trim().length > 0))]; + const normalizedSelectedIds = [...new Set((selectedModelIds ?? []).filter((id) => typeof id === 'string' && id.trim().length > 0))]; + const mappedId = modeModelMap?.[mode] ?? null; - if (mappedId && availableModelIds.includes(mappedId)) { + if (mappedId && normalizedAvailableIds.includes(mappedId)) { return { modelId: mappedId, reason: 'mode-mapped', missingMappedModel: false }; } - const selectedId = atSelectedModelId || selectedModelIds.find((id) => !!id) || null; - if (selectedId && availableModelIds.includes(selectedId)) { + const selectedId = atSelectedModelId || normalizedSelectedIds.find((id) => !!id) || null; + if (selectedId && normalizedAvailableIds.includes(selectedId)) { return { modelId: selectedId, reason: 'selected', @@ -34,9 +37,9 @@ export const resolveZ3R4HRoutedModelId = ({ }; } - if (availableModelIds.length > 0) { + if (normalizedAvailableIds.length > 0) { return { - modelId: availableModelIds[0], + modelId: normalizedAvailableIds[0], reason: 'first-available', missingMappedModel: Boolean(mappedId) };