@niadra/sdk 0.7.0 → 0.9.1

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 (125) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +55 -7
  3. package/dist/ai-sdk.cjs +3 -4
  4. package/dist/ai-sdk.cjs.map +1 -1
  5. package/dist/ai-sdk.d.cts +3 -3
  6. package/dist/ai-sdk.d.ts +3 -3
  7. package/dist/ai-sdk.js +3 -4
  8. package/dist/ai-sdk.js.map +1 -1
  9. package/dist/anthropic.cjs +1 -1
  10. package/dist/anthropic.cjs.map +1 -1
  11. package/dist/anthropic.d.cts +4 -4
  12. package/dist/anthropic.d.ts +4 -4
  13. package/dist/anthropic.js +1 -1
  14. package/dist/anthropic.js.map +1 -1
  15. package/dist/bedrock.cjs +1 -1
  16. package/dist/bedrock.cjs.map +1 -1
  17. package/dist/bedrock.d.cts +4 -4
  18. package/dist/bedrock.d.ts +4 -4
  19. package/dist/bedrock.js +1 -1
  20. package/dist/bedrock.js.map +1 -1
  21. package/dist/cli.js +157 -60
  22. package/dist/cli.js.map +1 -1
  23. package/dist/{client-DsIxZxZk.d.cts → client-CWMxmJHs.d.cts} +91 -28
  24. package/dist/{client-DsIxZxZk.d.ts → client-CWMxmJHs.d.ts} +91 -28
  25. package/dist/cloudflare-agents.cjs +1 -1
  26. package/dist/cloudflare-agents.cjs.map +1 -1
  27. package/dist/cloudflare-agents.d.cts +3 -3
  28. package/dist/cloudflare-agents.d.ts +3 -3
  29. package/dist/cloudflare-agents.js +1 -1
  30. package/dist/cloudflare-agents.js.map +1 -1
  31. package/dist/elevenlabs.cjs +1 -1
  32. package/dist/elevenlabs.cjs.map +1 -1
  33. package/dist/elevenlabs.d.cts +5 -5
  34. package/dist/elevenlabs.d.ts +5 -5
  35. package/dist/elevenlabs.js +1 -1
  36. package/dist/elevenlabs.js.map +1 -1
  37. package/dist/genkit.cjs +1 -1
  38. package/dist/genkit.cjs.map +1 -1
  39. package/dist/genkit.d.cts +3 -3
  40. package/dist/genkit.d.ts +3 -3
  41. package/dist/genkit.js +1 -1
  42. package/dist/genkit.js.map +1 -1
  43. package/dist/google-adk.cjs +1 -1
  44. package/dist/google-adk.cjs.map +1 -1
  45. package/dist/google-adk.d.cts +3 -3
  46. package/dist/google-adk.d.ts +3 -3
  47. package/dist/google-adk.js +1 -1
  48. package/dist/google-adk.js.map +1 -1
  49. package/dist/google-genai.cjs +1 -1
  50. package/dist/google-genai.cjs.map +1 -1
  51. package/dist/google-genai.d.cts +4 -4
  52. package/dist/google-genai.d.ts +4 -4
  53. package/dist/google-genai.js +1 -1
  54. package/dist/google-genai.js.map +1 -1
  55. package/dist/index.cjs +156 -57
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.cts +6 -8
  58. package/dist/index.d.ts +6 -8
  59. package/dist/index.js +156 -57
  60. package/dist/index.js.map +1 -1
  61. package/dist/{intercept-D7qFCaRb.d.ts → intercept-Bv0nLpSw.d.ts} +1 -1
  62. package/dist/{intercept-0_lJE6k1.d.cts → intercept-CGngQI8B.d.cts} +1 -1
  63. package/dist/langchain.cjs +3 -4
  64. package/dist/langchain.cjs.map +1 -1
  65. package/dist/langchain.d.cts +3 -3
  66. package/dist/langchain.d.ts +3 -3
  67. package/dist/langchain.js +3 -4
  68. package/dist/langchain.js.map +1 -1
  69. package/dist/livekit.cjs +1 -1
  70. package/dist/livekit.cjs.map +1 -1
  71. package/dist/livekit.d.cts +3 -3
  72. package/dist/livekit.d.ts +3 -3
  73. package/dist/livekit.js +1 -1
  74. package/dist/livekit.js.map +1 -1
  75. package/dist/llamaindex.cjs +1 -1
  76. package/dist/llamaindex.cjs.map +1 -1
  77. package/dist/llamaindex.d.cts +3 -3
  78. package/dist/llamaindex.d.ts +3 -3
  79. package/dist/llamaindex.js +1 -1
  80. package/dist/llamaindex.js.map +1 -1
  81. package/dist/mastra.cjs +3 -4
  82. package/dist/mastra.cjs.map +1 -1
  83. package/dist/mastra.d.cts +3 -3
  84. package/dist/mastra.d.ts +3 -3
  85. package/dist/mastra.js +3 -4
  86. package/dist/mastra.js.map +1 -1
  87. package/dist/openai-agents.cjs +1 -1
  88. package/dist/openai-agents.cjs.map +1 -1
  89. package/dist/openai-agents.d.cts +3 -3
  90. package/dist/openai-agents.d.ts +3 -3
  91. package/dist/openai-agents.js +1 -1
  92. package/dist/openai-agents.js.map +1 -1
  93. package/dist/retell.cjs +1 -1
  94. package/dist/retell.cjs.map +1 -1
  95. package/dist/retell.d.cts +5 -5
  96. package/dist/retell.d.ts +5 -5
  97. package/dist/retell.js +1 -1
  98. package/dist/retell.js.map +1 -1
  99. package/dist/{shared-Bb5B59Bu.d.ts → shared-B4Ef2Wpg.d.ts} +1 -1
  100. package/dist/{shared-DTPWVlWm.d.cts → shared-Cq8mz-7m.d.cts} +1 -1
  101. package/dist/strands.cjs +1 -1
  102. package/dist/strands.cjs.map +1 -1
  103. package/dist/strands.d.cts +3 -3
  104. package/dist/strands.d.ts +3 -3
  105. package/dist/strands.js +1 -1
  106. package/dist/strands.js.map +1 -1
  107. package/dist/twilio.d.cts +4 -4
  108. package/dist/twilio.d.ts +4 -4
  109. package/dist/vapi.cjs +1 -1
  110. package/dist/vapi.cjs.map +1 -1
  111. package/dist/vapi.d.cts +5 -5
  112. package/dist/vapi.d.ts +5 -5
  113. package/dist/vapi.js +1 -1
  114. package/dist/vapi.js.map +1 -1
  115. package/dist/voltagent.cjs +1 -1
  116. package/dist/voltagent.cjs.map +1 -1
  117. package/dist/voltagent.d.cts +3 -3
  118. package/dist/voltagent.d.ts +3 -3
  119. package/dist/voltagent.js +1 -1
  120. package/dist/voltagent.js.map +1 -1
  121. package/dist/{webhook-CG4om_DK.d.cts → webhook-jTx_SegV.d.cts} +1 -1
  122. package/dist/{webhook-1ozGyksG.d.ts → webhook-z2TjUzjv.d.ts} +1 -1
  123. package/dist/whatsapp.d.cts +2 -2
  124. package/dist/whatsapp.d.ts +2 -2
  125. package/package.json +3 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,64 @@
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
+ ## [Unreleased]
6
+
7
+ ## [0.9.1] - 2026-10-02
8
+
9
+ ### Changed
10
+
11
+ - The canonical phone of the suppression list follows the revised rules of the suppression spec (3.1 and 3.4): Mexico's and Argentina's mobile prefixes, an 11-digit North American number, a carrier code, `(0)`, `tel:` and direction marks. The key the SDK computes for an opted-out contact matches the server's again.
12
+
13
+ ### Added
14
+
15
+ - A route or field the API deprecates answers with the `Deprecation`, `Sunset` and `Link` headers; the
16
+ client logs one warning per deprecated route per process through its `logger`, with the two dates and the
17
+ migration note, never the path.
18
+
19
+ ## [0.9.0] - 2026-09-30
20
+
21
+ ### Added
22
+
23
+ - `ContextResult.ageMs`: how long ago Niadra sent or confirmed the pack a read served. It is 0 for an answer
24
+ just received and grows while the cache serves the pack (`cache`, `stale`, or `fallback` with Niadra down).
25
+ - The chaos test (`test/chaos.test.ts`): Niadra's process killed, its network gone silent, answering 503 and
26
+ answering past the deadline, in the middle of a conversation.
27
+ - A state read's objects carry `derived`: the type's derived fields over its related objects (a look's
28
+ `all_pieces_available`), computed at the read, each with `v`, `logic`, `over` and `unknown`
29
+ (`DerivedState`). A shared object of a derived type carries `derived_status`, and its push's `inputs` name
30
+ shared objects.
31
+
32
+ ### Fixed
33
+
34
+ - The local copy of the suppression list is read to its end against the server: a page shorter than the limit
35
+ ends a read, and its cursor is where the next read starts. The server names the cursor on the last page
36
+ too, so the copy read 50 pages of nothing and was never held: `mayContact()` and a check that Niadra did not
37
+ answer fell back on the purpose's direction. The stand-in cell answers as the server does.
38
+ - A batch of events that still fails after its attempts with an error that may pass goes back to the front of
39
+ the queue and leaves again after a pause, doubling up to a minute, instead of being dropped: what an agent
40
+ said during an outage longer than a few seconds reached Niadra only in part.
41
+ - A check about an outbound contact keeps the local copy of the suppression list, read in the background once
42
+ a minute. Before, only `mayContact()` read it, so an agent that only called `check()` had no copy when Niadra
43
+ went down, and a purpose that fails open (`service`, `transactional`) went out to a customer who had opted
44
+ out of it.
45
+
46
+ ## [0.8.0] - 2026-09-30
47
+
48
+ ### Added
49
+
50
+ - The claim guard takes the offers a context read served as evidence: each object in the constraints block's
51
+ `already_presented` carries the numbers it was last shown with (`values`: price, total, discount,
52
+ installment), each with its role and whether it may be claimed now, and `blockValues()` turns them into
53
+ values the guard checks a number against, as it checks a tool's result. An offer shown too long ago to claim makes the
54
+ number `stale`, and a price only the pack's text states is still `unsupported`. The constraints block's
55
+ `Shown` model gains `values` (`ShownValue`).
56
+
57
+ ### Removed
58
+
59
+ - `tool(..., { binding })`, `new Counterfactual(..., { bindings })` and `niadra counterfactual --bindings`: a
60
+ tool's binding comes only from the space's `tool-bindings` document, which the SDK profile serves. A
61
+ counterfactual for a tool the space does not bind stops before calling it.
62
+
5
63
  ## [0.7.0] - 2026-09-30
