@flutchai/flutch-sdk 0.1.5 → 0.1.7

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
@@ -3,7 +3,9 @@
3
3
  require('reflect-metadata');
4
4
  var common = require('@nestjs/common');
5
5
  var swagger = require('@nestjs/swagger');
6
- var path = require('path');
6
+ var fs = require('fs');
7
+ var path2 = require('path');
8
+ var os = require('os');
7
9
  var crypto = require('crypto');
8
10
  var promClient = require('prom-client');
9
11
  var core = require('@nestjs/core');
@@ -40,7 +42,9 @@ function _interopNamespace(e) {
40
42
  return Object.freeze(n);
41
43
  }
42
44
 
43
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
45
+ var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
46
+ var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
47
+ var os__namespace = /*#__PURE__*/_interopNamespace(os);
44
48
  var net__namespace = /*#__PURE__*/_interopNamespace(net);
45
49
  var LangGraph__namespace = /*#__PURE__*/_interopNamespace(LangGraph);
46
50
  var axios2__default = /*#__PURE__*/_interopDefault(axios2);
@@ -459,12 +463,21 @@ var init_ui_endpoints_discovery = __esm({
459
463
  this.endpointRegistry = endpointRegistry;
460
464
  }
461
465
  logger = new common.Logger(exports.UIEndpointsDiscoveryService.name);
466
+ async onModuleInit() {
467
+ await this.discoverUIEndpoints();
468
+ }
462
469
  /**
463
470
  * Discover and register all UI endpoint classes
464
471
  * Called automatically during module initialization
465
472
  */
466
473
  async discoverUIEndpoints() {
467
474
  this.logger.log("Starting UI endpoints discovery...");
475
+ if (!this.discoveryService) {
476
+ this.logger.warn(
477
+ "DiscoveryService not available, skipping UI endpoints discovery"
478
+ );
479
+ return;
480
+ }
468
481
  const providers = this.discoveryService.getProviders();
469
482
  let registeredCount = 0;
470
483
  let totalEndpoints = 0;
@@ -516,7 +529,9 @@ var init_ui_endpoints_discovery = __esm({
516
529
  }
517
530
  };
518
531
  exports.UIEndpointsDiscoveryService = __decorateClass([
519
- common.Injectable()
532
+ common.Injectable(),
533
+ __decorateParam(0, common.Optional()),
534
+ __decorateParam(1, common.Optional())
520
535
  ], exports.UIEndpointsDiscoveryService);
521
536
  }
522
537
  });
@@ -711,6 +726,523 @@ var init_agent_ui = __esm({
711
726
  init_ui_dispatch_controller();
712
727
  }
713
728
  });
