@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.
- package/CHANGELOG.md +58 -0
- package/README.md +55 -7
- package/dist/ai-sdk.cjs +3 -4
- package/dist/ai-sdk.cjs.map +1 -1
- package/dist/ai-sdk.d.cts +3 -3
- package/dist/ai-sdk.d.ts +3 -3
- package/dist/ai-sdk.js +3 -4
- package/dist/ai-sdk.js.map +1 -1
- package/dist/anthropic.cjs +1 -1
- package/dist/anthropic.cjs.map +1 -1
- package/dist/anthropic.d.cts +4 -4
- package/dist/anthropic.d.ts +4 -4
- package/dist/anthropic.js +1 -1
- package/dist/anthropic.js.map +1 -1
- package/dist/bedrock.cjs +1 -1
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts +4 -4
- package/dist/bedrock.d.ts +4 -4
- package/dist/bedrock.js +1 -1
- package/dist/bedrock.js.map +1 -1
- package/dist/cli.js +157 -60
- package/dist/cli.js.map +1 -1
- package/dist/{client-DsIxZxZk.d.cts → client-CWMxmJHs.d.cts} +91 -28
- package/dist/{client-DsIxZxZk.d.ts → client-CWMxmJHs.d.ts} +91 -28
- package/dist/cloudflare-agents.cjs +1 -1
- package/dist/cloudflare-agents.cjs.map +1 -1
- package/dist/cloudflare-agents.d.cts +3 -3
- package/dist/cloudflare-agents.d.ts +3 -3
- package/dist/cloudflare-agents.js +1 -1
- package/dist/cloudflare-agents.js.map +1 -1
- package/dist/elevenlabs.cjs +1 -1
- package/dist/elevenlabs.cjs.map +1 -1
- package/dist/elevenlabs.d.cts +5 -5
- package/dist/elevenlabs.d.ts +5 -5
- package/dist/elevenlabs.js +1 -1
- package/dist/elevenlabs.js.map +1 -1
- package/dist/genkit.cjs +1 -1
- package/dist/genkit.cjs.map +1 -1
- package/dist/genkit.d.cts +3 -3
- package/dist/genkit.d.ts +3 -3
- package/dist/genkit.js +1 -1
- package/dist/genkit.js.map +1 -1
- package/dist/google-adk.cjs +1 -1
- package/dist/google-adk.cjs.map +1 -1
- package/dist/google-adk.d.cts +3 -3
- package/dist/google-adk.d.ts +3 -3
- package/dist/google-adk.js +1 -1
- package/dist/google-adk.js.map +1 -1
- package/dist/google-genai.cjs +1 -1
- package/dist/google-genai.cjs.map +1 -1
- package/dist/google-genai.d.cts +4 -4
- package/dist/google-genai.d.ts +4 -4
- package/dist/google-genai.js +1 -1
- package/dist/google-genai.js.map +1 -1
- package/dist/index.cjs +156 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -8
- package/dist/index.d.ts +6 -8
- package/dist/index.js +156 -57
- package/dist/index.js.map +1 -1
- package/dist/{intercept-D7qFCaRb.d.ts → intercept-Bv0nLpSw.d.ts} +1 -1
- package/dist/{intercept-0_lJE6k1.d.cts → intercept-CGngQI8B.d.cts} +1 -1
- package/dist/langchain.cjs +3 -4
- package/dist/langchain.cjs.map +1 -1
- package/dist/langchain.d.cts +3 -3
- package/dist/langchain.d.ts +3 -3
- package/dist/langchain.js +3 -4
- package/dist/langchain.js.map +1 -1
- package/dist/livekit.cjs +1 -1
- package/dist/livekit.cjs.map +1 -1
- package/dist/livekit.d.cts +3 -3
- package/dist/livekit.d.ts +3 -3
- package/dist/livekit.js +1 -1
- package/dist/livekit.js.map +1 -1
- package/dist/llamaindex.cjs +1 -1
- package/dist/llamaindex.cjs.map +1 -1
- package/dist/llamaindex.d.cts +3 -3
- package/dist/llamaindex.d.ts +3 -3
- package/dist/llamaindex.js +1 -1
- package/dist/llamaindex.js.map +1 -1
- package/dist/mastra.cjs +3 -4
- package/dist/mastra.cjs.map +1 -1
- package/dist/mastra.d.cts +3 -3
- package/dist/mastra.d.ts +3 -3
- package/dist/mastra.js +3 -4
- package/dist/mastra.js.map +1 -1
- package/dist/openai-agents.cjs +1 -1
- package/dist/openai-agents.cjs.map +1 -1
- package/dist/openai-agents.d.cts +3 -3
- package/dist/openai-agents.d.ts +3 -3
- package/dist/openai-agents.js +1 -1
- package/dist/openai-agents.js.map +1 -1
- package/dist/retell.cjs +1 -1
- package/dist/retell.cjs.map +1 -1
- package/dist/retell.d.cts +5 -5
- package/dist/retell.d.ts +5 -5
- package/dist/retell.js +1 -1
- package/dist/retell.js.map +1 -1
- package/dist/{shared-Bb5B59Bu.d.ts → shared-B4Ef2Wpg.d.ts} +1 -1
- package/dist/{shared-DTPWVlWm.d.cts → shared-Cq8mz-7m.d.cts} +1 -1
- package/dist/strands.cjs +1 -1
- package/dist/strands.cjs.map +1 -1
- package/dist/strands.d.cts +3 -3
- package/dist/strands.d.ts +3 -3
- package/dist/strands.js +1 -1
- package/dist/strands.js.map +1 -1
- package/dist/twilio.d.cts +4 -4
- package/dist/twilio.d.ts +4 -4
- package/dist/vapi.cjs +1 -1
- package/dist/vapi.cjs.map +1 -1
- package/dist/vapi.d.cts +5 -5
- package/dist/vapi.d.ts +5 -5
- package/dist/vapi.js +1 -1
- package/dist/vapi.js.map +1 -1
- package/dist/voltagent.cjs +1 -1
- package/dist/voltagent.cjs.map +1 -1
- package/dist/voltagent.d.cts +3 -3
- package/dist/voltagent.d.ts +3 -3
- package/dist/voltagent.js +1 -1
- package/dist/voltagent.js.map +1 -1
- package/dist/{webhook-CG4om_DK.d.cts → webhook-jTx_SegV.d.cts} +1 -1
- package/dist/{webhook-1ozGyksG.d.ts → webhook-z2TjUzjv.d.ts} +1 -1
- package/dist/whatsapp.d.cts +2 -2
- package/dist/whatsapp.d.ts +2 -2
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -503,7 +503,7 @@ function internalRecord(span, ref, act) {
|
|
|
503
503
|
}
|
|
504
504
|
|
|
505
505
|
// src/version.ts
|
|
506
|
-
var VERSION = "0.
|
|
506
|
+
var VERSION = "0.9.1";
|
|
507
507
|
|
|
508
508
|
// src/transport.ts
|
|
509
509
|
var RETRYABLE_WRITE_STATUS = /* @__PURE__ */ new Set([408, 421, 429, 500, 502, 503, 504]);
|
|
@@ -597,6 +597,7 @@ var Transport = class {
|
|
|
597
597
|
} catch (error) {
|
|
598
598
|
throw deadline.explain(error);
|
|
599
599
|
}
|
|
600
|
+
warnIfDeprecated(this.config.logger, init.method ?? "GET", url, response.headers);
|
|
600
601
|
const requestId = response.headers.get("x-request-id");
|
|
601
602
|
let payload;
|
|
602
603
|
try {
|
|
@@ -666,6 +667,29 @@ var Deadline = class {
|
|
|
666
667
|
return new NiadraConnectionError(`connection failed: ${message}`, { cause: error });
|
|
667
668
|
}
|
|
668
669
|
};
|
|
670
|
+
var VERSIONING_DOCS = "https://docs.niadra.com/en/security/api-versioning";
|
|
671
|
+
var DEPRECATION_LINK = /<([^>]*)>[^,]*;\s*rel="?deprecation"?/gi;
|
|
672
|
+
var deprecationsSeen = /* @__PURE__ */ new Set();
|
|
673
|
+
function warnIfDeprecated(logger, method, url, headers) {
|
|
674
|
+
const since = headers.get("deprecation");
|
|
675
|
+
if (since === null) return;
|
|
676
|
+
const links = [...(headers.get("link") ?? "").matchAll(DEPRECATION_LINK)].map((match) => match[1] ?? "");
|
|
677
|
+
const key2 = `${method} ${links.join(" ") || (url.split("?")[0] ?? url)}`;
|
|
678
|
+
if (deprecationsSeen.has(key2)) return;
|
|
679
|
+
deprecationsSeen.add(key2);
|
|
680
|
+
const sunset = headers.get("sunset");
|
|
681
|
+
logger.warn(
|
|
682
|
+
`the API deprecated a ${method} route this client calls, since ${deprecatedSince(since)}; it stops answering on ${sunset === null ? "a date not announced yet" : sunsetDay(sunset)}. See ${links.join(", ") || VERSIONING_DOCS}`
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
function deprecatedSince(value) {
|
|
686
|
+
const seconds = Number(value.trim().replace(/^@/, ""));
|
|
687
|
+
return Number.isInteger(seconds) ? new Date(seconds * 1e3).toISOString().slice(0, 10) : value;
|
|
688
|
+
}
|
|
689
|
+
function sunsetDay(value) {
|
|
690
|
+
const time = Date.parse(value);
|
|
691
|
+
return Number.isNaN(time) ? value : new Date(time).toISOString().slice(0, 10);
|
|
692
|
+
}
|
|
669
693
|
async function readBody(response) {
|
|
670
694
|
const text2 = await response.text();
|
|
671
695
|
if (text2.length === 0) return null;
|
|
@@ -2885,6 +2909,11 @@ ${change.field}`)) out.push({ ref, field: change.field, value: change.now, claim
|
|
|
2885
2909
|
for (const s of constraints.soft ?? []) said.push([s.attr, s.value]);
|
|
2886
2910
|
for (const a of constraints.attributes ?? []) said.push([a.name, a.value]);
|
|
2887
2911
|
for (const [attr, value] of said) out.push({ ref: null, field: attr.split(".").pop() ?? attr, value, claimSafe: true });
|
|
2912
|
+
for (const shown of constraints.already_presented ?? []) {
|
|
2913
|
+
for (const [field, n] of Object.entries(shown.values ?? {})) {
|
|
2914
|
+
out.push({ ref: shown.ref, field, value: n.v, claimSafe: n.claim_safe, role: n.role ?? null });
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2888
2917
|
}
|
|
2889
2918
|
return out;
|
|
2890
2919
|
}
|
|
@@ -3251,7 +3280,7 @@ function thenable(value) {
|
|
|
3251
3280
|
function tool(name, fn, options = {}) {
|
|
3252
3281
|
const isAsync = isAsyncFunction(fn);
|
|
3253
3282
|
function bindingOf(frame) {
|
|
3254
|
-
return
|
|
3283
|
+
return (options.served ?? frame?.profile.bindings)?.(name) ?? null;
|
|
3255
3284
|
}
|
|
3256
3285
|
function masks(frame) {
|
|
3257
3286
|
return options.maskOutput ?? bindingOf(frame)?.capabilities?.mask_output ?? false;
|
|
@@ -3366,8 +3395,7 @@ function tool(name, fn, options = {}) {
|
|
|
3366
3395
|
const marker = {
|
|
3367
3396
|
name,
|
|
3368
3397
|
dryRun: options.dryRun ?? false,
|
|
3369
|
-
provenance: options.provenance ?? null
|
|
3370
|
-
binding: options.binding ?? null
|
|
3398
|
+
provenance: options.provenance ?? null
|
|
3371
3399
|
};
|
|
3372
3400
|
Object.defineProperty(wrapped, RECORDED, { value: marker });
|
|
3373
3401
|
return wrapped;
|
|
@@ -3629,6 +3657,7 @@ function claimsOf(frame, claims, logger) {
|
|
|
3629
3657
|
|
|
3630
3658
|
// src/queue.ts
|
|
3631
3659
|
var HEARTBEAT_WINDOW_MS = 6e4;
|
|
3660
|
+
var MAX_PAUSE_MS = 6e4;
|
|
3632
3661
|
var EventQueue = class {
|
|
3633
3662
|
constructor(send, options, logger, now = Date.now) {
|
|
3634
3663
|
this.send = send;
|
|
@@ -3649,6 +3678,8 @@ var EventQueue = class {
|
|
|
3649
3678
|
droppedSinceWarning = 0;
|
|
3650
3679
|
windowStart;
|
|
3651
3680
|
sentInWindow = 0;
|
|
3681
|
+
pauseMs = 0;
|
|
3682
|
+
resumeAt = 0;
|
|
3652
3683
|
/** Items waiting to be sent, not counting a batch already in flight. */
|
|
3653
3684
|
get size() {
|
|
3654
3685
|
return this.items.length;
|
|
@@ -3684,10 +3715,16 @@ var EventQueue = class {
|
|
|
3684
3715
|
return run;
|
|
3685
3716
|
}
|
|
3686
3717
|
/**
|
|
3687
|
-
* Starts a flush without waiting for it
|
|
3688
|
-
*
|
|
3718
|
+
* Starts a flush without waiting for it: once the pause after a failed batch ends, or at once with
|
|
3719
|
+
* `now` (a caller waits for an item). Item failures are logged and settled inside the drain, so only
|
|
3720
|
+
* an unexpected error reaches this catch.
|
|
3689
3721
|
*/
|
|
3690
|
-
flushInBackground() {
|
|
3722
|
+
flushInBackground(now = false) {
|
|
3723
|
+
const paused = this.resumeAt - this.now();
|
|
3724
|
+
if (!now && paused > 0) {
|
|
3725
|
+
this.schedule(paused);
|
|
3726
|
+
return;
|
|
3727
|
+
}
|
|
3691
3728
|
this.flush().catch((error) => {
|
|
3692
3729
|
this.logger.error(`event flush failed: ${toNiadraError(error).message}`);
|
|
3693
3730
|
});
|
|
@@ -3704,24 +3741,36 @@ var EventQueue = class {
|
|
|
3704
3741
|
while (this.items.length > 0) {
|
|
3705
3742
|
const batch = this.items.splice(0, this.options.maxBatchSize);
|
|
3706
3743
|
const heartbeat = this.heartbeat();
|
|
3707
|
-
|
|
3708
|
-
if (
|
|
3709
|
-
await this.sendBatch(batch, wire, report);
|
|
3744
|
+
if (heartbeat) batch.push({ item: heartbeat });
|
|
3745
|
+
if (!await this.sendBatch(batch, report)) break;
|
|
3710
3746
|
}
|
|
3711
3747
|
return report;
|
|
3712
3748
|
}
|
|
3713
|
-
|
|
3749
|
+
/** Sends one batch; `false` when it went back to the queue and the queue pauses. */
|
|
3750
|
+
async sendBatch(batch, report) {
|
|
3751
|
+
const wire = batch.map((pending) => pending.item);
|
|
3714
3752
|
let response;
|
|
3715
3753
|
try {
|
|
3716
3754
|
response = await this.send(wire);
|
|
3717
3755
|
} catch (error) {
|
|
3718
3756
|
const failure = toNiadraError(error);
|
|
3719
|
-
report.failed += batch.length;
|
|
3720
3757
|
report.errors.push(failure);
|
|
3721
|
-
|
|
3758
|
+
if (isTransient(failure)) {
|
|
3759
|
+
for (const pending of batch) pending.settle?.(failure);
|
|
3760
|
+
this.requeue(batch);
|
|
3761
|
+
this.pauseMs = Math.min(MAX_PAUSE_MS, Math.max(this.options.flushIntervalMs, this.pauseMs * 2));
|
|
3762
|
+
this.resumeAt = this.now() + this.pauseMs;
|
|
3763
|
+
this.logger.warn(`could not deliver ${batch.length} events, will retry: ${failure.message}`);
|
|
3764
|
+
this.schedule(this.pauseMs);
|
|
3765
|
+
return false;
|
|
3766
|
+
}
|
|
3767
|
+
report.failed += batch.length;
|
|
3768
|
+
this.logger.warn(`dropped ${batch.length} events refused by the API: ${failure.message}`);
|
|
3722
3769
|
for (const pending of batch) pending.settle?.(failure);
|
|
3723
|
-
return;
|
|
3770
|
+
return true;
|
|
3724
3771
|
}
|
|
3772
|
+
this.pauseMs = 0;
|
|
3773
|
+
this.resumeAt = 0;
|
|
3725
3774
|
const rejected = /* @__PURE__ */ new Map();
|
|
3726
3775
|
for (const itemError of response.errors) {
|
|
3727
3776
|
const detail = itemError.detail ? `: ${itemError.detail}` : "";
|
|
@@ -3732,6 +3781,7 @@ var EventQueue = class {
|
|
|
3732
3781
|
this.logger.warn(`server rejected ${rejected.size} of ${wire.length} items (${codes2})`);
|
|
3733
3782
|
}
|
|
3734
3783
|
batch.forEach((pending, index) => {
|
|
3784
|
+
if (pending.item.type === "heartbeat") return;
|
|
3735
3785
|
const error = rejected.get(index) ?? null;
|
|
3736
3786
|
if (error) {
|
|
3737
3787
|
report.failed++;
|
|
@@ -3742,6 +3792,17 @@ var EventQueue = class {
|
|
|
3742
3792
|
}
|
|
3743
3793
|
pending.settle?.(error);
|
|
3744
3794
|
});
|
|
3795
|
+
return true;
|
|
3796
|
+
}
|
|
3797
|
+
/** Puts a batch back at the front, keeping only what still fits; what does not is dropped. */
|
|
3798
|
+
requeue(batch) {
|
|
3799
|
+
const room = Math.max(0, this.options.maxQueueSize - this.items.length);
|
|
3800
|
+
const lost = batch.slice(room);
|
|
3801
|
+
this.items.unshift(...batch.slice(0, room));
|
|
3802
|
+
if (lost.length > 0) {
|
|
3803
|
+
this.logger.warn(`event queue is full; dropped ${lost.length} events`);
|
|
3804
|
+
for (const pending of lost) pending.settle?.(new NiadraError("event queue is full"));
|
|
3805
|
+
}
|
|
3745
3806
|
}
|
|
3746
3807
|
/**
|
|
3747
3808
|
* Once a minute, the next batch carries the number of items sent in the previous window.
|
|
@@ -3792,7 +3853,7 @@ function unref(timer) {
|
|
|
3792
3853
|
var MAX_TURNS = 50;
|
|
3793
3854
|
var COMPRESSED_ROOM = 4 * 1024 * 1024 - 64 * 1024;
|
|
3794
3855
|
var DECODED_ROOM = 16 * 1024 * 1024 - 256 * 1024;
|
|
3795
|
-
var
|
|
3856
|
+
var MAX_PAUSE_MS2 = 6e4;
|
|
3796
3857
|
var encoder2 = new TextEncoder();
|
|
3797
3858
|
async function encode(records) {
|
|
3798
3859
|
const raw = encoder2.encode(JSON.stringify({ turns: records }));
|
|
@@ -3951,7 +4012,7 @@ var TurnSender = class {
|
|
|
3951
4012
|
}
|
|
3952
4013
|
if (isTransient(error)) {
|
|
3953
4014
|
this.queue.requeue(batch.frames);
|
|
3954
|
-
this.pause = Math.min(
|
|
4015
|
+
this.pause = Math.min(MAX_PAUSE_MS2, Math.max(this.intervalMs, this.pause * 2));
|
|
3955
4016
|
this.resumeAt = this.now() + this.pause;
|
|
3956
4017
|
this.logger.warn(`could not deliver ${batch.frames.length} turns, will retry (${toNiadraError(error).name})`);
|
|
3957
4018
|
return false;
|
|
@@ -4339,26 +4400,42 @@ async function suppressionKey(salt, canonical) {
|
|
|
4339
4400
|
const key2 = await subtle.importKey("raw", saltBytes(salt), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
4340
4401
|
return toBase64url(new Uint8Array(await subtle.sign("HMAC", key2, new TextEncoder().encode(canonical))));
|
|
4341
4402
|
}
|
|
4403
|
+
var AREA_CODES = new Set(
|
|
4404
|
+
"11 12 13 14 15 16 17 18 19 21 22 24 27 28 31 32 33 34 35 37 38 41 42 43 44 45 46 47 48 49 51 53 54 55 61 62 63 64 65 66 67 68 69 71 73 74 75 77 79 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 97 98 99".split(" ")
|
|
4405
|
+
);
|
|
4406
|
+
var FORMAT_CHARACTERS = new RegExp("\\p{Cf}", "gu");
|
|
4342
4407
|
function phone(value) {
|
|
4343
|
-
|
|
4344
|
-
|
|
4408
|
+
let text2 = value.normalize("NFKC").replace(FORMAT_CHARACTERS, "").trim();
|
|
4409
|
+
if (text2.slice(0, 4).toLowerCase() === "tel:") text2 = text2.slice(4);
|
|
4410
|
+
const international = text2.startsWith("+") || text2.startsWith("00");
|
|
4411
|
+
if (international) text2 = text2.replaceAll("(0)", "");
|
|
4412
|
+
const raw = text2.replace(SEPARATORS2, "");
|
|
4345
4413
|
let digits = raw.startsWith("+") ? raw.slice(1) : international ? raw.slice(2) : raw;
|
|
4346
4414
|
if (!DIGITS2.test(digits)) throw new NiadraDestinationError("invalid_handle");
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4415
|
+
if (!international) {
|
|
4416
|
+
const national = digits.replace(/^0+/, "");
|
|
4417
|
+
if (isBrazilianNational(national)) {
|
|
4418
|
+
digits = `55${national}`;
|
|
4419
|
+
} else if (digits.startsWith("0") && (national.length === 12 || national.length === 13)) {
|
|
4420
|
+
if (isBrazilianNational(national.slice(2))) digits = `55${national.slice(2)}`;
|
|
4421
|
+
}
|
|
4350
4422
|
}
|
|
4351
4423
|
if (digits.length < 8 || digits.length > 15 || digits.startsWith("0")) {
|
|
4352
4424
|
throw new NiadraDestinationError("invalid_handle");
|
|
4353
4425
|
}
|
|
4354
4426
|
const rest = digits.slice(2);
|
|
4355
|
-
if (digits.startsWith("55") && rest.length === 10 &&
|
|
4427
|
+
if (digits.startsWith("55") && rest.length === 10 && AREA_CODES.has(rest.slice(0, 2)) && "6789".includes(rest.charAt(2))) {
|
|
4356
4428
|
digits = `55${rest.slice(0, 2)}9${rest.slice(2)}`;
|
|
4357
4429
|
}
|
|
4430
|
+
if (digits.length === 13 && (digits.startsWith("521") || digits.startsWith("549"))) {
|
|
4431
|
+
digits = digits.slice(0, 2) + digits.slice(3);
|
|
4432
|
+
}
|
|
4358
4433
|
return `phone:+${digits}`;
|
|
4359
4434
|
}
|
|
4360
|
-
function
|
|
4361
|
-
|
|
4435
|
+
function isBrazilianNational(national) {
|
|
4436
|
+
if (!AREA_CODES.has(national.slice(0, 2))) return false;
|
|
4437
|
+
if (national.length === 10) return "23456789".includes(national.charAt(2));
|
|
4438
|
+
return national.length === 11 && national.charAt(2) === "9";
|
|
4362
4439
|
}
|
|
4363
4440
|
function saltBytes(salt) {
|
|
4364
4441
|
const bytes = fromBase64url(salt);
|
|
@@ -4417,7 +4494,10 @@ var SuppressionCopy = class {
|
|
|
4417
4494
|
}
|
|
4418
4495
|
this.saltValue = salt;
|
|
4419
4496
|
}
|
|
4420
|
-
/**
|
|
4497
|
+
/**
|
|
4498
|
+
* Applies one page, in order. `true` when more pages follow: a full page. Every page carries the cursor to
|
|
4499
|
+
* read from next, the last one too, which the next read starts from.
|
|
4500
|
+
*/
|
|
4421
4501
|
apply(page) {
|
|
4422
4502
|
if (page.salt_id !== this.saltValue?.salt_id) {
|
|
4423
4503
|
this.saltValue = null;
|
|
@@ -4432,8 +4512,9 @@ var SuppressionCopy = class {
|
|
|
4432
4512
|
}
|
|
4433
4513
|
this.cursor = page.next_cursor ?? this.cursor;
|
|
4434
4514
|
this.absent = false;
|
|
4435
|
-
|
|
4436
|
-
|
|
4515
|
+
const more = Boolean(page.next_cursor) && page.items.length >= PAGE;
|
|
4516
|
+
if (!more) this.readAt = this.now();
|
|
4517
|
+
return more;
|
|
4437
4518
|
}
|
|
4438
4519
|
/** A 404: the space keeps no list. Anything else: the copy stays as it is. */
|
|
4439
4520
|
failed(error) {
|
|
@@ -4658,7 +4739,7 @@ var ContactGateway = class {
|
|
|
4658
4739
|
|
|
4659
4740
|
// src/outbox.ts
|
|
4660
4741
|
var CAPACITY = 1e3;
|
|
4661
|
-
var
|
|
4742
|
+
var MAX_PAUSE_MS3 = 6e4;
|
|
4662
4743
|
var Outbox = class {
|
|
4663
4744
|
constructor(logger, intervalMs = 1e3, now = Date.now) {
|
|
4664
4745
|
this.logger = logger;
|
|
@@ -4726,7 +4807,7 @@ var Outbox = class {
|
|
|
4726
4807
|
answer = await write.send();
|
|
4727
4808
|
} catch (error) {
|
|
4728
4809
|
if (isTransient(error)) {
|
|
4729
|
-
this.pause = Math.min(
|
|
4810
|
+
this.pause = Math.min(MAX_PAUSE_MS3, Math.max(this.intervalMs, this.pause * 2));
|
|
4730
4811
|
this.resumeAt = this.now() + this.pause;
|
|
4731
4812
|
return false;
|
|
4732
4813
|
}
|
|
@@ -5509,6 +5590,11 @@ var ContextCache = class {
|
|
|
5509
5590
|
}
|
|
5510
5591
|
return true;
|
|
5511
5592
|
}
|
|
5593
|
+
/** Milliseconds since the server last sent or confirmed the pack held for `key`; `null` when none is held. */
|
|
5594
|
+
age(key2) {
|
|
5595
|
+
const entry = this.entries.get(key2);
|
|
5596
|
+
return entry ? this.now() - entry.confirmedAt : null;
|
|
5597
|
+
}
|
|
5512
5598
|
/** The cached pack's ETag, without touching the order of eviction. */
|
|
5513
5599
|
etag(key2) {
|
|
5514
5600
|
return this.entries.get(key2)?.response.etag ?? null;
|
|
@@ -5702,7 +5788,7 @@ function mergeNotModified(cached, fresh) {
|
|
|
5702
5788
|
coordination: fresh.coordination ?? cached.coordination ?? null
|
|
5703
5789
|
};
|
|
5704
5790
|
}
|
|
5705
|
-
function resultFrom(response, source, error = null) {
|
|
5791
|
+
function resultFrom(response, source, error = null, ageMs = 0) {
|
|
5706
5792
|
const holdout = response.path === "holdout";
|
|
5707
5793
|
const text2 = holdout ? "" : response.text ?? "";
|
|
5708
5794
|
const pack = holdout ? null : response.pack ?? null;
|
|
@@ -5711,10 +5797,10 @@ function resultFrom(response, source, error = null) {
|
|
|
5711
5797
|
state: response.state ?? null,
|
|
5712
5798
|
coordination: response.coordination ?? null
|
|
5713
5799
|
};
|
|
5714
|
-
return { text: text2, suffix: renderSuffix(response), variables: response.variables, pack, source, response, error, ...blocks2 };
|
|
5800
|
+
return { text: text2, suffix: renderSuffix(response), variables: response.variables, pack, source, ageMs, response, error, ...blocks2 };
|
|
5715
5801
|
}
|
|
5716
5802
|
function emptyResult(error) {
|
|
5717
|
-
return { text: "", suffix: "", variables: {}, pack: null, source: "none", response: null, error, constraints: null, state: null, coordination: null };
|
|
5803
|
+
return { text: "", suffix: "", variables: {}, pack: null, source: "none", ageMs: null, response: null, error, constraints: null, state: null, coordination: null };
|
|
5718
5804
|
}
|
|
5719
5805
|
function renderSuffix(response) {
|
|
5720
5806
|
if (response.path === "holdout") return "";
|
|
@@ -8410,7 +8496,8 @@ var Niadra = class _Niadra {
|
|
|
8410
8496
|
baseURL,
|
|
8411
8497
|
apiKey,
|
|
8412
8498
|
fetch: fetchImpl,
|
|
8413
|
-
defaultHeaders: options.defaultHeaders ?? {}
|
|
8499
|
+
defaultHeaders: options.defaultHeaders ?? {},
|
|
8500
|
+
logger: this.logger
|
|
8414
8501
|
});
|
|
8415
8502
|
const queueOptions = { ...DEFAULT_QUEUE, ...options.queue };
|
|
8416
8503
|
queueOptions.maxBatchSize = Math.min(queueOptions.maxBatchSize, 499);
|
|
@@ -8507,19 +8594,29 @@ var Niadra = class _Niadra {
|
|
|
8507
8594
|
*/
|
|
8508
8595
|
async mayContact(handle, purpose, options = {}) {
|
|
8509
8596
|
if (this.core && this.suppressions.due()) {
|
|
8510
|
-
const read2 = this.suppressions.
|
|
8511
|
-
{
|
|
8512
|
-
salt: () => this.api.suppressionSalt({ timeout: this.timeouts.navigation }),
|
|
8513
|
-
page: (cursor, limit2) => this.api.suppressions({ cursor, limit: limit2 }, { timeout: this.timeouts.navigation })
|
|
8514
|
-
},
|
|
8515
|
-
this.suppressions.held ? this.timeouts.write : this.timeouts.navigation
|
|
8516
|
-
);
|
|
8597
|
+
const read2 = this.readSuppressions(this.suppressions.held ? this.timeouts.write : this.timeouts.navigation);
|
|
8517
8598
|
if (!this.suppressions.held) await read2;
|
|
8518
8599
|
}
|
|
8519
8600
|
const checkOptions = { channel: options.channel ?? null };
|
|
8520
8601
|
if (options.failOpen !== void 0) checkOptions.failOpen = options.failOpen;
|
|
8521
8602
|
return this.suppressions.mayContact(handle, purpose, checkOptions);
|
|
8522
8603
|
}
|
|
8604
|
+
readSuppressions(budgetMs) {
|
|
8605
|
+
return this.suppressions.read(
|
|
8606
|
+
{
|
|
8607
|
+
salt: () => this.api.suppressionSalt({ timeout: this.timeouts.navigation }),
|
|
8608
|
+
page: (cursor, limit2) => this.api.suppressions({ cursor, limit: limit2 }, { timeout: this.timeouts.navigation })
|
|
8609
|
+
},
|
|
8610
|
+
budgetMs
|
|
8611
|
+
);
|
|
8612
|
+
}
|
|
8613
|
+
/**
|
|
8614
|
+
* Reads the local copy of the suppression list in the background when it is due: a check that Niadra does not
|
|
8615
|
+
* answer falls back on it, so an opt-out holds through an outage.
|
|
8616
|
+
*/
|
|
8617
|
+
keepSuppressions() {
|
|
8618
|
+
if (this.core && this.suppressions.due()) void this.readSuppressions(this.timeouts.write);
|
|
8619
|
+
}
|
|
8523
8620
|
/**
|
|
8524
8621
|
* The build a turn runs on, for `conversation.turn({ build })`: each prompt's version, the digest of the
|
|
8525
8622
|
* corpus the agent consults (computed by you, never the files), the model, your context assembler's version
|
|
@@ -8593,7 +8690,10 @@ var Niadra = class _Niadra {
|
|
|
8593
8690
|
states: this.states,
|
|
8594
8691
|
contract: () => this.currentContract(),
|
|
8595
8692
|
internalText: this.internalText,
|
|
8596
|
-
check: (request, timeoutMs) =>
|
|
8693
|
+
check: (request, timeoutMs) => {
|
|
8694
|
+
if (request.direction === "outbound") this.keepSuppressions();
|
|
8695
|
+
return this.api.check(request, { timeout: timeoutMs });
|
|
8696
|
+
},
|
|
8597
8697
|
claim: (request, timeoutMs) => this.api.claim(request, {}, { timeout: timeoutMs }),
|
|
8598
8698
|
verifyClaim: (ref, field, value, options) => this.verifyClaim(ref, field, value, options),
|
|
8599
8699
|
enabled: this.enabled,
|
|
@@ -8707,21 +8807,21 @@ var Niadra = class _Niadra {
|
|
|
8707
8807
|
}
|
|
8708
8808
|
const key2 = cacheKey(request);
|
|
8709
8809
|
const hit = cache.lookup(key2);
|
|
8710
|
-
if (hit?.freshness === "fresh") return resultFrom(delivered(hit.response, cache.take(key2)), "cache");
|
|
8810
|
+
if (hit?.freshness === "fresh") return resultFrom(delivered(hit.response, cache.take(key2)), "cache", null, cache.age(key2));
|
|
8711
8811
|
if (hit?.freshness === "stale") {
|
|
8712
8812
|
this.revalidate(core, cache, key2, scope, request, timeout, options.headers).catch((error) => {
|
|
8713
8813
|
this.logger.debug(`background context refresh failed: ${describe(toNiadraError(error))}`);
|
|
8714
8814
|
});
|
|
8715
|
-
return resultFrom(delivered(hit.response, cache.take(key2)), "stale");
|
|
8815
|
+
return resultFrom(delivered(hit.response, cache.take(key2)), "stale", null, cache.age(key2));
|
|
8716
8816
|
}
|
|
8717
8817
|
try {
|
|
8718
8818
|
const pending = this.revalidate(core, cache, key2, scope, request, timeout, options.headers);
|
|
8719
8819
|
const { response, source } = await abortable(pending, options.signal);
|
|
8720
|
-
return resultFrom(delivered(response, cache.take(key2)), source);
|
|
8820
|
+
return resultFrom(delivered(response, cache.take(key2)), source, null, source === "network" ? 0 : cache.age(key2));
|
|
8721
8821
|
} catch (error) {
|
|
8722
8822
|
const failure = toNiadraError(error);
|
|
8723
8823
|
const fallback2 = cache.lookup(key2);
|
|
8724
|
-
return this.contextFailure(failure, fallback2 ? delivered(fallback2.response, cache.take(key2)) : null);
|
|
8824
|
+
return this.contextFailure(failure, fallback2 ? delivered(fallback2.response, cache.take(key2)) : null, cache.age(key2));
|
|
8725
8825
|
}
|
|
8726
8826
|
}
|
|
8727
8827
|
/**
|
|
@@ -8743,11 +8843,11 @@ var Niadra = class _Niadra {
|
|
|
8743
8843
|
const failure = toNiadraError(error);
|
|
8744
8844
|
this.observeAuth(failure, key2);
|
|
8745
8845
|
const fallback2 = cache && key2 ? cache.lookup(key2) : null;
|
|
8746
|
-
return this.contextFailure(failure, cache && key2 && fallback2 ? delivered(fallback2.response, cache.take(key2)) : null);
|
|
8846
|
+
return this.contextFailure(failure, cache && key2 && fallback2 ? delivered(fallback2.response, cache.take(key2)) : null, key2 ? cache?.age(key2) ?? null : null);
|
|
8747
8847
|
}
|
|
8748
8848
|
if (!cache || !key2 || !scope) return resultFrom(response, "network");
|
|
8749
8849
|
if (response.degraded && !response.not_modified && cached) {
|
|
8750
|
-
return resultFrom(delivered({ ...cached.response, slots: response.slots ?? null }, cache.take(key2)), "fallback");
|
|
8850
|
+
return resultFrom(delivered({ ...cached.response, slots: response.slots ?? null }, cache.take(key2)), "fallback", null, cache.age(key2));
|
|
8751
8851
|
}
|
|
8752
8852
|
const merged = response.not_modified && cached ? mergeNotModified(cached.response, response) : response;
|
|
8753
8853
|
cache.store(key2, scope, withoutSlots(merged), generation);
|
|
@@ -9249,11 +9349,11 @@ var Niadra = class _Niadra {
|
|
|
9249
9349
|
}
|
|
9250
9350
|
});
|
|
9251
9351
|
}
|
|
9252
|
-
contextFailure(error, fallback2) {
|
|
9352
|
+
contextFailure(error, fallback2, ageMs = null) {
|
|
9253
9353
|
if (this.strict) throw error;
|
|
9254
9354
|
if (fallback2) {
|
|
9255
9355
|
this.logger.warn(`context request failed, serving the last good pack: ${describe(error)}`);
|
|
9256
|
-
return resultFrom(fallback2, "fallback", error);
|
|
9356
|
+
return resultFrom(fallback2, "fallback", error, ageMs);
|
|
9257
9357
|
}
|
|
9258
9358
|
this.logger.warn(`context unavailable: ${describe(error)}`);
|
|
9259
9359
|
return emptyResult(error);
|
|
@@ -9354,11 +9454,11 @@ var Niadra = class _Niadra {
|
|
|
9354
9454
|
});
|
|
9355
9455
|
}
|
|
9356
9456
|
const response = compose(delivered(hit.response, cache.take(key2)), chosen2);
|
|
9357
|
-
return resultFrom(response, opening.length > 0 ? "network" : hit.freshness === "fresh" ? "cache" : "stale");
|
|
9457
|
+
return resultFrom(response, opening.length > 0 ? "network" : hit.freshness === "fresh" ? "cache" : "stale", null, cache.age(key2));
|
|
9358
9458
|
} catch (error) {
|
|
9359
9459
|
const failure = toNiadraError(error);
|
|
9360
9460
|
const fallback2 = cache.lookup(key2);
|
|
9361
|
-
return this.contextFailure(failure, fallback2 ? delivered(fallback2.response, cache.take(key2)) : null);
|
|
9461
|
+
return this.contextFailure(failure, fallback2 ? delivered(fallback2.response, cache.take(key2)) : null, cache.age(key2));
|
|
9362
9462
|
}
|
|
9363
9463
|
}
|
|
9364
9464
|
/** Starts one read of a line in the background. */
|
|
@@ -9501,7 +9601,7 @@ var Niadra = class _Niadra {
|
|
|
9501
9601
|
else resolve({ ok: false, idempotency_key: key2, error });
|
|
9502
9602
|
};
|
|
9503
9603
|
core.queue.push(item, settle2);
|
|
9504
|
-
core.queue.flushInBackground();
|
|
9604
|
+
core.queue.flushInBackground(true);
|
|
9505
9605
|
});
|
|
9506
9606
|
}
|
|
9507
9607
|
async endScope(item, scope) {
|
|
@@ -9971,7 +10071,8 @@ var Counterfactual = class {
|
|
|
9971
10071
|
const fn = this.tools[tool2];
|
|
9972
10072
|
if (fn === void 0) throw new NiadraError(`no function for the tool ${tool2}: pass it in tools`);
|
|
9973
10073
|
if (!Number.isInteger(k) || k < 1 || k > MAX_K) throw new RangeError(`k must be 1 to ${String(MAX_K)}`);
|
|
9974
|
-
await this.
|
|
10074
|
+
const raw = await this.served(tool2);
|
|
10075
|
+
if (raw === null) throw new NiadraError(`the space binds no tool ${tool2} for this key's source: see its tool-bindings`);
|
|
9975
10076
|
const ids = [...turnIds];
|
|
9976
10077
|
if ((options.scenarioIds ?? []).length > 0) {
|
|
9977
10078
|
const found2 = await this.niadra.callRoute({ method: "GET", path: "/v1/scenarios", query: { ids: (options.scenarioIds ?? []).join(","), limit: 50 } });
|
|
@@ -9989,7 +10090,7 @@ var Counterfactual = class {
|
|
|
9989
10090
|
continue;
|
|
9990
10091
|
}
|
|
9991
10092
|
for (const call of calls(record, tool2)) {
|
|
9992
|
-
const found2 = await this.case(record, call, fn, element, k);
|
|
10093
|
+
const found2 = await this.case(record, call, fn, raw, element, k);
|
|
9993
10094
|
if (found2 === null) run.untouched++;
|
|
9994
10095
|
else run.cases.push(found2);
|
|
9995
10096
|
}
|
|
@@ -9999,17 +10100,15 @@ var Counterfactual = class {
|
|
|
9999
10100
|
run.report = await this.niadra.callRoute({ method: "POST", path: "/v1/measure/counterfactual-runs", body: report });
|
|
10000
10101
|
return run;
|
|
10001
10102
|
}
|
|
10002
|
-
async case(record, call, fn, element, k) {
|
|
10103
|
+
async case(record, call, fn, raw, element, k) {
|
|
10003
10104
|
const base = { turn_id: record.turn_id, call_id: call.call_id };
|
|
10004
10105
|
const tool2 = String(call.name);
|
|
10005
10106
|
const wrapped = recordedTool(fn);
|
|
10006
|
-
const raw = this.options.bindings?.[tool2] ?? wrapped?.binding ?? await this.served(tool2);
|
|
10007
10107
|
let block;
|
|
10008
10108
|
let args;
|
|
10009
10109
|
try {
|
|
10010
10110
|
block = await this.value(record, blockBlob(record, call));
|
|
10011
10111
|
args = { ...await this.value(record, call.args) };
|
|
10012
|
-
if (raw === null) throw new BlobError("the tool has no binding");
|
|
10013
10112
|
} catch {
|
|
10014
10113
|
return { ...base, status: "infrastructure_error", dry_run: false };
|
|
10015
10114
|
}
|
|
@@ -11008,7 +11107,6 @@ async function counterfactual(argv, io) {
|
|
|
11008
11107
|
element: { type: "string" },
|
|
11009
11108
|
turn: { type: "string", multiple: true, default: [] },
|
|
11010
11109
|
scenario: { type: "string", multiple: true, default: [] },
|
|
11011
|
-
bindings: { type: "string" },
|
|
11012
11110
|
safe: { type: "string", multiple: true, default: [] },
|
|
11013
11111
|
k: { type: "string", default: "10" },
|
|
11014
11112
|
label: { type: "string" }
|
|
@@ -11018,8 +11116,7 @@ async function counterfactual(argv, io) {
|
|
|
11018
11116
|
if (!["constraints", "hard", "size", "exclude"].includes(values.element)) throw new Error(`--element ${values.element}: constraints, hard, size or exclude`);
|
|
11019
11117
|
if (values.turn.length === 0 && values.scenario.length === 0) throw new Error("--turn or --scenario is needed");
|
|
11020
11118
|
const tools = await load(values.tools);
|
|
11021
|
-
const
|
|
11022
|
-
const run = await new Counterfactual(io.client(), tools, { ...bindings ? { bindings } : {}, safe: values.safe }).run(values.turn, {
|
|
11119
|
+
const run = await new Counterfactual(io.client(), tools, { safe: values.safe }).run(values.turn, {
|
|
11023
11120
|
tool: values.tool,
|
|
11024
11121
|
element: values.element,
|
|
11025
11122
|
scenarioIds: values.scenario,
|