6
64
 
7
65
  The agent core. Every turn an agent takes is recorded in its own process; what it says is checked against
package/README.md CHANGED
@@ -77,6 +77,45 @@ ESM and CommonJS builds with full type definitions; it only needs `fetch`.
77
77
  | `objectState()`, `objectTimeline()` | a business object (an order, an invoice, a ticket) as the systems of record reported it |
78
78
  | `feedback()` | a correction of what Niadra derived, audited like any other event |
79
79
 
80
+ ## Benchmark
81
+
82
+ Niadra and ten other memory systems for agents (thirteen configurations) were measured on the same dataset, in the same AWS region
83
+ (us-east-2), with the same agent and the same judge for every system. The script, the dataset and every
84
+ result file are in this repository, under [`benchmarks/`](https://github.com/ainiadra/niadra-sdk-python/tree/main/benchmarks),
85
+ so anyone can run it again. The full page, with every metric and where Niadra does not lead, is at
86
+ [niadra.com/benchmark](https://niadra.com/benchmark).
87
+
88
+ Combined run of 01/10/2026 ([`2026-09-30-abb516`](https://github.com/ainiadra/niadra-sdk-python/tree/main/benchmarks/results/2026-09-30-abb516)),
89
+ cross-channel accuracy on the same 165 valid cases, judged by the same model:
90
+
91
+ | System | Accuracy | Model spend per 1,000 conversations |
92
+ |---|---|---|
93
+ | **Niadra** (3 repetitions) | **98.7%** | **US$ 0.36** |
94
+ | Hindsight | 86.7% | US$ 6.10 |
95
+ | Amazon Bedrock AgentCore Memory (3 repetitions) | 80% | US$ 7.50 (AWS public price, its models included) |
96
+ | Honcho (dialectic) | 79.4% | US$ 6.92 |
97
+ | Mem0 open source (3 repetitions) | 77.6% | US$ 1.88 |
98
+ | Memobase | 77% | US$ 4.13 |
99
+ | Supermemory local | 71.6% | US$ 5.78 |
100
+ | Cognee | 70.3% | US$ 6.95 |
101
+ | LangMem | 66.7% | US$ 3.70 |
102
+ | Graphiti | 52.8% | US$ 18.72 |
103
+ | MemOS | 51.6% | US$ 3.70 |
104
+
105
+ With a different user id on each channel (agents from different vendors), Mem0 open source drops to
106
+ 28.5%, AgentCore Memory to 27.9%, and Niadra stays at 98.7%. Sensitive values reaching an unverified
107
+ conversation: Niadra 0 of 32; Mem0 and AgentCore Memory 32 of 32.
108
+
109
+ Typed state ([`typed/2026-09-30-b59a5d`](https://github.com/ainiadra/niadra-sdk-python/tree/main/benchmarks/results/typed/2026-09-30-b59a5d)):
110
+ with the state and constraints blocks, 84.9% correct [78, 90] against 36.6% without them; declared
111
+ constraints respected went from 0% to 94.4%, and what changed since the customer last saw it from 0% to
112
+ 100%, with no extra tokens on a turn that asks for no block.
113
+
114
+ Where Niadra does not lead in that run: ingest acknowledgement against systems that write in the
115
+ background, opening a single history item, history search p95 against LangMem by a few ms, and tokens per
116
+ turn against readers that return answer text. The benchmark is produced by Niadra; that is why every input
117
+ and output is public.
118
+
80
119
  ## Questions people ask
81
120
 
82
121
  **How do I give my AI agent memory of past conversations on other channels?** Record the turns
@@ -691,10 +730,11 @@ await convo.turn({ build: Niadra.build({ prompts: { store: "v16" }, model: "gpt-
691
730
  without `include` keeps its suffix. With Niadra down, the last good blocks serve.
692
731
  - **Coordination** decides by each purpose's direction when Niadra does not answer within 200 ms: a
693
732
  customer's message and service go, marketing, retention, collection and an effect with a key wait, and
694
- the local copy of the opt-out list always holds.
695
- - **Tool bindings** the space declares come in the SDK profile: a tool without `binding` in code measures the
696
- constraints block through the one served for its name, and its `capabilities.mask_output` decides the
697
- masking when the code leaves `maskOutput` unset.
733
+ the local copy of the opt-out list always holds. Every check about an outbound contact keeps that copy,
734
+ read again in the background once a minute.
735
+ - **Tool bindings** live in the space's `tool-bindings` document and come in the SDK profile, never in code: a
736
+ tool measures the constraints block through the one served for its name, the counterfactual runs through it,
737
+ and its `capabilities.mask_output` decides the masking when the code leaves `maskOutput` unset.
698
738
  - **The `niadra` command** (Node) runs `replay`, `counterfactual`, `resolver-worker` (the space's refresh
699
739
  requests, read with your resolvers inside your boundary; a watch fires only on a value the worker
700
740
  confirmed, and a resolver returns `NOT_FOUND` when the source no longer has the object), `types derive` and
@@ -714,10 +754,16 @@ Memory should make an agent better, never make it fail. By default:
714
754
  | 401 or 403 | Not treated as an outage: the cached packs are dropped (all of them on 401, the one requested on 403) and `context()` returns empty. Revoking a key also stops what the process had cached. |
715
755
  | 421 (the space moved to another cell) | Retried at once, up to three attempts. |
716
756
  | 429 on a batch | Retried after `Retry-After`. |
717
- | Batch failure | Retried with exponential backoff and jitter, three attempts. 4xx answers other than 408, 421 and 429 are never retried. A batch that still fails is dropped and logged. |
757
+ | Batch failure | Retried with exponential backoff and jitter, three attempts. 4xx answers other than 408, 421 and 429 are never retried. A batch that still fails goes back to the front of the queue and leaves again after a pause that doubles, up to a minute, while Niadra stays down; each event keeps its idempotency key, so it is stored once. |
718
758
  | Queue full (10,000 items) | New events are dropped and logged. |
719
759
  | Server rejects one item of a batch (207) | Only that item fails; the rest are stored. |
720
760
 
761
+ With Niadra down, a read serves the conversation's last good pack (`source: "fallback"`) with `ageMs`
762
+ saying how old it is; the opt-out holds by the local copy of the suppression list; turn records, events
763
+ and declarations wait in their queues and leave once Niadra answers again, each stored once.
764
+ `test/chaos.test.ts` kills Niadra's process, silences its network, answers 503 and answers late in the
765
+ middle of a conversation, and checks all of it.
766
+
721
767
  Every call you wait for has its own time budget for the whole call, retries and waits included, independent of your platform's:
722
768
 
723
769
  | Call | Default |
@@ -729,7 +775,7 @@ Every call you wait for has its own time budget for the whole call, retries and
729
775
  | `identify()`, `verify()`, `handoff()`, `feedback()` and the reservation in `uploadMedia()` | 5 s |
730
776
  | The transfer in `uploadMedia()` | 60 s |
731
777
 
732
- An `identify()`, `verify()` or `handoff()` that runs out of time resolves with a `NiadraTimeoutError` and stays in the queue, which keeps sending it. `track()` never waits; each attempt of a background batch has 5 s. Override them with `timeouts`, or per call with `{ timeout }`. Pass `{ signal }` to cancel a call.
778
+ An `identify()`, `verify()` or `handoff()` that runs out of time, or that Niadra cannot take for now (a network error, a 5xx), resolves with that error and stays in the queue, which keeps sending it. `track()` never waits; each attempt of a background batch has 5 s. Override them with `timeouts`, or per call with `{ timeout }`. Pass `{ signal }` to cancel a call.
733
779
 
734
780
  ### The context cache
735
781
 
@@ -740,6 +786,8 @@ Inside a conversation or task, packs are cached in memory:
740
786
  - when a request fails: the last good pack, if it is less than 30 minutes old;
741
787
  - at most 1,000 packs, the least recently used evicted first.
742
788
 
789
+ `source` says which of these served the read, and `ageMs` how long ago Niadra sent or confirmed that pack.
790
+
743
791
  Refreshes send the cached ETag, so an unchanged pack costs a `not_modified` answer instead of the
744
792
  full text, and only one background refresh per pack runs at a time. A 401 or 403 is not an
745
793
  outage: the cached packs go (all of them on 401, the one requested on 403), so cutting a vendor's
@@ -789,7 +837,7 @@ Include `requestId` when you contact support.
789
837
 
790
838
  ```sh
791
839
  pnpm install
792
- pnpm check # typecheck, lint, tests (the integrations with their frameworks' real types)
840
+ pnpm check # typecheck, lint, tests (the integrations with their frameworks' real types), audit of the runtime dependencies
793
841
  pnpm build # ESM and CommonJS into dist/, one entry per integration
794
842
  pnpm runtimes # the build on Deno, Bun, workerd and the Edge Runtime
795
843
  pnpm --filter "./packages/*" check # the n8n and Flowise nodes
package/dist/ai-sdk.cjs CHANGED
@@ -385,7 +385,7 @@ function thenable(value) {
385
385
  function tool(name, fn, options = {}) {
386
386
  const isAsync = isAsyncFunction(fn);
387
387
  function bindingOf(frame) {
388
- return options.binding ?? (options.served ?? frame?.profile.bindings)?.(name) ?? null;
388
+ return (options.served ?? frame?.profile.bindings)?.(name) ?? null;
389
389
  }
390
390
  function masks(frame) {
391
391
  return options.maskOutput ?? bindingOf(frame)?.capabilities?.mask_output ?? false;
@@ -500,8 +500,7 @@ function tool(name, fn, options = {}) {
500
500
  const marker = {
501
501
  name,
502
502
  dryRun: options.dryRun ?? false,
503
- provenance: options.provenance ?? null,
504
- binding: options.binding ?? null
503
+ provenance: options.provenance ?? null
505
504
  };
506
505
  Object.defineProperty(wrapped, RECORDED, { value: marker });
507
506
  return wrapped;
@@ -527,7 +526,7 @@ function measure(frame, raw, args) {
527
526
 
528
527
  // src/context.ts
529
528
  function emptyResult(error) {
530
- return { text: "", suffix: "", variables: {}, pack: null, source: "none", response: null, error, constraints: null, state: null, coordination: null };
529
+ return { text: "", suffix: "", variables: {}, pack: null, source: "none", ageMs: null, response: null, error, constraints: null, state: null, coordination: null };
531
530
  }
532
531
 
533
532
  // src/integrations/shared.ts