729
+
730
+ // src/service-discovery/file-based.discovery.ts
731
+ var file_based_discovery_exports = {};
732
+ __export(file_based_discovery_exports, {
733
+ FileBasedDiscovery: () => exports.FileBasedDiscovery
734
+ });
735
+ exports.FileBasedDiscovery = void 0;
736
+ var init_file_based_discovery = __esm({
737
+ "src/service-discovery/file-based.discovery.ts"() {
738
+ exports.FileBasedDiscovery = class {
739
+ logger = new common.Logger(exports.FileBasedDiscovery.name);
740
+ servicesDir;
741
+ constructor() {
742
+ this.servicesDir = path2__namespace.join(os__namespace.homedir(), ".flutch", "services");
743
+ this.ensureServicesDirectory();
744
+ this.cleanupStaleServices();
745
+ }
746
+ /**
747
+ * Register service
748
+ */
749
+ async registerService(name, address, port, metadata, graphTypes = []) {
750
+ const registration = {
751
+ name,
752
+ address,
753
+ port,
754
+ metadata,
755
+ pid: process.pid,
756
+ timestamp: Date.now(),
757
+ graphTypes
758
+ };
759
+ const serviceFile = path2__namespace.join(
760
+ this.servicesDir,
761
+ `${name}-${process.pid}.json`
762
+ );
763
+ try {
764
+ await fs__namespace.promises.writeFile(
765
+ serviceFile,
766
+ JSON.stringify(registration, null, 2)
767
+ );
768
+ this.logger.log(`Registered service: ${name} at ${address}:${port}`);
769
+ process.on("exit", () => this.unregisterService(name));
770
+ process.on("SIGINT", () => {
771
+ this.unregisterService(name);
772
+ process.exit(0);
773
+ });
774
+ process.on("SIGTERM", () => {
775
+ this.unregisterService(name);
776
+ process.exit(0);
777
+ });
778
+ } catch (error) {
779
+ this.logger.error(`Failed to register service ${name}: ${error.message}`);
780
+ }
781
+ }
782
+ /**
783
+ * Unregister service
784
+ */
785
+ async unregisterService(name) {
786
+ const serviceFile = path2__namespace.join(
787
+ this.servicesDir,
788
+ `${name}-${process.pid}.json`
789
+ );
790
+ try {
791
+ if (fs__namespace.existsSync(serviceFile)) {
792
+ await fs__namespace.promises.unlink(serviceFile);
793
+ this.logger.log(`Unregistered service: ${name}`);
794
+ }
795
+ } catch (error) {
796
+ this.logger.error(
797
+ `Failed to unregister service ${name}: ${error.message}`
798
+ );
799
+ }
800
+ }
801
+ /**
802
+ * Get list of services by graph type
803
+ */
804
+ async getServices(graphType) {
805
+ try {
806
+ const files = await fs__namespace.promises.readdir(this.servicesDir);
807
+ const services = [];
808
+ for (const file of files) {
809
+ if (!file.endsWith(".json")) continue;
810
+ try {
811
+ const serviceFile = path2__namespace.join(this.servicesDir, file);
812
+ const content = await fs__namespace.promises.readFile(serviceFile, "utf-8");
813
+ const registration = JSON.parse(content);
814
+ if (!this.isProcessAlive(registration.pid)) {
815
+ await fs__namespace.promises.unlink(serviceFile);
816
+ continue;
817
+ }
818
+ if (registration.graphTypes.includes(graphType) || registration.metadata.graphTypes?.includes(graphType)) {
819
+ services.push({
820
+ name: registration.name,
821
+ address: registration.address,
822
+ port: registration.port,
823
+ metadata: registration.metadata
824
+ });
825
+ }
826
+ } catch (error) {
827
+ this.logger.warn(
828
+ `Failed to parse service file ${file}: ${error.message}`
829
+ );
830
+ }
831
+ }
832
+ return services;
833
+ } catch (error) {
834
+ this.logger.error(`Failed to get services: ${error.message}`);
835
+ return [];
836
+ }
837
+ }
838
+ /**
839
+ * Find service by name
840
+ */
841
+ async findServiceByName(serviceName) {
842
+ try {
843
+ const files = await fs__namespace.promises.readdir(this.servicesDir);
844
+ for (const file of files) {
845
+ if (!file.endsWith(".json")) continue;
846
+ try {
847
+ const serviceFile = path2__namespace.join(this.servicesDir, file);
848
+ const content = await fs__namespace.promises.readFile(serviceFile, "utf-8");
849
+ const registration = JSON.parse(content);
850
+ if (registration.name === serviceName && this.isProcessAlive(registration.pid)) {
851
+ return {
852
+ name: registration.name,
853
+ address: registration.address,
854
+ port: registration.port,
855
+ metadata: registration.metadata
856
+ };
857
+ }
858
+ } catch (error) {
859
+ this.logger.warn(
860
+ `Failed to parse service file ${file}: ${error.message}`
861
+ );
862
+ }
863
+ }
864
+ return null;
865
+ } catch (error) {
866
+ this.logger.error(
867
+ `Failed to find service ${serviceName}: ${error.message}`
868
+ );
869
+ return null;
870
+ }
871
+ }
872
+ /**
873
+ * Ensure services directory exists
874
+ */
875
+ ensureServicesDirectory() {
876
+ try {
877
+ const amelieDir = path2__namespace.join(os__namespace.homedir(), ".flutch");
878
+ if (!fs__namespace.existsSync(amelieDir)) {
879
+ fs__namespace.mkdirSync(amelieDir, { recursive: true });
880
+ }
881
+ if (!fs__namespace.existsSync(this.servicesDir)) {
882
+ fs__namespace.mkdirSync(this.servicesDir, { recursive: true });
883
+ }
884
+ } catch (error) {
885
+ this.logger.error(
886
+ `Failed to create services directory: ${error.message}`
887
+ );
888
+ }
889
+ }
890
+ /**
891
+ * Cleanup stale services
892
+ */
893
+ async cleanupStaleServices() {
894
+ try {
895
+ const files = await fs__namespace.promises.readdir(this.servicesDir);
896
+ for (const file of files) {
897
+ if (!file.endsWith(".json")) continue;
898
+ try {
899
+ const serviceFile = path2__namespace.join(this.servicesDir, file);
900
+ const content = await fs__namespace.promises.readFile(serviceFile, "utf-8");
901
+ const registration = JSON.parse(content);
902
+ if (!this.isProcessAlive(registration.pid)) {
903
+ await fs__namespace.promises.unlink(serviceFile);
904
+ this.logger.debug(`Cleaned up stale service: ${registration.name}`);
905
+ }
906
+ } catch (error) {
907
+ try {
908
+ await fs__namespace.promises.unlink(path2__namespace.join(this.servicesDir, file));
909
+ } catch {
910
+ }
911
+ }
912
+ }
913
+ } catch (error) {
914
+ this.logger.error(`Failed to cleanup stale services: ${error.message}`);
915
+ }
916
+ }
917
+ /**
918
+ * Check if process is still alive
919
+ */
920
+ isProcessAlive(pid) {
921
+ try {
922
+ process.kill(pid, 0);
923
+ return true;
924
+ } catch (error) {
925
+ return false;
926
+ }
927
+ }
928
+ };
929
+ exports.FileBasedDiscovery = __decorateClass([
930
+ common.Injectable()
931
+ ], exports.FileBasedDiscovery);
932
+ }
933
+ });
934
+
935
+ // src/core/builder-registry.service.ts
936
+ var builder_registry_service_exports = {};
937
+ __export(builder_registry_service_exports, {
938
+ BuilderRegistryService: () => exports.BuilderRegistryService
939
+ });
940
+ exports.BuilderRegistryService = void 0;
941
+ var init_builder_registry_service = __esm({
942
+ "src/core/builder-registry.service.ts"() {
943
+ exports.BuilderRegistryService = class {
944
+ builders = [];
945
+ registerBuilder(builder) {
946
+ const existingBuilder = this.builders.find(
947
+ (b) => b.graphType === builder.graphType
948
+ );
949
+ if (!existingBuilder) {
950
+ this.builders.push(builder);
951
+ }
952
+ }
953
+ getBuilders() {
954
+ return this.builders;
955
+ }
956
+ };
957
+ exports.BuilderRegistryService = __decorateClass([
958
+ common.Injectable()
959
+ ], exports.BuilderRegistryService);
960
+ }
961
+ });
962
+
963
+ // src/utils/graph-type.utils.ts
964
+ exports.GraphTypeUtils = void 0;
965
+ var init_graph_type_utils = __esm({
966
+ "src/utils/graph-type.utils.ts"() {
967
+ exports.GraphTypeUtils = class {
968
+ /**
969
+ * Parse full graph type
970
+ * @param fullType - full graph type
971
+ * @returns object with type components
972
+ */
973
+ static parse(fullType) {
974
+ if (fullType.includes("::")) {
975
+ const [baseType, version] = fullType.split("::");
976
+ const [companyId, name] = baseType.split(".");
977
+ return { companyId, name, version };
978
+ }
979
+ const parts = fullType.split(".");
980
+ if (parts.length === 1) {
981
+ return { companyId: "global", name: parts[0] };
982
+ }
983
+ return { companyId: parts[0], name: parts[1] };
984
+ }
985
+ /**
986
+ * Build full type from components
987
+ * @param companyId - company ID
988
+ * @param name - graph name
989
+ * @param version - version (optional)
990
+ * @returns full graph type
991
+ */
992
+ static build(companyId, name, version) {
993
+ const base = `${companyId}.${name}`;
994
+ return version ? `${base}::${version}` : base;
995
+ }
996
+ /**
997
+ * Normalize graph type for backward compatibility
998
+ * @param graphType - graph type in any format
999
+ * @returns normalized type
1000
+ */
1001
+ static normalize(graphType) {
1002
+ const { companyId, name, version } = this.parse(graphType);
1003
+ return this.build(companyId, name, version);
1004
+ }
1005
+ /**
1006
+ * Get base type without version
1007
+ * @param graphType - full graph type
1008
+ * @returns base type
1009
+ */
1010
+ static getBaseType(graphType) {
1011
+ if (graphType.includes("::")) {
1012
+ return graphType.split("::")[0];
1013
+ }
1014
+ const { companyId, name } = this.parse(graphType);
1015
+ return `${companyId}.${name}`;
1016
+ }
1017
+ /**
1018
+ * Extract version from graph type
1019
+ * @param graphType - full graph type
1020
+ * @returns version or undefined
1021
+ */
1022
+ static getVersion(graphType) {
1023
+ return graphType.includes("::") ? graphType.split("::")[1] : void 0;
1024
+ }
1025
+ /**
1026
+ * Validate version (basic semver check)
1027
+ * @param version - version to check
1028
+ * @returns true if version is valid
1029
+ */
1030
+ static isValidVersion(version) {
1031
+ const semverRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/;
1032
+ return semverRegex.test(version);
1033
+ }
1034
+ /**
1035
+ * Check if type is system (global)
1036
+ * @param graphType - graph type
1037
+ * @returns true if graph is system
1038
+ */
1039
+ static isSystemGraph(graphType) {
1040
+ const { companyId } = this.parse(graphType);
1041
+ return companyId === "global";
1042
+ }
1043
+ /**
1044
+ * Compare versions (simple comparison for sorting)
1045
+ * @param a - first version
1046
+ * @param b - second version
1047
+ * @returns -1, 0, 1 for sorting
1048
+ */
1049
+ static compareVersions(a, b) {
1050
+ const parseVersion = (v) => {
1051
+ const [main, prerelease] = v.split("-");
1052
+ const [major, minor, patch] = main.split(".").map(Number);
1053
+ return { major, minor, patch, prerelease };
1054
+ };
1055
+ const versionA = parseVersion(a);
1056
+ const versionB = parseVersion(b);
1057
+ if (versionA.major !== versionB.major) {
1058
+ return versionA.major - versionB.major;
1059
+ }
1060
+ if (versionA.minor !== versionB.minor) {
1061
+ return versionA.minor - versionB.minor;
1062
+ }
1063
+ if (versionA.patch !== versionB.patch) {
1064
+ return versionA.patch - versionB.patch;
1065
+ }
1066
+ if (versionA.prerelease && !versionB.prerelease) return -1;
1067
+ if (!versionA.prerelease && versionB.prerelease) return 1;
1068
+ if (versionA.prerelease && versionB.prerelease) {
1069
+ return versionA.prerelease.localeCompare(versionB.prerelease);
1070
+ }
1071
+ return 0;
1072
+ }
1073
+ };
1074
+ }
1075
+ });
1076
+
1077
+ // src/graph/versioning/versioned-graph.service.ts
1078
+ var versioned_graph_service_exports = {};
1079
+ __export(versioned_graph_service_exports, {
1080
+ VersionedGraphService: () => exports.VersionedGraphService
1081
+ });
1082
+ exports.VersionedGraphService = void 0;
1083
+ var init_versioned_graph_service = __esm({
1084
+ "src/graph/versioning/versioned-graph.service.ts"() {
1085
+ init_graph_type_utils();
1086
+ exports.VersionedGraphService = class {
1087
+ logger = new common.Logger(exports.VersionedGraphService.name);
1088
+ versionConfigs = /* @__PURE__ */ new Map();
1089
+ constructor() {
1090
+ }
1091
+ /**
1092
+ * Register versioning configuration
1093
+ */
1094
+ registerVersioning(config) {
1095
+ this.versionConfigs.set(config.baseGraphType, config);
1096
+ this.logger.log(
1097
+ `Registered versioning for ${config.baseGraphType} with ${config.versions.length} versions`
1098
+ );
1099
+ }
1100
+ /**
1101
+ * Resolve graph version
1102
+ */
1103
+ async resolveVersion(graphType, options = {}) {
1104
+ const parsed = exports.GraphTypeUtils.parse(graphType);
1105
+ const baseType = exports.GraphTypeUtils.getBaseType(graphType);
1106
+ const requestedVersion = exports.GraphTypeUtils.getVersion(graphType) || options.requestedVersion;
1107
+ const config = this.versionConfigs.get(baseType);
1108
+ if (!config) {
1109
+ throw new Error(`No versioning configuration found for ${baseType}`);
1110
+ }
1111
+ const route = this.findBestVersionRoute(config, requestedVersion, options);
1112
+ if (!route) {
1113
+ throw new Error(
1114
+ `No compatible version found for ${graphType} with options: ${JSON.stringify(options)}`
1115
+ );
1116
+ }
1117
+ const fullGraphType = exports.GraphTypeUtils.build(
1118
+ parsed.companyId,
1119
+ parsed.name,
1120
+ route.version
1121
+ );
1122
+ return {
1123
+ version: route.version,
1124
+ builderClass: route.builderClass,
1125
+ fullGraphType
1126
+ };
1127
+ }
1128
+ /**
1129
+ * Create builder for specified version
1130
+ */
1131
+ async createVersionedBuilder(graphType, moduleRef, options = {}) {
1132
+ const resolution = await this.resolveVersion(graphType, options);
1133
+ try {
1134
+ if (!moduleRef) {
1135
+ throw new Error(
1136
+ "ModuleRef is not available - falling back to direct instantiation"
1137
+ );
1138
+ }
1139
+ const builder = await moduleRef.create(resolution.builderClass);
1140
+ this.logger.debug(
1141
+ `Created versioned builder for ${resolution.fullGraphType}`
1142
+ );
1143
+ return builder;
1144
+ } catch (error) {
1145
+ this.logger.error(
1146
+ `Failed to create builder for ${resolution.fullGraphType}: ${error.message}`
1147
+ );
1148
+ throw new Error(`Failed to create versioned builder: ${error.message}`);
1149
+ }
1150
+ }
1151
+ /**
1152
+ * Get all available versions for a graph
1153
+ */
1154
+ getAvailableVersions(baseGraphType) {
1155
+ const config = this.versionConfigs.get(baseGraphType);
1156
+ if (!config) {
1157
+ return [];
1158
+ }
1159
+ return config.versions.map((route) => route.version).sort((a, b) => exports.GraphTypeUtils.compareVersions(b, a));
1160
+ }
1161
+ /**
1162
+ * Check version support
1163
+ */
1164
+ isVersionSupported(graphType, options = {}) {
1165
+ try {
1166
+ const baseType = exports.GraphTypeUtils.getBaseType(graphType);
1167
+ const requestedVersion = exports.GraphTypeUtils.getVersion(graphType);
1168
+ const config = this.versionConfigs.get(baseType);
1169
+ if (!config) {
1170
+ return false;
1171
+ }
1172
+ const route = this.findBestVersionRoute(
1173
+ config,
1174
+ requestedVersion,
1175
+ options
1176
+ );
1177
+ return route !== null;
1178
+ } catch {
1179
+ return false;
1180
+ }
1181
+ }
1182
+ /**
1183
+ * Find best version
1184
+ */
1185
+ findBestVersionRoute(config, requestedVersion, options = {}) {
1186
+ const { strict = false } = options;
1187
+ let candidates = [...config.versions];
1188
+ if (requestedVersion) {
1189
+ const exactMatch = candidates.find(
1190
+ (route) => route.version === requestedVersion
1191
+ );
1192
+ if (exactMatch) {
1193
+ return exactMatch;
1194
+ }
1195
+ if (strict) {
1196
+ return null;
1197
+ }
1198
+ const compatibleVersions = candidates.filter(
1199
+ (route) => this.isVersionCompatible(requestedVersion, route.version)
1200
+ );
1201
+ if (compatibleVersions.length > 0) {
1202
+ return compatibleVersions.sort(
1203
+ (a, b) => exports.GraphTypeUtils.compareVersions(b.version, a.version)
1204
+ )[0];
1205
+ }
1206
+ }
1207
+ const defaultRoute = candidates.find((route) => route.isDefault);
1208
+ if (defaultRoute) {
1209
+ return defaultRoute;
1210
+ }
1211
+ if (config.defaultVersionStrategy === "latest" || !config.defaultVersionStrategy) {
1212
+ const sortedVersions = candidates.sort(
1213
+ (a, b) => exports.GraphTypeUtils.compareVersions(b.version, a.version)
1214
+ );
1215
+ return sortedVersions[0] || null;
1216
+ }
1217
+ return null;
1218
+ }
1219
+ /**
1220
+ * Check version compatibility (simplified semantics)
1221
+ */
1222
+ isVersionCompatible(requested, available) {
1223
+ try {
1224
+ const requestedParts = requested.split(".").map(Number);
1225
+ const availableParts = available.split(".").map(Number);
1226
+ if (requestedParts[0] !== availableParts[0]) {
1227
+ return false;
1228
+ }
1229
+ return exports.GraphTypeUtils.compareVersions(available, requested) >= 0;
1230
+ } catch {
1231
+ return false;
1232
+ }
1233
+ }
1234
+ /**
1235
+ * Get versioning configuration information
1236
+ */
1237
+ getVersioningInfo(baseGraphType) {
1238
+ return this.versionConfigs.get(baseGraphType) || null;
1239
+ }
1240
+ };
1241
+ exports.VersionedGraphService = __decorateClass([
1242
+ common.Injectable()
1243
+ ], exports.VersionedGraphService);
1244
+ }
1245
+ });
714
1246
  var CallbackStore = class {
715
1247
  constructor(redis) {
716
1248
  this.redis = redis;
@@ -2552,7 +3084,7 @@ var _AbstractGraphBuilder = class _AbstractGraphBuilder {
2552
3084
  /**
2553
3085
  * Path to root graph manifest (defaults to graph.manifest.json in root)
2554
3086
  */
2555
- manifestPath = path__namespace.join(
3087
+ manifestPath = path2__namespace.join(
2556
3088
  process.cwd(),
2557
3089
  "graph.manifest.json"
2558
3090
  );
@@ -2632,10 +3164,10 @@ var _AbstractGraphBuilder = class _AbstractGraphBuilder {
2632
3164
  return null;
2633
3165
  }
2634
3166
  try {
2635
- const fs = await import('fs/promises');
2636
- const path2 = await import('path');
2637
- const manifestFullPath = path2.resolve(this.manifestPath);
2638
- const manifestContent = await fs.readFile(manifestFullPath, "utf-8");
3167
+ const fs2 = await import('fs/promises');
3168
+ const path3 = await import('path');
3169
+ const manifestFullPath = path3.resolve(this.manifestPath);
3170
+ const manifestContent = await fs2.readFile(manifestFullPath, "utf-8");
2639
3171
  const manifest = JSON.parse(manifestContent);
2640
3172
  this.manifest = manifest;
2641
3173
  return manifest;
@@ -2654,10 +3186,10 @@ var _AbstractGraphBuilder = class _AbstractGraphBuilder {
2654
3186
  return null;
2655
3187
  }
2656
3188
  try {
2657
- const fs = __require("fs");
2658
- const path2 = __require("path");
2659
- const manifestFullPath = path2.resolve(this.manifestPath);
2660
- const manifestContent = fs.readFileSync(manifestFullPath, "utf-8");
3189
+ const fs2 = __require("fs");
3190
+ const path3 = __require("path");
3191
+ const manifestFullPath = path3.resolve(this.manifestPath);
3192
+ const manifestContent = fs2.readFileSync(manifestFullPath, "utf-8");
2661
3193
  const manifest = JSON.parse(manifestContent);
2662
3194
  this.manifest = manifest;
2663
3195
  return manifest;
@@ -2697,12 +3229,12 @@ var _AbstractGraphBuilder = class _AbstractGraphBuilder {
2697
3229
  let configSchema = null;
2698
3230
  if (versionConfig.configSchemaPath) {
2699
3231
  try {
2700
- const fs = await import('fs/promises');
2701
- const schemaPath = path__namespace.resolve(
3232
+ const fs2 = await import('fs/promises');
3233
+ const schemaPath = path2__namespace.resolve(
2702
3234
  process.cwd(),
2703
3235
  versionConfig.configSchemaPath
2704
3236
  );
2705
- const schemaContent = await fs.readFile(schemaPath, "utf-8");
3237
+ const schemaContent = await fs2.readFile(schemaPath, "utf-8");
2706
3238
  const schemaData = JSON.parse(schemaContent);
2707
3239
  configSchema = schemaData.schema;
2708
3240
  } catch (error) {
@@ -3167,6 +3699,20 @@ exports.UniversalGraphService = __decorateClass([
3167
3699
  __decorateParam(2, common.Inject("GRAPH_ENGINE")),
3168
3700
  __decorateParam(3, common.Inject(exports.EndpointRegistry))
3169
3701
  ], exports.UniversalGraphService);
3702
+ function setupRedisMock() {
3703
+ if (process.env.NODE_ENV === "development" && !process.env.KUBERNETES_SERVICE_HOST) {
3704
+ console.log("[REDIS_MOCK] Intercepting ioredis requires for development");
3705
+ const Module2 = __require("module");
3706
+ const originalRequire = Module2.prototype.require;
3707
+ Module2.prototype.require = function(...args) {
3708
+ if (args[0] === "ioredis") {
3709
+ console.log("[REDIS_MOCK] Redirecting ioredis to ioredis-mock");
3710
+ return originalRequire.apply(this, ["ioredis-mock"]);
3711
+ }
3712
+ return originalRequire.apply(this, args);
3713
+ };
3714
+ }
3715
+ }
3170
3716
  async function isPortAvailable(port) {
3171
3717
  return new Promise((resolve2) => {
3172
3718
  const server = net__namespace.createServer();
@@ -3188,10 +3734,110 @@ async function findAvailablePort(startPort) {
3188
3734
  `No available ports found in range ${startPort}-${startPort + 99}`
3189
3735
  );
3190
3736
  }
3737
+ async function registerWithServiceDiscovery(AppModule, port, logger2, app) {
3738
+ try {
3739
+ logger2.debug(
3740
+ "[SERVICE_DISCOVERY] Starting service discovery registration..."
3741
+ );
3742
+ const { FileBasedDiscovery: FileBasedDiscovery2 } = await Promise.resolve().then(() => (init_file_based_discovery(), file_based_discovery_exports));
3743
+ logger2.debug(
3744
+ "[SERVICE_DISCOVERY] FileBasedDiscovery imported successfully"
3745
+ );
3746
+ const discovery = new FileBasedDiscovery2();
3747
+ logger2.debug("[SERVICE_DISCOVERY] FileBasedDiscovery instance created");
3748
+ const serviceName = AppModule.name.replace("Module", "").toLowerCase();
3749
+ let graphTypes = [];
3750
+ try {
3751
+ if (app) {
3752
+ const { BuilderRegistryService: BuilderRegistryService2 } = await Promise.resolve().then(() => (init_builder_registry_service(), builder_registry_service_exports));
3753
+ const builderRegistry = app.get(BuilderRegistryService2, {
3754
+ strict: false
3755
+ });
3756
+ logger2.debug(
3757
+ `BuilderRegistryService found in DI: ${!!builderRegistry}`
3758
+ );
3759
+ if (builderRegistry) {
3760
+ const builders = builderRegistry.getBuilders();
3761
+ logger2.debug(`Found ${builders.length} builders in registry`);
3762
+ const baseGraphTypes = builders.map((builder) => builder.graphType);
3763
+ logger2.debug(`Base graph types: [${baseGraphTypes.join(", ")}]`);
3764
+ try {
3765
+ logger2.debug("Attempting to import VersionedGraphService...");
3766
+ const { VersionedGraphService: VersionedGraphService2 } = await Promise.resolve().then(() => (init_versioned_graph_service(), versioned_graph_service_exports));
3767
+ logger2.debug("VersionedGraphService imported successfully");
3768
+ const versionedService = app.get(VersionedGraphService2, {
3769
+ strict: false
3770
+ });
3771
+ logger2.debug(
3772
+ `VersionedGraphService found in DI: ${!!versionedService}`
3773
+ );
3774
+ if (versionedService) {
3775
+ const allVersionedTypes = [];
3776
+ for (const baseType of baseGraphTypes) {
3777
+ logger2.debug(`Getting versions for base type: ${baseType}`);
3778
+ const versions = versionedService.getAvailableVersions(baseType);
3779
+ logger2.debug(
3780
+ `Found ${versions.length} versions for ${baseType}: [${versions.join(", ")}]`
3781
+ );
3782
+ if (versions.length > 0) {
3783
+ allVersionedTypes.push(baseType);
3784
+ versions.forEach((version) => {
3785
+ allVersionedTypes.push(`${baseType}::${version}`);
3786
+ });
3787
+ } else {
3788
+ allVersionedTypes.push(baseType);
3789
+ }
3790
+ }
3791
+ graphTypes = allVersionedTypes;
3792
+ logger2.debug(
3793
+ `Found ${baseGraphTypes.length} base types with ${graphTypes.length} total versioned types: ${graphTypes.join(", ")}`
3794
+ );
3795
+ } else {
3796
+ graphTypes = baseGraphTypes;
3797
+ logger2.debug(
3798
+ `VersionedGraphService not found in DI container, using base types: ${graphTypes.join(", ")}`
3799
+ );
3800
+ }
3801
+ } catch (error) {
3802
+ graphTypes = baseGraphTypes;
3803
+ logger2.debug(
3804
+ `Failed to get versioned types, using base types: ${error.message}`
3805
+ );
3806
+ logger2.debug(`Stack trace: ${error.stack}`);
3807
+ }
3808
+ }
3809
+ }
3810
+ } catch (error) {
3811
+ logger2.debug(`Failed to get graph types from builders: ${error.message}`);
3812
+ }
3813
+ if (graphTypes.length === 0) {
3814
+ logger2.debug("No builders found, using service name as graph type");
3815
+ graphTypes = [serviceName];
3816
+ }
3817
+ await discovery.registerService(
3818
+ serviceName,
3819
+ "localhost",
3820
+ port,
3821
+ {
3822
+ graphTypes,
3823
+ environment: "development",
3824
+ startTime: (/* @__PURE__ */ new Date()).toISOString(),
3825
+ version: process.env.npm_package_version || "1.0.0"
3826
+ },
3827
+ graphTypes
3828
+ );
3829
+ logger2.log(
3830
+ `\u{1F4E1} Service registered with discovery: ${serviceName} (types: ${graphTypes.join(", ")})`
3831
+ );
3832
+ } catch (error) {
3833
+ logger2.warn(`Failed to register with service discovery: ${error.message}`);
3834
+ }
3835
+ }
3191
3836
  async function bootstrap(AppModule, options = {}) {
3837
+ setupRedisMock();
3192
3838
  const app = await core.NestFactory.create(AppModule);
3193
3839
  const logger2 = new common.Logger("Bootstrap");
3194
- const requestedPort = options.port || parseInt(process.env.PORT || "3000", 10);
3840
+ const requestedPort = options.port || parseInt(process.env.PORT || "3100", 10);
3195
3841
  const port = await findAvailablePort(requestedPort);
3196
3842
  const globalPrefix = options.globalPrefix;
3197
3843
  if (port !== requestedPort) {
@@ -3212,63 +3858,27 @@ async function bootstrap(AppModule, options = {}) {
3212
3858
  credentials: true
3213
3859
  });
3214
3860
  const config = new swagger.DocumentBuilder().setTitle("Graph Service API").setDescription("API for graph service microservice").setVersion("1.0").addBearerAuth().build();
3215
- const document = swagger.SwaggerModule.createDocument(app, config);
3216
- swagger.SwaggerModule.setup("api/docs", app, document);
3217
- await app.listen(port);
3218
- const baseUrl = globalPrefix ? `http://localhost:${port}/${globalPrefix}` : `http://localhost:${port}`;
3219
- logger2.log(`\u{1F680} Graph service is running on: ${baseUrl}`);
3220
- logger2.log(`\u{1F4DA} API Documentation: http://localhost:${port}/api/docs`);
3221
- if (process.env.NODE_ENV !== "production") ;
3222
- return app;
3223
- }
3224
- exports.BuilderRegistryService = class BuilderRegistryService {
3225
- builders = [];
3226
- registerBuilder(builder) {
3227
- const existingBuilder = this.builders.find(
3228
- (b) => b.graphType === builder.graphType
3229
- );
3230
- if (!existingBuilder) {
3231
- this.builders.push(builder);
3232
- }
3233
- }
3234
- getBuilders() {
3235
- return this.builders;
3236
- }
3237
- };
3238
- exports.BuilderRegistryService = __decorateClass([
3239
- common.Injectable()
3240
- ], exports.BuilderRegistryService);
3241
- var GraphEngineType = /* @__PURE__ */ ((GraphEngineType2) => {
3242
- GraphEngineType2["LANGGRAPH"] = "langgraph";
3243
- GraphEngineType2["LANGFLOW"] = "langflow";
3244
- GraphEngineType2["FLOWISE"] = "flowise";
3245
- return GraphEngineType2;
3246
- })(GraphEngineType || {});
3247
- exports.GraphEngineFactory = class GraphEngineFactory {
3248
- constructor(langgraph) {
3249
- this.langgraph = langgraph;
3250
- }
3251
- /**
3252
- * Get engine for the specified type
3253
- */
3254
- getEngine(engineType) {
3255
- switch (engineType) {
3256
- case "langgraph" /* LANGGRAPH */:
3257
- return this.langgraph;
3258
- // Will add other types in the future
3259
- // case GraphEngineType.LANGFLOW:
3260
- // return new LangFlowEngine();
3261
- // case GraphEngineType.FLOWISE:
3262
- // return new FlowiseEngine();
3263
- default:
3264
- throw new Error(`Unsupported graph engine type: ${engineType}`);
3265
- }
3861
+ const document = swagger.SwaggerModule.createDocument(app, config);
3862
+ swagger.SwaggerModule.setup("api/docs", app, document);
3863
+ await app.listen(port);
3864
+ const baseUrl = globalPrefix ? `http://localhost:${port}/${globalPrefix}` : `http://localhost:${port}`;
3865
+ logger2.log(`\u{1F680} Graph service is running on: ${baseUrl}`);
3866
+ logger2.log(`\u{1F4DA} API Documentation: http://localhost:${port}/api/docs`);
3867
+ if (process.env.NODE_ENV !== "production") {
3868
+ logger2.debug(
3869
+ `Attempting service discovery registration (NODE_ENV: ${process.env.NODE_ENV || "undefined"})`
3870
+ );
3871
+ await registerWithServiceDiscovery(AppModule, port, logger2, app);
3872
+ } else {
3873
+ logger2.debug(
3874
+ `Skipping service discovery registration (NODE_ENV: ${process.env.NODE_ENV})`
3875
+ );
3266
3876
  }
3267
- };
3268
- exports.GraphEngineFactory = __decorateClass([
3269
- common.Injectable(),
3270
- __decorateParam(0, common.Inject())
3271
- ], exports.GraphEngineFactory);
3877
+ return app;
3878
+ }
3879
+
3880
+ // src/core/index.ts
3881
+ init_builder_registry_service();
3272
3882
 
3273
3883
  // src/messages/attachments.ts
3274
3884
  var AttachmentType = /* @__PURE__ */ ((AttachmentType2) => {
@@ -3650,274 +4260,8 @@ ${result.errors.join("\n")}`
3650
4260
  }
3651
4261
  };
3652
4262
 
3653
- // src/utils/graph-type.utils.ts
3654
- var GraphTypeUtils = class {
3655
- /**
3656
- * Parse full graph type
3657
- * @param fullType - full graph type
3658
- * @returns object with type components
3659
- */
3660
- static parse(fullType) {
3661
- if (fullType.includes("::")) {
3662
- const [baseType, version] = fullType.split("::");
3663
- const [companyId, name] = baseType.split(".");
3664
- return { companyId, name, version };
3665
- }
3666
- const parts = fullType.split(".");
3667
- if (parts.length === 1) {
3668
- return { companyId: "global", name: parts[0] };
3669
- }
3670
- return { companyId: parts[0], name: parts[1] };
3671
- }
3672
- /**
3673
- * Build full type from components
3674
- * @param companyId - company ID
3675
- * @param name - graph name
3676
- * @param version - version (optional)
3677
- * @returns full graph type
3678
- */
3679
- static build(companyId, name, version) {
3680
- const base = `${companyId}.${name}`;
3681
- return version ? `${base}::${version}` : base;
3682
- }
3683
- /**
3684
- * Normalize graph type for backward compatibility
3685
- * @param graphType - graph type in any format
3686
- * @returns normalized type
3687
- */
3688
- static normalize(graphType) {
3689
- const { companyId, name, version } = this.parse(graphType);
3690
- return this.build(companyId, name, version);
3691
- }
3692
- /**
3693
- * Get base type without version
3694
- * @param graphType - full graph type
3695
- * @returns base type
3696
- */
3697
- static getBaseType(graphType) {
3698
- if (graphType.includes("::")) {
3699
- return graphType.split("::")[0];
3700
- }
3701
- const { companyId, name } = this.parse(graphType);
3702
- return `${companyId}.${name}`;
3703
- }
3704
- /**
3705
- * Extract version from graph type
3706
- * @param graphType - full graph type
3707
- * @returns version or undefined
3708
- */
3709
- static getVersion(graphType) {
3710
- return graphType.includes("::") ? graphType.split("::")[1] : void 0;
3711
- }
3712
- /**
3713
- * Validate version (basic semver check)
3714
- * @param version - version to check
3715
- * @returns true if version is valid
3716
- */
3717
- static isValidVersion(version) {
3718
- const semverRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/;
3719
- return semverRegex.test(version);
3720
- }
3721
- /**
3722
- * Check if type is system (global)
3723
- * @param graphType - graph type
3724
- * @returns true if graph is system
3725
- */
3726
- static isSystemGraph(graphType) {
3727
- const { companyId } = this.parse(graphType);
3728
- return companyId === "global";
3729
- }
3730
- /**
3731
- * Compare versions (simple comparison for sorting)
3732
- * @param a - first version
3733
- * @param b - second version
3734
- * @returns -1, 0, 1 for sorting
3735
- */
3736
- static compareVersions(a, b) {
3737
- const parseVersion = (v) => {
3738
- const [main, prerelease] = v.split("-");
3739
- const [major, minor, patch] = main.split(".").map(Number);
3740
- return { major, minor, patch, prerelease };
3741
- };
3742
- const versionA = parseVersion(a);
3743
- const versionB = parseVersion(b);
3744
- if (versionA.major !== versionB.major) {
3745
- return versionA.major - versionB.major;
3746
- }
3747
- if (versionA.minor !== versionB.minor) {
3748
- return versionA.minor - versionB.minor;
3749
- }
3750
- if (versionA.patch !== versionB.patch) {
3751
- return versionA.patch - versionB.patch;
3752
- }
3753
- if (versionA.prerelease && !versionB.prerelease) return -1;
3754
- if (!versionA.prerelease && versionB.prerelease) return 1;
3755
- if (versionA.prerelease && versionB.prerelease) {
3756
- return versionA.prerelease.localeCompare(versionB.prerelease);
3757
- }
3758
- return 0;
3759
- }
3760
- };
3761
-
3762
- // src/graph/versioning/versioned-graph.service.ts
3763
- exports.VersionedGraphService = class VersionedGraphService {
3764
- logger = new common.Logger(exports.VersionedGraphService.name);
3765
- versionConfigs = /* @__PURE__ */ new Map();
3766
- constructor() {
3767
- }
3768
- /**
3769
- * Register versioning configuration
3770
- */
3771
- registerVersioning(config) {
3772
- this.versionConfigs.set(config.baseGraphType, config);
3773
- this.logger.log(
3774
- `Registered versioning for ${config.baseGraphType} with ${config.versions.length} versions`
3775
- );
3776
- }
3777
- /**
3778
- * Resolve graph version
3779
- */
3780
- async resolveVersion(graphType, options = {}) {
3781
- const parsed = GraphTypeUtils.parse(graphType);
3782
- const baseType = GraphTypeUtils.getBaseType(graphType);
3783
- const requestedVersion = GraphTypeUtils.getVersion(graphType) || options.requestedVersion;
3784
- const config = this.versionConfigs.get(baseType);
3785
- if (!config) {
3786
- throw new Error(`No versioning configuration found for ${baseType}`);
3787
- }
3788
- const route = this.findBestVersionRoute(config, requestedVersion, options);
3789
- if (!route) {
3790
- throw new Error(
3791
- `No compatible version found for ${graphType} with options: ${JSON.stringify(options)}`
3792
- );
3793
- }
3794
- const fullGraphType = GraphTypeUtils.build(
3795
- parsed.companyId,
3796
- parsed.name,
3797
- route.version
3798
- );
3799
- return {
3800
- version: route.version,
3801
- builderClass: route.builderClass,
3802
- fullGraphType
3803
- };
3804
- }
3805
- /**
3806
- * Create builder for specified version
3807
- */
3808
- async createVersionedBuilder(graphType, moduleRef, options = {}) {
3809
- const resolution = await this.resolveVersion(graphType, options);
3810
- try {
3811
- if (!moduleRef) {
3812
- throw new Error(
3813
- "ModuleRef is not available - falling back to direct instantiation"
3814
- );
3815
- }
3816
- const builder = await moduleRef.create(resolution.builderClass);
3817
- this.logger.debug(
3818
- `Created versioned builder for ${resolution.fullGraphType}`
3819
- );
3820
- return builder;
3821
- } catch (error) {
3822
- this.logger.error(
3823
- `Failed to create builder for ${resolution.fullGraphType}: ${error.message}`
3824
- );
3825
- throw new Error(`Failed to create versioned builder: ${error.message}`);
3826
- }
3827
- }
3828
- /**
3829
- * Get all available versions for a graph
3830
- */
3831
- getAvailableVersions(baseGraphType) {
3832
- const config = this.versionConfigs.get(baseGraphType);
3833
- if (!config) {
3834
- return [];
3835
- }
3836
- return config.versions.map((route) => route.version).sort((a, b) => GraphTypeUtils.compareVersions(b, a));
3837
- }
3838
- /**
3839
- * Check version support
3840
- */
3841
- isVersionSupported(graphType, options = {}) {
3842
- try {
3843
- const baseType = GraphTypeUtils.getBaseType(graphType);
3844
- const requestedVersion = GraphTypeUtils.getVersion(graphType);
3845
- const config = this.versionConfigs.get(baseType);
3846
- if (!config) {
3847
- return false;
3848
- }
3849
- const route = this.findBestVersionRoute(
3850
- config,
3851
- requestedVersion,
3852
- options
3853
- );
3854
- return route !== null;
3855
- } catch {
3856
- return false;
3857
- }
3858
- }
3859
- /**
3860
- * Find best version
3861
- */
3862
- findBestVersionRoute(config, requestedVersion, options = {}) {
3863
- const { strict = false } = options;
3864
- let candidates = [...config.versions];
3865
- if (requestedVersion) {
3866
- const exactMatch = candidates.find(
3867
- (route) => route.version === requestedVersion
3868
- );
3869
- if (exactMatch) {
3870
- return exactMatch;
3871
- }
3872
- if (strict) {
3873
- return null;
3874
- }
3875
- const compatibleVersions = candidates.filter(
3876
- (route) => this.isVersionCompatible(requestedVersion, route.version)
3877
- );
3878
- if (compatibleVersions.length > 0) {
3879
- return compatibleVersions.sort(
3880
- (a, b) => GraphTypeUtils.compareVersions(b.version, a.version)
3881
- )[0];
3882
- }
3883
- }
3884
- const defaultRoute = candidates.find((route) => route.isDefault);
3885
- if (defaultRoute) {
3886
- return defaultRoute;
3887
- }
3888
- if (config.defaultVersionStrategy === "latest" || !config.defaultVersionStrategy) {
3889
- const sortedVersions = candidates.sort(
3890
- (a, b) => GraphTypeUtils.compareVersions(b.version, a.version)
3891
- );
3892
- return sortedVersions[0] || null;
3893
- }
3894
- return null;
3895
- }
3896
- /**
3897
- * Check version compatibility (simplified semantics)
3898
- */
3899
- isVersionCompatible(requested, available) {
3900
- try {
3901
- const requestedParts = requested.split(".").map(Number);
3902
- const availableParts = available.split(".").map(Number);
3903
- if (requestedParts[0] !== availableParts[0]) {
3904
- return false;
3905
- }
3906
- return GraphTypeUtils.compareVersions(available, requested) >= 0;
3907
- } catch {
3908
- return false;
3909
- }
3910
- }
3911
- /**
3912
- * Get versioning configuration information
3913
- */
3914
- getVersioningInfo(baseGraphType) {
3915
- return this.versionConfigs.get(baseGraphType) || null;
3916
- }
3917
- };
3918
- exports.VersionedGraphService = __decorateClass([
3919
- common.Injectable()
3920
- ], exports.VersionedGraphService);
4263
+ // src/graph/versioning/index.ts
4264
+ init_versioned_graph_service();
3921
4265
  var logger = new common.Logger("ApiCallTracer");
3922
4266
  var DEFAULT_TRACER_OPTIONS = {
3923
4267
  maxStringLength: 5e3,
@@ -4061,8 +4405,36 @@ function sanitizeTraceError(error, options) {
4061
4405
  raw: sanitizeTraceData(error, 0, /* @__PURE__ */ new WeakSet(), options)
4062
4406
  };
4063
4407
  }
4064
-
4065
- // src/engines/langgraph/event-processor.utils.ts
4408
+ var GraphEngineType = /* @__PURE__ */ ((GraphEngineType2) => {
4409
+ GraphEngineType2["LANGGRAPH"] = "langgraph";
4410
+ GraphEngineType2["LANGFLOW"] = "langflow";
4411
+ GraphEngineType2["FLOWISE"] = "flowise";
4412
+ return GraphEngineType2;
4413
+ })(GraphEngineType || {});
4414
+ exports.GraphEngineFactory = class GraphEngineFactory {
4415
+ constructor(langgraph) {
4416
+ this.langgraph = langgraph;
4417
+ }
4418
+ /**
4419
+ * Get engine for the specified type
4420
+ */
4421
+ getEngine(engineType) {
4422
+ switch (engineType) {
4423
+ case "langgraph" /* LANGGRAPH */:
4424
+ return this.langgraph;
4425
+ // Will add other types in the future
4426
+ // case GraphEngineType.LANGFLOW:
4427
+ // return new LangFlowEngine();
4428
+ // case GraphEngineType.FLOWISE:
4429
+ // return new FlowiseEngine();
4430
+ default:
4431
+ throw new Error(`Unsupported graph engine type: ${engineType}`);
4432
+ }
4433
+ }
4434
+ };
4435
+ exports.GraphEngineFactory = __decorateClass([
4436
+ common.Injectable()
4437
+ ], exports.GraphEngineFactory);
4066
4438
  exports.EventProcessor = class EventProcessor {
4067
4439
  logger = new common.Logger(exports.EventProcessor.name);
4068
4440
  /**
@@ -4076,7 +4448,9 @@ exports.EventProcessor = class EventProcessor {
4076
4448
  llmCalls: [],
4077
4449
  traceEvents: [],
4078
4450
  traceStartedAt: null,
4079
- traceCompletedAt: null
4451
+ traceCompletedAt: null,
4452
+ currentReasoningSteps: [],
4453
+ currentToolUse: null
4080
4454
  };
4081
4455
  }
4082
4456
  /**
@@ -4104,6 +4478,51 @@ exports.EventProcessor = class EventProcessor {
4104
4478
  }
4105
4479
  return [];
4106
4480
  }
4481
+ /**
4482
+ * Groups tool_use and input_json_delta into proper structure
4483
+ * tool_use.input → output (tool execution result)
4484
+ * input_json_delta.input → output (tool execution result, accumulated)
4485
+ */
4486
+ mapReasoningSteps(rawSteps) {
4487
+ const steps = [];
4488
+ let currentToolUse = null;
4489
+ for (const raw of rawSteps) {
4490
+ if (raw.type === "tool_use" || raw.type === "tool_call") {
4491
+ if (currentToolUse) {
4492
+ steps.push(currentToolUse);
4493
+ }
4494
+ currentToolUse = {
4495
+ index: raw.index || 0,
4496
+ type: "tool_use",
4497
+ name: raw.name,
4498
+ id: raw.id,
4499
+ input: "",
4500
+ // Parameters (IN) - filled separately or empty
4501
+ output: raw.input || ""
4502
+ // Result (OUT) - comes in tool_use.input
4503
+ };
4504
+ } else if (raw.type === "input_json_delta") {
4505
+ if (currentToolUse) {
4506
+ currentToolUse.output = (currentToolUse.output || "") + (raw.input || "");
4507
+ }
4508
+ } else {
4509
+ if (currentToolUse) {
4510
+ steps.push(currentToolUse);
4511
+ currentToolUse = null;
4512
+ }
4513
+ steps.push({
4514
+ index: raw.index || 0,
4515
+ type: raw.type,
4516
+ text: raw.text || "",
4517
+ metadata: raw.metadata
4518
+ });
4519
+ }
4520
+ }
4521
+ if (currentToolUse) {
4522
+ steps.push(currentToolUse);
4523
+ }
4524
+ return steps;
4525
+ }
4107
4526
  /**
4108
4527
  * Process a LangGraph stream event
4109
4528
  * Mutates accumulator to collect data from different channels
@@ -4126,8 +4545,44 @@ exports.EventProcessor = class EventProcessor {
4126
4545
  if (event.event === "on_chat_model_stream" && event.metadata?.stream_channel === "processing" /* PROCESSING */ && event.data?.chunk?.content) {
4127
4546
  const chunk = event.data.chunk.content;
4128
4547
  const blocks = this.normalizeContentBlocks(chunk);
4129
- if (blocks.length > 0 && onPartial) {
4130
- onPartial(JSON.stringify({ processing: blocks }));
4548
+ for (const block of blocks) {
4549
+ if (block.type === "tool_use" || block.type === "tool_call") {
4550
+ if (acc.currentToolUse) {
4551
+ acc.currentReasoningSteps.push(acc.currentToolUse);
4552
+ }
4553
+ acc.currentToolUse = {
4554
+ index: acc.currentReasoningSteps.length,
4555
+ type: "tool_use",
4556
+ name: block.name,
4557
+ id: block.id,
4558
+ input: block.input || "",
4559
+ output: ""
4560
+ };
4561
+ if (onPartial) {
4562
+ onPartial(
4563
+ JSON.stringify({
4564
+ processing_delta: {
4565
+ type: "step_started",
4566
+ step: acc.currentToolUse
4567
+ }
4568
+ })
4569
+ );
4570
+ }
4571
+ } else if (block.type === "input_json_delta") {
4572
+ if (acc.currentToolUse && onPartial) {
4573
+ const chunk2 = block.input || "";
4574
+ acc.currentToolUse.output += chunk2;
4575
+ onPartial(
4576
+ JSON.stringify({
4577
+ processing_delta: {
4578
+ type: "output_chunk",
4579
+ stepId: acc.currentToolUse.id,
4580
+ chunk: chunk2
4581
+ }
4582
+ })
4583
+ );
4584
+ }
4585
+ }
4131
4586
  }
4132
4587
  return;
4133
4588
  }
@@ -4164,29 +4619,59 @@ exports.EventProcessor = class EventProcessor {
4164
4619
  );
4165
4620
  }
4166
4621
  if (event.metadata?.stream_channel === "processing" /* PROCESSING */) {
4167
- const stepsRaw = output?.content || // AIMessageChunk object (direct)
4168
- output?.kwargs?.content || // Serialized LangChain format
4169
- event.data?.chunk?.content || // Older version
4170
- [];
4171
- let steps;
4172
- if (Array.isArray(stepsRaw)) {
4173
- steps = stepsRaw;
4174
- } else if (typeof stepsRaw === "string" && stepsRaw.trim().length > 0) {
4175
- steps = [
4176
- {
4177
- index: 0,
4178
- type: "text",
4179
- text: stepsRaw.trim()
4180
- }
4181
- ];
4182
- } else {
4183
- steps = [];
4622
+ if (acc.currentToolUse) {
4623
+ acc.currentReasoningSteps.push(acc.currentToolUse);
4624
+ acc.currentToolUse = null;
4184
4625
  }
4185
- if (steps.length > 0) {
4626
+ if (acc.currentReasoningSteps.length > 0) {
4186
4627
  acc.reasoningChains.push({
4187
- steps,
4628
+ steps: acc.currentReasoningSteps,
4188
4629
  isComplete: true
4189
4630
  });
4631
+ if (onPartial) {
4632
+ onPartial(
4633
+ JSON.stringify({
4634
+ processing_delta: {
4635
+ type: "chain_completed"
4636
+ }
4637
+ })
4638
+ );
4639
+ }
4640
+ acc.currentReasoningSteps = [];
4641
+ } else {
4642
+ const stepsRaw = output?.content || // AIMessageChunk object (direct)
4643
+ output?.kwargs?.content || // Serialized LangChain format
4644
+ event.data?.chunk?.content || // Older version
4645
+ [];
4646
+ let steps;
4647
+ if (Array.isArray(stepsRaw)) {
4648
+ steps = this.mapReasoningSteps(stepsRaw);
4649
+ } else if (typeof stepsRaw === "string" && stepsRaw.trim().length > 0) {
4650
+ steps = [
4651
+ {
4652
+ index: 0,
4653
+ type: "text",
4654
+ text: stepsRaw.trim()
4655
+ }
4656
+ ];
4657
+ } else {
4658
+ steps = [];
4659
+ }
4660
+ if (steps.length > 0) {
4661
+ acc.reasoningChains.push({
4662
+ steps,
4663
+ isComplete: true
4664
+ });
4665
+ if (onPartial) {
4666
+ onPartial(
4667
+ JSON.stringify({
4668
+ processing_delta: {
4669
+ type: "chain_completed"
4670
+ }
4671
+ })
4672
+ );
4673
+ }
4674
+ }
4190
4675
  }
4191
4676
  }
4192
4677
  return;
@@ -4595,12 +5080,11 @@ exports.LangGraphEngine = class LangGraphEngine {
4595
5080
  }
4596
5081
  };
4597
5082
  exports.LangGraphEngine = __decorateClass([
4598
- common.Injectable(),
4599
- __decorateParam(0, common.Inject())
5083
+ common.Injectable()
4600
5084
  ], exports.LangGraphEngine);
4601
5085
 
4602
5086
  // src/core/universal-graph.module.ts
4603
- init_ui_dispatch_controller();
5087
+ init_builder_registry_service();
4604
5088
  init_agent_ui();
4605
5089
  function createMetaBuilder(config, versionedGraphService, moduleRef, callbackRegistry, endpointRegistry) {
4606
5090
  const className = `${config.baseGraphType.replace(/\./g, "")}VersionRouter`;
@@ -4669,6 +5153,8 @@ function createMetaBuilder(config, versionedGraphService, moduleRef, callbackReg
4669
5153
  exports.UniversalGraphModule = class UniversalGraphModule {
4670
5154
  static forRoot(options) {
4671
5155
  const providers = [
5156
+ // Discovery services from @nestjs/core
5157
+ core.MetadataScanner,
4672
5158
  // Event processor for stream handling
4673
5159
  exports.EventProcessor,
4674
5160
  // Graph engines
@@ -4698,14 +5184,8 @@ exports.UniversalGraphModule = class UniversalGraphModule {
4698
5184
  provide: CallbackRegistry,
4699
5185
  useClass: CallbackRegistry
4700
5186
  },
4701
- {
4702
- provide: exports.EndpointRegistry,
4703
- useClass: exports.EndpointRegistry
4704
- },
4705
- {
4706
- provide: exports.UIEndpointsDiscoveryService,
4707
- useClass: exports.UIEndpointsDiscoveryService
4708
- },
5187
+ exports.EndpointRegistry,
5188
+ exports.UIEndpointsDiscoveryService,
4709
5189
  {
4710
5190
  provide: exports.CallbackACL,
4711
5191
  useClass: exports.CallbackACL
@@ -4782,14 +5262,6 @@ exports.UniversalGraphModule = class UniversalGraphModule {
4782
5262
  },
4783
5263
  inject: [CallbackRegistry]
4784
5264
  },
4785
- {
4786
- provide: "UI_ENDPOINTS_DISCOVERY",
4787
- useFactory: async (discoveryService) => {
4788
- await discoveryService.discoverUIEndpoints();
4789
- return true;
4790
- },
4791
- inject: [exports.UIEndpointsDiscoveryService]
4792
- },
4793
5265
  {
4794
5266
  provide: "GRAPH_ENGINE",
4795
5267
  useFactory: (factory) => {
@@ -5209,6 +5681,94 @@ var McpToolFilter = class _McpToolFilter {
5209
5681
  }
5210
5682
  }
5211
5683
  };
5684
+ exports.McpRuntimeHttpClient = class McpRuntimeHttpClient {
5685
+ logger = new common.Logger(exports.McpRuntimeHttpClient.name);
5686
+ httpClient;
5687
+ baseUrl;
5688
+ constructor(mcpRuntimeUrl) {
5689
+ this.baseUrl = mcpRuntimeUrl || process.env.MCP_RUNTIME_URL || "http://localhost:3004";
5690
+ this.httpClient = axios2__default.default.create({
5691
+ baseURL: this.baseUrl,
5692
+ timeout: 3e4
5693
+ // 30 seconds
5694
+ });
5695
+ this.logger.log(
5696
+ `MCP Runtime HTTP Client initialized with URL: ${this.baseUrl}`
5697
+ );
5698
+ }
5699
+ /**
5700
+ * Get all available tools from MCP Runtime
5701
+ */
5702
+ async getTools() {
5703
+ try {
5704
+ this.logger.debug("Fetching available tools from MCP runtime");
5705
+ const response = await this.httpClient.get("/tools/list");
5706
+ const tools = Array.isArray(response.data) ? response.data : [];
5707
+ this.logger.log(`Retrieved ${tools.length} tools from MCP runtime`);
5708
+ return tools;
5709
+ } catch (error) {
5710
+ this.logger.error("Failed to fetch tools from MCP runtime:", error);
5711
+ throw new Error(`Failed to fetch tools: ${error.message}`);
5712
+ }
5713
+ }
5714
+ /**
5715
+ * Execute a tool by name with given arguments
5716
+ */
5717
+ async executeTool(name, args, context) {
5718
+ try {
5719
+ this.logger.debug(`Executing tool: ${name} with args:`, args);
5720
+ const payload = {
5721
+ name,
5722
+ arguments: args || {}
5723
+ };
5724
+ if (context) {
5725
+ payload.context = context;
5726
+ }
5727
+ const response = await this.httpClient.post("/tools/execute", payload);
5728
+ this.logger.log(`Tool ${name} executed successfully`);
5729
+ return response.data;
5730
+ } catch (error) {
5731
+ this.logger.error(`Failed to execute tool ${name}:`, error);
5732
+ if (error.response) {
5733
+ return {
5734
+ success: false,
5735
+ error: error.response.data.message || error.response.data.error || "Tool execution failed"
5736
+ };
5737
+ }
5738
+ return {
5739
+ success: false,
5740
+ error: error.message || "Unknown error occurred"
5741
+ };
5742
+ }
5743
+ }
5744
+ /**
5745
+ * Get tool execution statistics from MCP Runtime
5746
+ */
5747
+ async getToolStats() {
5748
+ try {
5749
+ const response = await this.httpClient.get("/tools/stats");
5750
+ return response.data;
5751
+ } catch (error) {
5752
+ this.logger.error("Failed to fetch tool stats:", error);
5753
+ return null;
5754
+ }
5755
+ }
5756
+ /**
5757
+ * Health check for MCP Runtime service
5758
+ */
5759
+ async isHealthy() {
5760
+ try {
5761
+ const response = await this.httpClient.get("/", { timeout: 5e3 });
5762
+ return response.status === 200;
5763
+ } catch (error) {
5764
+ this.logger.warn("MCP Runtime health check failed:", error.message);
5765
+ return false;
5766
+ }
5767
+ }
5768
+ };
5769
+ exports.McpRuntimeHttpClient = __decorateClass([
5770
+ common.Injectable()
5771
+ ], exports.McpRuntimeHttpClient);
5212
5772
 
5213
5773
  // src/models/enums.ts
5214
5774
  var ModelProvider = /* @__PURE__ */ ((ModelProvider2) => {
@@ -6370,6 +6930,28 @@ exports.RetrieverService = __decorateClass([
6370
6930
  common.Injectable()
6371
6931
  ], exports.RetrieverService);
6372
6932
 
6933
+ // src/utils/index.ts
6934
+ init_graph_type_utils();
6935
+
6936
+ // src/service-discovery/index.ts
6937
+ init_file_based_discovery();
6938
+ exports.StaticDiscovery = class StaticDiscovery {
6939
+ constructor(services) {
6940
+ this.services = services;
6941
+ }
6942
+ /**
6943
+ * Get list of services by category
6944
+ */
6945
+ async getServices(category) {
6946
+ return this.services.filter(
6947
+ (service) => service.category === category || service.metadata?.category === category
6948
+ );
6949
+ }
6950
+ };
6951
+ exports.StaticDiscovery = __decorateClass([
6952
+ common.Injectable()
6953
+ ], exports.StaticDiscovery);
6954
+
6373
6955
  exports.AbstractGraphBuilder = AbstractGraphBuilder;
6374
6956
  exports.AttachmentType = AttachmentType;
6375
6957
  exports.BaseGraphServiceController = exports.GraphController;
@@ -6385,7 +6967,6 @@ exports.GraphEngineType = GraphEngineType;
6385
6967
  exports.GraphManifestSchema = GraphManifestSchema;
6386
6968
  exports.GraphManifestValidator = GraphManifestValidator;
6387
6969
  exports.GraphServiceTokens = GraphServiceTokens;
6388
- exports.GraphTypeUtils = GraphTypeUtils;
6389
6970
  exports.IdempotencyStatus = IdempotencyStatus;
6390
6971
  exports.McpConverter = McpConverter;
6391
6972
  exports.McpToolFilter = McpToolFilter;