@niadra/sdk 0.1.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/CHANGELOG.md +160 -68
  2. package/README.md +451 -22
  3. package/dist/ai-sdk.cjs +1037 -0
  4. package/dist/ai-sdk.cjs.map +1 -0
  5. package/dist/ai-sdk.d.cts +118 -0
  6. package/dist/ai-sdk.d.ts +118 -0
  7. package/dist/ai-sdk.js +1030 -0
  8. package/dist/ai-sdk.js.map +1 -0
  9. package/dist/anthropic.cjs +528 -0
  10. package/dist/anthropic.cjs.map +1 -0
  11. package/dist/anthropic.d.cts +35 -0
  12. package/dist/anthropic.d.ts +35 -0
  13. package/dist/anthropic.js +523 -0
  14. package/dist/anthropic.js.map +1 -0
  15. package/dist/bedrock.cjs +392 -0
  16. package/dist/bedrock.cjs.map +1 -0
  17. package/dist/bedrock.d.cts +25 -0
  18. package/dist/bedrock.d.ts +25 -0
  19. package/dist/bedrock.js +388 -0
  20. package/dist/bedrock.js.map +1 -0
  21. package/dist/cli.js +11045 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/client-DsIxZxZk.d.cts +6905 -0
  24. package/dist/client-DsIxZxZk.d.ts +6905 -0
  25. package/dist/cloudflare-agents.cjs +626 -0
  26. package/dist/cloudflare-agents.cjs.map +1 -0
  27. package/dist/cloudflare-agents.d.cts +113 -0
  28. package/dist/cloudflare-agents.d.ts +113 -0
  29. package/dist/cloudflare-agents.js +622 -0
  30. package/dist/cloudflare-agents.js.map +1 -0
  31. package/dist/elevenlabs.cjs +738 -0
  32. package/dist/elevenlabs.cjs.map +1 -0
  33. package/dist/elevenlabs.d.cts +86 -0
  34. package/dist/elevenlabs.d.ts +86 -0
  35. package/dist/elevenlabs.js +733 -0
  36. package/dist/elevenlabs.js.map +1 -0
  37. package/dist/genkit.cjs +323 -0
  38. package/dist/genkit.cjs.map +1 -0
  39. package/dist/genkit.d.cts +67 -0
  40. package/dist/genkit.d.ts +67 -0
  41. package/dist/genkit.js +318 -0
  42. package/dist/genkit.js.map +1 -0
  43. package/dist/google-adk.cjs +705 -0
  44. package/dist/google-adk.cjs.map +1 -0
  45. package/dist/google-adk.d.cts +91 -0
  46. package/dist/google-adk.d.ts +91 -0
  47. package/dist/google-adk.js +701 -0
  48. package/dist/google-adk.js.map +1 -0
  49. package/dist/google-genai.cjs +422 -0
  50. package/dist/google-genai.cjs.map +1 -0
  51. package/dist/google-genai.d.cts +26 -0
  52. package/dist/google-genai.d.ts +26 -0
  53. package/dist/google-genai.js +418 -0
  54. package/dist/google-genai.js.map +1 -0
  55. package/dist/index.cjs +11421 -1895
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.cts +959 -1294
  58. package/dist/index.d.ts +959 -1294
  59. package/dist/index.js +11368 -1896
  60. package/dist/index.js.map +1 -1
  61. package/dist/intercept-0_lJE6k1.d.cts +20 -0
  62. package/dist/intercept-D7qFCaRb.d.ts +20 -0
  63. package/dist/langchain.cjs +1077 -0
  64. package/dist/langchain.cjs.map +1 -0
  65. package/dist/langchain.d.cts +102 -0
  66. package/dist/langchain.d.ts +102 -0
  67. package/dist/langchain.js +1068 -0
  68. package/dist/langchain.js.map +1 -0
  69. package/dist/livekit.cjs +404 -0
  70. package/dist/livekit.cjs.map +1 -0
  71. package/dist/livekit.d.cts +113 -0
  72. package/dist/livekit.d.ts +113 -0
  73. package/dist/livekit.js +398 -0
  74. package/dist/livekit.js.map +1 -0
  75. package/dist/llamaindex.cjs +349 -0
  76. package/dist/llamaindex.cjs.map +1 -0
  77. package/dist/llamaindex.d.cts +92 -0
  78. package/dist/llamaindex.d.ts +92 -0
  79. package/dist/llamaindex.js +344 -0
  80. package/dist/llamaindex.js.map +1 -0
  81. package/dist/mastra.cjs +1082 -0
  82. package/dist/mastra.cjs.map +1 -0
  83. package/dist/mastra.d.cts +86 -0
  84. package/dist/mastra.d.ts +86 -0
  85. package/dist/mastra.js +1075 -0
  86. package/dist/mastra.js.map +1 -0
  87. package/dist/openai-agents.cjs +465 -0
  88. package/dist/openai-agents.cjs.map +1 -0
  89. package/dist/openai-agents.d.cts +75 -0
  90. package/dist/openai-agents.d.ts +75 -0
  91. package/dist/openai-agents.js +459 -0
  92. package/dist/openai-agents.js.map +1 -0
  93. package/dist/retell.cjs +846 -0
  94. package/dist/retell.cjs.map +1 -0
  95. package/dist/retell.d.cts +161 -0
  96. package/dist/retell.d.ts +161 -0
  97. package/dist/retell.js +841 -0
  98. package/dist/retell.js.map +1 -0
  99. package/dist/shared-Bb5B59Bu.d.ts +39 -0
  100. package/dist/shared-DTPWVlWm.d.cts +39 -0
  101. package/dist/strands.cjs +352 -0
  102. package/dist/strands.cjs.map +1 -0
  103. package/dist/strands.d.cts +72 -0
  104. package/dist/strands.d.ts +72 -0
  105. package/dist/strands.js +347 -0
  106. package/dist/strands.js.map +1 -0
  107. package/dist/twilio.cjs +174 -0
  108. package/dist/twilio.cjs.map +1 -0
  109. package/dist/twilio.d.cts +64 -0
  110. package/dist/twilio.d.ts +64 -0
  111. package/dist/twilio.js +167 -0
  112. package/dist/twilio.js.map +1 -0
  113. package/dist/vapi.cjs +661 -0
  114. package/dist/vapi.cjs.map +1 -0
  115. package/dist/vapi.d.cts +78 -0
  116. package/dist/vapi.d.ts +78 -0
  117. package/dist/vapi.js +656 -0
  118. package/dist/vapi.js.map +1 -0
  119. package/dist/voltagent.cjs +509 -0
  120. package/dist/voltagent.cjs.map +1 -0
  121. package/dist/voltagent.d.cts +70 -0
  122. package/dist/voltagent.d.ts +70 -0
  123. package/dist/voltagent.js +503 -0
  124. package/dist/voltagent.js.map +1 -0
  125. package/dist/webhook-1ozGyksG.d.ts +37 -0
  126. package/dist/webhook-CG4om_DK.d.cts +37 -0
  127. package/dist/whatsapp.cjs +214 -0
  128. package/dist/whatsapp.cjs.map +1 -0
  129. package/dist/whatsapp.d.cts +81 -0
  130. package/dist/whatsapp.d.ts +81 -0
  131. package/dist/whatsapp.js +207 -0
  132. package/dist/whatsapp.js.map +1 -0
  133. package/package.json +351 -6
