diff --git a/.changeset/fn-003-model-override-organization.md b/.changeset/fn-003-model-override-organization.md new file mode 100644 index 0000000000..2ffc7830b6 --- /dev/null +++ b/.changeset/fn-003-model-override-organization.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Organize project and workflow model overrides in one Settings group. +category: feature +dev: Moves the Project Models JSX into Model Overrides subgroups and adds matching i18n/search metadata. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index d6f699d660..a25a046d5a 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -506,7 +506,7 @@ Behavior: FNXC:WorkflowEditor 2026-06-29-21:10: Optional-group template entry/exit ownership remains visual-only. Non-editable boundary connector lines must explain how template children attach to the container without persisting fake edges into workflow IR. --> - Optional-group, foreach, and loop containers show their template nodes inside the block. Canvas connections between the surrounding workflow and the block attach to the container boundary; connections between template nodes stay inside the block. Optional groups also draw non-editable entry/exit connector lines between the boundary and the template entry/exit nodes so single-step blocks such as Plan Review and Code Review do not look disconnected; those visual connectors are not saved into workflow IR. - The Settings panel is value-first for built-in workflows and groups workflow settings by Models, Review & Approval, Step Execution, and Advanced. Known workflow model values use the same model dropdown picker as **Settings → Project Models** so provider/model pairs and their inline Thinking Level companions are saved together; custom or non-model string values can still use typed inputs. Definitions remain available for custom workflow schema authoring. -- The main Settings modal exposes project-baseline Plan/Triage, Executor, Reviewer, and declared fallback model lanes from **Project Models**. Those dropdown values auto-save on the active default workflow and are inherited by every workflow. Resolution is task-specific selection → project baseline → global lane → selected-workflow value; Project Models therefore wins over values configured in a workflow's **Settings → Values**. Project Models also includes project-scoped **Merger** and **Title Summarization** lanes (not workflow-moved). Settings fallback model pickers (Global Fallback Model, workflow fallbacks, and project Title Summarizer Fallback) include the same inline Thinking Level selector when their companion key exists. +- The main Settings modal groups project-baseline Plan/Triage, Executor, Reviewer, and declared fallback model lanes in **Models · Project → Model Overrides → Workflow lanes**, directly after **Project lanes**. Those dropdown values auto-save on the active default workflow and are inherited by every workflow. Resolution is task-specific selection → project baseline → global lane → selected-workflow value; Project Models therefore wins over values configured in a workflow's **Settings → Values**. Project-scoped **Merger** remains in Project lanes, while **Title Summarization** and its fallback intentionally remain under **AI Title and Git Commit Message Summarization** with their enable toggles. Settings fallback model pickers (Global Fallback Model, workflow fallbacks, and project Title Summarizer Fallback) include the same inline Thinking Level selector when their companion key exists. - On desktop, the editor uses a multi-panel canvas layout for editing the graph and adjacent workflow metadata. The **Show simple editor** toggle switches that same workflow into the graph-outline editor with dedicated **Graph**, **Add**, **Settings**, **Fields**, **Columns**, and **Actions** tabs. - On viewports `<=768px`, the editor switches to a full-screen mobile sheet. Global workflow entry points open to the workflow list with no workflow preselected and prompt users to select a workflow to edit; the Board/List workflow dropdown row edit action opens directly to the selected workflow editor when that selected workflow is available. - Simple/mobile editing uses a graph outline instead of making the canvas the primary control. The outline shows nodes, branch/rework edges, column placement, and optional-group/foreach/loop template children as tappable rows and chips that open the same node and edge detail editors as desktop. The structural **start** node opens an inspector for the workflow entry column when the workflow defines columns; the **Name** field remains unavailable because the start label is structural. For custom workflows, editable outline rows also expose **Move up** and **Move down** controls that reorder steps within their current column or template parent; built-in workflows remain read-only and hide those controls. @@ -515,7 +515,7 @@ FNXC:WorkflowEditor 2026-06-29-21:10: Optional-group template entry/exit ownersh ## Custom Providers -Custom Providers live in **Settings → Authentication → Custom Providers**, inside the **Advanced: Custom Providers** disclosure. Use this section to add user-defined model providers that speak an OpenAI-compatible API, the OpenAI Responses API, an Anthropic-compatible API, or Google Generative AI. After a provider is saved with models, those models become selectable in model dropdowns, including **Settings → Project Models** lanes and workflow model lanes. +Custom Providers live in **Settings → Authentication → Custom Providers**, inside the **Advanced: Custom Providers** disclosure. Use this section to add user-defined model providers that speak an OpenAI-compatible API, the OpenAI Responses API, an Anthropic-compatible API, or Google Generative AI. After a provider is saved with models, those models become selectable in model dropdowns, including **Settings → Models · Project → Model Overrides** project and workflow lanes. Settings → Global Models also includes **Model pricing overrides** for Command Center estimates. The section shows a compact pricing snapshot/override-count summary; use **View pricing table** to add or edit rows with lowercased `provider:model` keys (or bare `:model` fallback keys), USD-per-1M token prices for input/output/cache read/cache write, and optional source text. **Fetch LiteLLM pricing** remains available from the collapsed summary and performs an explicit one-click refresh from LiteLLM's published model pricing JSON, replaces the override table only after a successful parse, and records the fetched timestamp/source; failed fetches keep the existing overrides. @@ -551,7 +551,7 @@ Use **Detect Models** to auto-fill **Available models** while adding or editing - selecting **Detect Models** to query the provider's `/models` endpoint and prepend detected model IDs to the field. 9. Select **Save Provider**. -Expected outcome: the provider appears in the Custom Providers list with its API type and base URL. Each saved model is then available in model dropdowns as a `{provider}/{modelId}` option, including **Settings → Project Models** default-workflow lanes and workflow model lanes in the workflow editor. +Expected outcome: the provider appears in the Custom Providers list with its API type and base URL. Each saved model is then available in model dropdowns as a `{provider}/{modelId}` option, including **Settings → Models · Project → Model Overrides → Workflow lanes** and workflow model lanes in the workflow editor. ### Edit a custom provider diff --git a/docs/settings-reference.md b/docs/settings-reference.md index 76a4c8c7c5..89938aaab4 100644 --- a/docs/settings-reference.md +++ b/docs/settings-reference.md @@ -298,9 +298,10 @@ Some knobs that used to live in this Settings reference as project settings are govern that execution belong to the workflow. **Where to set them.** The common model lanes for every workflow in a project are -available directly in **Settings → Project Models → Project workflow model lanes**: -Plan/Triage, Executor, Reviewer, and their fallback lanes declared -by the default workflow. Primary Plan/Triage, Executor, Reviewer, and declared fallback rows show an inline Thinking Level control when the workflow declares the companion `*ThinkingLevel` setting; unset means inherit. Those dropdown controls use the shared model picker and are auto-saved by the Settings modal after an edit, which writes +available directly in **Settings → Models · Project → Model Overrides → Workflow lanes**, +immediately after **Project lanes**: Plan/Triage, Executor, Reviewer, and their fallback lanes declared +by the default workflow. The project Summarization lane and its fallback remain under +**AI Title and Git Commit Message Summarization** with the enable toggles that govern them. Primary Plan/Triage, Executor, Reviewer, and declared fallback rows show an inline Thinking Level control when the workflow declares the companion `*ThinkingLevel` setting; unset means inherit. Those dropdown controls use the shared model picker and are auto-saved by the Settings modal after an edit, which writes workflow setting values on the active project's default workflow. Those stored values are the project model baseline inherited by every selected workflow. The baseline wins over global and per-workflow values; task-specific selections win @@ -1135,7 +1136,7 @@ Short-lived token bounds are enforced server-side: ## Model Selection Hierarchy -Fusion resolves task models as task-specific selection -> project workflow-model baseline -> global lane -> selected-workflow value -> project/global default model. The project baseline is stored as setting values on the project's active default workflow and can be edited from Settings -> Project Models -> Project workflow model lanes (auto-saved by the Settings modal). Lower-priority per-workflow values remain editable from Workflow editor -> Settings -> Values for declared workflow lanes and fallbacks. General-scope fallback selection remains the global Fallback Model picker in Settings -> General Models. +Fusion resolves task models as task-specific selection -> project workflow-model baseline -> global lane -> selected-workflow value -> project/global default model. The project baseline is stored as setting values on the project's active default workflow and can be edited from Settings -> Models · Project -> Model Overrides -> Workflow lanes (auto-saved by the Settings modal, directly after Project lanes). The project Summarization lane and its fallback intentionally remain under AI Title and Git Commit Message Summarization with their enable toggles. Lower-priority per-workflow values remain editable from Workflow editor -> Settings -> Values for declared workflow lanes and fallbacks. General-scope fallback selection remains the global Fallback Model picker in Settings -> General Models. Direct-chat defaults are project-scoped and independent of task workflow lanes. Configure them in **Settings -> Project Models -> Chat**. `chatDefaultKind: "agent"` resolves only when `chatDefaultAgentId` is set; `chatDefaultKind: "model"` resolves only when both `chatDefaultModelProvider` and `chatDefaultModelId` are set, with optional `chatDefaultThinkingLevel`. If `chatNewSessionMode` is `"always-default"` and that target resolves, every New Chat entry point creates the session directly. If the target is incomplete, or the mode is unset/`"prompt"`, Fusion opens the New Chat dialog instead and preselects the resolved default when one exists. Chat Rooms additionally support a per-room `thinkingLevel` default that applies to every room responder; clearing it inherits the resolved project/global default. diff --git a/packages/dashboard/app/__tests__/settings-sections.test.tsx b/packages/dashboard/app/__tests__/settings-sections.test.tsx index 58d192941f..5ba68ac33b 100644 --- a/packages/dashboard/app/__tests__/settings-sections.test.tsx +++ b/packages/dashboard/app/__tests__/settings-sections.test.tsx @@ -833,6 +833,16 @@ describe("ProjectModelsSection", () => { "validator", "validator-fallback", ]); + + const projectLanes = screen.getByTestId("project-models-project-lanes"); + const workflowLanes = screen.getByTestId("project-models-workflow-lanes"); + const chat = screen.getByTestId("project-models-chat-kind"); + const summarizationSection = screen.getByTestId("project-models-ai-summarization"); + expect(projectLanes.nextElementSibling).toBe(workflowLanes); + expect(projectLanes).toContainElement(screen.getByTestId("project-models-summarization-pointer")); + expect(workflowLanes).toContainElement(screen.getByTestId("workflow-model-lane-planning")); + expect(workflowLanes.compareDocumentPosition(chat) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy(); + expect(workflowLanes.compareDocumentPosition(summarizationSection) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy(); }); it("wires workflow fallback lane thinking render, persist, and reset", async () => { diff --git a/packages/dashboard/app/components/__tests__/SettingsModal.models-auth.test.tsx b/packages/dashboard/app/components/__tests__/SettingsModal.models-auth.test.tsx index c0fdb09742..d6cb4fa5b2 100644 --- a/packages/dashboard/app/components/__tests__/SettingsModal.models-auth.test.tsx +++ b/packages/dashboard/app/components/__tests__/SettingsModal.models-auth.test.tsx @@ -551,7 +551,7 @@ describe("SettingsModal", () => { const onOpenWorkflowSettings = vi.fn(); await setupWorkflowModelLaneTest({ renderProps: { onOpenWorkflowSettings } }); - const workflowHeading = screen.getByRole("heading", { name: "Project workflow model lanes" }); + const workflowHeading = screen.getByRole("heading", { name: "Workflow lanes" }); const advancedButton = screen.getByRole("button", { name: "Advanced workflow policy" }); const actionRow = advancedButton.closest(".settings-model-lane-actions"); const presetsHeading = screen.getByRole("heading", { name: "Model Presets" }); diff --git a/packages/dashboard/app/components/settings/sections/GlobalModelsSection.tsx b/packages/dashboard/app/components/settings/sections/GlobalModelsSection.tsx index ba9043bdd3..532b12d127 100644 --- a/packages/dashboard/app/components/settings/sections/GlobalModelsSection.tsx +++ b/packages/dashboard/app/components/settings/sections/GlobalModelsSection.tsx @@ -51,8 +51,14 @@ export function GlobalModelsSection({ form, setForm, availableModels, modelsLoad : ""; return (<> - {/* --- Default Model --- */} -
{t("settings.globalModels.globalBaselineModelsForEachAIRoleProject", " Global baseline models for each AI role. Project settings can override these per-project. ")}
{globalModelLanes.map((lane) => { const provider = form[lane.globalProviderKey as keyof Settings] as string | undefined; const model = form[lane.globalModelKey as keyof Settings] as string | undefined; @@ -177,8 +181,6 @@ export function GlobalModelsSection({ form, setForm, availableModels, modelsLoad })} >)} -{t("settings.projectModels.summarizationPointer", "Summarization models are configured under AI Title and Git Commit Message Summarization below.")}
+