@niadra/sdk 0.1.1 → 0.9.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 +200 -62
- package/README.md +462 -24
- package/dist/ai-sdk.cjs +1036 -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 +1029 -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 +11101 -0
- package/dist/cli.js.map +1 -0
- package/dist/client-B_ip8T2o.d.cts +6960 -0
- package/dist/client-B_ip8T2o.d.ts +6960 -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 +11494 -1910
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +957 -1294
- package/dist/index.d.ts +957 -1294
- package/dist/index.js +11441 -1911
- package/dist/index.js.map +1 -1
- package/dist/intercept-CBaPK_-k.d.ts +20 -0
- package/dist/intercept-CxmBLfoj.d.cts +20 -0
- package/dist/langchain.cjs +1076 -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 +1067 -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 +1081 -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 +1074 -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-BLkAbvuf.d.ts +39 -0
- package/dist/shared-DEkF2Y_z.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-BaraTaA9.d.ts +37 -0
- package/dist/webhook-CuR0Wckd.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 +351 -6
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var ai = require('ai');
|
|
4
|
+
|
|
5
|
+
// src/integrations/ai-sdk.ts
|
|
6
|
+
|
|
7
|
+
// src/capture/tool.ts
|
|
8
|
+
var RECORDED = /* @__PURE__ */ Symbol.for("niadra.tool");
|
|
9
|
+
function recordedTool(fn) {
|
|
10
|
+
return typeof fn === "function" ? fn[RECORDED] ?? null : null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/context.ts
|
|
14
|
+
function emptyResult(error) {
|
|
15
|
+
return { text: "", suffix: "", variables: {}, pack: null, source: "none", ageMs: null, response: null, error, constraints: null, state: null, coordination: null };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/integrations/shared.ts
|
|
19
|
+
var ATTESTED = { A: "V2", B: "V1", C: "V1" };
|
|
20
|
+
function attestationProof(attestation) {
|
|
21
|
+
if (!attestation) return null;
|
|
22
|
+
const value = attestation.trim().toUpperCase();
|
|
23
|
+
if (value.includes("FAILED") || value.startsWith("NO-")) return null;
|
|
24
|
+
const letter = value.length === 1 ? value : /PASSED-([ABC])$/.exec(value)?.[1];
|
|
25
|
+
const level = letter ? ATTESTED[letter] : void 0;
|
|
26
|
+
return level ? { method: "network_attestation", level } : null;
|
|
27
|
+
}
|
|
28
|
+
function resolveSession(source) {
|
|
29
|
+
if (typeof source !== "function") return source;
|
|
30
|
+
try {
|
|
31
|
+
return source() ?? null;
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function isConversation(session) {
|
|
37
|
+
return "customer" in session && typeof session.customer === "function";
|
|
38
|
+
}
|
|
39
|
+
function errorName(error) {
|
|
40
|
+
return error instanceof Error ? error.name : typeof error;
|
|
41
|
+
}
|
|
42
|
+
var Bridge = class {
|
|
43
|
+
constructor(session, proof, memory = false) {
|
|
44
|
+
this.session = session;
|
|
45
|
+
this.proof = proof;
|
|
46
|
+
this.memory = memory;
|
|
47
|
+
}
|
|
48
|
+
session;
|
|
49
|
+
proof;
|
|
50
|
+
memory;
|
|
51
|
+
proving = null;
|
|
52
|
+
/** `begin()` started the first read of a call: the first `context()` waits for it with `ready()`. */
|
|
53
|
+
begun = false;
|
|
54
|
+
opened = false;
|
|
55
|
+
/**
|
|
56
|
+
* The context and, when enabled, the agent's notes, read side by side within the same budget.
|
|
57
|
+
* Never rejects.
|
|
58
|
+
*/
|
|
59
|
+
async read(options = {}) {
|
|
60
|
+
const memoryParams = this.memory === false ? null : this.memory === true ? {} : withoutWrite(this.memory);
|
|
61
|
+
const [context, memory] = await Promise.all([
|
|
62
|
+
this.context(options),
|
|
63
|
+
memoryParams ? this.agentMemory(memoryParams, options) : Promise.resolve("")
|
|
64
|
+
]);
|
|
65
|
+
return { context, memory, prefix: [memory, context.text].filter(Boolean).join("\n\n"), suffix: context.suffix };
|
|
66
|
+
}
|
|
67
|
+
get logger() {
|
|
68
|
+
return this.session.logger;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Starts the first read of a call now, in the background, after the proof when one was given (the
|
|
72
|
+
* pack depends on the level it proves): at call start, so the read runs while the call is set up.
|
|
73
|
+
* The first `context()` then waits for it within `timeouts.contextVoiceStart`. Never throws.
|
|
74
|
+
*/
|
|
75
|
+
begin() {
|
|
76
|
+
const session = this.session;
|
|
77
|
+
if (!isConversation(session)) return;
|
|
78
|
+
const start = () => {
|
|
79
|
+
this.safe("start the first read", () => {
|
|
80
|
+
this.begun = session.begin();
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
if (this.proof === void 0 || this.proof === null) start();
|
|
84
|
+
else void this.verifyOnce().then(start);
|
|
85
|
+
}
|
|
86
|
+
/** Verifies once (when a proof was given), then reads the context. Never rejects. */
|
|
87
|
+
async context(options = {}) {
|
|
88
|
+
await this.verifyOnce();
|
|
89
|
+
try {
|
|
90
|
+
const session = this.session;
|
|
91
|
+
if (this.begun && !this.opened && isConversation(session)) {
|
|
92
|
+
this.opened = true;
|
|
93
|
+
await session.ready(options.timeout === void 0 ? {} : { timeout: options.timeout });
|
|
94
|
+
}
|
|
95
|
+
return await this.session.context(options);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
this.logger.warn(`could not read context (${errorName(error)})`);
|
|
98
|
+
return emptyResult(null);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** Records that `context` went into the prompt, unless it was empty for a reason other than the holdout. */
|
|
102
|
+
injected(context) {
|
|
103
|
+
if (!context.text && !context.suffix && context.response?.path !== "holdout") return;
|
|
104
|
+
this.safe("mark the injection", () => {
|
|
105
|
+
this.session.markInjected(context);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
customer(text, options = {}) {
|
|
109
|
+
const session = this.session;
|
|
110
|
+
if (!text.trim() || !isConversation(session)) return;
|
|
111
|
+
this.safe("record the customer's turn", () => session.customer(text, options));
|
|
112
|
+
}
|
|
113
|
+
/** Sends the customer's turn so far, while they speak. In the background; never throws. */
|
|
114
|
+
prefetch(text) {
|
|
115
|
+
const session = this.session;
|
|
116
|
+
if (!text.trim() || !isConversation(session)) return;
|
|
117
|
+
this.safe("prefetch the turn", () => session.prefetch(text));
|
|
118
|
+
}
|
|
119
|
+
agent(text, options = {}) {
|
|
120
|
+
if (!text.trim()) return;
|
|
121
|
+
this.safe("record the agent's turn", () => this.session.agent(text, options));
|
|
122
|
+
}
|
|
123
|
+
/** Records a transfer. Tasks have no transfer; the call is ignored for them. */
|
|
124
|
+
async handoff(target, reason) {
|
|
125
|
+
const session = this.session;
|
|
126
|
+
if (!isConversation(session)) return;
|
|
127
|
+
try {
|
|
128
|
+
await session.handoff(reason ? { target, reason } : { target });
|
|
129
|
+
} catch (error) {
|
|
130
|
+
this.logger.warn(`could not record the handoff (${errorName(error)})`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async end() {
|
|
134
|
+
try {
|
|
135
|
+
await this.session.end();
|
|
136
|
+
} catch (error) {
|
|
137
|
+
this.logger.warn(`could not end the session (${errorName(error)})`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** The navigation kit as plain specs (with the agent's memory tools when enabled), or none for a task about an object only. */
|
|
141
|
+
tools() {
|
|
142
|
+
let bound;
|
|
143
|
+
try {
|
|
144
|
+
const memory = this.memory;
|
|
145
|
+
bound = this.session.tools(memory === false ? {} : { agentMemory: true, writeAgentMemory: memory !== true && memory.write === true });
|
|
146
|
+
} catch (error) {
|
|
147
|
+
this.logger.warn(`could not build the tools (${errorName(error)})`);
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
return bound ? toolSpecs(bound) : [];
|
|
151
|
+
}
|
|
152
|
+
async agentMemory(params, options) {
|
|
153
|
+
try {
|
|
154
|
+
const result = await this.session.agentMemory(params, options.timeout === void 0 ? {} : { timeout: options.timeout });
|
|
155
|
+
return result.text;
|
|
156
|
+
} catch (error) {
|
|
157
|
+
this.logger.warn(`could not read the agent's memory (${errorName(error)})`);
|
|
158
|
+
return "";
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async verifyOnce() {
|
|
162
|
+
if (this.proof === void 0 || this.proof === null) return;
|
|
163
|
+
this.proving ??= this.runVerify();
|
|
164
|
+
await this.proving;
|
|
165
|
+
}
|
|
166
|
+
async runVerify() {
|
|
167
|
+
try {
|
|
168
|
+
const source = this.proof;
|
|
169
|
+
const proof = typeof source === "function" ? await source() : source;
|
|
170
|
+
if (!proof) return;
|
|
171
|
+
await this.session.verify(proof);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
this.logger.warn(`could not record the verification (${errorName(error)})`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
safe(what, run) {
|
|
177
|
+
try {
|
|
178
|
+
run();
|
|
179
|
+
} catch (error) {
|
|
180
|
+
this.logger.warn(`could not ${what} (${errorName(error)})`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
function withoutWrite(option) {
|
|
185
|
+
const { write: _, ...params } = option;
|
|
186
|
+
return params;
|
|
187
|
+
}
|
|
188
|
+
function toolSpecs(bound) {
|
|
189
|
+
return bound.definitions.map(({ function: definition }) => ({
|
|
190
|
+
name: definition.name,
|
|
191
|
+
description: definition.description,
|
|
192
|
+
parameters: definition.parameters,
|
|
193
|
+
execute: (args) => bound.call(definition.name, args)
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
function textOf(content) {
|
|
197
|
+
if (typeof content === "string") return content;
|
|
198
|
+
if (!Array.isArray(content)) return "";
|
|
199
|
+
const parts = [];
|
|
200
|
+
for (const part of content) {
|
|
201
|
+
if (typeof part === "string") parts.push(part);
|
|
202
|
+
else if (isRecord(part) && typeof part.text === "string" && (part.type === void 0 || part.type === "text")) {
|
|
203
|
+
parts.push(part.text);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return parts.join("");
|
|
207
|
+
}
|
|
208
|
+
function isRecord(value) {
|
|
209
|
+
return typeof value === "object" && value !== null;
|
|
210
|
+
}
|
|
211
|
+
function count(value) {
|
|
212
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : null;
|
|
213
|
+
}
|
|
214
|
+
var TurnHooks = class _TurnHooks {
|
|
215
|
+
constructor(adapter, enabled) {
|
|
216
|
+
this.adapter = adapter;
|
|
217
|
+
this.enabled = enabled;
|
|
218
|
+
}
|
|
219
|
+
adapter;
|
|
220
|
+
enabled;
|
|
221
|
+
/** Runs held open at most; past it the oldest run's turn closes, incomplete (a run whose end never came). */
|
|
222
|
+
static MAX_OPEN = 100;
|
|
223
|
+
frames = /* @__PURE__ */ new Map();
|
|
224
|
+
calls = /* @__PURE__ */ new Map();
|
|
225
|
+
/** The turn of the run `key`: the session's turn in progress, or a new one of its own. */
|
|
226
|
+
open(session, key, params = {}) {
|
|
227
|
+
if (!this.enabled) return void 0;
|
|
228
|
+
const held = this.frames.get(key);
|
|
229
|
+
if (held !== void 0) return held.frame;
|
|
230
|
+
try {
|
|
231
|
+
const active = session.activeTurn();
|
|
232
|
+
if (active !== void 0 && !this.owns(active)) {
|
|
233
|
+
this.frames.set(key, { frame: active, own: false });
|
|
234
|
+
return active;
|
|
235
|
+
}
|
|
236
|
+
const frame = session.openTurn({ ...params, adapter: this.adapter });
|
|
237
|
+
this.frames.set(key, { frame, own: true });
|
|
238
|
+
if (this.frames.size > _TurnHooks.MAX_OPEN) {
|
|
239
|
+
const [oldest] = this.frames.keys();
|
|
240
|
+
if (oldest !== void 0) {
|
|
241
|
+
this.frames.get(oldest)?.frame.incomplete();
|
|
242
|
+
this.close(oldest);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return frame;
|
|
246
|
+
} catch (error) {
|
|
247
|
+
session.logger.warn(`could not open the turn (${errorName(error)})`);
|
|
248
|
+
return void 0;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/** The turn of `key`, else the session's turn in progress. */
|
|
252
|
+
frame(session, key) {
|
|
253
|
+
if (!this.enabled) return void 0;
|
|
254
|
+
const held = key === void 0 ? void 0 : this.frames.get(key);
|
|
255
|
+
const frame = held?.frame ?? session.activeTurn();
|
|
256
|
+
return frame === void 0 || frame.closed ? void 0 : frame;
|
|
257
|
+
}
|
|
258
|
+
has(key) {
|
|
259
|
+
return this.frames.has(key);
|
|
260
|
+
}
|
|
261
|
+
owns(frame) {
|
|
262
|
+
for (const held of this.frames.values()) if (held.own && held.frame === frame) return true;
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
/** Ends the run `key`: a turn the adapter opened closes; the calls it left open failed. */
|
|
266
|
+
close(key, error) {
|
|
267
|
+
const held = this.frames.get(key);
|
|
268
|
+
if (held === void 0) return;
|
|
269
|
+
this.frames.delete(key);
|
|
270
|
+
for (const [callKey, call] of this.calls) {
|
|
271
|
+
if (call.frame !== held.frame) continue;
|
|
272
|
+
this.calls.delete(callKey);
|
|
273
|
+
if (held.own) call.failed(error ?? "error");
|
|
274
|
+
}
|
|
275
|
+
if (held.own) held.frame.close(error);
|
|
276
|
+
}
|
|
277
|
+
/** A tool call starting, keyed by `callKey`; `callId` is the provider's id of the call, when there is one. */
|
|
278
|
+
toolStart(session, callKey, name, args, options = {}) {
|
|
279
|
+
const frame = this.frame(session, options.frameKey);
|
|
280
|
+
if (frame === void 0) return;
|
|
281
|
+
try {
|
|
282
|
+
this.calls.set(callKey, frame.toolCall(name, args, { callId: options.callId ?? null, adoptable: true }));
|
|
283
|
+
} catch {
|
|
284
|
+
frame.incomplete();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* In a replay, how a framework tool the adapter stands in for answers: the recorded result of a call with the
|
|
289
|
+
* same arguments, or empty (a divergence), never the live tool. `null` outside a replay, and for a function
|
|
290
|
+
* wrapped with `tool()`, which answers itself.
|
|
291
|
+
*/
|
|
292
|
+
replayed(session, name, args, fn, frameKey) {
|
|
293
|
+
const frame = this.enabled ? this.frame(session, frameKey) : session.activeTurn();
|
|
294
|
+
if (frame?.playback == null || fn !== void 0 && recordedTool(fn) !== null) return null;
|
|
295
|
+
return frame.playback.answer(name, args, false);
|
|
296
|
+
}
|
|
297
|
+
toolEnd(callKey, result, error) {
|
|
298
|
+
const call = this.calls.get(callKey);
|
|
299
|
+
if (call === void 0) return;
|
|
300
|
+
this.calls.delete(callKey);
|
|
301
|
+
try {
|
|
302
|
+
if (error !== void 0) call.failed(error);
|
|
303
|
+
else call.result(result);
|
|
304
|
+
} catch {
|
|
305
|
+
call.frame.incomplete();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/** A model call that ended, with its tokens when the framework reported them. */
|
|
309
|
+
model(session, model, tokens = {}, frameKey) {
|
|
310
|
+
const frame = this.frame(session, frameKey);
|
|
311
|
+
if (frame === void 0) return;
|
|
312
|
+
try {
|
|
313
|
+
frame.modelCall(model, { tokensIn: tokens.in ?? null, tokensOut: tokens.out ?? null, tokensCached: tokens.cached ?? 0 });
|
|
314
|
+
} catch {
|
|
315
|
+
frame.incomplete();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
// src/integrations/prompt.ts
|
|
321
|
+
function injectPrompt(prompt, read) {
|
|
322
|
+
const injected = [...prompt];
|
|
323
|
+
if (read.suffix) {
|
|
324
|
+
const last = lastUserIndex(injected);
|
|
325
|
+
const message = injected[last];
|
|
326
|
+
if (isRecord(message) && Array.isArray(message.content)) {
|
|
327
|
+
injected[last] = { ...message, content: [...message.content, { type: "text", text: read.suffix }] };
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (read.prefix) {
|
|
331
|
+
let position = 0;
|
|
332
|
+
while (position < injected.length && roleOf(injected[position]) === "system") position++;
|
|
333
|
+
injected.splice(position, 0, { role: "system", content: read.prefix });
|
|
334
|
+
}
|
|
335
|
+
return injected;
|
|
336
|
+
}
|
|
337
|
+
function recordNewest(bridge, seen, prompt) {
|
|
338
|
+
const index = lastUserIndex(prompt);
|
|
339
|
+
if (index < 0) return;
|
|
340
|
+
const message = prompt[index];
|
|
341
|
+
const text = isRecord(message) ? textParts(message.content) : "";
|
|
342
|
+
const key = `${String(index)}:${text}`;
|
|
343
|
+
if (!text || seen.has(key)) return;
|
|
344
|
+
seen.add(key);
|
|
345
|
+
bridge.customer(text);
|
|
346
|
+
}
|
|
347
|
+
function textParts(content) {
|
|
348
|
+
if (typeof content === "string") return content;
|
|
349
|
+
if (!Array.isArray(content)) return "";
|
|
350
|
+
return content.map((part) => isRecord(part) && part.type === "text" && typeof part.text === "string" ? part.text : "").filter(Boolean).join("\n");
|
|
351
|
+
}
|
|
352
|
+
function lastUserIndex(prompt) {
|
|
353
|
+
for (let index = prompt.length - 1; index >= 0; index--) if (roleOf(prompt[index]) === "user") return index;
|
|
354
|
+
return -1;
|
|
355
|
+
}
|
|
356
|
+
function roleOf(message) {
|
|
357
|
+
return isRecord(message) && typeof message.role === "string" ? message.role : "";
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/integrations/ai-sdk.ts
|
|
361
|
+
function niadraMiddleware(session, options = {}) {
|
|
362
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
363
|
+
const hooks = new TurnHooks("ai-sdk", true);
|
|
364
|
+
const modelCall = (usage, model, modelId) => {
|
|
365
|
+
const current = resolveSession(session);
|
|
366
|
+
if (!current) return;
|
|
367
|
+
const name = typeof modelId === "string" && modelId ? modelId : model.modelId;
|
|
368
|
+
const reported = aiSdkUsage(usage, model, modelId);
|
|
369
|
+
const out = isRecord(usage) ? count(usage.outputTokens) ?? (isRecord(usage.outputTokens) ? count(usage.outputTokens.total) : null) : null;
|
|
370
|
+
hooks.model(current, name, reported ? { in: reported.prompt_tokens, out, cached: reported.cached_tokens ?? 0 } : {});
|
|
371
|
+
};
|
|
372
|
+
const stateOf = () => {
|
|
373
|
+
const current = resolveSession(session);
|
|
374
|
+
if (!current) return null;
|
|
375
|
+
let state = states.get(current);
|
|
376
|
+
if (!state) {
|
|
377
|
+
state = { bridge: new Bridge(current, options.verify, options.agentMemory), seen: /* @__PURE__ */ new Set() };
|
|
378
|
+
states.set(current, state);
|
|
379
|
+
}
|
|
380
|
+
return state;
|
|
381
|
+
};
|
|
382
|
+
return {
|
|
383
|
+
specificationVersion: "v3",
|
|
384
|
+
async transformParams({ params }) {
|
|
385
|
+
const state = stateOf();
|
|
386
|
+
if (!state || !Array.isArray(params.prompt)) return params;
|
|
387
|
+
try {
|
|
388
|
+
const prompt = params.prompt;
|
|
389
|
+
if (options.recordCustomer ?? true) recordNewest(state.bridge, state.seen, prompt);
|
|
390
|
+
const read = await state.bridge.read();
|
|
391
|
+
state.bridge.injected(read.context);
|
|
392
|
+
return { ...params, prompt: injectPrompt(prompt, read) };
|
|
393
|
+
} catch (error) {
|
|
394
|
+
state.bridge.logger.warn(`could not inject context (${errorName(error)})`);
|
|
395
|
+
return params;
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
async wrapGenerate({ doGenerate, model }) {
|
|
399
|
+
const result = await doGenerate();
|
|
400
|
+
if (isRecord(result)) modelCall(result.usage, model, isRecord(result.response) ? result.response.modelId : void 0);
|
|
401
|
+
if (options.recordAgent ?? true) {
|
|
402
|
+
const state = stateOf();
|
|
403
|
+
if (state) {
|
|
404
|
+
try {
|
|
405
|
+
const content = isRecord(result) && Array.isArray(result.content) ? result.content : [];
|
|
406
|
+
const text = content.map((part) => isRecord(part) && part.type === "text" && typeof part.text === "string" ? part.text : "").join("");
|
|
407
|
+
const response = isRecord(result) && isRecord(result.response) ? result.response : {};
|
|
408
|
+
record(state, text, isRecord(result) ? result.usage : void 0, model, response.modelId);
|
|
409
|
+
} catch (error) {
|
|
410
|
+
state.bridge.logger.warn(`could not capture the model's answer (${errorName(error)})`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return result;
|
|
415
|
+
},
|
|
416
|
+
async wrapStream({ doStream, model }) {
|
|
417
|
+
const result = await doStream();
|
|
418
|
+
const state = options.recordAgent ?? true ? stateOf() : null;
|
|
419
|
+
if (!state || !isRecord(result) || !(result.stream instanceof ReadableStream)) return result;
|
|
420
|
+
const parts = [];
|
|
421
|
+
let usage;
|
|
422
|
+
let modelId;
|
|
423
|
+
const capture = new TransformStream({
|
|
424
|
+
transform(chunk, controller) {
|
|
425
|
+
if (isRecord(chunk)) {
|
|
426
|
+
if (chunk.type === "text-delta") parts.push(typeof chunk.delta === "string" ? chunk.delta : typeof chunk.textDelta === "string" ? chunk.textDelta : "");
|
|
427
|
+
else if (chunk.type === "finish") usage = chunk.usage;
|
|
428
|
+
else if (chunk.type === "response-metadata") modelId = chunk.modelId;
|
|
429
|
+
}
|
|
430
|
+
controller.enqueue(chunk);
|
|
431
|
+
},
|
|
432
|
+
flush() {
|
|
433
|
+
try {
|
|
434
|
+
modelCall(usage, model, modelId);
|
|
435
|
+
record(state, parts.join(""), usage, model, modelId);
|
|
436
|
+
} catch (error) {
|
|
437
|
+
state.bridge.logger.warn(`could not capture the model's answer (${errorName(error)})`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
return { ...result, stream: result.stream.pipeThrough(capture) };
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
function niadraTools(session, options = {}) {
|
|
446
|
+
const tools = {};
|
|
447
|
+
for (const spec of new Bridge(session, void 0, options.agentMemory).tools()) {
|
|
448
|
+
tools[spec.name] = ai.tool({
|
|
449
|
+
description: spec.description,
|
|
450
|
+
inputSchema: ai.jsonSchema(spec.parameters),
|
|
451
|
+
execute: async (input) => parsed(await spec.execute(input))
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
return tools;
|
|
455
|
+
}
|
|
456
|
+
function aiSdkUsage(usage, model, modelId) {
|
|
457
|
+
if (!isRecord(usage)) return null;
|
|
458
|
+
const name = typeof modelId === "string" && modelId ? modelId : model.modelId;
|
|
459
|
+
const provider = model.provider?.split(".")[0]?.toLowerCase();
|
|
460
|
+
if (!name || !provider) return null;
|
|
461
|
+
let prompt;
|
|
462
|
+
let cached;
|
|
463
|
+
let written;
|
|
464
|
+
if (isRecord(usage.inputTokens)) {
|
|
465
|
+
const input = usage.inputTokens;
|
|
466
|
+
cached = count(input.cacheRead) ?? 0;
|
|
467
|
+
written = count(input.cacheWrite) ?? 0;
|
|
468
|
+
prompt = count(input.total) ?? (count(input.noCache) === null ? null : (count(input.noCache) ?? 0) + cached + written);
|
|
469
|
+
} else {
|
|
470
|
+
prompt = count(usage.inputTokens);
|
|
471
|
+
cached = count(usage.cachedInputTokens) ?? 0;
|
|
472
|
+
written = 0;
|
|
473
|
+
}
|
|
474
|
+
if (prompt === null) return null;
|
|
475
|
+
return { provider, model: name, prompt_tokens: Math.max(prompt, cached + written), cached_tokens: cached, cache_write_tokens: written };
|
|
476
|
+
}
|
|
477
|
+
function record(state, text, usage, model, modelId) {
|
|
478
|
+
const reported = aiSdkUsage(usage, model, modelId);
|
|
479
|
+
state.bridge.agent(text, reported ? { usage: reported } : {});
|
|
480
|
+
}
|
|
481
|
+
function parsed(text) {
|
|
482
|
+
try {
|
|
483
|
+
return JSON.parse(text);
|
|
484
|
+
} catch {
|
|
485
|
+
return text;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/integrations/cloudflare-agents.ts
|
|
490
|
+
var helpers = /* @__PURE__ */ new WeakMap();
|
|
491
|
+
function niadraAgent(agent, options) {
|
|
492
|
+
const existing = helpers.get(agent);
|
|
493
|
+
if (existing) return existing;
|
|
494
|
+
const helper = build(agent, options);
|
|
495
|
+
helpers.set(agent, helper);
|
|
496
|
+
return helper;
|
|
497
|
+
}
|
|
498
|
+
function build(agent, options) {
|
|
499
|
+
const logger = options.niadra.logger;
|
|
500
|
+
const session = options.session ?? open(agent, options);
|
|
501
|
+
const waitUntil = options.waitUntil ?? waitUntilOf(agent);
|
|
502
|
+
const flush = () => {
|
|
503
|
+
try {
|
|
504
|
+
const sending = options.niadra.flush().catch((error) => {
|
|
505
|
+
logger.warn(`could not send to Niadra (${errorName(error)})`);
|
|
506
|
+
});
|
|
507
|
+
waitUntil?.(sending);
|
|
508
|
+
} catch (error) {
|
|
509
|
+
logger.warn(`could not schedule the flush (${errorName(error)})`);
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
const base = niadraMiddleware(session ?? (() => null), {
|
|
513
|
+
...options.verify === void 0 ? {} : { verify: options.verify },
|
|
514
|
+
...options.recordCustomer === void 0 ? {} : { recordCustomer: options.recordCustomer },
|
|
515
|
+
...options.recordAgent === void 0 ? {} : { recordAgent: options.recordAgent },
|
|
516
|
+
...options.agentMemory === void 0 ? {} : { agentMemory: options.agentMemory }
|
|
517
|
+
});
|
|
518
|
+
const middleware = {
|
|
519
|
+
specificationVersion: base.specificationVersion,
|
|
520
|
+
transformParams: (call) => base.transformParams(call),
|
|
521
|
+
async wrapGenerate(call) {
|
|
522
|
+
const result = await base.wrapGenerate(call);
|
|
523
|
+
flush();
|
|
524
|
+
return result;
|
|
525
|
+
},
|
|
526
|
+
async wrapStream(call) {
|
|
527
|
+
const result = await base.wrapStream(call);
|
|
528
|
+
if (!isRecord(result) || !(result.stream instanceof ReadableStream)) return result;
|
|
529
|
+
const after = new TransformStream({ flush });
|
|
530
|
+
return { ...result, stream: result.stream.pipeThrough(after) };
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
const bridge = session ? new Bridge(session, options.verify, options.agentMemory) : null;
|
|
534
|
+
const seen = /* @__PURE__ */ new Set();
|
|
535
|
+
return {
|
|
536
|
+
session,
|
|
537
|
+
middleware,
|
|
538
|
+
tools: () => session ? niadraTools(session, options.agentMemory === void 0 ? {} : { agentMemory: options.agentMemory }) : {},
|
|
539
|
+
async prepare(messages) {
|
|
540
|
+
if (!bridge) return [...messages];
|
|
541
|
+
try {
|
|
542
|
+
if (options.recordCustomer ?? true) {
|
|
543
|
+
const index = lastUser(messages);
|
|
544
|
+
const text = index >= 0 ? textOf(messages[index]?.content) : "";
|
|
545
|
+
const key = `${String(index)}:${text}`;
|
|
546
|
+
if (text && !seen.has(key)) {
|
|
547
|
+
seen.add(key);
|
|
548
|
+
bridge.customer(text);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
const read = await bridge.read();
|
|
552
|
+
bridge.injected(read.context);
|
|
553
|
+
return inject(messages, read.prefix, read.suffix);
|
|
554
|
+
} catch (error) {
|
|
555
|
+
logger.warn(`could not inject context (${errorName(error)})`);
|
|
556
|
+
return [...messages];
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
record(text, turn = {}) {
|
|
560
|
+
if (!bridge || !(options.recordAgent ?? true)) return;
|
|
561
|
+
bridge.agent(text, turn);
|
|
562
|
+
flush();
|
|
563
|
+
},
|
|
564
|
+
flush,
|
|
565
|
+
async end() {
|
|
566
|
+
if (bridge) await bridge.end();
|
|
567
|
+
flush();
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
function open(agent, options) {
|
|
572
|
+
let subject;
|
|
573
|
+
try {
|
|
574
|
+
subject = typeof options.subject === "function" ? options.subject(agent) : options.subject;
|
|
575
|
+
} catch (error) {
|
|
576
|
+
options.niadra.logger.warn(`could not find the customer (${errorName(error)})`);
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
579
|
+
if (!subject) return null;
|
|
580
|
+
return options.niadra.conversation({ subject, channel: options.channel ?? "web_chat", conversation_id: options.conversationId ?? agent.name });
|
|
581
|
+
}
|
|
582
|
+
function workersAiUsage(answer, model) {
|
|
583
|
+
const usage = isRecord(answer) && isRecord(answer.usage) ? answer.usage : null;
|
|
584
|
+
const prompt = usage ? count(usage.prompt_tokens) : null;
|
|
585
|
+
const name = model.replace(/^@/, "");
|
|
586
|
+
if (prompt === null || !name) return null;
|
|
587
|
+
const details = usage && isRecord(usage.prompt_tokens_details) ? usage.prompt_tokens_details : {};
|
|
588
|
+
const cached = Math.min(count(details.cached_tokens) ?? 0, prompt);
|
|
589
|
+
return { provider: "workers-ai", model: name, prompt_tokens: prompt, cached_tokens: cached, cache_write_tokens: 0 };
|
|
590
|
+
}
|
|
591
|
+
function waitUntilOf(agent) {
|
|
592
|
+
const ctx = agent.ctx;
|
|
593
|
+
if (!isRecord(ctx) || typeof ctx.waitUntil !== "function") return void 0;
|
|
594
|
+
const waitUntil = ctx.waitUntil;
|
|
595
|
+
return (promise) => {
|
|
596
|
+
waitUntil.call(ctx, promise);
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
function lastUser(messages) {
|
|
600
|
+
for (let index = messages.length - 1; index >= 0; index--) if (messages[index]?.role === "user") return index;
|
|
601
|
+
return -1;
|
|
602
|
+
}
|
|
603
|
+
function inject(messages, prefix, suffix) {
|
|
604
|
+
const result = [...messages];
|
|
605
|
+
const index = lastUser(result);
|
|
606
|
+
const last = result[index];
|
|
607
|
+
if (suffix && last) {
|
|
608
|
+
const content = last.content;
|
|
609
|
+
const next = typeof content === "string" ? `${content}
|
|
610
|
+
|
|
611
|
+
${suffix}` : Array.isArray(content) ? [...content, { type: "text", text: suffix }] : content;
|
|
612
|
+
result[index] = { ...last, content: next };
|
|
613
|
+
}
|
|
614
|
+
if (prefix) {
|
|
615
|
+
let position = 0;
|
|
616
|
+
while (position < result.length && result[position]?.role === "system") position++;
|
|
617
|
+
result.splice(position, 0, { role: "system", content: prefix });
|
|
618
|
+
}
|
|
619
|
+
return result;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
exports.attestationProof = attestationProof;
|
|
623
|
+
exports.niadraAgent = niadraAgent;
|
|
624
|
+
exports.workersAiUsage = workersAiUsage;
|
|
625
|
+
//# sourceMappingURL=cloudflare-agents.cjs.map
|
|
626
|
+
//# sourceMappingURL=cloudflare-agents.cjs.map
|