Skip to content

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/1

One 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.

  • A model switcher in a host UI — list what the configured endpoint really serves.
  • Sizing a context budget — OpenRouter reports context_length, which feeds tool_tiers’ context_window or a compactor threshold.
  • A startup health check — a cheap authenticated call that fails fast on a bad key.
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")
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")
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}")
  • 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.