feat: add requires_auth flag for custom providers without authentication (#6705)

Signed-off-by: rabi <ramishra@redhat.com>
This commit is contained in:
Rabi Mishra
2026-01-28 22:34:12 +05:30
committed by GitHub
parent 5b757c7f72
commit 2673e8acca
13 changed files with 250 additions and 153 deletions
+6 -1
View File
@@ -3480,7 +3480,6 @@
"name",
"engine",
"display_name",
"api_key_env",
"base_url",
"models"
],
@@ -3517,6 +3516,9 @@
"name": {
"type": "string"
},
"requires_auth": {
"type": "boolean"
},
"supports_streaming": {
"type": "boolean",
"nullable": true
@@ -6698,6 +6700,9 @@
"type": "string"
}
},
"requires_auth": {
"type": "boolean"
},
"supports_streaming": {
"type": "boolean",
"nullable": true
+3 -1
View File
@@ -154,7 +154,7 @@ export type CspMetadata = {
};
export type DeclarativeProviderConfig = {
api_key_env: string;
api_key_env?: string;
base_url: string;
description?: string | null;
display_name: string;
@@ -164,6 +164,7 @@ export type DeclarativeProviderConfig = {
} | null;
models: Array<ModelInfo>;
name: string;
requires_auth?: boolean;
supports_streaming?: boolean | null;
timeout_seconds?: number | null;
};
@@ -1204,6 +1205,7 @@ export type UpdateCustomProviderRequest = {
[key: string]: string;
} | null;
models: Array<string>;
requires_auth?: boolean;
supports_streaming?: boolean | null;
};
@@ -24,7 +24,7 @@ export default function CustomProviderForm({
const [apiUrl, setApiUrl] = useState('');
const [apiKey, setApiKey] = useState('');
const [models, setModels] = useState('');
const [isLocalModel, setIsLocalModel] = useState(false);
const [noAuthRequired, setNoAuthRequired] = useState(false);
const [supportsStreaming, setSupportsStreaming] = useState(true);
const [validationErrors, setValidationErrors] = useState<Record<string, string>>({});
@@ -40,14 +40,13 @@ export default function CustomProviderForm({
setApiUrl(initialData.api_url);
setModels(initialData.models.join(', '));
setSupportsStreaming(initialData.supports_streaming ?? true);
setNoAuthRequired(!(initialData.requires_auth ?? true));
}
}, [initialData]);
const handleLocalModels = (checked: boolean) => {
setIsLocalModel(checked);
const handleNoAuthChange = (checked: boolean) => {
setNoAuthRequired(!!checked);
if (checked) {
setApiKey('notrequired');
} else {
setApiKey('');
}
};
@@ -58,7 +57,8 @@ export default function CustomProviderForm({
const errors: Record<string, string> = {};
if (!displayName) errors.displayName = 'Display name is required';
if (!apiUrl) errors.apiUrl = 'API URL is required';
if (!isLocalModel && !apiKey && !initialData) errors.apiKey = 'API key is required';
const existingHadAuth = initialData && (initialData.requires_auth ?? true);
if (!noAuthRequired && !apiKey && !existingHadAuth) errors.apiKey = 'API key is required';
if (!models) errors.models = 'At least one model is required';
if (Object.keys(errors).length > 0) {
@@ -78,6 +78,7 @@ export default function CustomProviderForm({
api_key: apiKey,
models: modelList,
supports_streaming: supportsStreaming,
requires_auth: !noAuthRequired,
});
};
@@ -173,40 +174,45 @@ export default function CustomProviderForm({
)}
<div>
<label
htmlFor="api-key"
className="flex items-center text-sm font-medium text-textStandard mb-2"
>
API Key
{!isLocalModel && !initialData && <span className="text-red-500 ml-1">*</span>}
</label>
<Input
id="api-key"
type="password"
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
placeholder={initialData ? 'Leave blank to keep existing key' : 'Your API key'}
aria-invalid={!!validationErrors.apiKey}
aria-describedby={validationErrors.apiKey ? 'api-key-error' : undefined}
className={validationErrors.apiKey ? 'border-red-500' : ''}
disabled={isLocalModel}
/>
{validationErrors.apiKey && (
<p id="api-key-error" className="text-red-500 text-sm mt-1">
{validationErrors.apiKey}
</p>
)}
<div className="flex items-center space-x-2 mb-2">
<Checkbox
id="no-auth-required"
checked={noAuthRequired}
onCheckedChange={handleNoAuthChange}
/>
<label
htmlFor="no-auth-required"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-textSubtle"
>
No authentication required
</label>
</div>
{!initialData && (
<div className="flex items-center space-x-2 mt-2">
<Checkbox id="local-model" checked={isLocalModel} onCheckedChange={handleLocalModels} />
{!noAuthRequired && (
<>
<label
htmlFor="local-model"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-textSubtle"
htmlFor="api-key"
className="flex items-center text-sm font-medium text-textStandard mb-2"
>
This is a local model (no auth required)
API Key
{!initialData && <span className="text-red-500 ml-1">*</span>}
</label>
</div>
<Input
id="api-key"
type="password"
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
placeholder={initialData ? 'Leave blank to keep existing key' : 'Your API key'}
aria-invalid={!!validationErrors.apiKey}
aria-describedby={validationErrors.apiKey ? 'api-key-error' : undefined}
className={validationErrors.apiKey ? 'border-red-500' : ''}
/>
{validationErrors.apiKey && (
<p id="api-key-error" className="text-red-500 text-sm mt-1">
{validationErrors.apiKey}
</p>
)}
</>
)}
</div>
{isEditable && (