Files
llmgw/internal/cli/tui_federation.go
Ilker ManapandClaude Opus 5.5 40e9fd2ab1 Federation: another llmgw cluster as a provider, its models as PEER/MODEL
ctl federation add/list/remove/sync keeps peers in the store (migration
0029); their /v1/models are offered here as external models named
PEER/MODEL and kept in step, a model still named by a fallback kept
withdrawn. Peers are checked at /ready, timed, and taken out of routing
while down. Requests to a peer carry x-llmgw-hop and are refused (508) when
they come back to a cluster they passed through; residency and no_store
keep requests off peers; X-Request-Id and, with --send-tags, attribution
tags go along. ctl model fallbacks sets overflow to a peer. Console view,
metrics, admin API routes and docs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-05 01:21:30 +02:00

81 lines
2.6 KiB
Go

package cli
import (
"fmt"
"strings"
"time"
"gitea.mynodes.xyz/ilker/llmgw/internal/control/federation"
)
// The console's federation view: the other llmgw clusters whose models are
// offered here, whether each is up and how far away, as `llmgw ctl
// federation list` shows them. Peers are added and removed with ctl, which
// needs a key file on this machine that a form here could not check.
func (m consoleModel) federationPanel(pw int) (string, string, string) {
keys := "→ or Enter open · ↑↓ choose · Q leave"
if m.inPanel {
keys = "↑↓ peer · Enter its models · ← back · Q leave"
}
v := m.data.federation
head := "\n " + sDim.Render("Other llmgw clusters whose models are offered here as PEER/MODEL.")
if v.Cluster != "" {
head += "\n " + sDim.Render("This cluster's id: "+v.Cluster)
}
head += "\n\n"
if len(v.Peers) == 0 {
return "Federation", head + " " + sDim.Render("No peers. Add one with: llmgw ctl federation add NAME --url URL --key-file FILE"), keys
}
var rows [][]string
for _, p := range v.Peers {
health := sOK.Render("up")
if !p.Up {
health = sBad.Render("down")
}
lat := "-"
if p.Latency > 0 {
lat = fmt.Sprintf("%.1fms", p.LatencyMs)
}
offered := 0
for _, md := range p.Models {
if !md.Withdrawn {
offered++
}
}
rows = append(rows, []string{p.Name, health, lat, fmt.Sprint(offered), p.URL})
}
return "Federation", head + table([]string{"PEER", "HEALTH", "LATENCY", "MODELS", "URL"}, rows, m.row, pw, m.inPanel), keys
}
// peerDialog is one peer whole: how it was last found, and its models.
func peerDialog(p federation.Status) (string, string) {
var b strings.Builder
fmt.Fprintf(&b, "%s\n", p.URL)
if p.Up {
fmt.Fprintf(&b, "%s, /ready in %.1fms", sOK.Render("up"), p.LatencyMs)
} else {
fmt.Fprintf(&b, "%s: %s", sBad.Render("down"), wrap(p.Error, 80, " "))
}
if !p.Checked.IsZero() {
fmt.Fprintf(&b, ", checked %s ago", time.Since(p.Checked).Round(time.Second))
}
tags := "not told who asks"
if p.SendTags {
tags = "told this cluster and the project of each request (x-llmgw-tags)"
}
fmt.Fprintf(&b, "\ncluster %s, key %s; %s\n\n", p.Cluster, p.KeyFile, tags)
if len(p.Models) == 0 {
b.WriteString(sDim.Render("offers this cluster's key no models") + "\n")
}
for _, md := range p.Models {
line := md.Name
if md.Withdrawn {
line += sDim.Render(" withdrawn by the peer; kept while a fallback here names it")
}
b.WriteString(" " + line + "\n")
}
fmt.Fprintf(&b, "\n%s", sDim.Render("llmgw ctl federation sync|remove "+p.Name+" · any key"))
return p.Name, b.String()
}