@firstflow/core 0.0.6 → 0.0.9
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/dist/anthropic.d.mts +9 -0
- package/dist/anthropic.d.ts +9 -0
- package/dist/anthropic.mjs +3 -2
- package/dist/{chunk-RZMKPIBO.mjs → chunk-KAH2MUTQ.mjs} +4 -2
- package/dist/{chunk-X3T7X4JQ.mjs → chunk-QBEGXT76.mjs} +12 -407
- package/dist/chunk-WQZUOUMF.mjs +404 -0
- package/dist/index.mjs +5 -3
- package/dist/langchain.d.mts +56 -0
- package/dist/langchain.d.ts +56 -0
- package/dist/langchain.js +1661 -0
- package/dist/langchain.mjs +277 -0
- package/dist/openai.d.mts +9 -0
- package/dist/openai.d.ts +9 -0
- package/dist/openai.mjs +3 -2
- package/package.json +22 -3
|
@@ -0,0 +1,1661 @@
|
|
|
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/langchain.ts
|
|
21
|
+
var langchain_exports = {};
|
|
22
|
+
__export(langchain_exports, {
|
|
23
|
+
FirstflowCallbackHandler: () => FirstflowCallbackHandler,
|
|
24
|
+
firstflowCallback: () => firstflowCallback,
|
|
25
|
+
withFirstflow: () => withFirstflow
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(langchain_exports);
|
|
28
|
+
|
|
29
|
+
// node_modules/tsup/assets/cjs_shims.js
|
|
30
|
+
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
31
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
32
|
+
|
|
33
|
+
// src/langchain.ts
|
|
34
|
+
var import_base = require("@langchain/core/callbacks/base");
|
|
35
|
+
|
|
36
|
+
// src/runtime.ts
|
|
37
|
+
var import_sdk_node = require("@opentelemetry/sdk-node");
|
|
38
|
+
var import_resources = require("@opentelemetry/resources");
|
|
39
|
+
var import_instrumentation_openai = require("@opentelemetry/instrumentation-openai");
|
|
40
|
+
var import_instrumentation_anthropic = require("@traceloop/instrumentation-anthropic");
|
|
41
|
+
|
|
42
|
+
// node_modules/@opentelemetry/api/build/esm/version.js
|
|
43
|
+
var VERSION = "1.9.1";
|
|
44
|
+
|
|
45
|
+
// node_modules/@opentelemetry/api/build/esm/internal/semver.js
|
|
46
|
+
var re = /^(\d+)\.(\d+)\.(\d+)(-(.+))?$/;
|
|
47
|
+
function _makeCompatibilityCheck(ownVersion) {
|
|
48
|
+
const acceptedVersions = /* @__PURE__ */ new Set([ownVersion]);
|
|
49
|
+
const rejectedVersions = /* @__PURE__ */ new Set();
|
|
50
|
+
const myVersionMatch = ownVersion.match(re);
|
|
51
|
+
if (!myVersionMatch) {
|
|
52
|
+
return () => false;
|
|
53
|
+
}
|
|
54
|
+
const ownVersionParsed = {
|
|
55
|
+
major: +myVersionMatch[1],
|
|
56
|
+
minor: +myVersionMatch[2],
|
|
57
|
+
patch: +myVersionMatch[3],
|
|
58
|
+
prerelease: myVersionMatch[4]
|
|
59
|
+
};
|
|
60
|
+
if (ownVersionParsed.prerelease != null) {
|
|
61
|
+
return function isExactmatch(globalVersion) {
|
|
62
|
+
return globalVersion === ownVersion;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function _reject(v) {
|
|
66
|
+
rejectedVersions.add(v);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
function _accept(v) {
|
|
70
|
+
acceptedVersions.add(v);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return function isCompatible2(globalVersion) {
|
|
74
|
+
if (acceptedVersions.has(globalVersion)) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
if (rejectedVersions.has(globalVersion)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const globalVersionMatch = globalVersion.match(re);
|
|
81
|
+
if (!globalVersionMatch) {
|
|
82
|
+
return _reject(globalVersion);
|
|
83
|
+
}
|
|
84
|
+
const globalVersionParsed = {
|
|
85
|
+
major: +globalVersionMatch[1],
|
|
86
|
+
minor: +globalVersionMatch[2],
|
|
87
|
+
patch: +globalVersionMatch[3],
|
|
88
|
+
prerelease: globalVersionMatch[4]
|
|
89
|
+
};
|
|
90
|
+
if (globalVersionParsed.prerelease != null) {
|
|
91
|
+
return _reject(globalVersion);
|
|
92
|
+
}
|
|
93
|
+
if (ownVersionParsed.major !== globalVersionParsed.major) {
|
|
94
|
+
return _reject(globalVersion);
|
|
95
|
+
}
|
|
96
|
+
if (ownVersionParsed.major === 0) {
|
|
97
|
+
if (ownVersionParsed.minor === globalVersionParsed.minor && ownVersionParsed.patch <= globalVersionParsed.patch) {
|
|
98
|
+
return _accept(globalVersion);
|
|
99
|
+
}
|
|
100
|
+
return _reject(globalVersion);
|
|
101
|
+
}
|
|
102
|
+
if (ownVersionParsed.minor <= globalVersionParsed.minor) {
|
|
103
|
+
return _accept(globalVersion);
|
|
104
|
+
}
|
|
105
|
+
return _reject(globalVersion);
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
var isCompatible = _makeCompatibilityCheck(VERSION);
|
|
109
|
+
|
|
110
|
+
// node_modules/@opentelemetry/api/build/esm/internal/global-utils.js
|
|
111
|
+
var major = VERSION.split(".")[0];
|
|
112
|
+
var GLOBAL_OPENTELEMETRY_API_KEY = /* @__PURE__ */ Symbol.for(`opentelemetry.js.api.${major}`);
|
|
113
|
+
var _global = typeof globalThis === "object" ? globalThis : typeof self === "object" ? self : typeof window === "object" ? window : typeof global === "object" ? global : {};
|
|
114
|
+
function registerGlobal(type, instance, diag2, allowOverride = false) {
|
|
115
|
+
var _a;
|
|
116
|
+
const api = _global[GLOBAL_OPENTELEMETRY_API_KEY] = (_a = _global[GLOBAL_OPENTELEMETRY_API_KEY]) !== null && _a !== void 0 ? _a : {
|
|
117
|
+
version: VERSION
|
|
118
|
+
};
|
|
119
|
+
if (!allowOverride && api[type]) {
|
|
120
|
+
const err = new Error(`@opentelemetry/api: Attempted duplicate registration of API: ${type}`);
|
|
121
|
+
diag2.error(err.stack || err.message);
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
if (api.version !== VERSION) {
|
|
125
|
+
const err = new Error(`@opentelemetry/api: Registration of version v${api.version} for ${type} does not match previously registered API v${VERSION}`);
|
|
126
|
+
diag2.error(err.stack || err.message);
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
api[type] = instance;
|
|
130
|
+
diag2.debug(`@opentelemetry/api: Registered a global for ${type} v${VERSION}.`);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
function getGlobal(type) {
|
|
134
|
+
var _a, _b;
|
|
135
|
+
const globalVersion = (_a = _global[GLOBAL_OPENTELEMETRY_API_KEY]) === null || _a === void 0 ? void 0 : _a.version;
|
|
136
|
+
if (!globalVersion || !isCompatible(globalVersion)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
return (_b = _global[GLOBAL_OPENTELEMETRY_API_KEY]) === null || _b === void 0 ? void 0 : _b[type];
|
|
140
|
+
}
|
|
141
|
+
function unregisterGlobal(type, diag2) {
|
|
142
|
+
diag2.debug(`@opentelemetry/api: Unregistering a global for ${type} v${VERSION}.`);
|
|
143
|
+
const api = _global[GLOBAL_OPENTELEMETRY_API_KEY];
|
|
144
|
+
if (api) {
|
|
145
|
+
delete api[type];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js
|
|
150
|
+
var DiagComponentLogger = class {
|
|
151
|
+
constructor(props) {
|
|
152
|
+
this._namespace = props.namespace || "DiagComponentLogger";
|
|
153
|
+
}
|
|
154
|
+
debug(...args) {
|
|
155
|
+
return logProxy("debug", this._namespace, args);
|
|
156
|
+
}
|
|
157
|
+
error(...args) {
|
|
158
|
+
return logProxy("error", this._namespace, args);
|
|
159
|
+
}
|
|
160
|
+
info(...args) {
|
|
161
|
+
return logProxy("info", this._namespace, args);
|
|
162
|
+
}
|
|
163
|
+
warn(...args) {
|
|
164
|
+
return logProxy("warn", this._namespace, args);
|
|
165
|
+
}
|
|
166
|
+
verbose(...args) {
|
|
167
|
+
return logProxy("verbose", this._namespace, args);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
function logProxy(funcName, namespace, args) {
|
|
171
|
+
const logger = getGlobal("diag");
|
|
172
|
+
if (!logger) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
return logger[funcName](namespace, ...args);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// node_modules/@opentelemetry/api/build/esm/diag/types.js
|
|
179
|
+
var DiagLogLevel;
|
|
180
|
+
(function(DiagLogLevel2) {
|
|
181
|
+
DiagLogLevel2[DiagLogLevel2["NONE"] = 0] = "NONE";
|
|
182
|
+
DiagLogLevel2[DiagLogLevel2["ERROR"] = 30] = "ERROR";
|
|
183
|
+
DiagLogLevel2[DiagLogLevel2["WARN"] = 50] = "WARN";
|
|
184
|
+
DiagLogLevel2[DiagLogLevel2["INFO"] = 60] = "INFO";
|
|
185
|
+
DiagLogLevel2[DiagLogLevel2["DEBUG"] = 70] = "DEBUG";
|
|
186
|
+
DiagLogLevel2[DiagLogLevel2["VERBOSE"] = 80] = "VERBOSE";
|
|
187
|
+
DiagLogLevel2[DiagLogLevel2["ALL"] = 9999] = "ALL";
|
|
188
|
+
})(DiagLogLevel || (DiagLogLevel = {}));
|
|
189
|
+
|
|
190
|
+
// node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js
|
|
191
|
+
function createLogLevelDiagLogger(maxLevel, logger) {
|
|
192
|
+
if (maxLevel < DiagLogLevel.NONE) {
|
|
193
|
+
maxLevel = DiagLogLevel.NONE;
|
|
194
|
+
} else if (maxLevel > DiagLogLevel.ALL) {
|
|
195
|
+
maxLevel = DiagLogLevel.ALL;
|
|
196
|
+
}
|
|
197
|
+
logger = logger || {};
|
|
198
|
+
function _filterFunc(funcName, theLevel) {
|
|
199
|
+
const theFunc = logger[funcName];
|
|
200
|
+
if (typeof theFunc === "function" && maxLevel >= theLevel) {
|
|
201
|
+
return theFunc.bind(logger);
|
|
202
|
+
}
|
|
203
|
+
return function() {
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
error: _filterFunc("error", DiagLogLevel.ERROR),
|
|
208
|
+
warn: _filterFunc("warn", DiagLogLevel.WARN),
|
|
209
|
+
info: _filterFunc("info", DiagLogLevel.INFO),
|
|
210
|
+
debug: _filterFunc("debug", DiagLogLevel.DEBUG),
|
|
211
|
+
verbose: _filterFunc("verbose", DiagLogLevel.VERBOSE)
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// node_modules/@opentelemetry/api/build/esm/api/diag.js
|
|
216
|
+
var API_NAME = "diag";
|
|
217
|
+
var DiagAPI = class _DiagAPI {
|
|
218
|
+
/** Get the singleton instance of the DiagAPI API */
|
|
219
|
+
static instance() {
|
|
220
|
+
if (!this._instance) {
|
|
221
|
+
this._instance = new _DiagAPI();
|
|
222
|
+
}
|
|
223
|
+
return this._instance;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Private internal constructor
|
|
227
|
+
* @private
|
|
228
|
+
*/
|
|
229
|
+
constructor() {
|
|
230
|
+
function _logProxy(funcName) {
|
|
231
|
+
return function(...args) {
|
|
232
|
+
const logger = getGlobal("diag");
|
|
233
|
+
if (!logger)
|
|
234
|
+
return;
|
|
235
|
+
return logger[funcName](...args);
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const self2 = this;
|
|
239
|
+
const setLogger = (logger, optionsOrLogLevel = { logLevel: DiagLogLevel.INFO }) => {
|
|
240
|
+
var _a, _b, _c;
|
|
241
|
+
if (logger === self2) {
|
|
242
|
+
const err = new Error("Cannot use diag as the logger for itself. Please use a DiagLogger implementation like ConsoleDiagLogger or a custom implementation");
|
|
243
|
+
self2.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
if (typeof optionsOrLogLevel === "number") {
|
|
247
|
+
optionsOrLogLevel = {
|
|
248
|
+
logLevel: optionsOrLogLevel
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const oldLogger = getGlobal("diag");
|
|
252
|
+
const newLogger = createLogLevelDiagLogger((_b = optionsOrLogLevel.logLevel) !== null && _b !== void 0 ? _b : DiagLogLevel.INFO, logger);
|
|
253
|
+
if (oldLogger && !optionsOrLogLevel.suppressOverrideMessage) {
|
|
254
|
+
const stack = (_c = new Error().stack) !== null && _c !== void 0 ? _c : "<failed to generate stacktrace>";
|
|
255
|
+
oldLogger.warn(`Current logger will be overwritten from ${stack}`);
|
|
256
|
+
newLogger.warn(`Current logger will overwrite one already registered from ${stack}`);
|
|
257
|
+
}
|
|
258
|
+
return registerGlobal("diag", newLogger, self2, true);
|
|
259
|
+
};
|
|
260
|
+
self2.setLogger = setLogger;
|
|
261
|
+
self2.disable = () => {
|
|
262
|
+
unregisterGlobal(API_NAME, self2);
|
|
263
|
+
};
|
|
264
|
+
self2.createComponentLogger = (options) => {
|
|
265
|
+
return new DiagComponentLogger(options);
|
|
266
|
+
};
|
|
267
|
+
self2.verbose = _logProxy("verbose");
|
|
268
|
+
self2.debug = _logProxy("debug");
|
|
269
|
+
self2.info = _logProxy("info");
|
|
270
|
+
self2.warn = _logProxy("warn");
|
|
271
|
+
self2.error = _logProxy("error");
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js
|
|
276
|
+
var BaggageImpl = class _BaggageImpl {
|
|
277
|
+
constructor(entries) {
|
|
278
|
+
this._entries = entries ? new Map(entries) : /* @__PURE__ */ new Map();
|
|
279
|
+
}
|
|
280
|
+
getEntry(key) {
|
|
281
|
+
const entry = this._entries.get(key);
|
|
282
|
+
if (!entry) {
|
|
283
|
+
return void 0;
|
|
284
|
+
}
|
|
285
|
+
return Object.assign({}, entry);
|
|
286
|
+
}
|
|
287
|
+
getAllEntries() {
|
|
288
|
+
return Array.from(this._entries.entries());
|
|
289
|
+
}
|
|
290
|
+
setEntry(key, entry) {
|
|
291
|
+
const newBaggage = new _BaggageImpl(this._entries);
|
|
292
|
+
newBaggage._entries.set(key, entry);
|
|
293
|
+
return newBaggage;
|
|
294
|
+
}
|
|
295
|
+
removeEntry(key) {
|
|
296
|
+
const newBaggage = new _BaggageImpl(this._entries);
|
|
297
|
+
newBaggage._entries.delete(key);
|
|
298
|
+
return newBaggage;
|
|
299
|
+
}
|
|
300
|
+
removeEntries(...keys) {
|
|
301
|
+
const newBaggage = new _BaggageImpl(this._entries);
|
|
302
|
+
for (const key of keys) {
|
|
303
|
+
newBaggage._entries.delete(key);
|
|
304
|
+
}
|
|
305
|
+
return newBaggage;
|
|
306
|
+
}
|
|
307
|
+
clear() {
|
|
308
|
+
return new _BaggageImpl();
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// node_modules/@opentelemetry/api/build/esm/baggage/utils.js
|
|
313
|
+
var diag = DiagAPI.instance();
|
|
314
|
+
function createBaggage(entries = {}) {
|
|
315
|
+
return new BaggageImpl(new Map(Object.entries(entries)));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// node_modules/@opentelemetry/api/build/esm/context/context.js
|
|
319
|
+
function createContextKey(description) {
|
|
320
|
+
return Symbol.for(description);
|
|
321
|
+
}
|
|
322
|
+
var BaseContext = class _BaseContext {
|
|
323
|
+
/**
|
|
324
|
+
* Construct a new context which inherits values from an optional parent context.
|
|
325
|
+
*
|
|
326
|
+
* @param parentContext a context from which to inherit values
|
|
327
|
+
*/
|
|
328
|
+
constructor(parentContext) {
|
|
329
|
+
const self2 = this;
|
|
330
|
+
self2._currentContext = parentContext ? new Map(parentContext) : /* @__PURE__ */ new Map();
|
|
331
|
+
self2.getValue = (key) => self2._currentContext.get(key);
|
|
332
|
+
self2.setValue = (key, value) => {
|
|
333
|
+
const context = new _BaseContext(self2._currentContext);
|
|
334
|
+
context._currentContext.set(key, value);
|
|
335
|
+
return context;
|
|
336
|
+
};
|
|
337
|
+
self2.deleteValue = (key) => {
|
|
338
|
+
const context = new _BaseContext(self2._currentContext);
|
|
339
|
+
context._currentContext.delete(key);
|
|
340
|
+
return context;
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
var ROOT_CONTEXT = new BaseContext();
|
|
345
|
+
|
|
346
|
+
// node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js
|
|
347
|
+
var defaultTextMapGetter = {
|
|
348
|
+
get(carrier, key) {
|
|
349
|
+
if (carrier == null) {
|
|
350
|
+
return void 0;
|
|
351
|
+
}
|
|
352
|
+
return carrier[key];
|
|
353
|
+
},
|
|
354
|
+
keys(carrier) {
|
|
355
|
+
if (carrier == null) {
|
|
356
|
+
return [];
|
|
357
|
+
}
|
|
358
|
+
return Object.keys(carrier);
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
var defaultTextMapSetter = {
|
|
362
|
+
set(carrier, key, value) {
|
|
363
|
+
if (carrier == null) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
carrier[key] = value;
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
// node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js
|
|
371
|
+
var NoopContextManager = class {
|
|
372
|
+
active() {
|
|
373
|
+
return ROOT_CONTEXT;
|
|
374
|
+
}
|
|
375
|
+
with(_context, fn, thisArg, ...args) {
|
|
376
|
+
return fn.call(thisArg, ...args);
|
|
377
|
+
}
|
|
378
|
+
bind(_context, target) {
|
|
379
|
+
return target;
|
|
380
|
+
}
|
|
381
|
+
enable() {
|
|
382
|
+
return this;
|
|
383
|
+
}
|
|
384
|
+
disable() {
|
|
385
|
+
return this;
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// node_modules/@opentelemetry/api/build/esm/api/context.js
|
|
390
|
+
var API_NAME2 = "context";
|
|
391
|
+
var NOOP_CONTEXT_MANAGER = new NoopContextManager();
|
|
392
|
+
var ContextAPI = class _ContextAPI {
|
|
393
|
+
/** Empty private constructor prevents end users from constructing a new instance of the API */
|
|
394
|
+
constructor() {
|
|
395
|
+
}
|
|
396
|
+
/** Get the singleton instance of the Context API */
|
|
397
|
+
static getInstance() {
|
|
398
|
+
if (!this._instance) {
|
|
399
|
+
this._instance = new _ContextAPI();
|
|
400
|
+
}
|
|
401
|
+
return this._instance;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Set the current context manager.
|
|
405
|
+
*
|
|
406
|
+
* @returns true if the context manager was successfully registered, else false
|
|
407
|
+
*/
|
|
408
|
+
setGlobalContextManager(contextManager) {
|
|
409
|
+
return registerGlobal(API_NAME2, contextManager, DiagAPI.instance());
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Get the currently active context
|
|
413
|
+
*/
|
|
414
|
+
active() {
|
|
415
|
+
return this._getContextManager().active();
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Execute a function with an active context
|
|
419
|
+
*
|
|
420
|
+
* @param context context to be active during function execution
|
|
421
|
+
* @param fn function to execute in a context
|
|
422
|
+
* @param thisArg optional receiver to be used for calling fn
|
|
423
|
+
* @param args optional arguments forwarded to fn
|
|
424
|
+
*/
|
|
425
|
+
with(context, fn, thisArg, ...args) {
|
|
426
|
+
return this._getContextManager().with(context, fn, thisArg, ...args);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Bind a context to a target function or event emitter
|
|
430
|
+
*
|
|
431
|
+
* @param context context to bind to the event emitter or function. Defaults to the currently active context
|
|
432
|
+
* @param target function or event emitter to bind
|
|
433
|
+
*/
|
|
434
|
+
bind(context, target) {
|
|
435
|
+
return this._getContextManager().bind(context, target);
|
|
436
|
+
}
|
|
437
|
+
_getContextManager() {
|
|
438
|
+
return getGlobal(API_NAME2) || NOOP_CONTEXT_MANAGER;
|
|
439
|
+
}
|
|
440
|
+
/** Disable and remove the global context manager */
|
|
441
|
+
disable() {
|
|
442
|
+
this._getContextManager().disable();
|
|
443
|
+
unregisterGlobal(API_NAME2, DiagAPI.instance());
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
// node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js
|
|
448
|
+
var NoopTextMapPropagator = class {
|
|
449
|
+
/** Noop inject function does nothing */
|
|
450
|
+
inject(_context, _carrier) {
|
|
451
|
+
}
|
|
452
|
+
/** Noop extract function does nothing and returns the input context */
|
|
453
|
+
extract(context, _carrier) {
|
|
454
|
+
return context;
|
|
455
|
+
}
|
|
456
|
+
fields() {
|
|
457
|
+
return [];
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js
|
|
462
|
+
var BAGGAGE_KEY = createContextKey("OpenTelemetry Baggage Key");
|
|
463
|
+
function getBaggage(context) {
|
|
464
|
+
return context.getValue(BAGGAGE_KEY) || void 0;
|
|
465
|
+
}
|
|
466
|
+
function getActiveBaggage() {
|
|
467
|
+
return getBaggage(ContextAPI.getInstance().active());
|
|
468
|
+
}
|
|
469
|
+
function setBaggage(context, baggage) {
|
|
470
|
+
return context.setValue(BAGGAGE_KEY, baggage);
|
|
471
|
+
}
|
|
472
|
+
function deleteBaggage(context) {
|
|
473
|
+
return context.deleteValue(BAGGAGE_KEY);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// node_modules/@opentelemetry/api/build/esm/api/propagation.js
|
|
477
|
+
var API_NAME3 = "propagation";
|
|
478
|
+
var NOOP_TEXT_MAP_PROPAGATOR = new NoopTextMapPropagator();
|
|
479
|
+
var PropagationAPI = class _PropagationAPI {
|
|
480
|
+
/** Empty private constructor prevents end users from constructing a new instance of the API */
|
|
481
|
+
constructor() {
|
|
482
|
+
this.createBaggage = createBaggage;
|
|
483
|
+
this.getBaggage = getBaggage;
|
|
484
|
+
this.getActiveBaggage = getActiveBaggage;
|
|
485
|
+
this.setBaggage = setBaggage;
|
|
486
|
+
this.deleteBaggage = deleteBaggage;
|
|
487
|
+
}
|
|
488
|
+
/** Get the singleton instance of the Propagator API */
|
|
489
|
+
static getInstance() {
|
|
490
|
+
if (!this._instance) {
|
|
491
|
+
this._instance = new _PropagationAPI();
|
|
492
|
+
}
|
|
493
|
+
return this._instance;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Set the current propagator.
|
|
497
|
+
*
|
|
498
|
+
* @returns true if the propagator was successfully registered, else false
|
|
499
|
+
*/
|
|
500
|
+
setGlobalPropagator(propagator) {
|
|
501
|
+
return registerGlobal(API_NAME3, propagator, DiagAPI.instance());
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Inject context into a carrier to be propagated inter-process
|
|
505
|
+
*
|
|
506
|
+
* @param context Context carrying tracing data to inject
|
|
507
|
+
* @param carrier carrier to inject context into
|
|
508
|
+
* @param setter Function used to set values on the carrier
|
|
509
|
+
*/
|
|
510
|
+
inject(context, carrier, setter = defaultTextMapSetter) {
|
|
511
|
+
return this._getGlobalPropagator().inject(context, carrier, setter);
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Extract context from a carrier
|
|
515
|
+
*
|
|
516
|
+
* @param context Context which the newly created context will inherit from
|
|
517
|
+
* @param carrier Carrier to extract context from
|
|
518
|
+
* @param getter Function used to extract keys from a carrier
|
|
519
|
+
*/
|
|
520
|
+
extract(context, carrier, getter = defaultTextMapGetter) {
|
|
521
|
+
return this._getGlobalPropagator().extract(context, carrier, getter);
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Return a list of all fields which may be used by the propagator.
|
|
525
|
+
*/
|
|
526
|
+
fields() {
|
|
527
|
+
return this._getGlobalPropagator().fields();
|
|
528
|
+
}
|
|
529
|
+
/** Remove the global propagator */
|
|
530
|
+
disable() {
|
|
531
|
+
unregisterGlobal(API_NAME3, DiagAPI.instance());
|
|
532
|
+
}
|
|
533
|
+
_getGlobalPropagator() {
|
|
534
|
+
return getGlobal(API_NAME3) || NOOP_TEXT_MAP_PROPAGATOR;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// node_modules/@opentelemetry/api/build/esm/propagation-api.js
|
|
539
|
+
var propagation = PropagationAPI.getInstance();
|
|
540
|
+
|
|
541
|
+
// src/firstflow-span-processor.ts
|
|
542
|
+
var FLUSH_SIZE = 20;
|
|
543
|
+
var FLUSH_INTERVAL_MS = 2e3;
|
|
544
|
+
var REQUEST_TIMEOUT_MS = 1e4;
|
|
545
|
+
var MAX_QUEUE_SIZE = 500;
|
|
546
|
+
var AGENT_ID_ATTR = "firstflow.agent_id";
|
|
547
|
+
function spanToOtlpJson(span) {
|
|
548
|
+
const attrs = span.attributes;
|
|
549
|
+
const otlpAttrs = [];
|
|
550
|
+
for (const [key, val] of Object.entries(attrs)) {
|
|
551
|
+
if (val === void 0) continue;
|
|
552
|
+
if (key === AGENT_ID_ATTR) continue;
|
|
553
|
+
if (typeof val === "string") {
|
|
554
|
+
otlpAttrs.push({ key, value: { stringValue: val } });
|
|
555
|
+
} else if (typeof val === "number") {
|
|
556
|
+
if (Number.isInteger(val)) {
|
|
557
|
+
otlpAttrs.push({ key, value: { intValue: val } });
|
|
558
|
+
} else {
|
|
559
|
+
otlpAttrs.push({ key, value: { doubleValue: val } });
|
|
560
|
+
}
|
|
561
|
+
} else if (typeof val === "boolean") {
|
|
562
|
+
otlpAttrs.push({ key, value: { boolValue: val } });
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
const startNs = BigInt(span.startTime[0]) * BigInt(1e9) + BigInt(span.startTime[1]);
|
|
566
|
+
const endNs = BigInt(span.endTime[0]) * BigInt(1e9) + BigInt(span.endTime[1]);
|
|
567
|
+
const parentId = span.parentSpanId;
|
|
568
|
+
return {
|
|
569
|
+
traceId: span.spanContext().traceId,
|
|
570
|
+
spanId: span.spanContext().spanId,
|
|
571
|
+
parentSpanId: parentId || void 0,
|
|
572
|
+
name: span.name,
|
|
573
|
+
startTimeUnixNano: startNs.toString(),
|
|
574
|
+
endTimeUnixNano: endNs.toString(),
|
|
575
|
+
status: span.status ? { code: span.status.code, message: span.status.message } : void 0,
|
|
576
|
+
attributes: otlpAttrs
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
var FirstflowSpanProcessor = class {
|
|
580
|
+
constructor(opts) {
|
|
581
|
+
this.opts = opts;
|
|
582
|
+
}
|
|
583
|
+
opts;
|
|
584
|
+
/** Spans partitioned by agent id — partitioning happens at ingest, not flush. */
|
|
585
|
+
buffers = /* @__PURE__ */ new Map();
|
|
586
|
+
bufferedCount = 0;
|
|
587
|
+
flushTimer;
|
|
588
|
+
onStart(span, parentContext) {
|
|
589
|
+
const agentId = propagation.getBaggage(parentContext)?.getEntry(AGENT_ID_ATTR)?.value;
|
|
590
|
+
if (agentId) span.setAttribute(AGENT_ID_ATTR, agentId);
|
|
591
|
+
}
|
|
592
|
+
onEnd(span) {
|
|
593
|
+
const genAi = span.attributes["gen_ai.system"];
|
|
594
|
+
if (!genAi) return;
|
|
595
|
+
const agentId = span.attributes[AGENT_ID_ATTR];
|
|
596
|
+
if (typeof agentId !== "string" || !agentId) return;
|
|
597
|
+
let bucket = this.buffers.get(agentId);
|
|
598
|
+
if (!bucket) {
|
|
599
|
+
bucket = [];
|
|
600
|
+
this.buffers.set(agentId, bucket);
|
|
601
|
+
}
|
|
602
|
+
if (this.bufferedCount >= MAX_QUEUE_SIZE) {
|
|
603
|
+
const firstKey = this.buffers.keys().next().value;
|
|
604
|
+
if (firstKey !== void 0) {
|
|
605
|
+
const b = this.buffers.get(firstKey);
|
|
606
|
+
b.shift();
|
|
607
|
+
if (b.length === 0) this.buffers.delete(firstKey);
|
|
608
|
+
this.bufferedCount--;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
bucket.push(span);
|
|
612
|
+
this.bufferedCount++;
|
|
613
|
+
if (this.bufferedCount >= FLUSH_SIZE) {
|
|
614
|
+
void this.flush();
|
|
615
|
+
} else {
|
|
616
|
+
this.scheduleFlush();
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
async shutdown() {
|
|
620
|
+
if (this.flushTimer != null) {
|
|
621
|
+
clearTimeout(this.flushTimer);
|
|
622
|
+
this.flushTimer = void 0;
|
|
623
|
+
}
|
|
624
|
+
await this.flush();
|
|
625
|
+
}
|
|
626
|
+
async forceFlush() {
|
|
627
|
+
await this.flush();
|
|
628
|
+
}
|
|
629
|
+
scheduleFlush() {
|
|
630
|
+
if (this.flushTimer != null) return;
|
|
631
|
+
this.flushTimer = setTimeout(() => {
|
|
632
|
+
this.flushTimer = void 0;
|
|
633
|
+
void this.flush();
|
|
634
|
+
}, FLUSH_INTERVAL_MS);
|
|
635
|
+
}
|
|
636
|
+
async flush() {
|
|
637
|
+
if (this.flushTimer != null) {
|
|
638
|
+
clearTimeout(this.flushTimer);
|
|
639
|
+
this.flushTimer = void 0;
|
|
640
|
+
}
|
|
641
|
+
if (this.bufferedCount === 0) return;
|
|
642
|
+
const batches = [...this.buffers.entries()];
|
|
643
|
+
this.buffers.clear();
|
|
644
|
+
this.bufferedCount = 0;
|
|
645
|
+
await Promise.all(batches.map(([agentId, spans]) => this.post(agentId, spans)));
|
|
646
|
+
}
|
|
647
|
+
async post(agentId, spans) {
|
|
648
|
+
if (spans.length === 0) return;
|
|
649
|
+
const otlpSpans = spans.map(spanToOtlpJson);
|
|
650
|
+
const body = JSON.stringify({
|
|
651
|
+
resourceSpans: [
|
|
652
|
+
{
|
|
653
|
+
resource: {
|
|
654
|
+
attributes: [
|
|
655
|
+
{ key: "service.name", value: { stringValue: "firstflow-server" } }
|
|
656
|
+
]
|
|
657
|
+
},
|
|
658
|
+
scopeSpans: [{ spans: otlpSpans }]
|
|
659
|
+
}
|
|
660
|
+
]
|
|
661
|
+
});
|
|
662
|
+
const url = `${this.opts.baseUrl}/v1/agents/${encodeURIComponent(agentId)}/traces`;
|
|
663
|
+
const ac = new AbortController();
|
|
664
|
+
const timer = setTimeout(() => ac.abort(), REQUEST_TIMEOUT_MS);
|
|
665
|
+
try {
|
|
666
|
+
await fetch(url, {
|
|
667
|
+
method: "POST",
|
|
668
|
+
headers: {
|
|
669
|
+
Authorization: `Bearer ${this.opts.apiKey}`,
|
|
670
|
+
"Content-Type": "application/json"
|
|
671
|
+
},
|
|
672
|
+
body,
|
|
673
|
+
signal: ac.signal
|
|
674
|
+
});
|
|
675
|
+
} catch {
|
|
676
|
+
} finally {
|
|
677
|
+
clearTimeout(timer);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
// src/sanitize.ts
|
|
683
|
+
var SENSITIVE_KEY_RE = /(password|secret|token|api[-_]?key|cookie|auth)/i;
|
|
684
|
+
var DEFAULT_MAX_DEPTH = 4;
|
|
685
|
+
var DEFAULT_MAX_STRING_LEN = 1024;
|
|
686
|
+
var RESERVED_KEYS = /* @__PURE__ */ new Set([
|
|
687
|
+
"token",
|
|
688
|
+
"api_key",
|
|
689
|
+
"distinct_id",
|
|
690
|
+
"$anon_distinct_id",
|
|
691
|
+
"$device_id",
|
|
692
|
+
"$session_id",
|
|
693
|
+
"$user_id",
|
|
694
|
+
"$set",
|
|
695
|
+
"$set_once",
|
|
696
|
+
"groups",
|
|
697
|
+
"$groups",
|
|
698
|
+
"event",
|
|
699
|
+
"timestamp",
|
|
700
|
+
"$insert_id",
|
|
701
|
+
"$lib",
|
|
702
|
+
"$lib_version",
|
|
703
|
+
"$current_url",
|
|
704
|
+
"$host",
|
|
705
|
+
"$pathname",
|
|
706
|
+
"$referrer",
|
|
707
|
+
"$referring_domain"
|
|
708
|
+
]);
|
|
709
|
+
function isReservedKey(key) {
|
|
710
|
+
return RESERVED_KEYS.has(key) || key.startsWith("$");
|
|
711
|
+
}
|
|
712
|
+
function sanitizeValueInternal(value, depth, maxDepth, maxStringLen) {
|
|
713
|
+
if (value === null || value === void 0) return value;
|
|
714
|
+
if (typeof value === "string") {
|
|
715
|
+
if (value.length <= maxStringLen) return value;
|
|
716
|
+
return `${value.slice(0, maxStringLen)}\u2026truncated`;
|
|
717
|
+
}
|
|
718
|
+
if (typeof value === "number" || typeof value === "boolean") return value;
|
|
719
|
+
if (typeof value !== "object") return void 0;
|
|
720
|
+
if (depth >= maxDepth) return void 0;
|
|
721
|
+
if (Array.isArray(value)) {
|
|
722
|
+
const next = [];
|
|
723
|
+
for (const entry of value) {
|
|
724
|
+
next.push(sanitizeValueInternal(entry, depth + 1, maxDepth, maxStringLen));
|
|
725
|
+
}
|
|
726
|
+
return next;
|
|
727
|
+
}
|
|
728
|
+
const obj = value;
|
|
729
|
+
const out = {};
|
|
730
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
731
|
+
const keyStr = String(k);
|
|
732
|
+
if (!isReservedKey(keyStr) && SENSITIVE_KEY_RE.test(keyStr)) continue;
|
|
733
|
+
const sv = sanitizeValueInternal(v, depth + 1, maxDepth, maxStringLen);
|
|
734
|
+
if (sv !== void 0) out[keyStr] = sv;
|
|
735
|
+
}
|
|
736
|
+
return Object.keys(out).length > 0 ? out : {};
|
|
737
|
+
}
|
|
738
|
+
function sanitizeAnalyticsProperties(properties, opts = {}) {
|
|
739
|
+
try {
|
|
740
|
+
const maxDepth = typeof opts.maxDepth === "number" && opts.maxDepth >= 1 ? opts.maxDepth : DEFAULT_MAX_DEPTH;
|
|
741
|
+
const maxStringLen = typeof opts.maxStringLen === "number" && opts.maxStringLen >= 1 ? opts.maxStringLen : DEFAULT_MAX_STRING_LEN;
|
|
742
|
+
const sanitized = sanitizeValueInternal(properties, 0, maxDepth, maxStringLen);
|
|
743
|
+
return sanitized && typeof sanitized === "object" && !Array.isArray(sanitized) ? sanitized : {};
|
|
744
|
+
} catch {
|
|
745
|
+
return {};
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// src/analytics-client.ts
|
|
750
|
+
var FLUSH_SIZE2 = 20;
|
|
751
|
+
var FLUSH_INTERVAL_MS2 = 1e3;
|
|
752
|
+
var MAX_QUEUE_SIZE2 = 1e3;
|
|
753
|
+
var REQUEST_TIMEOUT_MS2 = 5e3;
|
|
754
|
+
var MAX_BACKOFF_MS = 8e3;
|
|
755
|
+
var FirstflowAnalyticsClient = class {
|
|
756
|
+
constructor(opts) {
|
|
757
|
+
this.opts = opts;
|
|
758
|
+
}
|
|
759
|
+
opts;
|
|
760
|
+
buffer = [];
|
|
761
|
+
flushTimer;
|
|
762
|
+
backoffMs = 1e3;
|
|
763
|
+
closed = false;
|
|
764
|
+
track(userId, event, properties) {
|
|
765
|
+
if (this.closed) return;
|
|
766
|
+
this.enqueue({
|
|
767
|
+
event,
|
|
768
|
+
message_id: crypto.randomUUID(),
|
|
769
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
770
|
+
session_id: "",
|
|
771
|
+
anonymous_id: "",
|
|
772
|
+
user_id: userId,
|
|
773
|
+
sdk_version: this.opts.sdkVersion,
|
|
774
|
+
...properties && Object.keys(properties).length > 0 ? { props: sanitizeAnalyticsProperties(properties) } : {}
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
identify(userId, traits) {
|
|
778
|
+
if (this.closed) return;
|
|
779
|
+
this.enqueue({
|
|
780
|
+
event: "user_identified",
|
|
781
|
+
message_id: crypto.randomUUID(),
|
|
782
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
783
|
+
session_id: "",
|
|
784
|
+
anonymous_id: "",
|
|
785
|
+
user_id: userId,
|
|
786
|
+
sdk_version: this.opts.sdkVersion,
|
|
787
|
+
...traits && Object.keys(traits).length > 0 ? { props: sanitizeAnalyticsProperties(traits) } : {}
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
async shutdown() {
|
|
791
|
+
if (this.closed) return;
|
|
792
|
+
this.closed = true;
|
|
793
|
+
if (this.flushTimer != null) {
|
|
794
|
+
clearTimeout(this.flushTimer);
|
|
795
|
+
this.flushTimer = void 0;
|
|
796
|
+
}
|
|
797
|
+
await this.flush();
|
|
798
|
+
}
|
|
799
|
+
enqueue(event) {
|
|
800
|
+
if (this.buffer.length >= MAX_QUEUE_SIZE2) {
|
|
801
|
+
this.buffer.shift();
|
|
802
|
+
}
|
|
803
|
+
this.buffer.push(event);
|
|
804
|
+
if (this.buffer.length >= FLUSH_SIZE2) {
|
|
805
|
+
void this.flush();
|
|
806
|
+
} else {
|
|
807
|
+
this.scheduleFlush();
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
scheduleFlush() {
|
|
811
|
+
if (this.flushTimer != null) return;
|
|
812
|
+
this.flushTimer = setTimeout(() => {
|
|
813
|
+
this.flushTimer = void 0;
|
|
814
|
+
void this.flush();
|
|
815
|
+
}, FLUSH_INTERVAL_MS2);
|
|
816
|
+
}
|
|
817
|
+
async flush() {
|
|
818
|
+
if (this.flushTimer != null) {
|
|
819
|
+
clearTimeout(this.flushTimer);
|
|
820
|
+
this.flushTimer = void 0;
|
|
821
|
+
}
|
|
822
|
+
if (this.buffer.length === 0) return;
|
|
823
|
+
const batch = this.buffer.splice(0, this.buffer.length);
|
|
824
|
+
const url = `${this.opts.baseUrl}/agents/${encodeURIComponent(this.opts.agentId)}/analytics/events`;
|
|
825
|
+
const ac = new AbortController();
|
|
826
|
+
const timer = setTimeout(() => ac.abort(), REQUEST_TIMEOUT_MS2);
|
|
827
|
+
try {
|
|
828
|
+
const res = await fetch(url, {
|
|
829
|
+
method: "POST",
|
|
830
|
+
headers: {
|
|
831
|
+
Authorization: `Bearer ${this.opts.apiKey}`,
|
|
832
|
+
"Content-Type": "application/json"
|
|
833
|
+
},
|
|
834
|
+
body: JSON.stringify({ events: batch }),
|
|
835
|
+
signal: ac.signal
|
|
836
|
+
});
|
|
837
|
+
if (res.ok) {
|
|
838
|
+
this.backoffMs = 1e3;
|
|
839
|
+
} else {
|
|
840
|
+
this.requeueWithBackoff(batch);
|
|
841
|
+
}
|
|
842
|
+
} catch {
|
|
843
|
+
this.requeueWithBackoff(batch);
|
|
844
|
+
} finally {
|
|
845
|
+
clearTimeout(timer);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
requeueWithBackoff(events) {
|
|
849
|
+
if (this.closed) return;
|
|
850
|
+
const space = MAX_QUEUE_SIZE2 - this.buffer.length;
|
|
851
|
+
if (space > 0) {
|
|
852
|
+
this.buffer.unshift(...events.slice(0, space));
|
|
853
|
+
}
|
|
854
|
+
const wait = Math.min(this.backoffMs, MAX_BACKOFF_MS);
|
|
855
|
+
this.backoffMs = Math.min(this.backoffMs * 2, MAX_BACKOFF_MS);
|
|
856
|
+
this.flushTimer = setTimeout(() => {
|
|
857
|
+
this.flushTimer = void 0;
|
|
858
|
+
void this.flush();
|
|
859
|
+
}, wait);
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
|
|
863
|
+
// src/llm-content-redactor.ts
|
|
864
|
+
function stripGenAiContentAttributes(attrs) {
|
|
865
|
+
if (!attrs) return attrs;
|
|
866
|
+
const out = { ...attrs };
|
|
867
|
+
for (const key of Object.keys(out)) {
|
|
868
|
+
if (key.startsWith("gen_ai.prompt") || key.startsWith("gen_ai.completion") || key.startsWith("gen_ai.input.") || key.startsWith("gen_ai.output.")) {
|
|
869
|
+
delete out[key];
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
return out;
|
|
873
|
+
}
|
|
874
|
+
function withRedactedAttributes(span) {
|
|
875
|
+
return new Proxy(span, {
|
|
876
|
+
get(target, prop, receiver) {
|
|
877
|
+
if (prop === "attributes") {
|
|
878
|
+
const raw = Reflect.get(target, "attributes", receiver);
|
|
879
|
+
return stripGenAiContentAttributes(raw) ?? raw;
|
|
880
|
+
}
|
|
881
|
+
return Reflect.get(target, prop, receiver);
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
function createLlmContentRedactor(captureLlmContent, inner) {
|
|
886
|
+
return {
|
|
887
|
+
onStart(span, parentContext) {
|
|
888
|
+
inner.onStart(span, parentContext);
|
|
889
|
+
},
|
|
890
|
+
onEnd(span) {
|
|
891
|
+
if (captureLlmContent) {
|
|
892
|
+
inner.onEnd(span);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
inner.onEnd(withRedactedAttributes(span));
|
|
896
|
+
},
|
|
897
|
+
shutdown() {
|
|
898
|
+
return inner.shutdown();
|
|
899
|
+
},
|
|
900
|
+
forceFlush() {
|
|
901
|
+
return inner.forceFlush();
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// src/forwarder.ts
|
|
907
|
+
var FORWARD_TIMEOUT_MS = 2e3;
|
|
908
|
+
function forwardConversationMessage(args, failureBuffer) {
|
|
909
|
+
const url = `${args.baseUrl.replace(/\/$/, "")}/v1/conversations/${encodeURIComponent(
|
|
910
|
+
args.conversationId
|
|
911
|
+
)}/messages`;
|
|
912
|
+
const body = JSON.stringify({
|
|
913
|
+
agentId: args.agentId,
|
|
914
|
+
conversationId: args.conversationId,
|
|
915
|
+
userId: args.userId,
|
|
916
|
+
role: args.role,
|
|
917
|
+
content: args.content,
|
|
918
|
+
...args.recentMessages && args.recentMessages.length ? { recentMessages: args.recentMessages } : {},
|
|
919
|
+
...args.model !== void 0 ? { model: args.model } : {},
|
|
920
|
+
...args.provider !== void 0 ? { provider: args.provider } : {},
|
|
921
|
+
...args.inputTokens !== void 0 ? { inputTokens: args.inputTokens } : {},
|
|
922
|
+
...args.outputTokens !== void 0 ? { outputTokens: args.outputTokens } : {},
|
|
923
|
+
...args.cacheReadTokens !== void 0 ? { cacheReadTokens: args.cacheReadTokens } : {},
|
|
924
|
+
...args.cacheCreationTokens !== void 0 ? { cacheCreationTokens: args.cacheCreationTokens } : {},
|
|
925
|
+
...args.latencyMs !== void 0 ? { latencyMs: args.latencyMs } : {},
|
|
926
|
+
...args.timeToFirstTokenMs !== void 0 ? { timeToFirstTokenMs: args.timeToFirstTokenMs } : {},
|
|
927
|
+
...args.finishReason !== void 0 ? { finishReason: args.finishReason } : {},
|
|
928
|
+
...args.isError !== void 0 ? { isError: args.isError } : {},
|
|
929
|
+
...args.error !== void 0 ? { error: args.error } : {},
|
|
930
|
+
...args.inputCostUsd !== void 0 ? { inputCostUsd: args.inputCostUsd } : {},
|
|
931
|
+
...args.outputCostUsd !== void 0 ? { outputCostUsd: args.outputCostUsd } : {},
|
|
932
|
+
...args.totalCostUsd !== void 0 ? { totalCostUsd: args.totalCostUsd } : {},
|
|
933
|
+
...args.httpStatus !== void 0 ? { httpStatus: args.httpStatus } : {},
|
|
934
|
+
...args.properties !== void 0 ? { properties: args.properties } : {}
|
|
935
|
+
});
|
|
936
|
+
void (async () => {
|
|
937
|
+
const ac = new AbortController();
|
|
938
|
+
const timer = setTimeout(() => ac.abort(), FORWARD_TIMEOUT_MS);
|
|
939
|
+
try {
|
|
940
|
+
const res = await fetch(url, {
|
|
941
|
+
method: "POST",
|
|
942
|
+
headers: {
|
|
943
|
+
Authorization: `Bearer ${args.apiKey}`,
|
|
944
|
+
"Content-Type": "application/json"
|
|
945
|
+
},
|
|
946
|
+
body,
|
|
947
|
+
signal: ac.signal
|
|
948
|
+
});
|
|
949
|
+
if (!res.ok) {
|
|
950
|
+
failureBuffer?.push(args);
|
|
951
|
+
}
|
|
952
|
+
} catch {
|
|
953
|
+
failureBuffer?.push(args);
|
|
954
|
+
} finally {
|
|
955
|
+
clearTimeout(timer);
|
|
956
|
+
}
|
|
957
|
+
})();
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// src/trace-forwarder.ts
|
|
961
|
+
var TRACE_FORWARD_TIMEOUT_MS = 2e3;
|
|
962
|
+
function toIso(d) {
|
|
963
|
+
if (d === void 0 || d === null) return void 0;
|
|
964
|
+
return d instanceof Date ? d.toISOString() : d;
|
|
965
|
+
}
|
|
966
|
+
function serializeSpan(s) {
|
|
967
|
+
return {
|
|
968
|
+
...s.spanId !== void 0 ? { spanId: s.spanId } : {},
|
|
969
|
+
...s.parentSpanId !== void 0 ? { parentSpanId: s.parentSpanId } : {},
|
|
970
|
+
...s.type !== void 0 ? { type: s.type } : {},
|
|
971
|
+
...s.name !== void 0 ? { name: s.name } : {},
|
|
972
|
+
...s.model !== void 0 ? { model: s.model } : {},
|
|
973
|
+
...s.provider !== void 0 ? { provider: s.provider } : {},
|
|
974
|
+
...s.input !== void 0 ? { input: s.input } : {},
|
|
975
|
+
...s.output !== void 0 ? { output: s.output } : {},
|
|
976
|
+
...s.inputTokens !== void 0 ? { inputTokens: s.inputTokens } : {},
|
|
977
|
+
...s.outputTokens !== void 0 ? { outputTokens: s.outputTokens } : {},
|
|
978
|
+
...s.cacheReadTokens !== void 0 ? { cacheReadTokens: s.cacheReadTokens } : {},
|
|
979
|
+
...s.cacheCreationTokens !== void 0 ? { cacheCreationTokens: s.cacheCreationTokens } : {},
|
|
980
|
+
...s.latencyMs !== void 0 ? { latencyMs: s.latencyMs } : {},
|
|
981
|
+
...s.timeToFirstTokenMs !== void 0 ? { timeToFirstTokenMs: s.timeToFirstTokenMs } : {},
|
|
982
|
+
...s.finishReason !== void 0 ? { finishReason: s.finishReason } : {},
|
|
983
|
+
...s.isError !== void 0 ? { isError: s.isError } : {},
|
|
984
|
+
...s.error !== void 0 ? { error: s.error } : {},
|
|
985
|
+
...s.inputCostUsd !== void 0 ? { inputCostUsd: s.inputCostUsd } : {},
|
|
986
|
+
...s.outputCostUsd !== void 0 ? { outputCostUsd: s.outputCostUsd } : {},
|
|
987
|
+
...s.totalCostUsd !== void 0 ? { totalCostUsd: s.totalCostUsd } : {},
|
|
988
|
+
...s.toolsCalled !== void 0 ? { toolsCalled: s.toolsCalled } : {},
|
|
989
|
+
...s.toolCallCount !== void 0 ? { toolCallCount: s.toolCallCount } : {},
|
|
990
|
+
...s.inputState !== void 0 ? { inputState: s.inputState } : {},
|
|
991
|
+
...s.outputState !== void 0 ? { outputState: s.outputState } : {},
|
|
992
|
+
...s.httpStatus !== void 0 ? { httpStatus: s.httpStatus } : {},
|
|
993
|
+
...s.properties !== void 0 ? { properties: s.properties } : {},
|
|
994
|
+
...s.startedAt !== void 0 ? { startedAt: toIso(s.startedAt) } : {},
|
|
995
|
+
...s.endedAt !== void 0 ? { endedAt: toIso(s.endedAt) } : {}
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
function serializeTrace(t) {
|
|
999
|
+
return {
|
|
1000
|
+
...t.traceId !== void 0 ? { traceId: t.traceId } : {},
|
|
1001
|
+
...t.sessionId !== void 0 ? { sessionId: t.sessionId } : {},
|
|
1002
|
+
...t.userId !== void 0 ? { userId: t.userId } : {},
|
|
1003
|
+
...t.name !== void 0 ? { name: t.name } : {},
|
|
1004
|
+
...t.inputState !== void 0 ? { inputState: t.inputState } : {},
|
|
1005
|
+
...t.outputState !== void 0 ? { outputState: t.outputState } : {},
|
|
1006
|
+
...t.latencyMs !== void 0 ? { latencyMs: t.latencyMs } : {},
|
|
1007
|
+
...t.isError !== void 0 ? { isError: t.isError } : {},
|
|
1008
|
+
...t.error !== void 0 ? { error: t.error } : {},
|
|
1009
|
+
...t.properties !== void 0 ? { properties: t.properties } : {},
|
|
1010
|
+
...t.startedAt !== void 0 ? { startedAt: toIso(t.startedAt) } : {},
|
|
1011
|
+
...t.endedAt !== void 0 ? { endedAt: toIso(t.endedAt) } : {},
|
|
1012
|
+
...t.spans && t.spans.length > 0 ? { spans: t.spans.map(serializeSpan) } : {}
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
function forwardTrace(args) {
|
|
1016
|
+
const url = `${args.baseUrl.replace(/\/$/, "")}/v1/agents/${encodeURIComponent(args.agentId)}/traces`;
|
|
1017
|
+
const body = JSON.stringify(serializeTrace(args.trace));
|
|
1018
|
+
void (async () => {
|
|
1019
|
+
const ac = new AbortController();
|
|
1020
|
+
const timer = setTimeout(() => ac.abort(), TRACE_FORWARD_TIMEOUT_MS);
|
|
1021
|
+
try {
|
|
1022
|
+
await fetch(url, {
|
|
1023
|
+
method: "POST",
|
|
1024
|
+
headers: {
|
|
1025
|
+
Authorization: `Bearer ${args.apiKey}`,
|
|
1026
|
+
"Content-Type": "application/json"
|
|
1027
|
+
},
|
|
1028
|
+
body,
|
|
1029
|
+
signal: ac.signal
|
|
1030
|
+
});
|
|
1031
|
+
} catch {
|
|
1032
|
+
} finally {
|
|
1033
|
+
clearTimeout(timer);
|
|
1034
|
+
}
|
|
1035
|
+
})();
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// src/outcome-forwarder.ts
|
|
1039
|
+
var OUTCOME_FORWARD_TIMEOUT_MS = 2e3;
|
|
1040
|
+
function forwardOutcome(args) {
|
|
1041
|
+
const url = `${args.baseUrl.replace(/\/$/, "")}/v1/conversations/${encodeURIComponent(args.conversationId)}/signal`;
|
|
1042
|
+
const payload = {};
|
|
1043
|
+
if (args.outcome !== void 0) payload.outcome = args.outcome;
|
|
1044
|
+
if (args.intent !== void 0) payload.intent = args.intent;
|
|
1045
|
+
if (args.userId !== void 0) payload.userId = args.userId;
|
|
1046
|
+
const body = JSON.stringify(payload);
|
|
1047
|
+
void (async () => {
|
|
1048
|
+
const ac = new AbortController();
|
|
1049
|
+
const timer = setTimeout(() => ac.abort(), OUTCOME_FORWARD_TIMEOUT_MS);
|
|
1050
|
+
try {
|
|
1051
|
+
await fetch(url, {
|
|
1052
|
+
method: "PATCH",
|
|
1053
|
+
headers: {
|
|
1054
|
+
Authorization: `Bearer ${args.apiKey}`,
|
|
1055
|
+
"Content-Type": "application/json"
|
|
1056
|
+
},
|
|
1057
|
+
body,
|
|
1058
|
+
signal: ac.signal
|
|
1059
|
+
});
|
|
1060
|
+
} catch {
|
|
1061
|
+
} finally {
|
|
1062
|
+
clearTimeout(timer);
|
|
1063
|
+
}
|
|
1064
|
+
})();
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// src/feedback-forwarder.ts
|
|
1068
|
+
var FEEDBACK_FORWARD_TIMEOUT_MS = 2e3;
|
|
1069
|
+
function forwardFeedback(args) {
|
|
1070
|
+
const url = `${args.baseUrl.replace(/\/$/, "")}/v1/conversations/${encodeURIComponent(args.conversationId)}/feedback`;
|
|
1071
|
+
const payload = { rating: args.rating };
|
|
1072
|
+
if (args.comment !== void 0) payload.comment = args.comment;
|
|
1073
|
+
if (args.messageId !== void 0) payload.messageId = args.messageId;
|
|
1074
|
+
if (args.userId !== void 0) payload.userId = args.userId;
|
|
1075
|
+
const body = JSON.stringify(payload);
|
|
1076
|
+
void (async () => {
|
|
1077
|
+
const ac = new AbortController();
|
|
1078
|
+
const timer = setTimeout(() => ac.abort(), FEEDBACK_FORWARD_TIMEOUT_MS);
|
|
1079
|
+
try {
|
|
1080
|
+
await fetch(url, {
|
|
1081
|
+
method: "POST",
|
|
1082
|
+
headers: {
|
|
1083
|
+
Authorization: `Bearer ${args.apiKey}`,
|
|
1084
|
+
"Content-Type": "application/json"
|
|
1085
|
+
},
|
|
1086
|
+
body,
|
|
1087
|
+
signal: ac.signal
|
|
1088
|
+
});
|
|
1089
|
+
} catch {
|
|
1090
|
+
} finally {
|
|
1091
|
+
clearTimeout(timer);
|
|
1092
|
+
}
|
|
1093
|
+
})();
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// src/ring-buffer.ts
|
|
1097
|
+
var DEFAULT_MAX = 1e3;
|
|
1098
|
+
var RingBuffer = class {
|
|
1099
|
+
items = [];
|
|
1100
|
+
max;
|
|
1101
|
+
constructor(maxSize = DEFAULT_MAX) {
|
|
1102
|
+
this.max = maxSize;
|
|
1103
|
+
}
|
|
1104
|
+
push(item) {
|
|
1105
|
+
if (this.items.length >= this.max) {
|
|
1106
|
+
this.items.shift();
|
|
1107
|
+
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
1108
|
+
console.warn("[@firstflow/core] ring buffer overflow \u2014 dropped oldest entry");
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
this.items.push(item);
|
|
1112
|
+
}
|
|
1113
|
+
drainAll() {
|
|
1114
|
+
const out = this.items.slice();
|
|
1115
|
+
this.items.length = 0;
|
|
1116
|
+
return out;
|
|
1117
|
+
}
|
|
1118
|
+
size() {
|
|
1119
|
+
return this.items.length;
|
|
1120
|
+
}
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
// src/model-pricing.ts
|
|
1124
|
+
var PRICING = {
|
|
1125
|
+
// -------------------------------------------------------------------------
|
|
1126
|
+
// OpenAI
|
|
1127
|
+
// -------------------------------------------------------------------------
|
|
1128
|
+
"gpt-4o": { inputPer1M: 2.5, outputPer1M: 10 },
|
|
1129
|
+
"gpt-4o-mini": { inputPer1M: 0.15, outputPer1M: 0.6 },
|
|
1130
|
+
"gpt-4o-audio-preview": { inputPer1M: 2.5, outputPer1M: 10 },
|
|
1131
|
+
"gpt-4-turbo": { inputPer1M: 10, outputPer1M: 30 },
|
|
1132
|
+
"gpt-4": { inputPer1M: 30, outputPer1M: 60 },
|
|
1133
|
+
"gpt-3.5-turbo": { inputPer1M: 0.5, outputPer1M: 1.5 },
|
|
1134
|
+
"o1": { inputPer1M: 15, outputPer1M: 60 },
|
|
1135
|
+
"o1-mini": { inputPer1M: 1.1, outputPer1M: 4.4 },
|
|
1136
|
+
"o1-preview": { inputPer1M: 15, outputPer1M: 60 },
|
|
1137
|
+
"o3": { inputPer1M: 10, outputPer1M: 40 },
|
|
1138
|
+
"o3-mini": { inputPer1M: 1.1, outputPer1M: 4.4 },
|
|
1139
|
+
"o4-mini": { inputPer1M: 1.1, outputPer1M: 4.4 },
|
|
1140
|
+
// -------------------------------------------------------------------------
|
|
1141
|
+
// Anthropic
|
|
1142
|
+
// -------------------------------------------------------------------------
|
|
1143
|
+
"claude-opus-4-5": { inputPer1M: 15, outputPer1M: 75 },
|
|
1144
|
+
"claude-opus-4-7": { inputPer1M: 15, outputPer1M: 75 },
|
|
1145
|
+
"claude-sonnet-4-5": { inputPer1M: 3, outputPer1M: 15 },
|
|
1146
|
+
"claude-sonnet-4-6": { inputPer1M: 3, outputPer1M: 15 },
|
|
1147
|
+
"claude-haiku-4-5": { inputPer1M: 0.8, outputPer1M: 4 },
|
|
1148
|
+
"claude-3-5-sonnet-20241022": { inputPer1M: 3, outputPer1M: 15 },
|
|
1149
|
+
"claude-3-5-sonnet-20240620": { inputPer1M: 3, outputPer1M: 15 },
|
|
1150
|
+
"claude-3-5-haiku-20241022": { inputPer1M: 0.8, outputPer1M: 4 },
|
|
1151
|
+
"claude-3-opus-20240229": { inputPer1M: 15, outputPer1M: 75 },
|
|
1152
|
+
"claude-3-sonnet-20240229": { inputPer1M: 3, outputPer1M: 15 },
|
|
1153
|
+
"claude-3-haiku-20240307": { inputPer1M: 0.25, outputPer1M: 1.25 }
|
|
1154
|
+
};
|
|
1155
|
+
function findByPrefix(model) {
|
|
1156
|
+
let candidate = model;
|
|
1157
|
+
while (candidate.includes("-")) {
|
|
1158
|
+
candidate = candidate.replace(/-[^-]+$/, "");
|
|
1159
|
+
const match = Object.keys(PRICING).find((k) => k.startsWith(candidate));
|
|
1160
|
+
if (match) return PRICING[match];
|
|
1161
|
+
}
|
|
1162
|
+
return void 0;
|
|
1163
|
+
}
|
|
1164
|
+
function calculateCost(model, inputTokens, outputTokens) {
|
|
1165
|
+
const pricing = PRICING[model] ?? findByPrefix(model);
|
|
1166
|
+
if (!pricing) return null;
|
|
1167
|
+
const inputCostUsd = inputTokens / 1e6 * pricing.inputPer1M;
|
|
1168
|
+
const outputCostUsd = outputTokens / 1e6 * pricing.outputPer1M;
|
|
1169
|
+
return { inputCostUsd, outputCostUsd, totalCostUsd: inputCostUsd + outputCostUsd };
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
// src/constants.ts
|
|
1173
|
+
var DEFAULT_FIRSTFLOW_BASE_URL = "https://api.firstflow.app";
|
|
1174
|
+
var FIRSTFLOW_SERVER_PACKAGE_VERSION = "0.0.1-alpha.0";
|
|
1175
|
+
|
|
1176
|
+
// src/peer-deps.ts
|
|
1177
|
+
var import_node_module = require("module");
|
|
1178
|
+
var nodeRequire = (0, import_node_module.createRequire)(importMetaUrl);
|
|
1179
|
+
function requirePeer(moduleName) {
|
|
1180
|
+
return nodeRequire(moduleName);
|
|
1181
|
+
}
|
|
1182
|
+
function isPeerPreloaded(moduleName) {
|
|
1183
|
+
try {
|
|
1184
|
+
const resolved = nodeRequire.resolve(moduleName);
|
|
1185
|
+
const cached = nodeRequire.cache?.[resolved];
|
|
1186
|
+
return cached !== void 0 && cached.exports !== void 0;
|
|
1187
|
+
} catch {
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// src/runtime.ts
|
|
1193
|
+
function enrichSpanCosts(span) {
|
|
1194
|
+
if (span.inputCostUsd !== void 0 && span.outputCostUsd !== void 0) return span;
|
|
1195
|
+
if (!span.model || typeof span.inputTokens !== "number" || typeof span.outputTokens !== "number") {
|
|
1196
|
+
return span;
|
|
1197
|
+
}
|
|
1198
|
+
const cost = calculateCost(span.model, span.inputTokens, span.outputTokens);
|
|
1199
|
+
if (!cost) return span;
|
|
1200
|
+
return {
|
|
1201
|
+
...span,
|
|
1202
|
+
inputCostUsd: span.inputCostUsd ?? cost.inputCostUsd,
|
|
1203
|
+
outputCostUsd: span.outputCostUsd ?? cost.outputCostUsd,
|
|
1204
|
+
totalCostUsd: span.totalCostUsd ?? cost.totalCostUsd
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
function readCaptureLlmContent() {
|
|
1208
|
+
return process.env.FIRSTFLOW_CAPTURE_LLM_CONTENT?.trim().toLowerCase() === "true";
|
|
1209
|
+
}
|
|
1210
|
+
var Runtime = class {
|
|
1211
|
+
apiKey;
|
|
1212
|
+
baseUrl;
|
|
1213
|
+
forwardFailures = new RingBuffer(1e3);
|
|
1214
|
+
analyticsByAgent = /* @__PURE__ */ new Map();
|
|
1215
|
+
otelSdk;
|
|
1216
|
+
closed = false;
|
|
1217
|
+
constructor(apiKey, baseUrl) {
|
|
1218
|
+
this.apiKey = apiKey;
|
|
1219
|
+
this.baseUrl = baseUrl;
|
|
1220
|
+
this.startOpenTelemetry();
|
|
1221
|
+
process.once("beforeExit", () => {
|
|
1222
|
+
void this.shutdown();
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
startOpenTelemetry() {
|
|
1226
|
+
const captureLlmContent = readCaptureLlmContent();
|
|
1227
|
+
const inner = new FirstflowSpanProcessor({ apiKey: this.apiKey, baseUrl: this.baseUrl });
|
|
1228
|
+
const chain = createLlmContentRedactor(captureLlmContent, inner);
|
|
1229
|
+
const resource = (0, import_resources.resourceFromAttributes)({ "service.name": "firstflow-server" });
|
|
1230
|
+
const anthropicInstrumentation = new import_instrumentation_anthropic.AnthropicInstrumentation({ traceContent: captureLlmContent });
|
|
1231
|
+
const anthropicPreloaded = isPeerPreloaded("@anthropic-ai/sdk");
|
|
1232
|
+
this.otelSdk = new import_sdk_node.NodeSDK({
|
|
1233
|
+
resource,
|
|
1234
|
+
spanProcessors: [chain],
|
|
1235
|
+
instrumentations: [
|
|
1236
|
+
new import_instrumentation_openai.OpenAIInstrumentation({ captureMessageContent: captureLlmContent }),
|
|
1237
|
+
anthropicInstrumentation
|
|
1238
|
+
]
|
|
1239
|
+
});
|
|
1240
|
+
this.otelSdk.start();
|
|
1241
|
+
if (anthropicPreloaded) {
|
|
1242
|
+
try {
|
|
1243
|
+
anthropicInstrumentation.manuallyInstrument(requirePeer("@anthropic-ai/sdk"));
|
|
1244
|
+
} catch {
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
analyticsFor(agentId) {
|
|
1249
|
+
let client = this.analyticsByAgent.get(agentId);
|
|
1250
|
+
if (!client) {
|
|
1251
|
+
client = new FirstflowAnalyticsClient({
|
|
1252
|
+
apiKey: this.apiKey,
|
|
1253
|
+
baseUrl: this.baseUrl,
|
|
1254
|
+
agentId,
|
|
1255
|
+
sdkVersion: FIRSTFLOW_SERVER_PACKAGE_VERSION
|
|
1256
|
+
});
|
|
1257
|
+
this.analyticsByAgent.set(agentId, client);
|
|
1258
|
+
}
|
|
1259
|
+
return client;
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Build a request-agnostic `WrapContext` for the proxy. The context carries
|
|
1263
|
+
* only infrastructure hooks — the per-request agent/user/session are parsed
|
|
1264
|
+
* from each call and flow through `ObserveArgs`, never stored here.
|
|
1265
|
+
*/
|
|
1266
|
+
wrapContext() {
|
|
1267
|
+
return {
|
|
1268
|
+
apiKey: this.apiKey,
|
|
1269
|
+
baseUrl: this.baseUrl,
|
|
1270
|
+
onAssistantComplete: (a) => this.observe(a),
|
|
1271
|
+
onUserMessage: (a) => this.observe(a),
|
|
1272
|
+
onError: (a) => {
|
|
1273
|
+
if (!a.conversationId) return;
|
|
1274
|
+
this.observe({
|
|
1275
|
+
agentId: a.agentId,
|
|
1276
|
+
conversationId: a.conversationId,
|
|
1277
|
+
userId: a.userId,
|
|
1278
|
+
role: "assistant",
|
|
1279
|
+
content: "",
|
|
1280
|
+
isError: true,
|
|
1281
|
+
error: a.error,
|
|
1282
|
+
model: a.model,
|
|
1283
|
+
provider: a.provider,
|
|
1284
|
+
latencyMs: a.latencyMs,
|
|
1285
|
+
httpStatus: a.httpStatus
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1290
|
+
observe(args) {
|
|
1291
|
+
let { inputCostUsd, outputCostUsd, totalCostUsd } = args;
|
|
1292
|
+
if (totalCostUsd === void 0 && args.model && typeof args.inputTokens === "number" && typeof args.outputTokens === "number") {
|
|
1293
|
+
const cost = calculateCost(args.model, args.inputTokens, args.outputTokens);
|
|
1294
|
+
if (cost) {
|
|
1295
|
+
inputCostUsd = cost.inputCostUsd;
|
|
1296
|
+
outputCostUsd = cost.outputCostUsd;
|
|
1297
|
+
totalCostUsd = cost.totalCostUsd;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
forwardConversationMessage(
|
|
1301
|
+
{
|
|
1302
|
+
baseUrl: this.baseUrl,
|
|
1303
|
+
apiKey: this.apiKey,
|
|
1304
|
+
agentId: args.agentId,
|
|
1305
|
+
conversationId: args.conversationId,
|
|
1306
|
+
userId: args.userId,
|
|
1307
|
+
role: args.role,
|
|
1308
|
+
content: args.content,
|
|
1309
|
+
model: args.model,
|
|
1310
|
+
provider: args.provider,
|
|
1311
|
+
inputTokens: args.inputTokens,
|
|
1312
|
+
outputTokens: args.outputTokens,
|
|
1313
|
+
cacheReadTokens: args.cacheReadTokens,
|
|
1314
|
+
cacheCreationTokens: args.cacheCreationTokens,
|
|
1315
|
+
latencyMs: args.latencyMs,
|
|
1316
|
+
timeToFirstTokenMs: args.timeToFirstTokenMs,
|
|
1317
|
+
finishReason: args.finishReason,
|
|
1318
|
+
isError: args.isError,
|
|
1319
|
+
error: args.error,
|
|
1320
|
+
inputCostUsd,
|
|
1321
|
+
outputCostUsd,
|
|
1322
|
+
totalCostUsd,
|
|
1323
|
+
httpStatus: args.httpStatus,
|
|
1324
|
+
...args.recentMessages ? { recentMessages: args.recentMessages } : {},
|
|
1325
|
+
...args.properties ? { properties: args.properties } : {}
|
|
1326
|
+
},
|
|
1327
|
+
this.forwardFailures
|
|
1328
|
+
);
|
|
1329
|
+
this.analyticsFor(args.agentId).track(args.userId, "conversation_message", {
|
|
1330
|
+
conversation_id: args.conversationId,
|
|
1331
|
+
role: args.role,
|
|
1332
|
+
has_content: args.content.length > 0
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
trace(agentId, input) {
|
|
1336
|
+
const enriched = input.spans ? { ...input, spans: input.spans.map(enrichSpanCosts) } : input;
|
|
1337
|
+
forwardTrace({ baseUrl: this.baseUrl, apiKey: this.apiKey, agentId, trace: enriched });
|
|
1338
|
+
}
|
|
1339
|
+
outcome(args) {
|
|
1340
|
+
forwardOutcome({ baseUrl: this.baseUrl, apiKey: this.apiKey, ...args });
|
|
1341
|
+
}
|
|
1342
|
+
feedback(args) {
|
|
1343
|
+
forwardFeedback({ baseUrl: this.baseUrl, apiKey: this.apiKey, ...args });
|
|
1344
|
+
}
|
|
1345
|
+
track(agentId, userId, event, properties) {
|
|
1346
|
+
this.analyticsFor(agentId).track(
|
|
1347
|
+
userId,
|
|
1348
|
+
event,
|
|
1349
|
+
properties ? sanitizeAnalyticsProperties({ ...properties }) : void 0
|
|
1350
|
+
);
|
|
1351
|
+
}
|
|
1352
|
+
identify(agentId, userId, traits) {
|
|
1353
|
+
this.analyticsFor(agentId).identify(
|
|
1354
|
+
userId,
|
|
1355
|
+
traits ? sanitizeAnalyticsProperties({ ...traits }) : void 0
|
|
1356
|
+
);
|
|
1357
|
+
}
|
|
1358
|
+
async shutdown() {
|
|
1359
|
+
if (this.closed) return;
|
|
1360
|
+
this.closed = true;
|
|
1361
|
+
if (this.otelSdk) {
|
|
1362
|
+
await this.otelSdk.shutdown().catch(() => {
|
|
1363
|
+
});
|
|
1364
|
+
this.otelSdk = void 0;
|
|
1365
|
+
}
|
|
1366
|
+
for (const client of this.analyticsByAgent.values()) {
|
|
1367
|
+
await client.shutdown().catch(() => {
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
this.analyticsByAgent.clear();
|
|
1371
|
+
const pending = this.forwardFailures.drainAll();
|
|
1372
|
+
for (const p of pending) forwardConversationMessage(p, void 0);
|
|
1373
|
+
}
|
|
1374
|
+
};
|
|
1375
|
+
var _runtime;
|
|
1376
|
+
function getRuntime() {
|
|
1377
|
+
if (_runtime) return _runtime;
|
|
1378
|
+
const apiKey = (process.env.FIRSTFLOW_API_KEY ?? "").trim();
|
|
1379
|
+
if (!apiKey) {
|
|
1380
|
+
throw new Error(
|
|
1381
|
+
"[Firstflow] FIRSTFLOW_API_KEY is required. Set it in your server environment."
|
|
1382
|
+
);
|
|
1383
|
+
}
|
|
1384
|
+
const baseUrl = (process.env.FIRSTFLOW_API_BASE_URL ?? DEFAULT_FIRSTFLOW_BASE_URL).replace(/\/$/, "");
|
|
1385
|
+
_runtime = new Runtime(apiKey, baseUrl);
|
|
1386
|
+
return _runtime;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// src/langchain.ts
|
|
1390
|
+
function asString(v) {
|
|
1391
|
+
return typeof v === "string" ? v.trim() : "";
|
|
1392
|
+
}
|
|
1393
|
+
var warnedIncompleteTagging = false;
|
|
1394
|
+
function warnIncompleteOnce() {
|
|
1395
|
+
if (warnedIncompleteTagging) return;
|
|
1396
|
+
warnedIncompleteTagging = true;
|
|
1397
|
+
console.warn(
|
|
1398
|
+
"[@firstflow/core/langchain] A LangChain run was tagged with some but not all of `firstflowAgentId`, `sessionId`, `userId` \u2014 the turn was NOT observed. Provide all three in the run metadata to track it."
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
function readIdentity(metadata) {
|
|
1402
|
+
if (!metadata) return void 0;
|
|
1403
|
+
const nested = typeof metadata.firstflow === "object" && metadata.firstflow !== null ? metadata.firstflow : {};
|
|
1404
|
+
const agentId = asString(metadata.firstflowAgentId ?? nested.agentId);
|
|
1405
|
+
const sessionId = asString(metadata.sessionId ?? nested.sessionId);
|
|
1406
|
+
const userId = asString(metadata.userId ?? nested.userId);
|
|
1407
|
+
if (!agentId && !sessionId && !userId) return void 0;
|
|
1408
|
+
if (!agentId || !sessionId || !userId) {
|
|
1409
|
+
warnIncompleteOnce();
|
|
1410
|
+
return void 0;
|
|
1411
|
+
}
|
|
1412
|
+
return { agentId, sessionId, userId };
|
|
1413
|
+
}
|
|
1414
|
+
var KNOWN_PROVIDERS = /* @__PURE__ */ new Set(["openai", "anthropic"]);
|
|
1415
|
+
function roleOf(msg) {
|
|
1416
|
+
if (!msg || typeof msg !== "object") return void 0;
|
|
1417
|
+
const m = msg;
|
|
1418
|
+
let t;
|
|
1419
|
+
if (typeof m._getType === "function") t = m._getType();
|
|
1420
|
+
else if (typeof m.getType === "function") t = m.getType();
|
|
1421
|
+
else if (typeof m.role === "string") t = m.role;
|
|
1422
|
+
else if (typeof m.type === "string") t = m.type;
|
|
1423
|
+
switch (t) {
|
|
1424
|
+
case "human":
|
|
1425
|
+
case "user":
|
|
1426
|
+
return "user";
|
|
1427
|
+
case "ai":
|
|
1428
|
+
case "assistant":
|
|
1429
|
+
return "assistant";
|
|
1430
|
+
case "tool":
|
|
1431
|
+
case "function":
|
|
1432
|
+
return "tool";
|
|
1433
|
+
default:
|
|
1434
|
+
return void 0;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
function contentToText(content) {
|
|
1438
|
+
if (typeof content === "string") return content;
|
|
1439
|
+
if (!Array.isArray(content)) return "";
|
|
1440
|
+
let acc = "";
|
|
1441
|
+
for (const part of content) {
|
|
1442
|
+
if (typeof part === "string") {
|
|
1443
|
+
acc += part;
|
|
1444
|
+
} else if (part && typeof part === "object") {
|
|
1445
|
+
const p = part;
|
|
1446
|
+
if (p.type === "text" && typeof p.text === "string") acc += p.text;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
return acc;
|
|
1450
|
+
}
|
|
1451
|
+
function toRecentMessages(messages) {
|
|
1452
|
+
if (!Array.isArray(messages)) return [];
|
|
1453
|
+
const out = [];
|
|
1454
|
+
for (const msg of messages) {
|
|
1455
|
+
const role = roleOf(msg);
|
|
1456
|
+
if (role !== "user" && role !== "assistant") continue;
|
|
1457
|
+
const content = contentToText(msg.content).trim();
|
|
1458
|
+
if (!content) continue;
|
|
1459
|
+
out.push({ role, content });
|
|
1460
|
+
}
|
|
1461
|
+
return out;
|
|
1462
|
+
}
|
|
1463
|
+
function turnStartUserMessage(messages) {
|
|
1464
|
+
if (!Array.isArray(messages) || messages.length === 0) return void 0;
|
|
1465
|
+
const last = messages[messages.length - 1];
|
|
1466
|
+
if (roleOf(last) !== "user") return void 0;
|
|
1467
|
+
const text = contentToText(last.content).trim();
|
|
1468
|
+
return text || void 0;
|
|
1469
|
+
}
|
|
1470
|
+
function extractModel(extraParams, metadata) {
|
|
1471
|
+
const inv = extraParams?.invocation_params ?? {};
|
|
1472
|
+
const fromInv = inv.model ?? inv.model_name ?? inv.modelName;
|
|
1473
|
+
if (typeof fromInv === "string" && fromInv) return fromInv;
|
|
1474
|
+
const fromMeta = metadata?.ls_model_name;
|
|
1475
|
+
return typeof fromMeta === "string" && fromMeta ? fromMeta : void 0;
|
|
1476
|
+
}
|
|
1477
|
+
function extractProvider(metadata) {
|
|
1478
|
+
const p = metadata?.ls_provider;
|
|
1479
|
+
return typeof p === "string" && KNOWN_PROVIDERS.has(p) ? p : void 0;
|
|
1480
|
+
}
|
|
1481
|
+
function extractEndMeta(output) {
|
|
1482
|
+
const out = output ?? {};
|
|
1483
|
+
const generations = out.generations;
|
|
1484
|
+
let text = "";
|
|
1485
|
+
const meta = {};
|
|
1486
|
+
if (Array.isArray(generations)) {
|
|
1487
|
+
for (const promptGens of generations) {
|
|
1488
|
+
if (!Array.isArray(promptGens)) continue;
|
|
1489
|
+
for (const gen of promptGens) {
|
|
1490
|
+
if (!gen || typeof gen !== "object") continue;
|
|
1491
|
+
const g = gen;
|
|
1492
|
+
if (typeof g.text === "string" && g.text) text += g.text;
|
|
1493
|
+
const message = g.message;
|
|
1494
|
+
if (message) {
|
|
1495
|
+
if (!text) text += contentToText(message.content);
|
|
1496
|
+
const usage = message.usage_metadata;
|
|
1497
|
+
if (usage) {
|
|
1498
|
+
if (typeof usage.input_tokens === "number") meta.inputTokens = usage.input_tokens;
|
|
1499
|
+
if (typeof usage.output_tokens === "number") meta.outputTokens = usage.output_tokens;
|
|
1500
|
+
const inDetails = usage.input_token_details;
|
|
1501
|
+
if (typeof inDetails?.cache_read === "number") meta.cacheReadTokens = inDetails.cache_read;
|
|
1502
|
+
if (typeof inDetails?.cache_creation === "number")
|
|
1503
|
+
meta.cacheCreationTokens = inDetails.cache_creation;
|
|
1504
|
+
}
|
|
1505
|
+
const respMeta = message.response_metadata;
|
|
1506
|
+
const stop = respMeta?.stop_reason ?? respMeta?.finish_reason;
|
|
1507
|
+
if (typeof stop === "string" && meta.finishReason === void 0) meta.finishReason = stop;
|
|
1508
|
+
}
|
|
1509
|
+
const genInfo = g.generationInfo;
|
|
1510
|
+
const fr = genInfo?.finish_reason ?? genInfo?.finishReason;
|
|
1511
|
+
if (typeof fr === "string" && meta.finishReason === void 0) meta.finishReason = fr;
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
if (meta.inputTokens === void 0 || meta.outputTokens === void 0) {
|
|
1516
|
+
const llmOutput = out.llmOutput ?? {};
|
|
1517
|
+
const usage = llmOutput.tokenUsage ?? llmOutput.usage ?? {};
|
|
1518
|
+
const input = usage.promptTokens ?? usage.input_tokens ?? usage.prompt_tokens;
|
|
1519
|
+
const outp = usage.completionTokens ?? usage.output_tokens ?? usage.completion_tokens;
|
|
1520
|
+
if (meta.inputTokens === void 0 && typeof input === "number") meta.inputTokens = input;
|
|
1521
|
+
if (meta.outputTokens === void 0 && typeof outp === "number") meta.outputTokens = outp;
|
|
1522
|
+
}
|
|
1523
|
+
return { text, meta };
|
|
1524
|
+
}
|
|
1525
|
+
function safeObserve(fn) {
|
|
1526
|
+
try {
|
|
1527
|
+
fn();
|
|
1528
|
+
} catch (err) {
|
|
1529
|
+
warnRuntimeOnce(err);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
var warnedRuntime = false;
|
|
1533
|
+
function warnRuntimeOnce(err) {
|
|
1534
|
+
if (warnedRuntime) return;
|
|
1535
|
+
warnedRuntime = true;
|
|
1536
|
+
console.warn(
|
|
1537
|
+
`[@firstflow/core/langchain] Telemetry disabled: ${err instanceof Error ? err.message : String(err)}`
|
|
1538
|
+
);
|
|
1539
|
+
}
|
|
1540
|
+
var FirstflowCallbackHandler = class extends import_base.BaseCallbackHandler {
|
|
1541
|
+
name = "firstflow";
|
|
1542
|
+
runs = /* @__PURE__ */ new Map();
|
|
1543
|
+
// -- starts ----------------------------------------------------------------
|
|
1544
|
+
handleChatModelStart(_llm, messages, runId, _parentRunId, extraParams, _tags, metadata) {
|
|
1545
|
+
const identity = readIdentity(metadata);
|
|
1546
|
+
if (!identity) return;
|
|
1547
|
+
const prompt = Array.isArray(messages) ? messages[0] : messages;
|
|
1548
|
+
this.begin(runId, identity, prompt, extraParams, metadata);
|
|
1549
|
+
}
|
|
1550
|
+
handleLLMStart(_llm, prompts, runId, _parentRunId, extraParams, _tags, metadata) {
|
|
1551
|
+
const identity = readIdentity(metadata);
|
|
1552
|
+
if (!identity) return;
|
|
1553
|
+
const list = Array.isArray(prompts) ? prompts : [];
|
|
1554
|
+
const last = list.length ? list[list.length - 1] : void 0;
|
|
1555
|
+
const pseudo = typeof last === "string" ? [{ role: "user", content: last }] : [];
|
|
1556
|
+
this.begin(runId, identity, pseudo, extraParams, metadata);
|
|
1557
|
+
}
|
|
1558
|
+
begin(runId, identity, prompt, extraParams, metadata) {
|
|
1559
|
+
const recentMessages = toRecentMessages(prompt);
|
|
1560
|
+
const model = extractModel(extraParams, metadata);
|
|
1561
|
+
const provider = extractProvider(metadata);
|
|
1562
|
+
this.runs.set(runId, {
|
|
1563
|
+
identity,
|
|
1564
|
+
startTime: Date.now(),
|
|
1565
|
+
model,
|
|
1566
|
+
provider,
|
|
1567
|
+
recentMessages
|
|
1568
|
+
});
|
|
1569
|
+
const userContent = turnStartUserMessage(prompt);
|
|
1570
|
+
if (!userContent) return;
|
|
1571
|
+
safeObserve(
|
|
1572
|
+
() => getRuntime().observe({
|
|
1573
|
+
agentId: identity.agentId,
|
|
1574
|
+
conversationId: identity.sessionId,
|
|
1575
|
+
userId: identity.userId,
|
|
1576
|
+
role: "user",
|
|
1577
|
+
content: userContent,
|
|
1578
|
+
model,
|
|
1579
|
+
provider,
|
|
1580
|
+
...recentMessages.length ? { recentMessages } : {}
|
|
1581
|
+
})
|
|
1582
|
+
);
|
|
1583
|
+
}
|
|
1584
|
+
// -- streaming -------------------------------------------------------------
|
|
1585
|
+
handleLLMNewToken(_token, _idx, runId) {
|
|
1586
|
+
const state = this.runs.get(runId);
|
|
1587
|
+
if (state && state.firstTokenTime === void 0) state.firstTokenTime = Date.now();
|
|
1588
|
+
}
|
|
1589
|
+
// -- ends ------------------------------------------------------------------
|
|
1590
|
+
handleLLMEnd(output, runId) {
|
|
1591
|
+
const state = this.runs.get(runId);
|
|
1592
|
+
if (!state) return;
|
|
1593
|
+
this.runs.delete(runId);
|
|
1594
|
+
const { text, meta } = extractEndMeta(output);
|
|
1595
|
+
const { identity, startTime, firstTokenTime, model, provider, recentMessages } = state;
|
|
1596
|
+
safeObserve(
|
|
1597
|
+
() => getRuntime().observe({
|
|
1598
|
+
agentId: identity.agentId,
|
|
1599
|
+
conversationId: identity.sessionId,
|
|
1600
|
+
userId: identity.userId,
|
|
1601
|
+
role: "assistant",
|
|
1602
|
+
content: text,
|
|
1603
|
+
model,
|
|
1604
|
+
provider,
|
|
1605
|
+
...meta,
|
|
1606
|
+
latencyMs: Date.now() - startTime,
|
|
1607
|
+
...firstTokenTime !== void 0 ? { timeToFirstTokenMs: firstTokenTime - startTime } : {},
|
|
1608
|
+
httpStatus: 200,
|
|
1609
|
+
...recentMessages.length ? { recentMessages } : {}
|
|
1610
|
+
})
|
|
1611
|
+
);
|
|
1612
|
+
}
|
|
1613
|
+
handleLLMError(err, runId) {
|
|
1614
|
+
const state = this.runs.get(runId);
|
|
1615
|
+
if (!state) return;
|
|
1616
|
+
this.runs.delete(runId);
|
|
1617
|
+
const { identity, startTime, model, provider } = state;
|
|
1618
|
+
const status = err?.status;
|
|
1619
|
+
safeObserve(
|
|
1620
|
+
() => getRuntime().observe({
|
|
1621
|
+
agentId: identity.agentId,
|
|
1622
|
+
conversationId: identity.sessionId,
|
|
1623
|
+
userId: identity.userId,
|
|
1624
|
+
role: "assistant",
|
|
1625
|
+
content: "",
|
|
1626
|
+
isError: true,
|
|
1627
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1628
|
+
model,
|
|
1629
|
+
provider,
|
|
1630
|
+
latencyMs: Date.now() - startTime,
|
|
1631
|
+
httpStatus: typeof status === "number" ? status : 500
|
|
1632
|
+
})
|
|
1633
|
+
);
|
|
1634
|
+
}
|
|
1635
|
+
};
|
|
1636
|
+
var _shared;
|
|
1637
|
+
function firstflowCallback() {
|
|
1638
|
+
if (!_shared) _shared = new FirstflowCallbackHandler();
|
|
1639
|
+
return _shared;
|
|
1640
|
+
}
|
|
1641
|
+
function withFirstflow(identity, config) {
|
|
1642
|
+
const handler = firstflowCallback();
|
|
1643
|
+
const existing = Array.isArray(config?.callbacks) ? config.callbacks : config?.callbacks ? [config.callbacks] : [];
|
|
1644
|
+
const callbacks = existing.includes(handler) ? existing : [...existing, handler];
|
|
1645
|
+
return {
|
|
1646
|
+
...config,
|
|
1647
|
+
callbacks,
|
|
1648
|
+
metadata: {
|
|
1649
|
+
...config?.metadata ?? {},
|
|
1650
|
+
firstflowAgentId: identity.agentId,
|
|
1651
|
+
sessionId: identity.sessionId,
|
|
1652
|
+
userId: identity.userId
|
|
1653
|
+
}
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1657
|
+
0 && (module.exports = {
|
|
1658
|
+
FirstflowCallbackHandler,
|
|
1659
|
+
firstflowCallback,
|
|
1660
|
+
withFirstflow
|
|
1661
|
+
});
|