Skip to content

feat(windows): native Portal app with CPU/CUDA chat and documents - #7938

Closed
tang-vu wants to merge 34 commits into
Osmantic:mainfrom
tang-vu:feat/windows-native-desktop-preview-20261022
Closed

tang-vu wants to merge 34 commits into
Osmantic:mainfrom
tang-vu:feat/windows-native-desktop-preview-20261022

Conversation

@tang-vu

@tang-vu tang-vu commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Install ODS as a per-user Windows application, choose CPU (default) or NVIDIA CUDA (opt-in), open the existing Portal, chat locally, and create a verified Markdown file through the native Windows Save picker.

Closes #7937. Refs #7968.

ODS runs without Docker, WSL, Git, Node, Python or a terminal. The installer includes the static CPU engine and acquires the pinned 2B model on first use. CUDA acquires two checked official runtime archives after hardware qualification. This is an unsigned development preview covering text chat and one bounded document tool; full agents, voice, images, extensions and model switching remain separate work.

Watch the actual two-minute CUDA demo. Captions disclose automated live QA, cached runtime/model, recorded cuts and cropped picker navigation.

Implementation

  • Per-user Setup, Start Menu/Finish launch, HKCU registration, repair, upgrades and owned uninstall with model/history retention. Version 0.3 preserves text/document histories and numeric downgrade protection.
  • The same 2B model and 4K context use an app-owned Windows Job. Runtime and model SHA checks precede child/session-key creation. CUDA readiness requires complete actual GPU offload. Saved backend choice, cancellation, explicit CPU recovery and exact adapter matching are covered.
  • Source-built CPU runtime requires no separate MSVC/OpenMP installation. Optional CUDA needs the MSVC v14.44+ x64 runtime and a compatible NVIDIA driver (551.78+); the pinned CUDA 12.4 engine excludes RTX 50-series GPUs. Actual GPU qualification uses RTX 3060 12 GB.
  • Existing Portal composer, streaming, Stop/continue, saved history and document download remain connected to the private native adapter. A completed, hash-verified receipt authorizes the Windows picker. Cancel and conversation JSON export retain their existing contracts.
  • Microsoft WebView2 installation requires explicit owner consent, then uses the documented /silent /install flags. Minimum-version verification remains authoritative; an older shared runtime gets actionable device-administrator recovery guidance.
  • IronicRayquaza's review remains incorporated: recoverable storage limits, exact-token context, stall-only acquisition, cached-launch integrity, seed repair, actionable reflection errors, copied QA-kit execution and save/export regressions.

AI Assistance

I lead this contribution, its product direction, scope and quality decisions, collaborating with Codex on implementation, analysis, automated tests and review. The validation records identify agent-executed commands.

Release Lane

  • Mainline change targeting main; opt-in native development preview.

Changed Surface

  • Dashboard/native UI, private API/auth, installer/lifecycle, model routing/acquisition, build dependencies, Windows CI and documentation.

Risk And Validation

High risk. Current head: ddc453667edae3ffcefbfadb787d18e2a9ffeb5d; current upstream main merged normally. The final-head native Windows workflow succeeded. Checks currently show 74 completed and one inconsistent status: pixel-advice-host-stdlib (3.12) reports in_progress while its conclusion, completed timestamp and parent workflow report success. This status mismatch remains an explicit external gate.

Boundary Recorded result
Full native suite 286 desktop + 27 acquisition + 38 launch checks pass locally
Real NVIDIA Portal on exact CI package 9 chat/Stop/context/recovery + 11 document/Save/Cancel checks pass; 526 saved bytes verified by SHA-256
Clean Windows 10 Sandbox Actual Setup, first model download, 9 CPU chat + 11 document/save checks pass under a manually filtered medium token
Real installer prerequisite fixtures 17 pass, including exact silent flags, refusal/recovery and nonzero publisher exit with a verified usable runtime
Supporting controls 28 native frontend, 12 canonical-pin, 19 copied clean-user guard, 11 packaged-EXE checks pass
Source checks Commit identities, secret scan and diff checks pass; the new fixture's 15 PSSA warnings were reproduced and repaired without changing analyzer rules

The clean guest was Windows 10 Enterprise x64 build 19041. ODS/model/chat/document work used the same WDAG identity with a manually constructed non-elevated medium token, Administrators deny-only and a private current-user/SYSTEM default DACL. Microsoft WebView2 was prepared separately by the elevated guest parent, upgrading 141.0.3537.71 to 156.0.4314.42. This does not qualify a separately provisioned ordinary account or non-elevated Microsoft servicing. Git/Node/Docker/Python were absent; the inbox WSL command was present and optional-feature inventory was unavailable. No host model cache was mapped.

