Noolog Docs

Sampling parameters

temperature, presence_penalty, frequency_penalty and max_tokens are assembled by one helper shared by every chat strategy, so the rules below hold whichever engine an agent resolves to.

What is sent

Field Sent when
temperature always, unless omit_sampling_params is set
presence_penalty when resolved to a value and omit_sampling_params is unset
frequency_penalty when the agent sets one and omit_sampling_params is unset
max_tokens when greater than zero

presence_penalty defaults to 1.5. Setting presence_penalty: null explicitly suppresses it; omitting the key does not.

omit_sampling_params

- name: "Example"
  model_name: "some-model"
  omit_sampling_params: true
  max_tokens: 8192

Some backends fix the sampling parameters server-side and reject a request that carries them, rather than clamping the value. Those backends cannot be satisfied by sending a "neutral" number, because there is no neutral number: temperature: 0.0 is a real request for deterministic output, so an unset field and a zeroed field are indistinguishable on the wire.

omit_sampling_params: true drops all three sampling fields from the request. It does not affect max_tokens, which such backends still expect.

max_tokens: 0

Zero means "unset" here, and the field is omitted. It is not a portable way to say "unlimited" — some backends accept it, others reject it outright with a 400 naming their valid range. Since the config default is 0, an agent that never sets max_tokens sends no limit at all and inherits the backend's own default.

Provider throttles

concurrency and qps on a provider entry bound how hard the fleet may push that endpoint. Both are shared by every agent pointed at the same base_url, because provider limits are per account rather than per agent, and both are per-process: N agent processes on one provider get N independent budgets.

providers:
  example:
    type: openai
    base_url: "https://api.example.test/v1"
    concurrency: 10   # in-flight requests
    qps: 8            # requests per second

Omit either to leave that dimension unthrottled. 0 is read as unset, not as a total block. A provider whose published cap is per-model cannot be expressed by one entry — route each capacity class through its own entry.

Value precision

Sampling values are rounded to two decimals before they are sent. The config holds them as f32, which widens to its binary approximation on the wire — 0.7 becomes 0.699999988079071 — and a backend that validates decimal places rejects that as an illegal parameter rather than rounding it for us.

Endpoint paths

A base_url that already names an API version is used verbatim; one that does not gets /v1 appended. Assuming /v1 unconditionally puts a request for a differently-versioned endpoint on /v4/v1/chat/completions, which 404s in a way that reads like a bad model id rather than a client bug.

Reasoning effort

reasoning_effort is independent of the above and is emitted top-level for every engine except the two that need a different shape. Models that reason by default can be expensive left unset; setting it explicitly is usually worth it.