@flutchai/flutch-sdk 0.2.8 → 0.2.10

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
@@ -22,7 +22,7 @@ var axios2 = require('axios');
22
22
  var zodToJsonSchema = require('zod-to-json-schema');
23
23
  var manager = require('@langchain/core/callbacks/manager');
24
24
  var openai = require('@langchain/openai');
25
- var azureOpenai = require('@langchain/azure-openai');
25
+ var aws = require('@langchain/aws');
26
26
  var anthropic = require('@langchain/anthropic');
27
27
  var cohere = require('@langchain/cohere');
28
28
  var document_compressors = require('@langchain/core/retrievers/document_compressors');
@@ -53,6 +53,7 @@ var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
53
53
  var os__namespace = /*#__PURE__*/_interopNamespace(os);
54
54
  var net__namespace = /*#__PURE__*/_interopNamespace(net);
55
55
  var mongoose__default = /*#__PURE__*/_interopDefault(mongoose);
56
+ var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
56
57
  var LangGraph__namespace = /*#__PURE__*/_interopNamespace(LangGraph);
57
58
  var axios2__default = /*#__PURE__*/_interopDefault(axios2);
58
59
 
@@ -1365,10 +1366,10 @@ exports.AbstractGraphBuilder = class AbstractGraphBuilder {
1365
1366
  return null;
1366
1367
  }
