@flutchai/flutch-sdk 0.2.15 → 0.2.17

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
@@ -25,6 +25,7 @@ var openai = require('@langchain/openai');
25
25
  var aws = require('@langchain/aws');
26
26
  var anthropic = require('@langchain/anthropic');
27
27
  var cohere = require('@langchain/cohere');
28
+ var cohereAi = require('cohere-ai');
28
29
  var document_compressors = require('@langchain/core/retrievers/document_compressors');
29
30
  var mistralai = require('@langchain/mistralai');
30
31
 
@@ -6466,9 +6467,18 @@ function hashToolsConfig(toolsConfig) {
6466
6467
  const sorted = toolsConfig.map((t) => `${t.toolName}:${t.enabled}:${JSON.stringify(t.config || {})}`).sort().join("|");
6467
6468
  return crypto.createHash("md5").update(sorted).digest("hex").slice(0, 16);
6468
6469
  }
6470
+ function normalizeToolConfigs(tools) {
6471
+ if (!tools || tools.length === 0) return void 0;
6472
+ return tools.map(
6473
+ (t) => typeof t === "string" ? { toolName: t, enabled: true } : { toolName: t.name, enabled: t.enabled !== false, config: t.config }
6474
+ );
6475
+ }
6469
6476
  var DEFAULT_ROUTER_URL = "https://router.flutch.ai";
6470
6477
  function resolveRouterURL(baseURL) {
6471
- return baseURL ?? process.env.FLUTCH_ROUTER_URL ?? DEFAULT_ROUTER_URL;
6478
+ if (baseURL) return baseURL;
6479
+ if (process.env.FLUTCH_ROUTER_URL) return process.env.FLUTCH_ROUTER_URL;
6480
+ if (process.env.FLUTCH_API_TOKEN) return DEFAULT_ROUTER_URL;
6481
+ return void 0;
6472
6482
  }
