Skip to main content
Every field below is additive within /v1; see Versioning for what that guarantees, and it is a real guarantee: nothing was removed, renamed, or made required. It is not the same claim as “nothing about your traffic changes.” If you pin budget.operating_point on every request, as Operating points has always recommended, the entry directly below does not apply to you at all. If you do not, read it: an unpinned caller can see a genuinely different status code on some requests, not only additive fields. The importance default change further down is the one item worth five minutes of your attention regardless of pinning.

The default moves to np-2026-08-r4

A request that omits budget.operating_point now runs np-2026-08-r4 instead of np-2026-07-r2. Nothing else changed to cause this: the label itself is unchanged, immutable, and still resolvable by name exactly as before. Only the server’s resolution of an absent label moved. If you pin budget.operating_point on every request, this entry does not apply to you. A pinned label runs exactly the configuration it always has; see what a label pins. np-2026-07-r2 and np-2026-08-r3 both stay in the registry and stay pinnable; nothing about them changed. If you do not pin it, here is what moves, stated from live captures, not from the general description of r4 elsewhere on this site:
  • New, additive response fields start appearing: selection_recall, records_admitted, and four top-level fields (task_kind, selection_strategy_used, support_contract_used, adapter_attempt_count). A client that already ignores fields it does not recognise needs no change.
  • safety is populated far more often. It reads null on np-2026-07-r2’s plain fixed-budget path; np-2026-08-r4 was observed computing a real verdict on the same kind of request. See the two cases that are not errors.
  • A request that used to stand down with an empty selection may come back as a full-context pass-through instead. Where np-2026-07-r2 returns records_selected: 0 and nothing in selected[], np-2026-08-r4 can return every record you sent, unchanged, including one sent with importance: 0.0. Both are 200, neither is charged, and the shape of selected[] is genuinely different. See reading a stand-down.
  • gate.reason strings change. Different standdown and engage reasons are in play under r4 than under r2. This was already true of every label change; keep logging gate.reason rather than branching on it, and branch on outcome as Errors has always said.
  • A text request whose paragraphs normalize to more than 1,000 units is now rejected with 400, reason: "semantic_normalization_limit", instead of being silently capped at 1,000 units and served as a 200. See the normalization ceiling.
None of this is a wire-contract change: every field above is additive, and a client following the two rules that keep it working handles all of them without a code change. The text-normalization item is the one exception worth naming plainly: it is a new failure mode, not just a new field, and a client that does not already handle 400 gracefully can break on a request that previously returned 200. Everything else here is listed because behaviour moved for any caller that never chose a label, which is exactly the caller Operating points has always warned about; the fix in every case, including the text-normalization one, is the same one-line pin.

2026-09-03: np-2026-08-r4 is published

The registry now lists np-2026-08-r4. At the time of this entry, the default was unchanged: a request that omitted budget.operating_point still ran np-2026-07-r2. See the entry above for when the default itself moved. Across the three example requests on Choosing an operating point, np-2026-08-r4 returned the np-2026-07-r2 fields, the selection_recall block and records_admitted that np-2026-08-r3 added, four additive top-level fields (task_kind, selection_strategy_used, support_contract_used, adapter_attempt_count), a selection_recall.version of npsr-2026-08-r2, and further format_metrics entries. Optional format_metrics entries vary by label: on those three requests r4 did not emit capacity_cap_tokens, which r3 does. Treat any format_metrics entry as optional, as Versioning already asks. Choosing an operating point shows the same three requests under all three labels. The rest of this page describes the 2026-08-07 changes.

Behavior change: the default for a missing importance

Records that omit importance no longer default to 0.0.Previously, a record sent without an importance field was scored as if it had explicitly set importance: 0.0, the lowest possible value on the signal’s own scale. That biased selection against those records, toward stand-down, purely because the field was absent rather than because it was genuinely low-priority. Records now receive a neutral default instead, so omitting the field no longer counts against them.This changes selection output for requests whose records omit importance. As a historical example, at the time this note was written the site’s canonical billing-dispute fixture (a smaller, 12-record version of the one now on the quickstart; the fixture has since been enlarged for other reasons and no longer produces these exact numbers) previously returned records_selected: 1 and tokens_saved: 785. Under the same 12-record request it then returned records_selected: 2 and tokens_saved: 733: the neutral default let a second record clear the bar that the old zero-default held it under.Requests that set importance explicitly are unchanged. This only affects the default applied when the field is absent; a record that sends its own value, including 0.0, scores exactly as it did before.Stand-downs remain billed at charge_multiplier: "0" regardless of which default applied; see How billing works.
Nothing about this is a wire-contract change: no field was added, removed, renamed, or made required, and the response shape is identical. It is listed here because it can move selection output for a request that was, and remains, perfectly valid. If your integration pins exact record sets or byte-compares responses for requests that omit importance, re-run them against current behavior. If you always set importance explicitly, or don’t compare responses byte-for-byte, there is nothing to do.
This is what “a label pins the configuration, not the engine build” looks like in practice. The change above landed in the engine, not in any operating point’s settings, so it moved output under labels that were pinned the whole time. Pinning did its job: no threshold behind np-2026-07-r2 was retuned. It simply does not extend to the code reading those thresholds. See what a label pins, and record build_id from /v1/health next to policy_version if you keep results to compare.

Added: the simple request shape

You can now send raw material instead of pre-split records. See The simple shape in the quickstart for the full walkthrough; the short version:
  • Send text in place of records[]. Needlepath splits it on blank lines, and each resulting chunk becomes one record of kind external_data.
  • Each derived record gets a stable id of the form sha256:<16 hex characters>, the hash of that record’s own text, so you can recompute it yourself from the chunk content. The same paragraph always produces the same id.
  • budget.operating_point is optional on this shape, same as with records[]. Whichever operating point resolves is always echoed back in policy_version.
  • budget.max_context_tokens is still required: there is no operating-point default to fall back to when the request carries no records[]-based budget elsewhere.
  • Sending both text and records in the same request is a 400, with error: "text_and_records_both_set".
This is purely additive: records[] continues to work exactly as before, and nothing about it changed.

Added: optional fields

  • request_id is now optional everywhere. It remains a caller-side correlation id, echoed back on the response and useful for tying a request to your own logs; omit it and nothing about selection, metering, or the response shape changes.
  • records[].kind is now optional, defaulting to external_data when omitted. Setting it explicitly is still worth doing; see Records and tasks, since kind carries selection priors that a default cannot infer for you.

Also in this release: console

  • The self-serve dashboard now shows value metrics on the account overview: tokens saved, an estimated savings figure at a labelled reference price, and a lifetime savings percentage.
  • Usage analytics gained selectable time windows (all-time, 30 days, 7 days, and 24 hours) with both a chart and a table view, and a per-key breakdown.
  • A signed-in demo is now available that runs live requests against your own API key, rather than a shared or sample credential.

Not a version bump

Every item on this page ships at the existing /v1 URL version. Nothing here removes a field, renames a field, makes an optional field required, or narrows an accepted range; see What counts as breaking for the exact test. The importance-default change is a behavior change, not a contract change: the request and response shapes are byte-identical to before, and a client written against the documented schema keeps working without modification.