Skip to content

ListModels

Go · package github.com/muthuishere/toolnexus/golang · SPEC §8 · golang/list_models.go

func ListModels(ctx context.Context, opts ClientOptions) ([]ModelInfo, error)
type ModelInfo struct {
ID string
Name string // display name, when the provider gives one
ContextLength int // tokens, when reported (OpenRouter does); 0 = unknown
}

One listing call against opts.BaseURL, no retries, sorted by ID:

  • StyleOpenAI — GET {base}/models (OpenRouter’s context_length is read when present).
  • StyleAnthropic — GET {base}/v1/models, following has_more / last_id pagination.

It uses the same key rules as the client (APIKey / APIKeyEnv / the host’s own env var) and opts.HTTPClient.

A model picker or a /model command in a host UI, a startup check that the configured model exists, or sizing a context window (ContextLength) before building a ToolTiers budget.

1. The smallest useful call — an OpenAI-style server

Section titled “1. The smallest useful call — an OpenAI-style server”
package main
import (
"context"
"fmt"
"log"
"net/http"
"net/http/httptest"
toolnexus "github.com/muthuishere/toolnexus/golang"
)
func main() {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/models" {
http.NotFound(w, r)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"data":[{"id":"zeta"},{"id":"alpha"}]}`))
}))
defer srv.Close()
models, err := toolnexus.ListModels(context.Background(), toolnexus.ClientOptions{
BaseURL: srv.URL, Style: toolnexus.StyleOpenAI, APIKey: "YOUR_KEY_HERE",
})
if err != nil {
log.Fatal(err)
}
if len(models) != 2 || models[0].ID != "alpha" {
log.Fatalf("expected sorted ids, got %+v", models)
}
fmt.Println("ok:", models[0].ID, models[1].ID)
}

2. The realistic case — OpenRouter-style names and context lengths

Section titled “2. The realistic case — OpenRouter-style names and context lengths”
package main
import (
"context"
"fmt"
"log"
"net/http"
"net/http/httptest"
toolnexus "github.com/muthuishere/toolnexus/golang"
)
func main() {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"data":[{"id":"vendor/big","name":"Big Model","context_length":200000}]}`))
}))
defer srv.Close()
models, err := toolnexus.ListModels(context.Background(), toolnexus.ClientOptions{
BaseURL: srv.URL, Style: toolnexus.StyleOpenAI, APIKey: "YOUR_KEY_HERE",
})
if err != nil {
log.Fatal(err)
}
m := models[0]
if m.Name != "Big Model" || m.ContextLength != 200000 {
log.Fatalf("unexpected model info: %+v", m)
}
fmt.Printf("ok: %s (%s) %d tokens\n", m.ID, m.Name, m.ContextLength)
}

3. The full surface — Anthropic pagination and the key rule

Section titled “3. The full surface — Anthropic pagination and the key rule”
package main
import (
"context"
"fmt"
"log"
"net/http"
"net/http/httptest"
"strings"
toolnexus "github.com/muthuishere/toolnexus/golang"
)
func main() {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if r.URL.Query().Get("after_id") == "" {
_, _ = w.Write([]byte(`{"data":[{"id":"claude-b","display_name":"B"}],"has_more":true,"last_id":"claude-b"}`))
return
}
_, _ = w.Write([]byte(`{"data":[{"id":"claude-a","display_name":"A"}],"has_more":false}`))
}))
defer srv.Close()
models, err := toolnexus.ListModels(context.Background(), toolnexus.ClientOptions{
BaseURL: srv.URL, Style: toolnexus.StyleAnthropic, APIKey: "YOUR_KEY_HERE",
})
if err != nil {
log.Fatal(err)
}
if len(models) != 2 || models[0].ID != "claude-a" || models[0].Name != "A" {
log.Fatalf("expected both pages, sorted: %+v", models)
}
// A local host with no APIKey/APIKeyEnv is refused, as Run would be.
_, err = toolnexus.ListModels(context.Background(), toolnexus.ClientOptions{BaseURL: srv.URL, Style: toolnexus.StyleOpenAI})
if err == nil || !strings.Contains(err.Error(), "no API key") {
log.Fatalf("expected a no-API-key error, got %v", err)
}
fmt.Println("ok:", len(models), "models over 2 pages; keyless local call refused")
}
  • ClientOptions.APIKeyEnv — the key rules ListModels shares with the client.
  • ToolTiers — ContextWindow sizes the default tier budget.
  • CreateClient — The unified client: system prompt, skills injection, parallel and chained tool calls, retries, memory.