@niadra/sdk 0.1.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +161 -20
- package/README.md +484 -38
- package/dist/ai-sdk.cjs +1037 -0
- package/dist/ai-sdk.cjs.map +1 -0
- package/dist/ai-sdk.d.cts +118 -0
- package/dist/ai-sdk.d.ts +118 -0
- package/dist/ai-sdk.js +1030 -0
- package/dist/ai-sdk.js.map +1 -0
- package/dist/anthropic.cjs +528 -0
- package/dist/anthropic.cjs.map +1 -0
- package/dist/anthropic.d.cts +35 -0
- package/dist/anthropic.d.ts +35 -0
- package/dist/anthropic.js +523 -0
- package/dist/anthropic.js.map +1 -0
- package/dist/bedrock.cjs +392 -0
- package/dist/bedrock.cjs.map +1 -0
- package/dist/bedrock.d.cts +25 -0
- package/dist/bedrock.d.ts +25 -0
- package/dist/bedrock.js +388 -0
- package/dist/bedrock.js.map +1 -0
- package/dist/cli.js +11045 -0
- package/dist/cli.js.map +1 -0
- package/dist/client-DsIxZxZk.d.cts +6905 -0
- package/dist/client-DsIxZxZk.d.ts +6905 -0
- package/dist/cloudflare-agents.cjs +626 -0
- package/dist/cloudflare-agents.cjs.map +1 -0
- package/dist/cloudflare-agents.d.cts +113 -0
- package/dist/cloudflare-agents.d.ts +113 -0
- package/dist/cloudflare-agents.js +622 -0
- package/dist/cloudflare-agents.js.map +1 -0
- package/dist/elevenlabs.cjs +738 -0
- package/dist/elevenlabs.cjs.map +1 -0
- package/dist/elevenlabs.d.cts +86 -0
- package/dist/elevenlabs.d.ts +86 -0
- package/dist/elevenlabs.js +733 -0
- package/dist/elevenlabs.js.map +1 -0
- package/dist/genkit.cjs +323 -0
- package/dist/genkit.cjs.map +1 -0
- package/dist/genkit.d.cts +67 -0
- package/dist/genkit.d.ts +67 -0
- package/dist/genkit.js +318 -0
- package/dist/genkit.js.map +1 -0
- package/dist/google-adk.cjs +705 -0
- package/dist/google-adk.cjs.map +1 -0
- package/dist/google-adk.d.cts +91 -0
- package/dist/google-adk.d.ts +91 -0
- package/dist/google-adk.js +701 -0
- package/dist/google-adk.js.map +1 -0
- package/dist/google-genai.cjs +422 -0
- package/dist/google-genai.cjs.map +1 -0
- package/dist/google-genai.d.cts +26 -0
- package/dist/google-genai.d.ts +26 -0
- package/dist/google-genai.js +418 -0
- package/dist/google-genai.js.map +1 -0
- package/dist/index.cjs +11449 -1796
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1006 -1247
- package/dist/index.d.ts +1006 -1247
- package/dist/index.js +11393 -1797
- package/dist/index.js.map +1 -1
- package/dist/intercept-0_lJE6k1.d.cts +20 -0
- package/dist/intercept-D7qFCaRb.d.ts +20 -0
- package/dist/langchain.cjs +1077 -0
- package/dist/langchain.cjs.map +1 -0
- package/dist/langchain.d.cts +102 -0
- package/dist/langchain.d.ts +102 -0
- package/dist/langchain.js +1068 -0
- package/dist/langchain.js.map +1 -0
- package/dist/livekit.cjs +404 -0
- package/dist/livekit.cjs.map +1 -0
- package/dist/livekit.d.cts +113 -0
- package/dist/livekit.d.ts +113 -0
- package/dist/livekit.js +398 -0
- package/dist/livekit.js.map +1 -0
- package/dist/llamaindex.cjs +349 -0
- package/dist/llamaindex.cjs.map +1 -0
- package/dist/llamaindex.d.cts +92 -0
- package/dist/llamaindex.d.ts +92 -0
- package/dist/llamaindex.js +344 -0
- package/dist/llamaindex.js.map +1 -0
- package/dist/mastra.cjs +1082 -0
- package/dist/mastra.cjs.map +1 -0
- package/dist/mastra.d.cts +86 -0
- package/dist/mastra.d.ts +86 -0
- package/dist/mastra.js +1075 -0
- package/dist/mastra.js.map +1 -0
- package/dist/openai-agents.cjs +465 -0
- package/dist/openai-agents.cjs.map +1 -0
- package/dist/openai-agents.d.cts +75 -0
- package/dist/openai-agents.d.ts +75 -0
- package/dist/openai-agents.js +459 -0
- package/dist/openai-agents.js.map +1 -0
- package/dist/retell.cjs +846 -0
- package/dist/retell.cjs.map +1 -0
- package/dist/retell.d.cts +161 -0
- package/dist/retell.d.ts +161 -0
- package/dist/retell.js +841 -0
- package/dist/retell.js.map +1 -0
- package/dist/shared-Bb5B59Bu.d.ts +39 -0
- package/dist/shared-DTPWVlWm.d.cts +39 -0
- package/dist/strands.cjs +352 -0
- package/dist/strands.cjs.map +1 -0
- package/dist/strands.d.cts +72 -0
- package/dist/strands.d.ts +72 -0
- package/dist/strands.js +347 -0
- package/dist/strands.js.map +1 -0
- package/dist/twilio.cjs +174 -0
- package/dist/twilio.cjs.map +1 -0
- package/dist/twilio.d.cts +64 -0
- package/dist/twilio.d.ts +64 -0
- package/dist/twilio.js +167 -0
- package/dist/twilio.js.map +1 -0
- package/dist/vapi.cjs +661 -0
- package/dist/vapi.cjs.map +1 -0
- package/dist/vapi.d.cts +78 -0
- package/dist/vapi.d.ts +78 -0
- package/dist/vapi.js +656 -0
- package/dist/vapi.js.map +1 -0
- package/dist/voltagent.cjs +509 -0
- package/dist/voltagent.cjs.map +1 -0
- package/dist/voltagent.d.cts +70 -0
- package/dist/voltagent.d.ts +70 -0
- package/dist/voltagent.js +503 -0
- package/dist/voltagent.js.map +1 -0
- package/dist/webhook-1ozGyksG.d.ts +37 -0
- package/dist/webhook-CG4om_DK.d.cts +37 -0
- package/dist/whatsapp.cjs +214 -0
- package/dist/whatsapp.cjs.map +1 -0
- package/dist/whatsapp.d.cts +81 -0
- package/dist/whatsapp.d.ts +81 -0
- package/dist/whatsapp.js +207 -0
- package/dist/whatsapp.js.map +1 -0
- package/package.json +355 -7
|
@@ -0,0 +1,1068 @@
|
|
|
1
|
+
import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
|
|
2
|
+
import { SystemMessage, HumanMessage } from '@langchain/core/messages';
|
|
3
|
+
import { RunnableLambda } from '@langchain/core/runnables';
|
|
4
|
+
import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
5
|
+
|
|
6
|
+
// src/integrations/langchain.ts
|
|
7
|
+
|
|
8
|
+
// src/constraints/binding.ts
|
|
9
|
+
function parseBinding(raw, families = {}) {
|
|
10
|
+
return {
|
|
11
|
+
tool: raw.tool,
|
|
12
|
+
args: (raw.args ?? []).map((a) => ({
|
|
13
|
+
attr: a.attr,
|
|
14
|
+
param: a.param,
|
|
15
|
+
transform: a.transform ?? null,
|
|
16
|
+
negation: a.negation?.param ?? null,
|
|
17
|
+
ops: [...a.ops ?? []],
|
|
18
|
+
family: families[a.attr] ?? null
|
|
19
|
+
})),
|
|
20
|
+
overfetch: raw.overfetch ?? raw.capabilities?.overfetch ?? false
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function resultItems(raw, result) {
|
|
24
|
+
const out = [];
|
|
25
|
+
for (const spec of raw.results ?? []) {
|
|
26
|
+
for (const found2 of readPath(result, spec.path ?? "$")) {
|
|
27
|
+
if (typeof found2 !== "object" || found2 === null || Array.isArray(found2)) continue;
|
|
28
|
+
const entry = found2;
|
|
29
|
+
const item = {};
|
|
30
|
+
for (const [field, key] of Object.entries(spec.fields ?? {})) if (key in entry) item[`${String(spec.type)}.${field}`] = entry[key];
|
|
31
|
+
const ident = entry[spec.id ?? "id"];
|
|
32
|
+
if (typeof ident === "string" || typeof ident === "number") item.ref = `${String(spec.type)}:${spec.namespace ?? "default"}:${String(ident)}`;
|
|
33
|
+
out.push(item);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
function relaxed(raw, result) {
|
|
39
|
+
const path = raw.capabilities?.relax_flag;
|
|
40
|
+
return typeof path === "string" && readPath(result, path).some((v) => v === true);
|
|
41
|
+
}
|
|
42
|
+
function readPath(value, path) {
|
|
43
|
+
let found2 = [value];
|
|
44
|
+
const trimmed = path.replace(/^\$/, "").replace(/^\.+|\.+$/g, "");
|
|
45
|
+
if (!trimmed) return found2;
|
|
46
|
+
for (const part of trimmed.split(".")) {
|
|
47
|
+
const many = part.endsWith("[*]");
|
|
48
|
+
const key = many ? part.slice(0, -3) : part;
|
|
49
|
+
const step = [];
|
|
50
|
+
for (const current of found2) {
|
|
51
|
+
const got = key ? typeof current === "object" && current !== null ? current[key] : void 0 : current;
|
|
52
|
+
if (many) {
|
|
53
|
+
if (Array.isArray(got)) step.push(...got);
|
|
54
|
+
} else if (got !== void 0 && got !== null) step.push(got);
|
|
55
|
+
}
|
|
56
|
+
found2 = step;
|
|
57
|
+
}
|
|
58
|
+
return found2;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/claims/text.ts
|
|
62
|
+
var WORD_CHARS = String.raw`\p{L}\p{N}_`;
|
|
63
|
+
var SPACE_CHARS = String.raw`\t-\r\x1c-\x20\x85\xa0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000`;
|
|
64
|
+
var CLASSES = { w: WORD_CHARS, d: String.raw`\p{Nd}`, s: SPACE_CHARS };
|
|
65
|
+
var BOUNDARY = `(?:(?<=[${WORD_CHARS}])(?![${WORD_CHARS}])|(?<![${WORD_CHARS}])(?=[${WORD_CHARS}]))`;
|
|
66
|
+
function pattern(source, flags = "") {
|
|
67
|
+
let out = "";
|
|
68
|
+
let inClass = false;
|
|
69
|
+
for (let i = 0; i < source.length; i++) {
|
|
70
|
+
const ch = source.charAt(i);
|
|
71
|
+
if (ch === "\\") {
|
|
72
|
+
const next = source.charAt(++i);
|
|
73
|
+
const chars = CLASSES[next];
|
|
74
|
+
if (chars !== void 0) out += inClass ? chars : `[${chars}]`;
|
|
75
|
+
else if (next === "b" && !inClass) out += BOUNDARY;
|
|
76
|
+
else out += next === "Z" && !inClass ? "$" : `\\${next}`;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (ch === "[") inClass = true;
|
|
80
|
+
else if (ch === "]") inClass = false;
|
|
81
|
+
out += ch === "$" && !inClass ? String.raw`(?=\n?$)` : ch;
|
|
82
|
+
}
|
|
83
|
+
return new RegExp(out, `${flags}u`);
|
|
84
|
+
}
|
|
85
|
+
function memo(compute, size = 256) {
|
|
86
|
+
const cache = /* @__PURE__ */ new Map();
|
|
87
|
+
return (text) => {
|
|
88
|
+
const hit = cache.get(text);
|
|
89
|
+
if (hit !== void 0) return hit;
|
|
90
|
+
const value = compute(text);
|
|
91
|
+
const oldest = cache.keys().next();
|
|
92
|
+
if (cache.size >= size && !oldest.done) cache.delete(oldest.value);
|
|
93
|
+
cache.set(text, value);
|
|
94
|
+
return value;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
var ASCII = /^\p{ASCII}*$/u;
|
|
98
|
+
var MARK = /^[\p{Mn}\p{Mc}]$/u;
|
|
99
|
+
function combining(c) {
|
|
100
|
+
if (!MARK.test(c)) return false;
|
|
101
|
+
const run = `\u0301${c}\u0316`;
|
|
102
|
+
return run.normalize("NFD") !== run;
|
|
103
|
+
}
|
|
104
|
+
function plain(text) {
|
|
105
|
+
let out = "";
|
|
106
|
+
for (const c of text.normalize("NFKD")) if (!combining(c)) out += c;
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
var fold = memo((text) => {
|
|
110
|
+
if (ASCII.test(text)) return text.toLowerCase();
|
|
111
|
+
let out = "";
|
|
112
|
+
for (const ch of text) {
|
|
113
|
+
const folded2 = plain(ch).toLowerCase();
|
|
114
|
+
out += Array.from(folded2).length === 1 ? folded2 : "?";
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
});
|
|
118
|
+
pattern(String.raw`[!?;](?=\s|$)|\.(?=\s+[A-ZÀ-Ý]|\s*$)|\n`, "g");
|
|
119
|
+
|
|
120
|
+
// src/constraints/render.ts
|
|
121
|
+
var SAID = /* @__PURE__ */ new Set(["stated", "tool_args", "correction"]);
|
|
122
|
+
var NEGATED = /* @__PURE__ */ new Set(["not_in", "ne"]);
|
|
123
|
+
var POSITIVE = /* @__PURE__ */ new Set(["in", "eq"]);
|
|
124
|
+
function render(block, binding, call, mode = "advisory") {
|
|
125
|
+
if ((block.subject?.for ?? "self") !== (call.for ?? "self")) {
|
|
126
|
+
const args2 = { ...call.args };
|
|
127
|
+
return { applies: false, args: args2, suggested: {}, injected: [], hardSent: [], residual: [], postFilter: [], conflicts: [] };
|
|
128
|
+
}
|
|
129
|
+
const hard = block.hard ?? [];
|
|
130
|
+
const attributes = block.attributes ?? [];
|
|
131
|
+
const lost = new Set((block.conflicts ?? []).flatMap((c) => c.ids.filter((id) => id !== c.kept)));
|
|
132
|
+
const category = call.category ?? null;
|
|
133
|
+
const suggested = /* @__PURE__ */ new Map();
|
|
134
|
+
const sources = /* @__PURE__ */ new Map();
|
|
135
|
+
const residual = [];
|
|
136
|
+
const conflicts = [];
|
|
137
|
+
const routed = [];
|
|
138
|
+
for (const h of hard) {
|
|
139
|
+
if (lost.has(h.id) || h.category != null && h.category !== category) continue;
|
|
140
|
+
const route = routeOf(h, binding);
|
|
141
|
+
if (!route) {
|
|
142
|
+
residual.push(h.id);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const [arg, param] = route;
|
|
146
|
+
let value = shape(h.values, arg.transform);
|
|
147
|
+
if (suggested.has(param)) {
|
|
148
|
+
if (!POSITIVE.has(h.op) && !NEGATED.has(h.op)) {
|
|
149
|
+
residual.push(h.id);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const before = asList(suggested.get(param));
|
|
153
|
+
const merged = [...before, ...asList(value).filter((v) => !before.includes(v))];
|
|
154
|
+
value = merged.length === 1 ? merged[0] : merged;
|
|
155
|
+
}
|
|
156
|
+
suggested.set(param, value);
|
|
157
|
+
sources.set(param, [...sources.get(param) ?? [], h.id]);
|
|
158
|
+
routed.push([h, param]);
|
|
159
|
+
if (against(h, arg, call.args)) conflicts.push({ id: h.id, param: arg.param });
|
|
160
|
+
}
|
|
161
|
+
const asked = new Set(call.asked ?? []);
|
|
162
|
+
for (const a of attributes) {
|
|
163
|
+
const family = a.name.split(".")[0] ?? a.name;
|
|
164
|
+
if (a.category != null && a.category !== category) continue;
|
|
165
|
+
if (a.apply !== "always" && !asked.has(family) && !asked.has(a.name)) continue;
|
|
166
|
+
const carrier = binding.args.find((b) => b.family === family);
|
|
167
|
+
if (carrier && !suggested.has(carrier.param)) {
|
|
168
|
+
suggested.set(carrier.param, shape([a.value], carrier.transform));
|
|
169
|
+
sources.set(carrier.param, [a.id]);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if ((block.exclude ?? []).length > 0) residual.push("exclude");
|
|
173
|
+
const args = new Map(Object.entries(call.args));
|
|
174
|
+
const injected = [];
|
|
175
|
+
if (mode === "apply") {
|
|
176
|
+
const disputed = new Set(conflicts.map((c) => c.id));
|
|
177
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
178
|
+
...hard.filter((h) => SAID.has(h.source) && (h.scope === "turn" || h.scope === "session") && !disputed.has(h.id)).map((h) => h.id),
|
|
179
|
+
...attributes.filter((a) => a.source === "stated" || a.source === "correction").map((a) => a.id)
|
|
180
|
+
]);
|
|
181
|
+
for (const [param, value] of suggested) {
|
|
182
|
+
const ids = sources.get(param) ?? [];
|
|
183
|
+
if (!args.has(param) && ids.every((id) => allowed.has(id))) {
|
|
184
|
+
args.set(param, value);
|
|
185
|
+
injected.push(...ids);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const hardSent = routed.filter(([h, param]) => sent(h, param, args)).map(([h]) => h.id);
|
|
190
|
+
return {
|
|
191
|
+
applies: true,
|
|
192
|
+
args: Object.fromEntries(args),
|
|
193
|
+
suggested: Object.fromEntries(suggested),
|
|
194
|
+
injected,
|
|
195
|
+
hardSent,
|
|
196
|
+
residual,
|
|
197
|
+
postFilter: binding.overfetch ? [...residual] : [],
|
|
198
|
+
conflicts
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function honored(block, sentIds, results) {
|
|
202
|
+
const checks = (block.hard ?? []).filter((h) => sentIds.includes(h.id));
|
|
203
|
+
let violations = 0;
|
|
204
|
+
let unverifiable = 0;
|
|
205
|
+
for (const item of results) {
|
|
206
|
+
if (checks.some((h) => item[h.attr] != null && !satisfies(h.op, h.values, item[h.attr]))) violations++;
|
|
207
|
+
else if (checks.some((h) => item[h.attr] == null)) unverifiable++;
|
|
208
|
+
}
|
|
209
|
+
return { resultsChecked: results.length, violations, unverifiable };
|
|
210
|
+
}
|
|
211
|
+
function satisfies(op, values, value) {
|
|
212
|
+
const got = keyOf(value);
|
|
213
|
+
const want = values.map(keyOf);
|
|
214
|
+
const first = want[0];
|
|
215
|
+
switch (op) {
|
|
216
|
+
case "in":
|
|
217
|
+
case "eq":
|
|
218
|
+
return want.some((w) => same(got, w));
|
|
219
|
+
case "not_in":
|
|
220
|
+
case "ne":
|
|
221
|
+
return !want.some((w) => same(got, w));
|
|
222
|
+
case "lt":
|
|
223
|
+
return holds(compare(got, first), (c) => c < 0);
|
|
224
|
+
case "lte":
|
|
225
|
+
return holds(compare(got, first), (c) => c <= 0);
|
|
226
|
+
case "gt":
|
|
227
|
+
return holds(compare(got, first), (c) => c > 0);
|
|
228
|
+
case "gte":
|
|
229
|
+
return holds(compare(got, first), (c) => c >= 0);
|
|
230
|
+
case "between":
|
|
231
|
+
return holds(compare(first, got), (c) => c <= 0) && holds(compare(got, want[1]), (c) => c <= 0);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function shape(values, transform) {
|
|
235
|
+
const out = values.map((v) => {
|
|
236
|
+
if (typeof v !== "string") return v;
|
|
237
|
+
return transform === "lower" ? v.toLowerCase() : transform === "upper" ? v.toUpperCase() : v;
|
|
238
|
+
});
|
|
239
|
+
return out.length === 1 ? out[0] : out;
|
|
240
|
+
}
|
|
241
|
+
function asList(value) {
|
|
242
|
+
return Array.isArray(value) ? [...value] : [value];
|
|
243
|
+
}
|
|
244
|
+
function routeOf(h, binding) {
|
|
245
|
+
for (const arg of binding.args) {
|
|
246
|
+
if (arg.attr !== h.attr) continue;
|
|
247
|
+
const ops = arg.ops ?? [];
|
|
248
|
+
if (POSITIVE.has(h.op) && (ops.length === 0 || ops.includes(h.op) || ops.includes("in"))) return [arg, arg.param];
|
|
249
|
+
if (NEGATED.has(h.op) && arg.negation != null) return [arg, arg.negation];
|
|
250
|
+
if (!POSITIVE.has(h.op) && !NEGATED.has(h.op) && ops.includes(h.op)) return [arg, arg.param];
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
function sent(h, param, args) {
|
|
255
|
+
if (!args.has(param)) return false;
|
|
256
|
+
const given = asList(args.get(param));
|
|
257
|
+
if (NEGATED.has(h.op)) return h.values.every((v) => satisfies("in", given, v));
|
|
258
|
+
if (POSITIVE.has(h.op)) return given.every((v) => satisfies("in", h.values, v));
|
|
259
|
+
return given.every((v) => satisfies(h.op, h.values, v));
|
|
260
|
+
}
|
|
261
|
+
function against(h, arg, args) {
|
|
262
|
+
if (!Object.hasOwn(args, arg.param)) return false;
|
|
263
|
+
return asList(args[arg.param]).some((v) => !satisfies(h.op, h.values, v));
|
|
264
|
+
}
|
|
265
|
+
var DECIMAL = /^([+-]?)(?:(\d+)(?:\.(\d*))?|\.(\d+))(?:e([+-]?\d+))?$/i;
|
|
266
|
+
var OTHER = { kind: "other" };
|
|
267
|
+
function keyOf(value) {
|
|
268
|
+
if (typeof value === "string") {
|
|
269
|
+
return decimal(value.trim().replace(/_/g, "")) ?? { kind: "text", text: fold(value).trim() };
|
|
270
|
+
}
|
|
271
|
+
const number = typeof value === "boolean" ? Number(value) : value;
|
|
272
|
+
return typeof number === "number" && Number.isFinite(number) ? decimal(String(number)) ?? OTHER : OTHER;
|
|
273
|
+
}
|
|
274
|
+
function decimal(text) {
|
|
275
|
+
const m = DECIMAL.exec(text);
|
|
276
|
+
if (!m) return null;
|
|
277
|
+
const fraction = m[3] ?? m[4] ?? "";
|
|
278
|
+
const all = `${m[2] ?? ""}${fraction}`.replace(/^0+/, "");
|
|
279
|
+
const digits = all.replace(/0+$/, "");
|
|
280
|
+
if (!digits) return { kind: "number", sign: 0, digits: "", exponent: 0 };
|
|
281
|
+
const exponent = Number(m[5] ?? 0) - fraction.length + (all.length - digits.length);
|
|
282
|
+
return { kind: "number", sign: m[1] === "-" ? -1 : 1, digits, exponent };
|
|
283
|
+
}
|
|
284
|
+
function same(a, b) {
|
|
285
|
+
if (a.kind === "number" && b?.kind === "number") {
|
|
286
|
+
return a.sign === b.sign && a.digits === b.digits && a.exponent === b.exponent;
|
|
287
|
+
}
|
|
288
|
+
return a.kind === "text" && b?.kind === "text" && a.text === b.text;
|
|
289
|
+
}
|
|
290
|
+
function compare(a, b) {
|
|
291
|
+
if (a?.kind === "text" && b?.kind === "text") return a.text < b.text ? -1 : a.text > b.text ? 1 : 0;
|
|
292
|
+
if (a?.kind !== "number" || b?.kind !== "number") return null;
|
|
293
|
+
if (a.sign !== b.sign) return a.sign < b.sign ? -1 : 1;
|
|
294
|
+
if (a.sign === 0) return 0;
|
|
295
|
+
const lead = a.digits.length + a.exponent - (b.digits.length + b.exponent);
|
|
296
|
+
if (lead !== 0) return lead * a.sign < 0 ? -1 : 1;
|
|
297
|
+
const width = Math.max(a.digits.length, b.digits.length);
|
|
298
|
+
const left = a.digits.padEnd(width, "0");
|
|
299
|
+
const right = b.digits.padEnd(width, "0");
|
|
300
|
+
return left === right ? 0 : (left < right ? -1 : 1) * a.sign;
|
|
301
|
+
}
|
|
302
|
+
function holds(order, test) {
|
|
303
|
+
return order !== null && test(order);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// src/capture/context.ts
|
|
307
|
+
var chosen;
|
|
308
|
+
var stores = /* @__PURE__ */ new Map();
|
|
309
|
+
function storeClass() {
|
|
310
|
+
if (chosen !== void 0) return chosen;
|
|
311
|
+
try {
|
|
312
|
+
const proc = globalThis.process;
|
|
313
|
+
const hooks = proc?.getBuiltinModule?.("node:async_hooks");
|
|
314
|
+
chosen = hooks?.AsyncLocalStorage ?? null;
|
|
315
|
+
} catch {
|
|
316
|
+
chosen = null;
|
|
317
|
+
}
|
|
318
|
+
return chosen;
|
|
319
|
+
}
|
|
320
|
+
function store(name) {
|
|
321
|
+
const existing = stores.get(name);
|
|
322
|
+
if (existing) return existing;
|
|
323
|
+
const Class = storeClass();
|
|
324
|
+
if (!Class) return null;
|
|
325
|
+
const created = new Class();
|
|
326
|
+
stores.set(name, created);
|
|
327
|
+
return created;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/capture/frame.ts
|
|
331
|
+
var turns = () => store("niadra_turn");
|
|
332
|
+
function currentTurn() {
|
|
333
|
+
return turns()?.getStore();
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// src/capture/mask.ts
|
|
337
|
+
var MASKED = "[masked]";
|
|
338
|
+
var WITHHELD = "[withheld: the fields this agent may read are not known yet]";
|
|
339
|
+
function protect(result, access, types, onUnknown) {
|
|
340
|
+
if (access === null) return onUnknown === "block" ? WITHHELD : result;
|
|
341
|
+
const rules = /* @__PURE__ */ new Map();
|
|
342
|
+
for (const name of types ?? Object.keys(access)) {
|
|
343
|
+
for (const [field, effect] of Object.entries(access[name] ?? {})) rules.set(field, effect === "deny" || rules.get(field) === "deny" ? "deny" : effect);
|
|
344
|
+
}
|
|
345
|
+
if (rules.size === 0) return result;
|
|
346
|
+
if (typeof result === "string" && /^\s*[[{]/.test(result)) {
|
|
347
|
+
try {
|
|
348
|
+
return JSON.stringify(walk(JSON.parse(result), rules));
|
|
349
|
+
} catch {
|
|
350
|
+
return result;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return walk(result, rules);
|
|
354
|
+
}
|
|
355
|
+
function walk(value, rules) {
|
|
356
|
+
if (Array.isArray(value)) return value.map((v) => walk(v, rules));
|
|
357
|
+
if (typeof value !== "object" || value === null) return value;
|
|
358
|
+
const out = {};
|
|
359
|
+
for (const [key, v] of Object.entries(value)) {
|
|
360
|
+
const effect = rules.get(key);
|
|
361
|
+
if (effect === "deny") continue;
|
|
362
|
+
out[key] = effect === "mask" ? MASKED : walk(v, rules);
|
|
363
|
+
}
|
|
364
|
+
return out;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// src/capture/tool.ts
|
|
368
|
+
var RECORDED = /* @__PURE__ */ Symbol.for("niadra.tool");
|
|
369
|
+
function recordedTool(fn) {
|
|
370
|
+
return typeof fn === "function" ? fn[RECORDED] ?? null : null;
|
|
371
|
+
}
|
|
372
|
+
var isAsyncFunction = (fn) => Object.prototype.toString.call(fn) === "[object AsyncFunction]";
|
|
373
|
+
function isAsyncIterator(value) {
|
|
374
|
+
return typeof value === "object" && value !== null && typeof value.next === "function" && Symbol.asyncIterator in value;
|
|
375
|
+
}
|
|
376
|
+
function found(frame) {
|
|
377
|
+
try {
|
|
378
|
+
return frame?.() ?? void 0;
|
|
379
|
+
} catch {
|
|
380
|
+
return void 0;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function thenable(value) {
|
|
384
|
+
return typeof value === "object" && value !== null && typeof value.then === "function";
|
|
385
|
+
}
|
|
386
|
+
function tool(name, fn, options = {}) {
|
|
387
|
+
const isAsync = isAsyncFunction(fn);
|
|
388
|
+
function bindingOf(frame) {
|
|
389
|
+
return options.binding ?? (options.served ?? frame?.profile.bindings)?.(name) ?? null;
|
|
390
|
+
}
|
|
391
|
+
function masks(frame) {
|
|
392
|
+
return options.maskOutput ?? bindingOf(frame)?.capabilities?.mask_output ?? false;
|
|
393
|
+
}
|
|
394
|
+
function shield(result, frame) {
|
|
395
|
+
if (!masks(frame)) return result;
|
|
396
|
+
const access = options.access ?? frame?.profile.fieldAccess ?? (() => null);
|
|
397
|
+
return protect(result, access(), typesOf(result), options.onUnknown ?? "pass");
|
|
398
|
+
}
|
|
399
|
+
function typesOf(result) {
|
|
400
|
+
if (!options.provenance) return null;
|
|
401
|
+
try {
|
|
402
|
+
const found2 = options.provenance(result);
|
|
403
|
+
const items = found2 == null ? [] : Array.isArray(found2) ? found2 : [found2];
|
|
404
|
+
return items.map((o) => o.ref.split(":")[0] ?? "");
|
|
405
|
+
} catch {
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function end(call, result, model = result) {
|
|
410
|
+
const observations = observed(call, result);
|
|
411
|
+
let shown;
|
|
412
|
+
if (options.ui) {
|
|
413
|
+
try {
|
|
414
|
+
shown = options.ui(result);
|
|
415
|
+
} catch {
|
|
416
|
+
call.frame.incomplete();
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
call.result(model, { ui: shown, observations });
|
|
420
|
+
}
|
|
421
|
+
function observed(call, result) {
|
|
422
|
+
if (!options.provenance) return [];
|
|
423
|
+
try {
|
|
424
|
+
const found2 = options.provenance(result);
|
|
425
|
+
if (found2 == null) return [];
|
|
426
|
+
const items = Array.isArray(found2) ? found2 : [found2];
|
|
427
|
+
return items.filter((o) => typeof o.ref === "string" && typeof o.fields === "object");
|
|
428
|
+
} catch {
|
|
429
|
+
call.frame.incomplete();
|
|
430
|
+
return [];
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
async function* pieces(call, source) {
|
|
434
|
+
const kept = [];
|
|
435
|
+
try {
|
|
436
|
+
for await (const piece of source) {
|
|
437
|
+
const shown = shield(piece, call.frame);
|
|
438
|
+
kept.push(shown);
|
|
439
|
+
yield shown;
|
|
440
|
+
}
|
|
441
|
+
} catch (error) {
|
|
442
|
+
call.failed(error);
|
|
443
|
+
throw error;
|
|
444
|
+
}
|
|
445
|
+
end(call, kept);
|
|
446
|
+
}
|
|
447
|
+
const wrapped = function(...args) {
|
|
448
|
+
const frame = currentTurn() ?? found(options.frame);
|
|
449
|
+
if (frame === void 0 || frame.closed) {
|
|
450
|
+
if (!masks(frame)) return fn.apply(this, args);
|
|
451
|
+
const out = fn.apply(this, args);
|
|
452
|
+
if (isAsyncIterator(out)) return maskedPieces(out, frame);
|
|
453
|
+
return thenable(out) ? Promise.resolve(out).then((v) => shield(v, frame)) : shield(out, frame);
|
|
454
|
+
}
|
|
455
|
+
let recorded;
|
|
456
|
+
let callId;
|
|
457
|
+
try {
|
|
458
|
+
recorded = options.args ? options.args(...args) : args.length === 1 ? args[0] : args;
|
|
459
|
+
callId = options.callId?.(...args);
|
|
460
|
+
} catch {
|
|
461
|
+
recorded = args;
|
|
462
|
+
}
|
|
463
|
+
const call = frame.adopt(name, recorded) ?? frame.toolCall(name, recorded, typeof callId === "string" && callId ? { callId } : {});
|
|
464
|
+
const binding = bindingOf(frame);
|
|
465
|
+
if (binding !== null && frame.constraints !== null) call.measure = measure(frame, binding, recorded);
|
|
466
|
+
if (frame.playback !== null) call.played = frame.playback.answer(name, recorded, options.dryRun ?? false);
|
|
467
|
+
if (call.played !== null && !call.played.live) {
|
|
468
|
+
const value = call.played.value;
|
|
469
|
+
end(call, value);
|
|
470
|
+
return isAsync ? Promise.resolve(value) : value;
|
|
471
|
+
}
|
|
472
|
+
let result;
|
|
473
|
+
try {
|
|
474
|
+
result = call.run(() => fn.apply(this, args));
|
|
475
|
+
} catch (error) {
|
|
476
|
+
call.failed(error);
|
|
477
|
+
throw error;
|
|
478
|
+
}
|
|
479
|
+
if (isAsyncIterator(result)) return pieces(call, result);
|
|
480
|
+
if (thenable(result)) {
|
|
481
|
+
return Promise.resolve(result).then(
|
|
482
|
+
(value) => {
|
|
483
|
+
const shown2 = shield(value, frame);
|
|
484
|
+
end(call, value, shown2);
|
|
485
|
+
return shown2;
|
|
486
|
+
},
|
|
487
|
+
(error) => {
|
|
488
|
+
call.failed(error);
|
|
489
|
+
throw error;
|
|
490
|
+
}
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
const shown = shield(result, frame);
|
|
494
|
+
end(call, result, shown);
|
|
495
|
+
return shown;
|
|
496
|
+
};
|
|
497
|
+
async function* maskedPieces(source, frame) {
|
|
498
|
+
for await (const piece of source) yield shield(piece, frame);
|
|
499
|
+
}
|
|
500
|
+
Object.defineProperty(wrapped, "name", { value: fn.name || name });
|
|
501
|
+
const marker = {
|
|
502
|
+
name,
|
|
503
|
+
dryRun: options.dryRun ?? false,
|
|
504
|
+
provenance: options.provenance ?? null,
|
|
505
|
+
binding: options.binding ?? null
|
|
506
|
+
};
|
|
507
|
+
Object.defineProperty(wrapped, RECORDED, { value: marker });
|
|
508
|
+
return wrapped;
|
|
509
|
+
}
|
|
510
|
+
function measure(frame, raw, args) {
|
|
511
|
+
const block = frame.constraints;
|
|
512
|
+
if (block === null) return null;
|
|
513
|
+
const given = typeof args === "object" && args !== null && !Array.isArray(args) ? args : {};
|
|
514
|
+
const rendering = render(block, parseBinding(raw, frame.profile.families?.() ?? {}), { args: given });
|
|
515
|
+
if (!rendering.applies) return null;
|
|
516
|
+
return (result) => {
|
|
517
|
+
const seen = honored(block, rendering.hardSent, resultItems(raw, result));
|
|
518
|
+
return {
|
|
519
|
+
constraints: block.version,
|
|
520
|
+
hard_sent: [...rendering.hardSent],
|
|
521
|
+
results_checked: seen.resultsChecked,
|
|
522
|
+
violations: seen.violations,
|
|
523
|
+
unverifiable: seen.unverifiable,
|
|
524
|
+
...relaxed(raw, result) ? { relaxed: "declared" } : {}
|
|
525
|
+
};
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// src/errors.ts
|
|
530
|
+
var NiadraError = class extends Error {
|
|
531
|
+
name = "NiadraError";
|
|
532
|
+
};
|
|
533
|
+
var NiadraReplayRefusedError = class extends NiadraError {
|
|
534
|
+
constructor(tool2) {
|
|
535
|
+
super(`the tool ${tool2} would run live in a replay: wrap it with tool(), or pass it through recordTools()`);
|
|
536
|
+
this.tool = tool2;
|
|
537
|
+
}
|
|
538
|
+
tool;
|
|
539
|
+
name = "NiadraReplayRefusedError";
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
// src/replay/playback.ts
|
|
543
|
+
function replaying() {
|
|
544
|
+
return currentTurn()?.playback ?? null;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// src/usage.ts
|
|
548
|
+
function get(value, name) {
|
|
549
|
+
return (typeof value === "object" || typeof value === "function") && value !== null ? value[name] : void 0;
|
|
550
|
+
}
|
|
551
|
+
function providerOf(model, usage) {
|
|
552
|
+
const slash = model.indexOf("/");
|
|
553
|
+
if (slash > 0) return model.slice(0, slash).trim().toLowerCase();
|
|
554
|
+
const name = model.trim().toLowerCase();
|
|
555
|
+
if (name.startsWith("claude") || `.${name}`.includes(".anthropic.")) return "anthropic";
|
|
556
|
+
if (name.startsWith("gemini")) return "google";
|
|
557
|
+
if (get(usage, "prompt_tokens") === void 0 && get(usage, "cache_read_input_tokens") !== void 0) {
|
|
558
|
+
return "anthropic";
|
|
559
|
+
}
|
|
560
|
+
return "openai";
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/context.ts
|
|
564
|
+
function emptyResult(error) {
|
|
565
|
+
return { text: "", suffix: "", variables: {}, pack: null, source: "none", response: null, error, constraints: null, state: null, coordination: null };
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// src/integrations/shared.ts
|
|
569
|
+
var ATTESTED = { A: "V2", B: "V1", C: "V1" };
|
|
570
|
+
function attestationProof(attestation) {
|
|
571
|
+
if (!attestation) return null;
|
|
572
|
+
const value = attestation.trim().toUpperCase();
|
|
573
|
+
if (value.includes("FAILED") || value.startsWith("NO-")) return null;
|
|
574
|
+
const letter = value.length === 1 ? value : /PASSED-([ABC])$/.exec(value)?.[1];
|
|
575
|
+
const level = letter ? ATTESTED[letter] : void 0;
|
|
576
|
+
return level ? { method: "network_attestation", level } : null;
|
|
577
|
+
}
|
|
578
|
+
function resolveSession(source) {
|
|
579
|
+
if (typeof source !== "function") return source;
|
|
580
|
+
try {
|
|
581
|
+
return source() ?? null;
|
|
582
|
+
} catch {
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
function isConversation(session) {
|
|
587
|
+
return "customer" in session && typeof session.customer === "function";
|
|
588
|
+
}
|
|
589
|
+
function errorName(error) {
|
|
590
|
+
return error instanceof Error ? error.name : typeof error;
|
|
591
|
+
}
|
|
592
|
+
var Bridge = class {
|
|
593
|
+
constructor(session, proof, memory = false) {
|
|
594
|
+
this.session = session;
|
|
595
|
+
this.proof = proof;
|
|
596
|
+
this.memory = memory;
|
|
597
|
+
}
|
|
598
|
+
session;
|
|
599
|
+
proof;
|
|
600
|
+
memory;
|
|
601
|
+
proving = null;
|
|
602
|
+
/** `begin()` started the first read of a call: the first `context()` waits for it with `ready()`. */
|
|
603
|
+
begun = false;
|
|
604
|
+
opened = false;
|
|
605
|
+
/**
|
|
606
|
+
* The context and, when enabled, the agent's notes, read side by side within the same budget.
|
|
607
|
+
* Never rejects.
|
|
608
|
+
*/
|
|
609
|
+
async read(options = {}) {
|
|
610
|
+
const memoryParams = this.memory === false ? null : this.memory === true ? {} : withoutWrite(this.memory);
|
|
611
|
+
const [context, memory] = await Promise.all([
|
|
612
|
+
this.context(options),
|
|
613
|
+
memoryParams ? this.agentMemory(memoryParams, options) : Promise.resolve("")
|
|
614
|
+
]);
|
|
615
|
+
return { context, memory, prefix: [memory, context.text].filter(Boolean).join("\n\n"), suffix: context.suffix };
|
|
616
|
+
}
|
|
617
|
+
get logger() {
|
|
618
|
+
return this.session.logger;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Starts the first read of a call now, in the background, after the proof when one was given (the
|
|
622
|
+
* pack depends on the level it proves): at call start, so the read runs while the call is set up.
|
|
623
|
+
* The first `context()` then waits for it within `timeouts.contextVoiceStart`. Never throws.
|
|
624
|
+
*/
|
|
625
|
+
begin() {
|
|
626
|
+
const session = this.session;
|
|
627
|
+
if (!isConversation(session)) return;
|
|
628
|
+
const start = () => {
|
|
629
|
+
this.safe("start the first read", () => {
|
|
630
|
+
this.begun = session.begin();
|
|
631
|
+
});
|
|
632
|
+
};
|
|
633
|
+
if (this.proof === void 0 || this.proof === null) start();
|
|
634
|
+
else void this.verifyOnce().then(start);
|
|
635
|
+
}
|
|
636
|
+
/** Verifies once (when a proof was given), then reads the context. Never rejects. */
|
|
637
|
+
async context(options = {}) {
|
|
638
|
+
await this.verifyOnce();
|
|
639
|
+
try {
|
|
640
|
+
const session = this.session;
|
|
641
|
+
if (this.begun && !this.opened && isConversation(session)) {
|
|
642
|
+
this.opened = true;
|
|
643
|
+
await session.ready(options.timeout === void 0 ? {} : { timeout: options.timeout });
|
|
644
|
+
}
|
|
645
|
+
return await this.session.context(options);
|
|
646
|
+
} catch (error) {
|
|
647
|
+
this.logger.warn(`could not read context (${errorName(error)})`);
|
|
648
|
+
return emptyResult(null);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
/** Records that `context` went into the prompt, unless it was empty for a reason other than the holdout. */
|
|
652
|
+
injected(context) {
|
|
653
|
+
if (!context.text && !context.suffix && context.response?.path !== "holdout") return;
|
|
654
|
+
this.safe("mark the injection", () => {
|
|
655
|
+
this.session.markInjected(context);
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
customer(text, options = {}) {
|
|
659
|
+
const session = this.session;
|
|
660
|
+
if (!text.trim() || !isConversation(session)) return;
|
|
661
|
+
this.safe("record the customer's turn", () => session.customer(text, options));
|
|
662
|
+
}
|
|
663
|
+
/** Sends the customer's turn so far, while they speak. In the background; never throws. */
|
|
664
|
+
prefetch(text) {
|
|
665
|
+
const session = this.session;
|
|
666
|
+
if (!text.trim() || !isConversation(session)) return;
|
|
667
|
+
this.safe("prefetch the turn", () => session.prefetch(text));
|
|
668
|
+
}
|
|
669
|
+
agent(text, options = {}) {
|
|
670
|
+
if (!text.trim()) return;
|
|
671
|
+
this.safe("record the agent's turn", () => this.session.agent(text, options));
|
|
672
|
+
}
|
|
673
|
+
/** Records a transfer. Tasks have no transfer; the call is ignored for them. */
|
|
674
|
+
async handoff(target, reason) {
|
|
675
|
+
const session = this.session;
|
|
676
|
+
if (!isConversation(session)) return;
|
|
677
|
+
try {
|
|
678
|
+
await session.handoff(reason ? { target, reason } : { target });
|
|
679
|
+
} catch (error) {
|
|
680
|
+
this.logger.warn(`could not record the handoff (${errorName(error)})`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
async end() {
|
|
684
|
+
try {
|
|
685
|
+
await this.session.end();
|
|
686
|
+
} catch (error) {
|
|
687
|
+
this.logger.warn(`could not end the session (${errorName(error)})`);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
/** The navigation kit as plain specs (with the agent's memory tools when enabled), or none for a task about an object only. */
|
|
691
|
+
tools() {
|
|
692
|
+
let bound;
|
|
693
|
+
try {
|
|
694
|
+
const memory = this.memory;
|
|
695
|
+
bound = this.session.tools(memory === false ? {} : { agentMemory: true, writeAgentMemory: memory !== true && memory.write === true });
|
|
696
|
+
} catch (error) {
|
|
697
|
+
this.logger.warn(`could not build the tools (${errorName(error)})`);
|
|
698
|
+
return [];
|
|
699
|
+
}
|
|
700
|
+
return bound ? toolSpecs(bound) : [];
|
|
701
|
+
}
|
|
702
|
+
async agentMemory(params, options) {
|
|
703
|
+
try {
|
|
704
|
+
const result = await this.session.agentMemory(params, options.timeout === void 0 ? {} : { timeout: options.timeout });
|
|
705
|
+
return result.text;
|
|
706
|
+
} catch (error) {
|
|
707
|
+
this.logger.warn(`could not read the agent's memory (${errorName(error)})`);
|
|
708
|
+
return "";
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
async verifyOnce() {
|
|
712
|
+
if (this.proof === void 0 || this.proof === null) return;
|
|
713
|
+
this.proving ??= this.runVerify();
|
|
714
|
+
await this.proving;
|
|
715
|
+
}
|
|
716
|
+
async runVerify() {
|
|
717
|
+
try {
|
|
718
|
+
const source = this.proof;
|
|
719
|
+
const proof = typeof source === "function" ? await source() : source;
|
|
720
|
+
if (!proof) return;
|
|
721
|
+
await this.session.verify(proof);
|
|
722
|
+
} catch (error) {
|
|
723
|
+
this.logger.warn(`could not record the verification (${errorName(error)})`);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
safe(what, run) {
|
|
727
|
+
try {
|
|
728
|
+
run();
|
|
729
|
+
} catch (error) {
|
|
730
|
+
this.logger.warn(`could not ${what} (${errorName(error)})`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
function withoutWrite(option) {
|
|
735
|
+
const { write: _, ...params } = option;
|
|
736
|
+
return params;
|
|
737
|
+
}
|
|
738
|
+
function toolSpecs(bound) {
|
|
739
|
+
return bound.definitions.map(({ function: definition }) => ({
|
|
740
|
+
name: definition.name,
|
|
741
|
+
description: definition.description,
|
|
742
|
+
parameters: definition.parameters,
|
|
743
|
+
execute: (args) => bound.call(definition.name, args)
|
|
744
|
+
}));
|
|
745
|
+
}
|
|
746
|
+
function isRecord(value) {
|
|
747
|
+
return typeof value === "object" && value !== null;
|
|
748
|
+
}
|
|
749
|
+
function count(value) {
|
|
750
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : null;
|
|
751
|
+
}
|
|
752
|
+
var TurnHooks = class _TurnHooks {
|
|
753
|
+
constructor(adapter, enabled) {
|
|
754
|
+
this.adapter = adapter;
|
|
755
|
+
this.enabled = enabled;
|
|
756
|
+
}
|
|
757
|
+
adapter;
|
|
758
|
+
enabled;
|
|
759
|
+
/** Runs held open at most; past it the oldest run's turn closes, incomplete (a run whose end never came). */
|
|
760
|
+
static MAX_OPEN = 100;
|
|
761
|
+
frames = /* @__PURE__ */ new Map();
|
|
762
|
+
calls = /* @__PURE__ */ new Map();
|
|
763
|
+
/** The turn of the run `key`: the session's turn in progress, or a new one of its own. */
|
|
764
|
+
open(session, key, params = {}) {
|
|
765
|
+
if (!this.enabled) return void 0;
|
|
766
|
+
const held = this.frames.get(key);
|
|
767
|
+
if (held !== void 0) return held.frame;
|
|
768
|
+
try {
|
|
769
|
+
const active = session.activeTurn();
|
|
770
|
+
if (active !== void 0 && !this.owns(active)) {
|
|
771
|
+
this.frames.set(key, { frame: active, own: false });
|
|
772
|
+
return active;
|
|
773
|
+
}
|
|
774
|
+
const frame = session.openTurn({ ...params, adapter: this.adapter });
|
|
775
|
+
this.frames.set(key, { frame, own: true });
|
|
776
|
+
if (this.frames.size > _TurnHooks.MAX_OPEN) {
|
|
777
|
+
const [oldest] = this.frames.keys();
|
|
778
|
+
if (oldest !== void 0) {
|
|
779
|
+
this.frames.get(oldest)?.frame.incomplete();
|
|
780
|
+
this.close(oldest);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return frame;
|
|
784
|
+
} catch (error) {
|
|
785
|
+
session.logger.warn(`could not open the turn (${errorName(error)})`);
|
|
786
|
+
return void 0;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
/** The turn of `key`, else the session's turn in progress. */
|
|
790
|
+
frame(session, key) {
|
|
791
|
+
if (!this.enabled) return void 0;
|
|
792
|
+
const held = key === void 0 ? void 0 : this.frames.get(key);
|
|
793
|
+
const frame = held?.frame ?? session.activeTurn();
|
|
794
|
+
return frame === void 0 || frame.closed ? void 0 : frame;
|
|
795
|
+
}
|
|
796
|
+
has(key) {
|
|
797
|
+
return this.frames.has(key);
|
|
798
|
+
}
|
|
799
|
+
owns(frame) {
|
|
800
|
+
for (const held of this.frames.values()) if (held.own && held.frame === frame) return true;
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
/** Ends the run `key`: a turn the adapter opened closes; the calls it left open failed. */
|
|
804
|
+
close(key, error) {
|
|
805
|
+
const held = this.frames.get(key);
|
|
806
|
+
if (held === void 0) return;
|
|
807
|
+
this.frames.delete(key);
|
|
808
|
+
for (const [callKey, call] of this.calls) {
|
|
809
|
+
if (call.frame !== held.frame) continue;
|
|
810
|
+
this.calls.delete(callKey);
|
|
811
|
+
if (held.own) call.failed(error ?? "error");
|
|
812
|
+
}
|
|
813
|
+
if (held.own) held.frame.close(error);
|
|
814
|
+
}
|
|
815
|
+
/** A tool call starting, keyed by `callKey`; `callId` is the provider's id of the call, when there is one. */
|
|
816
|
+
toolStart(session, callKey, name, args, options = {}) {
|
|
817
|
+
const frame = this.frame(session, options.frameKey);
|
|
818
|
+
if (frame === void 0) return;
|
|
819
|
+
try {
|
|
820
|
+
this.calls.set(callKey, frame.toolCall(name, args, { callId: options.callId ?? null, adoptable: true }));
|
|
821
|
+
} catch {
|
|
822
|
+
frame.incomplete();
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* In a replay, how a framework tool the adapter stands in for answers: the recorded result of a call with the
|
|
827
|
+
* same arguments, or empty (a divergence), never the live tool. `null` outside a replay, and for a function
|
|
828
|
+
* wrapped with `tool()`, which answers itself.
|
|
829
|
+
*/
|
|
830
|
+
replayed(session, name, args, fn, frameKey) {
|
|
831
|
+
const frame = this.enabled ? this.frame(session, frameKey) : session.activeTurn();
|
|
832
|
+
if (frame?.playback == null || fn !== void 0 && recordedTool(fn) !== null) return null;
|
|
833
|
+
return frame.playback.answer(name, args, false);
|
|
834
|
+
}
|
|
835
|
+
toolEnd(callKey, result, error) {
|
|
836
|
+
const call = this.calls.get(callKey);
|
|
837
|
+
if (call === void 0) return;
|
|
838
|
+
this.calls.delete(callKey);
|
|
839
|
+
try {
|
|
840
|
+
if (error !== void 0) call.failed(error);
|
|
841
|
+
else call.result(result);
|
|
842
|
+
} catch {
|
|
843
|
+
call.frame.incomplete();
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
/** A model call that ended, with its tokens when the framework reported them. */
|
|
847
|
+
model(session, model, tokens = {}, frameKey) {
|
|
848
|
+
const frame = this.frame(session, frameKey);
|
|
849
|
+
if (frame === void 0) return;
|
|
850
|
+
try {
|
|
851
|
+
frame.modelCall(model, { tokensIn: tokens.in ?? null, tokensOut: tokens.out ?? null, tokensCached: tokens.cached ?? 0 });
|
|
852
|
+
} catch {
|
|
853
|
+
frame.incomplete();
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
|
|
858
|
+
// src/integrations/langchain.ts
|
|
859
|
+
var states = /* @__PURE__ */ new WeakMap();
|
|
860
|
+
function stateOf(session, options) {
|
|
861
|
+
let state = states.get(session);
|
|
862
|
+
if (!state) {
|
|
863
|
+
state = { bridge: new Bridge(session, options.verify, options.agentMemory), seen: /* @__PURE__ */ new Set() };
|
|
864
|
+
states.set(session, state);
|
|
865
|
+
}
|
|
866
|
+
return state;
|
|
867
|
+
}
|
|
868
|
+
async function withNiadraContext(session, messages, options = {}) {
|
|
869
|
+
const state = stateOf(session, options);
|
|
870
|
+
try {
|
|
871
|
+
const last = lastHumanIndex(messages);
|
|
872
|
+
const human = messages[last];
|
|
873
|
+
if ((options.recordCustomer ?? true) && human) {
|
|
874
|
+
const text = human.text;
|
|
875
|
+
const key = `${String(last)}:${text}`;
|
|
876
|
+
if (text && !state.seen.has(key)) {
|
|
877
|
+
state.seen.add(key);
|
|
878
|
+
state.bridge.customer(text);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
const read = await state.bridge.read();
|
|
882
|
+
state.bridge.injected(read.context);
|
|
883
|
+
const result = [...messages];
|
|
884
|
+
if (read.suffix && human) result[last] = withSuffix(human, read.suffix);
|
|
885
|
+
if (read.prefix) {
|
|
886
|
+
let position = 0;
|
|
887
|
+
while (position < result.length && result[position]?.type === "system") position++;
|
|
888
|
+
result.splice(position, 0, new SystemMessage(read.prefix));
|
|
889
|
+
}
|
|
890
|
+
return result;
|
|
891
|
+
} catch (error) {
|
|
892
|
+
state.bridge.logger.warn(`could not inject context (${errorName(error)})`);
|
|
893
|
+
return [...messages];
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
function niadraContext(session, options = {}) {
|
|
897
|
+
return RunnableLambda.from(async (input) => {
|
|
898
|
+
const messages = Array.isArray(input) ? input : input.messages;
|
|
899
|
+
const current = resolveSession(session);
|
|
900
|
+
return current ? withNiadraContext(current, messages, options) : [...messages];
|
|
901
|
+
}).withConfig({ runName: "niadra_context" });
|
|
902
|
+
}
|
|
903
|
+
var NiadraCallbackHandler = class extends BaseCallbackHandler {
|
|
904
|
+
constructor(session, options = {}) {
|
|
905
|
+
super();
|
|
906
|
+
this.session = session;
|
|
907
|
+
this.hooks = new TurnHooks("langchain", options.turns ?? false);
|
|
908
|
+
this.awaitHandlers = true;
|
|
909
|
+
this.raiseError = true;
|
|
910
|
+
}
|
|
911
|
+
session;
|
|
912
|
+
name = "niadra";
|
|
913
|
+
hooks;
|
|
914
|
+
/** Each nested run's top-level run, whose turn it records into. */
|
|
915
|
+
roots = /* @__PURE__ */ new Map();
|
|
916
|
+
/** The same handler: the turns it holds open are shared by every run it is passed to. */
|
|
917
|
+
copy() {
|
|
918
|
+
return this;
|
|
919
|
+
}
|
|
920
|
+
handleChainStart(_chain, _inputs, runId, runType, _tags, _metadata, _runName, parentRunId) {
|
|
921
|
+
this.started(runId, [runType, parentRunId].find(isRunId));
|
|
922
|
+
}
|
|
923
|
+
handleChainEnd(_outputs, runId) {
|
|
924
|
+
this.ended(runId);
|
|
925
|
+
}
|
|
926
|
+
handleChainError(error, runId) {
|
|
927
|
+
this.ended(runId, error);
|
|
928
|
+
}
|
|
929
|
+
handleChatModelStart(_llm, _messages, runId, parentRunId) {
|
|
930
|
+
this.started(runId, parentRunId);
|
|
931
|
+
}
|
|
932
|
+
handleToolStart(tool2, input, runId, parentRunId, _tags, _metadata, runName, toolCallId) {
|
|
933
|
+
if (replaying() !== null && _metadata?.[RECORDED2] !== true) {
|
|
934
|
+
throw new NiadraReplayRefusedError(runName ?? (isRecord(tool2) && typeof tool2.name === "string" ? tool2.name : "tool"));
|
|
935
|
+
}
|
|
936
|
+
const current = this.hooks.enabled ? resolveSession(this.session) : null;
|
|
937
|
+
if (!current) return;
|
|
938
|
+
const root = parentRunId === void 0 ? void 0 : this.rootOf(parentRunId);
|
|
939
|
+
this.roots.set(runId, root ?? runId);
|
|
940
|
+
const name = runName ?? (isRecord(tool2) && typeof tool2.name === "string" ? tool2.name : "tool");
|
|
941
|
+
this.hooks.toolStart(current, runId, name, parsed(input), { ...root ? { frameKey: root } : {}, callId: toolCallId ?? null });
|
|
942
|
+
}
|
|
943
|
+
handleToolEnd(output, runId) {
|
|
944
|
+
this.roots.delete(runId);
|
|
945
|
+
this.hooks.toolEnd(runId, isRecord(output) && "content" in output ? output.content : output);
|
|
946
|
+
}
|
|
947
|
+
handleToolError(error, runId) {
|
|
948
|
+
this.roots.delete(runId);
|
|
949
|
+
this.hooks.toolEnd(runId, void 0, error);
|
|
950
|
+
}
|
|
951
|
+
handleLLMEnd(output, runId) {
|
|
952
|
+
const current = resolveSession(this.session);
|
|
953
|
+
if (!current) return;
|
|
954
|
+
const bridge = states.get(current)?.bridge ?? new Bridge(current);
|
|
955
|
+
try {
|
|
956
|
+
const generation = output.generations[0]?.[0];
|
|
957
|
+
if (!generation) return;
|
|
958
|
+
const message = isRecord(generation) && "message" in generation ? generation.message : null;
|
|
959
|
+
if (message && runId !== void 0) this.model(current, message, runId);
|
|
960
|
+
const text = message ? message.text : generation.text;
|
|
961
|
+
const usage = message ? langchainUsage(message) : null;
|
|
962
|
+
bridge.agent(text, usage ? { usage } : {});
|
|
963
|
+
} catch (error) {
|
|
964
|
+
bridge.logger.warn(`could not record the agent's answer (${errorName(error)})`);
|
|
965
|
+
} finally {
|
|
966
|
+
if (runId !== void 0) this.ended(runId);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
handleLLMError(error, runId) {
|
|
970
|
+
this.ended(runId, error);
|
|
971
|
+
}
|
|
972
|
+
started(runId, parentRunId) {
|
|
973
|
+
if (!this.hooks.enabled) return;
|
|
974
|
+
if (parentRunId !== void 0) {
|
|
975
|
+
this.roots.set(runId, this.rootOf(parentRunId));
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
const current = resolveSession(this.session);
|
|
979
|
+
if (current) this.hooks.open(current, runId);
|
|
980
|
+
}
|
|
981
|
+
ended(runId, error) {
|
|
982
|
+
if (!this.hooks.enabled) return;
|
|
983
|
+
this.roots.delete(runId);
|
|
984
|
+
if (!this.hooks.has(runId)) return;
|
|
985
|
+
for (const [run, root] of this.roots) if (root === runId) this.roots.delete(run);
|
|
986
|
+
this.hooks.close(runId, error);
|
|
987
|
+
}
|
|
988
|
+
rootOf(runId) {
|
|
989
|
+
return this.roots.get(runId) ?? runId;
|
|
990
|
+
}
|
|
991
|
+
model(session, message, runId) {
|
|
992
|
+
if (!this.hooks.enabled) return;
|
|
993
|
+
const usage = message.usage_metadata;
|
|
994
|
+
const metadata = message.response_metadata;
|
|
995
|
+
const name = [metadata?.model_name, metadata?.model].find((value) => typeof value === "string" && value.length > 0);
|
|
996
|
+
const details = isRecord(usage) && isRecord(usage.input_token_details) ? usage.input_token_details : {};
|
|
997
|
+
this.hooks.model(
|
|
998
|
+
session,
|
|
999
|
+
name,
|
|
1000
|
+
isRecord(usage) ? { in: count(usage.input_tokens), out: count(usage.output_tokens), cached: count(details.cache_read) } : {},
|
|
1001
|
+
this.rootOf(runId)
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
var RECORDED2 = "niadra_recorded";
|
|
1006
|
+
function recordTools(tools, options = {}) {
|
|
1007
|
+
return tools.map((item) => {
|
|
1008
|
+
if (typeof item.func !== "function") throw new TypeError(`${item.name} has no function to wrap: wrap what it calls with tool()`);
|
|
1009
|
+
const func = recordedTool(item.func) ? item.func : tool(item.name, item.func, { args: (input) => input, dryRun: (options.dryRun ?? []).includes(item.name) });
|
|
1010
|
+
return new DynamicStructuredTool({
|
|
1011
|
+
name: item.name,
|
|
1012
|
+
description: item.description,
|
|
1013
|
+
schema: item.schema,
|
|
1014
|
+
func,
|
|
1015
|
+
metadata: { ...item.metadata ?? {}, [RECORDED2]: true }
|
|
1016
|
+
});
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
function niadraTools(session, options = {}) {
|
|
1020
|
+
return new Bridge(session, void 0, options.agentMemory).tools().map(
|
|
1021
|
+
(spec) => new DynamicStructuredTool({
|
|
1022
|
+
name: spec.name,
|
|
1023
|
+
description: spec.description,
|
|
1024
|
+
schema: spec.parameters,
|
|
1025
|
+
func: async (input) => spec.execute(isRecord(input) ? input : {})
|
|
1026
|
+
})
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
function langchainUsage(message) {
|
|
1030
|
+
const usage = message.usage_metadata;
|
|
1031
|
+
const metadata = message.response_metadata;
|
|
1032
|
+
if (!isRecord(usage)) return null;
|
|
1033
|
+
const model = [metadata?.model_name, metadata?.model].find((value) => typeof value === "string" && value.length > 0);
|
|
1034
|
+
const prompt = count(usage.input_tokens);
|
|
1035
|
+
if (!model || prompt === null) return null;
|
|
1036
|
+
const details = isRecord(usage.input_token_details) ? usage.input_token_details : {};
|
|
1037
|
+
const cached = count(details.cache_read) ?? 0;
|
|
1038
|
+
const written = count(details.cache_creation) ?? 0;
|
|
1039
|
+
const declared = typeof metadata?.model_provider === "string" ? metadata.model_provider.toLowerCase() : "";
|
|
1040
|
+
const provider = /^[a-z0-9][a-z0-9_.-]{0,63}$/.test(declared) ? declared : providerOf(model, usage);
|
|
1041
|
+
return { provider, model, prompt_tokens: Math.max(prompt, cached + written), cached_tokens: cached, cache_write_tokens: written };
|
|
1042
|
+
}
|
|
1043
|
+
var RUN_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1044
|
+
function isRunId(value) {
|
|
1045
|
+
return typeof value === "string" && RUN_ID.test(value);
|
|
1046
|
+
}
|
|
1047
|
+
function parsed(input) {
|
|
1048
|
+
try {
|
|
1049
|
+
return JSON.parse(input);
|
|
1050
|
+
} catch {
|
|
1051
|
+
return input;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
function lastHumanIndex(messages) {
|
|
1055
|
+
for (let index = messages.length - 1; index >= 0; index--) if (messages[index]?.type === "human") return index;
|
|
1056
|
+
return -1;
|
|
1057
|
+
}
|
|
1058
|
+
function withSuffix(message, suffix) {
|
|
1059
|
+
const content = message.content;
|
|
1060
|
+
const next = typeof content === "string" ? `${content}
|
|
1061
|
+
|
|
1062
|
+
${suffix}` : [...content, { type: "text", text: suffix }];
|
|
1063
|
+
return new HumanMessage({ ...message.id ? { id: message.id } : {}, content: next });
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
export { NiadraCallbackHandler, RECORDED2 as RECORDED, attestationProof, langchainUsage, niadraContext, niadraTools, recordTools, withNiadraContext };
|
|
1067
|
+
//# sourceMappingURL=langchain.js.map
|
|
1068
|
+
//# sourceMappingURL=langchain.js.map
|