/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. safetyis populated far more often. It readsnullonnp-2026-07-r2’s plain fixed-budget path;np-2026-08-r4was 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-r2returnsrecords_selected: 0and nothing inselected[],np-2026-08-r4can return every record you sent, unchanged, including one sent withimportance: 0.0. Both are200, neither is charged, and the shape ofselected[]is genuinely different. See reading a stand-down. gate.reasonstrings change. Different standdown and engage reasons are in play underr4than underr2. This was already true of every label change; keep logginggate.reasonrather than branching on it, and branch onoutcomeas Errors has always said.- A
textrequest whose paragraphs normalize to more than 1,000 units is now rejected with400,reason: "semantic_normalization_limit", instead of being silently capped at 1,000 units and served as a200. See the normalization ceiling.
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
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
textin place ofrecords[]. Needlepath splits it on blank lines, and each resulting chunk becomes one record of kindexternal_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_pointis optional on this shape, same as withrecords[]. Whichever operating point resolves is always echoed back inpolicy_version.budget.max_context_tokensis still required: there is no operating-point default to fall back to when the request carries norecords[]-based budget elsewhere.- Sending both
textandrecordsin the same request is a400, witherror: "text_and_records_both_set".
records[] continues to work exactly as before, and
nothing about it changed.
Added: optional fields
request_idis 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[].kindis now optional, defaulting toexternal_datawhen omitted. Setting it explicitly is still worth doing; see Records and tasks, sincekindcarries 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.