@matthewdunbar/amazon-bedrock-mantle 2.0.30 → 2.0.32

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.

Potentially problematic release.


This version of @matthewdunbar/amazon-bedrock-mantle might be problematic. Click here for more details.

package/dist/index.d.mts CHANGED
@@ -275,6 +275,11 @@ interface OpenAICompatibleProviderSettings {
275
275
  * The AWS session token to use for request signing. Defaults to `AWS_SESSION_TOKEN`.
276
276
  */
277
277
  sessionToken?: string;
278
+ /**
279
+ * The AWS shared profile name to load credentials from (e.g. `default`, `dev`).
280
+ * Falls back to `AWS_PROFILE` when not provided.
281
+ */
282
+ profile?: string;
278
283
  /**
279
284
  * Optional async credentials provider used for request signing.
280
285
  */
package/dist/index.d.ts CHANGED
@@ -275,6 +275,11 @@ interface OpenAICompatibleProviderSettings {
275
275
  * The AWS session token to use for request signing. Defaults to `AWS_SESSION_TOKEN`.
276
276
  */
277
277
  sessionToken?: string;
278
+ /**
279
+ * The AWS shared profile name to load credentials from (e.g. `default`, `dev`).
280
+ * Falls back to `AWS_PROFILE` when not provided.
281
+ */
282
+ profile?: string;
278
283
  /**
279
284
  * Optional async credentials provider used for request signing.
280
285
  */
package/dist/index.js CHANGED
@@ -617,7 +617,97 @@ var OpenAICompatibleChatLanguageModel = class {
617
617
  };
618
618
  }
619
619
  async doStream(options) {
620
- var _a;
620
+ var _a, _b, _c;
621
+ const shouldUseNonStreamingUsageFallback = this.providerOptionsName.includes("bedrock") && ((_a = this.config.includeUsage) != null ? _a : false);
622
+ if (shouldUseNonStreamingUsageFallback) {
623
+ const generateResult = await this.doGenerate(options);
624
+ const finishReason2 = this.config.legacyStringFinishReason ? generateResult.finishReason.unified : generateResult.finishReason;
625
+ return {
626
+ stream: new ReadableStream({
627
+ start(controller) {
628
+ controller.enqueue({
629
+ type: "stream-start",
630
+ warnings: generateResult.warnings
631
+ });
632
+ if (generateResult.response != null) {
633
+ controller.enqueue({
634
+ type: "response-metadata",
635
+ id: generateResult.response.id,
636
+ timestamp: generateResult.response.timestamp,
637
+ modelId: generateResult.response.modelId
638
+ });
639
+ }
640
+ let textIndex = 0;
641
+ let reasoningIndex = 0;
642
+ for (const contentPart of generateResult.content) {
643
+ switch (contentPart.type) {
644
+ case "text": {
645
+ const id = `txt-${textIndex++}`;
646
+ controller.enqueue({ type: "text-start", id });
647
+ controller.enqueue({
648
+ type: "text-delta",
649
+ id,
650
+ delta: contentPart.text
651
+ });
652
+ controller.enqueue({ type: "text-end", id });
653
+ break;
654
+ }
655
+ case "reasoning": {
656
+ const id = `reasoning-${reasoningIndex++}`;
657
+ controller.enqueue({ type: "reasoning-start", id });
658
+ controller.enqueue({
659
+ type: "reasoning-delta",
660
+ id,
661
+ delta: contentPart.text,
662
+ ...contentPart.providerMetadata != null ? { providerMetadata: contentPart.providerMetadata } : {}
663
+ });
664
+ controller.enqueue({ type: "reasoning-end", id });
665
+ break;
666
+ }
667
+ case "tool-call": {
668
+ controller.enqueue({
669
+ type: "tool-input-start",
670
+ id: contentPart.toolCallId,
671
+ toolName: contentPart.toolName,
672
+ ...contentPart.providerMetadata != null ? { providerMetadata: contentPart.providerMetadata } : {}
673
+ });
674
+ if (contentPart.input.length > 0) {
675
+ controller.enqueue({
676
+ type: "tool-input-delta",
677
+ id: contentPart.toolCallId,
678
+ delta: contentPart.input,
679
+ ...contentPart.providerMetadata != null ? { providerMetadata: contentPart.providerMetadata } : {}
680
+ });
681
+ }
682
+ controller.enqueue({
683
+ type: "tool-input-end",
684
+ id: contentPart.toolCallId,
685
+ ...contentPart.providerMetadata != null ? { providerMetadata: contentPart.providerMetadata } : {}
686
+ });
687
+ controller.enqueue(contentPart);
688
+ break;
689
+ }
690
+ case "tool-result":
691
+ case "tool-approval-request":
692
+ case "source":
693
+ case "file":
694
+ controller.enqueue(contentPart);
695
+ break;
696
+ }
697
+ }
698
+ controller.enqueue({
699
+ type: "finish",
700
+ finishReason: finishReason2,
701
+ usage: generateResult.usage,
702
+ ...generateResult.providerMetadata != null ? { providerMetadata: generateResult.providerMetadata } : {}
703
+ });
704
+ controller.close();
705
+ }
706
+ }),
707
+ request: generateResult.request,
708
+ response: generateResult.response == null ? void 0 : { headers: generateResult.response.headers }
709
+ };
710
+ }
621
711
  const { args, warnings } = await this.getArgs({ ...options });
622
712
  const body = this.transformRequestBody({
623
713
  ...args,
@@ -625,7 +715,7 @@ var OpenAICompatibleChatLanguageModel = class {
625
715
  // only include stream_options when in strict compatibility mode:
626
716
  stream_options: this.config.includeUsage ? { include_usage: true } : void 0
627
717
  });
628
- const metadataExtractor = (_a = this.config.metadataExtractor) == null ? void 0 : _a.createStreamExtractor();
718
+ const metadataExtractor = (_b = this.config.metadataExtractor) == null ? void 0 : _b.createStreamExtractor();
629
719
  const { responseHeaders, value: response } = await (0, import_provider_utils2.postJsonToApi)({
630
720
  url: this.config.url({
631
721
  path: "/chat/completions",
@@ -648,12 +738,32 @@ var OpenAICompatibleChatLanguageModel = class {
648
738
  let usage = void 0;
649
739
  let isFirstChunk = true;
650
740
  const providerOptionsName = this.providerOptionsName;
651
- const shouldTerminateOnFinishReason = providerOptionsName.includes("bedrock") && !this.config.includeUsage;
741
+ const shouldTerminateOnFinishReason = providerOptionsName.includes("bedrock");
742
+ const includeUsage = (_c = this.config.includeUsage) != null ? _c : false;
652
743
  let isActiveReasoning = false;
653
744
  let isActiveText = false;
654
745
  let hasFinished = false;
746
+ let hasSeenFinishReason = false;
747
+ let forcedFinishTimer;
748
+ const clearForcedFinishTimer = () => {
749
+ if (forcedFinishTimer == null) {
750
+ return;
751
+ }
752
+ clearTimeout(forcedFinishTimer);
753
+ forcedFinishTimer = void 0;
754
+ };
755
+ const scheduleForcedFinish = (controller) => {
756
+ clearForcedFinishTimer();
757
+ forcedFinishTimer = setTimeout(() => {
758
+ if (hasFinished) {
759
+ return;
760
+ }
761
+ emitFinish(controller);
762
+ controller.terminate();
763
+ }, 750);
764
+ };
655
765
  const emitFinish = (controller) => {
656
- var _a2, _b, _c, _d, _e;
766
+ var _a2, _b2, _c2, _d, _e;
657
767
  if (hasFinished) {
658
768
  return;
659
769
  }
@@ -690,8 +800,8 @@ var OpenAICompatibleChatLanguageModel = class {
690
800
  [providerOptionsName]: {},
691
801
  ...metadataExtractor == null ? void 0 : metadataExtractor.buildMetadata()
692
802
  };
693
- if (((_b = usage == null ? void 0 : usage.completion_tokens_details) == null ? void 0 : _b.accepted_prediction_tokens) != null) {
694
- providerMetadata[providerOptionsName].acceptedPredictionTokens = (_c = usage == null ? void 0 : usage.completion_tokens_details) == null ? void 0 : _c.accepted_prediction_tokens;
803
+ if (((_b2 = usage == null ? void 0 : usage.completion_tokens_details) == null ? void 0 : _b2.accepted_prediction_tokens) != null) {
804
+ providerMetadata[providerOptionsName].acceptedPredictionTokens = (_c2 = usage == null ? void 0 : usage.completion_tokens_details) == null ? void 0 : _c2.accepted_prediction_tokens;
695
805
  }
696
806
  if (((_d = usage == null ? void 0 : usage.completion_tokens_details) == null ? void 0 : _d.rejected_prediction_tokens) != null) {
697
807
  providerMetadata[providerOptionsName].rejectedPredictionTokens = (_e = usage == null ? void 0 : usage.completion_tokens_details) == null ? void 0 : _e.rejected_prediction_tokens;
@@ -712,7 +822,7 @@ var OpenAICompatibleChatLanguageModel = class {
712
822
  controller.enqueue({ type: "stream-start", warnings });
713
823
  },
714
824
  transform(chunk, controller) {
715
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
825
+ var _a2, _b2, _c2, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
716
826
  if (options.includeRawChunks) {
717
827
  controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
718
828
  }
@@ -740,17 +850,28 @@ var OpenAICompatibleChatLanguageModel = class {
740
850
  }
741
851
  if (value.usage != null) {
742
852
  usage = value.usage;
853
+ if (shouldTerminateOnFinishReason && hasSeenFinishReason && !hasFinished) {
854
+ clearForcedFinishTimer();
855
+ emitFinish(controller);
856
+ controller.terminate();
857
+ return;
858
+ }
743
859
  }
744
860
  const choice = value.choices[0];
745
861
  if ((choice == null ? void 0 : choice.finish_reason) != null) {
862
+ hasSeenFinishReason = true;
746
863
  finishReason = {
747
864
  unified: mapOpenAICompatibleFinishReason(choice.finish_reason),
748
865
  raw: (_a2 = choice.finish_reason) != null ? _a2 : void 0
749
866
  };
750
867
  if (shouldTerminateOnFinishReason) {
751
- emitFinish(controller);
752
- controller.terminate();
753
- return;
868
+ if (!includeUsage || usage != null) {
869
+ clearForcedFinishTimer();
870
+ emitFinish(controller);
871
+ controller.terminate();
872
+ return;
873
+ }
874
+ scheduleForcedFinish(controller);
754
875
  }
755
876
  }
756
877
  if ((choice == null ? void 0 : choice.delta) == null) {
@@ -799,7 +920,7 @@ var OpenAICompatibleChatLanguageModel = class {
799
920
  isActiveReasoning = false;
800
921
  }
801
922
  for (const toolCallDelta of delta.tool_calls) {
802
- const index = (_b = toolCallDelta.index) != null ? _b : toolCalls.length;
923
+ const index = (_b2 = toolCallDelta.index) != null ? _b2 : toolCalls.length;
803
924
  if (toolCalls[index] == null) {
804
925
  if (toolCallDelta.id == null) {
805
926
  throw new import_provider3.InvalidResponseDataError({
@@ -807,7 +928,7 @@ var OpenAICompatibleChatLanguageModel = class {
807
928
  message: `Expected 'id' to be a string.`
808
929
  });
809
930
  }
810
- if (((_c = toolCallDelta.function) == null ? void 0 : _c.name) == null) {
931
+ if (((_c2 = toolCallDelta.function) == null ? void 0 : _c2.name) == null) {
811
932
  throw new import_provider3.InvalidResponseDataError({
812
933
  data: toolCallDelta,
813
934
  message: `Expected 'function.name' to be a string.`
@@ -896,6 +1017,7 @@ var OpenAICompatibleChatLanguageModel = class {
896
1017
  }
897
1018
  },
898
1019
  flush(controller) {
1020
+ clearForcedFinishTimer();
899
1021
  emitFinish(controller);
900
1022
  }
901
1023
  })
@@ -1705,7 +1827,7 @@ var import_provider_utils6 = require("@ai-sdk/provider-utils");
1705
1827
  var import_aws4fetch = require("aws4fetch");
1706
1828
 
1707
1829
  // src/version.ts
1708
- var VERSION = true ? "2.0.30" : "0.0.0-test";
1830
+ var VERSION = true ? "2.0.32" : "0.0.0-test";
1709
1831
 
1710
1832
  // src/bedrock-mantle-sigv4-fetch.ts
1711
1833
  function createMantleSigV4FetchFunction(getCredentials, fetch = globalThis.fetch) {
@@ -1772,8 +1894,132 @@ function prepareBodyString(body) {
1772
1894
  return JSON.stringify(body);
1773
1895
  }
1774
1896
 
1897
+ // src/load-aws-profile-credentials.ts
1898
+ var import_promises = require("fs/promises");
1899
+ var import_node_os = require("os");
1900
+ var import_node_path = require("path");
1901
+ var import_node_child_process = require("child_process");
1902
+ var import_node_util = require("util");
1903
+ var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
1904
+ async function loadAwsProfileCredentials({
1905
+ profile,
1906
+ credentialsFilePath,
1907
+ configFilePath
1908
+ }) {
1909
+ var _a, _b, _c;
1910
+ const sharedCredentialsPath = (_a = credentialsFilePath != null ? credentialsFilePath : process.env.AWS_SHARED_CREDENTIALS_FILE) != null ? _a : (0, import_node_path.join)((0, import_node_os.homedir)(), ".aws", "credentials");
1911
+ const sharedConfigPath = (_b = configFilePath != null ? configFilePath : process.env.AWS_CONFIG_FILE) != null ? _b : (0, import_node_path.join)((0, import_node_os.homedir)(), ".aws", "config");
1912
+ const [credentialsIni, configIni] = await Promise.all([
1913
+ readIniFile(sharedCredentialsPath),
1914
+ readIniFile(sharedConfigPath)
1915
+ ]);
1916
+ const credentialsSection = credentialsIni == null ? void 0 : credentialsIni[profile];
1917
+ const configSection = configIni == null ? void 0 : configIni[profile === "default" ? "default" : `profile ${profile}`];
1918
+ if (credentialsSection == null && configSection == null) {
1919
+ return loadCredentialsViaAwsCli(profile);
1920
+ }
1921
+ const accessKeyId = credentialsSection == null ? void 0 : credentialsSection.aws_access_key_id;
1922
+ const secretAccessKey = credentialsSection == null ? void 0 : credentialsSection.aws_secret_access_key;
1923
+ if (accessKeyId == null || secretAccessKey == null) {
1924
+ return loadCredentialsViaAwsCli(profile);
1925
+ }
1926
+ const sessionToken = credentialsSection == null ? void 0 : credentialsSection.aws_session_token;
1927
+ const region = (_c = credentialsSection == null ? void 0 : credentialsSection.region) != null ? _c : configSection == null ? void 0 : configSection.region;
1928
+ return {
1929
+ accessKeyId,
1930
+ secretAccessKey,
1931
+ sessionToken,
1932
+ region
1933
+ };
1934
+ }
1935
+ async function loadCredentialsViaAwsCli(profile) {
1936
+ try {
1937
+ const { stdout } = await execFileAsync(
1938
+ "aws",
1939
+ [
1940
+ "configure",
1941
+ "export-credentials",
1942
+ "--profile",
1943
+ profile,
1944
+ "--format",
1945
+ "process"
1946
+ ],
1947
+ {
1948
+ timeout: 5e3
1949
+ }
1950
+ );
1951
+ const parsed = parseProcessCredentials(stdout);
1952
+ if (parsed == null) {
1953
+ return void 0;
1954
+ }
1955
+ return {
1956
+ accessKeyId: parsed.accessKeyId,
1957
+ secretAccessKey: parsed.secretAccessKey,
1958
+ sessionToken: parsed.sessionToken
1959
+ };
1960
+ } catch (e) {
1961
+ return void 0;
1962
+ }
1963
+ }
1964
+ function parseProcessCredentials(value) {
1965
+ try {
1966
+ const parsed = JSON.parse(value);
1967
+ if (parsed.AccessKeyId == null || parsed.SecretAccessKey == null) {
1968
+ return void 0;
1969
+ }
1970
+ return {
1971
+ accessKeyId: parsed.AccessKeyId,
1972
+ secretAccessKey: parsed.SecretAccessKey,
1973
+ sessionToken: parsed.SessionToken
1974
+ };
1975
+ } catch (e) {
1976
+ return void 0;
1977
+ }
1978
+ }
1979
+ async function readIniFile(filePath) {
1980
+ try {
1981
+ const contents = await (0, import_promises.readFile)(filePath, "utf8");
1982
+ return parseIni(contents);
1983
+ } catch (error) {
1984
+ if (error != null && typeof error === "object" && "code" in error && error.code === "ENOENT") {
1985
+ return void 0;
1986
+ }
1987
+ throw error;
1988
+ }
1989
+ }
1990
+ function parseIni(contents) {
1991
+ var _a;
1992
+ const sections = {};
1993
+ let currentSection;
1994
+ for (const rawLine of contents.split(/\r?\n/u)) {
1995
+ const line = rawLine.trim();
1996
+ if (line.length === 0 || line.startsWith("#") || line.startsWith(";")) {
1997
+ continue;
1998
+ }
1999
+ if (line.startsWith("[") && line.endsWith("]")) {
2000
+ currentSection = line.slice(1, -1).trim();
2001
+ (_a = sections[currentSection]) != null ? _a : sections[currentSection] = {};
2002
+ continue;
2003
+ }
2004
+ if (currentSection == null) {
2005
+ continue;
2006
+ }
2007
+ const delimiterIndex = line.indexOf("=");
2008
+ if (delimiterIndex === -1) {
2009
+ continue;
2010
+ }
2011
+ const key = line.slice(0, delimiterIndex).trim();
2012
+ const value = line.slice(delimiterIndex + 1).trim();
2013
+ if (key.length > 0) {
2014
+ sections[currentSection][key] = value;
2015
+ }
2016
+ }
2017
+ return sections;
2018
+ }
2019
+
1775
2020
  // src/openai-compatible-provider.ts
1776
2021
  function createOpenAICompatible(options) {
2022
+ var _a;
1777
2023
  const baseURL = (0, import_provider_utils7.withoutTrailingSlash)(options.baseURL);
1778
2024
  const providerName = options.name;
1779
2025
  const headers = {
@@ -1783,10 +2029,18 @@ function createOpenAICompatible(options) {
1783
2029
  const hasAuthorizationHeader = Object.keys(headers).some(
1784
2030
  (key) => key.toLowerCase() === "authorization"
1785
2031
  );
2032
+ const profile = (_a = options.profile) != null ? _a : (0, import_provider_utils7.loadOptionalSetting)({
2033
+ settingValue: options.profile,
2034
+ environmentVariableName: "AWS_PROFILE"
2035
+ });
2036
+ const profileCredentialsPromise = profile == null ? void 0 : loadAwsProfileCredentials({
2037
+ profile
2038
+ });
1786
2039
  const getHeaders = () => (0, import_provider_utils7.withUserAgentSuffix)(headers, `ai-sdk/openai-compatible/${VERSION}`);
1787
2040
  const sigV4Fetch = createMantleSigV4FetchFunction(async () => {
1788
- var _a;
1789
- const resolvedRegion = (_a = options.region) != null ? _a : (0, import_provider_utils7.loadSetting)({
2041
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
2042
+ const profileCredentials = await profileCredentialsPromise;
2043
+ const resolvedRegion = (_b = (_a2 = options.region) != null ? _a2 : profileCredentials == null ? void 0 : profileCredentials.region) != null ? _b : (0, import_provider_utils7.loadSetting)({
1790
2044
  settingValue: options.region,
1791
2045
  settingName: "region",
1792
2046
  environmentVariableName: "AWS_REGION",
@@ -1801,19 +2055,19 @@ function createOpenAICompatible(options) {
1801
2055
  }
1802
2056
  return {
1803
2057
  region: resolvedRegion,
1804
- accessKeyId: (0, import_provider_utils7.loadSetting)({
2058
+ accessKeyId: (_d = (_c = options.accessKeyId) != null ? _c : profileCredentials == null ? void 0 : profileCredentials.accessKeyId) != null ? _d : (0, import_provider_utils7.loadSetting)({
1805
2059
  settingValue: options.accessKeyId,
1806
2060
  settingName: "accessKeyId",
1807
2061
  environmentVariableName: "AWS_ACCESS_KEY_ID",
1808
2062
  description: "AWS access key ID"
1809
2063
  }),
1810
- secretAccessKey: (0, import_provider_utils7.loadSetting)({
2064
+ secretAccessKey: (_f = (_e = options.secretAccessKey) != null ? _e : profileCredentials == null ? void 0 : profileCredentials.secretAccessKey) != null ? _f : (0, import_provider_utils7.loadSetting)({
1811
2065
  settingValue: options.secretAccessKey,
1812
2066
  settingName: "secretAccessKey",
1813
2067
  environmentVariableName: "AWS_SECRET_ACCESS_KEY",
1814
2068
  description: "AWS secret access key"
1815
2069
  }),
1816
- sessionToken: (0, import_provider_utils7.loadOptionalSetting)({
2070
+ sessionToken: (_h = (_g = options.sessionToken) != null ? _g : profileCredentials == null ? void 0 : profileCredentials.sessionToken) != null ? _h : (0, import_provider_utils7.loadOptionalSetting)({
1817
2071
  settingValue: options.sessionToken,
1818
2072
  environmentVariableName: "AWS_SESSION_TOKEN"
1819
2073
  })