@flutchai/flutch-sdk 0.2.1 → 0.2.3

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 CHANGED
@@ -1323,92 +1323,39 @@ exports.AbstractGraphBuilder = class AbstractGraphBuilder {
1323
1323
  }
1324
1324
  }
1325
1325
  /**
1326
- * Creates execution context for graph with tracer and usageRecorder
1327
- * This method can be overridden in child classes for customization
1326
+ * Prepare config for graph execution
1327
+ * Deserialization happens in engine, so just pass through with customization hook
1328
1328
  */
1329
- createGraphContext(payload) {
1330
- return {
1331
- messageId: payload.messageId,
1332
- threadId: payload.threadId,
1333
- userId: payload.userId,
1334
- agentId: payload.agentId,
1335
- companyId: payload.companyId
1336
- };
1337
- }
1338
- /**
1339
- * Basic configuration preparation for graph execution
1340
- * Automatically creates context with tracer and usageRecorder
1341
- * Handles message deserialization and LangGraph-compatible structure
1342
- * FINAL method - cannot be overridden. Use customizeConfig() hook instead.
1343
- */
1344
- async prepareConfig(payload) {
1345
- const context = this.createGraphContext(payload);
1346
- let message = payload.message;
1347
- if (payload.message && typeof payload.message === "object" && "lc" in payload.message) {
1348
- try {
1349
- const { load } = await import('@langchain/core/load');
1350
- message = await load(JSON.stringify(payload.message));
1351
- this.logger.debug({
1352
- message: "Deserialized BaseMessage using load()",
1353
- type: message.constructor?.name
1354
- });
1355
- } catch (error) {
1356
- this.logger.warn({
1357
- message: "Failed to deserialize message",
1358
- error: error.message
1359
- });
1360
- }
1361
- }
1362
- const baseConfig = {
1363
- // Input for LangGraph (messages array)
1364
- input: message ? {
1365
- messages: [message]
1366
- } : void 0,
1367
- // Configurable settings for LangGraph checkpointing and context
1368
- configurable: {
1369
- thread_id: payload.threadId,
1370
- checkpoint_ns: this.graphType,
1371
- checkpoint_id: `${payload.threadId}-${Date.now()}`,
1372
- context,
1373
- // Add metadata for compatibility
1374
- metadata: {
1375
- userId: payload.userId,
1376
- agentId: payload.agentId,
1377
- requestId: payload.requestId,
1378
- graphType: this.graphType,
1379
- version: this.version,
1380
- workflowType: this.graphType
1381
- },
1382
- // Graph-specific settings from payload
1383
- graphSettings: payload.graphSettings || {}
1384
- }
1385
- };
1386
- const finalConfig = await this.customizeConfig(baseConfig, payload);
1387
- return finalConfig;
1329
+ async preparePayload(payload) {
1330
+ const finalPayload = await this.customizeConfig(payload);
1331
+ return finalPayload;
1388
1332
  }
1389
1333
  /**
1390
- * Hook for customizing config after base preparation
1334
+ * Hook for customizing config before graph execution
1391
1335
  * Override this method in child classes to add/modify config fields
1392
1336
  *
1393
- * @param config - Base config prepared by SDK
1394
- * @param payload - Original request payload
1395
- * @returns Modified config
1337
+ * @param payload - Original request payload with input and config
1338
+ * @returns Modified payload
1396
1339
  *
1397
1340
  * @example
1398
1341
  * ```typescript
1399
- * protected async customizeConfig(config: any, payload: IGraphRequestPayload): Promise<any> {
1400
- * // Add custom fields
1401
- * config.configurable.myCustomField = "value";
1402
- *
1403
- * // Modify existing fields
1404
- * config.configurable.context.customData = await this.loadCustomData(payload);
1405
- *
1406
- * return config;
1342
+ * protected async customizeConfig(payload: IGraphRequestPayload): Promise<any> {
1343
+ * // Add custom fields to config
1344
+ * return {
1345
+ * ...payload,
1346
+ * config: {
1347
+ * ...payload.config,
1348
+ * configurable: {
1349
+ * ...payload.config.configurable,
1350
+ * myCustomField: "value",
1351
+ * },
1352
+ * },
1353
+ * };
1407
1354
  * }
1408
1355
  * ```
1409
1356
  */
1410
- async customizeConfig(config, payload) {
1411
- return config;
1357
+ async customizeConfig(payload) {
1358
+ return payload;
1412
1359
  }
1413
1360
  /**
1414
1361
  * Load graph manifest (if using manifest-based approach)
@@ -1564,9 +1511,15 @@ exports.UniversalGraphService = class UniversalGraphService {
1564
1511
  * Generate answer without streaming
1565
1512
  */
1566
1513
  async generateAnswer(payload) {
1567
- const builder = this.getBuilderForType(payload.graphType);
1514
+ const graphType = payload.config?.configurable?.graphSettings?.graphType;
1515
+ if (!graphType) {
1516
+ throw new Error(
1517
+ "GraphType is required in payload.config.configurable.graphSettings"
1518
+ );
1519
+ }
1520
+ const builder = this.getBuilderForType(graphType);
1568
1521
  const graph = await builder.buildGraph(payload);
1569
- const config = await builder.prepareConfig(payload);
1522
+ const config = await builder.preparePayload(payload);
1570
1523
  const abortController = new AbortController();
1571
1524
  this.registerActiveGeneration(payload.requestId, () => {
1572
1525
  abortController.abort();
@@ -1598,13 +1551,16 @@ exports.UniversalGraphService = class UniversalGraphService {
1598
1551
  );
1599
1552
  const abortController = new AbortController();
1600
1553
  try {
1601
- const builder = this.getBuilderForType(payload.graphType);
1602
- this.logger.debug(`Got builder for graph type: ${payload.graphType}`);
1554
+ const graphType = payload.config?.configurable?.graphSettings?.graphType;
1555
+ if (!graphType) {
1556
+ throw new Error(
1557
+ "GraphType is required in payload.config.configurable.graphSettings"
1558
+ );
1559
+ }
1560
+ const builder = this.getBuilderForType(graphType);
1561
+ this.logger.debug(`Got builder for graph type: ${graphType}`);
1603
1562
  const graph = await builder.buildGraph(payload);
1604
- this.logger.debug(`Graph built for requestId: ${payload.requestId}`);
1605
- this.logger.debug(`Preparing config for requestId: ${payload.requestId}`);
1606
- const config = await builder.prepareConfig(payload);
1607
- this.logger.debug(`Config prepared`);
1563
+ const graphRequest = await builder.preparePayload(payload);
1608
1564
  this.registerActiveGeneration(payload.requestId, () => {
1609
1565
  abortController.abort();
1610
1566
  });
@@ -1614,7 +1570,7 @@ exports.UniversalGraphService = class UniversalGraphService {
1614
1570
  );
1615
1571
  const result = await this.engine.streamGraph(
1616
1572
  graph,
1617
- config,
1573
+ graphRequest,
1618
1574
  onPartial,
1619
1575
  abortController.signal
1620
1576
  );
@@ -5005,7 +4961,6 @@ exports.EventProcessor = class EventProcessor {
5005
4961
  exports.EventProcessor = __decorateClass([
5006
4962
  common.Injectable()
5007
4963
  ], exports.EventProcessor);
5008
- var DEFAULT_RECURSION_LIMIT = 40;
5009
4964
  process.setMaxListeners(0);
5010
4965
  exports.LangGraphEngine = class LangGraphEngine {
5011
4966
  constructor(eventProcessor, configService) {
@@ -5016,34 +4971,80 @@ exports.LangGraphEngine = class LangGraphEngine {
5016
4971
  }
5017
4972
  }
5018
4973
  logger = new common.Logger(exports.LangGraphEngine.name);
4974
+ /**
4975
+ * Deserialize input recursively
4976
+ * Handles serialized LangChain objects at any level of nesting
4977
+ */
4978
+ async deserializeInput(input) {
4979
+ const { load } = await import('@langchain/core/load');
4980
+ const deserializeValue = async (value) => {
4981
+ if (value && typeof value === "object" && "lc" in value) {
4982
+ try {
4983
+ const deserialized = await load(JSON.stringify(value));
4984
+ this.logger.debug({
4985
+ message: "Deserialized LangChain object",
4986
+ type: deserialized.constructor?.name
4987
+ });
4988
+ return deserialized;
4989
+ } catch (error) {
4990
+ this.logger.warn({
4991
+ message: "Failed to deserialize LangChain object",
4992
+ error: error.message
4993
+ });
4994
+ return value;
4995
+ }
4996
+ }
4997
+ if (Array.isArray(value)) {
4998
+ return await Promise.all(value.map((item) => deserializeValue(item)));
4999
+ }
5000
+ if (value && typeof value === "object" && value.constructor === Object) {
5001
+ const result = {};
5002
+ for (const [key, val] of Object.entries(value)) {
5003
+ result[key] = await deserializeValue(val);
5004
+ }
5005
+ return result;
5006
+ }
5007
+ return value;
5008
+ };
5009
+ return await deserializeValue(input);
5010
+ }
5019
5011
  /**
5020
5012
  * Method to invoke LangGraph
5021
5013
  */
5022
- async invokeGraph(graph, config, signal) {
5014
+ async invokeGraph(graph, preparedPayload, signal) {
5015
+ this.logger.debug("invokeGraph preparedPayload", preparedPayload);
5023
5016
  if (signal) {
5024
- config.signal = signal;
5017
+ preparedPayload.signal = signal;
5018
+ this.logger.debug("[ENGINE] Signal assigned to preparedPayload.signal");
5025
5019
  }
5026
- const recursionLimit = config.recursionLimit ?? DEFAULT_RECURSION_LIMIT;
5027
- const result = await graph.invoke(config.input || {}, {
5028
- ...config,
5029
- recursionLimit
5020
+ const input = await this.deserializeInput(preparedPayload.input || {});
5021
+ const result = await graph.invoke(input, {
5022
+ ...preparedPayload.config,
5023
+ signal: preparedPayload.signal
5030
5024
  });
5031
5025
  return this.processGraphResult(result);
5032
5026
  }
5033
- async streamGraph(graph, config, onPartial, signal) {
5027
+ async streamGraph(graph, preparedPayload, onPartial, signal) {
5034
5028
  const acc = this.eventProcessor.createAccumulator();
5035
5029
  let streamError = null;
5030
+ this.logger.debug({
5031
+ message: "[ENGINE] streamGraph called",
5032
+ hasSignal: !!signal,
5033
+ signalType: signal?.constructor?.name,
5034
+ hasAborted: signal?.aborted
5035
+ });
5036
5036
  try {
5037
5037
  if (signal) {
5038
- config.signal = signal;
5039
- }
5040
- const recursionLimit = config.recursionLimit ?? DEFAULT_RECURSION_LIMIT;
5041
- const eventStream = await graph.streamEvents(config.input || {}, {
5042
- ...config,
5043
- version: "v2",
5038
+ preparedPayload.signal = signal;
5039
+ this.logger.debug("[ENGINE] Signal assigned to preparedPayload.signal");
5040
+ }
5041
+ const input = await this.deserializeInput(preparedPayload.input || {});
5042
+ const eventStream = await graph.streamEvents(input, {
5043
+ ...preparedPayload.config,
5044
+ signal: preparedPayload.signal,
5045
+ // Include abort signal
5046
+ version: "v2"
5044
5047
  // Important for correct operation
5045
- recursionLimit
5046
- // Prevent GraphRecursionError (default is 25)
5047
5048
  });
5048
5049
  for await (const event of eventStream) {
5049
5050
  try {
@@ -5061,12 +5062,12 @@ exports.LangGraphEngine = class LangGraphEngine {
5061
5062
  );
5062
5063
  this.logger.error(`[STREAM-ERROR] Stack trace: ${streamError.stack}`);
5063
5064
  } finally {
5064
- await this.sendTraceFromAccumulator(acc, config, streamError);
5065
+ await this.sendTraceFromAccumulator(acc, preparedPayload, streamError);
5065
5066
  }
5066
5067
  const { content, trace } = this.eventProcessor.getResult(acc);
5067
5068
  this.logger.debug("[STREAM-RESULT] Got result from EventProcessor", {
5068
5069
  hasContent: !!content,
5069
- hasContext: !!config.configurable?.context,
5070
+ hasContext: !!preparedPayload.configurable?.context,
5070
5071
  hasTrace: !!trace,
5071
5072
  traceEvents: trace?.events?.length || 0,
5072
5073
  hadError: !!streamError
@@ -5279,9 +5280,11 @@ function createMetaBuilder(config, versionedGraphService, moduleRef) {
5279
5280
  return config.baseGraphType;
5280
5281
  }
5281
5282
  async buildGraph(payload) {
5282
- const graphType = payload.graphSettings?.graphType;
5283
+ const graphType = payload.config?.configurable?.graphSettings?.graphType;
5283
5284
  if (!graphType) {
5284
- throw new Error("GraphType is required in payload.graphSettings");
5285
+ throw new Error(
5286
+ "GraphType is required in payload.config.configurable.graphSettings"
5287
+ );
5285
5288
  }
5286
5289
  const resolution = await versionedGraphService.resolveVersion(graphType, {
5287
5290
  strict: false
@@ -5298,10 +5301,12 @@ function createMetaBuilder(config, versionedGraphService, moduleRef) {
5298
5301
  return versionedBuilder.buildGraph(payload);
5299
5302
  }
5300
5303
  }
5301
- async prepareConfig(payload) {
5302
- const graphType = payload.graphSettings?.graphType;
5304
+ async preparePayload(payload) {
5305
+ const graphType = payload.config?.configurable?.graphSettings?.graphType;
5303
5306
  if (!graphType) {
5304
- throw new Error("GraphType is required in payload.graphSettings");
5307
+ throw new Error(
5308
+ "GraphType is required in payload.config.configurable.graphSettings"
5309
+ );
5305
5310
  }
5306
5311
  const resolution = await versionedGraphService.resolveVersion(graphType, {
5307
5312
  strict: false
@@ -5316,12 +5321,18 @@ function createMetaBuilder(config, versionedGraphService, moduleRef) {
5316
5321
  }
5317
5322
  const updatedPayload = {
5318
5323
  ...payload,
5319
- graphSettings: {
5320
- ...payload.graphSettings,
5321
- graphType: resolution.fullGraphType
5324
+ config: {
5325
+ ...payload.config,
5326
+ configurable: {
5327
+ ...payload.config.configurable,
5328
+ graphSettings: {
5329
+ ...payload.config.configurable.graphSettings,
5330
+ graphType: resolution.fullGraphType
5331
+ }
5332
+ }
5322
5333
  }
5323
5334
  };
5324
- return versionedBuilder.prepareConfig(updatedPayload);
5335
+ return versionedBuilder.preparePayload(updatedPayload);
5325
5336
  }
5326
5337
  }
5327
5338
  Object.defineProperty(VersionRouter, "name", { value: className });
@@ -5555,7 +5566,7 @@ exports.UniversalGraphModule = class UniversalGraphModule {
5555
5566
  "ModuleRef not available - cannot build graph"
5556
5567
  );
5557
5568
  }
5558
- async prepareConfig(payload) {
5569
+ async preparePayload(payload) {
5559
5570
  throw new Error(
5560
5571
  "ModuleRef not available - cannot prepare config"
5561
5572
  );