AIX/LLMs: Bedrock: support Bedrock Long-term API Keys

This commit is contained in:
Enrico Ros
2026-02-25 17:03:00 -08:00
parent ed35d5b541
commit c36ff1edfa
9 changed files with 180 additions and 77 deletions
+2
View File
@@ -29,6 +29,7 @@ AZURE_OPENAI_API_ENDPOINT=
AZURE_OPENAI_API_KEY=
ANTHROPIC_API_KEY=
ANTHROPIC_API_HOST=
BEDROCK_BEARER_TOKEN=
BEDROCK_ACCESS_KEY_ID=
BEDROCK_SECRET_ACCESS_KEY=
BEDROCK_SESSION_TOKEN=
@@ -105,6 +106,7 @@ requiring the user to enter an API key
| `AZURE_DEPLOYMENTS_API_VERSION` | API version for the deployments listing endpoint | Optional, defaults to '2023-03-15-preview' |
| `ANTHROPIC_API_KEY` | The API key for Anthropic | Optional |
| `ANTHROPIC_API_HOST` | Changes the backend host for the Anthropic vendor, for proxies or custom endpoints | Optional |
| `BEDROCK_BEARER_TOKEN` | Bedrock long-term API key (`ABSK...`). Takes priority over IAM credentials. Short-term keys only work for runtime, not model listing | Optional |
| `BEDROCK_ACCESS_KEY_ID` | AWS IAM Access Key ID for Bedrock (Claude models via AWS) | Optional, but if set `BEDROCK_SECRET_ACCESS_KEY` must also be set |
| `BEDROCK_SECRET_ACCESS_KEY` | AWS IAM Secret Access Key for Bedrock | Optional, but if set `BEDROCK_ACCESS_KEY_ID` must also be set |
| `BEDROCK_SESSION_TOKEN` | AWS Session Token for temporary/STS credentials | Optional |
@@ -1,6 +1,6 @@
import { ANTHROPIC_API_PATHS, anthropicAccess, anthropicBetaFeatures, AnthropicHeaderOptions } from '~/modules/llms/server/anthropic/anthropic.access';
import { OPENAI_API_PATHS, openAIAccess } from '~/modules/llms/server/openai/openai.access';
import { bedrockAccessAsync, bedrockServerConfig, bedrockURLRuntime } from '~/modules/llms/server/bedrock/bedrock.access';
import { bedrockAccessAsync, bedrockResolveRegion, bedrockURLRuntime } from '~/modules/llms/server/bedrock/bedrock.access';
import { geminiAccess } from '~/modules/llms/server/gemini/gemini.access';
import { ollamaAccess } from '~/modules/llms/server/ollama/ollama.access';
@@ -90,7 +90,7 @@ export async function createChatGenerateDispatch(access: AixAPI_Access, model: A
if (invokeAPI === 'converse')
throw new Error('[Bedrock] Converse API is not yet implemented. Use Anthropic models with the InvokeModel API (invoke-anthropic).');
const region = bedrockServerConfig(access).region;
const region = bedrockResolveRegion(access);
const url = bedrockURLRuntime(region, model.id, streaming);
// body
+1 -1
View File
@@ -51,7 +51,7 @@ export const backendRouter = createTRPCRouter({
hasLlmAlibaba: !!env.ALIBABA_API_KEY || !!env.ALIBABA_API_HOST,
hasLlmAnthropic: !!env.ANTHROPIC_API_KEY,
hasLlmAzureOpenAI: !!env.AZURE_OPENAI_API_KEY && !!env.AZURE_OPENAI_API_ENDPOINT,
hasLlmBedrock: !!env.BEDROCK_ACCESS_KEY_ID && !!env.BEDROCK_SECRET_ACCESS_KEY,
hasLlmBedrock: !!env.BEDROCK_BEARER_TOKEN || (!!env.BEDROCK_ACCESS_KEY_ID && !!env.BEDROCK_SECRET_ACCESS_KEY),
hasLlmDeepseek: !!env.DEEPSEEK_API_KEY,
hasLlmGemini: !!env.GEMINI_API_KEY,
hasLlmGroq: !!env.GROQ_API_KEY,
@@ -1,12 +1,18 @@
/**
* Isomorphic AWS Bedrock API access - SigV4 signing via aws4fetch.
* Isomorphic AWS Bedrock API access - SigV4 signing via aws4fetch + Bearer token auth.
*
* This module provides the access schema and signing logic for AWS Bedrock API calls.
* It supports both the `bedrock` control plane (model listing) and `bedrock-runtime`
* data plane (model invocation).
*
* Authentication uses explicit AWS credentials only (no credential chain) for
* Edge Runtime compatibility. aws4fetch auto-detects service and region from URLs.
* Two authentication modes:
* - **Bearer token**: Simple `Authorization: Bearer <token>` header (AWS Bedrock API keys).
* Long-term keys (`ABSK...`) support both control plane and runtime.
* UNSUPPORTED: Short-term keys (`bedrock-api-key-...`) only support runtime (not model listing).
* - **SigV4**: Traditional IAM credentials signing via aws4fetch
*
* Priority: client bearer > client IAM > server bearer > server IAM.
* SigV4 uses explicit AWS credentials only (no credential chain) for Edge Runtime compatibility.
*/
import * as z from 'zod/v4';
@@ -17,11 +23,16 @@ import { AwsClient } from 'aws4fetch';
import { env } from '~/server/env.server';
// configuration
const DEFAULT_BEDROCK_REGION = 'us-east-1'; // default region for Bedrock, used if not provided by client or env
// --- Schema ---
export type BedrockAccessSchema = z.infer<typeof bedrockAccessSchema>;
export const bedrockAccessSchema = z.object({
dialect: z.literal('bedrock'),
bedrockBearerToken: z.string().trim(),
bedrockAccessKeyId: z.string().trim(),
bedrockSecretAccessKey: z.string().trim(),
bedrockSessionToken: z.string().trim().nullable(),
@@ -30,26 +41,41 @@ export const bedrockAccessSchema = z.object({
});
// --- Credential & Region Resolution ---
// --- Auth Resolution ---
/**
* Resolve all Bedrock access config: credentials (all-or-none) + region.
* If the user provides an access key, all credentials come from user; otherwise all from env.
*/
export function bedrockServerConfig(access: BedrockAccessSchema) {
const userProvided = !!access.bedrockAccessKeyId;
const accessKeyId = userProvided ? access.bedrockAccessKeyId : (env.BEDROCK_ACCESS_KEY_ID || '');
const secretAccessKey = userProvided ? access.bedrockSecretAccessKey : (env.BEDROCK_SECRET_ACCESS_KEY || '');
const sessionToken = (userProvided ? access.bedrockSessionToken : env.BEDROCK_SESSION_TOKEN) || undefined;
const region = (userProvided ? access.bedrockRegion : env.BEDROCK_REGION) || 'us-east-1';
type BedrockAuthBearer = { type: 'bearer'; bearerToken: string; region: string };
type BedrockAuthSigV4 = { type: 'sigv4'; accessKeyId: string; secretAccessKey: string; sessionToken: string | undefined; region: string };
if (!accessKeyId || !secretAccessKey)
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'Missing AWS credentials. Add your Access Key ID and Secret Access Key on the UI (Models Setup) or server side (your deployment).',
});
/** Resolve Bedrock authentication. */
function _bedrockResolveAuth(access: BedrockAccessSchema): BedrockAuthBearer | BedrockAuthSigV4 {
return { accessKeyId, secretAccessKey, sessionToken, region };
// 1. Client bearer token (highest priority)
let region = access.bedrockRegion || DEFAULT_BEDROCK_REGION; // client-provided region
if (access.bedrockBearerToken)
return { type: 'bearer', bearerToken: access.bedrockBearerToken, region };
// 2. Client IAM credentials
if (access.bedrockAccessKeyId && access.bedrockSecretAccessKey)
return { type: 'sigv4', accessKeyId: access.bedrockAccessKeyId, secretAccessKey: access.bedrockSecretAccessKey, sessionToken: access.bedrockSessionToken || undefined, region };
// 3. Server bearer token
region = env.BEDROCK_REGION || DEFAULT_BEDROCK_REGION; // server-provided region (ignores client for security reasons)
if (env.BEDROCK_BEARER_TOKEN)
return { type: 'bearer', bearerToken: env.BEDROCK_BEARER_TOKEN, region };
// 4. Server IAM credentials
if (env.BEDROCK_ACCESS_KEY_ID && env.BEDROCK_SECRET_ACCESS_KEY)
return { type: 'sigv4', accessKeyId: env.BEDROCK_ACCESS_KEY_ID, secretAccessKey: env.BEDROCK_SECRET_ACCESS_KEY, sessionToken: env.BEDROCK_SESSION_TOKEN || undefined, region };
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'Missing AWS credentials. Add your Bedrock API Key or IAM Access Key on the UI (Models Setup) or server side (your deployment).',
});
}
/** Resolve the Bedrock region from access config. */
export function bedrockResolveRegion(access: BedrockAccessSchema): string {
return _bedrockResolveAuth(access).region;
}
@@ -65,11 +91,11 @@ export function bedrockURLControlPlane(region: string, path: string): string {
}
// --- Bedrock Access (async SigV4) ---
// --- Bedrock Access (Bearer or async SigV4) ---
/**
* Signs a request for AWS Bedrock using SigV4 via aws4fetch.
* Returns { headers, url } like anthropicAccess/geminiAccess, but async due to SigV4 signing.
* Prepares a request for AWS Bedrock using either Bearer token or SigV4 signing.
* Returns { headers, url } like anthropicAccess/geminiAccess, but async due to potential SigV4 signing.
*/
export async function bedrockAccessAsync(
access: BedrockAccessSchema,
@@ -78,14 +104,27 @@ export async function bedrockAccessAsync(
body?: object,
): Promise<{ headers: HeadersInit; url: string }> {
const { accessKeyId, secretAccessKey, sessionToken, region } = bedrockServerConfig(access);
const auth = _bedrockResolveAuth(access);
// -- Bearer token: simple Authorization header --
if (auth.type === 'bearer')
return {
headers: {
'Authorization': `Bearer ${auth.bearerToken}`,
'Accept': 'application/json',
...(method === 'POST' ? { 'Content-Type': 'application/json' } : {}),
},
url,
};
// -- SigV4: sign with aws4fetch --
const awsClient = new AwsClient({
service: 'bedrock', // Bedrock uses 'bedrock' as the SigV4 service name for both control plane and runtime
accessKeyId,
secretAccessKey,
sessionToken,
region,
accessKeyId: auth.accessKeyId,
secretAccessKey: auth.secretAccessKey,
sessionToken: auth.sessionToken,
region: auth.region,
});
// sign the request - uses SubtleCrypto
@@ -16,7 +16,7 @@ import { anthropicInjectVariants, anthropicValidateModelDefs_DEV, AnthropicWire_
import { ANTHROPIC_API_PATHS, anthropicAccess } from './anthropic/anthropic.access';
// protocol: Bedrock
import { bedrockAccessAsync, bedrockURLControlPlane, bedrockServerConfig } from './bedrock/bedrock.access';
import { bedrockAccessAsync, bedrockResolveRegion, bedrockURLControlPlane } from './bedrock/bedrock.access';
import { bedrockModelsToDescriptions, BedrockWire_API_Models_List } from './bedrock/bedrock.models';
// protocol: Gemini
@@ -169,7 +169,7 @@ function _listModelsCreateDispatch(access: AixAPI_Access, signal?: AbortSignal):
fetchModels: async () => {
// construct URLs by region
const { region } = bedrockServerConfig(access);
const region = bedrockResolveRegion(access);
const fmUrl = bedrockURLControlPlane(region, '/foundation-models?byInferenceType=ON_DEMAND');
const ipUrl = bedrockURLControlPlane(region, '/inference-profiles?typeEquals=SYSTEM_DEFINED&maxResults=1000');
@@ -1,8 +1,6 @@
import * as React from 'react';
import { Autocomplete, AutocompleteOption, Box, FormControl, FormHelperText, FormLabel, Typography } from '@mui/joy';
import { Link } from '~/common/components/Link';
import { Autocomplete, AutocompleteOption, Box, FormControl, FormLabel, Typography } from '@mui/joy';
interface BedrockRegion {
@@ -76,11 +74,11 @@ export function BedrockRegionAutocomplete(props: {
<FormControl>
<Box sx={{ display: 'flex', flexDirection: 'row', alignItems: 'baseline', justifyContent: 'space-between' }}>
<FormLabel>
AWS Region
AWS Models Region
</FormLabel>
<FormHelperText sx={{ display: 'block' }}>
see <Link level='body-sm' href='https://docs.aws.amazon.com/bedrock/latest/userguide/models-regions.html' target='_blank'>regions</Link>
</FormHelperText>
{/*<FormHelperText sx={{ display: 'block' }}>*/}
{/* see <Link level='body-sm' href='https://docs.aws.amazon.com/bedrock/latest/userguide/models-regions.html' target='_blank'>regions</Link>*/}
{/*</FormHelperText>*/}
</Box>
<Autocomplete<BedrockRegion, false, false, true>
freeSolo
+83 -32
View File
@@ -1,10 +1,10 @@
import * as React from 'react';
import { Box, IconButton, Typography } from '@mui/joy';
import UnfoldLessIcon from '@mui/icons-material/UnfoldLess';
import UnfoldMoreIcon from '@mui/icons-material/UnfoldMore';
import { Box, Divider, IconButton, Typography } from '@mui/joy';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import type { DModelsServiceId } from '~/common/stores/llms/llms.service.types';
import { AlreadySet } from '~/common/components/AlreadySet';
import { ClaudeCrabIcon } from '~/common/components/icons/vendors/ClaudeCrabIcon';
import { FormInputKey } from '~/common/components/forms/FormInputKey';
import { InlineError } from '~/common/components/InlineError';
@@ -16,7 +16,21 @@ import { useLlmUpdateModels } from '../../llm.client.hooks';
import { useServiceSetup } from '../useServiceSetup';
import { BedrockRegionAutocomplete } from './BedrockRegionAutocomplete';
import { isValidBedrockAccessKeyId, isValidBedrockSecretAccessKey, ModelVendorBedrock } from './bedrock.vendor';
import { isValidBedrockAccessKeyId, isValidBedrockBearerToken, isValidBedrockSecretAccessKey, ModelVendorBedrock } from './bedrock.vendor';
const _styles = {
iamGrid: {
display: 'grid',
gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' },
gap: 'var(--Card-padding, 1rem)',
},
iamSectionDimmed: {
opacity: 0.5,
pointerEvents: 'none',
transition: 'opacity 0.2s',
},
} as const;
export function BedrockServiceSetup(props: { serviceId: DModelsServiceId }) {
@@ -26,18 +40,33 @@ export function BedrockServiceSetup(props: { serviceId: DModelsServiceId }) {
useServiceSetup(props.serviceId, ModelVendorBedrock);
// derived state
const { bedrockAccessKeyId, bedrockSecretAccessKey, bedrockSessionToken, bedrockRegion } = serviceAccess;
const { bedrockAccessKeyId, bedrockSecretAccessKey, bedrockBearerToken, bedrockRegion } = serviceAccess;
const needsUserKey = !serviceHasCloudTenantConfig;
// advanced mode
// const advanced = useToggleableBoolean(!!bedrockSessionToken);
const [showSetupInstructions, setShowSetupInstructions] = React.useState(false);
// Bearer validation
const bearerTokenValid = isValidBedrockBearerToken(bedrockBearerToken);
const bearerTokenError = !!bedrockBearerToken && !bearerTokenValid;
// IAM validation
const accessKeyValid = isValidBedrockAccessKeyId(bedrockAccessKeyId);
const secretKeyValid = isValidBedrockSecretAccessKey(bedrockSecretAccessKey);
const accessKeyError = (!!bedrockAccessKeyId) && !accessKeyValid;
const secretKeyError = (!!bedrockSecretAccessKey) && !secretKeyValid;
const shallFetchSucceed = bedrockAccessKeyId ? (accessKeyValid && secretKeyValid) : !needsUserKey;
const accessKeyError = !!bedrockAccessKeyId && !accessKeyValid;
const secretKeyError = !!bedrockSecretAccessKey && !secretKeyValid;
// bearer token takes implicit priority - dim IAM when bearer is active
const hasBearer = !!bedrockBearerToken;
// const hasIAM = !!bedrockAccessKeyId || !!bedrockSecretAccessKey;
// fetch: succeed if valid client credentials exist, or server-configured
const shallFetchSucceed =
bedrockBearerToken ? bearerTokenValid
: bedrockAccessKeyId ? (accessKeyValid && secretKeyValid)
: !needsUserKey;
// fetch models
const { isFetching, refetch, isError, error } =
@@ -49,40 +78,63 @@ export function BedrockServiceSetup(props: { serviceId: DModelsServiceId }) {
<Box sx={{ display: 'flex', gap: 2, alignItems: 'flex-start' }}>
<ClaudeCrabIcon sx={{ fontSize: '2rem', mt: 0.5 }} />
<Box sx={{ flex: 1 }}>
Access Claude models through your <Link color='neutral' href='https://aws.amazon.com/bedrock/' level='body-sm' target='_blank'>AWS Bedrock</Link> account.
Requires an IAM Access Key with Bedrock permissions - Bedrock does not support search.
Access Claude models through your <Link color='neutral' href='https://aws.amazon.com/bedrock/' level='body-sm' target='_blank'>AWS Bedrock</Link> account
using a long-term <strong>API Key</strong> or <strong>IAM credentials</strong>.
{showSetupInstructions && (
<Typography level='body-xs' component='ol' sx={{ pl: 2, mt: 1, display: 'flex', flexDirection: 'column', gap: 0.5 }}>
<li>Open the <Link href='https://console.aws.amazon.com/iam/' target='_blank'>AWS IAM Console</Link></li>
<li>Go to <strong>Users</strong> -&gt; <strong>Create user</strong> (e.g. <code>big-agi-bedrock</code>, no console access)</li>
<li>Attach the <strong>AmazonBedrockFullAccess</strong> policy</li>
<li>Open the user -&gt; <strong>Security credentials</strong> -&gt; <strong>Create access key</strong></li>
<li>Select <strong>&quot;Application running outside AWS&quot;</strong> -&gt; Create</li>
<li>Copy the <strong>Access Key ID</strong> and <strong>Secret Access Key</strong> (shown only once)</li>
<li>Enter them below with your <strong>AWS Region</strong></li>
<li><strong>API Key</strong>: in the <Link href='https://console.aws.amazon.com/bedrock/' target='_blank'>Bedrock Console</Link>, create a long-term key (<code>ABSK...</code>). Short-term keys don&apos;t support model listing</li>
<li><strong>AWS IAM</strong>: in the <Link href='https://console.aws.amazon.com/iam/' target='_blank'>IAM Console</Link>, create a user with the <strong>AmazonBedrockFullAccess</strong> permission policy. Open the user, go to <strong>Security credentials</strong>, then <strong>Create access key</strong> (<strong>&quot;Application running outside AWS&quot;</strong>) and copy both keys</li>
<li>Select your <strong>AWS Models Region</strong> below</li>
</Typography>
)}
</Box>
<IconButton size='sm' variant='plain' color='neutral' onClick={() => setShowSetupInstructions(on => !on)}>
{showSetupInstructions ? <UnfoldLessIcon /> : <UnfoldMoreIcon />}
<IconButton size='sm' variant={showSetupInstructions ? 'solid' : 'soft'} color='neutral' onClick={() => setShowSetupInstructions(on => !on)}>
<InfoOutlinedIcon />
</IconButton>
</Box>
</ApproximateCosts>
{/* Bearer token (API Key) - highest client-side priority */}
<FormInputKey
autoCompleteId='bedrock-access-key-id' label='AWS Access Key ID'
rightLabel={!needsUserKey ? 'Set on server' : undefined}
value={bedrockAccessKeyId} onChange={value => updateSettings({ bedrockAccessKeyId: value })}
required={needsUserKey} isError={accessKeyError}
placeholder='AKIA...'
autoCompleteId='bedrock-bearer-token' label='Bedrock long-term API Key'
rightLabel={<>{needsUserKey
? undefined
: <AlreadySet />
}</>}
value={bedrockBearerToken} onChange={value => updateSettings({ bedrockBearerToken: value })}
required={false} // required={needsUserKey && !hasIAM}
isError={bearerTokenError}
placeholder='ABSK...'
/>
<FormInputKey
autoCompleteId='bedrock-secret-access-key' label='AWS Secret Access Key'
value={bedrockSecretAccessKey} onChange={value => updateSettings({ bedrockSecretAccessKey: value })}
required={needsUserKey} isError={secretKeyError}
placeholder='wJalr...'
/>
<Divider>or</Divider>
{/* IAM credentials - side by side on md+, stacked on mobile, dimmed when bearer is active */}
<Box sx={hasBearer ? _styles.iamSectionDimmed : undefined}>
<Box sx={_styles.iamGrid}>
<FormInputKey
autoCompleteId='bedrock-access-key-id' label='AWS Access Key ID'
rightLabel={<>{needsUserKey
? undefined
: <AlreadySet />
}</>}
value={bedrockAccessKeyId} onChange={value => updateSettings({ bedrockAccessKeyId: value })}
required={false} // required={needsUserKey && !hasBearer}
isError={accessKeyError}
placeholder='AKIA...'
/>
<FormInputKey
autoCompleteId='bedrock-secret-access-key' label='AWS Secret Access Key'
value={bedrockSecretAccessKey} onChange={value => updateSettings({ bedrockSecretAccessKey: value })}
required={false} // required={needsUserKey && !hasBearer}
isError={secretKeyError}
placeholder='wJalr...'
/>
</Box>
</Box>
<BedrockRegionAutocomplete
value={bedrockRegion || ''}
@@ -99,8 +151,7 @@ export function BedrockServiceSetup(props: { serviceId: DModelsServiceId }) {
{/* onChange={text => updateSettings({ bedrockSessionToken: text })}*/}
{/*/>}*/}
<SetupFormRefetchButton refetch={refetch} disabled={!shallFetchSucceed || isFetching} loading={isFetching} error={isError} />
{/*<SetupFormRefetchButton refetch={refetch} disabled={!shallFetchSucceed || isFetching} loading={isFetching} error={isError} advanced={advanced} />*/}
<SetupFormRefetchButton refetch={refetch} disabled={!shallFetchSucceed || isFetching} loading={isFetching} error={isError} /*advanced={advanced}*/ />
{isError && <InlineError error={error} />}
+16 -4
View File
@@ -5,10 +5,12 @@ import type { IModelVendor } from '../IModelVendor';
// validation
export const isValidBedrockBearerToken = (key?: string) => !!key && key.length >= 20;
export const isValidBedrockAccessKeyId = (key?: string) => !!key && key.length >= 16;
export const isValidBedrockSecretAccessKey = (key?: string) => !!key && key.length >= 16;
export interface DBedrockServiceSettings {
bedrockBearerToken: string;
bedrockAccessKeyId: string;
bedrockSecretAccessKey: string;
bedrockSessionToken: string;
@@ -31,6 +33,7 @@ export const ModelVendorBedrock: IModelVendor<DBedrockServiceSettings, BedrockAc
// functions
initializeSetup: () => ({
bedrockBearerToken: '',
bedrockAccessKeyId: '',
bedrockSecretAccessKey: '',
bedrockSessionToken: '',
@@ -40,9 +43,18 @@ export const ModelVendorBedrock: IModelVendor<DBedrockServiceSettings, BedrockAc
getTransportAccess: (partialSetup): BedrockAccessSchema => ({
dialect: 'bedrock',
bedrockAccessKeyId: partialSetup?.bedrockAccessKeyId || '',
bedrockSecretAccessKey: partialSetup?.bedrockSecretAccessKey || '',
bedrockSessionToken: partialSetup?.bedrockSessionToken || null,
// bearer token takes priority; don't send IAM credentials alongside it
...(partialSetup?.bedrockBearerToken ? {
bedrockBearerToken: partialSetup.bedrockBearerToken,
bedrockAccessKeyId: '',
bedrockSecretAccessKey: '',
bedrockSessionToken: null,
} : {
bedrockBearerToken: '',
bedrockAccessKeyId: partialSetup?.bedrockAccessKeyId || '',
bedrockSecretAccessKey: partialSetup?.bedrockSecretAccessKey || '',
bedrockSessionToken: partialSetup?.bedrockSessionToken || null,
}),
bedrockRegion: partialSetup?.bedrockRegion || 'us-west-2',
clientSideFetch: _csfBedrockAvailable(partialSetup) && !!partialSetup?.csf,
}),
@@ -53,5 +65,5 @@ export const ModelVendorBedrock: IModelVendor<DBedrockServiceSettings, BedrockAc
};
function _csfBedrockAvailable(s?: Partial<DBedrockServiceSettings>) {
return !!s?.bedrockAccessKeyId && !!s?.bedrockSecretAccessKey;
return !!s?.bedrockBearerToken || (!!s?.bedrockAccessKeyId && !!s?.bedrockSecretAccessKey);
}
+2 -1
View File
@@ -53,7 +53,8 @@ export const env = createEnv({
ANTHROPIC_API_KEY: z.string().optional(),
ANTHROPIC_API_HOST: z.url().optional(),
// LLM: AWS Bedrock (using 2 or 3 auth values)
// LLM: AWS Bedrock (bearer token OR IAM credentials)
BEDROCK_BEARER_TOKEN: z.string().optional(), // Bedrock long-term API key (ABSK...) - takes priority over IAM credentials; short-term keys only work for runtime, not model listing
BEDROCK_ACCESS_KEY_ID: z.string().optional(),
BEDROCK_SECRET_ACCESS_KEY: z.string().optional(),
BEDROCK_SESSION_TOKEN: z.string().optional(), // required with the other 2 on corporate accounts sometimes