import { useEffect, useState } from "react"; import type { Backend, BedrockAuthMethod, BedrockConfig, OllamaConfig, OpenAiCompatibleConfig, Project, } from "../../../../lib/types"; import Field, { ConfigGroup, SwitchRow, monoInputClass, selectClass, } from "../../../ui/Field"; import Toggle from "../../../ui/Toggle"; export const DEFAULT_BEDROCK_CONFIG: BedrockConfig = { auth_method: "static_credentials", aws_region: "us-east-1", aws_access_key_id: null, aws_secret_access_key: null, aws_session_token: null, aws_profile: null, aws_bearer_token: null, model_id: null, disable_prompt_caching: false, service_tier: null, }; export const DEFAULT_OLLAMA_CONFIG: OllamaConfig = { base_url: "http://host.docker.internal:11434", model_id: null, }; export const DEFAULT_OPENAI_COMPATIBLE_CONFIG: OpenAiCompatibleConfig = { base_url: "http://host.docker.internal:4000", api_key: null, model_id: null, }; interface Props { project: Project; save: (patch: Partial) => Promise; disabled: boolean; } export default function ModelSection({ project, save, disabled }: Props) { const bedrock = project.bedrock_config ?? DEFAULT_BEDROCK_CONFIG; // Local text state — saved on blur, not on every keystroke. const [bedrockRegion, setBedrockRegion] = useState(bedrock.aws_region); const [accessKeyId, setAccessKeyId] = useState(bedrock.aws_access_key_id ?? ""); const [secretKey, setSecretKey] = useState(bedrock.aws_secret_access_key ?? ""); const [sessionToken, setSessionToken] = useState(bedrock.aws_session_token ?? ""); const [profile, setProfile] = useState(bedrock.aws_profile ?? ""); const [bearerToken, setBearerToken] = useState(bedrock.aws_bearer_token ?? ""); const [bedrockModelId, setBedrockModelId] = useState(bedrock.model_id ?? ""); const [serviceTier, setServiceTier] = useState(bedrock.service_tier ?? ""); const [ollamaBaseUrl, setOllamaBaseUrl] = useState( project.ollama_config?.base_url ?? DEFAULT_OLLAMA_CONFIG.base_url, ); const [ollamaModelId, setOllamaModelId] = useState( project.ollama_config?.model_id ?? "", ); const [oaiBaseUrl, setOaiBaseUrl] = useState( project.openai_compatible_config?.base_url ?? DEFAULT_OPENAI_COMPATIBLE_CONFIG.base_url, ); const [oaiApiKey, setOaiApiKey] = useState( project.openai_compatible_config?.api_key ?? "", ); const [oaiModelId, setOaiModelId] = useState( project.openai_compatible_config?.model_id ?? "", ); useEffect(() => { const bc = project.bedrock_config ?? DEFAULT_BEDROCK_CONFIG; setBedrockRegion(bc.aws_region); setAccessKeyId(bc.aws_access_key_id ?? ""); setSecretKey(bc.aws_secret_access_key ?? ""); setSessionToken(bc.aws_session_token ?? ""); setProfile(bc.aws_profile ?? ""); setBearerToken(bc.aws_bearer_token ?? ""); setBedrockModelId(bc.model_id ?? ""); setServiceTier(bc.service_tier ?? ""); setOllamaBaseUrl(project.ollama_config?.base_url ?? DEFAULT_OLLAMA_CONFIG.base_url); setOllamaModelId(project.ollama_config?.model_id ?? ""); setOaiBaseUrl( project.openai_compatible_config?.base_url ?? DEFAULT_OPENAI_COMPATIBLE_CONFIG.base_url, ); setOaiApiKey(project.openai_compatible_config?.api_key ?? ""); setOaiModelId(project.openai_compatible_config?.model_id ?? ""); }, [project]); const saveBedrock = (patch: Partial) => save({ bedrock_config: { ...bedrock, ...patch } }); const saveOllama = (patch: Partial) => save({ ollama_config: { ...(project.ollama_config ?? DEFAULT_OLLAMA_CONFIG), ...patch }, }); const saveOpenAi = (patch: Partial) => save({ openai_compatible_config: { ...(project.openai_compatible_config ?? DEFAULT_OPENAI_COMPATIBLE_CONFIG), ...patch, }, }); // Defaults to on: projects created before the field existed, and any data // that predates it, should still pick the shared token up. const useSharedToken = project.use_shared_auth_token !== false; const handleBackendChange = (mode: Backend) => { const patch: Partial = { backend: mode }; if (mode === "bedrock" && !project.bedrock_config) patch.bedrock_config = DEFAULT_BEDROCK_CONFIG; if (mode === "ollama" && !project.ollama_config) patch.ollama_config = DEFAULT_OLLAMA_CONFIG; if (mode === "open_ai_compatible" && !project.openai_compatible_config) patch.openai_compatible_config = DEFAULT_OPENAI_COMPATIBLE_CONFIG; save(patch); }; return ( {(id) => ( )} {/* Only Anthropic reads CLAUDE_CODE_OAUTH_TOKEN; the other backends authenticate through their own credentials entirely. */} {project.backend === "anthropic" && (
save({ use_shared_auth_token: value })} disabled={disabled} /> } />
)} {project.backend === "bedrock" && (
{(id) => ( )} {(id) => ( setBedrockRegion(e.target.value)} onBlur={() => saveBedrock({ aws_region: bedrockRegion })} placeholder="us-east-1" disabled={disabled} className={monoInputClass} /> )} {bedrock.auth_method === "static_credentials" && ( <> {(id) => ( setAccessKeyId(e.target.value)} onBlur={() => saveBedrock({ aws_access_key_id: accessKeyId || null })} placeholder="AKIA…" disabled={disabled} className={monoInputClass} /> )} {(id) => ( setSecretKey(e.target.value)} onBlur={() => saveBedrock({ aws_secret_access_key: secretKey || null }) } disabled={disabled} className={monoInputClass} /> )} {(id) => ( setSessionToken(e.target.value)} onBlur={() => saveBedrock({ aws_session_token: sessionToken || null }) } disabled={disabled} className={monoInputClass} /> )} )} {bedrock.auth_method === "profile" && ( {(id) => ( setProfile(e.target.value)} onBlur={() => saveBedrock({ aws_profile: profile || null })} placeholder="default" disabled={disabled} className={monoInputClass} /> )} )} {bedrock.auth_method === "bearer_token" && ( {(id) => ( setBearerToken(e.target.value)} onBlur={() => saveBedrock({ aws_bearer_token: bearerToken || null })} disabled={disabled} className={monoInputClass} /> )} )} {(id) => ( setBedrockModelId(e.target.value)} onBlur={() => saveBedrock({ model_id: bedrockModelId || null })} placeholder="anthropic.claude-sonnet-4-20250514-v1:0" disabled={disabled} className={monoInputClass} /> )} {(id) => ( setServiceTier(e.target.value)} onBlur={() => saveBedrock({ service_tier: serviceTier.trim() || null })} placeholder="(account default)" disabled={disabled} className={monoInputClass} /> )}
)} {project.backend === "ollama" && (
{(id) => ( setOllamaBaseUrl(e.target.value)} onBlur={() => saveOllama({ base_url: ollamaBaseUrl })} placeholder="http://host.docker.internal:11434" disabled={disabled} className={monoInputClass} /> )} {(id) => ( setOllamaModelId(e.target.value)} onBlur={() => saveOllama({ model_id: ollamaModelId || null })} placeholder="qwen3.5:27b" disabled={disabled} className={monoInputClass} /> )}
)} {project.backend === "open_ai_compatible" && (
{(id) => ( setOaiBaseUrl(e.target.value)} onBlur={() => saveOpenAi({ base_url: oaiBaseUrl })} placeholder="http://host.docker.internal:4000" disabled={disabled} className={monoInputClass} /> )} {(id) => ( setOaiApiKey(e.target.value)} onBlur={() => saveOpenAi({ api_key: oaiApiKey || null })} placeholder="sk-…" disabled={disabled} className={monoInputClass} /> )} {(id) => ( setOaiModelId(e.target.value)} onBlur={() => saveOpenAi({ model_id: oaiModelId || null })} placeholder="gpt-4o / gemini-pro / …" disabled={disabled} className={monoInputClass} /> )}
)}
); }