Exact local Setup SHA-256: db67a64152f4bb8b3eb123a17be2819bdc3c891941101be2b16d149b5972a8aa. It uses tested application source 95de936757f58 and installer source 5edf917986f2; production application/Portal source equivalence was verified when porting into this PR. Builder defaults now match the tested explicit 0.3 version. New CI rebuilds have their own receipts.

The downloaded final-head CI artifact was independently verified, then exercised on Windows 10 Pro 19045 / RTX 3060 12 GB / driver 616.92. Setup SHA-256: 2ce7bd85de2434c2434be57f80621f4f029492a60159c374b38d3e0fb8ed06bb; CPU engine: bf6368d12ce312fd31867463348eed9226af96becd9430e8ef88c7674e52d9e3. The exact CPU engine completed real math, rejected a wrong key on protected chat with 401 and cleaned its owned child/session. The unmodified CI application then passed the complete GPU 9/11 Portal checks, including saving 526 bytes with SHA-256 1ac3de761ed14adb31844e931b89c0fc580c77fd50a2a78632629fe5daaffdf4. All 62 portable files remained unchanged. This host qualification is separate from the local Setup's clean-guest run.

Actual SDK probes reproduced missing device stdout in 4/16 launches with early HasExited polling; waiting for the retained kernel process handle yielded complete output in 16/16. Independent agent review checked the Windows completion contract. Failed attempts and private video-wrapper path discrepancies are retained separately from product regressions.

Operational Change Check

  • Scoped CPU/GPU application, installer, model and actual clean-guest evidence recorded in VALIDATION.md.
  • Deferred: Windows 11, a separate ordinary account, shared Microsoft servicing without elevation, wider hardware/accessibility, full ODS agents/harness, signed website distribution and authenticated updates/rollback. Maintainer review and release acceptance remain separate.

Scope And Review Package

This updates existing #7938. The separate #8014 supplies the public CLI's native CUDA route; its CLI/lifecycle implementation and synthetic integration merge were excluded from this PR. Only the identical shared NVIDIA pin data is carried here. Existing PR and maintainer commit attribution is preserved.

The Windows native workflow now includes optional CUDA metadata in review artifacts while CPU remains the default. Manual dispatch can still request a CPU-only package. Close ODS before repair/removal; uninstall retains its private model/history data.

Add an opt-in WPF app with checked first-run runtime/model downloads, authenticated loopback chat and atomic Windows Job ownership. Keep the preview separate from the existing ODS installer and document deferred full-product and release qualification.
@tang-vu tang-vu changed the title feat(windows): add an opt-in native desktop chat preview feat(windows): run Portal text chat in a native desktop preview Oct 22, 2026
@tang-vu tang-vu changed the title feat(windows): run Portal text chat in a native desktop preview feat(windows): install native Portal CPU chat without Docker or WSL Oct 22, 2026
@tang-vu

tang-vu commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

@Lightheartdevs This follows the native Windows direction you outlined: a per-user installer, the existing Portal UI, and local CPU inference without Docker or WSL. The CI artifact has been installed and tested with real model inference on Windows.

I’d appreciate your feedback on this foundation for the Windows desktop effort. This is currently a CPU text-chat preview; clean-machine qualification, signing, and full agent support remain open.

@IronicRayquaza

Copy link
Copy Markdown
Contributor

Hey @tang-vu, nice work on this. The Job-object ownership and keeping the model key out of JavaScript are really solid, and every dashboard change stays behind nativeChat, so the normal Portal is untouched.

I reviewed head d4d7765 from a Windows 11 machine. This was a code review plus a few targeted checks; I haven't run the installer artifact yet. Here are some things I think would trip up a non-technical owner:

1. Chat stops working after ~256 replies, and the error points to the wrong fix
PortalState.Save (PortalState.cs:94) writes one receipt per reply and refuses new ones at 256. Nothing ever prunes completed receipts, so the cap covers the app's whole life across all chats. The IOException isn't caught in HandleAsync (only ArgumentException is), so it ends up in PortalHost.cs:135-139, which tells the owner to "Restart local AI to recover". Restarting doesn't help. Deleting a chat only helps partly, because each deletion adds a .deleted marker that also counts. If the folder ever goes over 256 files (a leftover .partial, or a deleted chat with no receipts), the constructor check at PortalState.cs:56 throws and Portal can't open at all.

