@flutchai/flutch-sdk 0.6.5 → 0.6.6

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
@@ -7113,6 +7113,48 @@ function modelAcceptsSamplingParams(modelIdentifier) {
7113
7113
  return !atOrAboveThreshold;
7114
7114
  }
7115
7115
  __name(modelAcceptsSamplingParams, "modelAcceptsSamplingParams");
7116
+ var PROMPT_CACHE_MIN_VERSIONS = {
7117
+ opus: {
7118
+ major: 4,
7119
+ minor: 0
7120
+ },
7121
+ sonnet: {
7122
+ major: 4,
7123
+ minor: 0
7124
+ },
7125
+ haiku: {
7126
+ major: 4,
7127
+ minor: 5
7128
+ }
7129
+ };
7130
+ function modelSupportsPromptCache(modelIdentifier) {
7131
+ if (!modelIdentifier) return false;
7132
+ const match = CLAUDE_FAMILY_VERSION.exec(modelIdentifier.toLowerCase());
7133
+ if (!match) return false;
7134
+ const [, family, majorRaw, minorRaw] = match;
7135
+ const threshold = PROMPT_CACHE_MIN_VERSIONS[family];
7136
+ if (!threshold) return false;
7137
+ const major = Number(majorRaw);
7138
+ const minor = minorRaw === void 0 ? 0 : Number(minorRaw);
7139
+ return major > threshold.major || major === threshold.major && minor >= threshold.minor;
7140
+ }
7141
+ __name(modelSupportsPromptCache, "modelSupportsPromptCache");
7142
+ function resolvePromptCacheControl(modelIdentifiers, promptCache, ttl) {
7143
+ const enabled = promptCache ?? modelIdentifiers.some((id) => modelSupportsPromptCache(id));
7144
+ return enabled ? {
7145
+ type: "ephemeral",
7146
+ ttl: ttl ?? "5m"
7147
+ } : void 0;
7148
+ }
7149
+ __name(resolvePromptCacheControl, "resolvePromptCacheControl");
7150
+ function buildEffortRequestFields(effort) {
7151
+ return effort ? {
7152
+ output_config: {
7153
+ effort
7154
+ }
7155
+ } : void 0;
7156
+ }
7157
+ __name(buildEffortRequestFields, "buildEffortRequestFields");
7116
7158
  function resolveSamplingParams(modelIdentifiers, requested, supportsSamplingParams) {
7117
7159
  const accepted = supportsSamplingParams ?? modelIdentifiers.every((id) => modelAcceptsSamplingParams(id));
7118
7160
  if (accepted) {
@@ -7443,7 +7485,9 @@ var ModelInitializer = class _ModelInitializer {
7443
7485
  generateModelCacheKey(config) {
7444
7486
  const base = generateModelCacheKey(config.modelId, config.temperature, config.maxTokens, config.toolsConfig, config.baseURL);
7445
7487
  const withMcp = config.mcpServers && config.mcpServers.length > 0 ? `${base}:mcp:${JSON.stringify(config.mcpServers)}` : base;
7446
- return config.supportsSamplingParams === void 0 ? withMcp : `${withMcp}:sp:${config.supportsSamplingParams}`;
7488
+ const withSampling = config.supportsSamplingParams === void 0 ? withMcp : `${withMcp}:sp:${config.supportsSamplingParams}`;
7489
+ const withCache = config.promptCache === void 0 && config.promptCacheTtl === void 0 ? withSampling : `${withSampling}:pc:${config.promptCache ?? "auto"}:${config.promptCacheTtl ?? "default"}`;
7490
+ return config.effort === void 0 ? withCache : `${withCache}:eff:${config.effort}`;
7447
7491
  }
7448
7492
  // Chat model creators
7449
7493
  chatModelCreators = {
@@ -7458,7 +7502,7 @@ var ModelInitializer = class _ModelInitializer {
7458
7502
  }
7459
7503
  return new openai.ChatOpenAI(config);
7460
7504
  },
7461
- [ModelProvider.ANTHROPIC]: ({ modelName, defaultTemperature, defaultMaxTokens, apiToken, baseURL }) => {
7505
+ [ModelProvider.ANTHROPIC]: ({ modelName, defaultTemperature, defaultMaxTokens, apiToken, baseURL }, promptCacheControl) => {
7462
7506
  const routerURL = resolveRouterURL(baseURL);
7463
7507
  return new anthropic.ChatAnthropic({
7464
7508
  modelName,
@@ -7468,6 +7512,13 @@ var ModelInitializer = class _ModelInitializer {
7468
7512
  temperature: defaultTemperature
7469
7513
  },
7470
7514
  maxTokens: defaultMaxTokens,
7515
+ // Top-level prompt caching: one breakpoint on the last cacheable block,
7516
+ // advanced automatically as the conversation grows. Survives the router
7517
+ // (which forwards the Anthropic body untouched) and is accepted by
7518
+ // Bedrock's InvokeModel schema behind it.
7519
+ ...promptCacheControl && {
7520
+ cache_control: promptCacheControl
7521
+ },
7471
7522
  anthropicApiKey: apiToken || this.resolveApiKey(ModelProvider.ANTHROPIC),
7472
7523
  ...routerURL && {
7473
7524
  anthropicApiUrl: routerURL,
@@ -7672,9 +7723,17 @@ var ModelInitializer = class _ModelInitializer {
7672
7723
  defaultMaxTokens: toOptionalNumber(config.maxTokens) ?? toOptionalNumber(modelConfig.defaultMaxTokens),
7673
7724
  baseURL: config.baseURL ?? modelConfig.baseURL
7674
7725
  };
7726
+ const promptCacheControl = resolvePromptCacheControl([
7727
+ finalConfig.bedrockModelId,
7728
+ finalConfig.modelName
7729
+ ], config.promptCache ?? modelConfig.promptCache, config.promptCacheTtl ?? modelConfig.promptCacheTtl);
7730
+ if (promptCacheControl) {
7731
+ this.logger.debug(`Prompt caching enabled for ${finalConfig.bedrockModelId ?? finalConfig.modelName} (ttl=${promptCacheControl.ttl})`);
7732
+ }
7675
7733
  this.logger.debug(`Creating new chat model instance: ${cacheKey}`);
7676
7734
  let model;
7677
7735
  if (finalConfig.useBedrock && finalConfig.bedrockModelId) {
7736
+ const effortFields = buildEffortRequestFields(config.effort ?? modelConfig.defaultEffort);
7678
7737
  model = new FlutchChatBedrockConverse({
7679
7738
  model: finalConfig.bedrockModelId,
7680
7739
  region: this.resolveBedrockRegion(),
@@ -7682,6 +7741,9 @@ var ModelInitializer = class _ModelInitializer {
7682
7741
  ...finalConfig.defaultTemperature !== void 0 && {
7683
7742
  temperature: finalConfig.defaultTemperature
7684
7743
  },
7744
+ ...effortFields && {
7745
+ additionalModelRequestFields: effortFields
7746
+ },
7685
7747
  maxTokens: finalConfig.defaultMaxTokens,
7686
7748
  streaming: true
7687
7749
  });
@@ -7690,14 +7752,24 @@ var ModelInitializer = class _ModelInitializer {
7690
7752
  if (!creator) {
7691
7753
  throw new Error(`Chat models not supported for provider: ${modelConfig.provider}`);
7692
7754
  }
7693
- model = creator(finalConfig);
7755
+ model = creator(finalConfig, promptCacheControl);
7694
7756
  }
7695
7757
  model.metadata = {
7696
7758
  ...model.metadata,
7697
7759
  modelId: config.modelId
7698
7760
  };
7699
7761
  if (config.toolsConfig || config.customTools || config.mcpServers && config.mcpServers.length > 0) {
7700
- const boundModel = await this.bindToolsToModel(model, config.toolsConfig, config.customTools, config.mcpServers, config.mcpContext);
7762
+ const boundModel = await this.bindToolsToModel(
7763
+ model,
7764
+ config.toolsConfig,
7765
+ config.customTools,
7766
+ config.mcpServers,
7767
+ config.mcpContext,
7768
+ // Converse takes cache control as a per-call option; the Anthropic
7769
+ // client already got it as a constructor field, and handing it the
7770
+ // same value twice would put an unknown key in its call options.
7771
+ finalConfig.useBedrock ? promptCacheControl : void 0
7772
+ );
7701
7773
  this.modelInstanceCache.set(cacheKey, boundModel);
7702
7774
  return boundModel;
7703
7775
  }
@@ -7709,11 +7781,20 @@ var ModelInitializer = class _ModelInitializer {
7709
7781
  * For toolsConfig: fetch tool executors from MCP Runtime
7710
7782
  * For customTools: use as-is (already prepared DynamicStructuredTool)
7711
7783
  *
7784
+ * `promptCacheControl` is the **Bedrock-only** half of prompt caching: it is
7785
+ * bound alongside the tools as a default call option, and `ChatBedrockConverse`
7786
+ * turns it into `cachePoint` blocks after the tool schemas, the system prompt
7787
+ * and the last message. Tool schemas dominate the request, so this is the one
7788
+ * place worth caching — a model with no tools keeps its plain `BaseChatModel`
7789
+ * type and no cache points (callers there rely on `withStructuredOutput` and
7790
+ * friends). The Anthropic client takes its cache settings in the constructor
7791
+ * instead and must not be handed them again here.
7792
+ *
7712
7793
  * Returns:
7713
7794
  * - Runnable when tools are bound (model.bindTools returns Runnable)
7714
7795
  * - BaseChatModel when no tools
7715
7796
  */
7716
- async bindToolsToModel(model, toolsConfig, customTools, mcpServers, mcpContext) {
7797
+ async bindToolsToModel(model, toolsConfig, customTools, mcpServers, mcpContext, promptCacheControl) {
7717
7798
  const allTools = [];
7718
7799
  const enabledToolsConfig = (toolsConfig || []).filter((tc) => tc.enabled !== false);
7719
7800
  const hasInlineServers = !!(mcpServers && mcpServers.length > 0);
@@ -7734,7 +7815,10 @@ var ModelInitializer = class _ModelInitializer {
7734
7815
  }
7735
7816
  if (allTools.length > 0) {
7736
7817
  this.logger.debug(`Binding ${allTools.length} tools to model`);
7737
- const modelWithTools = model.bindTools(allTools);
7818
+ const boundOptions = {
7819
+ cache_control: promptCacheControl
7820
+ };
7821
+ const modelWithTools = promptCacheControl ? model.bindTools(allTools, boundOptions) : model.bindTools(allTools);
7738
7822
  return modelWithTools;
7739
7823
  }
7740
7824
  return model;
@@ -8553,6 +8637,7 @@ exports.ModelProvider = ModelProvider;
8553
8637
  exports.ModelType = ModelType;
8554
8638
  exports.MongoTokenStore = MongoTokenStore;
8555
8639
  exports.OAuthTokenManager = OAuthTokenManager;
8640
+ exports.PROMPT_CACHE_MIN_VERSIONS = PROMPT_CACHE_MIN_VERSIONS;
8556
8641
  exports.RetrieverSearchType = RetrieverSearchType;
8557
8642
  exports.SAMPLING_PARAM_FREE_THRESHOLDS = SAMPLING_PARAM_FREE_THRESHOLDS;
8558
8643
  exports.StreamChannel = StreamChannel;
@@ -8564,6 +8649,7 @@ exports.WithEndpoints = WithEndpoints;
8564
8649
  exports.WithUIEndpoints = WithUIEndpoints;
8565
8650
  exports._internals = _internals;
8566
8651
  exports.bootstrap = bootstrap;
8652
+ exports.buildEffortRequestFields = buildEffortRequestFields;
8567
8653
  exports.buildOAuthAuthorizationUrl = buildOAuthAuthorizationUrl;
8568
8654
  exports.buildOpenAIModelConfig = buildOpenAIModelConfig;
8569
8655
  exports.clearAttachmentDataStore = clearAttachmentDataStore;
@@ -8599,10 +8685,12 @@ exports.isReasoningModel = isReasoningModel;
8599
8685
  exports.isSendableReasoningBlock = isSendableReasoningBlock;
8600
8686
  exports.loadOAuthProviders = loadOAuthProviders;
8601
8687
  exports.modelAcceptsSamplingParams = modelAcceptsSamplingParams;
8688
+ exports.modelSupportsPromptCache = modelSupportsPromptCache;
8602
8689
  exports.normalizeToolConfigs = normalizeToolConfigs;
8603
8690
  exports.registerFinanceExampleCallback = registerFinanceExampleCallback;
8604
8691
  exports.registerUIEndpointsFromClass = registerUIEndpointsFromClass;
8605
8692
  exports.resolveOAuthProviderConfig = resolveOAuthProviderConfig;
8693
+ exports.resolvePromptCacheControl = resolvePromptCacheControl;
8606
8694
  exports.resolveRouterURL = resolveRouterURL;
8607
8695
  exports.resolveSamplingParams = resolveSamplingParams;
8608
8696
  exports.sanitizeMessageReasoning = sanitizeMessageReasoning;