1367
1368
  try {
1368
- const fs2 = await import('fs/promises');
1369
- const path3 = await import('path');
1370
- const manifestFullPath = path3.resolve(this.manifestPath);
1371
- const manifestContent = await fs2.readFile(manifestFullPath, "utf-8");
1369
+ const fs3 = await import('fs/promises');
1370
+ const path4 = await import('path');
1371
+ const manifestFullPath = path4.resolve(this.manifestPath);
1372
+ const manifestContent = await fs3.readFile(manifestFullPath, "utf-8");
1372
1373
  const manifest = JSON.parse(manifestContent);
1373
1374
  this.manifest = manifest;
1374
1375
  return manifest;
@@ -1387,10 +1388,10 @@ exports.AbstractGraphBuilder = class AbstractGraphBuilder {
1387
1388
  return null;
1388
1389
  }
1389
1390
  try {
1390
- const fs2 = __require("fs");
1391
- const path3 = __require("path");
1392
- const manifestFullPath = path3.resolve(this.manifestPath);
1393
- const manifestContent = fs2.readFileSync(manifestFullPath, "utf-8");
1391
+ const fs3 = __require("fs");
1392
+ const path4 = __require("path");
1393
+ const manifestFullPath = path4.resolve(this.manifestPath);
1394
+ const manifestContent = fs3.readFileSync(manifestFullPath, "utf-8");
1394
1395
  const manifest = JSON.parse(manifestContent);
1395
1396
  this.manifest = manifest;
1396
1397
  return manifest;
@@ -1430,12 +1431,12 @@ exports.AbstractGraphBuilder = class AbstractGraphBuilder {
1430
1431
  let configSchema = null;
1431
1432
  if (versionConfig.configSchemaPath) {
1432
1433
  try {
1433
- const fs2 = await import('fs/promises');
1434
+ const fs3 = await import('fs/promises');
1434
1435
  const schemaPath = path2__namespace.resolve(
1435
1436
  process.cwd(),
1436
1437
  versionConfig.configSchemaPath
1437
1438
  );
1438
- const schemaContent = await fs2.readFile(schemaPath, "utf-8");
1439
+ const schemaContent = await fs3.readFile(schemaPath, "utf-8");
1439
1440
  const schemaData = JSON.parse(schemaContent);
1440
1441
  configSchema = schemaData.schema;
1441
1442
  } catch (error) {
@@ -6420,10 +6421,6 @@ exports.McpRuntimeHttpClient = __decorateClass([
6420
6421
 
6421
6422
  // src/models/enums.ts
6422
6423
  var ModelProvider = /* @__PURE__ */ ((ModelProvider2) => {
6423
- ModelProvider2["FLUTCH"] = "flutch";
6424
- ModelProvider2["FLUTCH_MISTRAL"] = "flutch-mistral";
6425
- ModelProvider2["FLUTCH_OPENAI"] = "flutch-openai";
6426
- ModelProvider2["FLUTCH_ANTHROPIC"] = "flutch-anthropic";
6427
6424
  ModelProvider2["MISTRAL"] = "mistral";
6428
6425
  ModelProvider2["OPENAI"] = "openai";
6429
6426
  ModelProvider2["ANTHROPIC"] = "anthropic";
@@ -6466,6 +6463,25 @@ function generateModelCacheKey(modelId, temperature, maxTokens, toolsConfig) {
6466
6463
  }
6467
6464
  return parts.join(":");
6468
6465
  }
6466
+ function buildOpenAIModelConfig(modelName, temperature, maxTokens, apiToken) {
6467
+ if (isReasoningModel(modelName)) {
6468
+ return {
6469
+ modelName,
6470
+ temperature: 1,
6471
+ // Reasoning models only support temperature=1
6472
+ maxCompletionTokens: maxTokens,
6473
+ streaming: true,
6474
+ openAIApiKey: apiToken
6475
+ };
6476
+ }
6477
+ return {
6478
+ modelName,
6479
+ temperature,
6480
+ maxTokens,
6481
+ streaming: true,
6482
+ openAIApiKey: apiToken
6483
+ };
6484
+ }
6469
6485
  var VoyageAIRerank = class extends document_compressors.BaseDocumentCompressor {
6470
6486
  apiKey;
6471
6487
  model;
@@ -6517,235 +6533,10 @@ var VoyageAIRerank = class extends document_compressors.BaseDocumentCompressor {
6517
6533
  }
6518
6534
  }
6519
6535
  };
6520
- function patchChatOpenAIForGPT5() {
6521
- const logger2 = new common.Logger("ModelInitializer.Patch");
6522
- logger2.warn(
6523
- `TEMPORARY WORKAROUND: Applying monkey patch for GPT-5 support in LangChain. Fixes: max_tokens->max_completion_tokens, temperature->1. This patch will be removed once LangChain officially supports GPT-5 models.`
6524
- );
6525
- const prototypes = [
6526
- openai.ChatOpenAI.prototype,
6527
- azureOpenai.AzureChatOpenAI.prototype
6528
- ];
6529
- prototypes.forEach((prototype, index) => {
6530
- const modelName = index === 0 ? "ChatOpenAI" : "AzureChatOpenAI";
6531
- logger2.warn(`Patching ${modelName} for GPT-5 support`);
6532
- const originalInvocationParams = prototype.invocationParams;
6533
- if (originalInvocationParams) {
6534
- prototype.invocationParams = function(options) {
6535
- const params = originalInvocationParams.call(this, options);
6536
- if (params.model && (params.model.includes("gpt-5") || /^gpt-(5|6|7|8|9)/.test(params.model))) {
6537
- if (params.max_tokens !== void 0) {
6538
- params.max_completion_tokens = params.max_tokens;
6539
- delete params.max_tokens;
6540
- }
6541
- if (params.max_output_tokens !== void 0 && !params.max_completion_tokens) {
6542
- params.max_completion_tokens = params.max_output_tokens;
6543
- delete params.max_output_tokens;
6544
- }
6545
- const originalTemperature = params.temperature;
6546
- if (params.temperature !== void 0 && params.temperature !== 1) {
6547
- params.temperature = 1;
6548
- logger2.debug(
6549
- `Fixed temperature for ${params.model}: ${originalTemperature} -> 1 (GPT-5 models only support temperature=1)`
6550
- );
6551
- }
6552
- }
6553
- if (params.model && (params.model.includes("gpt-5") || /^gpt-(5|6|7|8|9)/.test(params.model))) {
6554
- if (!params.stream_options) {
6555
- params.stream_options = { include_usage: true };
6556
- logger2.warn(
6557
- `[GPT-5 PATCH] Added stream_options.include_usage=true for ${params.model}`
6558
- );
6559
- } else if (params.stream_options.include_usage !== true) {
6560
- params.stream_options.include_usage = true;
6561
- logger2.warn(
6562
- `[GPT-5 PATCH] Updated stream_options.include_usage=true for ${params.model}`
6563
- );
6564
- }
6565
- }
6566
- return params;
6567
- };
6568
- logger2.warn(
6569
- `Successfully patched ${modelName}.invocationParams for GPT-5 support (TEMPORARY WORKAROUND)`
6570
- );
6571
- } else {
6572
- logger2.warn(
6573
- `Could not find invocationParams method to patch in ${modelName}`
6574
- );
6575
- }
6576
- const originalCompletionWithRetry = prototype.completionWithRetry;
6577
- if (originalCompletionWithRetry) {
6578
- prototype.completionWithRetry = async function(request, options) {
6579
- if (request?.model && (request.model.includes("gpt-5") || /^gpt-(5|6|7|8|9)/.test(request.model))) {
6580
- let hasChanges = false;
6581
- if (request.max_tokens !== void 0) {
6582
- request.max_completion_tokens = request.max_tokens;
6583
- delete request.max_tokens;
6584
- hasChanges = true;
6585
- }
6586
- if (request.temperature !== void 0 && request.temperature !== 1) {
6587
- const originalTemp = request.temperature;
6588
- request.temperature = 1;
6589
- logger2.debug(
6590
- `Fixed temperature in completionWithRetry for ${request.model}: ${originalTemp} -> 1`
6591
- );
6592
- hasChanges = true;
6593
- }
6594
- if (!request.stream_options) {
6595
- request.stream_options = { include_usage: true };
6596
- logger2.debug(
6597
- `Added stream_options.include_usage=true in completionWithRetry for ${request.model}`
6598
- );
6599
- hasChanges = true;
6600
- } else if (request.stream_options.include_usage !== true) {
6601
- request.stream_options.include_usage = true;
6602
- logger2.debug(
6603
- `Updated stream_options.include_usage=true in completionWithRetry for ${request.model}`
6604
- );
6605
- hasChanges = true;
6606
- }
6607
- if (hasChanges) {
6608
- logger2.debug(
6609
- `Fixed request params in completionWithRetry for ${request.model}`
6610
- );
6611
- }
6612
- }
6613
- const result = await originalCompletionWithRetry.call(
6614
- this,
6615
- request,
6616
- options
6617
- );
6618
- if (request?.model && (request.model.includes("gpt-5") || /^gpt-(5|6|7|8|9)/.test(request.model))) {
6619
- logger2.warn(
6620
- `[GPT-5 PATCH] Azure OpenAI Response for ${request.model}:`
6621
- );
6622
- logger2.warn(`Response keys: ${Object.keys(result || {}).join(", ")}`);
6623
- if (result?.usage) {
6624
- logger2.warn(
6625
- `Usage found: ${JSON.stringify(result.usage, null, 2)}`
6626
- );
6627
- } else {
6628
- logger2.warn(`No usage found in response`);
6629
- }
6630
- if (result?.choices && result.choices[0]) {
6631
- logger2.warn(
6632
- `First choice keys: ${Object.keys(result.choices[0]).join(", ")}`
6633
- );
6634
- }
6635
- }
6636
- return result;
6637
- };
6638
- logger2.warn(
6639
- `Successfully patched ${modelName}.completionWithRetry for GPT-5 support (TEMPORARY WORKAROUND)`
6640
- );
6641
- }
6642
- const originalIsReasoningModel = prototype.isReasoningModel;
6643
- if (originalIsReasoningModel) {
6644
- prototype.isReasoningModel = function() {
6645
- const model = this.modelName || this.model || this.lc_kwargs?.modelName;
6646
- const isReasoning = /^o\d/.test(model) || model.includes("gpt-5") || /^gpt-(6|7|8|9)/.test(model);
6647
- const originalResult = originalIsReasoningModel.call(this);
6648
- logger2.warn(
6649
- `[GPT-5 PATCH] isReasoningModel check for "${model}": patched=${isReasoning}, original=${originalResult}, modelName=${this.modelName}, model=${this.model}, lc_kwargs=${JSON.stringify(this.lc_kwargs?.modelName)}`
6650
- );
6651
- return isReasoning;
6652
- };
6653
- logger2.warn(
6654
- `Successfully patched ${modelName}.isReasoningModel for GPT-5+ reasoning models (TEMPORARY WORKAROUND)`
6655
- );
6656
- } else {
6657
- logger2.warn(
6658
- `Could not find isReasoningModel method to patch in ${modelName}`
6659
- );
6660
- }
6661
- const originalInvoke = prototype.invoke;
6662
- if (originalInvoke) {
6663
- prototype.invoke = async function(...args) {
6664
- const model = this.modelName || this.model || this.lc_kwargs?.modelName;
6665
- if (model && model.includes("gpt-5")) {
6666
- logger2.warn(`[GPT-5 PATCH] Starting invoke for ${model}`);
6667
- if (args[1]) {
6668
- const config = args[1];
6669
- logger2.warn(
6670
- `[GPT-5 PATCH] Invoke config keys: ${Object.keys(config || {}).join(", ")}`
6671
- );
6672
- if (config.tools) {
6673
- logger2.warn(
6674
- `[GPT-5 PATCH] Tools in config: ${config.tools.length} tools`
6675
- );
6676
- }
6677
- }
6678
- const boundTools = this.bound || this.boundTools || this.tools;
6679
- if (boundTools) {
6680
- logger2.warn(
6681
- `[GPT-5 PATCH] Model has bound tools: ${Array.isArray(boundTools) ? boundTools.length : "yes"}`
6682
- );
6683
- } else {
6684
- logger2.warn(`[GPT-5 PATCH] Model has NO bound tools`);
6685
- }
6686
- }
6687
- let result;
6688
- try {
6689
- result = await originalInvoke.apply(this, args);
6690
- } catch (error) {
6691
- if (model && model.includes("gpt-5")) {
6692
- logger2.error(
6693
- `[GPT-5 PATCH] Azure OpenAI invoke failed for ${model}:`,
6694
- {
6695
- errorMessage: error instanceof Error ? error.message : String(error),
6696
- errorStack: error instanceof Error ? error.stack : void 0,
6697
- errorType: error?.constructor?.name,
6698
- args: args.length,
6699
- hasConfig: !!args[1],
6700
- configKeys: args[1] ? Object.keys(args[1] || {}) : [],
6701
- tools: args[1]?.tools?.length || 0
6702
- }
6703
- );
6704
- }
6705
- throw error;
6706
- }
6707
- if (model && model.includes("gpt-5")) {
6708
- logger2.warn(`[GPT-5 PATCH] Azure OpenAI invoke result for ${model}:`);
6709
- logger2.warn(`Result keys: ${Object.keys(result || {}).join(", ")}`);
6710
- if (result?.usage_metadata || result?.usageMetadata) {
6711
- const usage = result.usage_metadata || result.usageMetadata;
6712
- logger2.warn(
6713
- `Usage metadata found: ${JSON.stringify(usage, null, 2)}`
6714
- );
6715
- }
6716
- if (result?.response_metadata || result?.responseMetadata) {
6717
- const responseMetadata = result.response_metadata || result.responseMetadata;
6718
- logger2.warn(
6719
- `Response metadata found: ${JSON.stringify(responseMetadata, null, 2)}`
6720
- );
6721
- if (!result.usage_metadata && responseMetadata?.estimatedTokenUsage) {
6722
- const estimatedUsage = responseMetadata.estimatedTokenUsage;
6723
- result.usage_metadata = {
6724
- input_tokens: estimatedUsage.promptTokens || 0,
6725
- output_tokens: estimatedUsage.completionTokens || 0,
6726
- total_tokens: estimatedUsage.totalTokens || 0
6727
- };
6728
- logger2.warn(
6729
- `[GPT-5 PATCH] Created usage_metadata from estimatedTokenUsage: ${JSON.stringify(result.usage_metadata, null, 2)}`
6730
- );
6731
- }
6732
- }
6733
- if (!result?.usage_metadata && !result?.usageMetadata) {
6734
- logger2.warn(`No usage_metadata found in invoke result`);
6735
- }
6736
- }
6737
- return result;
6738
- };
6739
- logger2.warn(
6740
- `Successfully patched ${modelName}.invoke for GPT-5 response logging (TEMPORARY WORKAROUND)`
6741
- );
6742
- }
6743
- });
6744
- }
6745
- patchChatOpenAIForGPT5();
6746
6536
  var ModelInitializer = class _ModelInitializer {
6747
- constructor(configFetcher, logger2) {
6537
+ constructor(configFetcher, logger2, apiKeyResolver) {
6748
6538
  this.configFetcher = configFetcher;
6539
+ this.apiKeyResolver = apiKeyResolver;
6749
6540
  this.logger = logger2 || new common.Logger(_ModelInitializer.name);
6750
6541
  }
6751
6542
  logger;
@@ -6753,9 +6544,30 @@ var ModelInitializer = class _ModelInitializer {
6753
6544
  modelConfigCache = /* @__PURE__ */ new Map();
6754
6545
  // Cache for model instances to avoid recreating identical models
6755
6546
  modelInstanceCache = /* @__PURE__ */ new Map();
6547
+ static DEFAULT_ENV_MAP = {
6548
+ ["openai" /* OPENAI */]: "OPENAI_API_KEY",
6549
+ ["anthropic" /* ANTHROPIC */]: "ANTHROPIC_API_KEY",
6550
+ ["mistral" /* MISTRAL */]: "MISTRAL_API_KEY",
6551
+ ["cohere" /* COHERE */]: "COHERE_API_KEY",
6552
+ ["voyageai" /* VOYAGEAI */]: "VOYAGEAI_API_KEY"
6553
+ };
6756
6554
  /**
6757
- * Generate cache key for model instances based on configuration
6555
+ * Resolve API key for a provider.
6556
+ * Uses custom resolver if provided, falls back to process.env.
6758
6557
  */
6558
+ resolveApiKey(provider) {
6559
+ if (this.apiKeyResolver) {
6560
+ return this.apiKeyResolver(provider);
6561
+ }
6562
+ const envVar = _ModelInitializer.DEFAULT_ENV_MAP[provider];
6563
+ return envVar ? process.env[envVar] : void 0;
6564
+ }
6565
+ /**
6566
+ * Resolve AWS region for Bedrock.
6567
+ */
6568
+ resolveBedrockRegion() {
6569
+ return process.env.BEDROCK_AWS_REGION || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || "us-east-1";
6570
+ }
6759
6571
  /**
6760
6572
  * Generate hash from toolsConfig for cache key
6761
6573
  * Uses MD5 hash to create short, unique identifier
@@ -6776,29 +6588,7 @@ var ModelInitializer = class _ModelInitializer {
6776
6588
  config.toolsConfig
6777
6589
  );
6778
6590
  }
6779
- /**
6780
- * TEMPORARY SOLUTION for compatibility with new OpenAI models
6781
- *
6782
- * OpenAI changed the API for new models (gpt-5, o-series):
6783
- * - Old models (gpt-3.5, gpt-4, gpt-4o): use maxTokens, support custom temperature
6784
- * - New reasoning models (gpt-5, gpt-o1, gpt-o3, gpt-o4): use maxCompletionTokens, only temperature = 1
6785
- *
6786
- * Patch fixes:
6787
- * 1. max_tokens -> max_completion_tokens for reasoning GPT-5+ models
6788
- * 2. temperature -> 1 (forced) for reasoning GPT-5+ models
6789
- *
6790
- * @param modelName - OpenAI model name
6791
- * @returns true if model requires maxCompletionTokens and temperature = 1
6792
- */
6793
- requiresMaxCompletionTokens(modelName) {
6794
- const requiresNew = isReasoningModel(modelName);
6795
- this.logger.debug(`Checking token parameter for model "${modelName}"`, {
6796
- modelName,
6797
- requiresMaxCompletionTokens: requiresNew
6798
- });
6799
- return requiresNew;
6800
- }
6801
- // Chat model creators (inherit from original LLMInitializer)
6591
+ // Chat model creators
6802
6592
  chatModelCreators = {
6803
6593
  ["openai" /* OPENAI */]: ({
6804
6594
  modelName,
@@ -6806,36 +6596,13 @@ var ModelInitializer = class _ModelInitializer {
6806
6596
  defaultMaxTokens,
6807
6597
  apiToken
6808
6598
  }) => {
6809
- if (this.requiresMaxCompletionTokens(modelName)) {
6810
- const fixedTemperature = 1;
6811
- const config = {
6812
- modelName,
6813
- temperature: fixedTemperature,
6814
- // Force set to 1
6815
- maxCompletionTokens: defaultMaxTokens,
6816
- // Only this parameter for new models
6817
- streaming: true,
6818
- openAIApiKey: apiToken || process.env.OPENAI_API_KEY
6819
- };
6820
- if (defaultTemperature !== 1) {
6821
- this.logger.debug(
6822
- `Fixed temperature for GPT-5+ model ${modelName}: ${defaultTemperature} -> 1 (GPT-5+ models only support temperature=1)`
6823
- );
6824
- }
6825
- const chatOpenAI = new openai.ChatOpenAI(config);
6826
- return chatOpenAI;
6827
- } else {
6828
- const config = {
6829
- modelName,
6830
- temperature: defaultTemperature,
6831
- maxTokens: defaultMaxTokens,
6832
- // Only this parameter for legacy models
6833
- streaming: true,
6834
- openAIApiKey: apiToken || process.env.OPENAI_API_KEY
6835
- };
6836
- const chatOpenAI = new openai.ChatOpenAI(config);
6837
- return chatOpenAI;
6838
- }
6599
+ const config = buildOpenAIModelConfig(
6600
+ modelName,
6601
+ defaultTemperature,
6602
+ defaultMaxTokens,
6603
+ apiToken || this.resolveApiKey("openai" /* OPENAI */) || ""
6604
+ );
6605
+ return new openai.ChatOpenAI(config);
6839
6606
  },
6840
6607
  ["anthropic" /* ANTHROPIC */]: ({
6841
6608
  modelName,
@@ -6846,7 +6613,7 @@ var ModelInitializer = class _ModelInitializer {
6846
6613
  modelName,
6847
6614
  temperature: defaultTemperature,
6848
6615
  maxTokens: defaultMaxTokens,
6849
- anthropicApiKey: apiToken || process.env.ANTHROPIC_API_KEY
6616
+ anthropicApiKey: apiToken || this.resolveApiKey("anthropic" /* ANTHROPIC */)
6850
6617
  }),
6851
6618
  ["cohere" /* COHERE */]: ({
6852
6619
  modelName,
@@ -6856,8 +6623,7 @@ var ModelInitializer = class _ModelInitializer {
6856
6623
  }) => new cohere.ChatCohere({
6857
6624
  model: modelName,
6858
6625
  temperature: defaultTemperature,
6859
- // Cohere uses maxTokens via max_tokens parameter, but it's not supported in ChatCohere API
6860
- apiKey: apiToken || process.env.COHERE_API_KEY
6626
+ apiKey: apiToken || this.resolveApiKey("cohere" /* COHERE */)
6861
6627
  }),
6862
6628
  ["mistral" /* MISTRAL */]: ({
6863
6629
  modelName,
@@ -6868,91 +6634,8 @@ var ModelInitializer = class _ModelInitializer {
6868
6634
  model: modelName,
6869
6635
  temperature: defaultTemperature,
6870
6636
  maxTokens: defaultMaxTokens,
6871
- apiKey: apiToken || process.env.MISTRAL_API_KEY
6637
+ apiKey: apiToken || this.resolveApiKey("mistral" /* MISTRAL */)
6872
6638
  }),
6873
- // AWS Bedrock support removed - use Anthropic or OpenAI directly instead
6874
- ["flutch-openai" /* FLUTCH_OPENAI */]: ({
6875
- modelName,
6876
- defaultTemperature,
6877
- defaultMaxTokens,
6878
- apiToken
6879
- }) => {
6880
- if (this.requiresMaxCompletionTokens(modelName)) {
6881
- const fixedTemperature = 1;
6882
- const config = {
6883
- modelName,
6884
- temperature: fixedTemperature,
6885
- // Force set to 1
6886
- maxCompletionTokens: defaultMaxTokens,
6887
- // Only this parameter for new models
6888
- streaming: true,
6889
- openAIApiKey: apiToken || process.env.OPENAI_API_KEY
6890
- };
6891
- if (defaultTemperature !== 1) {
6892
- this.logger.debug(
6893
- `Fixed temperature for FLUTCH GPT-5+ model ${modelName}: ${defaultTemperature} -> 1 (GPT-5+ models only support temperature=1)`
6894
- );
6895
- }
6896
- this.logger.debug(`Creating FLUTCH GPT-5+ model with config`, {
6897
- modelName,
6898
- maxCompletionTokens: defaultMaxTokens,
6899
- temperature: fixedTemperature,
6900
- originalTemperature: defaultTemperature,
6901
- hasApiKey: !!config.openAIApiKey
6902
- });
6903
- const chatOpenAI = new openai.ChatOpenAI(config);
6904
- this.logger.debug(`FLUTCH ChatOpenAI GPT-5+ instance created`, {
6905
- modelName,
6906
- // Use modelName from parameters
6907
- maxTokens: chatOpenAI.maxTokens,
6908
- maxCompletionTokens: chatOpenAI.maxCompletionTokens,
6909
- temperature: chatOpenAI.temperature,
6910
- streaming: chatOpenAI.streaming,
6911
- // Try to get internal parameters
6912
- clientConfig: chatOpenAI.clientConfig,
6913
- kwargs: chatOpenAI.kwargs
6914
- });
6915
- return chatOpenAI;
6916
- } else {
6917
- const config = {
6918
- modelName,
6919
- temperature: defaultTemperature,
6920
- maxTokens: defaultMaxTokens,
6921
- // Only this parameter for legacy models
6922
- streaming: true,
6923
- openAIApiKey: apiToken || process.env.OPENAI_API_KEY
6924
- };
6925
- this.logger.debug(`Creating FLUTCH legacy model with config`, {
6926
- modelName,
6927
- maxTokens: defaultMaxTokens,
6928
- temperature: defaultTemperature,
6929
- hasApiKey: !!config.openAIApiKey
6930
- });
6931
- const chatOpenAI = new openai.ChatOpenAI(config);
6932
- this.logger.debug(`FLUTCH ChatOpenAI legacy instance created`, {
6933
- modelName,
6934
- // Use modelName from parameters
6935
- maxTokens: chatOpenAI.maxTokens,
6936
- maxCompletionTokens: chatOpenAI.maxCompletionTokens,
6937
- temperature: chatOpenAI.temperature,
6938
- streaming: chatOpenAI.streaming,
6939
- // Try to get internal parameters
6940
- clientConfig: chatOpenAI.clientConfig,
6941
- kwargs: chatOpenAI.kwargs
6942
- });
6943
- return chatOpenAI;
6944
- }
6945
- },
6946
- // Other providers not yet implemented for chat
6947
- ["flutch" /* FLUTCH */]: () => {
6948
- throw new Error("Flutch chat models not implemented");
6949
- },
6950
- ["flutch-mistral" /* FLUTCH_MISTRAL */]: () => {
6951
- throw new Error("Flutch Mistral chat models not implemented");
6952
- },
6953
- ["flutch-anthropic" /* FLUTCH_ANTHROPIC */]: () => {
6954
- throw new Error("Flutch Anthropic chat models not implemented");
6955
- },
6956
6639
  ["voyageai" /* VOYAGEAI */]: () => {
6957
6640
  throw new Error("VoyageAI chat models not implemented");
6958
6641
  }
@@ -6961,14 +6644,14 @@ var ModelInitializer = class _ModelInitializer {
6961
6644
  rerankModelCreators = {
6962
6645
  ["cohere" /* COHERE */]: ({ modelName, apiToken, maxDocuments }) => {
6963
6646
  return new cohere.CohereRerank({
6964
- apiKey: apiToken || process.env.COHERE_API_KEY,
6647
+ apiKey: apiToken || this.resolveApiKey("cohere" /* COHERE */),
6965
6648
  model: modelName,
6966
6649
  topN: maxDocuments || 20
6967
6650
  });
6968
6651
  },
6969
6652
  ["voyageai" /* VOYAGEAI */]: ({ modelName, apiToken, maxDocuments }) => {
6970
6653
  return new VoyageAIRerank({
6971
- apiKey: apiToken || process.env.VOYAGEAI_API_KEY,
6654
+ apiKey: apiToken || this.resolveApiKey("voyageai" /* VOYAGEAI */),
6972
6655
  model: modelName,
6973
6656
  topN: maxDocuments || 20
6974
6657
  });
@@ -6977,27 +6660,19 @@ var ModelInitializer = class _ModelInitializer {
6977
6660
  ["openai" /* OPENAI */]: void 0,
6978
6661
  ["anthropic" /* ANTHROPIC */]: void 0,
6979
6662
  ["mistral" /* MISTRAL */]: void 0,
6980
- ["aws" /* AWS */]: void 0,
6981
- ["flutch" /* FLUTCH */]: void 0,
6982
- ["flutch-mistral" /* FLUTCH_MISTRAL */]: void 0,
6983
- ["flutch-openai" /* FLUTCH_OPENAI */]: void 0,
6984
- ["flutch-anthropic" /* FLUTCH_ANTHROPIC */]: void 0
6663
+ ["aws" /* AWS */]: void 0
6985
6664
  };
6986
6665
  // Embedding model creators
6987
6666
  embeddingModelCreators = {
6988
6667
  ["openai" /* OPENAI */]: ({ modelName, apiToken }) => new openai.OpenAIEmbeddings({
6989
6668
  model: modelName,
6990
- apiKey: apiToken || process.env.OPENAI_API_KEY
6669
+ apiKey: apiToken || this.resolveApiKey("openai" /* OPENAI */)
6991
6670
  }),
6992
6671
  // Other providers not yet implemented for embeddings
6993
6672
  ["anthropic" /* ANTHROPIC */]: void 0,
6994
6673
  ["cohere" /* COHERE */]: void 0,
6995
6674
  ["mistral" /* MISTRAL */]: void 0,
6996
6675
  ["aws" /* AWS */]: void 0,
6997
- ["flutch" /* FLUTCH */]: void 0,
6998
- ["flutch-mistral" /* FLUTCH_MISTRAL */]: void 0,
6999
- ["flutch-openai" /* FLUTCH_OPENAI */]: void 0,
7000
- ["flutch-anthropic" /* FLUTCH_ANTHROPIC */]: void 0,
7001
6676
  ["voyageai" /* VOYAGEAI */]: void 0
7002
6677
  };
7003
6678
  async initializeChatModel(config) {
@@ -7013,12 +6688,6 @@ var ModelInitializer = class _ModelInitializer {
7013
6688
  `Model ${config.modelId} is not a chat model (type: ${modelConfig.modelType})`
7014
6689
  );
7015
6690
  }
7016
- const creator = this.chatModelCreators[modelConfig.provider];
7017
- if (!creator) {
7018
- throw new Error(
7019
- `Chat models not supported for provider: ${modelConfig.provider}`
7020
- );
7021
- }
7022
6691
  const finalConfig = {
7023
6692
  ...modelConfig,
7024
6693
  defaultTemperature: Number(
@@ -7029,7 +6698,27 @@ var ModelInitializer = class _ModelInitializer {
7029
6698
  )
7030
6699
  };
7031
6700
  this.logger.debug(`Creating new chat model instance: ${cacheKey}`);
7032
- const model = creator(finalConfig);
6701
+ let model;
6702
+ if (finalConfig.useBedrock && finalConfig.bedrockModelId) {
6703
+ this.logger.debug(
6704
+ `Using Bedrock for model ${finalConfig.modelName}, bedrockModelId: ${finalConfig.bedrockModelId}`
6705
+ );
6706
+ model = new aws.ChatBedrockConverse({
6707
+ model: finalConfig.bedrockModelId,
6708
+ region: this.resolveBedrockRegion(),
6709
+ temperature: finalConfig.defaultTemperature,
6710
+ maxTokens: finalConfig.defaultMaxTokens,
6711
+ streaming: true
6712
+ });
6713
+ } else {
6714
+ const creator = this.chatModelCreators[modelConfig.provider];
6715
+ if (!creator) {
6716
+ throw new Error(
6717
+ `Chat models not supported for provider: ${modelConfig.provider}`
6718
+ );
6719
+ }
6720
+ model = creator(finalConfig);
6721
+ }
7033
6722
  model.metadata = {
7034
6723
  ...model.metadata,
7035
6724
  modelId: config.modelId
@@ -7637,6 +7326,205 @@ exports.StaticDiscovery = class StaticDiscovery {
7637
7326
  exports.StaticDiscovery = __decorateClass([
7638
7327
  common.Injectable()
7639
7328
  ], exports.StaticDiscovery);
7329
+ var ALGORITHM = "aes-256-cbc";
7330
+ var IV_LENGTH = 16;
7331
+ function encryptTokens(tokens, key) {
7332
+ const iv = crypto__namespace.randomBytes(IV_LENGTH);
7333
+ const cipher = crypto__namespace.createCipheriv(
7334
+ ALGORITHM,
7335
+ Buffer.from(key),
7336
+ iv
7337
+ );
7338
+ const json = JSON.stringify(tokens);
7339
+ let encrypted = cipher.update(json, "utf8", "hex");
7340
+ encrypted += cipher.final("hex");
7341
+ return iv.toString("hex") + ":" + encrypted;
7342
+ }
7343
+ function decryptTokens(encrypted, key) {
7344
+ const separatorIndex = encrypted.indexOf(":");
7345
+ if (separatorIndex === -1) {
7346
+ throw new Error("Invalid encrypted token format");
7347
+ }
7348
+ const ivHex = encrypted.substring(0, separatorIndex);
7349
+ const encryptedData = encrypted.substring(separatorIndex + 1);
7350
+ const iv = Buffer.from(ivHex, "hex");
7351
+ const decipher = crypto__namespace.createDecipheriv(
7352
+ ALGORITHM,
7353
+ Buffer.from(key),
7354
+ iv
7355
+ );
7356
+ let decrypted = decipher.update(encryptedData, "hex", "utf8");
7357
+ decrypted += decipher.final("utf8");
7358
+ return JSON.parse(decrypted);
7359
+ }
7360
+
7361
+ // src/oauth/oauth-token.manager.ts
7362
+ var EXPIRY_BUFFER_MS = 6e4;
7363
+ var OAuthTokenManager = class {
7364
+ store;
7365
+ encryptionKey;
7366
+ cache = /* @__PURE__ */ new Map();
7367
+ constructor(options) {
7368
+ if (!options.encryptionKey || options.encryptionKey.length < 32) {
7369
+ throw new Error(
7370
+ "OAUTH_ENCRYPTION_KEY must be at least 32 characters for AES-256-CBC"
7371
+ );
7372
+ }
7373
+ this.store = options.store;
7374
+ this.encryptionKey = options.encryptionKey;
7375
+ }
7376
+ /**
7377
+ * Get a fresh access token for the given provider.
7378
+ * Returns from cache → store → refresh flow (in that order).
7379
+ */
7380
+ async getAccessToken(config) {
7381
+ const cached = this.cache.get(config.provider);
7382
+ if (cached && cached.expiresAt > Date.now() + EXPIRY_BUFFER_MS) {
7383
+ return cached.token;
7384
+ }
7385
+ const encrypted = await this.store.get(config.provider);
7386
+ if (!encrypted) {
7387
+ throw new Error(
7388
+ `No OAuth tokens found for "${config.provider}". Complete the OAuth consent flow first and call saveTokens().`
7389
+ );
7390
+ }
7391
+ const tokens = decryptTokens(encrypted, this.encryptionKey);
7392
+ if (tokens.expiresAt > Date.now() + EXPIRY_BUFFER_MS) {
7393
+ this.setCache(config.provider, tokens.accessToken, tokens.expiresAt);
7394
+ return tokens.accessToken;
7395
+ }
7396
+ const refreshed = await this.refreshAccessToken(config, tokens.refreshToken);
7397
+ await this.persistTokens(config.provider, refreshed);
7398
+ return refreshed.accessToken;
7399
+ }
7400
+ /**
7401
+ * Store tokens after the initial OAuth consent flow.
7402
+ * Call this once after the user completes the OAuth redirect.
7403
+ */
7404
+ async saveTokens(provider, tokens) {
7405
+ await this.persistTokens(provider, tokens);
7406
+ }
7407
+ /**
7408
+ * Remove all tokens for a provider.
7409
+ */
7410
+ async revokeTokens(provider) {
7411
+ await this.store.delete(provider);
7412
+ this.cache.delete(provider);
7413
+ }
7414
+ /**
7415
+ * Check if tokens exist for a provider (without decrypting).
7416
+ */
7417
+ async hasTokens(provider) {
7418
+ const encrypted = await this.store.get(provider);
7419
+ return encrypted !== null;
7420
+ }
7421
+ async refreshAccessToken(config, refreshToken) {
7422
+ try {
7423
+ const response = await axios2__default.default.post(
7424
+ config.tokenUrl,
7425
+ new URLSearchParams({
7426
+ grant_type: "refresh_token",
7427
+ client_id: config.clientId,
7428
+ client_secret: config.clientSecret,
7429
+ refresh_token: refreshToken
7430
+ }).toString(),
7431
+ {
7432
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
7433
+ timeout: 1e4
7434
+ }
7435
+ );
7436
+ const data = response.data;
7437
+ return {
7438
+ accessToken: data.access_token,
7439
+ // Some providers rotate refresh tokens; keep the old one if not rotated
7440
+ refreshToken: data.refresh_token || refreshToken,
7441
+ expiresAt: Date.now() + (data.expires_in || 3600) * 1e3
7442
+ };
7443
+ } catch (error) {
7444
+ const status = error?.response?.status;
7445
+ const body = error?.response?.data;
7446
+ throw new Error(
7447
+ `OAuth refresh failed for "${config.provider}": ${status || "network error"} ${JSON.stringify(body) || error.message}`
7448
+ );
7449
+ }
7450
+ }
7451
+ async persistTokens(provider, tokens) {
7452
+ const encrypted = encryptTokens(tokens, this.encryptionKey);
7453
+ await this.store.save(provider, encrypted);
7454
+ this.setCache(provider, tokens.accessToken, tokens.expiresAt);
7455
+ }
7456
+ setCache(provider, token, expiresAt) {
7457
+ this.cache.set(provider, { token, expiresAt });
7458
+ }
7459
+ };
7460
+ var FileTokenStore = class {
7461
+ constructor(filePath) {
7462
+ this.filePath = filePath;
7463
+ }
7464
+ async get(provider) {
7465
+ const data = this.readFile();
7466
+ return data[provider] ?? null;
7467
+ }
7468
+ async save(provider, encrypted) {
7469
+ const data = this.readFile();
7470
+ data[provider] = encrypted;
7471
+ this.writeFile(data);
7472
+ }
7473
+ async delete(provider) {
7474
+ const data = this.readFile();
7475
+ delete data[provider];
7476
+ this.writeFile(data);
7477
+ }
7478
+ readFile() {
7479
+ try {
7480
+ if (fs__namespace.existsSync(this.filePath)) {
7481
+ const content = fs__namespace.readFileSync(this.filePath, "utf8");
7482
+ return JSON.parse(content);
7483
+ }
7484
+ } catch {
7485
+ }
7486
+ return {};
7487
+ }
7488
+ writeFile(data) {
7489
+ const dir = path2__namespace.dirname(this.filePath);
7490
+ if (!fs__namespace.existsSync(dir)) {
7491
+ fs__namespace.mkdirSync(dir, { recursive: true });
7492
+ }
7493
+ fs__namespace.writeFileSync(this.filePath, JSON.stringify(data, null, 2), "utf8");
7494
+ }
7495
+ };
7496
+
7497
+ // src/oauth/stores/mongo-token.store.ts
7498
+ var DEFAULT_COLLECTION = "oauth_tokens";
7499
+ var MongoTokenStore = class {
7500
+ constructor(db, collectionName) {
7501
+ this.db = db;
7502
+ this.collectionName = collectionName ?? DEFAULT_COLLECTION;
7503
+ }
7504
+ collectionName;
7505
+ initialized = false;
7506
+ async get(provider) {
7507
+ await this.ensureIndex();
7508
+ const doc = await this.db.collection(this.collectionName).findOne({ provider });
7509
+ return doc?.encrypted ?? null;
7510
+ }
7511
+ async save(provider, encrypted) {
7512
+ await this.ensureIndex();
7513
+ await this.db.collection(this.collectionName).updateOne(
7514
+ { provider },
7515
+ { $set: { provider, encrypted, updatedAt: /* @__PURE__ */ new Date() } },
7516
+ { upsert: true }
7517
+ );
7518
+ }
7519
+ async delete(provider) {
7520
+ await this.db.collection(this.collectionName).deleteOne({ provider });
7521
+ }
7522
+ async ensureIndex() {
7523
+ if (this.initialized) return;
7524
+ await this.db.collection(this.collectionName).createIndex({ provider: 1 }, { unique: true });
7525
+ this.initialized = true;
7526
+ }
7527
+ };
7640
7528
 
7641
7529
  exports.AttachmentType = AttachmentType;
7642
7530
  exports.BaseGraphServiceController = exports.GraphController;
@@ -7649,6 +7537,7 @@ exports.ChatFeature = ChatFeature;
7649
7537
  exports.DEFAULT_ATTACHMENT_THRESHOLD = DEFAULT_ATTACHMENT_THRESHOLD;
7650
7538
  exports.DEFAULT_TRACER_OPTIONS = DEFAULT_TRACER_OPTIONS;
7651
7539
  exports.Endpoint = Endpoint;
7540
+ exports.FileTokenStore = FileTokenStore;
7652
7541
  exports.GraphEngineType = GraphEngineType;
7653
7542
  exports.GraphManifestSchema = GraphManifestSchema;
7654
7543
  exports.GraphManifestValidator = GraphManifestValidator;
@@ -7659,6 +7548,8 @@ exports.McpToolFilter = McpToolFilter;
7659
7548
  exports.ModelInitializer = ModelInitializer;
7660
7549
  exports.ModelProvider = ModelProvider;
7661
7550
  exports.ModelType = ModelType;
7551
+ exports.MongoTokenStore = MongoTokenStore;
7552
+ exports.OAuthTokenManager = OAuthTokenManager;
7662
7553
  exports.RetrieverSearchType = RetrieverSearchType;
7663
7554
  exports.StreamChannel = StreamChannel;
7664
7555
  exports.UIEndpoint = UIEndpoint;
@@ -7674,7 +7565,9 @@ exports.createEndpointDescriptors = createEndpointDescriptors;
7674
7565
  exports.createGraphAttachment = createGraphAttachment;
7675
7566
  exports.createMongoClientAdapter = createMongoClientAdapter;
7676
7567
  exports.createStaticMessage = createStaticMessage;
7568
+ exports.decryptTokens = decryptTokens;
7677
7569
  exports.dispatchAttachments = dispatchAttachments;
7570
+ exports.encryptTokens = encryptTokens;
7678
7571
  exports.executeToolWithAttachments = executeToolWithAttachments;
7679
7572
  exports.findCallbackMethod = findCallbackMethod;
7680
7573
  exports.findEndpointMethod = findEndpointMethod;