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..cd198dfb61d 100644 --- a/README.md +++ b/README.md @@ -237,3 +237,267 @@ 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` (default package expectation: `runtime/llama.cpp/llama-server.exe` and `models/model.gguf`). +- **Open WebUI startup mode issue:** + - `OPEN_WEBUI_START_MODE=external` requires `open-webui` in PATH + - `OPEN_WEBUI_START_MODE=bundled` requires valid `OPEN_WEBUI_BUNDLED_EXE` +- **Port conflict before startup:** launcher now fails fast if `LLAMA_PORT` or WebUI port is already listening. +- **Readiness probe unavailable/blocked:** verify PowerShell policy or curl availability on Windows. +- **Startup timeout:** check `z3r4h_launcher.log`, then verify firewall and localhost reachability. + + +### 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 + +### 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 + + +### Task 12 Blocker-Fix Focus (Windows Local) + +Task 12 hardens clean-machine startup by improving launcher preflight clarity and failure diagnostics only (no product/backend feature expansion): +- explicit Open WebUI startup-mode branching (external vs bundled) +- readiness-probe fallback diagnostics +- model-path contract clarity +- fail-fast local port conflict checks + + +### Task 13 Release-Candidate Checklist (Windows Portable Package) + +Use this RC gate before any installer/wrapper work: +1. Scope and intent confirmed (documentation/readiness-only gate). +2. Package manifest complete (launcher/runtime/model artifacts present). +3. Runtime prerequisites confirmed on clean Windows machine. +4. Preflight checks pass (startup mode, paths, ports, log write access). +5. Cold launch validation passes (llama + Open WebUI ready). +6. Operator smoke checks pass (UI opens, one local response). +7. No unresolved P0/P1 blockers in checklist blocker register. +8. Evidence captured and signoff recorded. + + +### Task 14 Validation Execution Support (Windows Local) + +For clean-machine RC execution, run validation in this exact order: +1. Session header capture (operator/date/machine/build). +2. Package manifest verification. +3. Runtime prerequisite verification. +4. Launcher preflight checks (mode/paths/ports/log write). +5. Cold launch execution and readiness confirmation. +6. Operator smoke check (UI opens + one local prompt/response). +7. Blocker classification (P0/P1/P2) and disposition. +8. RC signoff decision with evidence pack attached. + +Use `Z3R4H_CLEAN_ENV_CHECKLIST.md` as the source of truth for pass/fail recording. + + +### Task 15 RC Run Result Capture (Windows Local) + +After executing validation, record outcomes using the Task 15 run-result template in `Z3R4H_CLEAN_ENV_CHECKLIST.md`: +- per-step pass/fail/blocked status +- evidence references per step +- blocker rollup (P0/P1/P2) +- final release recommendation (`GO`, `GO-WITH-RISK`, `NO-GO`) + + +### Task 16 v1 Shipping Format Decision (Windows) + +Compared options for v1: +1. Portable BAT-launched package (current baseline) +2. Wrapped desktop `.exe` / shell approach (intended v1 target) + +**v1 Recommendation:** Ship with the wrapped desktop `.exe` / shell approach as the primary operator entry point. + +Rationale for .exe-first: +- improves operator-first launch experience by reducing manual launcher handling +- provides a clearer product-like entry path for v1 distribution +- reduces perceived complexity for first-time Windows operators + +BAT path role during transition: +- retain BAT launch flow as controlled fallback while exe-first gates are validated +- do not position BAT as primary v1 operator experience + +Exe-first gating conditions before release decision: +- repeated RC runs show no unresolved P0 launch blockers in exe-first flow +- failure diagnostics remain operator-visible and supportable +- portability expectations are preserved for packaged runtime/model assets +- support burden is acceptable versus BAT baseline in pilot validation + + +### Task 17 .exe Wrapper Implementation Plan (v1 Path) + +Task 17 defines the implementation plan only (no wrapper code yet): +- wrapper technology options and recommendation +- runtime startup orchestration sequence +- diagnostics/logging expectations +- BAT launcher fallback/support role + +v1 intended entrypoint remains `.exe` / shell wrapper, with BAT preserved as fallback/support. + + +### Task 18 Concrete .exe Wrapper Implementation Plan (Build-Ready) + +Task 18 adds the build-ready implementation plan for the `.exe` wrapper path (planning only, no code): +- recommended wrapper technology +- concrete wrapper project layout +- startup orchestration and readiness sequence +- logging/error-handling model +- BAT fallback/support path expectations + +For v1, `.exe` remains the intended primary entrypoint; BAT remains fallback/support only. + + +### Task 19 Minimal Wrapper Scaffold (Implemented) + +Added initial native C#/.NET wrapper scaffold under `wrapper/` for `.exe`-first v1 path: +- project structure and entrypoint +- config/path resolution scaffold +- orchestration/readiness/logging stubs +- BAT fallback hook scaffold + +No full runtime orchestration, installer, or build automation was implemented in this task. + + +### Task 20 First Working Wrapper Milestone + +The wrapper now provides a first working milestone for `.exe`-first path by delivering: +- config/path validation +- structured logging and error categories +- structured exit codes +- BAT fallback invocation path (`auto`/`always`/`never`) + +Full runtime orchestration/readiness/browser launch remain intentionally deferred. + + +### Task 21 First Live Llama Orchestration Milestone + +Wrapper now performs first live orchestration by launching llama and validating llama readiness. +This milestone still does **not** start Open WebUI or launch a browser. +BAT fallback remains the support/recovery path. + + +### Task 22 Open WebUI + Dual-Service Readiness Milestone + +Wrapper now supports dual-service startup readiness: +1) launch/validate llama +2) launch/validate Open WebUI + +This milestone still excludes browser launch and advanced supervision. + + +### Task 23 Browser Launch on Dual-Service Readiness + +Wrapper now opens the configured local Open WebUI URL in the default browser +only after both llama and Open WebUI readiness checks pass. + +Fallback behavior remains unchanged for earlier startup failures (`auto` / `always` / `never`). +Browser-launch-only failures are returned as structured wrapper outcomes. + + +### Task 24 Wrapper-First RC Validation Execution Support + +RC validation workflow now explicitly treats the wrapper entrypoint as the +primary clean-machine validation path for `.exe`-first shipping. + +Validation guidance now records: +- wrapper stage-by-stage outcomes (config, llama, webui, browser-launch) +- wrapper exit code + terminal stage +- BAT fallback evidence only when wrapper failure triggers support handoff + + +### Task 25 Package-Root Resolution Blocker Fix + +Wrapper default package-root detection was corrected for published RC layout so it no longer collapses to `C:\\`. +Resolved runtime and fallback paths are now anchored to the detected package root and logged at startup. diff --git a/TASKS.md b/TASKS.md new file mode 100644 index 00000000000..8f62390a5f7 --- /dev/null +++ b/TASKS.md @@ -0,0 +1,257 @@ +# 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. + + +## 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 + + +## 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). + + +## Completed (Task 12) +- Hardened launcher preflight for clean-machine startup (mode branch clarity, port checks, and clearer failure handling). +- Added readiness probe fallback/diagnostic differentiation in launcher behavior. +- Updated Windows-local checklist and README troubleshooting for Task 12 blocker fixes. +- Kept scope minimal: launcher + documentation/status only. + +## Deferred (Beyond Task 12) +- Installer generation/signing +- CI/release automation +- Bundled Open WebUI runtime build/distribution workflow + + +## Completed (Task 13) +- Added a release-candidate packaging checklist structure for portable Windows Z3R4H readiness decisions. +- Documented package manifest requirements and runtime prerequisites for RC gating. +- Added explicit RC signoff criteria and evidence expectations. +- Kept scope documentation-only with no installer/wrapper/automation implementation. + +## Deferred (Beyond Task 13) +- Installer generation/signing +- Wrapper/bootstrapper implementation +- CI/release automation +- Bundled runtime build/distribution pipeline + + +## Completed (Task 14) +- Added operator-focused execution runbook for Task 13 RC checklist on clean Windows machines. +- Added required evidence pack definition for validation runs. +- Added blocker reporting fields and escalation rules for RC decision support. +- Kept scope documentation/readiness-only with no product/backend behavior changes. + +## Deferred (Beyond Task 14) +- Installer generation/signing +- Wrapper/bootstrapper implementation +- CI/release automation +- Bundled runtime build/distribution pipeline + + +## Completed (Task 15) +- Added RC run-result template for clean-Windows execution outcomes. +- Added pass/fail evidence field requirements for each validation step. +- Added blocker rollup and release recommendation rules (`GO`, `GO-WITH-RISK`, `NO-GO`). +- Kept scope documentation-only and operator-friendly. + +## Deferred (Beyond Task 15) +- Installer generation/signing +- Wrapper/bootstrapper implementation +- CI/release automation +- Bundled runtime build/distribution pipeline + + +## Completed (Task 16) +- Added v1 shipping-format decision support comparing portable BAT baseline vs wrapped `.exe` target path. +- Documented comparison criteria: operator experience, portability, support burden, and launch risk. +- Recorded exe-first v1 recommendation with explicit gating conditions for release readiness. +- Kept scope decision-oriented and documentation-only (no wrapper implementation). + +## Deferred (Beyond Task 16) +- Wrapper/desktop `.exe` implementation +- Installer generation/signing +- CI/release automation +- Bundled runtime build/distribution pipeline + + +## Completed (Task 17) +- Added .exe wrapper implementation planning docs for v1 (no code implementation). +- Documented wrapper technology options and selected lightweight native launcher approach. +- Added planned runtime orchestration flow, diagnostics/logging expectations, and BAT fallback strategy. +- Kept scope planning/documentation only. + +## Deferred (Beyond Task 17) +- Wrapper executable implementation +- Wrapper build pipeline/toolchain setup +- Installer generation/signing +- CI/release automation + + +## Completed (Task 18) +- Added concrete build-ready planning docs for `.exe` wrapper implementation (no code changes). +- Documented recommended wrapper technology and project/file structure. +- Documented exact startup orchestration flow and readiness sequence. +- Documented logging/error model and BAT fallback preservation strategy. + +## Deferred (Beyond Task 18) +- Wrapper code/build implementation +- Wrapper toolchain setup and artifact production +- Installer generation/signing +- CI/release automation + + +## Completed (Task 19) +- Added minimal native C#/.NET wrapper scaffold under `wrapper/` for `.exe`-first path. +- Added entrypoint/config/orchestration/logging/fallback scaffold files. +- Kept orchestration/readiness as stubs to avoid behavior changes in scaffold phase. + +## Deferred (Beyond Task 19) +- Full runtime orchestration and readiness logic +- Browser-open behavior implementation +- Wrapper build/release pipeline and packaging automation +- Installer generation/signing + + +## Completed (Task 20) +- Upgraded wrapper scaffold to first working milestone with config/path validation and structured exit behavior. +- Added fallback-mode support and actual BAT fallback invocation path. +- Added structured logging/error categories for milestone failure states. + +## Deferred (Beyond Task 20) +- Full runtime orchestration/readiness lifecycle +- Browser-open behavior +- Build/release pipeline and installer/signing + + +## Completed (Task 21) +- Extended wrapper to first live orchestration milestone: llama process launch + readiness polling. +- Added llama-specific structured exit codes and failure mapping. +- Preserved BAT fallback policies (`auto`/`always`/`never`) for support/recovery. + +## Deferred (Beyond Task 21) +- Open WebUI startup/orchestration +- Browser launch +- Dual-service lifecycle management +- Installer/signing/build automation + + +## Completed (Task 22) +- Extended wrapper from single-service llama milestone to dual-service startup readiness milestone. +- Added Open WebUI launch + readiness polling after llama readiness success. +- Added stage-aware exit mapping for llama/webui launch/readiness failures. + +## Deferred (Beyond Task 22) +- Browser launch +- Embedded UI +- Advanced process supervision/restart policy +- Installer/signing/build automation + + +## Completed (Task 23) +- Extended wrapper to launch the default browser after confirmed dual-service readiness. +- Added stage-aware browser launch success/failure handling and exit mapping. +- Preserved BAT fallback behavior for earlier startup failures only. + +## Deferred (Beyond Task 23) +- Embedded UI +- Advanced process supervision/restart policy +- Installer/signing/build automation + + +## Completed (Task 24) +- Adapted RC validation docs for wrapper-first execution on clean Windows machines. +- Added wrapper-specific evidence capture requirements (stage outcomes, exit code, BAT handoff evidence). +- Added wrapper-specific blocker categories for RC triage and release recommendation support. + +## Deferred (Beyond Task 24) +- Wrapper runtime behavior changes +- Product/backend changes +- Embedded UI +- Advanced process supervision/restart policy +- Installer/signing/build automation + + +## Completed (Task 25) +- Fixed wrapper package-root auto-detection for published RC layout. +- Fixed default llama and BAT path derivation from resolved package root. +- Added explicit startup logging for resolution source, package root, llama path, and BAT path. + +## Deferred (Beyond Task 25) +- Embedded UI +- Advanced process supervision/restart policy +- Installer/signing/build automation diff --git a/Z3R4H_CLEAN_ENV_CHECKLIST.md b/Z3R4H_CLEAN_ENV_CHECKLIST.md new file mode 100644 index 00000000000..edd50c0126d --- /dev/null +++ b/Z3R4H_CLEAN_ENV_CHECKLIST.md @@ -0,0 +1,649 @@ +# 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. +- 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 +- 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) + + +## 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 + + +## 15) Task 12 Blocker Fix Verification (Windows Local) +- Confirm startup mode branch is explicit: + - `OPEN_WEBUI_START_MODE=external` -> PATH check for `open-webui` + - `OPEN_WEBUI_START_MODE=bundled` -> file existence check for `OPEN_WEBUI_BUNDLED_EXE` +- Confirm launcher fails fast on occupied ports before starting processes. +- Confirm missing model path error shows configured path and expected package default. +- Confirm readiness probe failures are distinguishable from service startup timeouts. + +## 16) Task 12 Blockers Fixed Now +- Startup-mode ambiguity for Open WebUI command source. +- Readiness-probe fragility/diagnostic ambiguity. +- Model-path assumption clarity for packaged layout. +- Port-conflict detection clarity. + +## 17) Deferred Beyond Task 12 +- Installer generation/signing +- CI/release automation +- Bundled Open WebUI runtime build/distribution workflow +- Product/backend behavior changes outside launcher robustness + + +## 18) Task 13 Release-Candidate Checklist Structure +1. Scope & Intent +2. Package Manifest +3. Runtime Prerequisites +4. Preflight Validation +5. Launch Validation +6. Operator Smoke Checks +7. Blocker Gate (P0/P1) +8. Evidence & Signoff + +## 19) Package Manifest (Portable Windows RC) +Required: +- `launch_z3r4h.bat` +- `runtime/llama.cpp/llama-server.exe` (or configured equivalent) +- `models/model.gguf` (or configured equivalent) +- `runtime/open-webui/open-webui.exe` if `OPEN_WEBUI_START_MODE=bundled` +- writable launcher directory for `z3r4h_launcher.log` + +## 20) Runtime Prerequisites (Windows Local) +- CMD-based launcher execution supported +- localhost network access for configured ports +- Startup mode prerequisite: + - `external` mode -> `open-webui` in PATH + - `bundled` mode -> valid `OPEN_WEBUI_BUNDLED_EXE` +- Readiness probe capability via PowerShell and/or curl per launcher behavior + +## 21) RC Signoff Criteria +Mark build RC-ready only when all are true: +- Package manifest complete for selected startup mode +- Preflight checks pass with no ambiguous failures +- Cold launch completes with both services ready +- UI opens and one local prompt returns a response +- No unresolved P0/P1 launch blockers +- Evidence set captured: checklist results + key log excerpts + signoff date/owner + +## 22) Deferred Beyond Task 13 +- Installer generation/signing +- Wrapper/bootstrapper work +- CI/release automation +- Bundled runtime build/distribution pipeline +- Backend/product behavior changes + + +## 23) Task 14 Execution Workflow (Operator Runbook) +Execute in order and record pass/fail per step: +1. **Session Header** + - Operator name/initials + - Date/time (local) + - Machine profile (Windows version, shell, clean-profile confirmation) + - Build/package identifier +2. **Manifest Check** + - Verify required package contents for selected startup mode +3. **Prerequisite Check** + - Verify runtime prerequisites and startup mode requirements +4. **Preflight Check** + - Validate launcher configuration, ports, and log write path +5. **Cold Launch** + - Run launcher and confirm readiness path completes +6. **Smoke Validation** + - Confirm UI reachable and one local prompt returns response +7. **Blocker Gate** + - Classify and log blockers as P0/P1/P2 +8. **Signoff** + - Mark RC-ready or blocked with owner/date + +## 24) Task 14 Evidence Pack (Required) +Capture and store for each validation run: +- Session header metadata (operator/date/machine/build) +- Startup mode used (`external` or `bundled`) +- Step-by-step pass/fail outcomes from section 23 +- `z3r4h_launcher.log` excerpts for preflight, readiness, and any errors +- One smoke-test prompt/response result +- Blocker entries with severity/repro/evidence references +- Final signoff record (RC-ready vs blocked, owner/date) + +## 25) Blocker Reporting and Escalation Rules +For each blocker record: +- ID +- Severity (P0/P1/P2) +- Stage (manifest/prereq/preflight/launch/smoke/signoff) +- Reproducibility (always/intermittent) +- Expected vs actual behavior +- Evidence pointer (log timestamp, screenshot/notes path) +- Owner and status + +Escalation policy: +- **P0**: Immediate stop, RC status = blocked, escalate immediately. +- **P1**: RC blocked unless explicit acceptance is documented by owner. +- **P2**: RC may proceed with follow-up task logged and owner assigned. + +Status lifecycle: +- Open -> Triaged -> Mitigated -> Closed +- Open -> Triaged -> Accepted Risk (with owner/date) + +## 26) Deferred Beyond Task 14 +- Installer generation/signing +- Wrapper/bootstrapper implementation +- CI/release automation +- Bundled runtime build/distribution pipeline +- Product/backend behavior changes outside validation support + + +## 27) Task 15 RC Run Result Template +Complete this section for each clean-Windows RC run. + +### Run Metadata +- Run ID: +- Operator: +- Date/Time (local): +- Machine Profile: +- Build/Package ID: +- Startup Mode (`external`/`bundled`): + +### Step Results +| Step | Status (PASS/FAIL/BLOCKED) | Timestamp | Expected | Actual | Evidence Ref | Notes | +|---|---|---|---|---|---|---| +| Manifest Check | | | | | | | +| Prerequisite Check | | | | | | | +| Preflight Check | | | | | | | +| Cold Launch | | | | | | | +| Smoke Validation | | | | | | | +| Blocker Gate | | | | | | | +| Signoff | | | | | | | + +## 28) Task 15 Pass/Fail Evidence Fields (Required) +Per-step required fields: +- Step name +- Status (`PASS`, `FAIL`, `BLOCKED`) +- Timestamp +- Expected result +- Actual result +- Evidence reference (log excerpt path/time, console note, screenshot path if captured) +- Operator notes + +Run-level required evidence: +- `z3r4h_launcher.log` reference and key timestamps +- One smoke-test prompt/response record +- Environment notes affecting outcome (ports, mode, path overrides) + +## 29) Task 15 Blocker Rollup and Release Recommendation +### Blocker Rollup Table +| Severity | Count Open | Count Closed | Decision Impact | +|---|---:|---:|---| +| P0 | | | Immediate NO-GO while open | +| P1 | | | NO-GO unless explicitly accepted by owner | +| P2 | | | GO allowed with follow-up tracking | + +### Release Recommendation Rules +- Any open **P0** -> `NO-GO` +- Any open **P1** -> `NO-GO` unless acceptance is documented (owner/date/rationale) +- No open P0/P1 and only P2 or none -> `GO` or `GO-WITH-RISK` + +### Recommendation Record +- Recommendation (`GO` / `GO-WITH-RISK` / `NO-GO`): +- Rationale: +- Approver/Owner: +- Date: + +## 30) Deferred Beyond Task 15 +- Installer generation/signing +- Wrapper/bootstrapper implementation +- CI/release automation +- Bundled runtime build/distribution pipeline +- Product/backend behavior changes outside validation results capture + + +## 31) Task 16 Shipping Format Comparison (v1 Decision Support) +### Options Compared +- **Option A:** Portable BAT-launched package (current baseline) +- **Option B:** Wrapped desktop `.exe` / shell approach (intended v1 target) + +### Comparison Matrix +| Criterion | Option A: Portable BAT | Option B: Wrapped `.exe` | +|---|---|---| +| Operator first-run UX | Medium (manual launcher awareness) | Strong (single desktop entry path) | +| Time-to-ship from current state | Strong | Medium (requires wrapper delivery readiness) | +| Portability behavior | Strong | Medium/Strong (depends on wrapper packaging discipline) | +| Support burden profile | Medium (manual setup questions) | Medium (wrapper + runtime diagnostics) | +| Launch risk from extra layer | Lower | Higher initially (new shell layer) | +| v1 product presentation | Medium | Strong | + +## 32) Criteria Evaluated +- Operator experience and first-run clarity on clean Windows machines +- Portability of runtime/model/package assets +- Support burden and diagnosability for field issues +- Incremental launch risk introduced by wrapper layer +- Alignment with v1 shipping intent and distribution expectations + +## 33) Task 16 v1 Recommendation (Exe-First) +**Recommended v1 shipping format: Option B (Wrapped desktop `.exe` / shell approach).** + +Rationale: +- Best matches intended v1 operator experience (single obvious launch path). +- Better presentation for non-technical operators in initial distribution. +- Enables BAT launcher to shift to fallback/support role rather than primary UX. + +## 34) Exe-First Gating Conditions (Must Be True) +1. RC validation shows no unresolved P0 blockers in exe-first launch path. +2. P1 issues are either closed or explicitly accepted with owner/date/rationale. +3. Diagnostic visibility is preserved (launcher/log evidence still available to support). +4. Packaged portability assumptions remain valid after wrapper introduction. +5. Pilot support burden is acceptable relative to BAT baseline. + +## 35) Deferred Beyond Task 16 +- Wrapper/desktop `.exe` implementation +- Installer generation/signing +- CI/release automation +- Bundled runtime build/distribution pipeline changes +- Product/backend behavior changes + + +## 36) Task 17 Wrapper Technology Options +### Option A: Lightweight native launcher executable +- Small orchestration-focused wrapper +- Direct process start/monitor for local runtime services +- Minimal UI surface, strong control over startup states + +### Option B: Desktop shell framework wrapper +- Richer UI opportunities +- More runtime/moving parts for v1 + +### Option C: Executable stub delegating to BAT +- Fastest to scaffold +- Keeps BAT-centric launch behavior too visible for primary v1 UX + +## 37) Task 17 Recommended Wrapper Approach (v1) +**Recommended:** Option A (lightweight native launcher executable) as primary v1 entrypoint. + +Rationale: +- Balances operator simplicity with low orchestration complexity. +- Avoids large framework overhead for v1 launch path. +- Preserves direct control over startup, readiness, and failure states. + +## 38) Planned Runtime Orchestration Flow +1. Validate package structure and startup mode assumptions. +2. Validate key paths/ports and log file accessibility. +3. Launch local llama runtime process. +4. Poll llama readiness endpoint until success or timeout. +5. Launch Open WebUI process. +6. Poll Open WebUI readiness endpoint until success or timeout. +7. Open local UI URL for operator when both are ready. +8. Surface clear failure state with remediation hint if any stage fails. + +## 39) Diagnostics, Logging, and BAT Fallback Strategy +- Preserve launcher log continuity (`z3r4h_launcher.log` evidence flow). +- Keep failure categories operator-visible (path/mode/port/probe/timeout). +- Preserve BAT launcher as documented fallback/support path. +- Add explicit support step: if wrapper launch fails, retry via BAT path and capture comparative evidence. + +## 40) Deferred Beyond Task 17 +- Wrapper executable implementation +- Wrapper build pipeline/toolchain setup +- Installer generation/signing +- CI/release automation +- Product/backend behavior changes + + +## 41) Task 18 Recommended Wrapper Technology (Build-Ready Plan) +**Recommendation:** Lightweight native Windows launcher executable as the wrapper core. + +Rationale: +- Provides direct process orchestration control with minimal additional runtime surface. +- Keeps startup/readiness state handling explicit and supportable. +- Supports `.exe`-first operator experience without requiring heavy framework overhead for v1. + +## 42) Task 18 Proposed Wrapper Project/File Structure +```text +wrapper/ +├─ README.md +├─ src/ +│ ├─ main/ # entrypoint + single-instance behavior +│ ├─ config/ # package-root, mode, path, port resolution +│ ├─ orchestrator/ # process launch/monitor/stop sequencing +│ ├─ health/ # readiness checks + timeout policy +│ ├─ logging/ # wrapper events + launcher log bridging +│ └─ fallback/ # BAT fallback invocation support +├─ assets/ # icon/version placeholders +└─ build/ # output conventions and artifact layout +``` + +## 43) Task 18 Exact Startup Orchestration Flow +1. Resolve package root and effective configuration (mode/paths/ports). +2. Validate required files, ports, and log writeability. +3. Start llama runtime process. +4. Poll llama readiness endpoint until ready or timeout. +5. Start Open WebUI process. +6. Poll Open WebUI readiness endpoint until ready or timeout. +7. On success, open local UI URL in default browser (v1 default path). +8. On failure, emit stage-specific error and present fallback action. + +## 44) Logging, Error Handling, and BAT Fallback Preservation +- Preserve `z3r4h_launcher.log` continuity for support evidence. +- Emit wrapper-level stage markers (preflight/startup/readiness/failure). +- Map failures to actionable classes: + - config/path errors + - startup mode errors + - port conflicts + - readiness timeout/failure +- Keep BAT launcher as fallback/support path with explicit handoff condition and operator guidance. + +## 45) Task 18 Minimum Viable Wrapper Implementation Milestone +MVP is reached when all are true: +- `.exe` wrapper starts and monitors both runtime processes. +- Readiness checks gate success/failure with clear timeout behavior. +- Browser opens only after both services are ready. +- Failure diagnostics are operator-actionable and logged. +- BAT fallback can be triggered and documented for support use. + +## 46) Deferred Beyond Task 18 +- Wrapper code/build implementation +- Wrapper toolchain setup and artifact production +- Installer generation/signing +- CI/release automation +- Embedded-WebView-first approach for v1 +- Product/backend behavior changes + + +## 47) Task 19 Wrapper Scaffold Structure (Implemented) +```text +wrapper/ +├─ README.md +├─ .gitignore +├─ Z3R4H.Wrapper.sln +└─ src/Z3R4H.Wrapper/ + ├─ Z3R4H.Wrapper.csproj + ├─ Program.cs + ├─ App/ + │ ├─ WrapperApp.cs + │ └─ StartupResult.cs + ├─ Config/ + │ ├─ WrapperConfig.cs + │ └─ ConfigResolver.cs + ├─ Orchestration/RuntimeOrchestrator.cs + ├─ Health/ReadinessProbe.cs + ├─ Logging/WrapperLogger.cs + └─ Fallback/BatFallback.cs +``` + +## 48) Task 19 Entrypoint vs Stubbed Behavior +Entrypoint (`Program.cs` + `WrapperApp.cs`) currently: +- initializes logger/config/orchestrator/fallback components +- resolves package-root and BAT/log paths +- executes orchestration scaffold and returns structured exit code + +Still stubbed in Task 19: +- full process orchestration for llama/Open WebUI +- full readiness polling/timeout behavior +- browser open logic + +## 49) Task 19 Logging/Error Categories and BAT Fallback Hook +- Logging scaffold via `WrapperLogger` with stage/error outputs +- Error categories scaffolded: + - `ConfigError`, `PathError`, `ModeError`, `PortConflict`, `ProbeFailure`, `Timeout`, `StartupFailure`, `FallbackInvocation` +- BAT fallback represented via `BatFallback.ReportFallbackHint(...)` with explicit fallback path hint to `launch_z3r4h.bat` + +## 50) Deferred Beyond Task 19 +- Full orchestration and readiness implementation +- Browser-open behavior implementation +- Wrapper build/release pipeline and packaging automation +- Installer generation/signing +- Embedded UI path +- Product/backend behavior changes + + +## 51) Task 20 Wrapper Milestone Behavior (Implemented) +Wrapper now performs: +- package-root and key-path resolution +- config validation (`startup-mode`, `fallback`) +- structured stage/error logging +- structured exit code return +- BAT fallback invocation when configured + +## 52) Task 20 Supported Success/Failure States and Exit Codes +- `0` (`Success`): milestone validation success +- `10` (`ConfigResolutionFailed`): config resolution error +- `11` (`ConfigValidationFailed`): config/path validation failed +- `12` (`UnsupportedMode`): startup mode unsupported in milestone +- `20` (`FallbackInvoked`): BAT fallback invoked and completed +- `21` (`FallbackInvocationFailed`): BAT fallback failed to invoke/complete +- `99` (`UnhandledError`): unhandled wrapper exception + +## 53) Task 20 BAT Fallback Invocation/Logging Rules +- Fallback mode `always`: invoke BAT immediately +- Fallback mode `auto`: invoke BAT when validation/startup gate fails +- Fallback mode `never`: return failure without invoking BAT +- Every fallback attempt logs reason, target BAT path, and resulting exit code + +## 54) Deferred Beyond Task 20 +- Full llama/Open WebUI process orchestration +- Full readiness lifecycle and timeout policy +- Browser launch behavior +- Installer/signing/build automation +- Embedded UI path + + +## 55) Task 21 Live Llama Orchestration Behavior (Implemented) +Wrapper now performs: +- config/path validation including llama executable and model paths +- llama process launch via configured host/port/model args +- llama readiness polling against `/health` with timeout/poll intervals +- structured success/failure + optional BAT fallback + +## 56) Task 21 Supported Exit Codes +- `0` Success (llama launched + readiness passed) +- `10` ConfigResolutionFailed +- `11` ConfigValidationFailed +- `12` UnsupportedMode +- `13` LlamaLaunchFailed +- `14` LlamaReadinessFailed +- `20` FallbackInvoked +- `21` FallbackInvocationFailed +- `99` UnhandledError + +## 57) Task 21 BAT Fallback Interaction +- `always` -> invoke BAT immediately +- `auto` -> invoke BAT on llama launch/readiness failure +- `never` -> do not invoke BAT; return structured failure +- fallback logging includes reason, BAT path, and BAT exit result + +## 58) Deferred Beyond Task 21 +- Open WebUI startup +- Browser launch +- Dual-service orchestration lifecycle +- Installer/signing/build automation + + +## 59) Task 22 Dual-Service Startup Behavior (Implemented) +Wrapper now performs: +- llama launch + llama readiness +- Open WebUI launch after llama ready +- Open WebUI readiness polling +- stage-specific structured outcomes + +## 60) Task 22 New/Updated Exit Codes +- `0` Success (dual-service ready) +- `10` ConfigResolutionFailed +- `11` ConfigValidationFailed +- `12` UnsupportedMode +- `13` LlamaLaunchFailed +- `14` LlamaReadinessFailed +- `15` WebUiLaunchFailed +- `16` WebUiReadinessFailed +- `20` FallbackInvoked +- `21` FallbackInvocationFailed +- `99` UnhandledError + +## 61) Task 22 BAT Fallback Behavior for Dual-Service Startup +- `always`: invoke BAT immediately +- `auto`: invoke BAT on llama-stage or webui-stage failure +- `never`: return structured failure without BAT invocation +- fallback logs include failure stage, reason, BAT path, and BAT result + +## 62) Deferred Beyond Task 22 +- Browser launch +- Embedded UI +- Advanced process supervision/restart policies +- Installer/signing/build automation + + +## 63) Task 23 Browser Launch Behavior (Implemented) +After dual-service readiness succeeds, wrapper requests browser launch using the configured local Open WebUI URL. +Browser launch is not attempted before llama + Open WebUI readiness gates pass. + +## 64) Task 23 Exit Code Update +- `17` BrowserLaunchFailed + +## 65) Task 23 Fallback Behavior +- `always`: invoke BAT immediately (unchanged) +- `auto`: invoke BAT on earlier startup/readiness failures only (llama/webui stages) +- `never`: no fallback invocation +- browser-launch-only failure returns structured wrapper failure without BAT handoff + +## 66) Deferred Beyond Task 23 +- Embedded UI +- Advanced process supervision/restart policies +- Installer/signing/build automation + + +## 67) Task 24 Wrapper-First RC Workflow Adaptation (Implemented) +- Wrapper `.exe` execution is now the primary RC validation entrypoint on clean Windows machines. +- Required wrapper-stage run order for evidence: `config` -> `llama-*` -> `webui-*` -> `browser-launch`. +- BAT execution is a fallback/support branch only when wrapper failure triggers handoff. + +## 68) Task 24 Wrapper-Specific Evidence Fields (Required) +- Wrapper executable path and command arguments used. +- Wrapper exit code and terminal stage. +- Stage-by-stage pass/fail notes for config, llama, webui, and browser-launch. +- Readiness evidence for llama and Open WebUI stages. +- Browser-launch outcome evidence (success/failure message). +- BAT fallback invocation details (reason, BAT exit code) when applicable. +- Final RC recommendation with owner/date. + +## 69) Task 24 Wrapper-Specific Blocker Categories +- Wrapper config/path resolution failure. +- Wrapper llama launch/readiness failure. +- Wrapper Open WebUI launch/readiness failure. +- Wrapper browser-launch failure. +- Wrapper -> BAT fallback handoff failure. +- Wrapper exit-code/stage evidence mismatch. +- Wrapper-first clean-machine usability blocker (primary path fails even if BAT fallback runs). + +## 70) Deferred Beyond Task 24 +- Wrapper runtime behavior changes +- Product/backend changes +- Embedded UI +- Advanced supervision/restart policies +- Installer/signing/build automation diff --git a/Z3R4H_PROGRESS_SUMMARY.md b/Z3R4H_PROGRESS_SUMMARY.md new file mode 100644 index 00000000000..16ecd8b8931 --- /dev/null +++ b/Z3R4H_PROGRESS_SUMMARY.md @@ -0,0 +1,342 @@ +# 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. + + +## 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 + + +## 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`). + + +## Task 12 Blocker-Fix Status +- Implemented launcher-level clean-machine risk reductions in `launch_z3r4h.bat`: + - explicit Open WebUI startup mode (`external` vs `bundled`) with mode-specific preflight errors + - fail-fast local port conflict checks before service startup + - readiness probe fallback path and distinct probe-failure messaging + - clearer model-path failure diagnostics with expected package defaults +- Updated validation docs/checklist to reflect Task 12 verification criteria. + +### Task 12 Blockers Fixed Now +1. Open WebUI external CLI dependency ambiguity (mode-specific handling). +2. Readiness-probe fragility (fallback + clearer failure class). +3. Model-path assumption clarity (default contract + explicit path output). +4. Port-conflict detection clarity (pre-start fail-fast check). + +### Still Deferred Beyond Task 12 +- Installer generation/signing +- CI/release automation +- Bundled Open WebUI runtime build/distribution workflow + + +## Task 13 RC Packaging Checklist Status +- Added a consistent release-candidate checklist for portable Windows package readiness. +- Defined required package contents and runtime prerequisites by startup mode. +- Added explicit RC signoff gate criteria and required evidence set. +- Scope remained documentation/readiness-only (no behavior changes, no automation work). + +### Task 13 RC Gate Focus +1. Manifest completeness +2. Clean-machine preflight validity +3. Cold launch readiness +4. Local operator smoke pass +5. No unresolved P0/P1 blockers + +### Still Deferred Beyond Task 13 +- Installer generation/signing +- Wrapper/bootstrapper implementation +- CI/release automation +- Bundled runtime build/distribution pipeline + + +## Task 14 Validation Execution Support Status +- Added an execution-ready operator runbook for RC checklist validation on clean Windows machines. +- Added required evidence pack contents for consistent run-to-run validation records. +- Added blocker reporting schema and escalation rules tied to RC signoff decisions. +- Scope remained documentation/readiness only (no launcher/backend/product behavior changes). + +### Task 14 Execution-Support Deliverables +1. Ordered operator workflow +2. Required evidence pack +3. Blocker escalation policy +4. RC signoff support criteria + +### Still Deferred Beyond Task 14 +- Installer generation/signing +- Wrapper/bootstrapper implementation +- CI/release automation +- Bundled runtime build/distribution pipeline + + +## Task 15 RC Results Capture Status +- Added an operator-ready run-result template for real clean-Windows RC runs. +- Added required pass/fail evidence fields for consistent result capture. +- Added blocker rollup logic tied directly to release recommendation output. +- Scope remained documentation/readiness-only with no behavior changes. + +### Task 15 Decision Outputs +1. Step-level pass/fail/blocked record +2. Evidence-linked blocker outcomes +3. Explicit release recommendation (`GO` / `GO-WITH-RISK` / `NO-GO`) + +### Still Deferred Beyond Task 15 +- Installer generation/signing +- Wrapper/bootstrapper implementation +- CI/release automation +- Bundled runtime build/distribution pipeline + + +## Task 16 v1 Shipping Decision Status +- Added shipping-format comparison for v1 between portable BAT baseline and wrapped desktop `.exe` target path. +- Evaluated tradeoffs across operator experience, portability, support burden, and launch risk. +- Selected wrapped `.exe` / shell approach as intended v1 recommendation with gating conditions. +- Kept wrapper/installer implementation deferred beyond decision stage. + +### Task 16 Recommendation +- **v1 Ship Format:** Wrapped desktop `.exe` / shell approach +- **Reason:** Stronger first-run operator experience and clearer product-facing launch entry for v1 + +### Exe-First Gating Conditions +1. No unresolved P0 blockers in exe-first RC validation +2. P1 issues closed or explicitly accepted with owner/date +3. Diagnostics/support visibility preserved +4. Portability assumptions remain valid + +### Still Deferred Beyond Task 16 +- Wrapper/desktop `.exe` implementation +- Installer generation/signing +- CI/release automation +- Bundled runtime build/distribution pipeline + + +## Task 17 Wrapper Implementation Plan Status +- Added wrapper technology-option comparison and selected a lightweight native launcher direction for v1. +- Added planned startup orchestration flow for llama + Open WebUI readiness management. +- Added diagnostics/logging continuity and BAT fallback/support strategy documentation. +- Kept BAT as fallback/support path while `.exe` remains intended primary v1 entrypoint. + +### Task 17 Planned Wrapper Behaviors +1. Preflight validation +2. Runtime process orchestration +3. Readiness monitoring and timeout handling +4. Error visibility and fallback guidance + +### Still Deferred Beyond Task 17 +- Wrapper executable implementation +- Wrapper build pipeline/toolchain setup +- Installer generation/signing +- CI/release automation + + +## Task 18 Concrete Wrapper Plan Status +- Added build-ready wrapper planning details for `.exe`-first v1 entrypoint. +- Added concrete project layout and startup orchestration sequence. +- Added explicit logging/error-handling model and BAT fallback preservation plan. +- Defined minimum viable wrapper milestone for implementation handoff. + +### Task 18 MVP Definition +1. Wrapper orchestrates startup/readiness for llama + Open WebUI +2. Stage-specific errors are logged and operator-actionable +3. BAT fallback path is preserved for support + +### Still Deferred Beyond Task 18 +- Wrapper code/build implementation +- Wrapper toolchain setup and artifact production +- Installer generation/signing +- CI/release automation + + +## Task 19 Wrapper Scaffold Status +- Implemented initial native C#/.NET wrapper scaffold structure under `wrapper/`. +- Added executable entrypoint and core component stubs (config/orchestration/health/logging/fallback). +- Preserved BAT as fallback/support hint path in scaffold behavior. +- Deferred full orchestration, readiness, and packaging pipeline work. + +### Task 19 Scaffold Outputs +1. Wrapper project skeleton and solution +2. Entrypoint + startup result model +3. Logging/error category scaffold +4. BAT fallback hook scaffold + +### Still Deferred Beyond Task 19 +- Full runtime orchestration/readiness implementation +- Browser-open behavior +- Build/release pipeline + installer/signing + + +## Task 20 First Working Wrapper Milestone Status +- Implemented first functional wrapper milestone with config/path validation and structured exit outcomes. +- Added fallback mode handling (`auto`/`always`/`never`) and BAT invocation behavior. +- Added structured error categorization and milestone-stage logging. + +### Task 20 Milestone Delivers +1. Validation-first wrapper entrypoint +2. Structured success/failure exit codes +3. BAT fallback invocation + logging + +### Still Deferred Beyond Task 20 +- Full runtime orchestration/readiness lifecycle +- Browser-open behavior +- Build/release pipeline + installer/signing + + +## Task 21 Live Llama Orchestration Status +- Wrapper now launches llama runtime and validates readiness via `/health` polling. +- Structured exit outcomes expanded for llama launch/readiness failures. +- BAT fallback remains available as support/recovery mechanism. + +### Task 21 Milestone Delivers +1. Live llama process launch +2. Llama readiness validation +3. Structured recovery behavior with fallback policy + +### Still Deferred Beyond Task 21 +- Open WebUI startup +- Browser launch +- Dual-service orchestration lifecycle +- Build/release pipeline + installer/signing + + +## Task 22 Dual-Service Readiness Status +- Wrapper now performs dual-service startup sequencing: llama then Open WebUI. +- Added Open WebUI launch/readiness handling and stage-specific failure mapping. +- Fallback policy retained for both service stages (`auto`/`always`/`never`). + +### Task 22 Milestone Delivers +1. Llama live startup/readiness +2. Open WebUI startup/readiness +3. Structured dual-service outcome model + +### Still Deferred Beyond Task 22 +- Browser launch +- Embedded UI +- Advanced supervision + installer/signing/build automation + + +## Task 23 Browser Launch Milestone Status +- Wrapper now requests browser launch after llama + Open WebUI readiness succeeds. +- Added structured browser-launch stage handling and exit mapping. +- BAT fallback remains limited to earlier startup failures (`auto`/`always`/`never` behavior preserved). + +### Task 23 Milestone Delivers +1. Dual-service startup/readiness (existing) +2. Browser launch request after confirmed readiness +3. Structured browser-launch success/failure outcome + +### Still Deferred Beyond Task 23 +- Embedded UI +- Advanced supervision/restart lifecycle +- Build/release pipeline + installer/signing + + +## Task 24 Wrapper-First RC Validation Support Status +- RC validation workflow now explicitly treats wrapper `.exe` as primary clean-machine entrypoint. +- Added wrapper-specific evidence expectations (stage outcomes, exit code, BAT handoff evidence). +- Added wrapper-specific blocker categories for triage and release recommendation consistency. + +### Task 24 Milestone Delivers +1. Wrapper-first execution flow in RC validation docs +2. Wrapper-specific evidence capture requirements +3. Wrapper-specific blocker/risk classification for clean-machine runs + +### Still Deferred Beyond Task 24 +- Wrapper runtime behavior changes +- Product/backend changes +- Embedded UI +- Advanced supervision/restart lifecycle +- Build/release pipeline + installer/signing + + +## Task 25 Package-Root Resolution Fix Status +- Fixed wrapper default package-root detection to align with RC packaged layout. +- Resolved runtime/fallback defaults now derive from detected package root instead of filesystem root. +- Added startup logs for package-root source, resolved package root, resolved llama path, and resolved BAT path. + +### Task 25 Milestone Delivers +1. Correct package-root auto-detection in RC wrapper-first runs +2. Correct default path resolution for llama runtime and BAT fallback +3. Operator-visible path resolution diagnostics at startup + +### Still Deferred Beyond Task 25 +- Embedded UI +- Advanced supervision/restart lifecycle +- Build/release pipeline + installer/signing 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..ecf77470001 --- /dev/null +++ b/launch_z3r4h.bat @@ -0,0 +1,184 @@ +@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 mode: +REM - external (default): uses `open-webui` from PATH +REM - bundled: uses OPEN_WEBUI_BUNDLED_EXE +set "OPEN_WEBUI_START_MODE=external" +set "OPEN_WEBUI_BUNDLED_EXE=%PACKAGE_ROOT%runtime\open-webui\open-webui.exe" +set "OPEN_WEBUI_START_CMD=open-webui serve" + +set "OPEN_WEBUI_URL=http://localhost:8080" +set "OPEN_WEBUI_PORT=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)." + exit /b 1 +) + +echo %OPEN_WEBUI_URL% | findstr /I /R "^http://localhost[:/]" >nul +if errorlevel 1 ( + call :fail "OPEN_WEBUI_URL must be localhost-only (http://localhost:...)." + exit /b 1 +) + +if not exist "%LLAMA_SERVER_EXE%" ( + call :fail "Missing llama.cpp executable. Expected default: %PACKAGE_ROOT%runtime\llama.cpp\llama-server.exe | Configured: %LLAMA_SERVER_EXE%" + exit /b 1 +) +if not exist "%MODEL_PATH%" ( + call :fail "Missing model file. Expected default: %PACKAGE_ROOT%models\model.gguf | Configured: %MODEL_PATH%" + exit /b 1 +) + +if /I "%OPEN_WEBUI_START_MODE%"=="bundled" ( + if not exist "%OPEN_WEBUI_BUNDLED_EXE%" ( + call :fail "Bundled Open WebUI executable not found: %OPEN_WEBUI_BUNDLED_EXE%" + exit /b 1 + ) + set "OPEN_WEBUI_START_CMD=\"%OPEN_WEBUI_BUNDLED_EXE%\" serve" + call :log "Open WebUI startup mode: bundled (%OPEN_WEBUI_BUNDLED_EXE%)" +) else ( + where open-webui >nul 2>&1 + if errorlevel 1 ( + call :fail "External Open WebUI mode selected but open-webui not found in PATH. Set OPEN_WEBUI_START_MODE=bundled and configure OPEN_WEBUI_BUNDLED_EXE, or install open-webui in PATH." + exit /b 1 + ) + call :log "Open WebUI startup mode: external (open-webui in PATH)" +) + +call :check_port_free "%LLAMA_PORT%" "llama.cpp" +if errorlevel 1 exit /b 1 +call :check_port_free "%OPEN_WEBUI_PORT%" "Open WebUI" +if errorlevel 1 exit /b 1 + +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 2 ( + call :fail "Readiness probe unavailable/blocked (PowerShell and curl probes failed)." + exit /b 1 +) +if errorlevel 1 ( + call :fail "llama.cpp startup timeout. Verify port conflicts/firewall and review %LOG_FILE%." + exit /b 1 +) + +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 2 ( + call :fail "Readiness probe unavailable/blocked (PowerShell and curl probes failed)." + exit /b 1 +) +if errorlevel 1 ( + call :fail "Open WebUI startup timeout. Verify port conflicts/firewall and review %LOG_FILE%." + exit /b 1 +) + +call :log "Services ready. Opening browser..." +start "" "%OPEN_WEBUI_URL%" +call :log "Launcher completed successfully." +echo [OK] Z3R4H ready. +exit /b 0 + +:check_port_free +set "port=%~1" +set "service=%~2" +for /f "tokens=*" %%L in ('netstat -ano ^| findstr /R /C:":%port% .*LISTENING"') do ( + call :fail "Port %port% appears occupied before startup (%service%). Free the port or change launcher ports." + exit /b 1 +) +exit /b 0 + +:probe_url +set "probe_url=%~1" +powershell -NoProfile -ExecutionPolicy Bypass -Command "$u='%probe_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 exit /b 0 + +where curl.exe >nul 2>&1 +if errorlevel 1 exit /b 2 +curl.exe --max-time 2 --silent --output nul "%probe_url%" >nul 2>&1 +if errorlevel 1 exit /b 1 +exit /b 0 + +:wait_llama +set /a elapsed=0 +:wait_llama_loop +call :probe_url "http://%LLAMA_HOST%:%LLAMA_PORT%/health" +if not errorlevel 1 ( + call :log "llama.cpp is ready." + exit /b 0 +) +if errorlevel 2 exit /b 2 +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 +call :probe_url "%OPEN_WEBUI_URL%" +if not errorlevel 1 ( + call :log "Open WebUI is ready." + exit /b 0 +) +if errorlevel 2 exit /b 2 +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..872138b5aa0 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,29 @@ _history = structuredClone(_history); const responseMessageIds: Record = {}; - // If modelId is provided, use it, else use selected model + 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, + 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 +2178,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 +2814,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..2bc0adfc5dc --- /dev/null +++ b/src/lib/utils/z3r4hModeRouting.ts @@ -0,0 +1,49 @@ +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 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 && normalizedAvailableIds.includes(mappedId)) { + return { modelId: mappedId, reason: 'mode-mapped', missingMappedModel: false }; + } + + const selectedId = atSelectedModelId || normalizedSelectedIds.find((id) => !!id) || null; + if (selectedId && normalizedAvailableIds.includes(selectedId)) { + return { + modelId: selectedId, + reason: 'selected', + missingMappedModel: Boolean(mappedId && mappedId !== selectedId) + }; + } + + if (normalizedAvailableIds.length > 0) { + return { + modelId: normalizedAvailableIds[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", diff --git a/wrapper/.gitignore b/wrapper/.gitignore new file mode 100644 index 00000000000..7800585100d --- /dev/null +++ b/wrapper/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +.vs/ +*.user +*.suo diff --git a/wrapper/README.md b/wrapper/README.md new file mode 100644 index 00000000000..f4c4d3a455a --- /dev/null +++ b/wrapper/README.md @@ -0,0 +1,95 @@ +# Z3R4H Wrapper Scaffold (Task 19) + +This folder contains the minimal C#/.NET scaffold for the planned `.exe`-first wrapper path. + +## Scope in Task 19 +- Project/file structure +- Entrypoint wiring +- Config/path resolution scaffold +- Orchestration stubs +- Logging stubs +- BAT fallback hook scaffold + +## Not implemented in Task 19 +- Full runtime process orchestration +- Full readiness probing behavior +- Installer/signing/build automation +- Embedded UI shell + + +## Task 20 Milestone Behavior +- Validates core wrapper configuration and path assumptions. +- Uses structured exit codes for success/failure categories. +- Supports fallback modes: `auto`, `always`, `never`. +- Invokes BAT fallback in `auto` or `always` mode based on milestone rules. + +## Deferred After Task 20 +- Full runtime orchestration (llama/Open WebUI process control) +- Full readiness lifecycle +- Browser launch flow + + +## Task 21 Live Llama Orchestration Milestone +- Wrapper now starts llama runtime process from configured executable/model paths. +- Wrapper waits for llama readiness via `/health` polling. +- Structured exit codes now include llama launch/readiness outcomes. +- BAT fallback remains support/recovery via `auto`/`always`/`never` policy. + +## Deferred After Task 21 +- Open WebUI startup +- Browser launch +- Dual-service orchestration lifecycle + + +## Task 22 Dual-Service Readiness Milestone +- Preserves existing llama launch/readiness behavior. +- Starts Open WebUI process after llama readiness succeeds. +- Polls Open WebUI readiness endpoint until success/timeout. +- Returns structured dual-service exit outcomes. + +## Deferred After Task 22 +- Browser launch +- Embedded UI +- Advanced process supervision + + +## Task 23 Browser Launch Milestone +- Preserves existing llama + Open WebUI startup/readiness flow. +- Launches configured local UI URL in default browser only after dual-service readiness succeeds. +- Adds structured browser-launch outcome handling and logging. +- BAT fallback behavior remains unchanged for earlier startup failures only. + +## Deferred After Task 23 +- Embedded UI +- Advanced process supervision +- Installer/signing/build automation + + +## Task 24 Wrapper-First RC Validation Support +- RC validation now treats wrapper `.exe` execution as the primary clean-machine path. +- Operator workflow records wrapper stages in order: config -> llama -> webui -> browser-launch. +- BAT is captured as fallback/support evidence only when wrapper failure triggers handoff. + +## Wrapper-First Evidence Requirements +- Wrapper command/args, exit code, and terminal stage. +- Stage-specific console evidence for llama/webui/browser-launch outcomes. +- BAT handoff reason and BAT exit code when fallback occurs. + +## Deferred After Task 24 +- Embedded UI +- Advanced process supervision +- Installer/signing/build automation + + +## Task 25 Package-Root Resolution Blocker Fix +- Default package-root detection is now anchored to runtime package layout instead of fixed upward traversal. +- Wrapper now logs: + - resolved package root and resolution source (`arg` vs `auto`) + - resolved llama executable path + - resolved BAT fallback path +- Fallback and runtime paths are derived from resolved package root. + +### Quick verification (RC package) +Run: +- `Z3R4H.Wrapper.exe` +Expect config logs to show package root under your RC folder (not `C:\\`) and BAT path as `\\launch_z3r4h.bat`. diff --git a/wrapper/Z3R4H.Wrapper.sln b/wrapper/Z3R4H.Wrapper.sln new file mode 100644 index 00000000000..1abeab7098f --- /dev/null +++ b/wrapper/Z3R4H.Wrapper.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31912.275 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z3R4H.Wrapper", "src\Z3R4H.Wrapper\Z3R4H.Wrapper.csproj", "{6A4DF43D-36F8-4F7A-9D0A-5E7B58B63E95}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6A4DF43D-36F8-4F7A-9D0A-5E7B58B63E95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A4DF43D-36F8-4F7A-9D0A-5E7B58B63E95}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A4DF43D-36F8-4F7A-9D0A-5E7B58B63E95}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A4DF43D-36F8-4F7A-9D0A-5E7B58B63E95}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/wrapper/src/Z3R4H.Wrapper/App/StartupResult.cs b/wrapper/src/Z3R4H.Wrapper/App/StartupResult.cs new file mode 100644 index 00000000000..55a6b831bed --- /dev/null +++ b/wrapper/src/Z3R4H.Wrapper/App/StartupResult.cs @@ -0,0 +1,26 @@ +using Z3R4H.Wrapper.Logging; + +namespace Z3R4H.Wrapper.App; + +public enum WrapperExitCode +{ + Success = 0, + ConfigResolutionFailed = 10, + ConfigValidationFailed = 11, + UnsupportedMode = 12, + LlamaLaunchFailed = 13, + LlamaReadinessFailed = 14, + WebUiLaunchFailed = 15, + WebUiReadinessFailed = 16, + BrowserLaunchFailed = 17, + FallbackInvoked = 20, + FallbackInvocationFailed = 21, + UnhandledError = 99 +} + +public sealed record StartupResult( + bool Success, + int ExitCode, + string Message, + WrapperErrorCategory? ErrorCategory = null, + string? Stage = null); diff --git a/wrapper/src/Z3R4H.Wrapper/App/WrapperApp.cs b/wrapper/src/Z3R4H.Wrapper/App/WrapperApp.cs new file mode 100644 index 00000000000..91f37234151 --- /dev/null +++ b/wrapper/src/Z3R4H.Wrapper/App/WrapperApp.cs @@ -0,0 +1,80 @@ +using Z3R4H.Wrapper.Config; +using Z3R4H.Wrapper.Fallback; +using Z3R4H.Wrapper.Logging; +using Z3R4H.Wrapper.Orchestration; + +namespace Z3R4H.Wrapper.App; + +public sealed class WrapperApp( + WrapperLogger logger, + ConfigResolver configResolver, + RuntimeOrchestrator orchestrator, + BatFallback batFallback) +{ + public async Task RunAsync(string[] args, CancellationToken ct = default) + { + try + { + logger.Stage("startup", "Task 25 wrapper milestone starting"); + WrapperConfig config; + try + { + config = configResolver.Resolve(args); + } + catch (Exception ex) + { + logger.Error(WrapperErrorCategory.ConfigError, ex.Message); + return new StartupResult(false, (int)WrapperExitCode.ConfigResolutionFailed, ex.Message, WrapperErrorCategory.ConfigError, "config"); + } + + logger.Stage("config", $"Resolved package root ({config.PackageRootSource}): {config.PackageRoot}"); + logger.Info($"Resolved BAT path: {config.BatLauncherPath}"); + logger.Info($"Resolved llama path: {config.LlamaServerExePath}"); + logger.Info($"StartupMode={config.StartupMode}; FallbackMode={config.FallbackMode}; WebUI={config.OpenWebUiStartCommand}"); + + if (string.Equals(config.FallbackMode, "always", StringComparison.OrdinalIgnoreCase)) + { + var fallbackAlways = batFallback.InvokeFallback(config, "Fallback mode is set to always"); + return fallbackAlways.Success + ? new StartupResult(true, (int)WrapperExitCode.FallbackInvoked, fallbackAlways.Message, Stage: "fallback") + : new StartupResult(false, (int)WrapperExitCode.FallbackInvocationFailed, fallbackAlways.Message, WrapperErrorCategory.FallbackInvocation, "fallback"); + } + + var orchestrationResult = await orchestrator.StartAsync(config, ct); + if (!orchestrationResult.Success) + { + logger.Error(orchestrationResult.Category ?? WrapperErrorCategory.StartupFailure, orchestrationResult.Message); + + if (string.Equals(config.FallbackMode, "auto", StringComparison.OrdinalIgnoreCase) + && !string.Equals(orchestrationResult.Stage, "browser-launch", StringComparison.OrdinalIgnoreCase)) + { + var fallback = batFallback.InvokeFallback(config, $"{orchestrationResult.Stage}: {orchestrationResult.Message}"); + return fallback.Success + ? new StartupResult(true, (int)WrapperExitCode.FallbackInvoked, fallback.Message, Stage: "fallback") + : new StartupResult(false, (int)WrapperExitCode.FallbackInvocationFailed, fallback.Message, WrapperErrorCategory.FallbackInvocation, "fallback"); + } + + var exitCode = orchestrationResult.Stage switch + { + "llama-launch" => (int)WrapperExitCode.LlamaLaunchFailed, + "llama-readiness" => (int)WrapperExitCode.LlamaReadinessFailed, + "webui-launch" => (int)WrapperExitCode.WebUiLaunchFailed, + "webui-readiness" => (int)WrapperExitCode.WebUiReadinessFailed, + "browser-launch" => (int)WrapperExitCode.BrowserLaunchFailed, + _ when orchestrationResult.Category == WrapperErrorCategory.ModeError => (int)WrapperExitCode.UnsupportedMode, + _ => (int)WrapperExitCode.ConfigValidationFailed + }; + + return new StartupResult(false, exitCode, orchestrationResult.Message, orchestrationResult.Category, orchestrationResult.Stage); + } + + logger.Stage("startup", "Task 25 milestone completed (dual-service readiness + browser launch request)"); + return new StartupResult(true, (int)WrapperExitCode.Success, orchestrationResult.Message, Stage: orchestrationResult.Stage); + } + catch (Exception ex) + { + logger.Error(WrapperErrorCategory.UnhandledError, ex.Message); + return new StartupResult(false, (int)WrapperExitCode.UnhandledError, ex.Message, WrapperErrorCategory.UnhandledError, "unhandled"); + } + } +} diff --git a/wrapper/src/Z3R4H.Wrapper/Config/ConfigResolver.cs b/wrapper/src/Z3R4H.Wrapper/Config/ConfigResolver.cs new file mode 100644 index 00000000000..483c3211410 --- /dev/null +++ b/wrapper/src/Z3R4H.Wrapper/Config/ConfigResolver.cs @@ -0,0 +1,116 @@ +using System.Reflection; + +namespace Z3R4H.Wrapper.Config; + +public sealed class ConfigResolver +{ + public WrapperConfig Resolve(string[] args) + { + var values = ParseArgs(args); + var exeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? AppContext.BaseDirectory; + var hasPackageRootOverride = values.TryGetValue("package-root", out var configuredRoot); + var packageRoot = hasPackageRootOverride + ? Path.GetFullPath(configuredRoot!) + : ResolvePackageRootFromExe(exeDir); + var packageRootSource = hasPackageRootOverride ? "arg" : "auto"; + + var startupMode = values.GetValueOrDefault("startup-mode", "exe-first"); + var fallbackMode = values.GetValueOrDefault("fallback", "auto"); + + var llamaExe = values.GetValueOrDefault( + "llama-exe", + Path.Combine(packageRoot, "runtime", "llama.cpp", "llama-server.exe")); + var llamaModel = values.GetValueOrDefault( + "llama-model", + Path.Combine(packageRoot, "models", "model.gguf")); + + var llamaHost = values.GetValueOrDefault("llama-host", "127.0.0.1"); + var llamaPort = ParseInt(values.GetValueOrDefault("llama-port", "11434"), 11434); + var llamaTimeout = ParseInt(values.GetValueOrDefault("llama-timeout", "120"), 120); + var llamaPoll = ParseInt(values.GetValueOrDefault("llama-poll", "2"), 2); + + var webuiCmd = values.GetValueOrDefault("webui-cmd", "open-webui serve"); + var webuiUrl = values.GetValueOrDefault("webui-url", "http://localhost:8080"); + var webuiTimeout = ParseInt(values.GetValueOrDefault("webui-timeout", "180"), 180); + var webuiPoll = ParseInt(values.GetValueOrDefault("webui-poll", "2"), 2); + + return new WrapperConfig + { + PackageRoot = packageRoot, + PackageRootSource = packageRootSource, + BatLauncherPath = Path.Combine(packageRoot, "launch_z3r4h.bat"), + LogFilePath = Path.Combine(packageRoot, "z3r4h_launcher.log"), + LlamaServerExePath = llamaExe, + LlamaModelPath = llamaModel, + LlamaHost = llamaHost, + LlamaPort = llamaPort, + LlamaReadyTimeoutSeconds = llamaTimeout, + LlamaReadyPollSeconds = llamaPoll, + OpenWebUiStartCommand = webuiCmd, + OpenWebUiUrl = webuiUrl, + OpenWebUiReadyTimeoutSeconds = webuiTimeout, + OpenWebUiReadyPollSeconds = webuiPoll, + StartupMode = startupMode, + FallbackMode = fallbackMode + }; + } + + private static string ResolvePackageRootFromExe(string exeDir) + { + var current = new DirectoryInfo(Path.GetFullPath(exeDir)); + + if (LooksLikePackageRoot(current.FullName)) + { + return current.FullName; + } + + // Published RC layout is expected as \\wrapper\\Z3R4H.Wrapper.exe + if (string.Equals(current.Name, "wrapper", StringComparison.OrdinalIgnoreCase) + && current.Parent is not null + && LooksLikePackageRoot(current.Parent.FullName)) + { + return current.Parent.FullName; + } + + // Defensive upward search for launch marker if layout differs. + var probe = current; + for (var i = 0; i < 6 && probe is not null; i++) + { + if (LooksLikePackageRoot(probe.FullName)) + { + return probe.FullName; + } + probe = probe.Parent; + } + + // Last-resort: stay anchored to executable directory rather than filesystem root. + return current.FullName; + } + + private static bool LooksLikePackageRoot(string directory) + { + return File.Exists(Path.Combine(directory, "launch_z3r4h.bat")); + } + + private static int ParseInt(string value, int fallback) + => int.TryParse(value, out var parsed) ? parsed : fallback; + + private static Dictionary ParseArgs(string[] args) + { + var dict = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var arg in args) + { + if (!arg.StartsWith("--", StringComparison.Ordinal) || !arg.Contains('=')) + { + continue; + } + + var parts = arg[2..].Split('=', 2, StringSplitOptions.TrimEntries); + if (parts.Length == 2) + { + dict[parts[0]] = parts[1]; + } + } + return dict; + } +} diff --git a/wrapper/src/Z3R4H.Wrapper/Config/WrapperConfig.cs b/wrapper/src/Z3R4H.Wrapper/Config/WrapperConfig.cs new file mode 100644 index 00000000000..2764ed1056d --- /dev/null +++ b/wrapper/src/Z3R4H.Wrapper/Config/WrapperConfig.cs @@ -0,0 +1,24 @@ +namespace Z3R4H.Wrapper.Config; + +public sealed class WrapperConfig +{ + public required string PackageRoot { get; init; } + public string PackageRootSource { get; init; } = "auto"; + public required string BatLauncherPath { get; init; } + public required string LogFilePath { get; init; } + + public required string LlamaServerExePath { get; init; } + public required string LlamaModelPath { get; init; } + public string LlamaHost { get; init; } = "127.0.0.1"; + public int LlamaPort { get; init; } = 11434; + public int LlamaReadyTimeoutSeconds { get; init; } = 120; + public int LlamaReadyPollSeconds { get; init; } = 2; + + public string OpenWebUiStartCommand { get; init; } = "open-webui serve"; + public string OpenWebUiUrl { get; init; } = "http://localhost:8080"; + public int OpenWebUiReadyTimeoutSeconds { get; init; } = 180; + public int OpenWebUiReadyPollSeconds { get; init; } = 2; + + public string StartupMode { get; init; } = "exe-first"; + public string FallbackMode { get; init; } = "auto"; // auto | always | never +} diff --git a/wrapper/src/Z3R4H.Wrapper/Fallback/BatFallback.cs b/wrapper/src/Z3R4H.Wrapper/Fallback/BatFallback.cs new file mode 100644 index 00000000000..49c77834560 --- /dev/null +++ b/wrapper/src/Z3R4H.Wrapper/Fallback/BatFallback.cs @@ -0,0 +1,45 @@ +using System.Diagnostics; +using Z3R4H.Wrapper.Config; +using Z3R4H.Wrapper.Logging; + +namespace Z3R4H.Wrapper.Fallback; + +public sealed class BatFallback(WrapperLogger logger) +{ + public (bool Success, int ExitCode, string Message) InvokeFallback(WrapperConfig config, string reason) + { + logger.Error( + WrapperErrorCategory.FallbackInvocation, + $"Invoking BAT fallback because: {reason}. Target: {config.BatLauncherPath}"); + + if (!File.Exists(config.BatLauncherPath)) + { + return (false, -1, $"BAT fallback path not found: {config.BatLauncherPath}"); + } + + try + { + var psi = new ProcessStartInfo + { + FileName = "cmd.exe", + Arguments = $"/c \"\"{config.BatLauncherPath}\"\"", + WorkingDirectory = config.PackageRoot, + UseShellExecute = false + }; + + using var process = Process.Start(psi); + if (process is null) + { + return (false, -2, "Failed to start BAT fallback process."); + } + + process.WaitForExit(); + logger.Info($"BAT fallback exited with code {process.ExitCode}"); + return (true, process.ExitCode, "BAT fallback completed."); + } + catch (Exception ex) + { + return (false, -3, $"Exception while invoking BAT fallback: {ex.Message}"); + } + } +} diff --git a/wrapper/src/Z3R4H.Wrapper/Health/ReadinessProbe.cs b/wrapper/src/Z3R4H.Wrapper/Health/ReadinessProbe.cs new file mode 100644 index 00000000000..b09dfdd3bf3 --- /dev/null +++ b/wrapper/src/Z3R4H.Wrapper/Health/ReadinessProbe.cs @@ -0,0 +1,44 @@ +using Z3R4H.Wrapper.Logging; + +namespace Z3R4H.Wrapper.Health; + +public sealed class ReadinessProbe(WrapperLogger logger) +{ + private static readonly HttpClient Client = new(); + + public Task<(bool Success, string Message)> WaitForLlamaReadyAsync(string endpoint, int timeoutSeconds, int pollSeconds, CancellationToken ct = default) + => WaitForEndpointReadyAsync(endpoint, timeoutSeconds, pollSeconds, "llama", ct); + + public Task<(bool Success, string Message)> WaitForWebUiReadyAsync(string endpoint, int timeoutSeconds, int pollSeconds, CancellationToken ct = default) + => WaitForEndpointReadyAsync(endpoint, timeoutSeconds, pollSeconds, "open-webui", ct); + + private async Task<(bool Success, string Message)> WaitForEndpointReadyAsync(string endpoint, int timeoutSeconds, int pollSeconds, string label, CancellationToken ct) + { + var timeout = TimeSpan.FromSeconds(Math.Max(1, timeoutSeconds)); + var poll = TimeSpan.FromSeconds(Math.Max(1, pollSeconds)); + var started = DateTime.UtcNow; + + while (DateTime.UtcNow - started < timeout) + { + ct.ThrowIfCancellationRequested(); + try + { + using var req = new HttpRequestMessage(HttpMethod.Get, endpoint); + using var res = await Client.SendAsync(req, ct); + if ((int)res.StatusCode >= 200 && (int)res.StatusCode < 500) + { + return (true, $"{label} readiness endpoint reachable: {endpoint}"); + } + } + catch + { + // Continue polling until timeout. + } + + logger.Stage("health", $"Waiting for {label} readiness at {endpoint}..."); + await Task.Delay(poll, ct); + } + + return (false, $"Timed out waiting for {label} readiness at {endpoint}"); + } +} diff --git a/wrapper/src/Z3R4H.Wrapper/Logging/WrapperLogger.cs b/wrapper/src/Z3R4H.Wrapper/Logging/WrapperLogger.cs new file mode 100644 index 00000000000..66669042c96 --- /dev/null +++ b/wrapper/src/Z3R4H.Wrapper/Logging/WrapperLogger.cs @@ -0,0 +1,34 @@ +namespace Z3R4H.Wrapper.Logging; + +public enum WrapperErrorCategory +{ + ConfigError, + PathError, + ModeError, + PortConflict, + ProbeFailure, + Timeout, + StartupFailure, + FallbackInvocation, + UnhandledError +} + +public sealed class WrapperLogger +{ + public void Stage(string stage, string message) + { + Console.WriteLine($"[{Timestamp()}] [stage:{stage}] {message}"); + } + + public void Info(string message) + { + Console.WriteLine($"[{Timestamp()}] [info] {message}"); + } + + public void Error(WrapperErrorCategory category, string message) + { + Console.Error.WriteLine($"[{Timestamp()}] [error:{category}] {message}"); + } + + private static string Timestamp() => DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); +} diff --git a/wrapper/src/Z3R4H.Wrapper/Orchestration/RuntimeOrchestrator.cs b/wrapper/src/Z3R4H.Wrapper/Orchestration/RuntimeOrchestrator.cs new file mode 100644 index 00000000000..8a775bf291a --- /dev/null +++ b/wrapper/src/Z3R4H.Wrapper/Orchestration/RuntimeOrchestrator.cs @@ -0,0 +1,178 @@ +using System.Diagnostics; +using Z3R4H.Wrapper.Config; +using Z3R4H.Wrapper.Health; +using Z3R4H.Wrapper.Logging; + +namespace Z3R4H.Wrapper.Orchestration; + +public sealed class RuntimeOrchestrator(WrapperLogger logger, ReadinessProbe readinessProbe) +{ + public async Task<(bool Success, WrapperErrorCategory? Category, string Stage, string Message)> StartAsync(WrapperConfig config, CancellationToken ct = default) + { + logger.Stage("orchestration", "Task 22 milestone: dual-service startup (llama + open-webui readiness)"); + + var validation = ValidateConfig(config); + if (!validation.Success) + { + return validation; + } + + var llamaStart = StartLlama(config); + if (!llamaStart.Success) + { + return llamaStart; + } + + var llamaEndpoint = $"http://{config.LlamaHost}:{config.LlamaPort}/health"; + var llamaReady = await readinessProbe.WaitForLlamaReadyAsync(llamaEndpoint, config.LlamaReadyTimeoutSeconds, config.LlamaReadyPollSeconds, ct); + if (!llamaReady.Success) + { + return (false, WrapperErrorCategory.Timeout, "llama-readiness", llamaReady.Message); + } + + var webuiStart = StartWebUi(config); + if (!webuiStart.Success) + { + return webuiStart; + } + + var webuiReady = await readinessProbe.WaitForWebUiReadyAsync(config.OpenWebUiUrl, config.OpenWebUiReadyTimeoutSeconds, config.OpenWebUiReadyPollSeconds, ct); + if (!webuiReady.Success) + { + return (false, WrapperErrorCategory.Timeout, "webui-readiness", webuiReady.Message); + } + + var browserLaunch = LaunchBrowser(config.OpenWebUiUrl); + if (!browserLaunch.Success) + { + return browserLaunch; + } + + return (true, null, "browser-launch", "llama and open-webui startup/readiness succeeded; browser launch requested."); + } + + private (bool Success, WrapperErrorCategory? Category, string Stage, string Message) ValidateConfig(WrapperConfig config) + { + if (!Directory.Exists(config.PackageRoot)) + { + return (false, WrapperErrorCategory.PathError, "config", $"Package root not found: {config.PackageRoot}"); + } + + if (!File.Exists(config.BatLauncherPath)) + { + return (false, WrapperErrorCategory.PathError, "config", $"BAT fallback launcher not found: {config.BatLauncherPath}"); + } + + if (!File.Exists(config.LlamaServerExePath)) + { + return (false, WrapperErrorCategory.PathError, "config", $"llama executable not found: {config.LlamaServerExePath}"); + } + + if (!File.Exists(config.LlamaModelPath)) + { + return (false, WrapperErrorCategory.PathError, "config", $"llama model not found: {config.LlamaModelPath}"); + } + + if (!string.Equals(config.StartupMode, "exe-first", StringComparison.OrdinalIgnoreCase)) + { + return (false, WrapperErrorCategory.ModeError, "config", $"Unsupported startup mode for milestone: {config.StartupMode}"); + } + + var fallbackModes = new[] { "auto", "always", "never" }; + if (!fallbackModes.Contains(config.FallbackMode, StringComparer.OrdinalIgnoreCase)) + { + return (false, WrapperErrorCategory.ConfigError, "config", $"Invalid fallback mode: {config.FallbackMode}"); + } + + if (string.IsNullOrWhiteSpace(config.OpenWebUiStartCommand)) + { + return (false, WrapperErrorCategory.ConfigError, "config", "Open WebUI start command is empty."); + } + + if (string.IsNullOrWhiteSpace(config.OpenWebUiUrl)) + { + return (false, WrapperErrorCategory.ConfigError, "config", "Open WebUI URL is empty."); + } + + return (true, null, "config", "Configuration validation passed."); + } + + private (bool Success, WrapperErrorCategory? Category, string Stage, string Message) StartLlama(WrapperConfig config) + { + try + { + var psi = new ProcessStartInfo + { + FileName = config.LlamaServerExePath, + Arguments = $"-m \"{config.LlamaModelPath}\" --host {config.LlamaHost} --port {config.LlamaPort}", + WorkingDirectory = Path.GetDirectoryName(config.LlamaServerExePath) ?? config.PackageRoot, + UseShellExecute = false, + CreateNoWindow = true + }; + var process = Process.Start(psi); + if (process is null) + { + return (false, WrapperErrorCategory.StartupFailure, "llama-launch", "Failed to start llama process."); + } + + logger.Stage("orchestration", $"llama process started (pid={process.Id})"); + return (true, null, "llama-launch", "llama process started."); + } + catch (Exception ex) + { + return (false, WrapperErrorCategory.StartupFailure, "llama-launch", $"Exception starting llama: {ex.Message}"); + } + } + + private (bool Success, WrapperErrorCategory? Category, string Stage, string Message) StartWebUi(WrapperConfig config) + { + try + { + var psi = new ProcessStartInfo + { + FileName = "cmd.exe", + Arguments = $"/c {config.OpenWebUiStartCommand}", + WorkingDirectory = config.PackageRoot, + UseShellExecute = false, + CreateNoWindow = true + }; + var process = Process.Start(psi); + if (process is null) + { + return (false, WrapperErrorCategory.StartupFailure, "webui-launch", "Failed to start Open WebUI process."); + } + + logger.Stage("orchestration", $"open-webui process started (pid={process.Id})"); + return (true, null, "webui-launch", "Open WebUI process started."); + } + catch (Exception ex) + { + return (false, WrapperErrorCategory.StartupFailure, "webui-launch", $"Exception starting Open WebUI: {ex.Message}"); + } + } + + private (bool Success, WrapperErrorCategory? Category, string Stage, string Message) LaunchBrowser(string url) + { + try + { + var psi = new ProcessStartInfo + { + FileName = url, + UseShellExecute = true + }; + + var process = Process.Start(psi); + if (process is null) + { + return (false, WrapperErrorCategory.StartupFailure, "browser-launch", $"Failed to launch default browser for URL: {url}"); + } + + logger.Stage("orchestration", $"browser launch requested for {url}"); + return (true, null, "browser-launch", "Browser launch requested."); + } + catch (Exception ex) + { + return (false, WrapperErrorCategory.StartupFailure, "browser-launch", $"Exception launching browser: {ex.Message}"); + } + } +} diff --git a/wrapper/src/Z3R4H.Wrapper/Program.cs b/wrapper/src/Z3R4H.Wrapper/Program.cs new file mode 100644 index 00000000000..eb0d820691d --- /dev/null +++ b/wrapper/src/Z3R4H.Wrapper/Program.cs @@ -0,0 +1,26 @@ +using Z3R4H.Wrapper.App; +using Z3R4H.Wrapper.Config; +using Z3R4H.Wrapper.Fallback; +using Z3R4H.Wrapper.Health; +using Z3R4H.Wrapper.Logging; +using Z3R4H.Wrapper.Orchestration; + +var logger = new WrapperLogger(); +var resolver = new ConfigResolver(); +var probe = new ReadinessProbe(logger); +var orchestrator = new RuntimeOrchestrator(logger, probe); +var fallback = new BatFallback(logger); + +var app = new WrapperApp(logger, resolver, orchestrator, fallback); +var result = await app.RunAsync(args); + +if (!result.Success) +{ + logger.Error(result.ErrorCategory ?? WrapperErrorCategory.StartupFailure, $"Stage={result.Stage}; ExitCode={result.ExitCode}; {result.Message}"); +} +else +{ + logger.Info($"Stage={result.Stage}; ExitCode={result.ExitCode}; {result.Message}"); +} + +return result.ExitCode; diff --git a/wrapper/src/Z3R4H.Wrapper/Z3R4H.Wrapper.csproj b/wrapper/src/Z3R4H.Wrapper/Z3R4H.Wrapper.csproj new file mode 100644 index 00000000000..8f3e7c7878d --- /dev/null +++ b/wrapper/src/Z3R4H.Wrapper/Z3R4H.Wrapper.csproj @@ -0,0 +1,10 @@ + + + Exe + net8.0-windows + enable + enable + Z3R4H.Wrapper + Z3R4H.Wrapper + +