mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-01-02 22:32:27 +08:00
fix: complete bedrock support and UI/UX improvements
- Add bedrock to ALLOWED_CLIENT_PROVIDERS for client credentials - Pass AWS credentials through full chain (headers → API → provider) - Replace non-existent GPT-5 models with real ones (o1, o3-mini) - Add accessibility: aria-labels, focus-visible rings, inline errors - Add more AWS regions (Ohio, London, Paris, Mumbai, Seoul, São Paulo) - Fix setTimeout cleanup with useRef on component unmount - Fix TypeScript type consistency in getSelectedAIConfig fallback
This commit is contained in:
@@ -214,6 +214,11 @@ async function handleChatRequest(req: Request): Promise<Response> {
|
|||||||
baseUrl: req.headers.get("x-ai-base-url"),
|
baseUrl: req.headers.get("x-ai-base-url"),
|
||||||
apiKey: req.headers.get("x-ai-api-key"),
|
apiKey: req.headers.get("x-ai-api-key"),
|
||||||
modelId: req.headers.get("x-ai-model"),
|
modelId: req.headers.get("x-ai-model"),
|
||||||
|
// AWS Bedrock credentials
|
||||||
|
awsAccessKeyId: req.headers.get("x-aws-access-key-id"),
|
||||||
|
awsSecretAccessKey: req.headers.get("x-aws-secret-access-key"),
|
||||||
|
awsRegion: req.headers.get("x-aws-region"),
|
||||||
|
awsSessionToken: req.headers.get("x-aws-session-token"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read minimal style preference from header
|
// Read minimal style preference from header
|
||||||
|
|||||||
@@ -1041,6 +1041,20 @@ Continue from EXACTLY where you stopped.`,
|
|||||||
"x-ai-api-key": config.aiApiKey,
|
"x-ai-api-key": config.aiApiKey,
|
||||||
}),
|
}),
|
||||||
...(config.aiModel && { "x-ai-model": config.aiModel }),
|
...(config.aiModel && { "x-ai-model": config.aiModel }),
|
||||||
|
// AWS Bedrock credentials
|
||||||
|
...(config.awsAccessKeyId && {
|
||||||
|
"x-aws-access-key-id": config.awsAccessKeyId,
|
||||||
|
}),
|
||||||
|
...(config.awsSecretAccessKey && {
|
||||||
|
"x-aws-secret-access-key":
|
||||||
|
config.awsSecretAccessKey,
|
||||||
|
}),
|
||||||
|
...(config.awsRegion && {
|
||||||
|
"x-aws-region": config.awsRegion,
|
||||||
|
}),
|
||||||
|
...(config.awsSessionToken && {
|
||||||
|
"x-aws-session-token": config.awsSessionToken,
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
...(minimalStyle && {
|
...(minimalStyle && {
|
||||||
"x-minimal-style": "true",
|
"x-minimal-style": "true",
|
||||||
|
|||||||
@@ -116,6 +116,9 @@ export function ModelConfigDialog({
|
|||||||
const [scrollState, setScrollState] = useState({ top: false, bottom: true })
|
const [scrollState, setScrollState] = useState({ top: false, bottom: true })
|
||||||
const [customModelInput, setCustomModelInput] = useState("")
|
const [customModelInput, setCustomModelInput] = useState("")
|
||||||
const scrollRef = useRef<HTMLDivElement>(null)
|
const scrollRef = useRef<HTMLDivElement>(null)
|
||||||
|
const validationResetTimeoutRef = useRef<ReturnType<
|
||||||
|
typeof setTimeout
|
||||||
|
> | null>(null)
|
||||||
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false)
|
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false)
|
||||||
const [validatingModelIndex, setValidatingModelIndex] = useState<
|
const [validatingModelIndex, setValidatingModelIndex] = useState<
|
||||||
number | null
|
number | null
|
||||||
@@ -156,6 +159,15 @@ export function ModelConfigDialog({
|
|||||||
return () => scrollEl.removeEventListener("scroll", handleScroll)
|
return () => scrollEl.removeEventListener("scroll", handleScroll)
|
||||||
}, [selectedProvider])
|
}, [selectedProvider])
|
||||||
|
|
||||||
|
// Cleanup validation reset timeout on unmount
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (validationResetTimeoutRef.current) {
|
||||||
|
clearTimeout(validationResetTimeoutRef.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
// Get suggested models for current provider
|
// Get suggested models for current provider
|
||||||
const suggestedModels = selectedProvider
|
const suggestedModels = selectedProvider
|
||||||
? SUGGESTED_MODELS[selectedProvider.provider] || []
|
? SUGGESTED_MODELS[selectedProvider.provider] || []
|
||||||
@@ -292,8 +304,14 @@ export function ModelConfigDialog({
|
|||||||
if (allValid) {
|
if (allValid) {
|
||||||
setValidationStatus("success")
|
setValidationStatus("success")
|
||||||
updateProvider(selectedProviderId!, { validated: true })
|
updateProvider(selectedProviderId!, { validated: true })
|
||||||
// Reset to idle after showing success briefly
|
// Reset to idle after showing success briefly (with cleanup)
|
||||||
setTimeout(() => setValidationStatus("idle"), 1500)
|
if (validationResetTimeoutRef.current) {
|
||||||
|
clearTimeout(validationResetTimeoutRef.current)
|
||||||
|
}
|
||||||
|
validationResetTimeoutRef.current = setTimeout(() => {
|
||||||
|
setValidationStatus("idle")
|
||||||
|
validationResetTimeoutRef.current = null
|
||||||
|
}, 1500)
|
||||||
} else {
|
} else {
|
||||||
setValidationStatus("error")
|
setValidationStatus("error")
|
||||||
setValidationError(`${errorCount} model(s) failed validation`)
|
setValidationError(`${errorCount} model(s) failed validation`)
|
||||||
@@ -360,7 +378,7 @@ export function ModelConfigDialog({
|
|||||||
setShowApiKey(false)
|
setShowApiKey(false)
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"group flex items-center gap-3 px-3 py-2.5 rounded-lg text-left text-sm transition-all duration-150 hover:bg-accent",
|
"group flex items-center gap-3 px-3 py-2.5 rounded-lg text-left text-sm transition-all duration-150 hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||||
selectedProviderId ===
|
selectedProviderId ===
|
||||||
provider.id &&
|
provider.id &&
|
||||||
"bg-background shadow-sm ring-1 ring-border",
|
"bg-background shadow-sm ring-1 ring-border",
|
||||||
@@ -605,7 +623,12 @@ export function ModelConfigDialog({
|
|||||||
!showApiKey,
|
!showApiKey,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors"
|
aria-label={
|
||||||
|
showApiKey
|
||||||
|
? "Hide secret access key"
|
||||||
|
: "Show secret access key"
|
||||||
|
}
|
||||||
|
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded"
|
||||||
>
|
>
|
||||||
{showApiKey ? (
|
{showApiKey ? (
|
||||||
<EyeOff className="h-4 w-4" />
|
<EyeOff className="h-4 w-4" />
|
||||||
@@ -642,12 +665,16 @@ export function ModelConfigDialog({
|
|||||||
<SelectTrigger className="h-9 font-mono text-xs hover:bg-accent">
|
<SelectTrigger className="h-9 font-mono text-xs hover:bg-accent">
|
||||||
<SelectValue placeholder="Select region" />
|
<SelectValue placeholder="Select region" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent className="max-h-64">
|
||||||
<SelectItem value="us-east-1">
|
<SelectItem value="us-east-1">
|
||||||
us-east-1
|
us-east-1
|
||||||
(N.
|
(N.
|
||||||
Virginia)
|
Virginia)
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
<SelectItem value="us-east-2">
|
||||||
|
us-east-2
|
||||||
|
(Ohio)
|
||||||
|
</SelectItem>
|
||||||
<SelectItem value="us-west-2">
|
<SelectItem value="us-west-2">
|
||||||
us-west-2
|
us-west-2
|
||||||
(Oregon)
|
(Oregon)
|
||||||
@@ -656,14 +683,30 @@ export function ModelConfigDialog({
|
|||||||
eu-west-1
|
eu-west-1
|
||||||
(Ireland)
|
(Ireland)
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
<SelectItem value="eu-west-2">
|
||||||
|
eu-west-2
|
||||||
|
(London)
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="eu-west-3">
|
||||||
|
eu-west-3
|
||||||
|
(Paris)
|
||||||
|
</SelectItem>
|
||||||
<SelectItem value="eu-central-1">
|
<SelectItem value="eu-central-1">
|
||||||
eu-central-1
|
eu-central-1
|
||||||
(Frankfurt)
|
(Frankfurt)
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
<SelectItem value="ap-south-1">
|
||||||
|
ap-south-1
|
||||||
|
(Mumbai)
|
||||||
|
</SelectItem>
|
||||||
<SelectItem value="ap-northeast-1">
|
<SelectItem value="ap-northeast-1">
|
||||||
ap-northeast-1
|
ap-northeast-1
|
||||||
(Tokyo)
|
(Tokyo)
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
<SelectItem value="ap-northeast-2">
|
||||||
|
ap-northeast-2
|
||||||
|
(Seoul)
|
||||||
|
</SelectItem>
|
||||||
<SelectItem value="ap-southeast-1">
|
<SelectItem value="ap-southeast-1">
|
||||||
ap-southeast-1
|
ap-southeast-1
|
||||||
(Singapore)
|
(Singapore)
|
||||||
@@ -672,6 +715,11 @@ export function ModelConfigDialog({
|
|||||||
ap-southeast-2
|
ap-southeast-2
|
||||||
(Sydney)
|
(Sydney)
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
<SelectItem value="sa-east-1">
|
||||||
|
sa-east-1
|
||||||
|
(São
|
||||||
|
Paulo)
|
||||||
|
</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
@@ -771,7 +819,12 @@ export function ModelConfigDialog({
|
|||||||
!showApiKey,
|
!showApiKey,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors"
|
aria-label={
|
||||||
|
showApiKey
|
||||||
|
? "Hide API key"
|
||||||
|
: "Show API key"
|
||||||
|
}
|
||||||
|
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded"
|
||||||
>
|
>
|
||||||
{showApiKey ? (
|
{showApiKey ? (
|
||||||
<EyeOff className="h-4 w-4" />
|
<EyeOff className="h-4 w-4" />
|
||||||
@@ -984,7 +1037,7 @@ export function ModelConfigDialog({
|
|||||||
model.id
|
model.id
|
||||||
}
|
}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-3 p-3 transition-colors hover:bg-muted/30",
|
"transition-colors hover:bg-muted/30",
|
||||||
index ===
|
index ===
|
||||||
0 &&
|
0 &&
|
||||||
"rounded-t-xl",
|
"rounded-t-xl",
|
||||||
@@ -996,87 +1049,94 @@ export function ModelConfigDialog({
|
|||||||
"rounded-b-xl",
|
"rounded-b-xl",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* Status icon */}
|
<div className="flex items-center gap-3 p-3">
|
||||||
<div
|
{/* Status icon */}
|
||||||
className="flex items-center justify-center w-8 h-8 rounded-lg flex-shrink-0"
|
<div className="flex items-center justify-center w-8 h-8 rounded-lg flex-shrink-0">
|
||||||
title={
|
{validatingModelIndex !==
|
||||||
model.validationError ||
|
null &&
|
||||||
""
|
index ===
|
||||||
}
|
validatingModelIndex ? (
|
||||||
>
|
// Currently validating
|
||||||
{validatingModelIndex !==
|
<div className="w-full h-full rounded-lg bg-blue-500/10 flex items-center justify-center">
|
||||||
null &&
|
<Loader2 className="h-4 w-4 text-blue-500 animate-spin" />
|
||||||
index ===
|
</div>
|
||||||
validatingModelIndex ? (
|
) : validatingModelIndex !==
|
||||||
// Currently validating
|
null &&
|
||||||
<div className="w-full h-full rounded-lg bg-blue-500/10 flex items-center justify-center">
|
index >
|
||||||
<Loader2 className="h-4 w-4 text-blue-500 animate-spin" />
|
validatingModelIndex &&
|
||||||
</div>
|
model.validated ===
|
||||||
) : validatingModelIndex !==
|
undefined ? (
|
||||||
null &&
|
// Queued
|
||||||
index >
|
<div className="w-full h-full rounded-lg bg-muted flex items-center justify-center">
|
||||||
validatingModelIndex &&
|
<Clock className="h-4 w-4 text-muted-foreground" />
|
||||||
model.validated ===
|
</div>
|
||||||
undefined ? (
|
) : model.validated ===
|
||||||
// Queued
|
true ? (
|
||||||
<div className="w-full h-full rounded-lg bg-muted flex items-center justify-center">
|
// Valid
|
||||||
<Clock className="h-4 w-4 text-muted-foreground" />
|
<div className="w-full h-full rounded-lg bg-emerald-500/10 flex items-center justify-center">
|
||||||
</div>
|
<Check className="h-4 w-4 text-emerald-500" />
|
||||||
) : model.validated ===
|
</div>
|
||||||
true ? (
|
) : model.validated ===
|
||||||
// Valid
|
false ? (
|
||||||
<div className="w-full h-full rounded-lg bg-emerald-500/10 flex items-center justify-center">
|
// Invalid
|
||||||
<Check className="h-4 w-4 text-emerald-500" />
|
<div className="w-full h-full rounded-lg bg-destructive/10 flex items-center justify-center">
|
||||||
</div>
|
<AlertCircle className="h-4 w-4 text-destructive" />
|
||||||
) : model.validated ===
|
</div>
|
||||||
false ? (
|
) : (
|
||||||
// Invalid
|
// Not validated yet
|
||||||
<div className="w-full h-full rounded-lg bg-destructive/10 flex items-center justify-center">
|
<div className="w-full h-full rounded-lg bg-primary/5 flex items-center justify-center">
|
||||||
<AlertCircle className="h-4 w-4 text-destructive" />
|
<Zap className="h-4 w-4 text-primary" />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
)}
|
||||||
// Not validated yet
|
</div>
|
||||||
<div className="w-full h-full rounded-lg bg-primary/5 flex items-center justify-center">
|
<Input
|
||||||
<Zap className="h-4 w-4 text-primary" />
|
value={
|
||||||
</div>
|
model.modelId
|
||||||
)}
|
}
|
||||||
|
onChange={(
|
||||||
|
e,
|
||||||
|
) => {
|
||||||
|
updateModel(
|
||||||
|
selectedProviderId!,
|
||||||
|
model.id,
|
||||||
|
{
|
||||||
|
modelId:
|
||||||
|
e
|
||||||
|
.target
|
||||||
|
.value,
|
||||||
|
validated:
|
||||||
|
undefined,
|
||||||
|
validationError:
|
||||||
|
undefined,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
className="flex-1 font-mono text-sm h-8 border-0 bg-transparent focus-visible:bg-background focus-visible:ring-1"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="h-7 w-7 text-muted-foreground hover:text-destructive"
|
||||||
|
onClick={() =>
|
||||||
|
handleDeleteModel(
|
||||||
|
model.id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
aria-label={`Delete ${model.modelId}`}
|
||||||
|
>
|
||||||
|
<X className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Input
|
{/* Show validation error inline */}
|
||||||
value={
|
{model.validated ===
|
||||||
model.modelId
|
false &&
|
||||||
}
|
model.validationError && (
|
||||||
onChange={(
|
<p className="text-xs text-destructive px-3 pb-2 pl-14">
|
||||||
e,
|
|
||||||
) => {
|
|
||||||
updateModel(
|
|
||||||
selectedProviderId!,
|
|
||||||
model.id,
|
|
||||||
{
|
{
|
||||||
modelId:
|
model.validationError
|
||||||
e
|
}
|
||||||
.target
|
</p>
|
||||||
.value,
|
)}
|
||||||
validated:
|
|
||||||
undefined,
|
|
||||||
validationError:
|
|
||||||
undefined,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
className="flex-1 font-mono text-sm h-8 border-0 bg-transparent focus-visible:bg-background focus-visible:ring-1"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
className="h-7 w-7 text-muted-foreground hover:text-destructive"
|
|
||||||
onClick={() =>
|
|
||||||
handleDeleteModel(
|
|
||||||
model.id,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<X className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -299,6 +299,11 @@ export function getSelectedAIConfig(): {
|
|||||||
aiBaseUrl: string
|
aiBaseUrl: string
|
||||||
aiApiKey: string
|
aiApiKey: string
|
||||||
aiModel: string
|
aiModel: string
|
||||||
|
// AWS Bedrock credentials
|
||||||
|
awsAccessKeyId: string
|
||||||
|
awsSecretAccessKey: string
|
||||||
|
awsRegion: string
|
||||||
|
awsSessionToken: string
|
||||||
} {
|
} {
|
||||||
const empty = {
|
const empty = {
|
||||||
accessCode: "",
|
accessCode: "",
|
||||||
@@ -306,6 +311,10 @@ export function getSelectedAIConfig(): {
|
|||||||
aiBaseUrl: "",
|
aiBaseUrl: "",
|
||||||
aiApiKey: "",
|
aiApiKey: "",
|
||||||
aiModel: "",
|
aiModel: "",
|
||||||
|
awsAccessKeyId: "",
|
||||||
|
awsSecretAccessKey: "",
|
||||||
|
awsRegion: "",
|
||||||
|
awsSessionToken: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof window === "undefined") return empty
|
if (typeof window === "undefined") return empty
|
||||||
@@ -323,6 +332,11 @@ export function getSelectedAIConfig(): {
|
|||||||
aiBaseUrl: localStorage.getItem(OLD_KEYS.aiBaseUrl) || "",
|
aiBaseUrl: localStorage.getItem(OLD_KEYS.aiBaseUrl) || "",
|
||||||
aiApiKey: localStorage.getItem(OLD_KEYS.aiApiKey) || "",
|
aiApiKey: localStorage.getItem(OLD_KEYS.aiApiKey) || "",
|
||||||
aiModel: localStorage.getItem(OLD_KEYS.aiModel) || "",
|
aiModel: localStorage.getItem(OLD_KEYS.aiModel) || "",
|
||||||
|
// Old format didn't support AWS
|
||||||
|
awsAccessKeyId: "",
|
||||||
|
awsSecretAccessKey: "",
|
||||||
|
awsRegion: "",
|
||||||
|
awsSessionToken: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,5 +364,10 @@ export function getSelectedAIConfig(): {
|
|||||||
aiBaseUrl: model.baseUrl || "",
|
aiBaseUrl: model.baseUrl || "",
|
||||||
aiApiKey: model.apiKey,
|
aiApiKey: model.apiKey,
|
||||||
aiModel: model.modelId,
|
aiModel: model.modelId,
|
||||||
|
// AWS Bedrock credentials
|
||||||
|
awsAccessKeyId: model.awsAccessKeyId || "",
|
||||||
|
awsSecretAccessKey: model.awsSecretAccessKey || "",
|
||||||
|
awsRegion: model.awsRegion || "",
|
||||||
|
awsSessionToken: model.awsSessionToken || "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ export interface ClientOverrides {
|
|||||||
baseUrl?: string | null
|
baseUrl?: string | null
|
||||||
apiKey?: string | null
|
apiKey?: string | null
|
||||||
modelId?: string | null
|
modelId?: string | null
|
||||||
|
// AWS Bedrock credentials
|
||||||
|
awsAccessKeyId?: string | null
|
||||||
|
awsSecretAccessKey?: string | null
|
||||||
|
awsRegion?: string | null
|
||||||
|
awsSessionToken?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Providers that can be used with client-provided API keys
|
// Providers that can be used with client-provided API keys
|
||||||
@@ -41,6 +46,7 @@ const ALLOWED_CLIENT_PROVIDERS: ProviderName[] = [
|
|||||||
"anthropic",
|
"anthropic",
|
||||||
"google",
|
"google",
|
||||||
"azure",
|
"azure",
|
||||||
|
"bedrock",
|
||||||
"openrouter",
|
"openrouter",
|
||||||
"deepseek",
|
"deepseek",
|
||||||
"siliconflow",
|
"siliconflow",
|
||||||
@@ -537,12 +543,25 @@ export function getAIModel(overrides?: ClientOverrides): ModelConfig {
|
|||||||
|
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
case "bedrock": {
|
case "bedrock": {
|
||||||
// Use credential provider chain for IAM role support (Lambda, EC2, etc.)
|
// Use client-provided credentials if available, otherwise fall back to IAM/env vars
|
||||||
// Falls back to env vars (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) for local dev
|
const hasClientCredentials =
|
||||||
const bedrockProvider = createAmazonBedrock({
|
overrides?.awsAccessKeyId && overrides?.awsSecretAccessKey
|
||||||
region: process.env.AWS_REGION || "us-west-2",
|
const bedrockRegion =
|
||||||
credentialProvider: fromNodeProviderChain(),
|
overrides?.awsRegion || process.env.AWS_REGION || "us-west-2"
|
||||||
})
|
|
||||||
|
const bedrockProvider = hasClientCredentials
|
||||||
|
? createAmazonBedrock({
|
||||||
|
region: bedrockRegion,
|
||||||
|
accessKeyId: overrides.awsAccessKeyId!,
|
||||||
|
secretAccessKey: overrides.awsSecretAccessKey!,
|
||||||
|
...(overrides?.awsSessionToken && {
|
||||||
|
sessionToken: overrides.awsSessionToken,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
: createAmazonBedrock({
|
||||||
|
region: bedrockRegion,
|
||||||
|
credentialProvider: fromNodeProviderChain(),
|
||||||
|
})
|
||||||
model = bedrockProvider(modelId)
|
model = bedrockProvider(modelId)
|
||||||
// Add Anthropic beta options if using Claude models via Bedrock
|
// Add Anthropic beta options if using Claude models via Bedrock
|
||||||
if (modelId.includes("anthropic.claude")) {
|
if (modelId.includes("anthropic.claude")) {
|
||||||
|
|||||||
@@ -83,29 +83,22 @@ export const PROVIDER_INFO: Record<
|
|||||||
// Suggested models per provider for quick add
|
// Suggested models per provider for quick add
|
||||||
export const SUGGESTED_MODELS: Record<ProviderName, string[]> = {
|
export const SUGGESTED_MODELS: Record<ProviderName, string[]> = {
|
||||||
openai: [
|
openai: [
|
||||||
// GPT-5.2 series
|
// GPT-4o series (latest)
|
||||||
"gpt-5.2-pro",
|
|
||||||
"gpt-5.2-chat-latest",
|
|
||||||
"gpt-5.2",
|
|
||||||
// GPT-5.1 series
|
|
||||||
"gpt-5.1-codex-mini",
|
|
||||||
"gpt-5.1-codex",
|
|
||||||
"gpt-5.1-chat-latest",
|
|
||||||
"gpt-5.1",
|
|
||||||
// GPT-5 series
|
|
||||||
"gpt-5-pro",
|
|
||||||
"gpt-5",
|
|
||||||
"gpt-5-mini",
|
|
||||||
"gpt-5-nano",
|
|
||||||
"gpt-5-codex",
|
|
||||||
"gpt-5-chat-latest",
|
|
||||||
// GPT-4.1 series
|
|
||||||
"gpt-4.1",
|
|
||||||
"gpt-4.1-mini",
|
|
||||||
"gpt-4.1-nano",
|
|
||||||
// GPT-4o series
|
|
||||||
"gpt-4o",
|
"gpt-4o",
|
||||||
"gpt-4o-mini",
|
"gpt-4o-mini",
|
||||||
|
"gpt-4o-2024-11-20",
|
||||||
|
// GPT-4 Turbo
|
||||||
|
"gpt-4-turbo",
|
||||||
|
"gpt-4-turbo-preview",
|
||||||
|
// o1/o3 reasoning models
|
||||||
|
"o1",
|
||||||
|
"o1-mini",
|
||||||
|
"o1-preview",
|
||||||
|
"o3-mini",
|
||||||
|
// GPT-4
|
||||||
|
"gpt-4",
|
||||||
|
// GPT-3.5
|
||||||
|
"gpt-3.5-turbo",
|
||||||
],
|
],
|
||||||
anthropic: [
|
anthropic: [
|
||||||
// Claude 4.5 series (latest)
|
// Claude 4.5 series (latest)
|
||||||
|
|||||||
Reference in New Issue
Block a user