Files
fusion/packages/dashboard/app/components/settings/sections/context.ts
gsxdsm 5f14a58d3b FN-7770: add per-lane thinking-level overrides for project & global model settings
Adds an optional thinking-effort/reasoning override per model lane in Settings (project and global), resolved with precedence task > lane > global default, and reconciles this work with the already-landed FN-7768 inline thinking-level control on CustomModelDropdown (kept the shared shouldShowThinking/thinkingBadgeLabel implementation to avoid duplicating the selector/badge UI).

- Add lane thinking-level settings schema fields and runtime precedence (task > lane > global default) in @fusion/core
- Wire per-lane thinking selectors into GlobalModelsSection and ProjectModelsSection via CustomModelDropdown's existing showThinkingLevel/thinkingLevel/onThinkingLevelChange/defaultThinkingLevel props
- Resolve merger thinking level from the default lane rather than the title-summarizer lane in engine session helpers/executor/merger/triage
- Update settings-reference docs and add a minor changeset for the new lane thinking overrides
- Add/expand test coverage: settings-parity, store-settings, settings-sections, agent-session-helpers
- Add new i18n key models.options.defaultWithLevel across locales

Files changed:
 .changeset/fn-7770-lane-thinking.md                |   7 ++
 docs/settings-reference.md                         |   8 ++
 .../core/src/__tests__/settings-parity.test.ts     |  17 ++++
 packages/core/src/__tests__/store-settings.test.ts |  42 +++++++++
 packages/core/src/settings-schema.ts               |  14 +++
 packages/core/src/types.ts                         |  16 ++++
 .../app/__tests__/settings-sections.test.tsx       | 100 ++++++++++++++++++---
 .../app/components/CustomModelDropdown.css         |   1 +
 .../dashboard/app/components/SettingsModal.tsx     |  37 ++++++++
 .../settings/sections/GlobalModelsSection.tsx      |   9 +-
 .../settings/sections/ProjectModelsSection.tsx     |  12 ++-
 .../app/components/settings/sections/context.ts    |   2 +
 .../src/__tests__/agent-session-helpers.test.ts    |  36 ++++++++
 packages/engine/src/agent-session-helpers.ts       |  60 +++++++++++++
 packages/engine/src/executor.ts                    |  14 +--
 packages/engine/src/merger-ai.ts                   |  12 ++-
 packages/engine/src/merger.ts                      |  12 +--
 packages/engine/src/pr-response-run-ops.ts         |   4 +-
 packages/engine/src/step-session-executor.ts       |   3 +-
 packages/engine/src/triage.ts                      |   5 +-
 packages/i18n/locales/en/app.json                  |   3 +-
 packages/i18n/locales/es/app.json                  |   3 +-
 packages/i18n/locales/fr/app.json                  |   3 +-
 packages/i18n/locales/ko/app.json                  |   3 +-
 packages/i18n/locales/zh-CN/app.json               |   3 +-
 packages/i18n/locales/zh-TW/app.json               |   3 +-
 packages/i18n/src/resources.d.ts                   |   3 +
 27 files changed, 390 insertions(+), 42 deletions(-)

Fusion-Task-Id: FN-7770
Fusion-Task-Lineage: 3418c621-ac99-4cd4-a435-9348da03972f
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-10 01:15:40 -07:00

57 lines
2.3 KiB
TypeScript

/**
* Shared contract for the per-section components the SettingsModal shell composes
* (U9 / KTD-10).
*
* The shell owns ALL persistence: it holds the single merged `form`, the
* scope-aware save-split (see settings/save-split.ts), null-as-delete, and the
* changed-only project-write gate. Sections are presentational — they read from
* `form`/section-specific data and emit edits back through `setForm` (and a few
* section-scoped setters/handlers). They never call `updateSettings` /
* `updateGlobalSettings` themselves.
*
* This is intentionally a pragmatic prop bag rather than a redesigned state
* model: it mirrors exactly how the inline JSX read and wrote the modal's local
* state, so extraction is behavior-preserving. Each section's props interface
* extends {@link SectionBaseProps} and adds only the slice it needs.
*/
import type { Settings, GlobalSettings } from "@fusion/core";
/** A model-lane descriptor pairing a role's global and project override keys.
* Mirrors the `ModelLane` shape SettingsModal builds for its model pickers. */
export interface ModelLane {
laneId: string;
label: string;
globalProviderKey: keyof GlobalSettings;
globalModelKey: keyof GlobalSettings;
globalThinkingKey?: keyof GlobalSettings;
projectProviderKey: keyof Settings;
projectModelKey: keyof Settings;
projectThinkingKey?: keyof Settings;
helperText: string;
fallbackOrder: string;
}
/** Local form state extends Settings with a worktreeInitCommand override and
* lets tokenCap carry null (delete semantic). Mirrors SettingsModal's
* SettingsFormState. */
export type SettingsFormState = Settings & {
worktreeInitCommand?: string;
tokenCap?: number | null;
};
/** State updater identical to React's `setState` for the modal form. */
export type SetSettingsForm = (
updater: SettingsFormState | ((prev: SettingsFormState) => SettingsFormState),
) => void;
/** Async callback registered by a section when it owns a shell-triggered save side effect. */
export type SectionSaveHandler = () => Promise<void>;
/** Props every extracted section receives. */
export interface SectionBaseProps {
/** The single merged settings form (global + project keys). */
form: SettingsFormState;
/** Mutates the form; the shell's save-split decides scope + persistence. */
setForm: SetSettingsForm;
}