@niadra/sdk 0.9.1 → 0.10.3
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 +59 -0
- package/dist/ai-sdk.d.cts +3 -3
- package/dist/ai-sdk.d.ts +3 -3
- package/dist/anthropic.d.cts +4 -4
- package/dist/anthropic.d.ts +4 -4
- package/dist/bedrock.d.cts +4 -4
- package/dist/bedrock.d.ts +4 -4
- package/dist/cli.js +319 -96
- package/dist/cli.js.map +1 -1
- package/dist/{client-CWMxmJHs.d.cts → client-rmWhZJOx.d.cts} +190 -7
- package/dist/{client-CWMxmJHs.d.ts → client-rmWhZJOx.d.ts} +190 -7
- package/dist/cloudflare-agents.d.cts +3 -3
- package/dist/cloudflare-agents.d.ts +3 -3
- package/dist/elevenlabs.cjs +7 -5
- 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 +7 -5
- package/dist/elevenlabs.js.map +1 -1
- package/dist/genkit.d.cts +3 -3
- package/dist/genkit.d.ts +3 -3
- package/dist/google-adk.cjs +7 -5
- 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 +7 -5
- package/dist/google-adk.js.map +1 -1
- package/dist/google-genai.d.cts +4 -4
- package/dist/google-genai.d.ts +4 -4
- package/dist/index.cjs +329 -98
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +329 -98
- package/dist/index.js.map +1 -1
- package/dist/{intercept-CGngQI8B.d.cts → intercept-C0XODsy9.d.cts} +1 -1
- package/dist/{intercept-Bv0nLpSw.d.ts → intercept-veMDudKV.d.ts} +1 -1
- 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.map +1 -1
- package/dist/livekit.cjs +10 -2
- 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 +10 -2
- package/dist/livekit.js.map +1 -1
- package/dist/llamaindex.d.cts +3 -3
- package/dist/llamaindex.d.ts +3 -3
- package/dist/mastra.d.cts +3 -3
- package/dist/mastra.d.ts +3 -3
- package/dist/openai-agents.d.cts +3 -3
- package/dist/openai-agents.d.ts +3 -3
- package/dist/retell.cjs +7 -5
- 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 +7 -5
- package/dist/retell.js.map +1 -1
- package/dist/{shared-B4Ef2Wpg.d.ts → shared-Cs7h5C4Y.d.ts} +1 -1
- package/dist/{shared-Cq8mz-7m.d.cts → shared-zaTBum17.d.cts} +1 -1
- package/dist/strands.d.cts +3 -3
- package/dist/strands.d.ts +3 -3
- package/dist/twilio.cjs +10 -2
- package/dist/twilio.cjs.map +1 -1
- package/dist/twilio.d.cts +4 -4
- package/dist/twilio.d.ts +4 -4
- package/dist/twilio.js +10 -2
- package/dist/twilio.js.map +1 -1
- package/dist/vapi.cjs +7 -5
- 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 +7 -5
- package/dist/vapi.js.map +1 -1
- package/dist/voltagent.d.cts +3 -3
- package/dist/voltagent.d.ts +3 -3
- package/dist/{webhook-z2TjUzjv.d.ts → webhook-2V5QgnKI.d.ts} +1 -1
- package/dist/{webhook-jTx_SegV.d.cts → webhook-CX7nvQig.d.cts} +1 -1
- package/dist/whatsapp.cjs +10 -2
- package/dist/whatsapp.cjs.map +1 -1
- package/dist/whatsapp.d.cts +2 -2
- package/dist/whatsapp.d.ts +2 -2
- package/dist/whatsapp.js +10 -2
- package/dist/whatsapp.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,46 @@ var __export = (target, all) => {
|
|
|
6
6
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
+
// src/ids.ts
|
|
10
|
+
var lastMs = -1;
|
|
11
|
+
var counter = 0;
|
|
12
|
+
function randomBytes(length) {
|
|
13
|
+
const bytes = new Uint8Array(length);
|
|
14
|
+
const webCrypto = globalThis.crypto;
|
|
15
|
+
if (webCrypto?.getRandomValues) {
|
|
16
|
+
webCrypto.getRandomValues(bytes);
|
|
17
|
+
} else {
|
|
18
|
+
for (let i = 0; i < length; i++) bytes[i] = Math.floor(Math.random() * 256);
|
|
19
|
+
}
|
|
20
|
+
return bytes;
|
|
21
|
+
}
|
|
22
|
+
function uuidv7(now = Date.now()) {
|
|
23
|
+
let ms = now;
|
|
24
|
+
if (ms <= lastMs) {
|
|
25
|
+
ms = lastMs;
|
|
26
|
+
counter = counter + 1 & 4095;
|
|
27
|
+
if (counter === 0) ms += 1;
|
|
28
|
+
} else {
|
|
29
|
+
counter = (randomBytes(2)[0] ?? 0) & 127;
|
|
30
|
+
}
|
|
31
|
+
lastMs = ms;
|
|
32
|
+
const bytes = randomBytes(16);
|
|
33
|
+
const high = Math.floor(ms / 2 ** 16);
|
|
34
|
+
const low = ms % 2 ** 16;
|
|
35
|
+
bytes[0] = high >>> 24 & 255;
|
|
36
|
+
bytes[1] = high >>> 16 & 255;
|
|
37
|
+
bytes[2] = high >>> 8 & 255;
|
|
38
|
+
bytes[3] = high & 255;
|
|
39
|
+
bytes[4] = low >>> 8 & 255;
|
|
40
|
+
bytes[5] = low & 255;
|
|
41
|
+
bytes[6] = 112 | counter >>> 8 & 15;
|
|
42
|
+
bytes[7] = counter & 255;
|
|
43
|
+
bytes[8] = 128 | (bytes[8] ?? 0) & 63;
|
|
44
|
+
let hex2 = "";
|
|
45
|
+
for (const byte of bytes) hex2 += byte.toString(16).padStart(2, "0");
|
|
46
|
+
return `${hex2.slice(0, 8)}-${hex2.slice(8, 12)}-${hex2.slice(12, 16)}-${hex2.slice(16, 20)}-${hex2.slice(20)}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
9
49
|
// src/errors.ts
|
|
10
50
|
var NiadraError = class extends Error {
|
|
11
51
|
name = "NiadraError";
|
|
@@ -49,11 +89,12 @@ var NiadraAPIError = class extends NiadraError {
|
|
|
49
89
|
constructor(status, problem, requestId, retryAfterMs = null) {
|
|
50
90
|
const code = problem?.code ?? `http_${status}`;
|
|
51
91
|
const detail = problem?.detail ? `: ${problem.detail}` : "";
|
|
52
|
-
|
|
92
|
+
const id = requestId ?? problem?.request_id ?? null;
|
|
93
|
+
super(`${status} ${code}${detail}${id ? ` (request ${id})` : ""}`);
|
|
53
94
|
this.status = status;
|
|
54
95
|
this.code = code;
|
|
55
96
|
this.problem = problem;
|
|
56
|
-
this.requestId =
|
|
97
|
+
this.requestId = id;
|
|
57
98
|
this.retryAfterMs = retryAfterMs;
|
|
58
99
|
}
|
|
59
100
|
};
|
|
@@ -77,45 +118,11 @@ function toNiadraError(error) {
|
|
|
77
118
|
const message = error instanceof Error ? error.message : String(error);
|
|
78
119
|
return new NiadraError(message, { cause: error });
|
|
79
120
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const bytes = new Uint8Array(length);
|
|
86
|
-
const webCrypto = globalThis.crypto;
|
|
87
|
-
if (webCrypto?.getRandomValues) {
|
|
88
|
-
webCrypto.getRandomValues(bytes);
|
|
89
|
-
} else {
|
|
90
|
-
for (let i = 0; i < length; i++) bytes[i] = Math.floor(Math.random() * 256);
|
|
91
|
-
}
|
|
92
|
-
return bytes;
|
|
93
|
-
}
|
|
94
|
-
function uuidv7(now = Date.now()) {
|
|
95
|
-
let ms = now;
|
|
96
|
-
if (ms <= lastMs) {
|
|
97
|
-
ms = lastMs;
|
|
98
|
-
counter = counter + 1 & 4095;
|
|
99
|
-
if (counter === 0) ms += 1;
|
|
100
|
-
} else {
|
|
101
|
-
counter = (randomBytes(2)[0] ?? 0) & 127;
|
|
102
|
-
}
|
|
103
|
-
lastMs = ms;
|
|
104
|
-
const bytes = randomBytes(16);
|
|
105
|
-
const high = Math.floor(ms / 2 ** 16);
|
|
106
|
-
const low = ms % 2 ** 16;
|
|
107
|
-
bytes[0] = high >>> 24 & 255;
|
|
108
|
-
bytes[1] = high >>> 16 & 255;
|
|
109
|
-
bytes[2] = high >>> 8 & 255;
|
|
110
|
-
bytes[3] = high & 255;
|
|
111
|
-
bytes[4] = low >>> 8 & 255;
|
|
112
|
-
bytes[5] = low & 255;
|
|
113
|
-
bytes[6] = 112 | counter >>> 8 & 15;
|
|
114
|
-
bytes[7] = counter & 255;
|
|
115
|
-
bytes[8] = 128 | (bytes[8] ?? 0) & 63;
|
|
116
|
-
let hex2 = "";
|
|
117
|
-
for (const byte of bytes) hex2 += byte.toString(16).padStart(2, "0");
|
|
118
|
-
return `${hex2.slice(0, 8)}-${hex2.slice(8, 12)}-${hex2.slice(12, 16)}-${hex2.slice(16, 20)}-${hex2.slice(20)}`;
|
|
121
|
+
function explain(error) {
|
|
122
|
+
if (!(error instanceof NiadraAPIError)) return error instanceof Error ? error.name : String(error);
|
|
123
|
+
const detail = error.problem?.detail?.trim();
|
|
124
|
+
const said = `${error.status} ${error.code}${detail ? `: ${detail.slice(0, 300)}` : ""}`;
|
|
125
|
+
return error.requestId ? `${said} (request ${error.requestId})` : said;
|
|
119
126
|
}
|
|
120
127
|
|
|
121
128
|
// src/admin.ts
|
|
@@ -518,7 +525,7 @@ function internalRecord(span, ref, act) {
|
|
|
518
525
|
}
|
|
519
526
|
|
|
520
527
|
// src/version.ts
|
|
521
|
-
var VERSION = "0.
|
|
528
|
+
var VERSION = "0.10.3";
|
|
522
529
|
|
|
523
530
|
// src/transport.ts
|
|
524
531
|
var RETRYABLE_WRITE_STATUS = /* @__PURE__ */ new Set([408, 421, 429, 500, 502, 503, 504]);
|
|
@@ -531,8 +538,32 @@ var Transport = class {
|
|
|
531
538
|
}
|
|
532
539
|
config;
|
|
533
540
|
baseURL;
|
|
541
|
+
answeredAt;
|
|
542
|
+
/** When the allowance was first given since the last answer; it holds for the calls of that moment only. */
|
|
543
|
+
grantedAt;
|
|
544
|
+
/** When the client last sent a request of its own (`RequestSpec.activity`), in epoch milliseconds. */
|
|
545
|
+
lastActivityAt;
|
|
534
546
|
async request(spec) {
|
|
535
|
-
|
|
547
|
+
if (spec.activity !== false) this.lastActivityAt = Date.now();
|
|
548
|
+
const budgeted = this.withAllowance(spec);
|
|
549
|
+
return budgeted.retry.kind === "read" ? this.read(budgeted, budgeted.retry) : this.write(budgeted, budgeted.retry);
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* `spec` with the allowance for opening a connection, when it has a budget and none is likely open. The calls
|
|
553
|
+
* that start while the first one opens it get it too; after that, none does until an answer comes, so an
|
|
554
|
+
* outage costs the allowance once, not on every turn.
|
|
555
|
+
*/
|
|
556
|
+
withAllowance(spec) {
|
|
557
|
+
const allowance = this.config.coldAllowanceMs ?? 0;
|
|
558
|
+
const { retry } = spec;
|
|
559
|
+
if (allowance <= 0 || retry.kind === "write" && retry.totalMs === void 0) return spec;
|
|
560
|
+
const now = Date.now();
|
|
561
|
+
const keep = this.config.keepAliveMs ?? 0;
|
|
562
|
+
if (this.answeredAt !== void 0 && now - this.answeredAt <= keep) return spec;
|
|
563
|
+
this.grantedAt ??= now;
|
|
564
|
+
if (now - this.grantedAt > allowance) return spec;
|
|
565
|
+
const total = retry.kind === "write" && retry.totalMs !== void 0 ? { ...retry, totalMs: retry.totalMs + allowance } : retry;
|
|
566
|
+
return { ...spec, timeoutMs: spec.timeoutMs + allowance, retry: total };
|
|
536
567
|
}
|
|
537
568
|
async read(spec, policy) {
|
|
538
569
|
const deadline = new Deadline(spec.timeoutMs, spec.signal);
|
|
@@ -603,7 +634,18 @@ var Transport = class {
|
|
|
603
634
|
headers["content-type"] = "application/json";
|
|
604
635
|
init.body = JSON.stringify(spec.body);
|
|
605
636
|
}
|
|
606
|
-
|
|
637
|
+
try {
|
|
638
|
+
const answer = await this.exchange(this.url(spec.path, spec.query), init, deadline);
|
|
639
|
+
this.answered();
|
|
640
|
+
return answer;
|
|
641
|
+
} catch (error) {
|
|
642
|
+
if (error instanceof NiadraAPIError) this.answered();
|
|
643
|
+
throw error;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
answered() {
|
|
647
|
+
this.answeredAt = Date.now();
|
|
648
|
+
this.grantedAt = void 0;
|
|
607
649
|
}
|
|
608
650
|
async exchange(url, init, deadline) {
|
|
609
651
|
let response;
|
|
@@ -4044,8 +4086,7 @@ var TurnSender = class {
|
|
|
4044
4086
|
return true;
|
|
4045
4087
|
}
|
|
4046
4088
|
}
|
|
4047
|
-
|
|
4048
|
-
this.recorder.rejected(batch.frames.length, [code]);
|
|
4089
|
+
this.recorder.rejected(batch.frames.length, [explain(error)]);
|
|
4049
4090
|
return true;
|
|
4050
4091
|
}
|
|
4051
4092
|
accepted(batch, answer) {
|
|
@@ -4053,8 +4094,8 @@ var TurnSender = class {
|
|
|
4053
4094
|
this.resumeAt = 0;
|
|
4054
4095
|
this.recorder.sent(answer.accepted, answer.duplicates);
|
|
4055
4096
|
const again = [];
|
|
4056
|
-
const
|
|
4057
|
-
let
|
|
4097
|
+
const reasons = /* @__PURE__ */ new Set();
|
|
4098
|
+
let refused3 = 0;
|
|
4058
4099
|
for (const error of answer.errors ?? []) {
|
|
4059
4100
|
const frame = batch.frames[error.index];
|
|
4060
4101
|
if (frame === void 0) continue;
|
|
@@ -4063,12 +4104,12 @@ var TurnSender = class {
|
|
|
4063
4104
|
this.recorder.modeRefused();
|
|
4064
4105
|
again.push(frame);
|
|
4065
4106
|
} else {
|
|
4066
|
-
|
|
4067
|
-
|
|
4107
|
+
refused3++;
|
|
4108
|
+
reasons.add(error.detail ? `${error.code}: ${error.detail.slice(0, 300)}` : error.code);
|
|
4068
4109
|
}
|
|
4069
4110
|
}
|
|
4070
4111
|
if (again.length > 0) this.queue.requeue(again);
|
|
4071
|
-
if (
|
|
4112
|
+
if (refused3 > 0) this.recorder.rejected(refused3, [...reasons]);
|
|
4072
4113
|
}
|
|
4073
4114
|
};
|
|
4074
4115
|
|
|
@@ -4190,9 +4231,12 @@ var TurnRecorder = class {
|
|
|
4190
4231
|
this.accepted += accepted;
|
|
4191
4232
|
this.duplicates += duplicates;
|
|
4192
4233
|
}
|
|
4193
|
-
|
|
4234
|
+
/** `reasons`: the API's code and detail of each refusal (field paths and rules, never a value). */
|
|
4235
|
+
rejected(count3, reasons) {
|
|
4194
4236
|
this.rejectedTurns += count3;
|
|
4195
|
-
|
|
4237
|
+
const shown = [...new Set(reasons)].sort();
|
|
4238
|
+
const more = shown.length > 3 ? ` (and ${shown.length - 3} more)` : "";
|
|
4239
|
+
this.logger.warn(`${count3} turn records were refused: ${shown.slice(0, 3).join("; ")}${more}`);
|
|
4196
4240
|
}
|
|
4197
4241
|
/** The space does not record turns: these are dropped, and with `off` (a 404) recording stops a while. */
|
|
4198
4242
|
notRecorded(count3, off) {
|
|
@@ -4262,6 +4306,10 @@ async function hex(text2) {
|
|
|
4262
4306
|
}
|
|
4263
4307
|
|
|
4264
4308
|
// src/coordination/client.ts
|
|
4309
|
+
var REFUSED = /* @__PURE__ */ new Set([400, 401, 403, 422]);
|
|
4310
|
+
function refused(error) {
|
|
4311
|
+
return error instanceof NiadraAPIError && REFUSED.has(error.status);
|
|
4312
|
+
}
|
|
4265
4313
|
var FAIL_CLOSED = /* @__PURE__ */ new Set(["marketing", "retention", "collection"]);
|
|
4266
4314
|
var CHECK_BUDGET_MS = 200;
|
|
4267
4315
|
function fallback(request, suppressed, failOpen) {
|
|
@@ -4283,15 +4331,22 @@ function claimed(data, error) {
|
|
|
4283
4331
|
return { held: false, claim: null, error: code };
|
|
4284
4332
|
}
|
|
4285
4333
|
var Coordinator = class {
|
|
4286
|
-
constructor(outbox, suppressions, declareNow) {
|
|
4334
|
+
constructor(outbox, suppressions, declareNow, logger) {
|
|
4287
4335
|
this.outbox = outbox;
|
|
4288
4336
|
this.suppressions = suppressions;
|
|
4289
4337
|
this.declareNow = declareNow;
|
|
4338
|
+
this.logger = logger;
|
|
4290
4339
|
}
|
|
4291
4340
|
outbox;
|
|
4292
4341
|
suppressions;
|
|
4293
4342
|
declareNow;
|
|
4343
|
+
logger;
|
|
4294
4344
|
async failed(request, failOpen, error) {
|
|
4345
|
+
if (refused(error)) {
|
|
4346
|
+
this.logger?.warn(`the coordination check was refused: ${explain(error)}`);
|
|
4347
|
+
const decision = request.direction === "inbound" ? "allow" : "defer";
|
|
4348
|
+
return recorded({ decision, decision_id: uuidv7(), reasons: ["invalid_request"], valid_for_s: 0 });
|
|
4349
|
+
}
|
|
4295
4350
|
const off = error instanceof NiadraAPIError && error.status === 404;
|
|
4296
4351
|
const suppressed = request.subject != null && request.direction === "outbound" ? !await this.suppressions.mayContact(request.subject, request.purpose, { channel: request.channel ?? null, failOpen: true }) : false;
|
|
4297
4352
|
const plain2 = off ? { ...request, effect_key: null } : request;
|
|
@@ -4312,7 +4367,7 @@ var Coordinator = class {
|
|
|
4312
4367
|
if (who.subject) body.subject = who.subject;
|
|
4313
4368
|
if (who.object) body.object = who.object;
|
|
4314
4369
|
const key2 = uuidv7();
|
|
4315
|
-
this.outbox.put({ send: () => this.declareNow(body, key2) });
|
|
4370
|
+
this.outbox.put({ send: () => this.declareNow(body, key2), route: "POST /v1/coordination/declare" });
|
|
4316
4371
|
return key2;
|
|
4317
4372
|
}
|
|
4318
4373
|
};
|
|
@@ -4831,7 +4886,7 @@ var Outbox = class {
|
|
|
4831
4886
|
return false;
|
|
4832
4887
|
}
|
|
4833
4888
|
this.writes.shift();
|
|
4834
|
-
this.logger.warn(
|
|
4889
|
+
this.logger.warn(`${write.route ?? "a write"} was refused: ${explain(error)}`);
|
|
4835
4890
|
this.settle(write, void 0, error);
|
|
4836
4891
|
return true;
|
|
4837
4892
|
}
|
|
@@ -5721,9 +5776,17 @@ var handles = {
|
|
|
5721
5776
|
appUserId: (value, options) => build("app_user_id", value, void 0, options),
|
|
5722
5777
|
/** The id of a person or organization in a system of record; `system` names that system, such as `crm`. */
|
|
5723
5778
|
systemId: (value, system, options) => build("system_id", value, system, options),
|
|
5724
|
-
/**
|
|
5779
|
+
/**
|
|
5780
|
+
* A person's national document, such as a CPF: `govIdHmac("529.982.247-25", "BR")`. Send the number
|
|
5781
|
+
* itself, never a hash of it: the server checks its check digits, then keeps only a keyed hash with your
|
|
5782
|
+
* space's secret and an encrypted copy, and shows it masked. `country` is its ISO 3166-1 alpha-2 code.
|
|
5783
|
+
*/
|
|
5725
5784
|
govIdHmac: (value, country, options) => build("gov_id_hmac", value, country, options),
|
|
5726
|
-
/**
|
|
5785
|
+
/**
|
|
5786
|
+
* A company's registry number, such as a CNPJ: `orgRegistryHmac("11.222.333/0001-81", "BR")`. As with
|
|
5787
|
+
* `govIdHmac`, send the number itself; the server checks it and keeps only a keyed hash. Identifies an
|
|
5788
|
+
* organization.
|
|
5789
|
+
*/
|
|
5727
5790
|
orgRegistryHmac: (value, country) => build("org_registry_hmac", value, country, { subjectKind: "account" }),
|
|
5728
5791
|
/** An e-mail domain, such as `acme.com`. Identifies an organization. */
|
|
5729
5792
|
emailDomain: (domain) => build("email_domain", domain, void 0, { subjectKind: "account" }),
|
|
@@ -6397,6 +6460,7 @@ var AgentSession = class {
|
|
|
6397
6460
|
try {
|
|
6398
6461
|
return this.host.coordinator.decided(await this.host.check(request, options.timeoutMs ?? CHECK_BUDGET_MS), request, this.checked);
|
|
6399
6462
|
} catch (error) {
|
|
6463
|
+
if (this.host.strict && refused(error)) throw error;
|
|
6400
6464
|
return this.host.coordinator.failed(request, options.failOpen, error);
|
|
6401
6465
|
}
|
|
6402
6466
|
}
|
|
@@ -7008,6 +7072,7 @@ var SessionState = class {
|
|
|
7008
7072
|
/** The guards of the last read: they hold the answers to the turn they were written for. */
|
|
7009
7073
|
guards = /* @__PURE__ */ new Map();
|
|
7010
7074
|
lastReport = null;
|
|
7075
|
+
unlinkedSaid = false;
|
|
7011
7076
|
/** After the first pack, every read also asks what changed since. */
|
|
7012
7077
|
get wantsDelta() {
|
|
7013
7078
|
return this.etag !== null;
|
|
@@ -7036,6 +7101,19 @@ var SessionState = class {
|
|
|
7036
7101
|
this.last = absorbed;
|
|
7037
7102
|
return absorbed;
|
|
7038
7103
|
}
|
|
7104
|
+
/**
|
|
7105
|
+
* Once per session: the read named an organization (`about`) with no active link to the subject, so it went
|
|
7106
|
+
* on with the subject's own memory, never the organization's.
|
|
7107
|
+
*/
|
|
7108
|
+
sayUnlinked(result2, logger) {
|
|
7109
|
+
if (result2.response?.about_unlinked && !this.unlinkedSaid) {
|
|
7110
|
+
this.unlinkedSaid = true;
|
|
7111
|
+
logger.warn(
|
|
7112
|
+
"`about` names an organization with no active link to the subject; the context is the subject's own, without that organization's memory. Create the link to read it."
|
|
7113
|
+
);
|
|
7114
|
+
}
|
|
7115
|
+
return result2;
|
|
7116
|
+
}
|
|
7039
7117
|
/** The last backing check of an agent's answer. */
|
|
7040
7118
|
get lastBacking() {
|
|
7041
7119
|
return this.lastReport;
|
|
@@ -7283,7 +7361,7 @@ var Conversation = class {
|
|
|
7283
7361
|
* `query` picks this read's slots by other words than the turn; the pack is the pinned one.
|
|
7284
7362
|
*/
|
|
7285
7363
|
async context(options = {}) {
|
|
7286
|
-
const { query, turn, format, explain, include, ...requestOptions } = options;
|
|
7364
|
+
const { query, turn, format, explain: explain2, include, ...requestOptions } = options;
|
|
7287
7365
|
const params = {
|
|
7288
7366
|
subject: this.subject,
|
|
7289
7367
|
view: this.view,
|
|
@@ -7292,7 +7370,7 @@ var Conversation = class {
|
|
|
7292
7370
|
...this.params.about ? { about: this.params.about } : {},
|
|
7293
7371
|
...this.params.target ? { target: this.params.target } : {},
|
|
7294
7372
|
...format === "json" ? { format } : {},
|
|
7295
|
-
...
|
|
7373
|
+
...explain2 ? { explain: explain2 } : {}
|
|
7296
7374
|
};
|
|
7297
7375
|
if (query) params.query = query;
|
|
7298
7376
|
if (include?.length) params.include = include;
|
|
@@ -7300,7 +7378,7 @@ var Conversation = class {
|
|
|
7300
7378
|
params.turn = turn === void 0 ? this.turnText : turn;
|
|
7301
7379
|
const result2 = await this.client.context(params, requestOptions);
|
|
7302
7380
|
this.features.observe(result2);
|
|
7303
|
-
return this.state.observe(this.state.absorb(result2));
|
|
7381
|
+
return this.state.observe(this.state.sayUnlinked(this.state.absorb(result2), this.logger));
|
|
7304
7382
|
}
|
|
7305
7383
|
/**
|
|
7306
7384
|
* Starts this conversation's first read now, in the background: call it when the call starts
|
|
@@ -7480,6 +7558,35 @@ function withHandles(base, extra) {
|
|
|
7480
7558
|
return all;
|
|
7481
7559
|
}
|
|
7482
7560
|
|
|
7561
|
+
// src/warm.ts
|
|
7562
|
+
var EVERY_MS = 1e5;
|
|
7563
|
+
var IDLE_MS = 9e4;
|
|
7564
|
+
var WARM_FOR_MS = 6e5;
|
|
7565
|
+
var KeepWarm = class {
|
|
7566
|
+
constructor(enabled) {
|
|
7567
|
+
this.enabled = enabled;
|
|
7568
|
+
}
|
|
7569
|
+
enabled;
|
|
7570
|
+
open = /* @__PURE__ */ new Map();
|
|
7571
|
+
openedAt = 0;
|
|
7572
|
+
/** Notes an open conversation or task. */
|
|
7573
|
+
add(scope, session, now) {
|
|
7574
|
+
if (!this.enabled || typeof WeakRef === "undefined") return;
|
|
7575
|
+
this.open.set(scope, new WeakRef(session));
|
|
7576
|
+
this.openedAt = now;
|
|
7577
|
+
}
|
|
7578
|
+
/** The conversation or task ended. */
|
|
7579
|
+
end(scope) {
|
|
7580
|
+
this.open.delete(scope);
|
|
7581
|
+
}
|
|
7582
|
+
step(now, lastActivityAt, idleMs = IDLE_MS, warmForMs = WARM_FOR_MS) {
|
|
7583
|
+
for (const [scope, ref] of this.open) if (ref.deref() === void 0) this.open.delete(scope);
|
|
7584
|
+
const used = Math.max(lastActivityAt ?? 0, this.openedAt);
|
|
7585
|
+
if (this.open.size === 0 || now - used > warmForMs) return "stop";
|
|
7586
|
+
return now - used >= idleMs ? "ping" : "wait";
|
|
7587
|
+
}
|
|
7588
|
+
};
|
|
7589
|
+
|
|
7483
7590
|
// src/exit.ts
|
|
7484
7591
|
var registered = /* @__PURE__ */ new Set();
|
|
7485
7592
|
var installedOn = null;
|
|
@@ -7610,8 +7717,10 @@ var DEFAULT_TIMEOUTS = {
|
|
|
7610
7717
|
write: 5e3,
|
|
7611
7718
|
token: 2e3,
|
|
7612
7719
|
upload: 6e4,
|
|
7613
|
-
prefetch: 1e3
|
|
7720
|
+
prefetch: 1e3,
|
|
7721
|
+
connect: 1e3
|
|
7614
7722
|
};
|
|
7723
|
+
var FETCH_KEEPALIVE_MS = 4e3;
|
|
7615
7724
|
var DEFAULT_CACHE = {
|
|
7616
7725
|
ttlMs: 1e4,
|
|
7617
7726
|
staleWhileRevalidateMs: 10 * 6e4,
|
|
@@ -7718,7 +7827,7 @@ var Task = class {
|
|
|
7718
7827
|
* Resolves with an empty result, never rejects, unless the client is strict.
|
|
7719
7828
|
*/
|
|
7720
7829
|
async context(options = {}) {
|
|
7721
|
-
const { query, format, explain, include, ...requestOptions } = options;
|
|
7830
|
+
const { query, format, explain: explain2, include, ...requestOptions } = options;
|
|
7722
7831
|
const target = this.object ? { object: this.object } : this.params.subject ? { subject: this.params.subject } : {};
|
|
7723
7832
|
const params = {
|
|
7724
7833
|
...target,
|
|
@@ -7728,18 +7837,18 @@ var Task = class {
|
|
|
7728
7837
|
...this.level ? { verification: this.level } : {},
|
|
7729
7838
|
...this.params.target ? { target: this.params.target } : {},
|
|
7730
7839
|
...format === "json" ? { format } : {},
|
|
7731
|
-
...
|
|
7840
|
+
...explain2 ? { explain: explain2 } : {},
|
|
7732
7841
|
...include?.length ? { include } : {}
|
|
7733
7842
|
};
|
|
7734
7843
|
if (query) {
|
|
7735
7844
|
const answered = await this.client.context({ ...params, query }, requestOptions);
|
|
7736
7845
|
this.features.observe(answered);
|
|
7737
|
-
return this.state.observe(answered);
|
|
7846
|
+
return this.state.observe(this.state.sayUnlinked(answered, this.logger));
|
|
7738
7847
|
}
|
|
7739
7848
|
if (this.state.wantsDelta) params.delta = true;
|
|
7740
7849
|
const result2 = await this.client.context(params, requestOptions);
|
|
7741
7850
|
this.features.observe(result2);
|
|
7742
|
-
return this.state.observe(this.state.absorb(result2));
|
|
7851
|
+
return this.state.observe(this.state.sayUnlinked(this.state.absorb(result2), this.logger));
|
|
7743
7852
|
}
|
|
7744
7853
|
/**
|
|
7745
7854
|
* The agent's own working notes for this task's prompt, as `niadra.agentMemory()` with
|
|
@@ -7869,14 +7978,14 @@ var AGENT_MEMORY_TOOL_NAMES = {
|
|
|
7869
7978
|
search: "search_agent_memory",
|
|
7870
7979
|
remember: "remember"
|
|
7871
7980
|
};
|
|
7872
|
-
var ITEM_KINDS = ["episode", "fact", "open_item", "action", "object", "trait"];
|
|
7981
|
+
var ITEM_KINDS = ["episode", "fact", "open_item", "action", "object", "trait", "system_event"];
|
|
7873
7982
|
var NOTE_KINDS = ["procedure", "tool_note", "process_note", "pitfall"];
|
|
7874
7983
|
var TOOL_DEFINITIONS = [
|
|
7875
7984
|
{
|
|
7876
7985
|
"type": "function",
|
|
7877
7986
|
"function": {
|
|
7878
7987
|
"name": "search_customer_history",
|
|
7879
|
-
"description": "Search everything that already happened with this customer: past conversations, promises, agent actions, orders and invoices. Use it when the customer refers to something earlier or asks whether a problem happened before. Do not call it when the answer is already in the context block, including its '
|
|
7988
|
+
"description": "Search everything that already happened with this customer: past conversations, promises, agent actions, orders and invoices. Use it when the customer refers to something earlier or asks whether a problem happened before. Do not call it when the answer is already in the context block, including its 'Hist\xF3rico' line, which already counts recurrences. Returns short items with date, channel and outcome, plus a recurrence count. Open a conversation (`episode:`) or an object (`object:`) with open_history_item; the other items are complete as listed.",
|
|
7880
7989
|
"parameters": {
|
|
7881
7990
|
"type": "object",
|
|
7882
7991
|
"properties": {
|
|
@@ -7920,7 +8029,8 @@ var TOOL_DEFINITIONS = [
|
|
|
7920
8029
|
"open_item",
|
|
7921
8030
|
"action",
|
|
7922
8031
|
"object",
|
|
7923
|
-
"trait"
|
|
8032
|
+
"trait",
|
|
8033
|
+
"system_event"
|
|
7924
8034
|
]
|
|
7925
8035
|
}
|
|
7926
8036
|
},
|
|
@@ -7947,7 +8057,7 @@ var TOOL_DEFINITIONS = [
|
|
|
7947
8057
|
"type": "function",
|
|
7948
8058
|
"function": {
|
|
7949
8059
|
"name": "get_customer_timeline",
|
|
7950
|
-
"description": "List this customer's conversations
|
|
8060
|
+
"description": "List this customer's conversations, agent actions and system events in order, newest first, one line each. Use it to leaf through the history when you do not know what to search for; filters.item_kinds also lists the open items, facts, patterns or objects it names. Pass next_cursor to continue. Prefer search_customer_history for a specific question.",
|
|
7951
8061
|
"parameters": {
|
|
7952
8062
|
"type": "object",
|
|
7953
8063
|
"properties": {
|
|
@@ -7995,7 +8105,8 @@ var TOOL_DEFINITIONS = [
|
|
|
7995
8105
|
"open_item",
|
|
7996
8106
|
"action",
|
|
7997
8107
|
"object",
|
|
7998
|
-
"trait"
|
|
8108
|
+
"trait",
|
|
8109
|
+
"system_event"
|
|
7999
8110
|
]
|
|
8000
8111
|
}
|
|
8001
8112
|
},
|
|
@@ -8014,7 +8125,7 @@ var TOOL_DEFINITIONS = [
|
|
|
8014
8125
|
"type": "function",
|
|
8015
8126
|
"function": {
|
|
8016
8127
|
"name": "open_history_item",
|
|
8017
|
-
"description": "Open one conversation or business object returned by search_customer_history or get_customer_timeline: what was asked, what was promised and by whom, the outcome and what memory came from it. Use it only after a search or timeline pointed to the item.",
|
|
8128
|
+
"description": "Open one conversation (`episode:`) or business object (`object:`) returned by search_customer_history or get_customer_timeline: what was asked, what was promised and by whom, the outcome and what memory came from it. Actions, events, facts and promises are complete as listed and do not open. Use it only after a search or timeline pointed to the item.",
|
|
8018
8129
|
"parameters": {
|
|
8019
8130
|
"type": "object",
|
|
8020
8131
|
"properties": {
|
|
@@ -8385,6 +8496,13 @@ function compose(body, read) {
|
|
|
8385
8496
|
const pack = body.pack ? { pack: { ...body.pack, slots: fetched?.pack?.slots ?? [] } } : {};
|
|
8386
8497
|
return { ...body, slots: fetched?.slots ?? null, guards: fetched?.guards ?? [], ...pack };
|
|
8387
8498
|
}
|
|
8499
|
+
var RTT_MARGIN_MS = 50;
|
|
8500
|
+
function budgetWarnings(rttMs, timeouts, explicit) {
|
|
8501
|
+
const ms = Math.round(rttMs);
|
|
8502
|
+
return [...explicit].sort().filter((name) => timeouts[name] < rttMs + RTT_MARGIN_MS).map(
|
|
8503
|
+
(name) => `timeouts.${name} (${timeouts[name]} ms) is shorter than the round trip to the region (${ms} ms) plus ${RTT_MARGIN_MS} ms for the API: its reads will run out of time. Leave it at its default, which adds the measured round trip, or raise it`
|
|
8504
|
+
);
|
|
8505
|
+
}
|
|
8388
8506
|
function rttWarnings(rttMs, timeouts) {
|
|
8389
8507
|
const ms = Math.round(rttMs);
|
|
8390
8508
|
const found2 = [];
|
|
@@ -8422,6 +8540,12 @@ var Niadra = class _Niadra {
|
|
|
8422
8540
|
enabled;
|
|
8423
8541
|
core;
|
|
8424
8542
|
timeouts;
|
|
8543
|
+
keepWarm;
|
|
8544
|
+
warmTimer;
|
|
8545
|
+
/** The read budgets the caller left at their defaults: they take the measured round trip on top. */
|
|
8546
|
+
defaultReads;
|
|
8547
|
+
voiceStarted = false;
|
|
8548
|
+
voiceWarned = false;
|
|
8425
8549
|
strict;
|
|
8426
8550
|
/** Where the client reports what it swallows in fail-open mode. */
|
|
8427
8551
|
logger;
|
|
@@ -8466,6 +8590,8 @@ var Niadra = class _Niadra {
|
|
|
8466
8590
|
this.strict = options.strict ?? false;
|
|
8467
8591
|
this.logger = options.logger ?? consoleLogger;
|
|
8468
8592
|
this.timeouts = { ...DEFAULT_TIMEOUTS, ...options.timeouts };
|
|
8593
|
+
this.keepWarm = new KeepWarm(options.keepWarm ?? true);
|
|
8594
|
+
this.defaultReads = new Set(["context", "navigation"].filter((name) => options.timeouts?.[name] === void 0));
|
|
8469
8595
|
this.voice = new VoiceLines(
|
|
8470
8596
|
options.voice === false ? { ...DEFAULT_VOICE, enabled: false } : { ...DEFAULT_VOICE, ...options.voice }
|
|
8471
8597
|
);
|
|
@@ -8491,13 +8617,14 @@ var Niadra = class _Niadra {
|
|
|
8491
8617
|
this.coordinator = new Coordinator(
|
|
8492
8618
|
this.outbox,
|
|
8493
8619
|
this.suppressions,
|
|
8494
|
-
(body, key2) => this.api.declare(body, { idempotency_key: key2 })
|
|
8620
|
+
(body, key2) => this.api.declare(body, { idempotency_key: key2 }),
|
|
8621
|
+
this.logger
|
|
8495
8622
|
);
|
|
8496
8623
|
this.states = new AgentStates(
|
|
8497
8624
|
this.outbox,
|
|
8498
8625
|
{
|
|
8499
|
-
read: (scope, agent) => this.api.readAgentState({ scope, agent }, { timeout: this.
|
|
8500
|
-
write: (write) => this.api.writeAgentState(write, { timeout: this.
|
|
8626
|
+
read: (scope, agent) => this.api.readAgentState({ scope, agent }, { timeout: this.readBudget("navigation") }),
|
|
8627
|
+
write: (write) => this.api.writeAgentState(write, { timeout: this.readBudget("navigation") })
|
|
8501
8628
|
},
|
|
8502
8629
|
this.logger
|
|
8503
8630
|
);
|
|
@@ -8524,6 +8651,7 @@ var Niadra = class _Niadra {
|
|
|
8524
8651
|
this.core = setup;
|
|
8525
8652
|
this.enabled = true;
|
|
8526
8653
|
this.disabledReason = null;
|
|
8654
|
+
this.probe(setup);
|
|
8527
8655
|
if (options.flushOnExit ?? true) this.unregisterExit = registerExitFlush(this);
|
|
8528
8656
|
}
|
|
8529
8657
|
setup(options) {
|
|
@@ -8546,7 +8674,9 @@ var Niadra = class _Niadra {
|
|
|
8546
8674
|
apiKey,
|
|
8547
8675
|
fetch: fetchImpl,
|
|
8548
8676
|
defaultHeaders: options.defaultHeaders ?? {},
|
|
8549
|
-
logger: this.logger
|
|
8677
|
+
logger: this.logger,
|
|
8678
|
+
coldAllowanceMs: this.timeouts.connect,
|
|
8679
|
+
keepAliveMs: options.keepAliveMs ?? FETCH_KEEPALIVE_MS
|
|
8550
8680
|
});
|
|
8551
8681
|
const queueOptions = { ...DEFAULT_QUEUE, ...options.queue };
|
|
8552
8682
|
queueOptions.maxBatchSize = Math.min(queueOptions.maxBatchSize, 499);
|
|
@@ -8602,7 +8732,7 @@ var Niadra = class _Niadra {
|
|
|
8602
8732
|
return result2;
|
|
8603
8733
|
}
|
|
8604
8734
|
readContext(core, params, request, options) {
|
|
8605
|
-
const timeout = options.timeout ?? (request.view === "voice" ? this.timeouts.contextVoice : this.
|
|
8735
|
+
const timeout = options.timeout ?? (request.view === "voice" ? this.timeouts.contextVoice : this.readBudget("context"));
|
|
8606
8736
|
const { query: own3, ...pinned2 } = request;
|
|
8607
8737
|
const query = turnText(own3 ?? params.turn);
|
|
8608
8738
|
const voiceCache = this.voiceCache(core, pinned2, options.cache);
|
|
@@ -8618,7 +8748,7 @@ var Niadra = class _Niadra {
|
|
|
8618
8748
|
*/
|
|
8619
8749
|
async profile() {
|
|
8620
8750
|
if (!this.core) return null;
|
|
8621
|
-
return this.profileCache.refresh(() => this.api.sdkProfile({ timeout: this.
|
|
8751
|
+
return this.profileCache.refresh(() => this.api.sdkProfile({ timeout: this.readBudget("navigation") }));
|
|
8622
8752
|
}
|
|
8623
8753
|
/**
|
|
8624
8754
|
* Checks outputs against this claim contract instead of the one the profile serves (a company's own copy,
|
|
@@ -8643,7 +8773,7 @@ var Niadra = class _Niadra {
|
|
|
8643
8773
|
*/
|
|
8644
8774
|
async mayContact(handle, purpose, options = {}) {
|
|
8645
8775
|
if (this.core && this.suppressions.due()) {
|
|
8646
|
-
const read = this.readSuppressions(this.suppressions.held ? this.timeouts.write : this.
|
|
8776
|
+
const read = this.readSuppressions(this.suppressions.held ? this.timeouts.write : this.readBudget("navigation"));
|
|
8647
8777
|
if (!this.suppressions.held) await read;
|
|
8648
8778
|
}
|
|
8649
8779
|
const checkOptions = { channel: options.channel ?? null };
|
|
@@ -8653,8 +8783,8 @@ var Niadra = class _Niadra {
|
|
|
8653
8783
|
readSuppressions(budgetMs) {
|
|
8654
8784
|
return this.suppressions.read(
|
|
8655
8785
|
{
|
|
8656
|
-
salt: () => this.api.suppressionSalt({ timeout: this.
|
|
8657
|
-
page: (cursor, limit3) => this.api.suppressions({ cursor, limit: limit3 }, { timeout: this.
|
|
8786
|
+
salt: () => this.api.suppressionSalt({ timeout: this.readBudget("navigation") }),
|
|
8787
|
+
page: (cursor, limit3) => this.api.suppressions({ cursor, limit: limit3 }, { timeout: this.readBudget("navigation") })
|
|
8658
8788
|
},
|
|
8659
8789
|
budgetMs
|
|
8660
8790
|
);
|
|
@@ -8733,6 +8863,7 @@ var Niadra = class _Niadra {
|
|
|
8733
8863
|
}
|
|
8734
8864
|
/** What a conversation or a task needs of its client for the agent features. */
|
|
8735
8865
|
get agentHost() {
|
|
8866
|
+
const client = this;
|
|
8736
8867
|
return {
|
|
8737
8868
|
recorder: this.turns,
|
|
8738
8869
|
coordinator: this.coordinator,
|
|
@@ -8746,7 +8877,10 @@ var Niadra = class _Niadra {
|
|
|
8746
8877
|
claim: (request, timeoutMs) => this.api.claim(request, {}, { timeout: timeoutMs }),
|
|
8747
8878
|
verifyClaim: (ref, field, value, options) => this.verifyClaim(ref, field, value, options),
|
|
8748
8879
|
enabled: this.enabled,
|
|
8749
|
-
|
|
8880
|
+
strict: this.strict,
|
|
8881
|
+
get navigationMs() {
|
|
8882
|
+
return client.readBudget("navigation");
|
|
8883
|
+
}
|
|
8750
8884
|
};
|
|
8751
8885
|
}
|
|
8752
8886
|
/**
|
|
@@ -8774,7 +8908,7 @@ var Niadra = class _Niadra {
|
|
|
8774
8908
|
if (!cache) return false;
|
|
8775
8909
|
const key2 = cacheKey(request);
|
|
8776
8910
|
const line = this.voice.line(cacheScope(request) ?? "");
|
|
8777
|
-
this.
|
|
8911
|
+
this.startVoice(core);
|
|
8778
8912
|
line.request = request;
|
|
8779
8913
|
if (!cache.has(key2) && line.inFlight().length === 0) {
|
|
8780
8914
|
this.voiceRead(core, cache, line, key2, request, null, this.timeouts.contextVoiceStart);
|
|
@@ -8911,13 +9045,13 @@ var Niadra = class _Niadra {
|
|
|
8911
9045
|
if (!params.query || params.query.length > 2e3) {
|
|
8912
9046
|
throw new NiadraValidationError("query must be 1 to 2000 characters");
|
|
8913
9047
|
}
|
|
8914
|
-
return this.readSpec("POST", "/v1/history/search", params, this.
|
|
9048
|
+
return this.readSpec("POST", "/v1/history/search", params, this.readBudget("navigation"), options);
|
|
8915
9049
|
});
|
|
8916
9050
|
}
|
|
8917
9051
|
/** The customer's history, newest first, one line per item, paginated by cursor. */
|
|
8918
9052
|
async timeline(params, options = {}) {
|
|
8919
9053
|
return this.navigate(
|
|
8920
|
-
() => this.readSpec("POST", "/v1/history/timeline", params, this.
|
|
9054
|
+
() => this.readSpec("POST", "/v1/history/timeline", params, this.readBudget("navigation"), options)
|
|
8921
9055
|
);
|
|
8922
9056
|
}
|
|
8923
9057
|
/**
|
|
@@ -8930,9 +9064,10 @@ var Niadra = class _Niadra {
|
|
|
8930
9064
|
if (!id) throw new NiadraValidationError("open() needs an item id");
|
|
8931
9065
|
const body = { item_id: id };
|
|
8932
9066
|
if (params.subject) body.subject = params.subject;
|
|
9067
|
+
if (params.about) body.about = params.about;
|
|
8933
9068
|
if (params.verification) body.verification = params.verification;
|
|
8934
9069
|
if (params.conversation_id) body.conversation_id = params.conversation_id;
|
|
8935
|
-
return this.readSpec("POST", "/v1/history/open", body, this.
|
|
9070
|
+
return this.readSpec("POST", "/v1/history/open", body, this.readBudget("navigation"), options);
|
|
8936
9071
|
});
|
|
8937
9072
|
}
|
|
8938
9073
|
/**
|
|
@@ -8944,7 +9079,7 @@ var Niadra = class _Niadra {
|
|
|
8944
9079
|
* const { data: invoice } = await niadra.objectState("invoice:erp:0823");
|
|
8945
9080
|
*/
|
|
8946
9081
|
async objectState(object, options = {}) {
|
|
8947
|
-
return this.navigate(() => this.readSpec("GET", objectPath(object), void 0, this.
|
|
9082
|
+
return this.navigate(() => this.readSpec("GET", objectPath(object), void 0, this.readBudget("navigation"), options));
|
|
8948
9083
|
}
|
|
8949
9084
|
/**
|
|
8950
9085
|
* System events and agent actions about one object, newest first, one line each and never
|
|
@@ -8957,7 +9092,7 @@ var Niadra = class _Niadra {
|
|
|
8957
9092
|
throw new NiadraValidationError("limit must be between 1 and 100");
|
|
8958
9093
|
}
|
|
8959
9094
|
const path = `${objectPath(object)}/timeline`;
|
|
8960
|
-
const spec = this.readSpec("GET", path, void 0, this.
|
|
9095
|
+
const spec = this.readSpec("GET", path, void 0, this.readBudget("navigation"), options);
|
|
8961
9096
|
spec.query = { cursor: params.cursor, limit: String(limit3) };
|
|
8962
9097
|
return spec;
|
|
8963
9098
|
});
|
|
@@ -8976,6 +9111,7 @@ var Niadra = class _Niadra {
|
|
|
8976
9111
|
timeline: (params, voice) => this.timeline(params, this.voiceBudget(voice)),
|
|
8977
9112
|
open: (id, customer, bound, voice) => {
|
|
8978
9113
|
const scope = { subject: customer };
|
|
9114
|
+
if (bound.about) scope.about = bound.about;
|
|
8979
9115
|
if (bound.verification) scope.verification = bound.verification;
|
|
8980
9116
|
if (bound.conversation_id) scope.conversation_id = bound.conversation_id;
|
|
8981
9117
|
return this.open(id, scope, this.voiceBudget(voice));
|
|
@@ -9010,7 +9146,7 @@ var Niadra = class _Niadra {
|
|
|
9010
9146
|
const key2 = AgentMemoryCache.key(params);
|
|
9011
9147
|
const fresh = cache?.fresh(key2);
|
|
9012
9148
|
if (fresh) return blockResult(fresh, "cache");
|
|
9013
|
-
const timeout = options.timeout ?? (params.view === "voice" ? this.timeouts.contextVoice : this.
|
|
9149
|
+
const timeout = options.timeout ?? (params.view === "voice" ? this.timeouts.contextVoice : this.readBudget("context"));
|
|
9014
9150
|
const spec = this.readSpec("GET", "/v1/agent-memory/block", void 0, timeout, options);
|
|
9015
9151
|
spec.query = {
|
|
9016
9152
|
max_tokens: String(params.max_tokens ?? 300),
|
|
@@ -9047,7 +9183,7 @@ var Niadra = class _Niadra {
|
|
|
9047
9183
|
if (params.limit !== void 0) body.limit = params.limit;
|
|
9048
9184
|
if (params.conversation_id) body.conversation_id = params.conversation_id;
|
|
9049
9185
|
if (params.task_id) body.task_id = params.task_id;
|
|
9050
|
-
return this.readSpec("POST", "/v1/agent-memory/search", body, this.
|
|
9186
|
+
return this.readSpec("POST", "/v1/agent-memory/search", body, this.readBudget("navigation"), options);
|
|
9051
9187
|
});
|
|
9052
9188
|
return result2.error ? result2 : { data: result2.data.notes, error: null };
|
|
9053
9189
|
}
|
|
@@ -9141,6 +9277,41 @@ var Niadra = class _Niadra {
|
|
|
9141
9277
|
return { ok: false, idempotency_key: key2, error: this.swallow(error, "feedback") };
|
|
9142
9278
|
}
|
|
9143
9279
|
}
|
|
9280
|
+
/**
|
|
9281
|
+
* How the space's agents used the context they read (`GET /v1/context-use`): sessions, deliveries, use,
|
|
9282
|
+
* repetition, transfers and recontact, with intervals, grouped by `group_by`. A key of an `analyst` source
|
|
9283
|
+
* with the `analytics` scope reads every source of the space; a key with `admin` reads its own source.
|
|
9284
|
+
*/
|
|
9285
|
+
contextUse(params = {}, options = {}) {
|
|
9286
|
+
return this.navigate(() => {
|
|
9287
|
+
const { group_by: groups, ...filters } = params;
|
|
9288
|
+
const query = { ...filters };
|
|
9289
|
+
if (groups?.length) query.group_by = groups;
|
|
9290
|
+
return { ...this.readSpec("GET", "/v1/context-use", void 0, this.timeouts.write, options), query };
|
|
9291
|
+
});
|
|
9292
|
+
}
|
|
9293
|
+
/**
|
|
9294
|
+
* Links a person to the organization they act for (an account or a partner), as a system of record that
|
|
9295
|
+
* knows who works for whom: a CRM, an HR system. Needs a key with the `identity:link` scope (or `admin`);
|
|
9296
|
+
* `can_see_contacts` needs `admin`. Reads with `about` reach the organization through the link.
|
|
9297
|
+
*/
|
|
9298
|
+
link(params, options = {}) {
|
|
9299
|
+
const { idempotency_key: key2, ...rest } = params;
|
|
9300
|
+
const body = { can_see_contacts: false, method: "system_import", ...rest };
|
|
9301
|
+
return this.navigate(() => this.writeSpec("/v1/identity/links", body, key2 ?? uuidv7(), options));
|
|
9302
|
+
}
|
|
9303
|
+
/**
|
|
9304
|
+
* Ends a link, from `valid_to` (now when absent): the person no longer acts for the organization, and reads
|
|
9305
|
+
* with `about` for the pair go on with the person's own memory. Needs `identity:link` or `admin`.
|
|
9306
|
+
*/
|
|
9307
|
+
endLink(linkId, params = {}, options = {}) {
|
|
9308
|
+
return this.navigate(() => {
|
|
9309
|
+
if (!linkId) throw new NiadraValidationError("endLink() needs a link id");
|
|
9310
|
+
const body = params.valid_to ? { valid_to: params.valid_to } : {};
|
|
9311
|
+
const path = `/v1/identity/links/${encodeURIComponent(linkId)}/end`;
|
|
9312
|
+
return this.writeSpec(path, body, params.idempotency_key ?? uuidv7(), options);
|
|
9313
|
+
});
|
|
9314
|
+
}
|
|
9144
9315
|
/**
|
|
9145
9316
|
* Up to 500 corrections in one call, each with its own idempotency key (minted when missing).
|
|
9146
9317
|
* Resolves with `accepted`, `duplicates` for replayed keys and one error per refused item, by index.
|
|
@@ -9233,16 +9404,20 @@ var Niadra = class _Niadra {
|
|
|
9233
9404
|
* emits `conversation.ended` when you call `end()`.
|
|
9234
9405
|
*/
|
|
9235
9406
|
conversation(params) {
|
|
9236
|
-
|
|
9407
|
+
const conversation = new Conversation(this, params, {
|
|
9237
9408
|
endConversation: (id) => this.endScope(buildConversationEnded(id), `conversation:${id}`)
|
|
9238
9409
|
});
|
|
9410
|
+
this.warm(`conversation:${conversation.id}`, conversation);
|
|
9411
|
+
return conversation;
|
|
9239
9412
|
}
|
|
9240
9413
|
/** A helper for one internal-agent task: binds `task_id` to reads and writes and emits `task.ended`. */
|
|
9241
9414
|
task(params) {
|
|
9242
|
-
|
|
9415
|
+
const task = new Task(this, params, {
|
|
9243
9416
|
endTask: (id) => this.endScope(buildTaskEnded(id), `task:${id}`),
|
|
9244
9417
|
verifyTask: (verify) => this.verifyWith(verify)
|
|
9245
9418
|
});
|
|
9419
|
+
this.warm(`task:${task.id}`, task);
|
|
9420
|
+
return task;
|
|
9246
9421
|
}
|
|
9247
9422
|
/**
|
|
9248
9423
|
* Sends every queued event and resolves when done. Call it before a serverless function
|
|
@@ -9262,6 +9437,8 @@ var Niadra = class _Niadra {
|
|
|
9262
9437
|
*/
|
|
9263
9438
|
async shutdown() {
|
|
9264
9439
|
this.unregisterExit();
|
|
9440
|
+
clearInterval(this.warmTimer);
|
|
9441
|
+
this.warmTimer = void 0;
|
|
9265
9442
|
if (!this.core) return;
|
|
9266
9443
|
await this.turnSender?.stop(this.timeouts.write);
|
|
9267
9444
|
await this.outbox.stop(this.timeouts.write);
|
|
@@ -9365,9 +9542,9 @@ var Niadra = class _Niadra {
|
|
|
9365
9542
|
const response = await core.transport.request(this.readSpec("POST", "/v1/context", request, timeout, { signal, headers }));
|
|
9366
9543
|
return normalizeContext(response.data);
|
|
9367
9544
|
} catch (error) {
|
|
9368
|
-
const
|
|
9545
|
+
const refused3 = error instanceof NiadraAPIError && error.status === 404;
|
|
9369
9546
|
const left = timeout - (Date.now() - started);
|
|
9370
|
-
if (!request.include?.length || !
|
|
9547
|
+
if (!request.include?.length || !refused3 || left <= 0) throw error;
|
|
9371
9548
|
for (const name of request.include) this.refusedBlocks.set(name, Date.now() + BLOCK_RECHECK_AFTER_MS);
|
|
9372
9549
|
const { include: _dropped, ...plain2 } = request;
|
|
9373
9550
|
const response = await core.transport.request(this.readSpec("POST", "/v1/context", plain2, left, { signal, headers }));
|
|
@@ -9455,9 +9632,32 @@ var Niadra = class _Niadra {
|
|
|
9455
9632
|
const rtt = Math.min(...samples);
|
|
9456
9633
|
this.voice.rtt = rtt;
|
|
9457
9634
|
this.logger.debug(`round trip to the region ${Math.round(rtt)} ms`);
|
|
9458
|
-
|
|
9635
|
+
const explicit = ["context", "navigation"].filter((name) => !this.defaultReads.has(name));
|
|
9636
|
+
for (const warning of budgetWarnings(rtt, this.timeouts, explicit)) this.logger.warn(warning);
|
|
9637
|
+
if (this.voiceStarted) this.warnVoice();
|
|
9459
9638
|
})();
|
|
9460
9639
|
}
|
|
9640
|
+
/**
|
|
9641
|
+
* A read budget: one the caller left at its default is what the API may take, and the measured round trip
|
|
9642
|
+
* to the region goes on top, so an agent far from the region (Sao Paulo, 170 ms from us-east-2) is not
|
|
9643
|
+
* timed out by the network; one the caller set is a ceiling.
|
|
9644
|
+
*/
|
|
9645
|
+
readBudget(name) {
|
|
9646
|
+
const rtt = this.voice.rtt;
|
|
9647
|
+
return rtt !== null && this.defaultReads.has(name) ? this.timeouts[name] + rtt : this.timeouts[name];
|
|
9648
|
+
}
|
|
9649
|
+
/** The client reads in voice: the voice budgets' warnings matter from now on. */
|
|
9650
|
+
startVoice(core) {
|
|
9651
|
+
this.voiceStarted = true;
|
|
9652
|
+
this.probe(core);
|
|
9653
|
+
this.warnVoice();
|
|
9654
|
+
}
|
|
9655
|
+
warnVoice() {
|
|
9656
|
+
const rtt = this.voice.rtt;
|
|
9657
|
+
if (this.voiceWarned || rtt === null) return;
|
|
9658
|
+
this.voiceWarned = true;
|
|
9659
|
+
for (const warning of rttWarnings(rtt, this.timeouts)) this.logger.warn(warning);
|
|
9660
|
+
}
|
|
9461
9661
|
/**
|
|
9462
9662
|
* A voice turn: the pinned body from memory, and the slots of the read of its words when that
|
|
9463
9663
|
* read lands within `timeout`. See `voice.ts`.
|
|
@@ -9467,7 +9667,7 @@ var Niadra = class _Niadra {
|
|
|
9467
9667
|
const key2 = cacheKey(request);
|
|
9468
9668
|
const deadline = Date.now() + timeout;
|
|
9469
9669
|
const line = this.voice.line(scope);
|
|
9470
|
-
this.
|
|
9670
|
+
this.startVoice(core);
|
|
9471
9671
|
line.request = request;
|
|
9472
9672
|
const words2 = wordsOf(query);
|
|
9473
9673
|
const background = this.timeouts.prefetch;
|
|
@@ -9653,8 +9853,39 @@ var Niadra = class _Niadra {
|
|
|
9653
9853
|
core.queue.flushInBackground(true);
|
|
9654
9854
|
});
|
|
9655
9855
|
}
|
|
9856
|
+
/** Notes an open conversation or task; the first one starts the keep-warm timer (`warm.ts`). */
|
|
9857
|
+
warm(scope, session) {
|
|
9858
|
+
const core = this.core;
|
|
9859
|
+
if (!core || !this.keepWarm.enabled) return;
|
|
9860
|
+
this.keepWarm.add(scope, session, Date.now());
|
|
9861
|
+
if (this.warmTimer !== void 0) return;
|
|
9862
|
+
const timer = setInterval(() => {
|
|
9863
|
+
this.warmTick(core);
|
|
9864
|
+
}, EVERY_MS);
|
|
9865
|
+
timer.unref?.();
|
|
9866
|
+
this.warmTimer = timer;
|
|
9867
|
+
}
|
|
9868
|
+
warmTick(core) {
|
|
9869
|
+
const step = this.keepWarm.step(Date.now(), core.transport.lastActivityAt);
|
|
9870
|
+
if (step === "stop") {
|
|
9871
|
+
clearInterval(this.warmTimer);
|
|
9872
|
+
this.warmTimer = void 0;
|
|
9873
|
+
return;
|
|
9874
|
+
}
|
|
9875
|
+
if (step !== "ping") return;
|
|
9876
|
+
core.transport.request({
|
|
9877
|
+
method: "GET",
|
|
9878
|
+
path: "/healthz",
|
|
9879
|
+
timeoutMs: 2e3,
|
|
9880
|
+
retry: { kind: "read", maxAttempts: 1 },
|
|
9881
|
+
activity: false
|
|
9882
|
+
}).catch((error) => {
|
|
9883
|
+
this.logger.debug(`keep-warm ping failed: ${describe(toNiadraError(error))}`);
|
|
9884
|
+
});
|
|
9885
|
+
}
|
|
9656
9886
|
async endScope(item, scope) {
|
|
9657
9887
|
this.forgetScope(scope);
|
|
9888
|
+
this.keepWarm.end(scope);
|
|
9658
9889
|
return this.sendNow(() => item);
|
|
9659
9890
|
}
|
|
9660
9891
|
async sendBatch(transport, items2, maxAttempts, backoff) {
|
|
@@ -11509,7 +11740,7 @@ var Replayer = class {
|
|
|
11509
11740
|
try {
|
|
11510
11741
|
answer = await this.niadra.callRoute({ method: "POST", path: "/v1/scenario-runs", body, idempotencyKey: uuidv7() });
|
|
11511
11742
|
} catch (error) {
|
|
11512
|
-
if (error instanceof NiadraAPIError && error.code === "pin_mismatch") return
|
|
11743
|
+
if (error instanceof NiadraAPIError && error.code === "pin_mismatch") return refused2(scenarioIds, results);
|
|
11513
11744
|
throw error;
|
|
11514
11745
|
}
|
|
11515
11746
|
let run = runOf(answer);
|
|
@@ -11612,7 +11843,7 @@ var Replayer = class {
|
|
|
11612
11843
|
return result(scenarioId, turnId, caseId, run, "completed", { paraphrase: rephrased, assertions, divergent_calls: played.divergent, latency_ms: latency });
|
|
11613
11844
|
}
|
|
11614
11845
|
};
|
|
11615
|
-
function
|
|
11846
|
+
function refused2(scenarioIds, results) {
|
|
11616
11847
|
const scenarios = scenarioIds.map((id) => {
|
|
11617
11848
|
const mine = results.filter((r) => r.scenario_id === id);
|
|
11618
11849
|
return {
|