Skip to content

Sampling Temperature: 0 is unrepresentable on the wire (omitempty drops it) #1133

Description

@PratikDhanave

Describe the bug

CreateMessageParams.Temperature and CreateMessageWithToolsParams.Temperature are declared as:

Temperature float64 `json:"temperature,omitempty"`

With omitempty, a float64 value of 0 is dropped from the marshaled JSON entirely. For sampling, temperature: 0 is a meaningful, distinct value (greedy/deterministic decoding) — not the same as "unspecified" (where a client applies its own default, typically ~0.7–1.0).

So a server that requests deterministic output:

json.Marshal(&CreateMessageParams{MaxTokens: 100, Messages: msgs, Temperature: 0})
// -> no "temperature" key in the output

produces JSON with no temperature field. A non-Go client (JS/Python) then samples at its own default temperature, contrary to the server's explicit request. (Go↔Go happens to round-trip because the receiver also decodes the absent field back to 0.0, which masks it in same-SDK tests.)

Scope / context

This is not an isolated slip — it's a consequence of the consistent convention in protocol.go, where every optional numeric field uses float64 ...,omitempty (Priority, CostPriority, IntelligencePriority, SpeedPriority, Total, Temperature). For the priority/total fields, 0 conventionally means "unspecified", so omitempty is fine. Temperature is the one where 0 is a distinct, commonly-used value, so the convention loses information there.

Possible directions (all have tradeoffs — hence an issue, not a PR)

  1. Temperature *float64 (+ omitempty) — correct semantics (nil = unset, &0 = explicit 0), but a breaking API change on a stable v1.x type and inconsistent with the sibling fields.
  2. Drop omitempty — non-breaking to the type, but then unset also serializes as "temperature":0, forcing deterministic sampling on clients for the common unset case (semantically wrong the other way).
  3. Custom MarshalJSON — preserves the exported type and unset semantics, but adds a hand-written marshaler where the package currently has none.

Filing this so the maintainers can decide the preferred direction (and whether the same applies to the other numeric fields). Happy to send a PR once you indicate which approach you'd accept.

Version

main / v1.7.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Nice to haves, rare edge cases

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions