fix(agent): omit sampling params the agent spec never set - #97
Merged
Conversation
AgentRunner defaulted temperature to 0 whenever a compiled spec omitted
it, and the runner type made the field non-optional, so a caller had no
way to express "send no temperature at all".
Claude 4.7+ and Opus/Sonnet 5 reject temperature, top_p and top_k
outright with a 400 ("`temperature` is deprecated for this model"), and
Anthropic's migration guidance is to omit them and steer via prompting.
The fabricated default therefore makes every agent that never asked for
a temperature unusable on those models.
The spec type already declared temperature as optional; the runner now
carries it as optional too and passes it through untouched. Lua omits a
key assigned nil in a table constructor, so the options table drops the
field on its own once the default stops being invented. An explicit
temperature -- including an explicit 0 -- is still forwarded.
Adds src/agent/test, mirroring src/llm/test, because the agent package
shipped tests with no harness to run them.
wolfy-j
force-pushed
the
fix/agent-omit-unset-sampling-params
branch
from
July 28, 2026 21:21
c4357f9 to
266ac92
Compare
The agent package shipped tests that no harness and no CI job executed.
With src/agent/test in place the module joins both matrices.
Linting it for the first time surfaced 7 type errors in compiler.lua,
fixed here:
- set_from_list and behaviors_from_trait accumulate into untyped locals,
so their inferred returns ({[string]: true}, {[integer]: table}) did
not match the declared ones. Both locals now carry the declared type.
- normalize_raw_binding already validates that contract, binding and
kind are non-empty strings, but returned an untyped table, so every
field read downstream degraded to any and no BindingSpec built from
one type-checked. It now returns NormalizedBinding, threaded through
collect_raw_bindings and raw_bindings_from_trait.
- Binding ids arrive as registry data of any type against a string?
field. optional_id carries a value through as a string and leaves nil
alone, shared by the three sites that build a spec.
wolfy-j
force-pushed
the
fix/agent-omit-unset-sampling-params
branch
from
July 28, 2026 21:25
266ac92 to
9c8eacf
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
AgentRunnerdefaultedtemperatureto0whenever a compiled spec omitted it:CompiledAgentSpecalready declaredtemperature: number?, but theAgentRunnertype declaredtemperature: number, so a caller had no way to express "send no temperature at all".Claude 4.7+ and Opus/Sonnet 5 reject
temperature,top_pandtop_koutright. Verified against the live API:claude-opus-5claude-sonnet-5claude-haiku-4-5-20251001Anthropic's guidance is to omit these and steer via prompting; adaptive thinking requires the model to control its own sampling. So the fabricated default makes every agent that never asked for a temperature unusable on those models — the flagship and balanced tiers.
Sending
temperature: 1is not an adequate workaround: it is accepted, but it suppresses the model's thinking block (['thinking','text']becomes['text']), silently degrading output.Fix
Stop inventing the default.
temperatureis dropped fromAGENT_CONFIG.defaults, the runner type carries it asnumber?, and the spec value passes through untouched.Lua omits a key assigned
nilin a table constructor, so the existingoptionstable drops the field on its own once the fabrication stops — no conditional assignment needed.An explicit temperature, including an explicit
0, is still forwarded. Only "author said nothing" now means "send nothing".The
wippy.llmClaude mapper is deliberately untouched:claude_options.temperature = contract_options.temperatureis already nil-transparent, and having the provider strip a value a caller explicitly set would be the mirror-image bug.Tests
src/agent/testis new — the agent package shipped tests with no harness to run them, mirroringsrc/llm/test. That gap is why this went unnoticed.Four cases, all in
agent_test.lua:nilandoptionscarries notemperature/top_p/top_k0.7-> forwarded as0.70explicitly -> forwarded as0, not treated as unsetnilrather than0Before the fix: 2 failed / 312. After: 312 passed.