feat(webui): registry editor context-window/output/temperature fields + advanced section
This commit is contained in:
@@ -245,6 +245,7 @@ function ModelEditor({
|
|||||||
const [expanded, setExpanded] = useState(
|
const [expanded, setExpanded] = useState(
|
||||||
() => availabilityFor(data, ref) === null
|
() => availabilityFor(data, ref) === null
|
||||||
);
|
);
|
||||||
|
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||||
const capability = (key: "tools" | "vision" | "structured_output") => {
|
const capability = (key: "tools" | "vision" | "structured_output") => {
|
||||||
const protocolAllows = spec?.protocol_capabilities[key] !== false;
|
const protocolAllows = spec?.protocol_capabilities[key] !== false;
|
||||||
return (
|
return (
|
||||||
@@ -350,6 +351,52 @@ function ModelEditor({
|
|||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
|
<div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
|
||||||
|
<NumberField
|
||||||
|
label="Context window"
|
||||||
|
value={runtime.context_window_tokens}
|
||||||
|
nullable
|
||||||
|
onChange={(value) => setRuntime({ context_window_tokens: value })}
|
||||||
|
/>
|
||||||
|
<NumberField
|
||||||
|
label="Max output tokens"
|
||||||
|
value={runtime.max_output_tokens}
|
||||||
|
rule={rule("max_output_tokens")}
|
||||||
|
onChange={(value) =>
|
||||||
|
setRuntime({ max_output_tokens: value ?? runtime.max_output_tokens })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<NumberField
|
||||||
|
label={rule("temperature")?.supported === false ? "Temperature (unsupported)" : "Temperature"}
|
||||||
|
value={runtime.temperature}
|
||||||
|
nullable
|
||||||
|
rule={rule("temperature")}
|
||||||
|
onChange={(value) => setRuntime({ temperature: value })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<span className="text-xs font-medium text-muted-foreground">
|
||||||
|
Capabilities
|
||||||
|
</span>
|
||||||
|
{capability("tools")}
|
||||||
|
{capability("vision")}
|
||||||
|
{capability("structured_output")}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-expanded={showAdvanced}
|
||||||
|
className="flex items-center gap-1 text-xs font-medium text-muted-foreground hover:text-foreground"
|
||||||
|
onClick={() => setShowAdvanced((current) => !current)}
|
||||||
|
>
|
||||||
|
{showAdvanced ? (
|
||||||
|
<ChevronDown className="size-3.5" aria-hidden="true" />
|
||||||
|
) : (
|
||||||
|
<ChevronRight className="size-3.5" aria-hidden="true" />
|
||||||
|
)}
|
||||||
|
Advanced
|
||||||
|
</button>
|
||||||
|
{showAdvanced && (
|
||||||
|
<div className="mt-2 grid grid-cols-2 gap-2 sm:grid-cols-3">
|
||||||
<Field label="Limit mode">
|
<Field label="Limit mode">
|
||||||
<select
|
<select
|
||||||
className={inputClass}
|
className={inputClass}
|
||||||
@@ -364,26 +411,12 @@ function ModelEditor({
|
|||||||
<option value="input_only">input_only</option>
|
<option value="input_only">input_only</option>
|
||||||
</select>
|
</select>
|
||||||
</Field>
|
</Field>
|
||||||
<NumberField
|
|
||||||
label="Context window"
|
|
||||||
value={runtime.context_window_tokens}
|
|
||||||
nullable
|
|
||||||
onChange={(value) => setRuntime({ context_window_tokens: value })}
|
|
||||||
/>
|
|
||||||
<NumberField
|
<NumberField
|
||||||
label="Max input tokens"
|
label="Max input tokens"
|
||||||
value={runtime.max_input_tokens}
|
value={runtime.max_input_tokens}
|
||||||
nullable
|
nullable
|
||||||
onChange={(value) => setRuntime({ max_input_tokens: value })}
|
onChange={(value) => setRuntime({ max_input_tokens: value })}
|
||||||
/>
|
/>
|
||||||
<NumberField
|
|
||||||
label="Max output tokens"
|
|
||||||
value={runtime.max_output_tokens}
|
|
||||||
rule={rule("max_output_tokens")}
|
|
||||||
onChange={(value) =>
|
|
||||||
setRuntime({ max_output_tokens: value ?? runtime.max_output_tokens })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<NumberField
|
<NumberField
|
||||||
label="Min effective input"
|
label="Min effective input"
|
||||||
value={runtime.min_effective_input_tokens}
|
value={runtime.min_effective_input_tokens}
|
||||||
@@ -448,13 +481,6 @@ function ModelEditor({
|
|||||||
<option value="tested_contract">tested contract</option>
|
<option value="tested_contract">tested contract</option>
|
||||||
</select>
|
</select>
|
||||||
</Field>
|
</Field>
|
||||||
<NumberField
|
|
||||||
label={rule("temperature")?.supported === false ? "Temperature (unsupported)" : "Temperature"}
|
|
||||||
value={runtime.temperature}
|
|
||||||
nullable
|
|
||||||
rule={rule("temperature")}
|
|
||||||
onChange={(value) => setRuntime({ temperature: value })}
|
|
||||||
/>
|
|
||||||
<NumberField
|
<NumberField
|
||||||
label="Top p"
|
label="Top p"
|
||||||
value={runtime.top_p}
|
value={runtime.top_p}
|
||||||
@@ -493,13 +519,7 @@ function ModelEditor({
|
|||||||
</select>
|
</select>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-4">
|
)}
|
||||||
<span className="text-xs font-medium text-muted-foreground">
|
|
||||||
Capabilities
|
|
||||||
</span>
|
|
||||||
{capability("tools")}
|
|
||||||
{capability("vision")}
|
|
||||||
{capability("structured_output")}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -562,6 +582,8 @@ function ProviderEditor({
|
|||||||
const spec = adapterSpecFor(data.adapter_specs, provider.adapter);
|
const spec = adapterSpecFor(data.adapter_specs, provider.adapter);
|
||||||
const authModes = supportedAuthModes(spec);
|
const authModes = supportedAuthModes(spec);
|
||||||
const credentialStatus = credentialStatusFor(data, provider.auth.credential_id);
|
const credentialStatus = credentialStatusFor(data, provider.auth.credential_id);
|
||||||
|
const [showSecret, setShowSecret] = useState(false);
|
||||||
|
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||||
const setRuntime = (patch: Partial<ProviderConfig["runtime"]>) =>
|
const setRuntime = (patch: Partial<ProviderConfig["runtime"]>) =>
|
||||||
onChange({ ...provider, runtime: { ...provider.runtime, ...patch } });
|
onChange({ ...provider, runtime: { ...provider.runtime, ...patch } });
|
||||||
|
|
||||||
@@ -690,50 +712,67 @@ function ProviderEditor({
|
|||||||
</select>
|
</select>
|
||||||
</Field>
|
</Field>
|
||||||
{provider.auth.mode !== "none" && (
|
{provider.auth.mode !== "none" && (
|
||||||
<>
|
<Field
|
||||||
<Field
|
label="API Key"
|
||||||
label="Credential id"
|
hint={
|
||||||
hint={
|
stagedCredential
|
||||||
credentialStatus?.configured
|
? "staged — will be saved with the registry"
|
||||||
? `configured${credentialStatus.hint ? ` (${credentialStatus.hint})` : ""}`
|
: credentialStatus?.configured
|
||||||
: "not configured"
|
? `configured${credentialStatus.hint ? ` (${credentialStatus.hint})` : ""} — leave blank to keep`
|
||||||
}
|
: "paste your API key"
|
||||||
>
|
}
|
||||||
|
>
|
||||||
|
<div className="relative">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type={showSecret ? "text" : "password"}
|
||||||
className={inputClass}
|
className={`${inputClass} pr-8`}
|
||||||
value={provider.auth.credential_id ?? ""}
|
|
||||||
onChange={(event) =>
|
|
||||||
onChange({
|
|
||||||
...provider,
|
|
||||||
auth: { ...provider.auth, credential_id: event.target.value || null },
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Field>
|
|
||||||
<Field
|
|
||||||
label="Secret (write-once)"
|
|
||||||
hint={
|
|
||||||
stagedCredential
|
|
||||||
? "staged — saved with the registry"
|
|
||||||
: "leave blank to keep the current secret"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
className={inputClass}
|
|
||||||
value={stagedCredential ?? ""}
|
value={stagedCredential ?? ""}
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
onChange={(event) =>
|
placeholder={
|
||||||
provider.auth.credential_id &&
|
credentialStatus?.configured
|
||||||
onCredentialStage(provider.auth.credential_id, event.target.value)
|
? (credentialStatus.hint ?? "configured")
|
||||||
|
: "sk-..."
|
||||||
}
|
}
|
||||||
|
onChange={(event) => {
|
||||||
|
const credentialId =
|
||||||
|
provider.auth.credential_id ?? `${provider.id}-credential`;
|
||||||
|
if (!provider.auth.credential_id) {
|
||||||
|
onChange({
|
||||||
|
...provider,
|
||||||
|
auth: { ...provider.auth, credential_id: credentialId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onCredentialStage(credentialId, event.target.value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Field>
|
<button
|
||||||
</>
|
type="button"
|
||||||
|
aria-label={showSecret ? "Hide API key" : "Show API key"}
|
||||||
|
className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
|
||||||
|
onClick={() => setShowSecret((current) => !current)}
|
||||||
|
>
|
||||||
|
{showSecret ? <EyeOff size={16} /> : <Eye size={16} />}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Field>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
|
<div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-expanded={showAdvanced}
|
||||||
|
className="flex items-center gap-1 text-xs font-medium text-muted-foreground hover:text-foreground"
|
||||||
|
onClick={() => setShowAdvanced((current) => !current)}
|
||||||
|
>
|
||||||
|
{showAdvanced ? (
|
||||||
|
<ChevronDown className="size-3.5" aria-hidden="true" />
|
||||||
|
) : (
|
||||||
|
<ChevronRight className="size-3.5" aria-hidden="true" />
|
||||||
|
)}
|
||||||
|
Advanced
|
||||||
|
</button>
|
||||||
|
{showAdvanced && (
|
||||||
|
<div className="mt-2 grid grid-cols-2 gap-2 sm:grid-cols-3">
|
||||||
<NumberField
|
<NumberField
|
||||||
label="Timeout (s)"
|
label="Timeout (s)"
|
||||||
value={provider.runtime.timeout_seconds}
|
value={provider.runtime.timeout_seconds}
|
||||||
@@ -779,6 +818,8 @@ function ProviderEditor({
|
|||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</Field>
|
</Field>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
|||||||
Reference in New Issue
Block a user