package docgen import ( "fmt" "strings" ) // Sources are the files configuration is declared in. // // Listed rather than discovered, because "every file with a koanf tag" would // sweep in structs that are configuration in the Go sense and not in the // operator's — a scoring weight built at wiring time is not something anyone // writes in a file. A test checks the list against what is actually tagged, so // a new configuration file is a failure here rather than a silent omission. var Sources = []string{ "internal/config/config.go", "internal/agent/agent.go", "internal/agent/discovery/discover.go", "internal/agent/engines/engine.go", "internal/agent/engines/llamacpp.go", "internal/agent/engines/vllm.go", "internal/agent/engines/sglang.go", "internal/agent/engines/sim.go", "internal/agent/supervisor/supervisor.go", "internal/tlsconf/tlsconf.go", "internal/control/catalog/catalog.go", "internal/router/admission/controller.go", "internal/accounting/cost.go", } // notReference are files with koanf tags that an operator never writes. // // Inventory and catalog entries carry them so the same structs can be decoded // from an API payload or a model file; putting them in a configuration // reference would invite somebody to write them into server.yaml. var notReference = []string{ "internal/control/inventory/inventory.go", } // Render turns collected blocks into the reference document. func Render(blocks []Block) string { var b strings.Builder b.WriteString(`# Configuration reference Every setting llmgw reads from a file, with the type it takes and what it is for. **Generated from the source.** The descriptions are the comments on the fields themselves, so this cannot describe a setting that does not exist or miss one that does — and a test fails when it has drifted. Do not edit it; edit the comment and run ` + "`go generate ./...`" + `. Where a setting takes another block, the block is listed under its own heading rather than repeated. `) // An index first: the reason to open a reference is usually to find one // key, and scanning thirteen headings for it is the thing this replaces. b.WriteString("## Every key\n\n| Key | Type | In |\n|---|---|---|\n") for _, bl := range blocks { for _, f := range bl.Fields { b.WriteString(fmt.Sprintf("| `%s` | %s | [%s](#%s) |\n", f.Key, code(f.Type), bl.Name, anchor(bl.Name))) } } b.WriteString("\n") for _, bl := range blocks { fmt.Fprintf(&b, "## %s\n\n", bl.Name) if bl.Doc != "" { b.WriteString(bl.Doc + "\n\n") } for _, f := range bl.Fields { fmt.Fprintf(&b, "### `%s`\n\n%s\n\n", f.Key, code(f.Type)) if f.Doc != "" { b.WriteString(f.Doc + "\n\n") } if f.Nested != "" && hasBlock(blocks, f.Nested) { fmt.Fprintf(&b, "Takes a [%s](#%s) block.\n\n", f.Nested, anchor(f.Nested)) } } } return b.String() } func hasBlock(blocks []Block, name string) bool { for _, b := range blocks { if b.Name == name { return true } } return false } func code(s string) string { return "`" + s + "`" } // anchor is how GitHub and Gitea slug a heading. func anchor(s string) string { return strings.ToLower(s) }