@raindrop-ai/langchain 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -0
- package/dist/index.d.mts +320 -0
- package/dist/index.d.ts +320 -0
- package/dist/index.js +1147 -0
- package/dist/index.mjs +1119 -0
- package/package.json +45 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
RaindropCallbackHandler: () => RaindropCallbackHandler,
|
|
24
|
+
createRaindropLangChain: () => createRaindropLangChain
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/callback-handler.ts
|
|
29
|
+
var import_base = require("@langchain/core/callbacks/base");
|
|
30
|
+
|
|
31
|
+
// ../core/dist/chunk-FOHDGBT5.js
|
|
32
|
+
function getCrypto() {
|
|
33
|
+
const c = globalThis.crypto;
|
|
34
|
+
return c;
|
|
35
|
+
}
|
|
36
|
+
function randomBytes(length) {
|
|
37
|
+
const cryptoObj = getCrypto();
|
|
38
|
+
const out = new Uint8Array(length);
|
|
39
|
+
if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
|
|
40
|
+
cryptoObj.getRandomValues(out);
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
function randomUUID() {
|
|
47
|
+
const cryptoObj = getCrypto();
|
|
48
|
+
if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
|
|
49
|
+
return cryptoObj.randomUUID();
|
|
50
|
+
}
|
|
51
|
+
const b = randomBytes(16);
|
|
52
|
+
b[6] = b[6] & 15 | 64;
|
|
53
|
+
b[8] = b[8] & 63 | 128;
|
|
54
|
+
const hex = [...b].map((x) => x.toString(16).padStart(2, "0")).join("");
|
|
55
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
56
|
+
}
|
|
57
|
+
function base64Encode(bytes) {
|
|
58
|
+
const maybeBuffer = globalThis.Buffer;
|
|
59
|
+
if (maybeBuffer) {
|
|
60
|
+
return maybeBuffer.from(bytes).toString("base64");
|
|
61
|
+
}
|
|
62
|
+
let binary = "";
|
|
63
|
+
for (let i2 = 0; i2 < bytes.length; i2++) {
|
|
64
|
+
binary += String.fromCharCode(bytes[i2]);
|
|
65
|
+
}
|
|
66
|
+
const btoaFn = globalThis.btoa;
|
|
67
|
+
if (typeof btoaFn === "function") return btoaFn(binary);
|
|
68
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
69
|
+
let out = "";
|
|
70
|
+
let i = 0;
|
|
71
|
+
while (i < binary.length) {
|
|
72
|
+
const c1 = binary.charCodeAt(i++) & 255;
|
|
73
|
+
const c2 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
|
|
74
|
+
const c3 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
|
|
75
|
+
const e1 = c1 >> 2;
|
|
76
|
+
const e2 = (c1 & 3) << 4 | (Number.isNaN(c2) ? 0 : c2 >> 4);
|
|
77
|
+
const e3 = Number.isNaN(c2) ? 64 : (c2 & 15) << 2 | (Number.isNaN(c3) ? 0 : c3 >> 6);
|
|
78
|
+
const e4 = Number.isNaN(c3) ? 64 : c3 & 63;
|
|
79
|
+
out += alphabet.charAt(e1);
|
|
80
|
+
out += alphabet.charAt(e2);
|
|
81
|
+
out += e3 === 64 ? "=" : alphabet.charAt(e3);
|
|
82
|
+
out += e4 === 64 ? "=" : alphabet.charAt(e4);
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
function wait(ms) {
|
|
87
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
88
|
+
}
|
|
89
|
+
function formatEndpoint(endpoint) {
|
|
90
|
+
if (!endpoint) return void 0;
|
|
91
|
+
return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
|
|
92
|
+
}
|
|
93
|
+
function parseRetryAfter(headers) {
|
|
94
|
+
var _a;
|
|
95
|
+
const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
|
|
96
|
+
if (!value) return void 0;
|
|
97
|
+
const asNumber = Number(value);
|
|
98
|
+
if (value.trim() !== "" && !Number.isNaN(asNumber)) return asNumber * 1e3;
|
|
99
|
+
const asDate = new Date(value).getTime();
|
|
100
|
+
if (!Number.isNaN(asDate)) {
|
|
101
|
+
const delta = asDate - Date.now();
|
|
102
|
+
return delta > 0 ? delta : 0;
|
|
103
|
+
}
|
|
104
|
+
return void 0;
|
|
105
|
+
}
|
|
106
|
+
function getRetryDelayMs(attemptNumber, previousError) {
|
|
107
|
+
if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
|
|
108
|
+
const v = previousError.retryAfterMs;
|
|
109
|
+
if (typeof v === "number") return Math.max(0, v);
|
|
110
|
+
}
|
|
111
|
+
if (attemptNumber <= 1) return 0;
|
|
112
|
+
const base = 500;
|
|
113
|
+
const factor = Math.pow(2, attemptNumber - 2);
|
|
114
|
+
return base * factor;
|
|
115
|
+
}
|
|
116
|
+
async function withRetry(operation, opName, opts) {
|
|
117
|
+
const prefix = opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
|
|
118
|
+
let lastError = void 0;
|
|
119
|
+
for (let attemptNumber = 1; attemptNumber <= opts.maxAttempts; attemptNumber++) {
|
|
120
|
+
if (attemptNumber > 1) {
|
|
121
|
+
const delay = getRetryDelayMs(attemptNumber, lastError);
|
|
122
|
+
if (opts.debug) {
|
|
123
|
+
console.warn(
|
|
124
|
+
`${prefix} ${opName} retry ${attemptNumber}/${opts.maxAttempts} in ${delay}ms`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
if (delay > 0) await wait(delay);
|
|
128
|
+
} else if (opts.debug) {
|
|
129
|
+
console.log(`${prefix} ${opName} attempt ${attemptNumber}/${opts.maxAttempts}`);
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
return await operation();
|
|
133
|
+
} catch (err) {
|
|
134
|
+
lastError = err;
|
|
135
|
+
if (opts.debug) {
|
|
136
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
137
|
+
console.warn(
|
|
138
|
+
`${prefix} ${opName} attempt ${attemptNumber} failed: ${msg}${attemptNumber === opts.maxAttempts ? " (no more retries)" : ""}`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
if (lastError && typeof lastError === "object" && "retryable" in lastError && !lastError.retryable)
|
|
142
|
+
break;
|
|
143
|
+
if (attemptNumber === opts.maxAttempts) break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
147
|
+
}
|
|
148
|
+
async function postJson(url, body, headers, opts) {
|
|
149
|
+
const opName = `POST ${url}`;
|
|
150
|
+
await withRetry(
|
|
151
|
+
async () => {
|
|
152
|
+
const resp = await fetch(url, {
|
|
153
|
+
method: "POST",
|
|
154
|
+
headers: {
|
|
155
|
+
"Content-Type": "application/json",
|
|
156
|
+
...headers
|
|
157
|
+
},
|
|
158
|
+
body: JSON.stringify(body)
|
|
159
|
+
});
|
|
160
|
+
if (!resp.ok) {
|
|
161
|
+
const text = await resp.text().catch(() => "");
|
|
162
|
+
const err = new Error(
|
|
163
|
+
`HTTP ${resp.status} ${resp.statusText}${text ? `: ${text}` : ""}`
|
|
164
|
+
);
|
|
165
|
+
const retryAfterMs = parseRetryAfter(resp.headers);
|
|
166
|
+
if (typeof retryAfterMs === "number") err.retryAfterMs = retryAfterMs;
|
|
167
|
+
err.retryable = resp.status === 429 || resp.status >= 500;
|
|
168
|
+
throw err;
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
opName,
|
|
172
|
+
opts
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
var SpanStatusCode = {
|
|
176
|
+
UNSET: 0,
|
|
177
|
+
OK: 1,
|
|
178
|
+
ERROR: 2
|
|
179
|
+
};
|
|
180
|
+
function createSpanIds(parent) {
|
|
181
|
+
const traceId = parent ? parent.traceIdB64 : base64Encode(randomBytes(16));
|
|
182
|
+
const spanId = base64Encode(randomBytes(8));
|
|
183
|
+
return {
|
|
184
|
+
traceIdB64: traceId,
|
|
185
|
+
spanIdB64: spanId,
|
|
186
|
+
parentSpanIdB64: parent ? parent.spanIdB64 : void 0
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function nowUnixNanoString() {
|
|
190
|
+
return Date.now().toString() + "000000";
|
|
191
|
+
}
|
|
192
|
+
function attrString(key, value) {
|
|
193
|
+
if (value === void 0) return void 0;
|
|
194
|
+
return { key, value: { stringValue: value } };
|
|
195
|
+
}
|
|
196
|
+
function attrInt(key, value) {
|
|
197
|
+
if (value === void 0) return void 0;
|
|
198
|
+
if (!Number.isFinite(value)) return void 0;
|
|
199
|
+
return { key, value: { intValue: String(Math.trunc(value)) } };
|
|
200
|
+
}
|
|
201
|
+
function buildOtlpSpan(args) {
|
|
202
|
+
const attrs = args.attributes.filter((x) => x !== void 0);
|
|
203
|
+
const span = {
|
|
204
|
+
traceId: args.ids.traceIdB64,
|
|
205
|
+
spanId: args.ids.spanIdB64,
|
|
206
|
+
name: args.name,
|
|
207
|
+
startTimeUnixNano: args.startTimeUnixNano,
|
|
208
|
+
endTimeUnixNano: args.endTimeUnixNano
|
|
209
|
+
};
|
|
210
|
+
if (args.ids.parentSpanIdB64) span.parentSpanId = args.ids.parentSpanIdB64;
|
|
211
|
+
if (attrs.length) span.attributes = attrs;
|
|
212
|
+
if (args.status) span.status = args.status;
|
|
213
|
+
return span;
|
|
214
|
+
}
|
|
215
|
+
function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", serviceVersion = "0.0.0") {
|
|
216
|
+
return {
|
|
217
|
+
resourceSpans: [
|
|
218
|
+
{
|
|
219
|
+
resource: {
|
|
220
|
+
attributes: [{ key: "service.name", value: { stringValue: serviceName } }]
|
|
221
|
+
},
|
|
222
|
+
scopeSpans: [
|
|
223
|
+
{
|
|
224
|
+
scope: { name: serviceName, version: serviceVersion },
|
|
225
|
+
spans
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function mergePatches(target, source) {
|
|
233
|
+
var _a, _b, _c, _d;
|
|
234
|
+
const out = { ...target, ...source };
|
|
235
|
+
if (target.properties || source.properties) {
|
|
236
|
+
out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
|
|
237
|
+
}
|
|
238
|
+
if (target.attachments || source.attachments) {
|
|
239
|
+
out.attachments = [...(_c = target.attachments) != null ? _c : [], ...(_d = source.attachments) != null ? _d : []];
|
|
240
|
+
}
|
|
241
|
+
return out;
|
|
242
|
+
}
|
|
243
|
+
var EventShipper = class {
|
|
244
|
+
constructor(opts) {
|
|
245
|
+
this.buffers = /* @__PURE__ */ new Map();
|
|
246
|
+
this.sticky = /* @__PURE__ */ new Map();
|
|
247
|
+
this.timers = /* @__PURE__ */ new Map();
|
|
248
|
+
this.inFlight = /* @__PURE__ */ new Set();
|
|
249
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
250
|
+
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
251
|
+
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
252
|
+
this.enabled = opts.enabled !== false;
|
|
253
|
+
this.debug = opts.debug;
|
|
254
|
+
this.partialFlushMs = (_c = opts.partialFlushMs) != null ? _c : 1e3;
|
|
255
|
+
this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
|
|
256
|
+
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
257
|
+
this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
|
|
258
|
+
const isNode = typeof process !== "undefined" && typeof process.version === "string";
|
|
259
|
+
this.context = {
|
|
260
|
+
library: {
|
|
261
|
+
name: (_f = opts.libraryName) != null ? _f : "@raindrop-ai/core",
|
|
262
|
+
version: (_g = opts.libraryVersion) != null ? _g : "0.0.0"
|
|
263
|
+
},
|
|
264
|
+
metadata: {
|
|
265
|
+
jsRuntime: isNode ? "node" : "web",
|
|
266
|
+
...isNode ? { nodeVersion: process.version } : {}
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
isDebugEnabled() {
|
|
271
|
+
return this.debug;
|
|
272
|
+
}
|
|
273
|
+
authHeaders() {
|
|
274
|
+
return this.writeKey ? { Authorization: `Bearer ${this.writeKey}` } : {};
|
|
275
|
+
}
|
|
276
|
+
async patch(eventId, patch) {
|
|
277
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
278
|
+
if (!this.enabled) return;
|
|
279
|
+
if (!eventId || !eventId.trim()) return;
|
|
280
|
+
if (this.debug) {
|
|
281
|
+
console.log(`${this.prefix} queue patch`, {
|
|
282
|
+
eventId,
|
|
283
|
+
userId: patch.userId,
|
|
284
|
+
convoId: patch.convoId,
|
|
285
|
+
eventName: patch.eventName,
|
|
286
|
+
hasInput: typeof patch.input === "string" && patch.input.length > 0,
|
|
287
|
+
hasOutput: typeof patch.output === "string" && patch.output.length > 0,
|
|
288
|
+
attachments: (_b = (_a = patch.attachments) == null ? void 0 : _a.length) != null ? _b : 0,
|
|
289
|
+
isPending: patch.isPending
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
|
|
293
|
+
const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
|
|
294
|
+
const merged = mergePatches(existing, patch);
|
|
295
|
+
merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
|
|
296
|
+
this.buffers.set(eventId, merged);
|
|
297
|
+
this.sticky.set(eventId, {
|
|
298
|
+
userId: (_h = merged.userId) != null ? _h : sticky.userId,
|
|
299
|
+
convoId: (_i = merged.convoId) != null ? _i : sticky.convoId,
|
|
300
|
+
eventName: (_j = merged.eventName) != null ? _j : sticky.eventName,
|
|
301
|
+
isPending: (_k = merged.isPending) != null ? _k : sticky.isPending
|
|
302
|
+
});
|
|
303
|
+
const t = this.timers.get(eventId);
|
|
304
|
+
if (t) clearTimeout(t);
|
|
305
|
+
if (merged.isPending === false) {
|
|
306
|
+
await this.flushOne(eventId);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const timeout = setTimeout(() => {
|
|
310
|
+
void this.flushOne(eventId).catch(() => {
|
|
311
|
+
});
|
|
312
|
+
}, this.partialFlushMs);
|
|
313
|
+
this.timers.set(eventId, timeout);
|
|
314
|
+
}
|
|
315
|
+
async finish(eventId, patch) {
|
|
316
|
+
await this.patch(eventId, { ...patch, isPending: false });
|
|
317
|
+
}
|
|
318
|
+
async flush() {
|
|
319
|
+
if (!this.enabled) return;
|
|
320
|
+
const ids = [...this.buffers.keys()];
|
|
321
|
+
await Promise.all(ids.map((id) => this.flushOne(id)));
|
|
322
|
+
await Promise.all([...this.inFlight].map((p) => p.catch(() => {
|
|
323
|
+
})));
|
|
324
|
+
}
|
|
325
|
+
async shutdown() {
|
|
326
|
+
for (const t of this.timers.values()) clearTimeout(t);
|
|
327
|
+
this.timers.clear();
|
|
328
|
+
await this.flush();
|
|
329
|
+
}
|
|
330
|
+
async trackSignal(signal) {
|
|
331
|
+
var _a, _b;
|
|
332
|
+
if (!this.enabled) return;
|
|
333
|
+
const body = [
|
|
334
|
+
{
|
|
335
|
+
event_id: signal.eventId,
|
|
336
|
+
signal_name: signal.name,
|
|
337
|
+
signal_type: (_a = signal.type) != null ? _a : "default",
|
|
338
|
+
timestamp: signal.timestamp,
|
|
339
|
+
sentiment: signal.sentiment,
|
|
340
|
+
attachment_id: signal.attachmentId,
|
|
341
|
+
properties: {
|
|
342
|
+
...(_b = signal.properties) != null ? _b : {},
|
|
343
|
+
...signal.comment ? { comment: signal.comment } : {},
|
|
344
|
+
...signal.after ? { after: signal.after } : {}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
];
|
|
348
|
+
const url = `${this.baseUrl}signals/track`;
|
|
349
|
+
try {
|
|
350
|
+
await postJson(url, body, this.authHeaders(), {
|
|
351
|
+
maxAttempts: 3,
|
|
352
|
+
debug: this.debug,
|
|
353
|
+
sdkName: this.sdkName
|
|
354
|
+
});
|
|
355
|
+
} catch (err) {
|
|
356
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
357
|
+
console.warn(`${this.prefix} failed to send signal (dropping): ${msg}`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async identify(users) {
|
|
361
|
+
if (!this.enabled) return;
|
|
362
|
+
const list = Array.isArray(users) ? users : [users];
|
|
363
|
+
const body = list.filter((user) => {
|
|
364
|
+
if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
|
|
365
|
+
if (this.debug) {
|
|
366
|
+
console.warn(`${this.prefix} skipping identify: missing userId`);
|
|
367
|
+
}
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
return true;
|
|
371
|
+
}).map((user) => {
|
|
372
|
+
var _a;
|
|
373
|
+
return {
|
|
374
|
+
user_id: user.userId,
|
|
375
|
+
traits: (_a = user.traits) != null ? _a : {}
|
|
376
|
+
};
|
|
377
|
+
});
|
|
378
|
+
if (body.length === 0) return;
|
|
379
|
+
const url = `${this.baseUrl}users/identify`;
|
|
380
|
+
try {
|
|
381
|
+
await postJson(url, body, this.authHeaders(), {
|
|
382
|
+
maxAttempts: 3,
|
|
383
|
+
debug: this.debug,
|
|
384
|
+
sdkName: this.sdkName
|
|
385
|
+
});
|
|
386
|
+
} catch (err) {
|
|
387
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
388
|
+
console.warn(`${this.prefix} failed to send identify (dropping): ${msg}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async flushOne(eventId) {
|
|
392
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
393
|
+
if (!this.enabled) return;
|
|
394
|
+
const timer = this.timers.get(eventId);
|
|
395
|
+
if (timer) {
|
|
396
|
+
clearTimeout(timer);
|
|
397
|
+
this.timers.delete(eventId);
|
|
398
|
+
}
|
|
399
|
+
const accumulated = this.buffers.get(eventId);
|
|
400
|
+
this.buffers.delete(eventId);
|
|
401
|
+
if (!accumulated) return;
|
|
402
|
+
const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
|
|
403
|
+
const eventName = (_c = (_b = accumulated.eventName) != null ? _b : sticky.eventName) != null ? _c : this.defaultEventName;
|
|
404
|
+
const userId = (_d = accumulated.userId) != null ? _d : sticky.userId;
|
|
405
|
+
if (!userId) {
|
|
406
|
+
if (this.debug) {
|
|
407
|
+
console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
|
|
408
|
+
}
|
|
409
|
+
this.sticky.delete(eventId);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
|
|
413
|
+
const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
|
|
414
|
+
const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
|
|
415
|
+
const payload = {
|
|
416
|
+
event_id: eventId,
|
|
417
|
+
user_id: userId,
|
|
418
|
+
event: eventName,
|
|
419
|
+
timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
|
|
420
|
+
ai_data: {
|
|
421
|
+
input: accumulated.input,
|
|
422
|
+
output: accumulated.output,
|
|
423
|
+
model: accumulated.model,
|
|
424
|
+
convo_id: convoId
|
|
425
|
+
},
|
|
426
|
+
properties: {
|
|
427
|
+
...restProperties,
|
|
428
|
+
...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
|
|
429
|
+
$context: this.context
|
|
430
|
+
},
|
|
431
|
+
attachments: accumulated.attachments,
|
|
432
|
+
is_pending: isPending
|
|
433
|
+
};
|
|
434
|
+
const url = `${this.baseUrl}events/track_partial`;
|
|
435
|
+
if (this.debug) {
|
|
436
|
+
console.log(`${this.prefix} sending track_partial`, {
|
|
437
|
+
eventId,
|
|
438
|
+
eventName,
|
|
439
|
+
userId,
|
|
440
|
+
convoId,
|
|
441
|
+
isPending,
|
|
442
|
+
inputPreview: typeof accumulated.input === "string" ? accumulated.input.slice(0, 120) : void 0,
|
|
443
|
+
outputPreview: typeof accumulated.output === "string" ? accumulated.output.slice(0, 120) : void 0,
|
|
444
|
+
attachments: (_k = (_j = accumulated.attachments) == null ? void 0 : _j.length) != null ? _k : 0,
|
|
445
|
+
attachmentKinds: (_m = (_l = accumulated.attachments) == null ? void 0 : _l.map((a) => ({
|
|
446
|
+
type: a.type,
|
|
447
|
+
role: a.role,
|
|
448
|
+
name: a.name,
|
|
449
|
+
valuePreview: a.value.slice(0, 60)
|
|
450
|
+
}))) != null ? _m : [],
|
|
451
|
+
endpoint: url
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
const p = postJson(url, payload, this.authHeaders(), {
|
|
455
|
+
maxAttempts: 3,
|
|
456
|
+
debug: this.debug,
|
|
457
|
+
sdkName: this.sdkName
|
|
458
|
+
});
|
|
459
|
+
this.inFlight.add(p);
|
|
460
|
+
try {
|
|
461
|
+
try {
|
|
462
|
+
await p;
|
|
463
|
+
if (this.debug) {
|
|
464
|
+
console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
|
|
465
|
+
}
|
|
466
|
+
} catch (err) {
|
|
467
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
468
|
+
console.warn(`${this.prefix} failed to send track_partial (dropping): ${msg}`);
|
|
469
|
+
}
|
|
470
|
+
} finally {
|
|
471
|
+
this.inFlight.delete(p);
|
|
472
|
+
}
|
|
473
|
+
if (!isPending) {
|
|
474
|
+
this.sticky.delete(eventId);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
var TraceShipper = class {
|
|
479
|
+
constructor(opts) {
|
|
480
|
+
this.queue = [];
|
|
481
|
+
this.inFlight = /* @__PURE__ */ new Set();
|
|
482
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
483
|
+
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
484
|
+
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
485
|
+
this.enabled = opts.enabled !== false;
|
|
486
|
+
this.debug = opts.debug;
|
|
487
|
+
this.debugSpans = opts.debugSpans === true;
|
|
488
|
+
this.flushIntervalMs = (_c = opts.flushIntervalMs) != null ? _c : 1e3;
|
|
489
|
+
this.maxBatchSize = (_d = opts.maxBatchSize) != null ? _d : 50;
|
|
490
|
+
this.maxQueueSize = (_e = opts.maxQueueSize) != null ? _e : 5e3;
|
|
491
|
+
this.sdkName = (_f = opts.sdkName) != null ? _f : "core";
|
|
492
|
+
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
493
|
+
this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
|
|
494
|
+
this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
|
|
495
|
+
}
|
|
496
|
+
isDebugEnabled() {
|
|
497
|
+
return this.debug;
|
|
498
|
+
}
|
|
499
|
+
authHeaders() {
|
|
500
|
+
return this.writeKey ? { Authorization: `Bearer ${this.writeKey}` } : {};
|
|
501
|
+
}
|
|
502
|
+
startSpan(args) {
|
|
503
|
+
var _a, _b;
|
|
504
|
+
const ids = createSpanIds(args.parent);
|
|
505
|
+
const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
|
|
506
|
+
const attrs = [
|
|
507
|
+
attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
|
|
508
|
+
attrString("ai.operationId", args.operationId)
|
|
509
|
+
];
|
|
510
|
+
if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
|
|
511
|
+
return { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
|
|
512
|
+
}
|
|
513
|
+
endSpan(span, extra) {
|
|
514
|
+
var _a, _b;
|
|
515
|
+
if (span.endTimeUnixNano) return;
|
|
516
|
+
span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
|
|
517
|
+
if ((_b = extra == null ? void 0 : extra.attributes) == null ? void 0 : _b.length) {
|
|
518
|
+
span.attributes.push(...extra.attributes);
|
|
519
|
+
}
|
|
520
|
+
let status = extra == null ? void 0 : extra.status;
|
|
521
|
+
if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
|
|
522
|
+
const message = extra.error instanceof Error ? extra.error.message : String(extra.error);
|
|
523
|
+
status = { code: SpanStatusCode.ERROR, message };
|
|
524
|
+
}
|
|
525
|
+
const otlp = buildOtlpSpan({
|
|
526
|
+
ids: span.ids,
|
|
527
|
+
name: span.name,
|
|
528
|
+
startTimeUnixNano: span.startTimeUnixNano,
|
|
529
|
+
endTimeUnixNano: span.endTimeUnixNano,
|
|
530
|
+
attributes: span.attributes,
|
|
531
|
+
status
|
|
532
|
+
});
|
|
533
|
+
this.enqueue(otlp);
|
|
534
|
+
}
|
|
535
|
+
createSpan(args) {
|
|
536
|
+
var _a;
|
|
537
|
+
const ids = createSpanIds(args.parent);
|
|
538
|
+
const attrs = [
|
|
539
|
+
attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId)
|
|
540
|
+
];
|
|
541
|
+
if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
|
|
542
|
+
const otlp = buildOtlpSpan({
|
|
543
|
+
ids,
|
|
544
|
+
name: args.name,
|
|
545
|
+
startTimeUnixNano: args.startTimeUnixNano,
|
|
546
|
+
endTimeUnixNano: args.endTimeUnixNano,
|
|
547
|
+
attributes: attrs,
|
|
548
|
+
status: args.status
|
|
549
|
+
});
|
|
550
|
+
this.enqueue(otlp);
|
|
551
|
+
}
|
|
552
|
+
enqueue(span) {
|
|
553
|
+
if (!this.enabled) return;
|
|
554
|
+
if (this.debugSpans) {
|
|
555
|
+
const short = (s) => s ? s.slice(-8) : "none";
|
|
556
|
+
console.log(
|
|
557
|
+
`${this.prefix}[span] name=${span.name} trace=${short(span.traceId)} span=${short(span.spanId)} parent=${short(
|
|
558
|
+
span.parentSpanId
|
|
559
|
+
)}`
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
if (this.queue.length >= this.maxQueueSize) {
|
|
563
|
+
this.queue.shift();
|
|
564
|
+
}
|
|
565
|
+
this.queue.push(span);
|
|
566
|
+
if (this.queue.length >= this.maxBatchSize) {
|
|
567
|
+
void this.flush().catch(() => {
|
|
568
|
+
});
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
if (!this.timer) {
|
|
572
|
+
this.timer = setTimeout(() => {
|
|
573
|
+
this.timer = void 0;
|
|
574
|
+
void this.flush().catch(() => {
|
|
575
|
+
});
|
|
576
|
+
}, this.flushIntervalMs);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
async flush() {
|
|
580
|
+
if (!this.enabled) return;
|
|
581
|
+
if (this.timer) {
|
|
582
|
+
clearTimeout(this.timer);
|
|
583
|
+
this.timer = void 0;
|
|
584
|
+
}
|
|
585
|
+
while (this.queue.length > 0) {
|
|
586
|
+
const batch = this.queue.splice(0, this.maxBatchSize);
|
|
587
|
+
const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
|
|
588
|
+
const url = `${this.baseUrl}traces`;
|
|
589
|
+
if (this.debug) {
|
|
590
|
+
console.log(`${this.prefix} sending traces batch`, {
|
|
591
|
+
spans: batch.length,
|
|
592
|
+
endpoint: url
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
const p = postJson(url, body, this.authHeaders(), {
|
|
596
|
+
maxAttempts: 3,
|
|
597
|
+
debug: this.debug,
|
|
598
|
+
sdkName: this.sdkName
|
|
599
|
+
});
|
|
600
|
+
this.inFlight.add(p);
|
|
601
|
+
try {
|
|
602
|
+
try {
|
|
603
|
+
await p;
|
|
604
|
+
if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
|
|
605
|
+
} catch (err) {
|
|
606
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
607
|
+
console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`);
|
|
608
|
+
}
|
|
609
|
+
} finally {
|
|
610
|
+
this.inFlight.delete(p);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
async shutdown() {
|
|
615
|
+
if (this.timer) {
|
|
616
|
+
clearTimeout(this.timer);
|
|
617
|
+
this.timer = void 0;
|
|
618
|
+
}
|
|
619
|
+
await this.flush();
|
|
620
|
+
await Promise.all([...this.inFlight].map((p) => p.catch(() => {
|
|
621
|
+
})));
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
// src/callback-handler.ts
|
|
626
|
+
var LANGGRAPH_INTERNAL_NAMES = /* @__PURE__ */ new Set([
|
|
627
|
+
"LangGraph",
|
|
628
|
+
"__start__",
|
|
629
|
+
"__end__",
|
|
630
|
+
"ChannelWrite",
|
|
631
|
+
"ChannelRead"
|
|
632
|
+
]);
|
|
633
|
+
var RaindropCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
634
|
+
constructor(opts) {
|
|
635
|
+
var _a, _b, _c;
|
|
636
|
+
super();
|
|
637
|
+
this.name = "RaindropCallbackHandler";
|
|
638
|
+
this.spans = /* @__PURE__ */ new Map();
|
|
639
|
+
this.rootRunIds = /* @__PURE__ */ new Map();
|
|
640
|
+
this.eventIds = /* @__PURE__ */ new Map();
|
|
641
|
+
this.eventShipper = opts.eventShipper;
|
|
642
|
+
this.traceShipper = opts.traceShipper;
|
|
643
|
+
this.userId = opts.userId;
|
|
644
|
+
this.convoId = opts.convoId;
|
|
645
|
+
this.traceChains = (_a = opts.traceChains) != null ? _a : true;
|
|
646
|
+
this.traceRetrievers = (_b = opts.traceRetrievers) != null ? _b : true;
|
|
647
|
+
this.filterLangGraphInternals = (_c = opts.filterLangGraphInternals) != null ? _c : true;
|
|
648
|
+
}
|
|
649
|
+
getEventId(runId, parentRunId) {
|
|
650
|
+
var _a;
|
|
651
|
+
const rootId = parentRunId ? (_a = this.rootRunIds.get(parentRunId)) != null ? _a : parentRunId : runId;
|
|
652
|
+
this.rootRunIds.set(runId, rootId);
|
|
653
|
+
if (!this.eventIds.has(rootId)) {
|
|
654
|
+
this.eventIds.set(rootId, randomUUID());
|
|
655
|
+
}
|
|
656
|
+
return this.eventIds.get(rootId);
|
|
657
|
+
}
|
|
658
|
+
getParent(parentRunId) {
|
|
659
|
+
if (!parentRunId) return void 0;
|
|
660
|
+
const parentSpan = this.spans.get(parentRunId);
|
|
661
|
+
if (!parentSpan) return void 0;
|
|
662
|
+
return {
|
|
663
|
+
traceIdB64: parentSpan.ids.traceIdB64,
|
|
664
|
+
spanIdB64: parentSpan.ids.spanIdB64
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
cleanup(runId) {
|
|
668
|
+
var _a;
|
|
669
|
+
this.spans.delete(runId);
|
|
670
|
+
this.spans.delete(`${runId}:agent_action`);
|
|
671
|
+
const rootId = (_a = this.rootRunIds.get(runId)) != null ? _a : runId;
|
|
672
|
+
this.rootRunIds.delete(runId);
|
|
673
|
+
if (rootId === runId) {
|
|
674
|
+
this.eventIds.delete(rootId);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
async finalizeEventIfRoot(runId, patch) {
|
|
678
|
+
var _a;
|
|
679
|
+
const rootId = (_a = this.rootRunIds.get(runId)) != null ? _a : runId;
|
|
680
|
+
const isRoot = rootId === runId;
|
|
681
|
+
const eventId = this.eventIds.get(rootId);
|
|
682
|
+
if (!eventId) return;
|
|
683
|
+
if (isRoot) {
|
|
684
|
+
if (this.convoId) {
|
|
685
|
+
await this.eventShipper.patch(eventId, { userId: this.userId, convoId: this.convoId, isPending: true });
|
|
686
|
+
}
|
|
687
|
+
await this.eventShipper.finish(eventId, { userId: this.userId, ...patch });
|
|
688
|
+
} else if (patch) {
|
|
689
|
+
await this.eventShipper.patch(eventId, { userId: this.userId, convoId: this.convoId, ...patch, isPending: true });
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
// ---------------------------------------------------------------------------
|
|
693
|
+
// LLM events
|
|
694
|
+
// ---------------------------------------------------------------------------
|
|
695
|
+
/** Called at the start of an LLM run with string prompts. */
|
|
696
|
+
async handleLLMStart(llm, prompts, runId, parentRunId, _extraParams, tags, metadata, runName) {
|
|
697
|
+
try {
|
|
698
|
+
if (this.filterLangGraphInternals && this.spans.has(runId)) return;
|
|
699
|
+
const eventId = this.getEventId(runId, parentRunId);
|
|
700
|
+
const modelId = getName(llm, runName);
|
|
701
|
+
const span = this.traceShipper.startSpan({
|
|
702
|
+
name: "llm",
|
|
703
|
+
parent: this.getParent(parentRunId),
|
|
704
|
+
eventId,
|
|
705
|
+
attributes: [
|
|
706
|
+
attrString("ai.model.provider", modelId),
|
|
707
|
+
attrString("ai.operationId", "llm")
|
|
708
|
+
]
|
|
709
|
+
});
|
|
710
|
+
this.spans.set(runId, span);
|
|
711
|
+
await this.eventShipper.patch(eventId, {
|
|
712
|
+
userId: this.userId,
|
|
713
|
+
convoId: this.convoId,
|
|
714
|
+
input: prompts.join("\n"),
|
|
715
|
+
properties: buildProperties(tags, metadata),
|
|
716
|
+
isPending: true
|
|
717
|
+
});
|
|
718
|
+
} catch (e) {
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
/** Called at the start of a chat model run with structured messages. */
|
|
722
|
+
async handleChatModelStart(llm, messages, runId, parentRunId, _extraParams, tags, metadata, runName) {
|
|
723
|
+
try {
|
|
724
|
+
if (this.filterLangGraphInternals && this.spans.has(runId)) return;
|
|
725
|
+
const eventId = this.getEventId(runId, parentRunId);
|
|
726
|
+
const modelId = getName(llm, runName);
|
|
727
|
+
const span = this.traceShipper.startSpan({
|
|
728
|
+
name: "llm",
|
|
729
|
+
parent: this.getParent(parentRunId),
|
|
730
|
+
eventId,
|
|
731
|
+
attributes: [
|
|
732
|
+
attrString("ai.model.provider", modelId),
|
|
733
|
+
attrString("ai.operationId", "chat")
|
|
734
|
+
]
|
|
735
|
+
});
|
|
736
|
+
this.spans.set(runId, span);
|
|
737
|
+
const allMessages = messages.flat();
|
|
738
|
+
const userMessages = allMessages.filter((m) => {
|
|
739
|
+
var _a, _b;
|
|
740
|
+
const role = (_b = (_a = m._getType) == null ? void 0 : _a.call(m)) != null ? _b : "unknown";
|
|
741
|
+
return role === "human";
|
|
742
|
+
});
|
|
743
|
+
const toExtract = userMessages.length > 0 ? userMessages : allMessages.slice(-1);
|
|
744
|
+
const inputText = toExtract.map((m) => typeof m.content === "string" ? m.content : safeStringify(m.content)).join("\n");
|
|
745
|
+
await this.eventShipper.patch(eventId, {
|
|
746
|
+
userId: this.userId,
|
|
747
|
+
convoId: this.convoId,
|
|
748
|
+
input: inputText,
|
|
749
|
+
properties: buildProperties(tags, metadata),
|
|
750
|
+
isPending: true
|
|
751
|
+
});
|
|
752
|
+
} catch (e) {
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
async handleLLMEnd(output, runId, _parentRunId) {
|
|
756
|
+
try {
|
|
757
|
+
const span = this.spans.get(runId);
|
|
758
|
+
if (!span) {
|
|
759
|
+
await this.finalizeEventIfRoot(runId);
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
const { model, promptTokens, completionTokens, outputText } = extractLLMMetadata(output);
|
|
763
|
+
this.traceShipper.endSpan(span, {
|
|
764
|
+
attributes: [
|
|
765
|
+
attrString("ai.response.model", model),
|
|
766
|
+
attrInt("ai.usage.prompt_tokens", promptTokens),
|
|
767
|
+
attrInt("ai.usage.completion_tokens", completionTokens)
|
|
768
|
+
]
|
|
769
|
+
});
|
|
770
|
+
const properties = {};
|
|
771
|
+
if (promptTokens != null) properties["ai.usage.prompt_tokens"] = promptTokens;
|
|
772
|
+
if (completionTokens != null) properties["ai.usage.completion_tokens"] = completionTokens;
|
|
773
|
+
await this.finalizeEventIfRoot(runId, {
|
|
774
|
+
output: outputText,
|
|
775
|
+
model,
|
|
776
|
+
properties: Object.keys(properties).length > 0 ? properties : void 0
|
|
777
|
+
});
|
|
778
|
+
} catch (e) {
|
|
779
|
+
} finally {
|
|
780
|
+
this.cleanup(runId);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
/** Called when an LLM run encounters an error. */
|
|
784
|
+
async handleLLMError(err, runId) {
|
|
785
|
+
try {
|
|
786
|
+
const span = this.spans.get(runId);
|
|
787
|
+
if (span) {
|
|
788
|
+
this.traceShipper.endSpan(span, { error: err });
|
|
789
|
+
}
|
|
790
|
+
await this.finalizeEventIfRoot(runId);
|
|
791
|
+
} catch (e) {
|
|
792
|
+
} finally {
|
|
793
|
+
this.cleanup(runId);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
// ---------------------------------------------------------------------------
|
|
797
|
+
// Chain events
|
|
798
|
+
// ---------------------------------------------------------------------------
|
|
799
|
+
async handleChainStart(chain, _inputs, runId, parentRunId, _tags, _metadata, _runType, runName) {
|
|
800
|
+
var _a;
|
|
801
|
+
try {
|
|
802
|
+
const chainName = getName(chain, runName);
|
|
803
|
+
if (this.filterLangGraphInternals && isLangGraphInternal(chainName)) return;
|
|
804
|
+
this.getEventId(runId, parentRunId);
|
|
805
|
+
if (!this.traceChains) return;
|
|
806
|
+
const eventId = this.eventIds.get((_a = this.rootRunIds.get(runId)) != null ? _a : runId);
|
|
807
|
+
const span = this.traceShipper.startSpan({
|
|
808
|
+
name: "chain",
|
|
809
|
+
parent: this.getParent(parentRunId),
|
|
810
|
+
eventId,
|
|
811
|
+
attributes: [
|
|
812
|
+
attrString("chain.name", chainName),
|
|
813
|
+
attrString("ai.operationId", "chain")
|
|
814
|
+
]
|
|
815
|
+
});
|
|
816
|
+
this.spans.set(runId, span);
|
|
817
|
+
} catch (e) {
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
async handleChainEnd(_outputs, runId) {
|
|
821
|
+
try {
|
|
822
|
+
if (this.traceChains) {
|
|
823
|
+
const span = this.spans.get(runId);
|
|
824
|
+
if (span) this.traceShipper.endSpan(span);
|
|
825
|
+
}
|
|
826
|
+
await this.finalizeEventIfRoot(runId);
|
|
827
|
+
} catch (e) {
|
|
828
|
+
} finally {
|
|
829
|
+
this.cleanup(runId);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
async handleChainError(err, runId) {
|
|
833
|
+
try {
|
|
834
|
+
const span = this.spans.get(runId);
|
|
835
|
+
if (span) this.traceShipper.endSpan(span, { error: err });
|
|
836
|
+
await this.finalizeEventIfRoot(runId);
|
|
837
|
+
} catch (e) {
|
|
838
|
+
} finally {
|
|
839
|
+
this.cleanup(runId);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
// ---------------------------------------------------------------------------
|
|
843
|
+
// Tool events
|
|
844
|
+
// ---------------------------------------------------------------------------
|
|
845
|
+
async handleToolStart(tool, input, runId, parentRunId, _tags, _metadata, runName) {
|
|
846
|
+
try {
|
|
847
|
+
const eventId = this.getEventId(runId, parentRunId);
|
|
848
|
+
const toolName = getName(tool, runName);
|
|
849
|
+
const span = this.traceShipper.startSpan({
|
|
850
|
+
name: "tool",
|
|
851
|
+
parent: this.getParent(parentRunId),
|
|
852
|
+
eventId,
|
|
853
|
+
attributes: [
|
|
854
|
+
attrString("tool.name", toolName),
|
|
855
|
+
attrString("tool.input", truncate(input, 4096))
|
|
856
|
+
]
|
|
857
|
+
});
|
|
858
|
+
this.spans.set(runId, span);
|
|
859
|
+
} catch (e) {
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
/** Called at the end of a tool run. */
|
|
863
|
+
async handleToolEnd(output, runId) {
|
|
864
|
+
try {
|
|
865
|
+
const span = this.spans.get(runId);
|
|
866
|
+
if (span) {
|
|
867
|
+
const outputStr = typeof output === "string" ? output : safeStringify(output);
|
|
868
|
+
this.traceShipper.endSpan(span, {
|
|
869
|
+
attributes: [attrString("tool.output", truncate(outputStr, 4096))]
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
await this.finalizeEventIfRoot(runId);
|
|
873
|
+
} catch (e) {
|
|
874
|
+
} finally {
|
|
875
|
+
this.cleanup(runId);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
/** Called when a tool run encounters an error. */
|
|
879
|
+
async handleToolError(err, runId) {
|
|
880
|
+
try {
|
|
881
|
+
const span = this.spans.get(runId);
|
|
882
|
+
if (span) this.traceShipper.endSpan(span, { error: err });
|
|
883
|
+
await this.finalizeEventIfRoot(runId);
|
|
884
|
+
} catch (e) {
|
|
885
|
+
} finally {
|
|
886
|
+
this.cleanup(runId);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
// ---------------------------------------------------------------------------
|
|
890
|
+
// Retriever events
|
|
891
|
+
// ---------------------------------------------------------------------------
|
|
892
|
+
/** Called at the start of a retriever run. */
|
|
893
|
+
async handleRetrieverStart(retriever, query, runId, parentRunId, _tags, _metadata, name) {
|
|
894
|
+
try {
|
|
895
|
+
const eventId = this.getEventId(runId, parentRunId);
|
|
896
|
+
if (!this.traceRetrievers) return;
|
|
897
|
+
const retrieverName = getName(retriever, name);
|
|
898
|
+
const span = this.traceShipper.startSpan({
|
|
899
|
+
name: "retriever",
|
|
900
|
+
parent: this.getParent(parentRunId),
|
|
901
|
+
eventId,
|
|
902
|
+
attributes: [
|
|
903
|
+
attrString("retriever.name", retrieverName),
|
|
904
|
+
attrString("retriever.query", truncate(query, 2048))
|
|
905
|
+
]
|
|
906
|
+
});
|
|
907
|
+
this.spans.set(runId, span);
|
|
908
|
+
} catch (e) {
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
/** Called at the end of a retriever run. */
|
|
912
|
+
async handleRetrieverEnd(documents, runId) {
|
|
913
|
+
try {
|
|
914
|
+
if (this.traceRetrievers) {
|
|
915
|
+
const span = this.spans.get(runId);
|
|
916
|
+
if (span) {
|
|
917
|
+
this.traceShipper.endSpan(span, {
|
|
918
|
+
attributes: [attrInt("retriever.document_count", documents.length)]
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
await this.finalizeEventIfRoot(runId);
|
|
923
|
+
} catch (e) {
|
|
924
|
+
} finally {
|
|
925
|
+
this.cleanup(runId);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
/** Called when a retriever run encounters an error. */
|
|
929
|
+
async handleRetrieverError(err, runId) {
|
|
930
|
+
try {
|
|
931
|
+
const span = this.spans.get(runId);
|
|
932
|
+
if (span) this.traceShipper.endSpan(span, { error: err });
|
|
933
|
+
await this.finalizeEventIfRoot(runId);
|
|
934
|
+
} catch (e) {
|
|
935
|
+
} finally {
|
|
936
|
+
this.cleanup(runId);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
// ---------------------------------------------------------------------------
|
|
940
|
+
// Agent events
|
|
941
|
+
// ---------------------------------------------------------------------------
|
|
942
|
+
async handleAgentAction(action, runId, parentRunId) {
|
|
943
|
+
try {
|
|
944
|
+
const eventId = this.getEventId(runId, parentRunId);
|
|
945
|
+
const span = this.traceShipper.startSpan({
|
|
946
|
+
name: "agent_action",
|
|
947
|
+
parent: this.getParent(parentRunId),
|
|
948
|
+
eventId,
|
|
949
|
+
attributes: [
|
|
950
|
+
attrString("agent.tool", action.tool),
|
|
951
|
+
attrString("agent.tool_input", truncate(
|
|
952
|
+
typeof action.toolInput === "string" ? action.toolInput : safeStringify(action.toolInput),
|
|
953
|
+
4096
|
|
954
|
+
))
|
|
955
|
+
]
|
|
956
|
+
});
|
|
957
|
+
this.spans.set(`${runId}:agent_action`, span);
|
|
958
|
+
} catch (e) {
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
async handleAgentEnd(_action, runId) {
|
|
962
|
+
try {
|
|
963
|
+
const spanKey = `${runId}:agent_action`;
|
|
964
|
+
const span = this.spans.get(spanKey);
|
|
965
|
+
if (span) {
|
|
966
|
+
this.traceShipper.endSpan(span);
|
|
967
|
+
this.spans.delete(spanKey);
|
|
968
|
+
}
|
|
969
|
+
} catch (e) {
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
function getName(serialized, runName) {
|
|
974
|
+
var _a;
|
|
975
|
+
if (runName) return runName;
|
|
976
|
+
if ((_a = serialized == null ? void 0 : serialized.id) == null ? void 0 : _a.length) return serialized.id[serialized.id.length - 1];
|
|
977
|
+
if ("name" in serialized && typeof serialized.name === "string") return serialized.name;
|
|
978
|
+
return "unknown";
|
|
979
|
+
}
|
|
980
|
+
function isLangGraphInternal(name) {
|
|
981
|
+
if (LANGGRAPH_INTERNAL_NAMES.has(name)) return true;
|
|
982
|
+
if (name.startsWith("Branch")) return true;
|
|
983
|
+
if (name.startsWith("ChannelWrite")) return true;
|
|
984
|
+
if (name.startsWith("__") && name.endsWith("__")) return true;
|
|
985
|
+
return false;
|
|
986
|
+
}
|
|
987
|
+
function buildProperties(tags, metadata) {
|
|
988
|
+
if (!(tags == null ? void 0 : tags.length) && !metadata) return void 0;
|
|
989
|
+
const props = {};
|
|
990
|
+
if (tags == null ? void 0 : tags.length) props["langchain.tags"] = tags;
|
|
991
|
+
if (metadata) Object.assign(props, metadata);
|
|
992
|
+
return props;
|
|
993
|
+
}
|
|
994
|
+
function safeStringify(value) {
|
|
995
|
+
var _a;
|
|
996
|
+
try {
|
|
997
|
+
return (_a = JSON.stringify(value)) != null ? _a : "";
|
|
998
|
+
} catch (e) {
|
|
999
|
+
return String(value);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
function truncate(str, maxLen) {
|
|
1003
|
+
if (str.length <= maxLen) return str;
|
|
1004
|
+
return str.slice(0, maxLen - 3) + "...";
|
|
1005
|
+
}
|
|
1006
|
+
function extractLLMMetadata(output) {
|
|
1007
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
1008
|
+
const gen = (_b = (_a = output.generations) == null ? void 0 : _a[0]) == null ? void 0 : _b[0];
|
|
1009
|
+
const message = gen == null ? void 0 : gen.message;
|
|
1010
|
+
const responseMeta = message == null ? void 0 : message.response_metadata;
|
|
1011
|
+
const usageMeta = message == null ? void 0 : message.usage_metadata;
|
|
1012
|
+
const llmOutput = output.llmOutput;
|
|
1013
|
+
const tokenUsage = (_c = llmOutput == null ? void 0 : llmOutput.token_usage) != null ? _c : llmOutput == null ? void 0 : llmOutput.tokenUsage;
|
|
1014
|
+
const estimatedTokens = llmOutput == null ? void 0 : llmOutput.estimatedTokens;
|
|
1015
|
+
const model = (_f = (_e = (_d = responseMeta == null ? void 0 : responseMeta.model_name) != null ? _d : responseMeta == null ? void 0 : responseMeta.model) != null ? _e : llmOutput == null ? void 0 : llmOutput.model_name) != null ? _f : llmOutput == null ? void 0 : llmOutput.model;
|
|
1016
|
+
const usage = (_g = usageMeta != null ? usageMeta : tokenUsage) != null ? _g : estimatedTokens;
|
|
1017
|
+
const promptTokens = (_i = (_h = usage == null ? void 0 : usage.input_tokens) != null ? _h : usage == null ? void 0 : usage.prompt_tokens) != null ? _i : usage == null ? void 0 : usage.promptTokens;
|
|
1018
|
+
const completionTokens = (_k = (_j = usage == null ? void 0 : usage.output_tokens) != null ? _j : usage == null ? void 0 : usage.completion_tokens) != null ? _k : usage == null ? void 0 : usage.completionTokens;
|
|
1019
|
+
const outputText = (_m = (_l = gen == null ? void 0 : gen.text) != null ? _l : typeof (message == null ? void 0 : message.content) === "string" ? message.content : void 0) != null ? _m : (message == null ? void 0 : message.content) ? JSON.stringify(message.content) : void 0;
|
|
1020
|
+
return { model, promptTokens, completionTokens, outputText };
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// package.json
|
|
1024
|
+
var package_default = {
|
|
1025
|
+
name: "@raindrop-ai/langchain",
|
|
1026
|
+
version: "0.0.1",
|
|
1027
|
+
description: "Raindrop integration for LangChain",
|
|
1028
|
+
main: "dist/index.js",
|
|
1029
|
+
module: "dist/index.mjs",
|
|
1030
|
+
types: "dist/index.d.ts",
|
|
1031
|
+
exports: {
|
|
1032
|
+
".": {
|
|
1033
|
+
types: "./dist/index.d.ts",
|
|
1034
|
+
import: "./dist/index.mjs",
|
|
1035
|
+
require: "./dist/index.js"
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
1038
|
+
sideEffects: false,
|
|
1039
|
+
files: ["dist/**"],
|
|
1040
|
+
scripts: {
|
|
1041
|
+
build: "tsup",
|
|
1042
|
+
dev: "tsup --watch",
|
|
1043
|
+
clean: "rm -rf dist",
|
|
1044
|
+
test: "vitest run"
|
|
1045
|
+
},
|
|
1046
|
+
peerDependencies: {
|
|
1047
|
+
"@langchain/core": ">=0.3.0 <1.0.0"
|
|
1048
|
+
},
|
|
1049
|
+
devDependencies: {
|
|
1050
|
+
"@raindrop-ai/core": "workspace:*",
|
|
1051
|
+
"@langchain/core": ">=0.3.0",
|
|
1052
|
+
"@types/node": "^20.11.17",
|
|
1053
|
+
msw: "^2.12.7",
|
|
1054
|
+
tsup: "^8.4.0",
|
|
1055
|
+
typescript: "^5.3.3",
|
|
1056
|
+
vitest: "^2.1.9"
|
|
1057
|
+
},
|
|
1058
|
+
tsup: {
|
|
1059
|
+
entry: ["src/index.ts"],
|
|
1060
|
+
format: ["cjs", "esm"],
|
|
1061
|
+
dts: { resolve: true },
|
|
1062
|
+
clean: true,
|
|
1063
|
+
noExternal: ["@raindrop-ai/core"]
|
|
1064
|
+
},
|
|
1065
|
+
publishConfig: {
|
|
1066
|
+
access: "public"
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
|
|
1070
|
+
// src/version.ts
|
|
1071
|
+
var libraryName = package_default.name;
|
|
1072
|
+
var libraryVersion = package_default.version;
|
|
1073
|
+
|
|
1074
|
+
// src/index.ts
|
|
1075
|
+
function createRaindropLangChain(opts) {
|
|
1076
|
+
var _a, _b;
|
|
1077
|
+
const writeKey = opts.writeKey;
|
|
1078
|
+
const enabled = !!writeKey;
|
|
1079
|
+
if (!writeKey) {
|
|
1080
|
+
console.warn("[raindrop-ai/langchain] writeKey not provided; telemetry shipping is disabled");
|
|
1081
|
+
}
|
|
1082
|
+
const eventShipper = new EventShipper({
|
|
1083
|
+
writeKey,
|
|
1084
|
+
endpoint: opts.endpoint,
|
|
1085
|
+
enabled,
|
|
1086
|
+
debug: (_a = opts.debug) != null ? _a : false,
|
|
1087
|
+
sdkName: "langchain",
|
|
1088
|
+
libraryName,
|
|
1089
|
+
libraryVersion
|
|
1090
|
+
});
|
|
1091
|
+
const traceShipper = new TraceShipper({
|
|
1092
|
+
writeKey,
|
|
1093
|
+
endpoint: opts.endpoint,
|
|
1094
|
+
enabled,
|
|
1095
|
+
debug: (_b = opts.debug) != null ? _b : false,
|
|
1096
|
+
sdkName: "langchain",
|
|
1097
|
+
serviceName: "raindrop.langchain",
|
|
1098
|
+
serviceVersion: libraryVersion
|
|
1099
|
+
});
|
|
1100
|
+
const handler = new RaindropCallbackHandler({
|
|
1101
|
+
eventShipper,
|
|
1102
|
+
traceShipper,
|
|
1103
|
+
userId: opts.userId,
|
|
1104
|
+
convoId: opts.convoId,
|
|
1105
|
+
traceChains: opts.traceChains,
|
|
1106
|
+
traceRetrievers: opts.traceRetrievers,
|
|
1107
|
+
filterLangGraphInternals: opts.filterLangGraphInternals
|
|
1108
|
+
});
|
|
1109
|
+
return {
|
|
1110
|
+
handler,
|
|
1111
|
+
async flush() {
|
|
1112
|
+
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
1113
|
+
},
|
|
1114
|
+
async shutdown() {
|
|
1115
|
+
await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
|
|
1116
|
+
},
|
|
1117
|
+
events: {
|
|
1118
|
+
async patch(eventId, patch) {
|
|
1119
|
+
await eventShipper.patch(eventId, patch);
|
|
1120
|
+
},
|
|
1121
|
+
async finish(eventId, patch) {
|
|
1122
|
+
await eventShipper.finish(eventId, patch);
|
|
1123
|
+
},
|
|
1124
|
+
async addAttachments(eventId, attachments) {
|
|
1125
|
+
await eventShipper.patch(eventId, { attachments });
|
|
1126
|
+
},
|
|
1127
|
+
async setProperties(eventId, properties) {
|
|
1128
|
+
await eventShipper.patch(eventId, { properties });
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
users: {
|
|
1132
|
+
async identify(users) {
|
|
1133
|
+
await eventShipper.identify(users);
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
signals: {
|
|
1137
|
+
async track(signal) {
|
|
1138
|
+
await eventShipper.trackSignal(signal);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1144
|
+
0 && (module.exports = {
|
|
1145
|
+
RaindropCallbackHandler,
|
|
1146
|
+
createRaindropLangChain
|
|
1147
|
+
});
|