fix: prevent SageMaker TGI from being marked configured when only Bedrock keys are set (#7284)
Signed-off-by: ibaaaaal rifaldi.51922721@mahasiswa.unikom.ac.id Co-authored-by: Lifei Zhou <lifei@squareup.com>
This commit is contained in:
@@ -323,7 +323,7 @@ impl ProviderDef for BedrockProvider {
|
|||||||
BEDROCK_DOC_LINK,
|
BEDROCK_DOC_LINK,
|
||||||
vec![
|
vec![
|
||||||
ConfigKey::new("AWS_PROFILE", false, false, Some("default"), true),
|
ConfigKey::new("AWS_PROFILE", false, false, Some("default"), true),
|
||||||
ConfigKey::new("AWS_REGION", false, false, None, true),
|
ConfigKey::new("AWS_REGION", true, false, Some("us-east-1"), true),
|
||||||
ConfigKey::new("AWS_BEARER_TOKEN_BEDROCK", false, true, None, true),
|
ConfigKey::new("AWS_BEARER_TOKEN_BEDROCK", false, true, None, true),
|
||||||
ConfigKey::new("BEDROCK_ENABLE_CACHING", false, false, Some("false"), false),
|
ConfigKey::new("BEDROCK_ENABLE_CACHING", false, false, Some("false"), false),
|
||||||
],
|
],
|
||||||
@@ -456,11 +456,18 @@ mod tests {
|
|||||||
.iter()
|
.iter()
|
||||||
.find(|k| k.name == "AWS_REGION")
|
.find(|k| k.name == "AWS_REGION")
|
||||||
.expect("AWS_REGION config key should exist");
|
.expect("AWS_REGION config key should exist");
|
||||||
assert!(!aws_region.required, "AWS_REGION should not be required");
|
assert!(
|
||||||
|
aws_region.required,
|
||||||
|
"AWS_REGION is required for Bedrock to be marked as configured"
|
||||||
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!aws_region.secret,
|
!aws_region.secret,
|
||||||
"AWS_REGION should not be marked as secret"
|
"AWS_REGION should not be marked as secret"
|
||||||
);
|
);
|
||||||
|
assert!(
|
||||||
|
aws_region.default.is_some(),
|
||||||
|
"AWS_REGION should have a default value"
|
||||||
|
);
|
||||||
|
|
||||||
let bearer_token = meta
|
let bearer_token = meta
|
||||||
.config_keys
|
.config_keys
|
||||||
|
|||||||
@@ -285,8 +285,8 @@ impl ProviderDef for SageMakerTgiProvider {
|
|||||||
SAGEMAKER_TGI_DOC_LINK,
|
SAGEMAKER_TGI_DOC_LINK,
|
||||||
vec![
|
vec![
|
||||||
ConfigKey::new("SAGEMAKER_ENDPOINT_NAME", true, false, None, true),
|
ConfigKey::new("SAGEMAKER_ENDPOINT_NAME", true, false, None, true),
|
||||||
ConfigKey::new("AWS_REGION", true, false, Some("us-east-1"), true),
|
ConfigKey::new("AWS_REGION", false, false, Some("us-east-1"), true),
|
||||||
ConfigKey::new("AWS_PROFILE", true, false, Some("default"), true),
|
ConfigKey::new("AWS_PROFILE", false, false, Some("default"), true),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,11 +145,17 @@ export default function ChatInput({
|
|||||||
null
|
null
|
||||||
) as React.RefObject<HTMLDivElement>;
|
) as React.RefObject<HTMLDivElement>;
|
||||||
const { getProviders } = useConfig();
|
const { getProviders } = useConfig();
|
||||||
const { getCurrentModelAndProvider, currentModel: configModel, currentProvider: configProvider } = useModelAndProvider();
|
const {
|
||||||
|
getCurrentModelAndProvider,
|
||||||
|
currentModel: configModel,
|
||||||
|
currentProvider: configProvider,
|
||||||
|
} = useModelAndProvider();
|
||||||
|
|
||||||
// Local override for when the user changes the model in the modal,
|
// Local override for when the user changes the model in the modal,
|
||||||
// before the session object is re-fetched from the backend.
|
// before the session object is re-fetched from the backend.
|
||||||
const [modelOverride, setModelOverride] = useState<{ model: string; provider: string } | null>(null);
|
const [modelOverride, setModelOverride] = useState<{ model: string; provider: string } | null>(
|
||||||
|
null
|
||||||
|
);
|
||||||
const effectiveModel = modelOverride?.model ?? sessionModel ?? configModel;
|
const effectiveModel = modelOverride?.model ?? sessionModel ?? configModel;
|
||||||
const effectiveProvider = modelOverride?.provider ?? sessionProvider ?? configProvider;
|
const effectiveProvider = modelOverride?.provider ?? sessionProvider ?? configProvider;
|
||||||
|
|
||||||
@@ -157,8 +163,12 @@ export default function ChatInput({
|
|||||||
// active chats, config defaults for Hub / no-session contexts).
|
// active chats, config defaults for Hub / no-session contexts).
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!modelOverride) return;
|
if (!modelOverride) return;
|
||||||
const sessionCaughtUp = sessionModel === modelOverride.model && sessionProvider === modelOverride.provider;
|
const sessionCaughtUp =
|
||||||
const configCaughtUp = !sessionId && configModel === modelOverride.model && configProvider === modelOverride.provider;
|
sessionModel === modelOverride.model && sessionProvider === modelOverride.provider;
|
||||||
|
const configCaughtUp =
|
||||||
|
!sessionId &&
|
||||||
|
configModel === modelOverride.model &&
|
||||||
|
configProvider === modelOverride.provider;
|
||||||
if (sessionCaughtUp || configCaughtUp) {
|
if (sessionCaughtUp || configCaughtUp) {
|
||||||
setModelOverride(null);
|
setModelOverride(null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,13 @@ interface CostTrackerProps {
|
|||||||
provider: string | null;
|
provider: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CostTracker({ inputTokens = 0, outputTokens = 0, sessionCosts, model: currentModel, provider: currentProvider }: CostTrackerProps) {
|
export function CostTracker({
|
||||||
|
inputTokens = 0,
|
||||||
|
outputTokens = 0,
|
||||||
|
sessionCosts,
|
||||||
|
model: currentModel,
|
||||||
|
provider: currentProvider,
|
||||||
|
}: CostTrackerProps) {
|
||||||
const [costInfo, setCostInfo] = useState<ModelInfoData | null>(null);
|
const [costInfo, setCostInfo] = useState<ModelInfoData | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [showPricing, setShowPricing] = useState(true);
|
const [showPricing, setShowPricing] = useState(true);
|
||||||
|
|||||||
@@ -49,8 +49,12 @@ export const CreditsExhaustedNotification: React.FC<CreditsExhaustedNotification
|
|||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<AlertTriangle className="h-4 w-4 text-yellow-600 dark:text-yellow-400 mt-0.5 shrink-0" />
|
<AlertTriangle className="h-4 w-4 text-yellow-600 dark:text-yellow-400 mt-0.5 shrink-0" />
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="text-sm font-semibold text-yellow-800 dark:text-yellow-200">Insufficient Credits</div>
|
<div className="text-sm font-semibold text-yellow-800 dark:text-yellow-200">
|
||||||
<div className="text-sm text-yellow-800/80 dark:text-yellow-200/80 mt-1">{notification.msg}</div>
|
Insufficient Credits
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-yellow-800/80 dark:text-yellow-200/80 mt-1">
|
||||||
|
{notification.msg}
|
||||||
|
</div>
|
||||||
{topUpUrl && (
|
{topUpUrl && (
|
||||||
<button
|
<button
|
||||||
onClick={handleTopUp}
|
onClick={handleTopUp}
|
||||||
|
|||||||
@@ -206,10 +206,7 @@ export const DictationSettings = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<MicrophoneSelector
|
<MicrophoneSelector selectedDeviceId={preferredMic} onDeviceChange={handleMicChange} />
|
||||||
selectedDeviceId={preferredMic}
|
|
||||||
onDeviceChange={handleMicChange}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ interface MicrophoneSelectorProps {
|
|||||||
|
|
||||||
const TEST_DURATION_MS = 5000;
|
const TEST_DURATION_MS = 5000;
|
||||||
|
|
||||||
export const MicrophoneSelector = ({ selectedDeviceId, onDeviceChange }: MicrophoneSelectorProps) => {
|
export const MicrophoneSelector = ({
|
||||||
|
selectedDeviceId,
|
||||||
|
onDeviceChange,
|
||||||
|
}: MicrophoneSelectorProps) => {
|
||||||
const [devices, setDevices] = useState<MediaDeviceInfo[]>([]);
|
const [devices, setDevices] = useState<MediaDeviceInfo[]>([]);
|
||||||
const [hasPermission, setHasPermission] = useState(false);
|
const [hasPermission, setHasPermission] = useState(false);
|
||||||
const [isTesting, setIsTesting] = useState(false);
|
const [isTesting, setIsTesting] = useState(false);
|
||||||
@@ -163,9 +166,7 @@ export const MicrophoneSelector = ({ selectedDeviceId, onDeviceChange }: Microph
|
|||||||
value={selectedDeviceId ?? 'system_default'}
|
value={selectedDeviceId ?? 'system_default'}
|
||||||
onValueChange={(v) => onDeviceChange(v === 'system_default' ? null : v)}
|
onValueChange={(v) => onDeviceChange(v === 'system_default' ? null : v)}
|
||||||
>
|
>
|
||||||
<DropdownMenuRadioItem value="system_default">
|
<DropdownMenuRadioItem value="system_default">System Default</DropdownMenuRadioItem>
|
||||||
System Default
|
|
||||||
</DropdownMenuRadioItem>
|
|
||||||
{devices.map((device, i) => (
|
{devices.map((device, i) => (
|
||||||
<DropdownMenuRadioItem key={device.deviceId} value={device.deviceId}>
|
<DropdownMenuRadioItem key={device.deviceId} value={device.deviceId}>
|
||||||
<span className="truncate">{getDeviceLabel(device, i)}</span>
|
<span className="truncate">{getDeviceLabel(device, i)}</span>
|
||||||
|
|||||||
@@ -101,7 +101,11 @@ export const SwitchModelModal = ({
|
|||||||
sessionProvider,
|
sessionProvider,
|
||||||
}: SwitchModelModalProps) => {
|
}: SwitchModelModalProps) => {
|
||||||
const { getProviders, read, upsert } = useConfig();
|
const { getProviders, read, upsert } = useConfig();
|
||||||
const { changeModel, currentModel: configModel, currentProvider: configProvider } = useModelAndProvider();
|
const {
|
||||||
|
changeModel,
|
||||||
|
currentModel: configModel,
|
||||||
|
currentProvider: configProvider,
|
||||||
|
} = useModelAndProvider();
|
||||||
// Use session-specific model/provider if available, otherwise fall back to config defaults
|
// Use session-specific model/provider if available, otherwise fall back to config defaults
|
||||||
const currentModel = sessionModel ?? configModel;
|
const currentModel = sessionModel ?? configModel;
|
||||||
const currentProvider = sessionProvider ?? configProvider;
|
const currentProvider = sessionProvider ?? configProvider;
|
||||||
|
|||||||
Reference in New Issue
Block a user