diff --git a/spire-ui/src/components/SettingsLlmModelForm.tsx b/spire-ui/src/components/SettingsLlmModelForm.tsx index 3d0e9ead..718ada69 100644 --- a/spire-ui/src/components/SettingsLlmModelForm.tsx +++ b/spire-ui/src/components/SettingsLlmModelForm.tsx @@ -131,57 +131,65 @@ export default function SettingsLlmModelForm({ initial, onClose, onSaved }: Sett return (
-
e.stopPropagation()} role="dialog" aria-modal="true"> +
e.stopPropagation()} role="dialog" aria-modal="true">

{editing ? 'Edit model' : 'Add model'}

-
- + +
+ + + + + + - - +
+ +
+
Prices · $ per 1M tokens
+ {pricingMode === 'METERED' + ? + : Self-hosted: this model has no per-token price.} +
- - - - - {pricingMode === 'METERED' && } - - - {error &&
{error}
}
diff --git a/spire-ui/src/components/SettingsLlmModelRateFields.tsx b/spire-ui/src/components/SettingsLlmModelRateFields.tsx index cba2c376..1f8f194b 100644 --- a/spire-ui/src/components/SettingsLlmModelRateFields.tsx +++ b/spire-ui/src/components/SettingsLlmModelRateFields.tsx @@ -1,3 +1,4 @@ +import { useId } from 'react'; import type { LlmModelView, PricingMode } from '../api'; import { dollarsToMillicentsPerMillion, millicentsPerMillionToDollars } from '../money'; import { MANDATORY_RATE_TYPES, RATE_TYPES, TOKEN_TYPE_LABEL, type RateType } from '../llmPricing'; @@ -85,24 +86,28 @@ interface RateFieldProps { } /** One rate input, mapped over {@link RATE_TYPES} rather than hand-written per dimension — the label, - * the optional/mandatory marker and the placeholder all already come from shared, tested tables. */ + * the optional/mandatory marker and the placeholder all already come from shared, tested tables. The + * row shows only the type's name and a star when it is required; the input's own name still says the + * whole thing ("Input rate $ / 1M tokens, required"), which a screen reader and the tests both read. */ function RateField({ type, value, onChange, notBilled, onNotBilled }: RateFieldProps) { - const optional = !MANDATORY_RATE_TYPES.includes(type); + const id = useId(); + const mandatory = MANDATORY_RATE_TYPES.includes(type); return ( -
-