2. Long chats fail on every new message
llama-server runs with --ctx-size 4096 (Runtime.cs:356), but Portal's boundedHistory sends up to 48 earlier messages / 256 KB. With answers up to 512 tokens, a chat passes 4096 tokens after roughly 7–10 turns. From then on, every message in that chat comes back as response_incomplete. The standalone WPF chat already guards this with the 8-turn limit (Runtime.cs:413), but the Portal path has no equivalent, and /compact is blocked in native mode. (I worked this out from the code; I haven't confirmed it live yet.)

3. Model download can't finish on slower connections
ModelDownload.EnsureAsync has a hard 30-minute limit (Runtime.cs:117) and no resume, and it deletes the partial file on failure (:172). For the 1,280,835,840-byte model, that needs ≥ 5.7 Mbit/s sustained. Anything slower fails every time, restarting from 0%, and the message shown is "Check your connection or try a shorter message" (App.cs:230). Resuming with an HTTP Range request, or a stall-only timeout, would fix it.

4. Every launch hashes the 1.28 GB model twice
App.cs:165 → EnsureAsync → MatchesAsync hashes it, then LocalRuntime.StartAsync (Runtime.cs:331) hashes it again. The engine is hashed twice too (RuntimeDownload.cs:22 and Runtime.cs:324-330), and it all repeats on every "Restart local AI". SHA256.Create() is SHA256Managed on .NET Framework; I measured ~346 MB/s on this Windows 11 machine before any disk I/O, so on a laptop with a slower disk this probably accounts for a good part of the cached startup time.

5. Generic error when Portal fails to open
PortalWindow is created through Activator.CreateInstance (App.cs:176), so any constructor failure reaches HandleFailure wrapped in a TargetInvocationException. The owner sees "Exception has been thrown by the target of an invocation." Unwrapping InnerException would show the real message.

