FN-8752: move escalation model to project selector
Centralize executor escalation model selection with the project-scoped provider-aware model control. - Move escalation provider and model fields from Scheduling to Project Models - Persist and clear escalation model pairs atomically through the shared selector - Update search metadata, localization, documentation, and mobile coverage Files changed: docs/settings-reference.md | 6 +- .../__tests__/SettingsModal.mobileClose.test.tsx | 29 +++++++ .../__tests__/SettingsModal.models-auth.test.tsx | 94 ++++++++++++++++++++++ .../search/__tests__/settings-search-index.test.ts | 17 ++++ .../app/components/settings/section-keys.ts | 4 +- .../sections/ProjectModelsSection.search.ts | 10 +++ .../settings/sections/ProjectModelsSection.tsx | 39 +++++++++ .../settings/sections/SchedulingSection.search.ts | 18 ----- .../settings/sections/SchedulingSection.tsx | 2 - .../settings-default-descriptions.test.tsx | 4 +- packages/dashboard/src/shared/settings-sections.ts | 9 +++ packages/i18n/locales/en/app.json | 4 + packages/i18n/src/resources.d.ts | 4 + 13 files changed, 213 insertions(+), 27 deletions(-) Fusion-Task-Id: FN-8752 Fusion-Task-Lineage: f0f430d7-7976-4b65-89c5-8eab3487d26a Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -1858,11 +1858,11 @@ Values are project-scoped and finite values are floored; count/backoff must be a
|
||||
| Setting | Type/default | Behavior |
|
||||
| --- | --- | --- |
|
||||
| `executorModelEscalationEnabled` | boolean, `false` | Opt in to one alternate attempt after same-model retries exhaust. |
|
||||
| `executorEscalationProvider` | string, unset | Provider for an alternate model; requires `executorEscalationModelId`. |
|
||||
| `executorEscalationModelId` | string, unset | Alternate model ID; requires `executorEscalationProvider`. |
|
||||
| `executorEscalationProvider` | string, unset | Provider portion of the alternate model selected in **Settings → Models · Project**. |
|
||||
| `executorEscalationModelId` | string, unset | Model portion of that provider-aware selector. |
|
||||
| `executorEscalationNodeId` | string, unset | Optional configured node target. |
|
||||
|
||||
Escalation is enabled only when the toggle is true and either a complete provider/model pair or a node ID is configured. It is single-shot: after FN-7996 exhausts same-model retries, Fusion persists the override and tries once before the existing terminal park. The alternate model enters the [model-selection hierarchy](#model-selection-hierarchy) as a task-level override; a node target enters `resolveEffectiveNode` as a task-level routing override and is requeued so scheduler routing is recalculated. This remains opt-in by default to avoid unexpected model cost or execution behavior. Column-agent overrides still govern their sessions and can supersede a task-level model target.
|
||||
Choose the alternate model with the standard provider-aware selector in **Settings → Models · Project**; clearing it removes both persisted pair keys, and incomplete legacy pairs display as unset. **Settings → Scheduling** retains the enable toggle, optional node target, and retry policy. Escalation is enabled only when the toggle is true and either a complete provider/model pair or a node ID is configured. It is single-shot: after FN-7996 exhausts same-model retries, Fusion persists the override and tries once before the existing terminal park. The alternate model enters the [model-selection hierarchy](#model-selection-hierarchy) as a task-level override; a node target enters `resolveEffectiveNode` as a task-level routing override and is requeued so scheduler routing is recalculated. This remains opt-in by default to avoid unexpected model cost or execution behavior. Column-agent overrides still govern their sessions and can supersede a task-level model target.
|
||||
|
||||
| `triageDuplicateResolution` | `"prompt" \| "keep" \| "delete"` | `"prompt"` | Controls `DUPLICATE: FN-NNNN` markers emitted during triage. **prompt** flags and system-pauses the task for an operator Keep/Delete decision; the existing decision banner links to the canonical task. **keep** dismisses the marker and replans a real task. **delete** restores legacy auto-delete behavior. |
|
||||
|
||||
|
||||
@@ -132,6 +132,35 @@ describe("SettingsModal mobile embedded close button (FN-7627)", () => {
|
||||
expect(toggle).toBeChecked();
|
||||
});
|
||||
|
||||
/*
|
||||
FNXC:ExecutorEscalation 2026-08-03-05:43:
|
||||
Mobile Settings uses a section picker rather than the desktop rail. The one escalation model selector must remain in Models · Project after mobile navigation, while Scheduling retains policy and node routing without duplicate provider/model input shells.
|
||||
*/
|
||||
it("keeps the sole escalation selector in Project Models when the mobile section picker changes", async () => {
|
||||
mockUseViewportMode.mockReturnValue("mobile");
|
||||
mockFetchSettings.mockResolvedValue({
|
||||
...defaultSettings,
|
||||
executorEscalationProvider: "anthropic",
|
||||
executorEscalationModelId: "claude-sonnet-4-5",
|
||||
});
|
||||
mockFetchModels.mockResolvedValue({
|
||||
models: [{ provider: "anthropic", id: "claude-sonnet-4-5", name: "Claude Sonnet 4.5" }],
|
||||
favoriteProviders: [],
|
||||
favoriteModels: [],
|
||||
});
|
||||
|
||||
renderModal({ presentation: "embedded", projectId: "proj-1", initialSection: "project-models" });
|
||||
await waitFor(() => expect(mockFetchSettings).toHaveBeenCalled());
|
||||
|
||||
expect(await screen.findByLabelText("Executor Escalation Model")).toHaveTextContent("Claude Sonnet 4.5");
|
||||
fireEvent.change(screen.getByLabelText("Settings Section"), { target: { value: "scheduling" } });
|
||||
|
||||
expect(await screen.findByRole("checkbox", { name: "Escalate after tool-failure retries" })).toBeVisible();
|
||||
expect(screen.getByLabelText("Escalation node ID")).toBeVisible();
|
||||
expect(screen.queryByLabelText("Escalation provider")).not.toBeInTheDocument();
|
||||
expect(screen.queryByLabelText("Escalation model ID")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("still renders and calls onClose in embedded+mobile when opened without a selected projectId (overview entry)", async () => {
|
||||
mockUseViewportMode.mockReturnValue("mobile");
|
||||
const onClose = vi.fn();
|
||||
|
||||
@@ -239,6 +239,100 @@ describe("SettingsModal", () => {
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
FNXC:ExecutorEscalation 2026-08-03-05:43:
|
||||
The original Scheduling text fields accepted incomplete provider/model pairs. The project-scoped picker must instead present one provider-qualified selection, save both legacy keys together, and clear both keys together.
|
||||
*/
|
||||
it("selects and clears the executor escalation model as one project-scoped pair", async () => {
|
||||
mockFetchModels.mockResolvedValue({
|
||||
models: MODEL_FIXTURE,
|
||||
favoriteProviders: [],
|
||||
favoriteModels: [],
|
||||
});
|
||||
mockFetchSettings.mockResolvedValue({
|
||||
...defaultSettings,
|
||||
executorEscalationProvider: "anthropic",
|
||||
executorEscalationModelId: "claude-sonnet-4-5",
|
||||
});
|
||||
mockFetchSettingsByScope.mockResolvedValue({
|
||||
global: defaultSettings,
|
||||
project: {
|
||||
executorEscalationProvider: "anthropic",
|
||||
executorEscalationModelId: "claude-sonnet-4-5",
|
||||
},
|
||||
});
|
||||
|
||||
renderModal({ initialSection: "project-models" });
|
||||
await waitForSettingsModalReady();
|
||||
|
||||
const selector = screen.getByLabelText("Executor Escalation Model");
|
||||
expect(selector).toHaveTextContent("Claude Sonnet 4.5");
|
||||
await settingsModalUser.click(selector);
|
||||
await settingsModalUser.click(await screen.findByText("GPT-4o"));
|
||||
fireEvent.click(document.querySelector(".modal-close") as HTMLButtonElement);
|
||||
|
||||
await waitFor(() => expect(mockUpdateSettings).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
executorEscalationProvider: "openai",
|
||||
executorEscalationModelId: "gpt-4o",
|
||||
}),
|
||||
undefined,
|
||||
));
|
||||
|
||||
cleanup();
|
||||
mockUpdateSettings.mockClear();
|
||||
renderModal({ initialSection: "project-models" });
|
||||
await waitForSettingsModalReady();
|
||||
await settingsModalUser.click(screen.getByLabelText("Executor Escalation Model"));
|
||||
await settingsModalUser.click(await screen.findByText("No escalation model"));
|
||||
fireEvent.click(document.querySelector(".modal-close") as HTMLButtonElement);
|
||||
|
||||
await waitFor(() => expect(mockUpdateSettings).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
executorEscalationProvider: null,
|
||||
executorEscalationModelId: null,
|
||||
}),
|
||||
undefined,
|
||||
));
|
||||
});
|
||||
|
||||
it("disables the escalation selector while the catalog is loading or empty", async () => {
|
||||
let resolveModels: ((value: { models: typeof MODEL_FIXTURE; favoriteProviders: string[]; favoriteModels: string[] }) => void) | undefined;
|
||||
mockFetchModels.mockImplementation(() => new Promise((resolve) => {
|
||||
resolveModels = resolve;
|
||||
}));
|
||||
|
||||
renderModal({ initialSection: "project-models" });
|
||||
await waitForSettingsModalReady();
|
||||
|
||||
expect(screen.getByLabelText("Executor Escalation Model")).toBeDisabled();
|
||||
resolveModels?.({ models: MODEL_FIXTURE, favoriteProviders: [], favoriteModels: [] });
|
||||
await waitFor(() => expect(screen.getByLabelText("Executor Escalation Model")).not.toBeDisabled());
|
||||
});
|
||||
|
||||
it("treats incomplete legacy escalation pairs as unset and removes Scheduling model inputs", async () => {
|
||||
mockFetchModels.mockResolvedValue({
|
||||
models: MODEL_FIXTURE,
|
||||
favoriteProviders: [],
|
||||
favoriteModels: [],
|
||||
});
|
||||
mockFetchSettings.mockResolvedValue({
|
||||
...defaultSettings,
|
||||
executorEscalationProvider: "anthropic",
|
||||
});
|
||||
|
||||
renderModal({ initialSection: "project-models" });
|
||||
await waitForSettingsModalReady();
|
||||
|
||||
expect(screen.getByLabelText("Executor Escalation Model")).toHaveTextContent("No escalation model");
|
||||
await settingsModalUser.click(screen.getByRole("button", { name: "Scheduling" }));
|
||||
|
||||
expect(screen.queryByLabelText("Escalation provider")).not.toBeInTheDocument();
|
||||
expect(screen.queryByLabelText("Escalation model ID")).not.toBeInTheDocument();
|
||||
expect(screen.getByRole("checkbox", { name: "Escalate after tool-failure retries" })).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("Escalation node ID")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders and saves OpenRouter advanced settings", async () => {
|
||||
mockFetchModels.mockResolvedValue({
|
||||
models: MODEL_FIXTURE,
|
||||
|
||||
@@ -203,6 +203,23 @@ describe("settings search ranking", () => {
|
||||
expect(results.map((r) => r.key)).toEqual(["aCostThing", "showCostBadgeOnCards"]);
|
||||
});
|
||||
|
||||
it("routes escalation model discovery only to Project Models while keeping policy routing in Scheduling", () => {
|
||||
const escalationResults = rankSettingsSearchResults(SETTINGS_SEARCH_ENTRIES, "alternate model", resolveEnglish);
|
||||
expect(escalationResults.map((result) => `${result.sectionId}:${result.key}`)).toContain(
|
||||
"project-models:executorEscalationModel",
|
||||
);
|
||||
expect(escalationResults.some((result) => result.sectionId === "scheduling" && /Escalation (provider|model ID)/.test(result.label))).toBe(false);
|
||||
|
||||
const policyResults = rankSettingsSearchResults(SETTINGS_SEARCH_ENTRIES, "escalate after tool-failure retries", resolveEnglish);
|
||||
expect(policyResults.map((result) => `${result.sectionId}:${result.key}`)).toContain(
|
||||
"scheduling:executorModelEscalationEnabled",
|
||||
);
|
||||
const nodeResults = rankSettingsSearchResults(SETTINGS_SEARCH_ENTRIES, "escalation node", resolveEnglish);
|
||||
expect(nodeResults.map((result) => `${result.sectionId}:${result.key}`)).toContain(
|
||||
"scheduling:executorEscalationNodeId",
|
||||
);
|
||||
});
|
||||
|
||||
it("finds the real 'summarize' miss that motivated the rewrite", () => {
|
||||
// FN-7907 / 2026-07-14: operators searched "summarize"; the section's
|
||||
// keyword list did not carry it, so Project Models did not surface.
|
||||
|
||||
@@ -140,8 +140,6 @@ export const PROJECT_SECTION_KEYS: Readonly<Record<string, readonly string[]>> =
|
||||
"executorToolFailureRetryBackoffMs",
|
||||
"executorToolFailureThreshold",
|
||||
"executorModelEscalationEnabled",
|
||||
"executorEscalationProvider",
|
||||
"executorEscalationModelId",
|
||||
"executorEscalationNodeId",
|
||||
"groupOverlappingFiles",
|
||||
"heartbeatScopeDiscipline",
|
||||
@@ -204,6 +202,8 @@ export const PROJECT_SECTION_KEYS: Readonly<Record<string, readonly string[]>> =
|
||||
"prTitlePromptInstructions",
|
||||
"tokenCap",
|
||||
"useAiMergeCommitSummary",
|
||||
"executorEscalationProvider",
|
||||
"executorEscalationModelId",
|
||||
...MODEL_LANE_KEYS,
|
||||
],
|
||||
};
|
||||
|
||||
@@ -9,6 +9,16 @@
|
||||
import type { SettingsSearchEntry } from "../search/types";
|
||||
|
||||
export const projectModelsSearchEntries: SettingsSearchEntry[] = [
|
||||
{
|
||||
sectionId: "project-models",
|
||||
key: "executorEscalationModel",
|
||||
labelKey: "settings.projectModels.executorEscalationModel",
|
||||
labelFallback: "Executor Escalation Model",
|
||||
helpKey: "settings.projectModels.executorEscalationModelHelp",
|
||||
helpFallback:
|
||||
"Alternate model used once tool-failure retries are exhausted. No default — unset means no alternate model; configure escalation policy and an optional node target in Scheduling.",
|
||||
keywords: ["tool failure", "alternate model", "retry model", "provider", "executor"],
|
||||
},
|
||||
{
|
||||
sectionId: "project-models",
|
||||
key: "tokenCap",
|
||||
|
||||
@@ -7,6 +7,7 @@ import { SettingsToggleRow } from "../SettingsToggleRow";
|
||||
import { SettingsSelectRow } from "../SettingsSelectRow";
|
||||
import { SettingsNumberRow } from "../SettingsNumberRow";
|
||||
import { SettingsTextareaRow } from "../SettingsTextareaRow";
|
||||
import { SettingsFieldRow } from "../SettingsFieldRow";
|
||||
import { SettingsHelpTip } from "../SettingsHelpTip";
|
||||
import { applyPresetToSelection } from "../../../utils/modelPresets";
|
||||
import type { ToastType } from "../../../hooks/useToast";
|
||||
@@ -547,6 +548,44 @@ export function ProjectModelsSection({ form, setForm, models, projectId, onOpenW
|
||||
/>
|
||||
|
||||
{/* --- Project Model Lanes --- */}
|
||||
{/*
|
||||
FNXC:ExecutorEscalation 2026-08-03-05:43:
|
||||
The alternate executor target is a project model choice, while Scheduling owns only the retry policy and optional node routing. Use the shared provider-aware dropdown so complete persisted pairs hydrate together, selecting a model updates both existing keys, and the default choice clears both without accepting arbitrary text.
|
||||
*/}
|
||||
<SettingsFieldRow
|
||||
htmlFor="executorEscalationModel"
|
||||
label={t("settings.projectModels.executorEscalationModel", "Executor Escalation Model")}
|
||||
help={t("settings.projectModels.executorEscalationModelHelp", "Alternate model used once tool-failure retries are exhausted. No default — unset means no alternate model; configure escalation policy and an optional node target in Scheduling.")}
|
||||
scope="project"
|
||||
>
|
||||
<CustomModelDropdown
|
||||
id="executorEscalationModel"
|
||||
label={t("settings.projectModels.executorEscalationModel", "Executor Escalation Model")}
|
||||
models={availableModels}
|
||||
disabled={modelsLoading || availableModels.length === 0}
|
||||
value={form.executorEscalationProvider && form.executorEscalationModelId ? `${form.executorEscalationProvider}/${form.executorEscalationModelId}` : ""}
|
||||
onChange={(value) => {
|
||||
if (!value) {
|
||||
setForm((current) => ({ ...current, executorEscalationProvider: undefined, executorEscalationModelId: undefined } as SettingsFormState));
|
||||
return;
|
||||
}
|
||||
const slashIdx = value.indexOf("/");
|
||||
if (slashIdx <= 0) return;
|
||||
setForm((current) => ({
|
||||
...current,
|
||||
executorEscalationProvider: value.slice(0, slashIdx),
|
||||
executorEscalationModelId: value.slice(slashIdx + 1),
|
||||
} as SettingsFormState));
|
||||
}}
|
||||
placeholder={t("settings.projectModels.selectExecutorEscalationModel", "Select an escalation model")}
|
||||
defaultOptionLabel={t("settings.projectModels.noExecutorEscalationModel", "No escalation model")}
|
||||
favoriteProviders={favoriteProviders}
|
||||
onToggleFavorite={onToggleFavorite}
|
||||
favoriteModels={favoriteModels}
|
||||
onToggleModelFavorite={onToggleModelFavorite}
|
||||
menuWidth="readable"
|
||||
/>
|
||||
</SettingsFieldRow>
|
||||
{/* FNXC:SettingsHelp 2026-07-16-12:45: Section description moved behind the shared "?" affordance beside the heading — operator requirement: no inline description paragraphs in Settings. */}
|
||||
<div className="settings-field-label-row">
|
||||
<h4 className="settings-section-heading settings-section-heading--spaced">{t("settings.projectModels.modelLanes", "Model Lanes")}</h4>
|
||||
|
||||
@@ -66,24 +66,6 @@ export const schedulingSearchEntries: SettingsSearchEntry[] = [
|
||||
helpFallback: "After same-model retries are exhausted, try one configured alternate model or node. Disabled by default.",
|
||||
keywords: ["executor", "model", "node", "escalation", "tool error"],
|
||||
},
|
||||
{
|
||||
sectionId: "scheduling",
|
||||
key: "executorEscalationProvider",
|
||||
labelKey: "settings.scheduling.executorEscalationProvider",
|
||||
labelFallback: "Escalation provider",
|
||||
helpKey: "settings.scheduling.executorEscalationProviderHelp",
|
||||
helpFallback: "Provider for the alternate model. Requires an alternate model ID.",
|
||||
keywords: ["executor", "model", "provider", "escalation"],
|
||||
},
|
||||
{
|
||||
sectionId: "scheduling",
|
||||
key: "executorEscalationModelId",
|
||||
labelKey: "settings.scheduling.executorEscalationModelId",
|
||||
labelFallback: "Escalation model ID",
|
||||
helpKey: "settings.scheduling.executorEscalationModelIdHelp",
|
||||
helpFallback: "Alternate model ID. Requires an escalation provider.",
|
||||
keywords: ["executor", "model", "escalation"],
|
||||
},
|
||||
{
|
||||
sectionId: "scheduling",
|
||||
key: "executorEscalationNodeId",
|
||||
|
||||
@@ -40,8 +40,6 @@ export function SchedulingSection({ form, setForm, concurrencyLoading = false, o
|
||||
<SettingsNumberRow descriptor={{ key: "executorToolFailureThreshold", label: t("settings.scheduling.executorToolFailureThreshold", "Consecutive tool failures"), help: t("settings.scheduling.executorToolFailureThresholdHelp", "Terminal tool errors required before retrying. Default: 3."), scope: "project", min: 1, step: 1 }} value={form.executorToolFailureThreshold ?? 3} onChange={(v) => setForm((f) => ({ ...f, executorToolFailureThreshold: Math.max(1, Math.floor(v ?? 3)) } as SettingsFormState))} />
|
||||
{/* FNXC:ExecutorEscalation 2026-07-16-21:00: Keep alternate model/node escalation opt-in and adjacent to its FN-7996 retry policy; a complete model pair or node id is required before the executor consumes its one extra attempt. */}
|
||||
<SettingsToggleRow descriptor={{ key: "executorModelEscalationEnabled", label: t("settings.scheduling.executorModelEscalationEnabled", "Escalate after tool-failure retries"), help: t("settings.scheduling.executorModelEscalationEnabledHelp", "After same-model retries are exhausted, try one configured alternate model or node. Disabled by default."), scope: "project" }} value={form.executorModelEscalationEnabled === true} onChange={(value) => setForm((f) => ({ ...f, executorModelEscalationEnabled: value === true } as SettingsFormState))} />
|
||||
<SettingsTextRow descriptor={{ key: "executorEscalationProvider", label: t("settings.scheduling.executorEscalationProvider", "Escalation provider"), help: t("settings.scheduling.executorEscalationProviderHelp", "Provider for the alternate model. Requires an alternate model ID."), scope: "project" }} value={form.executorEscalationProvider ?? ""} onChange={(value) => setForm((f) => ({ ...f, executorEscalationProvider: value ?? "" } as SettingsFormState))} />
|
||||
<SettingsTextRow descriptor={{ key: "executorEscalationModelId", label: t("settings.scheduling.executorEscalationModelId", "Escalation model ID"), help: t("settings.scheduling.executorEscalationModelIdHelp", "Alternate model ID. Requires an escalation provider."), scope: "project" }} value={form.executorEscalationModelId ?? ""} onChange={(value) => setForm((f) => ({ ...f, executorEscalationModelId: value ?? "" } as SettingsFormState))} />
|
||||
<SettingsTextRow descriptor={{ key: "executorEscalationNodeId", label: t("settings.scheduling.executorEscalationNodeId", "Escalation node ID"), help: t("settings.scheduling.executorEscalationNodeIdHelp", "Optional configured node; a node target re-enters scheduler routing."), scope: "project" }} value={form.executorEscalationNodeId ?? ""} onChange={(value) => setForm((f) => ({ ...f, executorEscalationNodeId: value ?? "" } as SettingsFormState))} />
|
||||
<SettingsNumberRow
|
||||
descriptor={{
|
||||
|
||||
@@ -220,8 +220,8 @@ const SETTING_DESCRIPTION_KEYS: Record<string, string> = {
|
||||
executorToolFailureRetryBackoffMs: "scheduling.executorToolFailureRetryBackoffMsHelp",
|
||||
executorToolFailureThreshold: "scheduling.executorToolFailureThresholdHelp",
|
||||
executorModelEscalationEnabled: "scheduling.executorModelEscalationEnabledHelp",
|
||||
executorEscalationProvider: "scheduling.executorEscalationProviderHelp",
|
||||
executorEscalationModelId: "scheduling.executorEscalationModelIdHelp",
|
||||
executorEscalationProvider: "projectModels.executorEscalationModelHelp",
|
||||
executorEscalationModelId: "projectModels.executorEscalationModelHelp",
|
||||
executorEscalationNodeId: "scheduling.executorEscalationNodeIdHelp",
|
||||
taskStuckTimeoutMs: "scheduling.timeoutInMinutesForDetectingStuckTasksWhen",
|
||||
staleHighFanoutBlockerAgeThresholdMs: "scheduling.escalateHighFanOutBlockersOnlyAfterThey",
|
||||
|
||||
@@ -91,6 +91,9 @@ const SETTINGS_SECTION_DEFINITIONS: readonly SettingsSectionDefinition[] = [
|
||||
|
||||
* FNXC:SettingsNavigation 2026-07-14-20:15:
|
||||
* Title auto-summarization lives under Project Models but operators search for "summarize", "auto summarize", "title summarization", and related phrases that did not match the prior chat-only/summarization-model index. Advertise those terms and the control's i18n keys so Settings search finds this section.
|
||||
*
|
||||
* FNXC:ExecutorEscalation 2026-08-03-05:43:
|
||||
* The executor alternate model is a project model selector, not a Scheduling text setting. Keep its discovery terms and label/help keys here so desktop navigation, the mobile picker, and external Settings metadata name the one canonical destination.
|
||||
*/
|
||||
{
|
||||
id: "project-models",
|
||||
@@ -101,6 +104,10 @@ const SETTINGS_SECTION_DEFINITIONS: readonly SettingsSectionDefinition[] = [
|
||||
"default provider",
|
||||
"default model",
|
||||
"workflow model lanes",
|
||||
"executor escalation model",
|
||||
"escalation model",
|
||||
"alternate model",
|
||||
"tool-failure retry model",
|
||||
"Plan/Triage",
|
||||
"Executor",
|
||||
"Reviewer",
|
||||
@@ -149,6 +156,8 @@ const SETTINGS_SECTION_DEFINITIONS: readonly SettingsSectionDefinition[] = [
|
||||
"settings.projectModels.chatDefaultModel",
|
||||
"settings.projectModels.chatDefaultAgent",
|
||||
"settings.projectModels.aITitleAndGitCommitMessageSummarization",
|
||||
"settings.projectModels.executorEscalationModel",
|
||||
"settings.projectModels.executorEscalationModelHelp",
|
||||
"settings.projectModels.autoSummarizeLongDescriptionsAsTitles",
|
||||
"settings.projectModels.whenEnabledTasksCreatedWithoutATitleBut",
|
||||
"settings.projectModels.aIMergeCommitSummaries",
|
||||
|
||||
@@ -6515,6 +6515,10 @@
|
||||
"delete": " Delete ",
|
||||
"edit": " Edit ",
|
||||
"executorModel": "Executor model",
|
||||
"executorEscalationModel": "Executor Escalation Model",
|
||||
"executorEscalationModelHelp": "Alternate model used once tool-failure retries are exhausted. No default — unset means no alternate model; configure escalation policy and an optional node target in Scheduling.",
|
||||
"selectExecutorEscalationModel": "Select an escalation model",
|
||||
"noExecutorEscalationModel": "No escalation model",
|
||||
"fallsBackTo": " Falls back to: ",
|
||||
"loadingAvailableModels": "Loading available models…",
|
||||
"loadingWorkflowModelLanes": "Loading workflow model lanes…",
|
||||
|
||||
4
packages/i18n/src/resources.d.ts
vendored
4
packages/i18n/src/resources.d.ts
vendored
@@ -6564,6 +6564,10 @@ export default interface Resources {
|
||||
"delete": " Delete ",
|
||||
"edit": " Edit ",
|
||||
"executorModel": "Executor model",
|
||||
"executorEscalationModel": "Executor Escalation Model",
|
||||
"executorEscalationModelHelp": "Alternate model used once tool-failure retries are exhausted. No default — unset means no alternate model; configure escalation policy and an optional node target in Scheduling.",
|
||||
"selectExecutorEscalationModel": "Select an escalation model",
|
||||
"noExecutorEscalationModel": "No escalation model",
|
||||
"fallsBackTo": " Falls back to: ",
|
||||
"loadingAgents": "Loading agents…",
|
||||
"loadingAvailableModels": "Loading available models…",
|
||||
|
||||
Reference in New Issue
Block a user