From 8effb557d56593edec5a71b2e7eb41e1113ff3fa Mon Sep 17 00:00:00 2001 From: Alex Fallah Date: Fri, 23 Jan 2026 16:50:30 -0500 Subject: [PATCH] feat: add dynamic Bedrock model discovery Add automatic discovery of AWS Bedrock models using ListFoundationModels API. When AWS credentials are detected, models that support streaming and text output are automatically discovered and made available. - Add @aws-sdk/client-bedrock dependency - Add discoverBedrockModels() with caching (default 1 hour) - Add resolveImplicitBedrockProvider() for auto-registration - Add BedrockDiscoveryConfig for optional filtering by provider/region - Filter to active, streaming, text-output models only - Update docs/bedrock.md with auto-discovery documentation --- docs/bedrock.md | 28 ++ package.json | 1 + pnpm-lock.yaml | 577 +++++++++++++++++++++++++- src/agents/bedrock-discovery.test.ts | 96 +++++ src/agents/bedrock-discovery.ts | 184 ++++++++ src/agents/models-config.providers.ts | 25 ++ src/agents/models-config.ts | 8 + src/commands/models.list.test.ts | 2 + src/commands/models/list.registry.ts | 7 +- src/config/types.models.ts | 8 + src/config/zod-schema.core.ts | 11 + 11 files changed, 944 insertions(+), 3 deletions(-) create mode 100644 src/agents/bedrock-discovery.test.ts create mode 100644 src/agents/bedrock-discovery.ts diff --git a/docs/bedrock.md b/docs/bedrock.md index 6967c2f94..f9fb602c0 100644 --- a/docs/bedrock.md +++ b/docs/bedrock.md @@ -17,6 +17,33 @@ not an API key. - Auth: AWS credentials (env vars, shared config, or instance role) - Region: `AWS_REGION` or `AWS_DEFAULT_REGION` (default: `us-east-1`) +## Automatic model discovery + +If AWS credentials are detected, Clawdbot can automatically discover Bedrock +models that support **streaming** and **text output**. Discovery uses +`bedrock:ListFoundationModels` and is cached (default: 1 hour). + +Config options live under `models.bedrockDiscovery`: + +```json5 +{ + models: { + bedrockDiscovery: { + enabled: true, + region: "us-east-1", + providerFilter: ["anthropic", "amazon"], + refreshInterval: 3600 + } + } +} +``` + +Notes: +- `enabled` defaults to `true` when AWS credentials are present. +- `region` defaults to `AWS_REGION` or `AWS_DEFAULT_REGION`, then `us-east-1`. +- `providerFilter` matches Bedrock provider names (for example `anthropic`). +- `refreshInterval` is seconds; set to `0` to disable caching. + ## Setup (manual) 1) Ensure AWS credentials are available on the **gateway host**: @@ -67,6 +94,7 @@ export AWS_BEARER_TOKEN_BEDROCK="..." ## Notes - Bedrock requires **model access** enabled in your AWS account/region. +- Automatic discovery needs the `bedrock:ListFoundationModels` permission. - If you use profiles, set `AWS_PROFILE` on the gateway host. - Clawdbot surfaces the credential source in this order: `AWS_BEARER_TOKEN_BEDROCK`, then `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY`, then `AWS_PROFILE`, then the diff --git a/package.json b/package.json index f12d83a74..2e979e28d 100644 --- a/package.json +++ b/package.json @@ -147,6 +147,7 @@ "packageManager": "pnpm@10.23.0", "dependencies": { "@agentclientprotocol/sdk": "0.13.0", + "@aws-sdk/client-bedrock": "^3.975.0", "@buape/carbon": "0.14.0", "@clack/prompts": "^0.11.0", "@grammyjs/runner": "^2.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f2ac16e31..c170870dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,6 +16,9 @@ importers: '@agentclientprotocol/sdk': specifier: 0.13.0 version: 0.13.0(zod@4.3.5) + '@aws-sdk/client-bedrock': + specifier: ^3.975.0 + version: 3.975.0 '@buape/carbon': specifier: 0.14.0 version: 0.14.0(hono@4.11.4) @@ -493,46 +496,90 @@ packages: resolution: {integrity: sha512-rzSuqgMkL488bR9TnZEALBa+SV1FfR3B7CkYvs6R5uZm2AqBMfq7xNZR/pgMiAH/YLlI9FWAh1aPmdnG7iXxnA==} engines: {node: '>=20.0.0'} + '@aws-sdk/client-bedrock@3.975.0': + resolution: {integrity: sha512-rA30CX0zcTGKx0S8JSyASVKFYTdQmkDkpkE5o1Mv4j3RmLcp7J2/WeYGVLjWprkNjlAlfpxG3V9VqPsayQ3LzA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/client-sso@3.972.0': resolution: {integrity: sha512-5qw6qLiRE4SUiz0hWy878dSR13tSVhbTWhsvFT8mGHe37NRRiaobm5MA2sWD0deRAuO98djSiV+dhWXa1xIFNw==} engines: {node: '>=20.0.0'} + '@aws-sdk/client-sso@3.974.0': + resolution: {integrity: sha512-ci+GiM0c4ULo4D79UMcY06LcOLcfvUfiyt8PzNY0vbt5O8BfCPYf4QomwVgkNcLLCYmroO4ge2Yy1EsLUlcD6g==} + engines: {node: '>=20.0.0'} + '@aws-sdk/core@3.972.0': resolution: {integrity: sha512-nEeUW2M9F+xdIaD98F5MBcQ4ITtykj3yKbgFZ6J0JtL3bq+Z90szQ6Yy8H/BLPYXTs3V4n9ifnBo8cprRDiE6A==} engines: {node: '>=20.0.0'} + '@aws-sdk/core@3.973.1': + resolution: {integrity: sha512-Ocubx42QsMyVs9ANSmFpRm0S+hubWljpPLjOi9UFrtcnVJjrVJTzQ51sN0e5g4e8i8QZ7uY73zosLmgYL7kZTQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-env@3.972.0': resolution: {integrity: sha512-kKHoNv+maHlPQOAhYamhap0PObd16SAb3jwaY0KYgNTiSbeXlbGUZPLioo9oA3wU10zItJzx83ClU7d7h40luA==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-env@3.972.1': + resolution: {integrity: sha512-/etNHqnx96phy/SjI0HRC588o4vKH5F0xfkZ13yAATV7aNrb+5gYGNE6ePWafP+FuZ3HkULSSlJFj0AxgrAqYw==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-http@3.972.0': resolution: {integrity: sha512-xzEi81L7I5jGUbpmqEHCe7zZr54hCABdj4H+3LzktHYuovV/oqnvoDdvZpGFR0e/KAw1+PL38NbGrpG30j6qlA==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-http@3.972.2': + resolution: {integrity: sha512-mXgdaUfe5oM+tWKyeZ7Vh/iQ94FrkMky1uuzwTOmFADiRcSk5uHy/e3boEFedXiT/PRGzgBmqvJVK4F6lUISCg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-ini@3.972.0': resolution: {integrity: sha512-ruhAMceUIq2aknFd3jhWxmO0P0Efab5efjyIXOkI9i80g+zDY5VekeSxfqRKStEEJSKSCHDLQuOu0BnAn4Rzew==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-ini@3.972.1': + resolution: {integrity: sha512-OdbJA3v+XlNDsrYzNPRUwr8l7gw1r/nR8l4r96MDzSBDU8WEo8T6C06SvwaXR8SpzsjO3sq5KMP86wXWg7Rj4g==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-login@3.972.0': resolution: {integrity: sha512-SsrsFJsEYAJHO4N/r2P0aK6o8si6f1lprR+Ej8J731XJqTckSGs/HFHcbxOyW/iKt+LNUvZa59/VlJmjhF4bEQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-login@3.972.1': + resolution: {integrity: sha512-CccqDGL6ZrF3/EFWZefvKW7QwwRdxlHUO8NVBKNVcNq6womrPDvqB6xc9icACtE0XB0a7PLoSTkAg8bQVkTO2w==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-node@3.972.0': resolution: {integrity: sha512-wwJDpEGl6+sOygic8QKu0OHVB8SiodqF1fr5jvUlSFfS6tJss/E9vBc2aFjl7zI6KpAIYfIzIgM006lRrZtWCQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-node@3.972.1': + resolution: {integrity: sha512-DwXPk9GfuU/xG9tmCyXFVkCr6X3W8ZCoL5Ptb0pbltEx1/LCcg7T+PBqDlPiiinNCD6ilIoMJDWsnJ8ikzZA7Q==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-process@3.972.0': resolution: {integrity: sha512-nmzYhamLDJ8K+v3zWck79IaKMc350xZnWsf/GeaXO6E3MewSzd3lYkTiMi7lEp3/UwDm9NHfPguoPm+mhlSWQQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-process@3.972.1': + resolution: {integrity: sha512-bi47Zigu3692SJwdBvo8y1dEwE6B61stCwCFnuRWJVTfiM84B+VTSCV661CSWJmIZzmcy7J5J3kWyxL02iHj0w==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-sso@3.972.0': resolution: {integrity: sha512-6mYyfk1SrMZ15cH9T53yAF4YSnvq4yU1Xlgm3nqV1gZVQzmF5kr4t/F3BU3ygbvzi4uSwWxG3I3TYYS5eMlAyg==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-sso@3.972.1': + resolution: {integrity: sha512-dLZVNhM7wSgVUFsgVYgI5hb5Z/9PUkT46pk/SHrSmUqfx6YDvoV4YcPtaiRqviPpEGGiRtdQMEadyOKIRqulUQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.0': resolution: {integrity: sha512-vsJXBGL8H54kz4T6do3p5elATj5d1izVGUXMluRJntm9/I0be/zUYtdd4oDTM2kSUmd4Zhyw3fMQ9lw7CVhd4A==} engines: {node: '>=20.0.0'} + '@aws-sdk/credential-provider-web-identity@3.972.1': + resolution: {integrity: sha512-YMDeYgi0u687Ay0dAq/pFPKuijrlKTgsaB/UATbxCs/FzZfMiG4If5ksywHmmW7MiYUF8VVv+uou3TczvLrN4w==} + engines: {node: '>=20.0.0'} + '@aws-sdk/eventstream-handler-node@3.972.0': resolution: {integrity: sha512-B1AEv+TQOVxg2t60GMfrcagJvQjpx1p6UASUoFMLevV9K3WNI5qYTjtutMiifKY0HwK6g86zXgN/dpeaSi3q5Q==} engines: {node: '>=20.0.0'} @@ -545,18 +592,34 @@ packages: resolution: {integrity: sha512-3eztFI6F9/eHtkIaWKN3nT+PM+eQ6p1MALDuNshFk323ixuCZzOOVT8oUqtZa30Z6dycNXJwhlIq7NhUVFfimw==} engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-host-header@3.972.1': + resolution: {integrity: sha512-/R82lXLPmZ9JaUGSUdKtBp2k/5xQxvBT3zZWyKiBOhyulFotlfvdlrO8TnqstBimsl4lYEYySDL+W6ldFh6ALg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-logger@3.972.0': resolution: {integrity: sha512-ZvdyVRwzK+ra31v1pQrgbqR/KsLD+wwJjHgko6JfoKUBIcEfAwJzQKO6HspHxdHWTVUz6MgvwskheR/TTYZl2g==} engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-logger@3.972.1': + resolution: {integrity: sha512-JGgFl6cHg9G2FHu4lyFIzmFN8KESBiRr84gLC3Aeni0Gt1nKm+KxWLBuha/RPcXxJygGXCcMM4AykkIwxor8RA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-recursion-detection@3.972.0': resolution: {integrity: sha512-F2SmUeO+S6l1h6dydNet3BQIk173uAkcfU1HDkw/bUdRLAnh15D3HP9vCZ7oCPBNcdEICbXYDmx0BR9rRUHGlQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-recursion-detection@3.972.1': + resolution: {integrity: sha512-taGzNRe8vPHjnliqXIHp9kBgIemLE/xCaRTMH1NH0cncHeaPcjxtnCroAAM9aOlPuKvBe2CpZESyvM1+D8oI7Q==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-user-agent@3.972.0': resolution: {integrity: sha512-kFHQm2OCBJCzGWRafgdWHGFjitUXY/OxXngymcX4l8CiyiNDZB27HDDBg2yLj3OUJc4z4fexLMmP8r9vgag19g==} engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-user-agent@3.972.2': + resolution: {integrity: sha512-d+Exq074wy0X6wvShg/kmZVtkah+28vMuqCtuY3cydg8LUZOJBtbAolCpEJizSyb8mJJZF9BjWaTANXL4OYnkg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/middleware-websocket@3.972.0': resolution: {integrity: sha512-3pvbb/HtE7A8U38jk24RQ9T92d40NNSzjDEVEkBYZYhxExVcJ/Lk5Z+NM283FEtoi1T++oYrLuYDr1CIQxnaXQ==} engines: {node: '>= 14.0.0'} @@ -565,18 +628,42 @@ packages: resolution: {integrity: sha512-QGlbnuGzSQJVG6bR9Qw6G0Blh6abFR4VxNa61ttMbzy9jt28xmk2iGtrYLrQPlCCPhY6enHqjTWm3n3LOb0wAw==} engines: {node: '>=20.0.0'} + '@aws-sdk/nested-clients@3.974.0': + resolution: {integrity: sha512-k3dwdo/vOiHMJc9gMnkPl1BA5aQfTrZbz+8fiDkWrPagqAioZgmo5oiaOaeX0grObfJQKDtcpPFR4iWf8cgl8Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/nested-clients@3.975.0': + resolution: {integrity: sha512-OkeFHPlQj2c/Y5bQGkX14pxhDWUGUFt3LRHhjcDKsSCw6lrxKcxN3WFZN0qbJwKNydP+knL5nxvfgKiCLpTLRA==} + engines: {node: '>=20.0.0'} + '@aws-sdk/region-config-resolver@3.972.0': resolution: {integrity: sha512-JyOf+R/6vJW8OEVFCAyzEOn2reri/Q+L0z9zx4JQSKWvTmJ1qeFO25sOm8VIfB8URKhfGRTQF30pfYaH2zxt/A==} engines: {node: '>=20.0.0'} + '@aws-sdk/region-config-resolver@3.972.1': + resolution: {integrity: sha512-voIY8RORpxLAEgEkYaTFnkaIuRwVBEc+RjVZYcSSllPV+ZEKAacai6kNhJeE3D70Le+JCfvRb52tng/AVHY+jQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/token-providers@3.972.0': resolution: {integrity: sha512-kWlXG+y5nZhgXGEtb72Je+EvqepBPs8E3vZse//1PYLWs2speFqbGE/ywCXmzEJgHgVqSB/u/lqBvs5WlYmSqQ==} engines: {node: '>=20.0.0'} + '@aws-sdk/token-providers@3.974.0': + resolution: {integrity: sha512-cBykL0LiccKIgNhGWvQRTPvsBLPZxnmJU3pYxG538jpFX8lQtrCy1L7mmIHNEdxIdIGEPgAEHF8/JQxgBToqUQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.975.0': + resolution: {integrity: sha512-AWQt64hkVbDQ+CmM09wnvSk2mVyH4iRROkmYkr3/lmUtFNbE2L/fnw26sckZnUcFCsHPqbkQrcsZAnTcBLbH4w==} + engines: {node: '>=20.0.0'} + '@aws-sdk/types@3.972.0': resolution: {integrity: sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==} engines: {node: '>=20.0.0'} + '@aws-sdk/types@3.973.0': + resolution: {integrity: sha512-jYIdB7a7jhRTvyb378nsjyvJh1Si+zVduJ6urMNGpz8RjkmHZ+9vM2H07XaIB2Cfq0GhJRZYOfUCH8uqQhqBkQ==} + engines: {node: '>=20.0.0'} + '@aws-sdk/util-endpoints@3.972.0': resolution: {integrity: sha512-6JHsl1V/a1ZW8D8AFfd4R52fwZPnZ5H4U6DS8m/bWT8qad72NvbOFAC7U2cDtFs2TShqUO3TEiX/EJibtY3ijg==} engines: {node: '>=20.0.0'} @@ -592,6 +679,9 @@ packages: '@aws-sdk/util-user-agent-browser@3.972.0': resolution: {integrity: sha512-eOLdkQyoRbDgioTS3Orr7iVsVEutJyMZxvyZ6WAF95IrF0kfWx5Rd/KXnfbnG/VKa2CvjZiitWfouLzfVEyvJA==} + '@aws-sdk/util-user-agent-browser@3.972.1': + resolution: {integrity: sha512-IgF55NFmJX8d9Wql9M0nEpk2eYbuD8G4781FN4/fFgwTXBn86DvlZJuRWDCMcMqZymnBVX7HW9r+3r9ylqfW0w==} + '@aws-sdk/util-user-agent-node@3.972.0': resolution: {integrity: sha512-GOy+AiSrE9kGiojiwlZvVVSXwylu4+fmP0MJfvras/MwP09RB/YtQuOVR1E0fKQc6OMwaTNBjgAbOEhxuWFbAw==} engines: {node: '>=20.0.0'} @@ -601,10 +691,23 @@ packages: aws-crt: optional: true + '@aws-sdk/util-user-agent-node@3.972.1': + resolution: {integrity: sha512-oIs4JFcADzoZ0c915R83XvK2HltWupxNsXUIuZse2rgk7b97zTpkxaqXiH0h9ylh31qtgo/t8hp4tIqcsMrEbQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + '@aws-sdk/xml-builder@3.972.0': resolution: {integrity: sha512-POaGMcXnozzqBUyJM3HLUZ9GR6OKJWPGJEmhtTnxZXt8B6JcJ/6K3xRJ5H/j8oovVLz8Wg6vFxAHv8lvuASxMg==} engines: {node: '>=20.0.0'} + '@aws-sdk/xml-builder@3.972.1': + resolution: {integrity: sha512-6zZGlPOqn7Xb+25MAXGb1JhgvaC5HjZj6GzszuVrnEgbhvzBRFGKYemuHBV4bho+dtqeYKPgaZUv7/e80hIGNg==} + engines: {node: '>=20.0.0'} + '@aws/lambda-invoke-store@0.2.3': resolution: {integrity: sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==} engines: {node: '>=18.0.0'} @@ -2221,6 +2324,10 @@ packages: resolution: {integrity: sha512-bg2TfzgsERyETAxc/Ims/eJX8eAnIeTi4r4LHpMpfF/2NyO6RsWis0rjKcCPaGksljmOb23BZRiCeT/3NvwkXw==} engines: {node: '>=18.0.0'} + '@smithy/core@3.21.1': + resolution: {integrity: sha512-NUH8R4O6FkN8HKMojzbGg/5pNjsfTjlMmeFclyPfPaXXUrbr5TzhWgbf7t92wfrpCHRgpjyz7ffASIS3wX28aA==} + engines: {node: '>=18.0.0'} + '@smithy/credential-provider-imds@4.2.8': resolution: {integrity: sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw==} engines: {node: '>=18.0.0'} @@ -2273,10 +2380,18 @@ packages: resolution: {integrity: sha512-kwWpNltpxrvPabnjEFvwSmA+66l6s2ReCvgVSzW/z92LU4T28fTdgZ18IdYRYOrisu2NMQ0jUndRScbO65A/zg==} engines: {node: '>=18.0.0'} + '@smithy/middleware-endpoint@4.4.11': + resolution: {integrity: sha512-/WqsrycweGGfb9sSzME4CrsuayjJF6BueBmkKlcbeU5q18OhxRrvvKlmfw3tpDsK5ilx2XUJvoukwxHB0nHs/Q==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-retry@4.4.26': resolution: {integrity: sha512-ozZMoTAr+B2aVYfLYfkssFvc8ZV3p/vLpVQ7/k277xxUOA9ykSPe5obL2j6yHfbdrM/SZV7qj0uk/hSqavHrLw==} engines: {node: '>=18.0.0'} + '@smithy/middleware-retry@4.4.27': + resolution: {integrity: sha512-xFUYCGRVsfgiN5EjsJJSzih9+yjStgMTCLANPlf0LVQkPDYCe0hz97qbdTZosFOiYlGBlHYityGRxrQ/hxhfVQ==} + engines: {node: '>=18.0.0'} + '@smithy/middleware-serde@4.2.9': resolution: {integrity: sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ==} engines: {node: '>=18.0.0'} @@ -2325,6 +2440,10 @@ packages: resolution: {integrity: sha512-6o804SCyHGMXAb5mFJ+iTy9kVKv7F91a9szN0J+9X6p8A0NrdpUxdaC57aye2ipQkP2C4IAqETEpGZ0Zj77Haw==} engines: {node: '>=18.0.0'} + '@smithy/smithy-client@4.10.12': + resolution: {integrity: sha512-VKO/HKoQ5OrSHW6AJUmEnUKeXI1/5LfCwO9cwyao7CmLvGnZeM1i36Lyful3LK1XU7HwTVieTqO1y2C/6t3qtA==} + engines: {node: '>=18.0.0'} + '@smithy/types@4.12.0': resolution: {integrity: sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==} engines: {node: '>=18.0.0'} @@ -2361,10 +2480,18 @@ packages: resolution: {integrity: sha512-8ugoNMtss2dJHsXnqsibGPqoaafvWJPACmYKxJ4E6QWaDrixsAemmiMMAVbvwYadjR0H9G2+AlzsInSzRi8PSw==} engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-browser@4.3.26': + resolution: {integrity: sha512-vva0dzYUTgn7DdE0uaha10uEdAgmdLnNFowKFjpMm6p2R0XDk5FHPX3CBJLzWQkQXuEprsb0hGz9YwbicNWhjw==} + engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-node@4.2.28': resolution: {integrity: sha512-mjUdcP8h3E0K/XvNMi9oBXRV3DMCzeRiYIieZ1LQ7jq5tu6GH/GTWym7a1xIIE0pKSoLcpGsaImuQhGPSIJzAA==} engines: {node: '>=18.0.0'} + '@smithy/util-defaults-mode-node@4.2.29': + resolution: {integrity: sha512-c6D7IUBsZt/aNnTBHMTf+OVh+h/JcxUUgfTcIJaWRe6zhOum1X+pNKSZtZ+7fbOn5I99XVFtmrnXKv8yHHErTQ==} + engines: {node: '>=18.0.0'} + '@smithy/util-endpoints@3.2.8': resolution: {integrity: sha512-8JaVTn3pBDkhZgHQ8R0epwWt+BqPSLCjdjXXusK1onwJlRuN69fbvSK66aIKKO7SwVFM6x2J2ox5X8pOaWcUEw==} engines: {node: '>=18.0.0'} @@ -5331,7 +5458,7 @@ snapshots: '@aws-crypto/sha256-js': 5.2.0 '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.972.0 + '@aws-sdk/types': 3.973.0 '@aws-sdk/util-locate-window': 3.965.3 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -5339,7 +5466,7 @@ snapshots: '@aws-crypto/sha256-js@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.972.0 + '@aws-sdk/types': 3.973.0 tslib: 2.8.1 '@aws-crypto/supports-web-crypto@5.2.0': @@ -5404,6 +5531,51 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/client-bedrock@3.975.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.1 + '@aws-sdk/credential-provider-node': 3.972.1 + '@aws-sdk/middleware-host-header': 3.972.1 + '@aws-sdk/middleware-logger': 3.972.1 + '@aws-sdk/middleware-recursion-detection': 3.972.1 + '@aws-sdk/middleware-user-agent': 3.972.2 + '@aws-sdk/region-config-resolver': 3.972.1 + '@aws-sdk/token-providers': 3.975.0 + '@aws-sdk/types': 3.973.0 + '@aws-sdk/util-endpoints': 3.972.0 + '@aws-sdk/util-user-agent-browser': 3.972.1 + '@aws-sdk/util-user-agent-node': 3.972.1 + '@smithy/config-resolver': 4.4.6 + '@smithy/core': 3.21.1 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/hash-node': 4.2.8 + '@smithy/invalid-dependency': 4.2.8 + '@smithy/middleware-content-length': 4.2.8 + '@smithy/middleware-endpoint': 4.4.11 + '@smithy/middleware-retry': 4.4.27 + '@smithy/middleware-serde': 4.2.9 + '@smithy/middleware-stack': 4.2.8 + '@smithy/node-config-provider': 4.3.8 + '@smithy/node-http-handler': 4.4.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.10.12 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.26 + '@smithy/util-defaults-mode-node': 4.2.29 + '@smithy/util-endpoints': 3.2.8 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/client-sso@3.972.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 @@ -5447,6 +5619,49 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/client-sso@3.974.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.1 + '@aws-sdk/middleware-host-header': 3.972.1 + '@aws-sdk/middleware-logger': 3.972.1 + '@aws-sdk/middleware-recursion-detection': 3.972.1 + '@aws-sdk/middleware-user-agent': 3.972.2 + '@aws-sdk/region-config-resolver': 3.972.1 + '@aws-sdk/types': 3.973.0 + '@aws-sdk/util-endpoints': 3.972.0 + '@aws-sdk/util-user-agent-browser': 3.972.1 + '@aws-sdk/util-user-agent-node': 3.972.1 + '@smithy/config-resolver': 4.4.6 + '@smithy/core': 3.21.1 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/hash-node': 4.2.8 + '@smithy/invalid-dependency': 4.2.8 + '@smithy/middleware-content-length': 4.2.8 + '@smithy/middleware-endpoint': 4.4.11 + '@smithy/middleware-retry': 4.4.27 + '@smithy/middleware-serde': 4.2.9 + '@smithy/middleware-stack': 4.2.8 + '@smithy/node-config-provider': 4.3.8 + '@smithy/node-http-handler': 4.4.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.10.12 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.26 + '@smithy/util-defaults-mode-node': 4.2.29 + '@smithy/util-endpoints': 3.2.8 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/core@3.972.0': dependencies: '@aws-sdk/types': 3.972.0 @@ -5463,6 +5678,22 @@ snapshots: '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 + '@aws-sdk/core@3.973.1': + dependencies: + '@aws-sdk/types': 3.973.0 + '@aws-sdk/xml-builder': 3.972.1 + '@smithy/core': 3.21.1 + '@smithy/node-config-provider': 4.3.8 + '@smithy/property-provider': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/signature-v4': 5.3.8 + '@smithy/smithy-client': 4.10.12 + '@smithy/types': 4.12.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.972.0': dependencies: '@aws-sdk/core': 3.972.0 @@ -5471,6 +5702,14 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@aws-sdk/credential-provider-env@3.972.1': + dependencies: + '@aws-sdk/core': 3.973.1 + '@aws-sdk/types': 3.973.0 + '@smithy/property-provider': 4.2.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.972.0': dependencies: '@aws-sdk/core': 3.972.0 @@ -5484,6 +5723,19 @@ snapshots: '@smithy/util-stream': 4.5.10 tslib: 2.8.1 + '@aws-sdk/credential-provider-http@3.972.2': + dependencies: + '@aws-sdk/core': 3.973.1 + '@aws-sdk/types': 3.973.0 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/node-http-handler': 4.4.8 + '@smithy/property-provider': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.10.12 + '@smithy/types': 4.12.0 + '@smithy/util-stream': 4.5.10 + tslib: 2.8.1 + '@aws-sdk/credential-provider-ini@3.972.0': dependencies: '@aws-sdk/core': 3.972.0 @@ -5503,6 +5755,25 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-ini@3.972.1': + dependencies: + '@aws-sdk/core': 3.973.1 + '@aws-sdk/credential-provider-env': 3.972.1 + '@aws-sdk/credential-provider-http': 3.972.2 + '@aws-sdk/credential-provider-login': 3.972.1 + '@aws-sdk/credential-provider-process': 3.972.1 + '@aws-sdk/credential-provider-sso': 3.972.1 + '@aws-sdk/credential-provider-web-identity': 3.972.1 + '@aws-sdk/nested-clients': 3.974.0 + '@aws-sdk/types': 3.973.0 + '@smithy/credential-provider-imds': 4.2.8 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-login@3.972.0': dependencies: '@aws-sdk/core': 3.972.0 @@ -5516,6 +5787,19 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-login@3.972.1': + dependencies: + '@aws-sdk/core': 3.973.1 + '@aws-sdk/nested-clients': 3.974.0 + '@aws-sdk/types': 3.973.0 + '@smithy/property-provider': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-node@3.972.0': dependencies: '@aws-sdk/credential-provider-env': 3.972.0 @@ -5533,6 +5817,23 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-node@3.972.1': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.1 + '@aws-sdk/credential-provider-http': 3.972.2 + '@aws-sdk/credential-provider-ini': 3.972.1 + '@aws-sdk/credential-provider-process': 3.972.1 + '@aws-sdk/credential-provider-sso': 3.972.1 + '@aws-sdk/credential-provider-web-identity': 3.972.1 + '@aws-sdk/types': 3.973.0 + '@smithy/credential-provider-imds': 4.2.8 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-process@3.972.0': dependencies: '@aws-sdk/core': 3.972.0 @@ -5542,6 +5843,15 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@aws-sdk/credential-provider-process@3.972.1': + dependencies: + '@aws-sdk/core': 3.973.1 + '@aws-sdk/types': 3.973.0 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@aws-sdk/credential-provider-sso@3.972.0': dependencies: '@aws-sdk/client-sso': 3.972.0 @@ -5555,6 +5865,19 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-sso@3.972.1': + dependencies: + '@aws-sdk/client-sso': 3.974.0 + '@aws-sdk/core': 3.973.1 + '@aws-sdk/token-providers': 3.974.0 + '@aws-sdk/types': 3.973.0 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/credential-provider-web-identity@3.972.0': dependencies: '@aws-sdk/core': 3.972.0 @@ -5567,6 +5890,18 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/credential-provider-web-identity@3.972.1': + dependencies: + '@aws-sdk/core': 3.973.1 + '@aws-sdk/nested-clients': 3.974.0 + '@aws-sdk/types': 3.973.0 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/eventstream-handler-node@3.972.0': dependencies: '@aws-sdk/types': 3.972.0 @@ -5588,12 +5923,25 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@aws-sdk/middleware-host-header@3.972.1': + dependencies: + '@aws-sdk/types': 3.973.0 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@aws-sdk/middleware-logger@3.972.0': dependencies: '@aws-sdk/types': 3.972.0 '@smithy/types': 4.12.0 tslib: 2.8.1 + '@aws-sdk/middleware-logger@3.972.1': + dependencies: + '@aws-sdk/types': 3.973.0 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@aws-sdk/middleware-recursion-detection@3.972.0': dependencies: '@aws-sdk/types': 3.972.0 @@ -5602,6 +5950,14 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@aws-sdk/middleware-recursion-detection@3.972.1': + dependencies: + '@aws-sdk/types': 3.973.0 + '@aws/lambda-invoke-store': 0.2.3 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@aws-sdk/middleware-user-agent@3.972.0': dependencies: '@aws-sdk/core': 3.972.0 @@ -5612,6 +5968,16 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@aws-sdk/middleware-user-agent@3.972.2': + dependencies: + '@aws-sdk/core': 3.973.1 + '@aws-sdk/types': 3.973.0 + '@aws-sdk/util-endpoints': 3.972.0 + '@smithy/core': 3.21.1 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@aws-sdk/middleware-websocket@3.972.0': dependencies: '@aws-sdk/types': 3.972.0 @@ -5668,6 +6034,92 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/nested-clients@3.974.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.1 + '@aws-sdk/middleware-host-header': 3.972.1 + '@aws-sdk/middleware-logger': 3.972.1 + '@aws-sdk/middleware-recursion-detection': 3.972.1 + '@aws-sdk/middleware-user-agent': 3.972.2 + '@aws-sdk/region-config-resolver': 3.972.1 + '@aws-sdk/types': 3.973.0 + '@aws-sdk/util-endpoints': 3.972.0 + '@aws-sdk/util-user-agent-browser': 3.972.1 + '@aws-sdk/util-user-agent-node': 3.972.1 + '@smithy/config-resolver': 4.4.6 + '@smithy/core': 3.21.1 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/hash-node': 4.2.8 + '@smithy/invalid-dependency': 4.2.8 + '@smithy/middleware-content-length': 4.2.8 + '@smithy/middleware-endpoint': 4.4.11 + '@smithy/middleware-retry': 4.4.27 + '@smithy/middleware-serde': 4.2.9 + '@smithy/middleware-stack': 4.2.8 + '@smithy/node-config-provider': 4.3.8 + '@smithy/node-http-handler': 4.4.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.10.12 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.26 + '@smithy/util-defaults-mode-node': 4.2.29 + '@smithy/util-endpoints': 3.2.8 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/nested-clients@3.975.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.1 + '@aws-sdk/middleware-host-header': 3.972.1 + '@aws-sdk/middleware-logger': 3.972.1 + '@aws-sdk/middleware-recursion-detection': 3.972.1 + '@aws-sdk/middleware-user-agent': 3.972.2 + '@aws-sdk/region-config-resolver': 3.972.1 + '@aws-sdk/types': 3.973.0 + '@aws-sdk/util-endpoints': 3.972.0 + '@aws-sdk/util-user-agent-browser': 3.972.1 + '@aws-sdk/util-user-agent-node': 3.972.1 + '@smithy/config-resolver': 4.4.6 + '@smithy/core': 3.21.1 + '@smithy/fetch-http-handler': 5.3.9 + '@smithy/hash-node': 4.2.8 + '@smithy/invalid-dependency': 4.2.8 + '@smithy/middleware-content-length': 4.2.8 + '@smithy/middleware-endpoint': 4.4.11 + '@smithy/middleware-retry': 4.4.27 + '@smithy/middleware-serde': 4.2.9 + '@smithy/middleware-stack': 4.2.8 + '@smithy/node-config-provider': 4.3.8 + '@smithy/node-http-handler': 4.4.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/smithy-client': 4.10.12 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.26 + '@smithy/util-defaults-mode-node': 4.2.29 + '@smithy/util-endpoints': 3.2.8 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/region-config-resolver@3.972.0': dependencies: '@aws-sdk/types': 3.972.0 @@ -5676,6 +6128,14 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@aws-sdk/region-config-resolver@3.972.1': + dependencies: + '@aws-sdk/types': 3.973.0 + '@smithy/config-resolver': 4.4.6 + '@smithy/node-config-provider': 4.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@aws-sdk/token-providers@3.972.0': dependencies: '@aws-sdk/core': 3.972.0 @@ -5688,11 +6148,40 @@ snapshots: transitivePeerDependencies: - aws-crt + '@aws-sdk/token-providers@3.974.0': + dependencies: + '@aws-sdk/core': 3.973.1 + '@aws-sdk/nested-clients': 3.974.0 + '@aws-sdk/types': 3.973.0 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/token-providers@3.975.0': + dependencies: + '@aws-sdk/core': 3.973.1 + '@aws-sdk/nested-clients': 3.975.0 + '@aws-sdk/types': 3.973.0 + '@smithy/property-provider': 4.2.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + '@aws-sdk/types@3.972.0': dependencies: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@aws-sdk/types@3.973.0': + dependencies: + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@aws-sdk/util-endpoints@3.972.0': dependencies: '@aws-sdk/types': 3.972.0 @@ -5719,6 +6208,13 @@ snapshots: bowser: 2.13.1 tslib: 2.8.1 + '@aws-sdk/util-user-agent-browser@3.972.1': + dependencies: + '@aws-sdk/types': 3.973.0 + '@smithy/types': 4.12.0 + bowser: 2.13.1 + tslib: 2.8.1 + '@aws-sdk/util-user-agent-node@3.972.0': dependencies: '@aws-sdk/middleware-user-agent': 3.972.0 @@ -5727,12 +6223,26 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@aws-sdk/util-user-agent-node@3.972.1': + dependencies: + '@aws-sdk/middleware-user-agent': 3.972.2 + '@aws-sdk/types': 3.973.0 + '@smithy/node-config-provider': 4.3.8 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@aws-sdk/xml-builder@3.972.0': dependencies: '@smithy/types': 4.12.0 fast-xml-parser: 5.2.5 tslib: 2.8.1 + '@aws-sdk/xml-builder@3.972.1': + dependencies: + '@smithy/types': 4.12.0 + fast-xml-parser: 5.2.5 + tslib: 2.8.1 + '@aws/lambda-invoke-store@0.2.3': {} '@azure/abort-controller@2.1.2': @@ -7302,6 +7812,19 @@ snapshots: '@smithy/uuid': 1.1.0 tslib: 2.8.1 + '@smithy/core@3.21.1': + dependencies: + '@smithy/middleware-serde': 4.2.9 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-stream': 4.5.10 + '@smithy/util-utf8': 4.2.0 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + '@smithy/credential-provider-imds@4.2.8': dependencies: '@smithy/node-config-provider': 4.3.8 @@ -7385,6 +7908,17 @@ snapshots: '@smithy/util-middleware': 4.2.8 tslib: 2.8.1 + '@smithy/middleware-endpoint@4.4.11': + dependencies: + '@smithy/core': 3.21.1 + '@smithy/middleware-serde': 4.2.9 + '@smithy/node-config-provider': 4.3.8 + '@smithy/shared-ini-file-loader': 4.4.3 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-middleware': 4.2.8 + tslib: 2.8.1 + '@smithy/middleware-retry@4.4.26': dependencies: '@smithy/node-config-provider': 4.3.8 @@ -7397,6 +7931,18 @@ snapshots: '@smithy/uuid': 1.1.0 tslib: 2.8.1 + '@smithy/middleware-retry@4.4.27': + dependencies: + '@smithy/node-config-provider': 4.3.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/service-error-classification': 4.2.8 + '@smithy/smithy-client': 4.10.12 + '@smithy/types': 4.12.0 + '@smithy/util-middleware': 4.2.8 + '@smithy/util-retry': 4.2.8 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + '@smithy/middleware-serde@4.2.9': dependencies: '@smithy/protocol-http': 5.3.8 @@ -7474,6 +8020,16 @@ snapshots: '@smithy/util-stream': 4.5.10 tslib: 2.8.1 + '@smithy/smithy-client@4.10.12': + dependencies: + '@smithy/core': 3.21.1 + '@smithy/middleware-endpoint': 4.4.11 + '@smithy/middleware-stack': 4.2.8 + '@smithy/protocol-http': 5.3.8 + '@smithy/types': 4.12.0 + '@smithy/util-stream': 4.5.10 + tslib: 2.8.1 + '@smithy/types@4.12.0': dependencies: tslib: 2.8.1 @@ -7519,6 +8075,13 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@smithy/util-defaults-mode-browser@4.3.26': + dependencies: + '@smithy/property-provider': 4.2.8 + '@smithy/smithy-client': 4.10.12 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@smithy/util-defaults-mode-node@4.2.28': dependencies: '@smithy/config-resolver': 4.4.6 @@ -7529,6 +8092,16 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 + '@smithy/util-defaults-mode-node@4.2.29': + dependencies: + '@smithy/config-resolver': 4.4.6 + '@smithy/credential-provider-imds': 4.2.8 + '@smithy/node-config-provider': 4.3.8 + '@smithy/property-provider': 4.2.8 + '@smithy/smithy-client': 4.10.12 + '@smithy/types': 4.12.0 + tslib: 2.8.1 + '@smithy/util-endpoints@3.2.8': dependencies: '@smithy/node-config-provider': 4.3.8 diff --git a/src/agents/bedrock-discovery.test.ts b/src/agents/bedrock-discovery.test.ts new file mode 100644 index 000000000..2a7e6bd97 --- /dev/null +++ b/src/agents/bedrock-discovery.test.ts @@ -0,0 +1,96 @@ +import type { BedrockClient } from "@aws-sdk/client-bedrock"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const sendMock = vi.fn(); +const clientFactory = () => ({ send: sendMock }) as unknown as BedrockClient; + +describe("bedrock discovery", () => { + beforeEach(() => { + sendMock.mockReset(); + }); + + it("filters to active streaming text models and maps modalities", async () => { + const { discoverBedrockModels, resetBedrockDiscoveryCacheForTest } = + await import("./bedrock-discovery.js"); + resetBedrockDiscoveryCacheForTest(); + + sendMock.mockResolvedValueOnce({ + modelSummaries: [ + { + modelId: "anthropic.claude-3-7-sonnet-20250219-v1:0", + modelName: "Claude 3.7 Sonnet", + providerName: "anthropic", + inputModalities: ["TEXT", "IMAGE"], + outputModalities: ["TEXT"], + responseStreamingSupported: true, + modelLifecycle: { status: "ACTIVE" }, + }, + { + modelId: "anthropic.claude-3-haiku-20240307-v1:0", + modelName: "Claude 3 Haiku", + providerName: "anthropic", + inputModalities: ["TEXT"], + outputModalities: ["TEXT"], + responseStreamingSupported: false, + modelLifecycle: { status: "ACTIVE" }, + }, + { + modelId: "meta.llama3-8b-instruct-v1:0", + modelName: "Llama 3 8B", + providerName: "meta", + inputModalities: ["TEXT"], + outputModalities: ["TEXT"], + responseStreamingSupported: true, + modelLifecycle: { status: "INACTIVE" }, + }, + { + modelId: "amazon.titan-embed-text-v1", + modelName: "Titan Embed", + providerName: "amazon", + inputModalities: ["TEXT"], + outputModalities: ["EMBEDDING"], + responseStreamingSupported: true, + modelLifecycle: { status: "ACTIVE" }, + }, + ], + }); + + const models = await discoverBedrockModels({ region: "us-east-1", clientFactory }); + expect(models).toHaveLength(1); + expect(models[0]).toMatchObject({ + id: "anthropic.claude-3-7-sonnet-20250219-v1:0", + name: "Claude 3.7 Sonnet", + reasoning: false, + input: ["text", "image"], + contextWindow: 128000, + maxTokens: 8192, + }); + }); + + it("applies provider filter", async () => { + const { discoverBedrockModels, resetBedrockDiscoveryCacheForTest } = + await import("./bedrock-discovery.js"); + resetBedrockDiscoveryCacheForTest(); + + sendMock.mockResolvedValueOnce({ + modelSummaries: [ + { + modelId: "anthropic.claude-3-7-sonnet-20250219-v1:0", + modelName: "Claude 3.7 Sonnet", + providerName: "anthropic", + inputModalities: ["TEXT"], + outputModalities: ["TEXT"], + responseStreamingSupported: true, + modelLifecycle: { status: "ACTIVE" }, + }, + ], + }); + + const models = await discoverBedrockModels({ + region: "us-east-1", + config: { providerFilter: ["amazon"] }, + clientFactory, + }); + expect(models).toHaveLength(0); + }); +}); diff --git a/src/agents/bedrock-discovery.ts b/src/agents/bedrock-discovery.ts new file mode 100644 index 000000000..8ae61ec7a --- /dev/null +++ b/src/agents/bedrock-discovery.ts @@ -0,0 +1,184 @@ +import { + BedrockClient, + ListFoundationModelsCommand, + type ListFoundationModelsCommandOutput, +} from "@aws-sdk/client-bedrock"; + +import type { BedrockDiscoveryConfig, ModelDefinitionConfig } from "../config/types.js"; + +const DEFAULT_REFRESH_INTERVAL_SECONDS = 3600; +const DEFAULT_CONTEXT_WINDOW = 128000; +const DEFAULT_MAX_TOKENS = 8192; +const DEFAULT_COST = { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, +}; + +type BedrockModelSummary = NonNullable[number]; + +type BedrockDiscoveryCacheEntry = { + expiresAt: number; + value?: ModelDefinitionConfig[]; + inFlight?: Promise; +}; + +const discoveryCache = new Map(); +let hasLoggedBedrockError = false; + +function normalizeProviderFilter(filter?: string[]): string[] { + if (!filter || filter.length === 0) return []; + const normalized = new Set( + filter.map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0), + ); + return Array.from(normalized).sort(); +} + +function buildCacheKey(params: { + region: string; + providerFilter: string[]; + refreshIntervalSeconds: number; +}): string { + return JSON.stringify(params); +} + +function includesTextModalities(modalities?: Array): boolean { + return (modalities ?? []).some((entry) => entry.toLowerCase() === "text"); +} + +function isActive(summary: BedrockModelSummary): boolean { + const status = summary.modelLifecycle?.status; + return typeof status === "string" ? status.toUpperCase() === "ACTIVE" : false; +} + +function mapInputModalities(summary: BedrockModelSummary): Array<"text" | "image"> { + const inputs = summary.inputModalities ?? []; + const mapped = new Set<"text" | "image">(); + for (const modality of inputs) { + const lower = modality.toLowerCase(); + if (lower === "text") mapped.add("text"); + if (lower === "image") mapped.add("image"); + } + if (mapped.size === 0) mapped.add("text"); + return Array.from(mapped); +} + +function inferReasoningSupport(summary: BedrockModelSummary): boolean { + const haystack = `${summary.modelId ?? ""} ${summary.modelName ?? ""}`.toLowerCase(); + return haystack.includes("reasoning") || haystack.includes("thinking"); +} + +function inferContextWindow(): number { + return DEFAULT_CONTEXT_WINDOW; +} + +function inferMaxTokens(): number { + return DEFAULT_MAX_TOKENS; +} + +function matchesProviderFilter(summary: BedrockModelSummary, filter: string[]): boolean { + if (filter.length === 0) return true; + const providerName = + summary.providerName ?? + (typeof summary.modelId === "string" ? summary.modelId.split(".")[0] : undefined); + const normalized = providerName?.trim().toLowerCase(); + if (!normalized) return false; + return filter.includes(normalized); +} + +function shouldIncludeSummary(summary: BedrockModelSummary, filter: string[]): boolean { + if (!summary.modelId?.trim()) return false; + if (!matchesProviderFilter(summary, filter)) return false; + if (summary.responseStreamingSupported !== true) return false; + if (!includesTextModalities(summary.outputModalities)) return false; + if (!isActive(summary)) return false; + return true; +} + +function toModelDefinition(summary: BedrockModelSummary): ModelDefinitionConfig { + const id = summary.modelId?.trim() ?? ""; + return { + id, + name: summary.modelName?.trim() || id, + reasoning: inferReasoningSupport(summary), + input: mapInputModalities(summary), + cost: DEFAULT_COST, + contextWindow: inferContextWindow(), + maxTokens: inferMaxTokens(), + }; +} + +export function resetBedrockDiscoveryCacheForTest(): void { + discoveryCache.clear(); + hasLoggedBedrockError = false; +} + +export async function discoverBedrockModels(params: { + region: string; + config?: BedrockDiscoveryConfig; + now?: () => number; + clientFactory?: (region: string) => BedrockClient; +}): Promise { + const refreshIntervalSeconds = Math.max( + 0, + Math.floor(params.config?.refreshInterval ?? DEFAULT_REFRESH_INTERVAL_SECONDS), + ); + const providerFilter = normalizeProviderFilter(params.config?.providerFilter); + const cacheKey = buildCacheKey({ + region: params.region, + providerFilter, + refreshIntervalSeconds, + }); + const now = params.now?.() ?? Date.now(); + + if (refreshIntervalSeconds > 0) { + const cached = discoveryCache.get(cacheKey); + if (cached?.value && cached.expiresAt > now) { + return cached.value; + } + if (cached?.inFlight) { + return cached.inFlight; + } + } + + const clientFactory = params.clientFactory ?? ((region: string) => new BedrockClient({ region })); + const client = clientFactory(params.region); + + const discoveryPromise = (async () => { + const response = await client.send(new ListFoundationModelsCommand({})); + const discovered: ModelDefinitionConfig[] = []; + for (const summary of response.modelSummaries ?? []) { + if (!shouldIncludeSummary(summary, providerFilter)) continue; + discovered.push(toModelDefinition(summary)); + } + return discovered.sort((a, b) => a.name.localeCompare(b.name)); + })(); + + if (refreshIntervalSeconds > 0) { + discoveryCache.set(cacheKey, { + expiresAt: now + refreshIntervalSeconds * 1000, + inFlight: discoveryPromise, + }); + } + + try { + const value = await discoveryPromise; + if (refreshIntervalSeconds > 0) { + discoveryCache.set(cacheKey, { + expiresAt: now + refreshIntervalSeconds * 1000, + value, + }); + } + return value; + } catch (error) { + if (refreshIntervalSeconds > 0) { + discoveryCache.delete(cacheKey); + } + if (!hasLoggedBedrockError) { + hasLoggedBedrockError = true; + console.warn(`[bedrock-discovery] Failed to list models: ${String(error)}`); + } + return []; + } +} diff --git a/src/agents/models-config.providers.ts b/src/agents/models-config.providers.ts index 251f7b92b..d9fe734ee 100644 --- a/src/agents/models-config.providers.ts +++ b/src/agents/models-config.providers.ts @@ -5,6 +5,7 @@ import { } from "../providers/github-copilot-token.js"; import { ensureAuthProfileStore, listProfilesForProvider } from "./auth-profiles.js"; import { resolveAwsSdkEnvVarName, resolveEnvApiKey } from "./model-auth.js"; +import { discoverBedrockModels } from "./bedrock-discovery.js"; import { buildSyntheticModelDefinition, SYNTHETIC_BASE_URL, @@ -375,3 +376,27 @@ export async function resolveImplicitCopilotProvider(params: { models: [], } satisfies ProviderConfig; } + +export async function resolveImplicitBedrockProvider(params: { + agentDir: string; + config?: ClawdbotConfig; + env?: NodeJS.ProcessEnv; +}): Promise { + const env = params.env ?? process.env; + const discoveryConfig = params.config?.models?.bedrockDiscovery; + const enabled = discoveryConfig?.enabled; + const hasAwsCreds = resolveAwsSdkEnvVarName() !== undefined; + if (enabled === false) return null; + if (enabled !== true && !hasAwsCreds) return null; + + const region = discoveryConfig?.region ?? env.AWS_REGION ?? env.AWS_DEFAULT_REGION ?? "us-east-1"; + const models = await discoverBedrockModels({ region, config: discoveryConfig }); + if (models.length === 0) return null; + + return { + baseUrl: `https://bedrock-runtime.${region}.amazonaws.com`, + api: "bedrock-converse-stream", + auth: "aws-sdk", + models, + } satisfies ProviderConfig; +} diff --git a/src/agents/models-config.ts b/src/agents/models-config.ts index 50d5da62b..63fb63f3d 100644 --- a/src/agents/models-config.ts +++ b/src/agents/models-config.ts @@ -6,6 +6,7 @@ import { resolveClawdbotAgentDir } from "./agent-paths.js"; import { normalizeProviders, type ProviderConfig, + resolveImplicitBedrockProvider, resolveImplicitCopilotProvider, resolveImplicitProviders, } from "./models-config.providers.js"; @@ -84,6 +85,13 @@ export async function ensureClawdbotModelsJson( implicit: implicitProviders, explicit: explicitProviders, }); + const implicitBedrock = await resolveImplicitBedrockProvider({ agentDir, config: cfg }); + if (implicitBedrock) { + const existing = providers["amazon-bedrock"]; + providers["amazon-bedrock"] = existing + ? mergeProviderModels(implicitBedrock, existing) + : implicitBedrock; + } const implicitCopilot = await resolveImplicitCopilotProvider({ agentDir }); if (implicitCopilot && !providers["github-copilot"]) { providers["github-copilot"] = implicitCopilot; diff --git a/src/commands/models.list.test.ts b/src/commands/models.list.test.ts index 850f27246..e904e3484 100644 --- a/src/commands/models.list.test.ts +++ b/src/commands/models.list.test.ts @@ -11,6 +11,7 @@ const resolveAuthStorePathForDisplay = vi .mockReturnValue("/tmp/clawdbot-agent/auth-profiles.json"); const resolveProfileUnusableUntilForDisplay = vi.fn().mockReturnValue(null); const resolveEnvApiKey = vi.fn().mockReturnValue(undefined); +const resolveAwsSdkEnvVarName = vi.fn().mockReturnValue(undefined); const getCustomProviderApiKey = vi.fn().mockReturnValue(undefined); const discoverAuthStorage = vi.fn().mockReturnValue({}); const discoverModels = vi.fn(); @@ -39,6 +40,7 @@ vi.mock("../agents/auth-profiles.js", () => ({ vi.mock("../agents/model-auth.js", () => ({ resolveEnvApiKey, + resolveAwsSdkEnvVarName, getCustomProviderApiKey, })); diff --git a/src/commands/models/list.registry.ts b/src/commands/models/list.registry.ts index 0a14bb5ad..95c96e40b 100644 --- a/src/commands/models/list.registry.ts +++ b/src/commands/models/list.registry.ts @@ -4,7 +4,11 @@ import { discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-age import { resolveClawdbotAgentDir } from "../../agents/agent-paths.js"; import type { AuthProfileStore } from "../../agents/auth-profiles.js"; import { listProfilesForProvider } from "../../agents/auth-profiles.js"; -import { getCustomProviderApiKey, resolveEnvApiKey } from "../../agents/model-auth.js"; +import { + getCustomProviderApiKey, + resolveAwsSdkEnvVarName, + resolveEnvApiKey, +} from "../../agents/model-auth.js"; import { ensureClawdbotModelsJson } from "../../agents/models-config.js"; import type { ClawdbotConfig } from "../../config/config.js"; import type { ModelRow } from "./list.types.js"; @@ -28,6 +32,7 @@ const isLocalBaseUrl = (baseUrl: string) => { const hasAuthForProvider = (provider: string, cfg: ClawdbotConfig, authStore: AuthProfileStore) => { if (listProfilesForProvider(authStore, provider).length > 0) return true; + if (provider === "amazon-bedrock" && resolveAwsSdkEnvVarName()) return true; if (resolveEnvApiKey(provider)) return true; if (getCustomProviderApiKey(cfg, provider)) return true; return false; diff --git a/src/config/types.models.ts b/src/config/types.models.ts index f11f368f1..70d5377d7 100644 --- a/src/config/types.models.ts +++ b/src/config/types.models.ts @@ -43,7 +43,15 @@ export type ModelProviderConfig = { models: ModelDefinitionConfig[]; }; +export type BedrockDiscoveryConfig = { + enabled?: boolean; + region?: string; + providerFilter?: string[]; + refreshInterval?: number; +}; + export type ModelsConfig = { mode?: "merge" | "replace"; providers?: Record; + bedrockDiscovery?: BedrockDiscoveryConfig; }; diff --git a/src/config/zod-schema.core.ts b/src/config/zod-schema.core.ts index 7bdf86bdf..6fc605eaa 100644 --- a/src/config/zod-schema.core.ts +++ b/src/config/zod-schema.core.ts @@ -59,10 +59,21 @@ export const ModelProviderSchema = z }) .strict(); +export const BedrockDiscoverySchema = z + .object({ + enabled: z.boolean().optional(), + region: z.string().optional(), + providerFilter: z.array(z.string()).optional(), + refreshInterval: z.number().int().nonnegative().optional(), + }) + .strict() + .optional(); + export const ModelsConfigSchema = z .object({ mode: z.union([z.literal("merge"), z.literal("replace")]).optional(), providers: z.record(z.string(), ModelProviderSchema).optional(), + bedrockDiscovery: BedrockDiscoverySchema, }) .strict() .optional();