Smaller things

  • CI cost: the new steps are inside lint-powershell.yml, which runs on every PR with no path filter. The Windows job went from ~9.6 min to ~16.5 min. Each run also downloads ~280 MB of build tools and compiles llama.cpp from source, which adds new ways for unrelated PRs to fail. A separate workflow limited to desktop/windows/** might be better.
  • WebView2 versions disagree: the installer requires WebView2 ≥ 155 (installer.iss:147), but the app accepts any version (PortalHost.cs:26). A machine whose WebView2 updates are held back below 155 would fail Setup even though the runtime is installed.
  • Uninstall leaves files behind: the 1.28 GB model stays in %LOCALAPPDATA%\ODS Desktop Preview with no option to remove it. I know that's deliberate, but an uninstall checkbox would help owners who don't know it's there.

Happy to help test fixes on Windows 11, since that's still listed as an open gate in VALIDATION.md.

@tang-vu

tang-vu commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor Author

@IronicRayquaza Thanks for the concrete review and the offer to test on Windows 11. I addressed the reliability findings and carried them through actual native document and clean-Windows flows. Current head: b718cdfd2ed8ec1bf5acf7b7268396c3d35e1018.

  1. Lifetime storage: existing/legacy stores remain openable, recoverable and deletable above the admission budget. New results have a 4,096-result/64 MiB budget; deletion markers use separate accounting. HTTP 507 explains recovery and preserves the draft. Saved results/tombstones are never silently evicted.
  2. Long conversations: shipped b9014 /apply-template and /tokenize contracts select complete recent turns while preserving full saved history and reserving output. Oversized latest prompts refuse before inference with actionable guidance. Real model checks cover over-context history, refusal and a successful next request; document mode budgets both rounds and the actual tool schema/result.
  3. Slow acquisition: stall-only policy, with 30-second inactivity bounds on headers/network reads and no total-duration limit. Tests cover continuing progress, stalls, cancellation, checksum refusal and preserved old cache. Retry restarts the partial transfer; HTTP Range resume remains unimplemented.
  4. Startup hashing: a cached candidate is explicitly unverified until one CNG launch gate checks its pins before child/key creation. Same-size corruption still refuses; only typed model-integrity failures allow repair. Reopening prefers a repaired private cache while preserving a corrupt installed seed.
  5. Reflection errors: the UI unwraps nested TargetInvocationException instances and reports the underlying recovery text. Actual WPF checks cover it.
  6. CI: heavy engine/package/lifecycle work is in its own complete path-filtered workflow. Copied handoff drivers execute before publication. New pure-console regressions exercise the actual driver on PowerShell 5.1/7, including simultaneous large UTF-8 streams, exact failure status and a lost-stderr negative control. Named diagnostics survive failed CI; incomplete installers are not published.
  7. WebView2: Setup, preflight and selected environment use 154.0.4258.31, the SDK compatibility minimum. The real clean guest installed and used 156.0.4314.42.
  8. Uninstall: the real notice names the retained data folder and 1.28 GB model; cancelling preserves the installation. An erase-data checkbox remains separate because deletion needs scoped ownership/recovery behavior. Shared WebView2 remains retained.

The explicit document mode uses the existing Portal card and a genuine native Save/Cancel picker. Exact Markdown bytes/hash and small/large JSON conversation exports are protected, including choices held beyond Blob revocation and recovery without replay. A real high-core model timeout also led to bounded eight-worker generation/batch budgets, preserving the lower-core rule, auth, integrity, context/output limits and deadlines.

The complete native workflow on code head a9d9267f6 passed 281 native, 11 packaged-EXE, 11 Portal, 23 installer + 2 history, 14 prerequisite, 31 copied document/JSON/picker, and 2 startup checks, plus 7 bootstrap and 6 driver cases in each PowerShell version. Final-head CI passed 75/75 checks after the documentation/screenshot update; there are no pending/failed checks or conflicts at this readback.

The exact final-head Setup, SHA-256 a6185d424ae23101fa2869054904d98fff2ccd2133bfb25e899aa25727d5ffeb, passed a fresh Windows 10 Sandbox with the exact same copied QA inputs published by CI: real missing-WebView2 acquisition, per-user Setup/Start Menu/Finish launch, model download, 9 chat and 11 document/save checks. The actual token was elevated; Git/Node/Docker/Python were absent and no host model cache was mapped. The 468-byte Markdown matched SHA-256 62cd654a5498f30f4f8ebd88e67445e93b767df2783e770a5ce921a39e4bf575 after actual Save; Cancel wrote nothing. Both native runner receipts have exit zero and empty stderr. The final host observer and independent evidence audit both passed; all eleven output files and frozen inputs were verified.

The first bootstrap failure and later failed model-QA attempt remain recorded. The corrected runner now matches App.Main's TLS policy and retains its real output/error streams; those earlier attempts are not counted as model passes. Windows 11/non-elevated fresh use, offline/proxy/Microsoft failure cases, wider UX and release acceptance remain separate gates. Details and genuine clean-guest screenshots are in VALIDATION.md.

@tang-vu tang-vu changed the title feat(windows): install native Portal CPU chat without Docker or WSL feat(windows): install native Portal chat and Markdown documents Oct 22, 2026
Exercise real Setup with an isolated publisher boundary and same-wizard retry. Keep analyzer bootstrap failures explicit while avoiding a handled NuGet probe leaking into the Actions footer.
Record unavailable optional feature inventory after the mandatory guest guard while preserving required failures. Execute seven isolated actual-script startup contracts in both PowerShell interpreters.
@tang-vu tang-vu changed the title feat(windows): install native Portal chat and Markdown documents feat(windows): native Portal app with CPU/CUDA chat and documents Oct 23, 2026
@tang-vu

tang-vu commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

@Lightheartdevs the 0.3 desktop review package now includes the CPU/default and NVIDIA/opt-in flow, with a real two-minute demo and final-head CI artifact.

I downloaded that exact artifact and qualified CPU math/auth/cleanup plus all 9 GPU chat and 11 document/save checks. The separate clean Windows 10 Sandbox run passed first model acquisition and CPU 9/11 checks under a manually filtered medium token after separately elevated Microsoft-only prerequisite preparation. Exact hashes, source equivalence and remaining Windows 11/separate-account/release gates are in the PR body and validation notes.

One check has an inconsistent GitHub readback: pixel-advice-host-stdlib (3.12) still has status in_progress, although its conclusion is success, completed timestamp is 2026-10-23T17:46:38Z, every step is complete, and its parent workflow is successful. The PR counter therefore remains 74/75. Could you check that status if it blocks review or merging?

@Lightheartdevs

Copy link
Copy Markdown
Collaborator

Thanks for this. On 2026-10-24 we re-audited every open PR against current main and are merging only fixes for failures that users or our test fleet actually hit.

ODS is consolidating native Windows into one runtime behind the host agent. A parallel C# app with a self-built, patched llama.cpp and native-chat branches in core Pixel.jsx (10.7k lines) can't land alongside that.

If you've seen this fail on a real install of current main, please open an issue with the steps and logs, and a focused PR for it is very welcome.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows native: qualify Portal chat and document first use

3 participants