diff --git a/cmd/mavweb/ecosystem.go b/cmd/mavweb/ecosystem.go index 77a329c..1bb1439 100644 --- a/cmd/mavweb/ecosystem.go +++ b/cmd/mavweb/ecosystem.go @@ -117,8 +117,5 @@ func handleEcosystem(w http.ResponseWriter, r *http.Request, urls ecoURLs, core d.Calls.Rows = rows } - w.Header().Set("Content-Type", "text/html; charset=utf-8") - if err := ecosystemTmpl.Execute(w, d); err != nil { - log.Printf("ecosystem render: %v", err) - } + renderPage(w, ecosystemTmpl, d) } diff --git a/cmd/mavweb/models.go b/cmd/mavweb/models.go index ded6af1..2b38bcd 100644 --- a/cmd/mavweb/models.go +++ b/cmd/mavweb/models.go @@ -2,8 +2,8 @@ package main import ( "context" + _ "embed" "errors" - "html/template" "log" "net/http" "strconv" @@ -31,43 +31,10 @@ type modelController interface { SwapModel(ctx context.Context, req ipc.SwapModelReq) (ipc.SwapModelResp, error) } -var modelsTmpl = template.Must(template.New("models").Funcs(shellFuncs()).Parse(shellHTML + modelsHTML)) +//go:embed models.html +var modelsHTML string -const modelsHTML = `{{template "shellTop" "models"}} -

Resident model

-

swapping requires step-up — assert a passkey first. The old model is unloaded before the new one is loaded (one model fits the iGPU at a time), so turns during the load are refused and fall back to the classifier.

-

a swap is not remembered. Nothing writes it down, so the next restart of the daemon — including the one mavupdate does — comes back on phraser.model_path from the config. Make it stick by editing that.

-{{if .Msg}}
{{.Msg}}
{{end}} -{{if .Err}}
{{.Err}}
{{end}} -{{if .Off}} -
-

swap not configured

-

this core has no phraser.swap_models allowlist, so there is nothing to swap to. Add the gguf paths you allow to deploy/mavend.json and restart once.

-
-{{else}} -
-

loaded now

-
- - - - - -
model{{.Status.Model}}
file{{.Status.ModelPath}}
server{{.Status.BaseURL}}
n_ctx{{.Status.NCtx}}
n_gpu_layers{{.Status.NGpuLayers}}
-

the model name is what llama-server reports for itself, not what the config says it should be.

-
-
-

allowed models {{len .Status.Swappable}}

-{{if .Status.Swappable}}
-{{range .Status.Swappable}} -{{end}} -
file
{{.}}
- -
-{{else}}
no models allowlisted
{{end}} -
-{{end}} -{{template "shellBottom"}}` +var modelsTmpl = parsePage("models", modelsHTML, nil) type modelsPage struct { Msg string @@ -154,8 +121,5 @@ func handleModels(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI, swap } } page.Status = st - w.Header().Set("Content-Type", "text/html; charset=utf-8") - if err := modelsTmpl.Execute(w, page); err != nil { - log.Printf("models render: %v", err) - } + renderPage(w, modelsTmpl, page) } diff --git a/cmd/mavweb/models.html b/cmd/mavweb/models.html new file mode 100644 index 0000000..0990b54 --- /dev/null +++ b/cmd/mavweb/models.html @@ -0,0 +1,35 @@ +{{template "shellTop" "models"}} +

Resident model

+

swapping requires step-up — assert a passkey first. The old model is unloaded before the new one is loaded (one model fits the iGPU at a time), so turns during the load are refused and fall back to the classifier.

+

a swap is not remembered. Nothing writes it down, so the next restart of the daemon — including the one mavupdate does — comes back on phraser.model_path from the config. Make it stick by editing that.

+{{if .Msg}}
{{.Msg}}
{{end}} +{{if .Err}}
{{.Err}}
{{end}} +{{if .Off}} +
+

swap not configured

+

this core has no phraser.swap_models allowlist, so there is nothing to swap to. Add the gguf paths you allow to deploy/mavend.json and restart once.

+
+{{else}} +
+

loaded now

+
+ + + + + +
model{{.Status.Model}}
file{{.Status.ModelPath}}
server{{.Status.BaseURL}}
n_ctx{{.Status.NCtx}}
n_gpu_layers{{.Status.NGpuLayers}}
+

the model name is what llama-server reports for itself, not what the config says it should be.

+
+
+

allowed models {{len .Status.Swappable}}

+{{if .Status.Swappable}}
+{{range .Status.Swappable}} +{{end}} +
file
{{.}}
+ +
+{{else}}
no models allowlisted
{{end}} +
+{{end}} +{{template "shellBottom"}} diff --git a/cmd/mavweb/passkey.html b/cmd/mavweb/passkey.html new file mode 100644 index 0000000..6ea67e0 --- /dev/null +++ b/cmd/mavweb/passkey.html @@ -0,0 +1,58 @@ +{{template "shellTop" "passkey"}} +

Passkey

+

Enroll a passkey once, then assert it to unlock destructive actions (tool enable) for a few minutes.

+
+ + + + +
+

Rewriting the cold-start key points it at the passkey you assert next. Every other enrolled passkey stops being able to unlock a cold-booted daemon.

+
+{{template "shellBottom"}} + diff --git a/cmd/mavweb/webauthn.go b/cmd/mavweb/webauthn.go index 3312c7f..f1ef4a7 100644 --- a/cmd/mavweb/webauthn.go +++ b/cmd/mavweb/webauthn.go @@ -2,6 +2,7 @@ package main import ( "context" + _ "embed" "encoding/json" "errors" "fmt" @@ -76,72 +77,17 @@ func newPasskeyHandle(cfg webauthn.Config, core ipc.CoreAPI, storePath string, s // on: assert here (bumps the daemon session to L3 for the assertion TTL), then // enable a tool on /tools within that window. func (h *PasskeyHandle) Page(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/html; charset=utf-8") - passkeyTmpl.Execute(w, nil) + renderPage(w, passkeyTmpl, nil) } -var passkeyTmpl = parsePage("passkey", passkeyPageHTML, nil) +// passkeyPageHTML — the enrolment page's own markup, wrapped by passkeyTmpl +// with shellTop/shellBottom. It was a Go string constant, which is the one +// place page markup still lived in Go. +// +//go:embed passkey.html +var passkeyPageHTML string -// passkeyPageHTML — rendered via passkeyTmpl, which wraps it with -// shellTop/shellBottom. -const passkeyPageHTML = `{{template "shellTop" "passkey"}} -

Passkey

-

Enroll a passkey once, then assert it to unlock destructive actions (tool enable) for a few minutes.

-
- - - - -
-

Rewriting the cold-start key points it at the passkey you assert next. Every other enrolled passkey stops being able to unlock a cold-booted daemon.

-
-{{template "shellBottom"}} -` +var passkeyTmpl = parsePage("passkey", passkeyPageHTML, nil) func (h *PasskeyHandle) RegisterBegin(w http.ResponseWriter, r *http.Request) { opts, challenge, err := h.rp.CreationOptions([]byte("maven-user"), "maven user")