package/CHANGELOG.md CHANGED
@@ -2,76 +2,168 @@
2
2
 
3
3
  All notable changes to this package are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the package follows [Semantic Versioning](https://semver.org/).
4
4
 
5
- ## [0.1.1] - 2026-09-24
5
+ ## [0.7.0] - 2026-09-30
6
6
 
7
- ### Added
8
-
9
- - The agent's turn carries the usage the model provider reported for the call behind it, as
10
- `usage` (`ModelUsage`: provider, model, prompt tokens with the cached ones included, cached
11
- tokens, tokens written to the cache). `wrap()` reads it from every OpenAI-compatible response
12
- and from the last chunk of a stream that asked for it (`stream_options: { include_usage: true }`),
13
- and never changes the request. Niadra sums it per agent, vendor and model, and the Console shows
14
- the prompt cache's hit rate and estimated savings.
15
- - `agent(text, { usage })` on conversations and tasks takes the provider's response (OpenAI chat
16
- completions or Responses, Anthropic messages) or a `ModelUsage`, for agents that do not use
17
- `wrap()`; `modelUsage()` reads one yourself. A response without usage is left out; the turn is
18
- recorded either way.
19
- - CI runs the build on Deno (with no permissions), Bun, workerd (Cloudflare Workers) and the Vercel
20
- Edge Runtime (`pnpm runtimes`), and the README names them.
21
-
22
- ### Changed
23
-
24
- - `engines` asks for Node 20 or later, the versions the CI tests. The README no longer claims Node 18.
25
- - A conversation turn (a message with a `conversation_id`) leaves the queue at most 200 ms after it
26
- was queued, taking whatever else is waiting along, instead of up to a second: it is what the other
27
- agents read in `live`. `queue.turnFlushIntervalMs` sets it; other items still wait for
28
- `flushIntervalMs` (1 s) or `flushAt` (15).
29
- - The timeline tool says the history comes newest first, as the server returns it, instead of
30
- "in chronological order".
31
- - The search tool no longer offers the model a `system_event` item kind, and its description names
32
- business objects instead of system events: a system event is never an item, it changes its object,
33
- so the filter is `object`. The server still reads `system_event` from 0.1.0 as `object`.
34
- - `open()` sends `POST /v1/history/open` with the item id, the level and the conversation id in the
35
- body, instead of `GET /v1/history/items/{id}` with the conversation id in the query: a
36
- conversation id may be a phone number or an e-mail, and a URL reaches access logs.
37
- - `open()` takes `subject`, the customer the item must belong to; the server opens any other item
38
- as 404. The tool kit passes its bound customer, so `open_history_item` opens only that
39
- customer's items.
40
- - `task_id` on `open()` is no longer sent: the server never read it on this route. The field stays
41
- in `OpenParams` for code written against 0.1.0.
42
- - The `excerpt` field of an opened item says the server no longer sends it.
43
-
44
- ### Fixed
45
-
46
- - Building a client on Deno without `--allow-env` no longer throws: a runtime that refuses to read
47
- the environment now counts as one without `NIADRA_API_KEY` and `NIADRA_BASE_URL`.
48
- - `feedback()` and the reservation in `uploadMedia()` end within `timeouts.write` (5 s) in total,
49
- retries and backoff included, instead of 5 s per attempt.
50
- - The transfer in `uploadMedia()` ends within `timeouts.upload` (60 s) in total instead of per attempt.
51
- - `identify()`, `verify()` and `handoff()` resolve by `timeouts.write` with a `NiadraTimeoutError`
52
- when the queue could not confirm them in time; the item stays queued and is still sent.
53
-
54
- ## [0.1.0] - 2026-09-23
7
+ The agent core. Every turn an agent takes is recorded in its own process; what it says is checked against
8
+ what its tools returned; agents, people and systems coordinate before they contact a customer or act; the
9
+ objects a company's systems push reach the agent as typed state with the freshness to say them; each agent
10
+ keeps its working state; and a company replays turns, derives its types and measures a tool's
11
+ counterfactual in its own CI. The framework adapters record turns. Every feature is off until the space
12
+ turns it on, and a space that did not ask sees no change.
55
13
 
