Skip to content

feat(agent): default temperature to 0 + configurable temperature/top_p/seed (#266) - #267

Merged
cboettig merged 3 commits into
mainfrom
feat/configurable-llm-temperature-266
Jun 23, 2026
Merged

feat(agent): default temperature to 0 + configurable temperature/top_p/seed (#266)#267
cboettig merged 3 commits into
mainfrom
feat/configurable-llm-temperature-266

Conversation

@cboettig

@cboettig cboettig commented Jun 23, 2026

Copy link
Copy Markdown
Member

Closes #266.

Problem

callLLM() sent no temperature, so the LLM endpoint applied its own default — 0.7 on the NRP open-llm-proxy. With nothing pinning sampling, the same factual question returns a different answer each turn (the sampling half of the ca-30x30 determinism report; methodology was fixed separately).

Change

New Agent._samplingParams(modelConfig) resolves temperature, top_p, and seed:

  • per-model first (config.llm_models[].temperature), then
  • top-level global default (config.temperature), then
  • built-in default: temperature: 0. top_p/seed have no sensible universal default, so they stay omitted unless configured.

The resolved params are spread into the callLLM() payload.

Why default temperature to 0 client-side

geo-agent is not bound to our proxy — it talks to any OpenAI-compatible endpoint (NRP llm-proxy, OpenRouter, a visitor's own key on the live demo), and those defaults vary (0.7 and up). Pinning 0 in the client means reproducible answers regardless of which endpoint is behind it, rather than inheriting whatever that endpoint happens to default to. (The proxy's own default is being lowered separately, but that only protects clients hitting that proxy.)

Escape hatches

  • Raise it: set temperature per-model or globally in config.json.
  • Opt out entirely: set a model's temperature: null → the key is omitted and the endpoint default applies.
  • temperature: 0 is preserved everywhere (falsy-but-valid).

Behavior change note

This is not purely non-breaking: deployments that previously relied on the implicit 0.7 will now run at 0. That's the intended fix for #266 — factual/analyst use is the common case. Apps wanting the old behavior set temperature: 0.7 (or null to inherit the endpoint default).

Tests

  • Agent._samplingParams — default-to-0, per-model, global fallback, override, temperature: 0, and per-model null opt-out cases.
  • Agent.callLLM sampling payload — asserts the outgoing fetch body carries temperature: 0 when unconfigured (no top_p/seed), and the configured values when set.

All 343 tests pass.

Docs

Added a "Sampling parameters" subsection to docs/guide/configuration.md documenting the default, the resolution order, the null opt-out, and the MoE-not-bit-reproducible caveat.

cboettig added 2 commits June 21, 2026 01:35
…bes (#130)

Findings 1-3 from #130 (Finding 4, early ChatUI render, deferred to a
browser-verified follow-up):

1. Drop the listTools() health check in MCPClient.ensureConnected() — it
   added a full round trip to every callTool/listPrompts/getPrompt. Trust
   the connected flag; callTool's reconnect-and-retry is the real safety net
   for the only frequent long-lived op, and boot-time prompt reads run right
   after a fresh connect.
2. listMcpToolsWithRetry now awaits connect() + getTools() (cache) instead
   of a second listTools() round trip — connect already cached the tools.
3. Fire mcp.connect() and the system-prompt fetch at the top of main(), and
   Promise.all the catalog walk + map-style load instead of awaiting them
   serially. The MCP cold-start now overlaps catalog+map+prompt I/O.

Tests: mcp-client ensureConnected/onReconnect specs updated for the new
no-probe contract (staleness now surfaces via callTool / explicit reconnect).
Full suite green (334).

main.js boot is browser-bootstrap (0% harness) — verify via the cold-load
network waterfall on padus per the issue's validation plan.
…ions (#266)

The client sent no sampling params, so the endpoint default applied
(0.7 on the NRP proxy) — making repeated identical questions diverge.

Add _samplingParams(): resolves temperature, top_p, and seed per-model
first, then from a top-level config default, omitting any that are unset
so behavior is unchanged when nothing is configured. Factual/analyst
deployments can now pin temperature: 0 in config.json.

Docs + tests included.
@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 51.49% 3773 / 7327
🔵 Statements 51.47% 3773 / 7330
🔵 Functions 59.19% 132 / 223
🔵 Branches 82.67% 759 / 918
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
app/agent.js 86.8% 81.03% 67.85% 86.8% 57-58, 64-65, 73-75, 92-93, 118, 217-219, 226-227, 241-245, 277-282, 291-295, 330-331, 512-536, 545-553, 559-560
app/main.js 0% 0% 0% 0% 1-468
app/mcp-client.js 99.14% 84.48% 100% 99.14% 197-198
Generated in workflow #116 for commit e738a5e by the Vitest Coverage Report Action

Builds on the configurable sampling params: when neither per-model nor
global config sets a temperature, geo-agent now sends temperature: 0
rather than omitting it. geo-agent talks to many OpenAI-compatible
endpoints (NRP proxy, OpenRouter, user-supplied keys) whose own defaults
vary (0.7+), so reproducibility shouldn't hinge on the endpoint default.

A model can still opt back out by setting temperature: null (omits the
key, inheriting the endpoint default). top_p/seed stay omitted by default
(no sensible universal value).

Docs + tests updated.
@cboettig cboettig changed the title feat(agent): configurable temperature/top_p/seed on chat completions (#266) feat(agent): default temperature to 0 + configurable temperature/top_p/seed (#266) Jun 23, 2026
@cboettig
cboettig merged commit 90d02eb into main Jun 23, 2026
1 check passed
@cboettig
cboettig deleted the feat/configurable-llm-temperature-266 branch June 23, 2026 23:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Send a configurable temperature on chat-completion calls (currently unset → proxy defaults to 0.7)

1 participant