Toolnexus.Client.list_models
Elixir · package toolnexus · SPEC §8
@spec list_models(keyword() | map()) :: {:ok, [%{id: String.t(), name: String.t() | nil, context_length: integer() | nil}]} | {:error, String.t()}def list_models(opts) # the same options as Client.create/1One GET, no retries. openai style: GET {base_url}/models (OpenRouter’s context_length is
read when present). anthropic style: GET {base_url}/v1/models, following has_more /
last_id pages. Results are sorted by id; name and context_length are nil when the
provider does not report them. The key follows the API-key-by-host
rule; a missing key, an HTTP error or a bad body is {:error, message}, never a raise.
When to use it
Section titled “When to use it”- A model switcher in a host UI — list what the configured endpoint really serves.
- Sizing a context budget — OpenRouter reports
context_length, which feedstool_tiers’context_windowor a compactor threshold. - A startup health check — a cheap authenticated call that fails fast on a bad key.
Why this and not the alternative
Section titled “Why this and not the alternative”Examples
Section titled “Examples”1. The smallest call
Section titled “1. The smallest call”t = fn _req -> {:ok, %{status: 200, headers: %{}, body: %{"data" => [%{"id" => "gpt-b"}, %{"id" => "gpt-a"}]}}}end
{:ok, models} = Toolnexus.Client.list_models(base_url: "https://api.example/v1", api_key: "YOUR_KEY_HERE", transport: t)["gpt-a", "gpt-b"] = Enum.map(models, & &1.id)IO.puts("ok: #{length(models)} models")2. OpenRouter’s context length
Section titled “2. OpenRouter’s context length”t = fn _req -> {:ok, %{status: 200, headers: %{}, body: %{"data" => [%{"id" => "z/model", "name" => "Z", "context_length" => 200_000}]}}}end
{:ok, [m]} = Toolnexus.Client.list_models(base_url: "https://router.example/api/v1", api_key: "YOUR_KEY_HERE", transport: t)true = m == %{id: "z/model", name: "Z", context_length: 200_000}IO.puts("ok: #{m.id} has #{m.context_length} tokens")3. Anthropic pagination and errors
Section titled “3. Anthropic pagination and errors”me = self()
t = fn req -> send(me, {:url, req.url}) body = if String.contains?(req.url, "after_id"), do: %{"data" => [%{"id" => "claude-a", "display_name" => "A"}], "has_more" => false}, else: %{"data" => [%{"id" => "claude-b", "display_name" => "B"}], "has_more" => true, "last_id" => "claude-b"} {:ok, %{status: 200, headers: %{}, body: body}}end
{:ok, [a, b]} = Toolnexus.Client.list_models(base_url: "https://api.example/v1", style: "anthropic", api_key: "YOUR_KEY_HERE", transport: t)true = a.id == "claude-a" and b.name == "B"
denied = fn _ -> {:ok, %{status: 401, headers: %{}, body: ~s({"error":"bad"})}} end{:error, msg} = Toolnexus.Client.list_models(base_url: "https://api.example", api_key: "YOUR_KEY_HERE", transport: denied)true = msg =~ "HTTP 401"IO.puts("ok: two pages, then #{msg}")See also
Section titled “See also”Toolnexus.Client.create— The unified client: system prompt, skills injection, parallel and chained tool calls, retries, memory.Toolnexus.Client.run— Send a prompt, let the loop call tools until the model stops, get a RunResult.Toolnexus.Client.stream— The streaming loop: text deltas, tool-call events, and suspension events as they happen.Toolnexus.Client.create— Intercept before/after model calls and tool calls: audit, redact, veto, or rewrite.