@flutchai/flutch-sdk 0.1.24 → 0.1.25
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/index.cjs +132 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +133 -89
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1245,28 +1245,54 @@ var init_versioned_graph_service = __esm({
|
|
|
1245
1245
|
], exports.VersionedGraphService);
|
|
1246
1246
|
}
|
|
1247
1247
|
});
|
|
1248
|
+
function generateCallbackToken(graphType) {
|
|
1249
|
+
return `cb::${graphType}::${crypto.randomBytes(8).toString("base64url")}`;
|
|
1250
|
+
}
|
|
1251
|
+
function createCallbackRecord(entry, token, now) {
|
|
1252
|
+
return {
|
|
1253
|
+
...entry,
|
|
1254
|
+
token,
|
|
1255
|
+
status: "pending",
|
|
1256
|
+
createdAt: now,
|
|
1257
|
+
retries: 0
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
function resolveCallbackTTL(entry) {
|
|
1261
|
+
return entry.metadata?.ttlSec ?? 600;
|
|
1262
|
+
}
|
|
1263
|
+
function parseCallbackRecord(data) {
|
|
1264
|
+
try {
|
|
1265
|
+
return JSON.parse(data);
|
|
1266
|
+
} catch {
|
|
1267
|
+
return null;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
function markAsFailed(record, error) {
|
|
1271
|
+
return {
|
|
1272
|
+
...record,
|
|
1273
|
+
status: "failed",
|
|
1274
|
+
retries: (record.retries || 0) + 1,
|
|
1275
|
+
lastError: error
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
function markAsPending(record) {
|
|
1279
|
+
return { ...record, status: "pending" };
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
// src/callbacks/callback-store.ts
|
|
1248
1283
|
var CallbackStore = class {
|
|
1249
1284
|
constructor(redis) {
|
|
1250
1285
|
this.redis = redis;
|
|
1251
1286
|
this.isProduction = process.env.NODE_ENV === "production";
|
|
1252
1287
|
}
|
|
1253
1288
|
isProduction;
|
|
1254
|
-
generateToken(graphType) {
|
|
1255
|
-
return `cb::${graphType}::${crypto.randomBytes(8).toString("base64url")}`;
|
|
1256
|
-
}
|
|
1257
1289
|
/**
|
|
1258
1290
|
* Issues a new callback token and persists its payload.
|
|
1259
1291
|
*/
|
|
1260
1292
|
async issue(entry) {
|
|
1261
|
-
const token =
|
|
1262
|
-
const record =
|
|
1263
|
-
|
|
1264
|
-
token,
|
|
1265
|
-
status: "pending",
|
|
1266
|
-
createdAt: Date.now(),
|
|
1267
|
-
retries: 0
|
|
1268
|
-
};
|
|
1269
|
-
const ttl = entry.metadata?.ttlSec ?? 600;
|
|
1293
|
+
const token = generateCallbackToken(entry.graphType);
|
|
1294
|
+
const record = createCallbackRecord(entry, token, Date.now());
|
|
1295
|
+
const ttl = resolveCallbackTTL(entry);
|
|
1270
1296
|
await this.redis.setex(`callback:${token}`, ttl, JSON.stringify(record));
|
|
1271
1297
|
return token;
|
|
1272
1298
|
}
|
|
@@ -1281,7 +1307,9 @@ var CallbackStore = class {
|
|
|
1281
1307
|
}
|
|
1282
1308
|
}
|
|
1283
1309
|
/**
|
|
1284
|
-
* Production version
|
|
1310
|
+
* Production version: uses Redis Lua scripting for atomic get-and-lock.
|
|
1311
|
+
* NOTE: redis.eval() here executes a Lua script on the Redis server,
|
|
1312
|
+
* NOT JavaScript eval(). This is the standard ioredis API for Lua scripting.
|
|
1285
1313
|
*/
|
|
1286
1314
|
async getAndLockAtomic(token) {
|
|
1287
1315
|
const script = `
|
|
@@ -1305,18 +1333,17 @@ var CallbackStore = class {
|
|
|
1305
1333
|
if (!data) {
|
|
1306
1334
|
return null;
|
|
1307
1335
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
return null;
|
|
1312
|
-
}
|
|
1313
|
-
record.status = "processing";
|
|
1314
|
-
await this.redis.set(key, JSON.stringify(record));
|
|
1315
|
-
return record;
|
|
1316
|
-
} catch (error) {
|
|
1317
|
-
console.error("Failed to parse callback record:", error);
|
|
1336
|
+
const record = parseCallbackRecord(data);
|
|
1337
|
+
if (!record) {
|
|
1338
|
+
console.error("Failed to parse callback record");
|
|
1318
1339
|
return null;
|
|
1319
1340
|
}
|
|
1341
|
+
if (record.status !== "pending") {
|
|
1342
|
+
return null;
|
|
1343
|
+
}
|
|
1344
|
+
record.status = "processing";
|
|
1345
|
+
await this.redis.set(key, JSON.stringify(record));
|
|
1346
|
+
return record;
|
|
1320
1347
|
}
|
|
1321
1348
|
/**
|
|
1322
1349
|
* Finalizes callback processing by removing token.
|
|
@@ -1335,7 +1362,8 @@ var CallbackStore = class {
|
|
|
1335
1362
|
}
|
|
1336
1363
|
}
|
|
1337
1364
|
/**
|
|
1338
|
-
* Production version
|
|
1365
|
+
* Production version: uses Redis Lua scripting for atomic fail.
|
|
1366
|
+
* NOTE: redis.eval() here executes a Lua script on the Redis server.
|
|
1339
1367
|
*/
|
|
1340
1368
|
async failAtomic(token, error) {
|
|
1341
1369
|
const script = `
|
|
@@ -1360,17 +1388,14 @@ var CallbackStore = class {
|
|
|
1360
1388
|
if (!data) {
|
|
1361
1389
|
return null;
|
|
1362
1390
|
}
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
record.retries = (record.retries || 0) + 1;
|
|
1367
|
-
record.lastError = error;
|
|
1368
|
-
await this.redis.set(key, JSON.stringify(record));
|
|
1369
|
-
return record;
|
|
1370
|
-
} catch (parseError) {
|
|
1371
|
-
console.error("Failed to parse callback record:", parseError);
|
|
1391
|
+
const record = parseCallbackRecord(data);
|
|
1392
|
+
if (!record) {
|
|
1393
|
+
console.error("Failed to parse callback record");
|
|
1372
1394
|
return null;
|
|
1373
1395
|
}
|
|
1396
|
+
const updated = markAsFailed(record, error);
|
|
1397
|
+
await this.redis.set(key, JSON.stringify(updated));
|
|
1398
|
+
return updated;
|
|
1374
1399
|
}
|
|
1375
1400
|
/**
|
|
1376
1401
|
* Reset callback status to pending for retry.
|
|
@@ -1383,7 +1408,8 @@ var CallbackStore = class {
|
|
|
1383
1408
|
}
|
|
1384
1409
|
}
|
|
1385
1410
|
/**
|
|
1386
|
-
* Production version
|
|
1411
|
+
* Production version: uses Redis Lua scripting for atomic retry.
|
|
1412
|
+
* NOTE: redis.eval() here executes a Lua script on the Redis server.
|
|
1387
1413
|
*/
|
|
1388
1414
|
async retryAtomic(token) {
|
|
1389
1415
|
const script = `
|
|
@@ -1406,15 +1432,14 @@ var CallbackStore = class {
|
|
|
1406
1432
|
if (!data) {
|
|
1407
1433
|
return null;
|
|
1408
1434
|
}
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
await this.redis.set(key, JSON.stringify(record));
|
|
1413
|
-
return record;
|
|
1414
|
-
} catch (parseError) {
|
|
1415
|
-
console.error("Failed to parse callback record:", parseError);
|
|
1435
|
+
const record = parseCallbackRecord(data);
|
|
1436
|
+
if (!record) {
|
|
1437
|
+
console.error("Failed to parse callback record");
|
|
1416
1438
|
return null;
|
|
1417
1439
|
}
|
|
1440
|
+
const updated = markAsPending(record);
|
|
1441
|
+
await this.redis.set(key, JSON.stringify(updated));
|
|
1442
|
+
return updated;
|
|
1418
1443
|
}
|
|
1419
1444
|
};
|
|
1420
1445
|
|
|
@@ -3066,6 +3091,38 @@ exports.CallbackController = __decorateClass([
|
|
|
3066
3091
|
|
|
3067
3092
|
// src/graph/abstract-graph.builder.ts
|
|
3068
3093
|
init_agent_ui();
|
|
3094
|
+
|
|
3095
|
+
// src/graph/graph.logic.ts
|
|
3096
|
+
function isValidSemver(version) {
|
|
3097
|
+
return /^\d+\.\d+\.\d+$/.test(version);
|
|
3098
|
+
}
|
|
3099
|
+
function parseCallbackToken(token) {
|
|
3100
|
+
const parts = token.split("_");
|
|
3101
|
+
if (parts.length < 4 || parts[0] !== "cb") {
|
|
3102
|
+
return null;
|
|
3103
|
+
}
|
|
3104
|
+
const graphName = parts[1];
|
|
3105
|
+
const handler = parts[2];
|
|
3106
|
+
const graphType = `${graphName}::1.0.0`;
|
|
3107
|
+
return { graphType, handler };
|
|
3108
|
+
}
|
|
3109
|
+
function decodeCallbackParams(token) {
|
|
3110
|
+
const parts = token.split("_");
|
|
3111
|
+
if (parts.length < 4) {
|
|
3112
|
+
return {};
|
|
3113
|
+
}
|
|
3114
|
+
try {
|
|
3115
|
+
const encodedParams = parts.slice(3).join("_");
|
|
3116
|
+
const decodedParams = Buffer.from(encodedParams, "base64url").toString(
|
|
3117
|
+
"utf8"
|
|
3118
|
+
);
|
|
3119
|
+
return JSON.parse(decodedParams);
|
|
3120
|
+
} catch {
|
|
3121
|
+
return {};
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
|
|
3125
|
+
// src/graph/abstract-graph.builder.ts
|
|
3069
3126
|
var _AbstractGraphBuilder = class _AbstractGraphBuilder {
|
|
3070
3127
|
logger = new common.Logger(_AbstractGraphBuilder.name);
|
|
3071
3128
|
callbackRegistry;
|
|
@@ -3274,8 +3331,7 @@ var _AbstractGraphBuilder = class _AbstractGraphBuilder {
|
|
|
3274
3331
|
* Version validation
|
|
3275
3332
|
*/
|
|
3276
3333
|
validateVersion() {
|
|
3277
|
-
|
|
3278
|
-
if (!versionRegex.test(this.version)) {
|
|
3334
|
+
if (!isValidSemver(this.version)) {
|
|
3279
3335
|
throw new Error(
|
|
3280
3336
|
`Invalid version format: ${this.version}. Expected format: X.Y.Z`
|
|
3281
3337
|
);
|
|
@@ -3625,36 +3681,21 @@ exports.UniversalGraphService = class UniversalGraphService {
|
|
|
3625
3681
|
* Expected format: cb_{graphName}_{handler}_{encodedParams}
|
|
3626
3682
|
*/
|
|
3627
3683
|
parseCallbackToken(token) {
|
|
3628
|
-
const
|
|
3629
|
-
if (
|
|
3684
|
+
const result = parseCallbackToken(token);
|
|
3685
|
+
if (!result) {
|
|
3630
3686
|
throw new Error(`Invalid callback token format: ${token}`);
|
|
3631
3687
|
}
|
|
3632
|
-
|
|
3633
|
-
const handler = parts[2];
|
|
3634
|
-
const graphType = `${graphName}::1.0.0`;
|
|
3635
|
-
return { graphType, handler };
|
|
3688
|
+
return result;
|
|
3636
3689
|
}
|
|
3637
3690
|
/**
|
|
3638
3691
|
* Extract parameters from callback token
|
|
3639
3692
|
*/
|
|
3640
3693
|
parseCallbackParams(token) {
|
|
3641
|
-
const
|
|
3642
|
-
if (
|
|
3643
|
-
|
|
3644
|
-
}
|
|
3645
|
-
try {
|
|
3646
|
-
const encodedParams = parts.slice(3).join("_");
|
|
3647
|
-
const decodedParams = Buffer.from(encodedParams, "base64url").toString(
|
|
3648
|
-
"utf8"
|
|
3649
|
-
);
|
|
3650
|
-
return JSON.parse(decodedParams);
|
|
3651
|
-
} catch (error) {
|
|
3652
|
-
this.logger.warn(
|
|
3653
|
-
`Failed to parse callback params from token: ${token}`,
|
|
3654
|
-
error
|
|
3655
|
-
);
|
|
3656
|
-
return {};
|
|
3694
|
+
const result = decodeCallbackParams(token);
|
|
3695
|
+
if (Object.keys(result).length === 0 && token.split("_").length >= 4) {
|
|
3696
|
+
this.logger.warn(`Failed to parse callback params from token: ${token}`);
|
|
3657
3697
|
}
|
|
3698
|
+
return result;
|
|
3658
3699
|
}
|
|
3659
3700
|
/**
|
|
3660
3701
|
* Call a graph endpoint
|
|
@@ -5984,6 +6025,24 @@ var ChatFeature = /* @__PURE__ */ ((ChatFeature2) => {
|
|
|
5984
6025
|
ChatFeature2["JSON_MODE"] = "json_mode";
|
|
5985
6026
|
return ChatFeature2;
|
|
5986
6027
|
})(ChatFeature || {});
|
|
6028
|
+
function isReasoningModel(modelName) {
|
|
6029
|
+
return modelName.includes("gpt-5") || modelName.includes("gpt-o1") || modelName.includes("gpt-o2") || modelName.includes("gpt-o3") || modelName.includes("gpt-o4") || /^gpt-(5|6|7|8|9)/.test(modelName) || /^gpt-o[1-4]/.test(modelName);
|
|
6030
|
+
}
|
|
6031
|
+
function hashToolsConfig(toolsConfig) {
|
|
6032
|
+
const sorted = toolsConfig.map((t) => `${t.toolName}:${t.enabled}:${JSON.stringify(t.config || {})}`).sort().join("|");
|
|
6033
|
+
return crypto.createHash("md5").update(sorted).digest("hex").slice(0, 16);
|
|
6034
|
+
}
|
|
6035
|
+
function generateModelCacheKey(modelId, temperature, maxTokens, toolsConfig) {
|
|
6036
|
+
const parts = [
|
|
6037
|
+
modelId,
|
|
6038
|
+
temperature ?? "default",
|
|
6039
|
+
maxTokens ?? "default"
|
|
6040
|
+
];
|
|
6041
|
+
if (toolsConfig && toolsConfig.length > 0) {
|
|
6042
|
+
parts.push(hashToolsConfig(toolsConfig));
|
|
6043
|
+
}
|
|
6044
|
+
return parts.join(":");
|
|
6045
|
+
}
|
|
5987
6046
|
var VoyageAIRerank = class extends document_compressors.BaseDocumentCompressor {
|
|
5988
6047
|
apiKey;
|
|
5989
6048
|
model;
|
|
@@ -6279,8 +6338,7 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
6279
6338
|
* Uses MD5 hash to create short, unique identifier
|
|
6280
6339
|
*/
|
|
6281
6340
|
hashToolsConfig(toolsConfig) {
|
|
6282
|
-
|
|
6283
|
-
return crypto.createHash("md5").update(sorted).digest("hex").slice(0, 16);
|
|
6341
|
+
return hashToolsConfig(toolsConfig);
|
|
6284
6342
|
}
|
|
6285
6343
|
/**
|
|
6286
6344
|
* Generate cache key from ModelByIdConfig
|
|
@@ -6288,16 +6346,12 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
6288
6346
|
* Example: "model123:0.7:4096" or "model123:0.7:4096:a1b2c3d4e5f6g7h8"
|
|
6289
6347
|
*/
|
|
6290
6348
|
generateModelCacheKey(config) {
|
|
6291
|
-
|
|
6349
|
+
return generateModelCacheKey(
|
|
6292
6350
|
config.modelId,
|
|
6293
|
-
config.temperature
|
|
6294
|
-
config.maxTokens
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
const toolsHash = this.hashToolsConfig(config.toolsConfig);
|
|
6298
|
-
parts.push(toolsHash);
|
|
6299
|
-
}
|
|
6300
|
-
return parts.join(":");
|
|
6351
|
+
config.temperature,
|
|
6352
|
+
config.maxTokens,
|
|
6353
|
+
config.toolsConfig
|
|
6354
|
+
);
|
|
6301
6355
|
}
|
|
6302
6356
|
/**
|
|
6303
6357
|
* TEMPORARY SOLUTION for compatibility with new OpenAI models
|
|
@@ -6314,20 +6368,10 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
6314
6368
|
* @returns true if model requires maxCompletionTokens and temperature = 1
|
|
6315
6369
|
*/
|
|
6316
6370
|
requiresMaxCompletionTokens(modelName) {
|
|
6317
|
-
const requiresNew =
|
|
6318
|
-
/^gpt-(5|6|7|8|9)/.test(modelName) || /^gpt-o[1-4]/.test(modelName);
|
|
6371
|
+
const requiresNew = isReasoningModel(modelName);
|
|
6319
6372
|
this.logger.debug(`Checking token parameter for model "${modelName}"`, {
|
|
6320
6373
|
modelName,
|
|
6321
|
-
requiresMaxCompletionTokens: requiresNew
|
|
6322
|
-
checks: {
|
|
6323
|
-
includesGpt5: modelName.includes("gpt-5"),
|
|
6324
|
-
includesO1: modelName.includes("gpt-o1"),
|
|
6325
|
-
includesO2: modelName.includes("gpt-o2"),
|
|
6326
|
-
includesO3: modelName.includes("gpt-o3"),
|
|
6327
|
-
includesO4: modelName.includes("gpt-o4"),
|
|
6328
|
-
regexGpt5Plus: /^gpt-(5|6|7|8|9)/.test(modelName),
|
|
6329
|
-
regexO1to4: /^gpt-o[1-4]/.test(modelName)
|
|
6330
|
-
}
|
|
6374
|
+
requiresMaxCompletionTokens: requiresNew
|
|
6331
6375
|
});
|
|
6332
6376
|
return requiresNew;
|
|
6333
6377
|
}
|