Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ differing backup and rewrites known legacy namespaced selected ids to bare ids.
| `models?` | `string[]` | Seed/fallback model list. With `liveModels: false`, these are the only discovered models. |
| `liveModels?` | `boolean` | Fetch the live catalog on start/sync (default `true`). Custom providers use `${baseUrl}/models`; built-ins may use a registry URL and filter. |
| `selectedModels?` | `string[]` | Catalog allowlist after discovery. Non-empty exposes only those ids; empty or omitted exposes all discovered models. |
| `contextWindow?` | `number` | Provider-wide Codex-visible context cap. Smaller live metadata is retained. |
| `modelContextWindows?` | `Record<string, number>` | Per-model context caps. These override `contextWindow` and never raise smaller live metadata. |
| `contextWindow?` | `number` | Provider-wide context fallback when upstream metadata is absent; otherwise a cap that retains smaller live metadata. The Models dashboard exposes this separately from `providerContextCaps`. |
| `modelContextWindows?` | `Record<string, number>` | Per-model context fallbacks/caps. These override `contextWindow`: an unknown window uses the configured value, while smaller live metadata remains authoritative. |
| `modelInputModalities?` | `Record<string, string[]>` | Per-model input hints such as `["text"]` or `["text", "image"]`. |
| `modelMaxInputTokens?` | `Record<string, number>` | Positive per-model max input limits used for catalog auto-compaction hints. |
| `defaultMaxOutputTokens?` | `number` | Provider-wide `openai-chat` fallback when the client omits `max_output_tokens`. |
Expand Down
10 changes: 10 additions & 0 deletions gui/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,16 @@ export const de: Record<TKey, string> = {
"models.v2ThreadsInvalid": "Thread-Limit muss eine ganze Zahl >= 1 sein",
"models.v2ThreadsApply": "Anwenden",
"models.capValue": "Limit {value}",
"models.contextSettings": "Kontextfenster",
"models.contextSettingsTitle": "Kontextfenster — {provider}",
"models.contextDefault": "Anbieterstandard",
"models.contextModel": "Modell",
"models.contextModelOverride": "Modellüberschreibung",
"models.contextHint": "Wird verwendet, wenn Upstream-Metadaten fehlen; andernfalls begrenzt der Wert ein größeres gemeldetes Fenster. Leer lassen für automatische Erkennung.",
"models.contextAutomatic": "Automatische Erkennung",
"models.contextSaved": "Kontextfenster aktualisiert — gilt ab der nächsten Codex-Runde.",
"models.contextSaveFailed": "Kontextfenster konnten nicht gespeichert werden",
"models.contextInvalid": "Kontextfenster müssen positive ganze Zahlen sein",
"models.contextCappedValue": "{value}-Limit",
"models.setAll": "Alle setzen",
"models.setAllHint": "Wendet das {value}-Kontext-Limit auf alle gerouteten Anbieter an. Native Anbieter bleiben unberührt.",
Expand Down
10 changes: 10 additions & 0 deletions gui/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,16 @@ export const en = {
"models.v2ThreadsInvalid": "Thread limit must be an integer >= 1",
"models.v2ThreadsApply": "Apply",
"models.capValue": "Cap {value}",
"models.contextSettings": "Context windows",
"models.contextSettingsTitle": "Context windows — {provider}",
"models.contextDefault": "Provider default",
"models.contextModel": "Model",
"models.contextModelOverride": "Model override",
"models.contextHint": "Used when upstream metadata is missing; otherwise limits a larger reported window. Leave blank for automatic discovery.",
"models.contextAutomatic": "Automatic discovery",
"models.contextSaved": "Context windows updated — takes effect on the next Codex turn.",
"models.contextSaveFailed": "Failed to save context windows",
"models.contextInvalid": "Context windows must be positive whole numbers",
"models.contextCappedValue": "{value} cap",
"models.setAll": "Set all",
"models.setAllHint": "Apply the {value} context cap to every routed provider. Native providers are unaffected.",
Expand Down
10 changes: 10 additions & 0 deletions gui/src/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,16 @@ export const ja: Record<TKey, string> = {
"models.v2ThreadsInvalid": "スレッド上限は 1 以上の整数にしてください",
"models.v2ThreadsApply": "適用",
"models.capValue": "上限 {value}",
"models.contextSettings": "コンテキストウィンドウ",
"models.contextSettingsTitle": "コンテキストウィンドウ — {provider}",
"models.contextDefault": "プロバイダーのデフォルト",
"models.contextModel": "モデル",
"models.contextModelOverride": "モデル別の上書き",
"models.contextHint": "上流メタデータがない場合に使われ、メタデータがある場合は報告値の上限になります。自動検出に戻すには空欄にします。",
"models.contextAutomatic": "自動検出",
"models.contextSaved": "コンテキストウィンドウを更新しました — 次回の Codex ターンから有効です。",
"models.contextSaveFailed": "コンテキストウィンドウを保存できませんでした",
"models.contextInvalid": "コンテキストウィンドウは正の整数で指定してください",
"models.contextCappedValue": "{value} 上限",
"models.setAll": "すべて設定",
"models.setAllHint": "{value} のコンテキスト上限をすべてのルーティング済みプロバイダーに適用します。ネイティブプロバイダーには影響しません。",
Expand Down
10 changes: 10 additions & 0 deletions gui/src/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,16 @@ export const ko: Record<TKey, string> = {
"models.v2ThreadsInvalid": "스레드 한도는 1 이상 정수여야 합니다",
"models.v2ThreadsApply": "적용",
"models.capValue": "{value} 제한",
"models.contextSettings": "컨텍스트 윈도우",
"models.contextSettingsTitle": "컨텍스트 윈도우 — {provider}",
"models.contextDefault": "프로바이더 기본값",
"models.contextModel": "모델",
"models.contextModelOverride": "모델별 재정의",
"models.contextHint": "업스트림 메타데이터가 없을 때 사용하며, 메타데이터가 있으면 더 큰 보고값의 상한으로 적용합니다. 자동 검색을 사용하려면 비워 두세요.",
"models.contextAutomatic": "자동 검색",
"models.contextSaved": "컨텍스트 윈도우가 업데이트되었습니다 — 다음 Codex 턴부터 적용됩니다.",
"models.contextSaveFailed": "컨텍스트 윈도우를 저장하지 못했습니다",
"models.contextInvalid": "컨텍스트 윈도우는 양의 정수여야 합니다",
"models.contextCappedValue": "{value} 제한",
"models.setAll": "전체 적용",
"models.setAllHint": "{value} 컨텍스트 상한을 라우팅된 모든 프로바이더에 적용합니다. 네이티브 프로바이더는 영향을 받지 않습니다.",
Expand Down
10 changes: 10 additions & 0 deletions gui/src/i18n/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,16 @@ export const ru: Record<TKey, string> = {
"models.v2ThreadsInvalid": "Лимит потоков должен быть целым числом >= 1",
"models.v2ThreadsApply": "Применить",
"models.capValue": "Лимит {value}",
"models.contextSettings": "Контекстные окна",
"models.contextSettingsTitle": "Контекстные окна — {provider}",
"models.contextDefault": "Значение провайдера",
"models.contextModel": "Модель",
"models.contextModelOverride": "Переопределение модели",
"models.contextHint": "Используется, если вышестоящие метаданные отсутствуют; иначе ограничивает большее заявленное окно. Оставьте поле пустым для автоматического определения.",
"models.contextAutomatic": "Автоматическое определение",
"models.contextSaved": "Контекстные окна обновлены — изменения вступят в силу на следующем ходе Codex.",
"models.contextSaveFailed": "Не удалось сохранить контекстные окна",
"models.contextInvalid": "Контекстные окна должны быть положительными целыми числами",
"models.contextCappedValue": "Лимит {value}",
"models.setAll": "Применить ко всем",
"models.setAllHint": "Применяет лимит контекста {value} ко всем маршрутизируемым провайдерам. Нативные провайдеры не затрагиваются.",
Expand Down
10 changes: 10 additions & 0 deletions gui/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,16 @@ export const zh: Record<TKey, string> = {
"models.v2ThreadsInvalid": "线程上限必须为 >= 1 的整数",
"models.v2ThreadsApply": "应用",
"models.capValue": "限制 {value}",
"models.contextSettings": "上下文窗口",
"models.contextSettingsTitle": "上下文窗口 — {provider}",
"models.contextDefault": "提供方默认值",
"models.contextModel": "模型",
"models.contextModelOverride": "模型覆盖值",
"models.contextHint": "上游缺少元数据时使用该值;上游已有元数据时,它只限制更大的报告值。留空则恢复自动发现。",
"models.contextAutomatic": "自动发现",
"models.contextSaved": "上下文窗口已更新 — 将在下一个 Codex 回合生效。",
"models.contextSaveFailed": "保存上下文窗口失败",
"models.contextInvalid": "上下文窗口必须为正整数",
"models.contextCappedValue": "{value} 限制",
"models.setAll": "全部设置",
"models.setAllHint": "将 {value} 上下文上限应用到所有已路由的提供方。原生提供方不受影响。",
Expand Down
6 changes: 6 additions & 0 deletions gui/src/models-groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export interface ConfiguredProviderSummary {
disabled?: boolean;
liveModels?: boolean;
models?: string[];
contextWindow?: number;
modelContextWindows?: Record<string, number>;
discovery?: ProviderDiscoverySummary;
}

Expand All @@ -23,6 +25,8 @@ export interface ProviderModelGroup<Row> {
native: boolean;
liveModels: boolean;
configuredModels: string[];
contextWindow?: number;
modelContextWindows?: Record<string, number>;
discovery?: ProviderDiscoverySummary;
}

Expand Down Expand Up @@ -56,6 +60,8 @@ export function buildProviderModelGroups<Row extends { provider: string; native?
native: providerRows.length > 0 && providerRows.every(row => row.native === true),
liveModels: configured?.liveModels !== false,
configuredModels: configured?.models ?? [],
contextWindow: configured?.contextWindow,
modelContextWindows: configured?.modelContextWindows,
discovery: configured?.discovery,
};
})
Expand Down
176 changes: 176 additions & 0 deletions gui/src/pages/Models.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ export default function Models({ apiBase }: { apiBase: string }) {
const [customFormModalities, setCustomFormModalities] = useState<string[]>(["text"]);
const [customSaving, setCustomSaving] = useState(false);
const [customError, setCustomError] = useState("");
const [contextModalProvider, setContextModalProvider] = useState<string | null>(null);
const [contextModalModels, setContextModalModels] = useState<string[]>([]);
const [contextModelId, setContextModelId] = useState("");
const [contextDefaultDraft, setContextDefaultDraft] = useState("");
const [contextModelDrafts, setContextModelDrafts] = useState<Record<string, string>>({});
const [contextSaving, setContextSaving] = useState(false);
const [contextError, setContextError] = useState("");
const [hoveredModel, setHoveredModel] = useState<{ namespaced: string; rect: DOMRect } | null>(null);
const hoverTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const [shadowCall, setShadowCall] = useState<ShadowCallData | null>(null);
Expand Down Expand Up @@ -342,6 +349,75 @@ export default function Models({ apiBase }: { apiBase: string }) {
*/
const catalogCountReady = models.length > 0 || catalogState.data !== undefined;

const openContextSettings = (group: ProviderModelGroup<ModelRow>) => {
const modelIds = [...new Set([
...group.rows.map(model => model.id),
...group.configuredModels,
])].sort();
const modelId = modelIds[0] ?? "";
setContextModalProvider(group.provider);
setContextModalModels(modelIds);
setContextModelId(modelId);
setContextDefaultDraft(group.contextWindow ? String(group.contextWindow) : "");
setContextModelDrafts(Object.fromEntries(
Object.entries(group.modelContextWindows ?? {})
.map(([model, window]) => [model, String(window)]),
));
setContextError("");
};

const selectContextModel = (modelId: string) => {
setContextModelId(modelId);
};
Comment on lines +369 to +371

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Switching the model selector silently discards the unsaved override draft.

selectContextModel at Line 339 always overwrites contextModelDraft from group.modelContextWindows?.[modelId] the moment the user picks a different model in the Select at Line 1336-1342. If the user types a new override value for the currently selected model and then reselects a different model to check its value, the typed-but-unsaved value is lost with no warning, since nothing persists it before the overwrite.

Preserve per-model drafts across selector changes so browsing other models does not erase in-progress edits.
[recommended_refactor_or_suggestion]

♻️ Proposed fix: keep a per-model draft map
   const [contextModelDraft, setContextModelDraft] = useState("");
+  const [contextModelDrafts, setContextModelDrafts] = useState<Record<string, string>>({});
   const selectContextModel = (modelId: string) => {
     const group = groups.find(candidate => candidate.provider === contextModalProvider);
+    setContextModelDrafts(prev => ({ ...prev, [contextModelId]: contextModelDraft }));
     setContextModelId(modelId);
-    setContextModelDraft(group?.modelContextWindows?.[modelId]
-      ? String(group.modelContextWindows[modelId])
-      : "");
+    setContextModelDraft(
+      contextModelDrafts[modelId]
+      ?? (group?.modelContextWindows?.[modelId] ? String(group.modelContextWindows[modelId]) : ""),
+    );
   };

contextModelDrafts should also be reset in openContextSettings when the dialog opens for a new provider.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gui/src/pages/Models.tsx` around lines 339 - 345, Update selectContextModel
to preserve unsaved context overrides in a per-model contextModelDrafts map
instead of overwriting the current draft when switching models; load each
model’s existing draft or persisted value when selected, and reset
contextModelDrafts in openContextSettings when opening settings for a new
provider.


const parseContextWindowDraft = (raw: string): number | null | undefined => {
const normalized = raw.replace(/[_,\s]/g, "");
if (!normalized) return null;
const value = Number(normalized);
return Number.isFinite(value) && Number.isInteger(value) && value > 0
? value
: undefined;
};

const saveContextSettings = async () => {
if (!contextModalProvider) return;
const providerWindow = parseContextWindowDraft(contextDefaultDraft);
const modelWindow = parseContextWindowDraft(contextModelDrafts[contextModelId] ?? "");
if (providerWindow === undefined || modelWindow === undefined) {
setContextError(t("models.contextInvalid"));
return;
}
const group = groups.find(candidate => candidate.provider === contextModalProvider);
if (!group) {
setContextError(t("models.contextSaveFailed"));
return;
}

setContextSaving(true);
setContextError("");
try {
const body: Record<string, unknown> = { contextWindow: providerWindow };
if (contextModelId) {
body.modelContextWindows = { [contextModelId]: modelWindow };
}
const response = await fetch(
`${apiBase}/api/providers?name=${encodeURIComponent(contextModalProvider)}`,
{
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
},
);
await readJsonOrThrow(response, t("models.contextSaveFailed"));
setContextModalProvider(null);
publishFeedback(true, t("models.contextSaved"));
await load(true);
} catch (error) {
setContextError(error instanceof Error ? error.message : t("models.contextSaveFailed"));
} finally {
setContextSaving(false);
}
};
Comment on lines +382 to +420

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

A refresh failure after a successful save reports the save as failed, unlike every other modal mutation in this file.

At Line 385, readJsonOrThrow(response, ...) does not throw, so the PATCH succeeded and the context-window values are persisted. At Line 386, load(true) is only a post-save catalog refresh. If it fails (transient network error, slow proxy), Lines 387-390 set contextError to t("models.loadFail") ("Failed to load models — is the proxy running?") and return before Line 391-392 ever run — so the modal stays open, showing an error that implies the save itself failed, when it did not.

Compare with addCustomModel (Lines 690-697) and updateCustomModel (Lines 714-721): both close the modal and call publishFeedback(true, ...) immediately once the write succeeds, then await load(true) afterward without gating success on its result. saveContextSettings is the only modal-driven mutation in this file that reverses that order and conditions the success path on the refresh outcome.

A user hitting a refresh hiccup right after saving will see a misleading "proxy not running" style message and may retry the save unnecessarily. Report success as soon as the PATCH succeeds, and let the refresh failure surface separately (the page already has catalogState.showError for a stale-catalog banner at Line 1554).

🐛 Proposed fix: match the addCustomModel/updateCustomModel pattern
       await readJsonOrThrow(response, t("models.contextSaveFailed"));
-      const refreshed = await load(true);
-      if (!refreshed) {
-        setContextError(t("models.loadFail"));
-        return;
-      }
       setContextModalProvider(null);
       publishFeedback(true, t("models.contextSaved"));
+      await load(true);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const saveContextSettings = async () => {
if (!contextModalProvider) return;
const providerWindow = parseContextWindowDraft(contextDefaultDraft);
const modelWindow = parseContextWindowDraft(contextModelDraft);
if (providerWindow === undefined || modelWindow === undefined) {
setContextError(t("models.contextInvalid"));
return;
}
const group = groups.find(candidate => candidate.provider === contextModalProvider);
if (!group) {
setContextError(t("models.contextSaveFailed"));
return;
}
setContextSaving(true);
setContextError("");
try {
const body: Record<string, unknown> = { contextWindow: providerWindow };
if (contextModelId) {
body.modelContextWindows = { [contextModelId]: modelWindow };
}
const response = await fetch(
`${apiBase}/api/providers?name=${encodeURIComponent(contextModalProvider)}`,
{
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
},
);
await readJsonOrThrow(response, t("models.contextSaveFailed"));
const refreshed = await load(true);
if (!refreshed) {
setContextError(t("models.loadFail"));
return;
}
setContextModalProvider(null);
publishFeedback(true, t("models.contextSaved"));
} catch (error) {
setContextError(error instanceof Error ? error.message : t("models.contextSaveFailed"));
} finally {
setContextSaving(false);
}
};
const saveContextSettings = async () => {
if (!contextModalProvider) return;
const providerWindow = parseContextWindowDraft(contextDefaultDraft);
const modelWindow = parseContextWindowDraft(contextModelDraft);
if (providerWindow === undefined || modelWindow === undefined) {
setContextError(t("models.contextInvalid"));
return;
}
const group = groups.find(candidate => candidate.provider === contextModalProvider);
if (!group) {
setContextError(t("models.contextSaveFailed"));
return;
}
setContextSaving(true);
setContextError("");
try {
const body: Record<string, unknown> = { contextWindow: providerWindow };
if (contextModelId) {
body.modelContextWindows = { [contextModelId]: modelWindow };
}
const response = await fetch(
`${apiBase}/api/providers?name=${encodeURIComponent(contextModalProvider)}`,
{
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
},
);
await readJsonOrThrow(response, t("models.contextSaveFailed"));
setContextModalProvider(null);
publishFeedback(true, t("models.contextSaved"));
await load(true);
} catch (error) {
setContextError(error instanceof Error ? error.message : t("models.contextSaveFailed"));
} finally {
setContextSaving(false);
}
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gui/src/pages/Models.tsx` around lines 356 - 398, Update saveContextSettings
so the context modal closes and publishFeedback reports success immediately
after readJsonOrThrow confirms the PATCH succeeded. Then call load(true) without
gating or reversing the successful save flow on its return value; remove the
refreshed-result check and contextError assignment for refresh failure, allowing
the existing catalog error handling to surface it separately.


// One-shot default collapse. It stays an effect on `groups` so CACHED groups collapse
// immediately on first paint, even when revalidation is slow or fails; moving it into
Expand Down Expand Up @@ -783,6 +859,14 @@ export default function Models({ apiBase }: { apiBase: string }) {
<span className="muted mono text-label">{t("models.active", { active: activeCount, total: rows.length })}</span>
</button>
<div className="row models-provider-actions">
{!isNative && (
<button
type="button"
className="btn btn-ghost btn-sm text-caption"
onClick={() => openContextSettings(group)}
aria-haspopup="dialog"
>{t("models.contextSettings")}</button>
)}
{!isNative && (
<button
type="button"
Expand Down Expand Up @@ -1144,6 +1228,98 @@ export default function Models({ apiBase }: { apiBase: string }) {
</div>
)}

{contextModalProvider && (
<div
className="modal-overlay"
role="dialog"
aria-modal="true"
aria-label={t("models.contextSettings")}
onClick={() => { if (!contextSaving) setContextModalProvider(null); }}
onKeyDown={(event) => {
if (event.key === "Escape" && !contextSaving) setContextModalProvider(null);
}}
>
<div className="modal-card" onClick={event => event.stopPropagation()}>
<div className="modal-head">
<h3>{t("models.contextSettingsTitle", {
provider: formatProviderDisplayName(contextModalProvider, t),
})}</h3>
<button
type="button"
className="btn btn-ghost btn-sm"
onClick={() => setContextModalProvider(null)}
disabled={contextSaving}
aria-label={t("common.close")}
>&times;</button>
</div>

{contextError && <Notice tone="err">{contextError}</Notice>}
<p className="modal-desc leading-relaxed">{t("models.contextHint")}</p>

<div className="models-context-fields">
<label className="text-label models-field">
{t("models.contextDefault")}
<input
className="input"
inputMode="numeric"
value={contextDefaultDraft}
onChange={event => setContextDefaultDraft(event.target.value)}
disabled={contextSaving}
placeholder={t("models.contextAutomatic")}
autoFocus
/>
</label>

{contextModalModels.length > 0 && (
<>
<div className="text-label models-field">
{t("models.contextModel")}
<Select
value={contextModelId}
options={contextModalModels.map(model => ({ value: model, label: model }))}
onChange={selectContextModel}
disabled={contextSaving}
label={t("models.contextModel")}
/>
</div>
<label className="text-label models-field">
{t("models.contextModelOverride")}
<input
className="input"
inputMode="numeric"
value={contextModelDrafts[contextModelId] ?? ""}
onChange={event => setContextModelDrafts(current => ({
...current,
[contextModelId]: event.target.value,
}))}
disabled={contextSaving}
placeholder={t("models.contextAutomatic")}
/>
</label>
</>
)}
</div>

<div className="modal-actions">
<button
type="button"
className="btn btn-ghost"
onClick={() => setContextModalProvider(null)}
disabled={contextSaving}
>{t("common.cancel")}</button>
<button
type="button"
className="btn btn-primary"
onClick={() => void saveContextSettings()}
disabled={contextSaving}
>
{contextSaving ? t("models.customSaving") : t("models.customApply")}
</button>
</div>
</div>
</div>
)}

{customModalOpen && (
<div
className="modal-overlay"
Expand Down
6 changes: 6 additions & 0 deletions gui/src/styles-models-workspace.css
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,12 @@
margin-top: var(--space-3);
}

.models-context-fields {
display: flex;
flex-direction: column;
gap: var(--space-4);
}

.models-field {
display: flex;
flex-direction: column;
Expand Down
Loading
Loading