56
- First public release, with the same surface as the Python SDK.
14
+ The versions published before it were previews: nothing of theirs carries over, and none of their names,
15
+ options or fallbacks is kept.
57
16
 
58
17
  ### Added
59
18
 
60
- - `Niadra` client with the endpoint derived from the source key (`https://<space>.<region>.api.niadra.com`), overridable with `baseURL`.
61
- - `context()` with a per-conversation cache: TTL, stale-while-revalidate with one deduplicated refresh per pack, last good value on failure, and ETag revalidation through `known_etag`. 401 and 403 drop cached packs, and a `degraded` answer never replaces a good one. Plain and delta reads of a conversation share one entry, and each delta is handed out once.
62
- - History navigation: `search()`, `timeline()` and `open()`.
63
- - `tools(subject)`: the navigation kit as function-calling definitions, with the customer bound outside the model.
64
- - `subjectToken()` for binding a customer to an MCP session.
65
- - Writes: `track()`, `action()`, `identify()`, `verify()` and `handoff()`, through a bounded queue that batches by count and time, retries with backoff and sends a coverage heartbeat once a minute.
66
- - `conversation()` helper that reads the pack the server pins, asks for deltas after the first read and keeps them until the pack changes, captures turns and emits `conversation.ended`.
67
- - `task()` helper for internal agents that centers its pack on its object, keeps deltas and stamps like a conversation, captures the agent's answers and emits `task.ended`; `verify()` on a task, whose `tools()` follow its level.
68
- - `markInjected()` and `contextStamp` on conversations and tasks: the agent's turns and actions carry the etag of the pack its prompt held and when it went in, as the event's `context_stamp`.
69
- - `wrap()` for OpenAI-compatible clients: injects the pack and the suffix into `chat.completions.create` and `parse` (also under `beta`), stamps the injection, records the answer, streams included, keeps `.withResponse()` working, and never lets a capture failure reach the caller. `injectContext()` places a pack in a message list by the same rule.
70
- - `objectState()` and `objectTimeline()` for business objects.
71
- - `feedback()` to retract or correct a fact, resolve an open item or record a conversation's outcome.
72
- - `uploadMedia()`: reserves an upload, sends the bytes to the signed URL with exactly the headers it names (HTTPS
73
- only, never the key) and resolves with `media_ref` and `media_sha256`; optionally bound to a `subject`.
74
- - Fail-open behavior on every public method, and `strict: true` to throw instead.
75
- - Per-method time budgets, 421 retries for moved spaces, and `problem+json` errors mapped to typed classes.
76
- - Flush on `beforeExit` in Node, `flush()` and `shutdown()` everywhere else.
77
- - Handle builders and wire types for every contract model.
19
+ - `Niadra`, with the endpoint derived from the source key and fail-open behavior on every public method
20
+ (`strict: true` to throw instead), in Node, Deno, Bun, Cloudflare Workers and edge runtimes.
21
+ - `context()` before the model call, cached per conversation and revalidated by ETag, with the customer's
22
+ last turn as `query` (the turn's `slots`), `prefetch()` while the customer speaks, the voice read path,
23
+ `format: "json"` for the pack as data (`context-pack.v1`) and `explain: true` for why each slot was chosen.
24
+ - History navigation (`search()`, `timeline()`, `open()`) and `tools()`, the same navigation as
25
+ function-calling tools bound to one customer, with `subjectToken()` for MCP.
26
+ - Writes through a bounded queue with one batch in flight (`track()`, `action()`, `identify()`, `verify()`,
27
+ `handoff()`), `conversation()` and `task()`, `feedback()`, `feedbackBatch()`, `uploadMedia()`,
28
+ `ingestStatus()`, `whoami()`, `objectState()` (the object as a state read serves it, `ObjectRead`) and
29
+ `objectTimeline()`.
30
+ - Agent memory (`agentMemory()`, `searchAgentMemory()`, `remember()`), backed answers and the guard lines a
31
+ read carries; `niadra.admin` for a key with the `admin` scope.
32
+ - `wrap()` for OpenAI-compatible clients and the adapters under `@niadra/sdk/<integration>`; the n8n and
33
+ Flowise nodes in `packages/`.
34
+ - `niadra.api` (`Api`): one method per route of turn records, replay and scenarios, typed state and the
35
+ agent's working state, subject signals and measurement, and coordination, named in camelCase as the
36
+ server names the operation. Unlike the rest of the client they never fail open.
37
+ - The types of those routes (`TurnRecord`, `StateReadRequest`, `CheckResult` and the rest), generated
38
+ from the server's OpenAPI document by `scripts/sync-spec.ts`.
39
+ - Turn records: `conversation.turn()` records what one turn read, called and said, with the build it ran
40
+ on (`Niadra.build()`), and `tool()` wraps a tool of yours so each call inside a turn is recorded, copied
41
+ as JSON at the moment, with the objects its result showed. The turn in progress follows the async
42
+ context (`AsyncLocalStorage`; `useAsyncLocalStorage()` supplies one where `node:async_hooks` is missing),
43
+ so parallel sub-agents keep their own turns. A bounded queue keeps the closed turns (values of unflagged
44
+ turns go first when it is full) and a background sender posts them to `POST /v1/turns` in the space's
45
+ content mode, with the values in your own bucket in `pointer` mode (`niadra.turns.store()`). Closing a
46
+ turn never waits for the network, and a recorded tool call costs under 2 ms at the 95th percentile.
47
+ - The warm cache for when Niadra is down: `niadra.profile()` keeps the SDK profile (features, claim
48
+ contract); `context({ include: ["constraints", "state"] })` reads the constraints block and the state view
49
+ with the pack, and a failed read serves the last good ones; `niadra.mayContact()` checks an outbound
50
+ contact against the local copy of the suppression list, which keeps applying with Niadra out of reach.
51
+ - The claim contract inside a turn: what the agent says is checked against what its tools returned and
52
+ each claim goes to the turn record with its verdict (count mode never changes an output).
53
+ `conversation.claims.guard(stream)` holds what could start a claim until its sentence ends (150 ms at
54
+ most, 300 ms a message) and lets it go as the contract's actions say: a blocked sentence gives way to the
55
+ category's caveat, a stale copy of one field becomes its fresh value only when that is unequivocal, a
56
+ warning marks the claim. `claims.guardText()` does the same on a whole output. An immutable output never
57
+ changes: a block sends it to a person.
58
+ - Coordination: `conversation.check()` asks before acting and, when Niadra does not answer within 200 ms,
59
+ decides by the purpose's direction (a customer's message and service go, marketing, retention,
60
+ collection and an effect with a key wait, the local opt-out always holds); `conversation.declare` sends
61
+ what happened in the background until Niadra takes it; `conversation.claim()` holds a lease or a task
62
+ lock. `task()` takes the same calls.
63
+ - `niadra.contactGateway()` and `verifyContactToken()`: the contact token's offline check at your gateway
64
+ (Ed25519 through Web Crypto), with the space's public keys kept while Niadra is down and each token let
65
+ through once.
66
+ - The agent's working state: `conversation.agentState.get()` and `put()`, compare-and-swap or merge by key
67
+ (`DELETE` removes a key), reading its own writes, kept and sent again while Niadra is down.
68
+ - `niadra.resolvers` and `verifyClaim()`: a value not safe to claim is read again by your resolver, inside
69
+ your boundary and within 300 ms, and the fresh value decides. `ContentResolver` puts back the text a
70
+ pointer-mode space keeps in your storage, and `ResolverWorker` serves the space's refresh requests with
71
+ your resolvers.
72
+ - Replay inside your boundary: `Replayer` runs the turns of a scenario N times with the build you pin,
73
+ answers your tools from the record (`tool(name, fn, { dryRun: true })` lets one run for real when the
74
+ record has no answer), keeps everything the agent sends from leaving, evaluates the assertions and
75
+ reports the run, and Niadra answers with the statistical verdict. Runs are numbered from 1, as the
76
+ replay spec numbers them.
77
+ - `overlapAtK()`: the depth-weighted overlap of two ranked lists that the tool counterfactual reports
78
+ (`spec/counterfactual.md`, 4); it passes the `counterfactual-overlap` vectors.
79
+ - The recording the SDK profile serves: a turn leaves in the content mode the space names for the source,
80
+ and a turn without a pin the space requires for replay is kept with a warning, once.
81
+ - Turn records from the framework adapters. LangChain.js and LangGraph.js:
82
+ `new NiadraCallbackHandler(conversation, { turns: true })` records each top-level run as a turn, with its
83
+ tool calls (the provider's call ids) and its model calls with their tokens. Mastra:
84
+ `niadraProcessor({ turns: true })` records each request as a turn. Vercel AI SDK: `niadraMiddleware`
85
+ records each model call in the turn in progress, `recordTools(tools)` records each tool call with the
86
+ provider's call id, and `niadraTurn()` keeps a `streamText` turn open until the stream finishes. A run
87
+ inside a turn in progress records into it, and a function wrapped with `tool()` inside a framework's tool
88
+ takes over its call, so a replay answers it from the record.
89
+ - `conversation.activeTurn()`: the turn in progress, from the async context or the newest the session
90
+ opened and has not closed; `tool()` takes `callId` and `frame` for frameworks that run tools elsewhere.
91
+ - `canonicalJson()` and `jsonDigest()`: the digest of a turn record's value, SHA-256 over its canonical
92
+ JSON (RFC 8785), as every producer computes it.
93
+ - `expr`: niadra-expr, the language of the type registry's conditions, timers, keys and readings.
94
+ `expr.parse()` reads an expression, `expr.compileExpression()` resolves its names against a type's
95
+ declarations, and `expr.evaluate()` computes it over an object's slots with the four logical values,
96
+ as the server does; it passes every case of `spec/vectors/niadra-expr.v0.json`. Dates and times are
97
+ integers (days, milliseconds), never the machine's time zone.
98
+ - The conformance vectors of the open specifications, run by `test/vectors.test.ts`, and the design of
99
+ the turn capture (`docs/design/turn-capture.md`).
100
+ - `canonicalDestination()` and `suppressionKey()`: a handle's canonical destination (`phone:+<E.164>`
101
+ with the Brazilian ninth digit, `email:<address>`) and its key per reader,
102
+ `base64url(HMAC-SHA256(salt, ...))`, as the suppression list and the contact token compute them.
103
+ `suppressionKey()` is async (Web Crypto); errors are `NiadraDestinationError`.
104
+ - `exposureToken()` and `parseExposureToken()`: the exposure token a card carries,
105
+ `nx1.<id>.<position>.<verifier>`, built synchronously and read with the refusals of its spec
106
+ (`NiadraExposureTokenError`).
107
+ - `renderConstraints()` and `honoredConstraints()`: the constraints block rendered for one tool call
108
+ through the tool's binding, in advisory or apply mode, and the count of what the call's results
109
+ honored.
110
+ - `claims`: the claim contract's reference checker, pure and without a model. `mentions()` reads the
111
+ numbers of an output in Portuguese, English or Spanish (class, normalized value, span in code points),
112
+ `rolesOf()` their roles, `check()` the claims each category of a contract detects with their nature,
113
+ verdict and action, `detected()` what a phrase of the negative corpus must never trigger, and `score()`
114
+ the text anchor. It passes the claim-parser, claim-detect and claim-anchor vectors and finds nothing in
115
+ the negative corpus of the three example contracts.
116
+ - The `niadra` command for Node (`npx niadra`): `resolver-worker`, `replay`, `counterfactual`,
117
+ `types derive` (with `--check`) and `contract test`, with the Python command's arguments and exit codes.
118
+ `types derive` reads one PostgreSQL table's catalog (never a row), computes the same fingerprint as the
119
+ Python SDK and passes the `type-derive` vectors; `--check` sends Niadra only the fingerprint and the
120
+ counts.
121
+ - The blocks a read asks for reach the model: with `include`, the state view's lines and the constraints
122
+ block go in `suffix` after the slots, inside one `<niadra>` section in the pack's language, byte for byte
123
+ what the Python SDK writes; a read without blocks keeps its suffix. The context answer also carries the
124
+ coordination block.
125
+ - `niadra.internalText`: fingerprints of the company's own prompt (the same SHA-256 shingles as the Python
126
+ SDK); a repeated passage gives way to the claim contract's `redact` line and is recorded with
127
+ `internal_text_found`, never the text.
128
+ - `tool(name, fn, { binding })` records what a call did with the constraints block, and `maskOutput: true`
129
+ keeps the fields the key may not read from the model (the last profile read while Niadra is down,
130
+ `onUnknown: "block"` to fail closed). A turn keeps the pack, the block and the working state it read, and
131
+ what the person was shown or engaged with (`frame.interact`).
132
+ - The tool counterfactual: `Counterfactual` behaves as the Python runner, sending Niadra only overlaps and
133
+ positions.
134
+ - A replay starts from the working state the recorded turn read, and a sub-turn of a replayed turn is
135
+ replayed and never sent. Mastra tools answer from the record; LangChain tools passed through
136
+ `recordTools()` too, and the handler refuses any other with `NiadraReplayRefusedError` before it runs.
137
+ - Turn records from OpenAI Agents JS, Google ADK and VoltAgent with `turns: true`: each run is a turn, with
138
+ each tool call (the framework's own call id) and each model call. ADK tools answer from the record in a
139
+ replay; OpenAI Agents JS and VoltAgent cannot stop a tool from their hooks, so wrap those tools with
140
+ `tool()` to replay them.
141
+ - One example per concept of the agent core (`examples/claim-guard.ts`, `coordination.ts`, `object-state.ts`,
142
+ `working-state.ts`, `masked-tool.ts`, `tool-counterfactual.ts`) and `examples/ci/niadra-checks.yml`, each
143
+ run by the tests.
144
+ - `ContextResponse.budget` (`BudgetBlock`, with `BudgetPack`, `BudgetUse` and `BudgetCut`): with
145
+ `include: ["budget"]`, what the pack costs per section, what this agent already spent in the conversation
146
+ and the case, and the units the measurement says it leaves unused. Shown, never enforced.
147
+ - `niadra.api.overview()`: the coordination overview in counts (`GET /v1/coordination/overview`).
148
+ - `pnpm sync-spec --spec` also copies the Context Pack schema (`spec/context-pack.v1.json`), and
149
+ `test/spec.test.ts` holds `ContextResponse` and every include block to it.
150
+ - The tool bindings the space declares come in the SDK profile (`SdkProfile.tool_bindings`, typed
151
+ `ToolBinding`), for this source's tools. A tool without a binding in code measures the constraints block
152
+ and runs its counterfactual through the binding served for its name, and `binding` in code wins.
153
+ Left unset, `maskOutput` follows the served binding's `capabilities.mask_output`. `api.constraints()` with
154
+ `tool` answers the block rendered for that tool, as advice.
155
+ - Watch revalidation in `ResolverWorker` and `npx niadra resolver-worker`: a watch fires only on a value its
156
+ source confirmed. The worker serves `watch_revalidation` requests first, pushes every object it read with
157
+ the `request_id` it answers (which settles the request and decides the object's due watches even when the
158
+ value did not change), and releases a request it cannot answer
159
+ (`POST /v1/state/refresh-requests/{id}/release`), as `not_found` when the resolver returns `NOT_FOUND` and
160
+ `failed` when it fails. A type without a resolver, or whose resolver's circuit is open, still waits out its
161
+ lease. `Resolvers.fetch()` says why a read brought no object.
162
+ - `ConstraintsBlock.text`: the constraints block as the server writes it for a model, each field by its
163
+ type's label and each operator in words, in the space's language. The suffix places it as it places the
164
+ state view's text.
165
+ - The claim contract reads the computed values a state read serves as evidence, by their name, while they
166
+ are claim-safe, and the claim guard takes as evidence every value the include blocks placed in the turn
167
+ block. A value that is not claim-safe backs nothing.
168
+ - A hedged number is no claim (the claim contract spec, 5.4): "I can't confirm the $24.90 still applies" or
169
+ "$689.00, not $612.00" state no such price.