6473
6483
  function generateModelCacheKey(modelId, temperature, maxTokens, toolsConfig, baseURL) {
6474
6484
  const parts = [
@@ -6508,13 +6518,14 @@ var VoyageAIRerank = class extends document_compressors.BaseDocumentCompressor {
6508
6518
  model;
6509
6519
  topN;
6510
6520
  truncation;
6511
- baseUrl = "https://api.voyageai.com/v1/rerank";
6521
+ baseUrl;
6512
6522
  constructor(config) {
6513
6523
  super();
6514
6524
  this.apiKey = config.apiKey || process.env.VOYAGEAI_API_KEY || "";
6515
6525
  this.model = config.model || "rerank-2";
6516
6526
  this.topN = config.topN || 20;
6517
6527
  this.truncation = config.truncation ?? true;
6528
+ this.baseUrl = config.baseUrl ? `${config.baseUrl}/v1/rerank` : "https://api.voyageai.com/v1/rerank";
6518
6529
  if (!this.apiKey) {
6519
6530
  throw new Error(
6520
6531
  "VoyageAI API key is required. Set VOYAGEAI_API_KEY environment variable or pass apiKey in config."
@@ -6574,12 +6585,15 @@ var ModelInitializer = class _ModelInitializer {
6574
6585
  };
6575
6586
  /**
6576
6587
  * Resolve API key for a provider.
6577
- * Uses custom resolver if provided, falls back to process.env.
6588
+ * Priority: custom resolver > FLUTCH_API_TOKEN > provider-specific env var.
6578
6589
  */
6579
6590
  resolveApiKey(provider) {
6580
6591
  if (this.apiKeyResolver) {
6581
6592
  return this.apiKeyResolver(provider);
6582
6593
  }
6594
+ if (process.env.FLUTCH_API_TOKEN) {
6595
+ return process.env.FLUTCH_API_TOKEN;
6596
+ }
6583
6597
  const envVar = _ModelInitializer.DEFAULT_ENV_MAP[provider];
6584
6598
  return envVar ? process.env[envVar] : void 0;
6585
6599
  }
@@ -6625,7 +6639,10 @@ var ModelInitializer = class _ModelInitializer {
6625
6639
  defaultMaxTokens,
6626
6640
  apiToken || this.resolveApiKey("openai" /* OPENAI */) || ""
6627
6641
  );
6628
- config.configuration = { baseURL: `${resolveRouterURL(baseURL)}/v1` };
6642
+ const routerURL = resolveRouterURL(baseURL);
6643
+ if (routerURL) {
6644
+ config.configuration = { baseURL: `${routerURL}/v1` };
6645
+ }
6629
6646
  return new openai.ChatOpenAI(config);
6630
6647
  },
6631
6648
  ["anthropic" /* ANTHROPIC */]: ({
@@ -6639,52 +6656,81 @@ var ModelInitializer = class _ModelInitializer {
6639
6656
  temperature: defaultTemperature,
6640
6657
  maxTokens: defaultMaxTokens,
6641
6658
  anthropicApiKey: apiToken || this.resolveApiKey("anthropic" /* ANTHROPIC */),
6642
- anthropicApiUrl: resolveRouterURL(baseURL)
6659
+ ...resolveRouterURL(baseURL) && {
6660
+ anthropicApiUrl: resolveRouterURL(baseURL)
6661
+ }
6643
6662
  }),
6644
6663
  ["cohere" /* COHERE */]: ({
6645
6664
  modelName,
6646
6665
  defaultTemperature,
6647
6666
  defaultMaxTokens,
6648
- apiToken
6649
- }) => new cohere.ChatCohere({
6650
- model: modelName,
6651
- temperature: defaultTemperature,
6652
- apiKey: apiToken || this.resolveApiKey("cohere" /* COHERE */)
6653
- }),
6667
+ apiToken,
6668
+ baseURL
6669
+ }) => {
6670
+ const routerURL = resolveRouterURL(baseURL);
6671
+ const token = apiToken || this.resolveApiKey("cohere" /* COHERE */);
6672
+ return routerURL ? new cohere.ChatCohere({
6673
+ model: modelName,
6674
+ temperature: defaultTemperature,
6675
+ client: new cohereAi.CohereClient({ token, baseUrl: routerURL })
6676
+ }) : new cohere.ChatCohere({
6677
+ model: modelName,
6678
+ temperature: defaultTemperature,
6679
+ apiKey: token
6680
+ });
6681
+ },
6654
6682
  ["mistral" /* MISTRAL */]: ({
6655
6683
  modelName,
6656
6684
  defaultTemperature,
6657
6685
  defaultMaxTokens,
6658
6686
  apiToken,
6659
6687
  baseURL
6660
- }) => new mistralai.ChatMistralAI({
6661
- model: modelName,
6662
- temperature: defaultTemperature,
6663
- maxTokens: defaultMaxTokens,
6664
- apiKey: apiToken || this.resolveApiKey("mistral" /* MISTRAL */),
6665
- // Route through the same gateway as OpenAI/Anthropic.
6666
- // Without serverURL, ChatMistralAI ignores FLUTCH_ROUTER_URL and calls
6667
- // api.mistral.ai directly inconsistent with other providers.
6668
- serverURL: `${resolveRouterURL(baseURL)}/v1`
6669
- }),
6688
+ }) => {
6689
+ const routerURL = resolveRouterURL(baseURL);
6690
+ return new mistralai.ChatMistralAI({
6691
+ model: modelName,
6692
+ temperature: defaultTemperature,
6693
+ maxTokens: defaultMaxTokens,
6694
+ apiKey: apiToken || this.resolveApiKey("mistral" /* MISTRAL */),
6695
+ ...routerURL && { serverURL: `${routerURL}/v1` }
6696
+ });
6697
+ },
6670
6698
  ["voyageai" /* VOYAGEAI */]: () => {
6671
6699
  throw new Error("VoyageAI chat models not implemented");
6672
6700
  }
6673
6701
  };
6674
6702
  // Rerank model creators
6675
6703
  rerankModelCreators = {
6676
- ["cohere" /* COHERE */]: ({ modelName, apiToken, maxDocuments }) => {
6677
- return new cohere.CohereRerank({
6678
- apiKey: apiToken || this.resolveApiKey("cohere" /* COHERE */),
6704
+ ["cohere" /* COHERE */]: ({
6705
+ modelName,
6706
+ apiToken,
6707
+ maxDocuments,
6708
+ baseURL
6709
+ }) => {
6710
+ const routerURL = resolveRouterURL(baseURL);
6711
+ const token = apiToken || this.resolveApiKey("cohere" /* COHERE */);
6712
+ return routerURL ? new cohere.CohereRerank({
6713
+ model: modelName,
6714
+ topN: maxDocuments || 20,
6715
+ client: new cohereAi.CohereClient({ token, baseUrl: routerURL })
6716
+ }) : new cohere.CohereRerank({
6679
6717
  model: modelName,
6680
- topN: maxDocuments || 20
6718
+ topN: maxDocuments || 20,
6719
+ apiKey: token
6681
6720
  });
6682
6721
  },
6683
- ["voyageai" /* VOYAGEAI */]: ({ modelName, apiToken, maxDocuments }) => {
6722
+ ["voyageai" /* VOYAGEAI */]: ({
6723
+ modelName,
6724
+ apiToken,
6725
+ maxDocuments,
6726
+ baseURL
6727
+ }) => {
6728
+ const routerURL = resolveRouterURL(baseURL);
6684
6729
  return new VoyageAIRerank({
6685
6730
  apiKey: apiToken || this.resolveApiKey("voyageai" /* VOYAGEAI */),
6686
6731
  model: modelName,
6687
- topN: maxDocuments || 20
6732
+ topN: maxDocuments || 20,
6733
+ ...routerURL && { baseUrl: routerURL }
6688
6734
  });
6689
6735
  },
6690
6736
  // Other providers don't support rerank yet
@@ -6695,10 +6741,16 @@ var ModelInitializer = class _ModelInitializer {
6695
6741
  };
6696
6742
  // Embedding model creators
6697
6743
  embeddingModelCreators = {
6698
- ["openai" /* OPENAI */]: ({ modelName, apiToken }) => new openai.OpenAIEmbeddings({
6699
- model: modelName,
6700
- apiKey: apiToken || this.resolveApiKey("openai" /* OPENAI */)
6701
- }),
6744
+ ["openai" /* OPENAI */]: ({ modelName, apiToken, baseURL }) => {
6745
+ const routerURL = resolveRouterURL(baseURL);
6746
+ return new openai.OpenAIEmbeddings({
6747
+ model: modelName,
6748
+ apiKey: apiToken || this.resolveApiKey("openai" /* OPENAI */),
6749
+ ...routerURL && {
6750
+ configuration: { baseURL: `${routerURL}/v1` }
6751
+ }
6752
+ });
6753
+ },
6702
6754
  // Other providers not yet implemented for embeddings
6703
6755
  ["anthropic" /* ANTHROPIC */]: void 0,
6704
6756
  ["cohere" /* COHERE */]: void 0,
@@ -6706,7 +6758,82 @@ var ModelInitializer = class _ModelInitializer {
6706
6758
  ["aws" /* AWS */]: void 0,
6707
6759
  ["voyageai" /* VOYAGEAI */]: void 0
6708
6760
  };
6709
- async initializeChatModel(config) {
6761
+ // ══════════════════════════════════════════════════════════════
6762
+ // initializeChatModel — overloaded: ModelConfig | ModelByIdConfig
6763
+ // ══════════════════════════════════════════════════════════════
6764
+ async initializeChatModel(config, customTools) {
6765
+ if ("provider" in config && "modelName" in config) {
6766
+ return this.initializeChatModelDirect(config, customTools);
6767
+ }
6768
+ return this.initializeChatModelByIdInternal(config);
6769
+ }
6770
+ /**
6771
+ * Direct initialization by provider + modelName (no DB lookup).
6772
+ */
6773
+ async initializeChatModelDirect(config, customTools) {
6774
+ const toolsConfig = normalizeToolConfigs(config.tools);
6775
+ const modelIdentifier = `${config.provider}:${config.modelName}`;
6776
+ const cacheKey = generateModelCacheKey(
6777
+ modelIdentifier,
6778
+ config.temperature,
6779
+ config.maxTokens,
6780
+ toolsConfig,
6781
+ config.baseURL
6782
+ );
6783
+ const cached = this.modelInstanceCache.get(cacheKey);
6784
+ if (cached) {
6785
+ this.logger.debug(`Using cached chat model instance: ${cacheKey}`);
6786
+ return cached;
6787
+ }
6788
+ const provider = config.provider;
6789
+ if (!Object.values(ModelProvider).includes(provider)) {
6790
+ throw new Error(
6791
+ `Unknown provider "${provider}". Valid: ${Object.values(ModelProvider).join(", ")}`
6792
+ );
6793
+ }
6794
+ const apiToken = this.resolveApiKey(provider);
6795
+ const temperature = config.temperature ?? 0.7;
6796
+ const maxTokens = config.maxTokens ?? 4096;
6797
+ const modelConfig = {
6798
+ modelId: modelIdentifier,
6799
+ modelName: config.modelName,
6800
+ provider,
6801
+ modelType: "chat" /* CHAT */,
6802
+ defaultTemperature: Number(temperature),
6803
+ defaultMaxTokens: Number(maxTokens),
6804
+ apiToken,
6805
+ requiresApiKey: true,
6806
+ baseURL: config.baseURL
6807
+ };
6808
+ this.logger.debug(
6809
+ `Creating chat model: ${modelIdentifier} (apiKeyResolved=${!!apiToken})`
6810
+ );
6811
+ const creator = this.chatModelCreators[provider];
6812
+ if (!creator) {
6813
+ throw new Error(`Chat models not supported for provider: ${provider}`);
6814
+ }
6815
+ const model = creator(modelConfig);
6816
+ model.metadata = {
6817
+ ...model.metadata,
6818
+ modelId: modelIdentifier
6819
+ };
6820
+ if (toolsConfig || customTools) {
6821
+ const boundModel = await this.bindToolsToModel(
6822
+ model,
6823
+ toolsConfig,
6824
+ customTools
6825
+ );
6826
+ this.modelInstanceCache.set(cacheKey, boundModel);
6827
+ return boundModel;
6828
+ }
6829
+ this.modelInstanceCache.set(cacheKey, model);
6830
+ return model;
6831
+ }
6832
+ /**
6833
+ * Legacy initialization by model ID (DB lookup via configFetcher).
6834
+ * @deprecated Pass ModelConfig with provider + modelName instead.
6835
+ */
6836
+ async initializeChatModelByIdInternal(config) {
6710
6837
  const cacheKey = this.generateModelCacheKey(config);
6711
6838
  const cachedModel = this.modelInstanceCache.get(cacheKey);
6712
6839
  if (cachedModel) {
@@ -6732,9 +6859,6 @@ var ModelInitializer = class _ModelInitializer {
6732
6859
  this.logger.debug(`Creating new chat model instance: ${cacheKey}`);
6733
6860
  let model;
6734
6861
  if (finalConfig.useBedrock && finalConfig.bedrockModelId) {
6735
- this.logger.debug(
6736
- `Using Bedrock for model ${finalConfig.modelName}, bedrockModelId: ${finalConfig.bedrockModelId}`
6737
- );
6738
6862
  model = new aws.ChatBedrockConverse({
6739
6863
  model: finalConfig.bedrockModelId,
6740
6864
  region: this.resolveBedrockRegion(),
@@ -6755,29 +6879,12 @@ var ModelInitializer = class _ModelInitializer {
6755
6879
  ...model.metadata,
6756
6880
  modelId: config.modelId
6757
6881
  };
6758
- this.logger.debug("\u{1F527} Model initialized with metadata", {
6759
- modelId: config.modelId,
6760
- metadataKeys: Object.keys(model.metadata || {}),
6761
- hasModelId: !!model.metadata?.modelId
6762
- });
6763
- this.logger.debug(
6764
- `[TOOLS CHECK] toolsConfig exists: ${!!config.toolsConfig}, customTools exists: ${!!config.customTools}`
6765
- );
6766
- if (config.toolsConfig) {
6767
- this.logger.debug(
6768
- `[TOOLS CHECK] toolsConfig length: ${config.toolsConfig.length}, content: ${JSON.stringify(config.toolsConfig)}`
6769
- );
6770
- }
6771
6882
  if (config.toolsConfig || config.customTools) {
6772
- this.logger.debug(
6773
- `[TOOLS] Calling bindToolsToModel with toolsConfig: ${JSON.stringify(config.toolsConfig)}`
6774
- );
6775
6883
  const boundModel = await this.bindToolsToModel(
6776
6884
  model,
6777
6885
  config.toolsConfig,
6778
6886
  config.customTools
6779
6887
  );
6780
- this.logger.debug(`[TOOLS] bindToolsToModel returned successfully`);
6781
6888
  this.modelInstanceCache.set(cacheKey, boundModel);
6782
6889
  return boundModel;
6783
6890
  }
@@ -7612,6 +7719,7 @@ exports.CallbackRegistry = CallbackRegistry;
7612
7719
  exports.CallbackStore = CallbackStore;
7613
7720
  exports.ChatFeature = ChatFeature;
7614
7721
  exports.DEFAULT_ATTACHMENT_THRESHOLD = DEFAULT_ATTACHMENT_THRESHOLD;
7722
+ exports.DEFAULT_ROUTER_URL = DEFAULT_ROUTER_URL;
7615
7723
  exports.DEFAULT_TRACER_OPTIONS = DEFAULT_TRACER_OPTIONS;
7616
7724
  exports.Endpoint = Endpoint;
7617
7725
  exports.FileTokenStore = FileTokenStore;
@@ -7638,6 +7746,7 @@ exports.WithUIEndpoints = WithUIEndpoints;
7638
7746
  exports._internals = _internals;
7639
7747
  exports.bootstrap = bootstrap;
7640
7748
  exports.buildOAuthAuthorizationUrl = buildOAuthAuthorizationUrl;
7749
+ exports.buildOpenAIModelConfig = buildOpenAIModelConfig;
7641
7750
  exports.clearAttachmentDataStore = clearAttachmentDataStore;
7642
7751
  exports.createEndpointDescriptors = createEndpointDescriptors;
7643
7752
  exports.createGraphAttachment = createGraphAttachment;
@@ -7650,6 +7759,7 @@ exports.executeToolWithAttachments = executeToolWithAttachments;
7650
7759
  exports.findCallbackMethod = findCallbackMethod;
7651
7760
  exports.findEndpointMethod = findEndpointMethod;
7652
7761
  exports.generateAttachmentSummary = generateAttachmentSummary;
7762
+ exports.generateModelCacheKey = generateModelCacheKey;
7653
7763
  exports.getAttachmentData = getAttachmentData;
7654
7764
  exports.getCallbackMetadata = getCallbackMetadata;
7655
7765
  exports.getEndpointMetadata = getEndpointMetadata;
@@ -7659,10 +7769,14 @@ exports.getUIEndpointClassMetadata = getUIEndpointClassMetadata;
7659
7769
  exports.getUIEndpointMethodsMetadata = getUIEndpointMethodsMetadata;
7660
7770
  exports.hasCallbacks = hasCallbacks;
7661
7771
  exports.hasUIEndpoints = hasUIEndpoints;
7772
+ exports.hashToolsConfig = hashToolsConfig;
7773
+ exports.isReasoningModel = isReasoningModel;
7662
7774
  exports.loadOAuthProviders = loadOAuthProviders;
7775
+ exports.normalizeToolConfigs = normalizeToolConfigs;
7663
7776
  exports.registerFinanceExampleCallback = registerFinanceExampleCallback;
7664
7777
  exports.registerUIEndpointsFromClass = registerUIEndpointsFromClass;
7665
7778
  exports.resolveOAuthProviderConfig = resolveOAuthProviderConfig;
7779
+ exports.resolveRouterURL = resolveRouterURL;
7666
7780
  exports.sanitizeTraceData = sanitizeTraceData;
7667
7781
  exports.storeAttachmentData = storeAttachmentData;
7668
7782
  exports.traceApiCall = traceApiCall;