feat(FN-1678): merge fusion/fn-1678

This commit is contained in:
gsxdsm
2026-04-15 09:31:03 -07:00
parent 13b80f89e4
commit dc39fa82d5
12 changed files with 559 additions and 69 deletions

View File

@@ -5655,6 +5655,269 @@ describe("Per-task model overrides", () => {
});
});
// ── Lane hierarchy model resolution tests ─────────────────────────────────────
describe("Executor lane hierarchy model resolution", () => {
beforeEach(() => {
vi.clearAllMocks();
mockedExistsSync.mockReturnValue(true);
});
it("resolves task override when both provider and modelId are set", async () => {
const store = createMockStore();
const capturedOptions: any[] = [];
mockedCreateHaiAgent.mockImplementation(async (opts: any) => {
capturedOptions.push(opts);
return {
session: {
prompt: vi.fn().mockResolvedValue(undefined),
dispose: vi.fn(),
state: {},
},
} as any;
});
store.getSettings.mockResolvedValue({
maxConcurrent: 2,
maxWorktrees: 4,
pollIntervalMs: 15000,
defaultProvider: "openai",
defaultModelId: "gpt-4o",
executionGlobalProvider: "google",
executionGlobalModelId: "gemini-2.5",
executionProvider: undefined,
executionModelId: undefined,
});
const executor = new TaskExecutor(store, "/tmp/test");
store.getTask.mockResolvedValue({
id: "FN-001",
title: "Test",
description: "Test task",
column: "in-progress",
dependencies: [],
steps: [],
currentStep: 0,
log: [],
prompt: "# test",
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
modelProvider: "anthropic",
modelId: "claude-sonnet-4-5",
});
await executor.execute({
id: "FN-001",
title: "Test",
description: "Test task",
column: "in-progress",
dependencies: [],
steps: [],
currentStep: 0,
log: [],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
modelProvider: "anthropic",
modelId: "claude-sonnet-4-5",
});
// Task override takes precedence
expect(capturedOptions[0].defaultProvider).toBe("anthropic");
expect(capturedOptions[0].defaultModelId).toBe("claude-sonnet-4-5");
});
it("resolves project execution override when task override is not set", async () => {
const store = createMockStore();
const capturedOptions: any[] = [];
mockedCreateHaiAgent.mockImplementation(async (opts: any) => {
capturedOptions.push(opts);
return {
session: {
prompt: vi.fn().mockResolvedValue(undefined),
dispose: vi.fn(),
state: {},
},
} as any;
});
store.getSettings.mockResolvedValue({
maxConcurrent: 2,
maxWorktrees: 4,
pollIntervalMs: 15000,
defaultProvider: "openai",
defaultModelId: "gpt-4o",
executionGlobalProvider: "google",
executionGlobalModelId: "gemini-2.5",
executionProvider: "anthropic",
executionModelId: "claude-opus-4",
});
const executor = new TaskExecutor(store, "/tmp/test");
store.getTask.mockResolvedValue({
id: "FN-001",
title: "Test",
description: "Test task",
column: "in-progress",
dependencies: [],
steps: [],
currentStep: 0,
log: [],
prompt: "# test",
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
// No task-level model override
});
await executor.execute({
id: "FN-001",
title: "Test",
description: "Test task",
column: "in-progress",
dependencies: [],
steps: [],
currentStep: 0,
log: [],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
// No task-level model override
});
// Project execution override takes precedence over global lane
expect(capturedOptions[0].defaultProvider).toBe("anthropic");
expect(capturedOptions[0].defaultModelId).toBe("claude-opus-4");
});
it("resolves global execution lane when project override is not set", async () => {
const store = createMockStore();
const capturedOptions: any[] = [];
mockedCreateHaiAgent.mockImplementation(async (opts: any) => {
capturedOptions.push(opts);
return {
session: {
prompt: vi.fn().mockResolvedValue(undefined),
dispose: vi.fn(),
state: {},
},
} as any;
});
store.getSettings.mockResolvedValue({
maxConcurrent: 2,
maxWorktrees: 4,
pollIntervalMs: 15000,
defaultProvider: "openai",
defaultModelId: "gpt-4o",
executionGlobalProvider: "google",
executionGlobalModelId: "gemini-2.5",
executionProvider: undefined,
executionModelId: undefined,
});
const executor = new TaskExecutor(store, "/tmp/test");
store.getTask.mockResolvedValue({
id: "FN-001",
title: "Test",
description: "Test task",
column: "in-progress",
dependencies: [],
steps: [],
currentStep: 0,
log: [],
prompt: "# test",
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
// No task-level model override
});
await executor.execute({
id: "FN-001",
title: "Test",
description: "Test task",
column: "in-progress",
dependencies: [],
steps: [],
currentStep: 0,
log: [],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
// No task-level model override
});
// Global execution lane takes precedence over default
expect(capturedOptions[0].defaultProvider).toBe("google");
expect(capturedOptions[0].defaultModelId).toBe("gemini-2.5");
});
it("falls back to default when no lane overrides are set", async () => {
const store = createMockStore();
const capturedOptions: any[] = [];
mockedCreateHaiAgent.mockImplementation(async (opts: any) => {
capturedOptions.push(opts);
return {
session: {
prompt: vi.fn().mockResolvedValue(undefined),
dispose: vi.fn(),
state: {},
},
} as any;
});
store.getSettings.mockResolvedValue({
maxConcurrent: 2,
maxWorktrees: 4,
pollIntervalMs: 15000,
defaultProvider: "openai",
defaultModelId: "gpt-4o",
executionGlobalProvider: undefined,
executionGlobalModelId: undefined,
executionProvider: undefined,
executionModelId: undefined,
});
const executor = new TaskExecutor(store, "/tmp/test");
store.getTask.mockResolvedValue({
id: "FN-001",
title: "Test",
description: "Test task",
column: "in-progress",
dependencies: [],
steps: [],
currentStep: 0,
log: [],
prompt: "# test",
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
// No task-level model override
});
await executor.execute({
id: "FN-001",
title: "Test",
description: "Test task",
column: "in-progress",
dependencies: [],
steps: [],
currentStep: 0,
log: [],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
// No task-level model override
});
// Default takes precedence when no lane overrides are set
expect(capturedOptions[0].defaultProvider).toBe("openai");
expect(capturedOptions[0].defaultModelId).toBe("gpt-4o");
});
});
// ── Per-task thinkingLevel override tests ───────────────────────────
describe("Per-task thinkingLevel override", () => {

View File

@@ -497,12 +497,21 @@ export class TaskExecutor {
activeEntry.lastModelId = task.modelId;
const settings = await this.store.getSettings();
// Resolve model using canonical lane hierarchy for hot-swap
const newProvider = task.modelProvider && task.modelId
? task.modelProvider
: settings?.defaultProvider;
: (settings?.executionProvider && settings?.executionModelId
? settings.executionProvider
: (settings?.executionGlobalProvider && settings?.executionGlobalModelId
? settings.executionGlobalProvider
: settings?.defaultProvider));
const newModelId = task.modelProvider && task.modelId
? task.modelId
: settings?.defaultModelId;
: (settings?.executionProvider && settings?.executionModelId
? settings.executionModelId
: (settings?.executionGlobalProvider && settings?.executionGlobalModelId
? settings.executionGlobalModelId
: settings?.defaultModelId));
if (newProvider && newModelId) {
try {
@@ -1414,14 +1423,25 @@ export class TaskExecutor {
});
const agentWork = async () => {
// Resolve model settings: use per-task overrides if both provider and modelId are set,
// otherwise fall back to global settings
// Resolve model settings using canonical lane hierarchy:
// 1. Task override pair (modelProvider + modelId)
// 2. Project execution override pair (executionProvider + executionModelId)
// 3. Global execution lane pair (executionGlobalProvider + executionGlobalModelId)
// 4. Default pair (defaultProvider + defaultModelId)
const executorProvider = detail.modelProvider && detail.modelId
? detail.modelProvider
: settings.defaultProvider;
: (settings.executionProvider && settings.executionModelId
? settings.executionProvider
: (settings.executionGlobalProvider && settings.executionGlobalModelId
? settings.executionGlobalProvider
: settings.defaultProvider));
const executorModelId = detail.modelProvider && detail.modelId
? detail.modelId
: settings.defaultModelId;
: (settings.executionProvider && settings.executionModelId
? settings.executionModelId
: (settings.executionGlobalProvider && settings.executionGlobalModelId
? settings.executionGlobalModelId
: settings.defaultModelId));
const executorFallbackProvider = settings.fallbackProvider;
const executorFallbackModelId = settings.fallbackModelId;
const executorThinkingLevel = detail.thinkingLevel ?? settings.defaultThinkingLevel;
@@ -2337,16 +2357,24 @@ export class TaskExecutor {
reviewType, promptContent, baseline,
{
onText: (delta) => options.onAgentText?.(taskId, delta),
// Execution defaults as final fallback
defaultProvider: settings.defaultProvider,
defaultModelId: settings.defaultModelId,
fallbackProvider: settings.fallbackProvider,
fallbackModelId: settings.fallbackModelId,
defaultThinkingLevel: detail.thinkingLevel ?? settings.defaultThinkingLevel,
// Per-task validator overrides take precedence over global validator settings
validatorModelProvider: detail.validatorModelProvider ?? settings.validatorProvider,
validatorModelId: detail.validatorModelId ?? settings.validatorModelId,
validatorFallbackModelProvider: settings.validatorFallbackProvider,
validatorFallbackModelId: settings.validatorFallbackModelId,
// Task-level validator override (from task)
taskValidatorProvider: detail.validatorModelProvider,
taskValidatorModelId: detail.validatorModelId,
// Project-level validator override
projectValidatorProvider: settings.validatorProvider,
projectValidatorModelId: settings.validatorModelId,
// Project-level validator fallback
projectValidatorFallbackProvider: settings.validatorFallbackProvider,
projectValidatorFallbackModelId: settings.validatorFallbackModelId,
// Global validator lane
globalValidatorProvider: settings.validatorGlobalProvider,
globalValidatorModelId: settings.validatorGlobalModelId,
store,
taskId,
task: detail,

View File

@@ -259,7 +259,7 @@ describe("reviewStep — validator model overrides", () => {
vi.clearAllMocks();
});
it("uses validatorModelProvider and validatorModelId when both are set", async () => {
it("uses taskValidatorProvider and taskValidatorModelId when both are set", async () => {
mockedCreateHaiAgent.mockResolvedValue(
createMockSession("### Verdict: APPROVE\n### Summary\nLooks good."),
);
@@ -270,8 +270,8 @@ describe("reviewStep — validator model overrides", () => {
{
defaultProvider: "openai",
defaultModelId: "gpt-4o",
validatorModelProvider: "anthropic",
validatorModelId: "claude-sonnet-4-5",
taskValidatorProvider: "anthropic",
taskValidatorModelId: "claude-sonnet-4-5",
},
);
@@ -281,7 +281,7 @@ describe("reviewStep — validator model overrides", () => {
expect(opts.defaultModelId).toBe("claude-sonnet-4-5");
});
it("falls back to defaultProvider/defaultModelId when validatorModelProvider is missing", async () => {
it("falls back to defaultProvider/defaultModelId when taskValidatorProvider is missing", async () => {
mockedCreateHaiAgent.mockResolvedValue(
createMockSession("### Verdict: APPROVE\n### Summary\nLooks good."),
);
@@ -292,8 +292,8 @@ describe("reviewStep — validator model overrides", () => {
{
defaultProvider: "openai",
defaultModelId: "gpt-4o",
// validatorModelProvider is missing
validatorModelId: "claude-sonnet-4-5",
// taskValidatorProvider is missing
taskValidatorModelId: "claude-sonnet-4-5",
},
);
@@ -303,7 +303,7 @@ describe("reviewStep — validator model overrides", () => {
expect(opts.defaultModelId).toBe("gpt-4o");
});
it("falls back to defaultProvider/defaultModelId when validatorModelId is missing", async () => {
it("falls back to defaultProvider/defaultModelId when taskValidatorModelId is missing", async () => {
mockedCreateHaiAgent.mockResolvedValue(
createMockSession("### Verdict: APPROVE\n### Summary\nLooks good."),
);
@@ -314,8 +314,8 @@ describe("reviewStep — validator model overrides", () => {
{
defaultProvider: "openai",
defaultModelId: "gpt-4o",
validatorModelProvider: "anthropic",
// validatorModelId is missing
taskValidatorProvider: "anthropic",
// taskValidatorModelId is missing
},
);
@@ -344,6 +344,74 @@ describe("reviewStep — validator model overrides", () => {
expect(opts.defaultProvider).toBe("openai");
expect(opts.defaultModelId).toBe("gpt-4o");
});
it("resolves project validator override when task override is not set", async () => {
mockedCreateHaiAgent.mockResolvedValue(
createMockSession("### Verdict: APPROVE\n### Summary\nLooks good."),
);
await reviewStep(
"/tmp/worktree", "FN-100", 1, "Test Step", "plan", "# prompt",
undefined,
{
defaultProvider: "openai",
defaultModelId: "gpt-4o",
projectValidatorProvider: "anthropic",
projectValidatorModelId: "claude-opus-4",
// taskValidatorProvider is not set
},
);
expect(mockedCreateHaiAgent).toHaveBeenCalledTimes(1);
const opts = mockedCreateHaiAgent.mock.calls[0][0];
expect(opts.defaultProvider).toBe("anthropic");
expect(opts.defaultModelId).toBe("claude-opus-4");
});
it("resolves global validator lane when project override is not set", async () => {
mockedCreateHaiAgent.mockResolvedValue(
createMockSession("### Verdict: APPROVE\n### Summary\nLooks good."),
);
await reviewStep(
"/tmp/worktree", "FN-100", 1, "Test Step", "plan", "# prompt",
undefined,
{
defaultProvider: "openai",
defaultModelId: "gpt-4o",
globalValidatorProvider: "google",
globalValidatorModelId: "gemini-2.5",
// projectValidatorProvider is not set
// taskValidatorProvider is not set
},
);
expect(mockedCreateHaiAgent).toHaveBeenCalledTimes(1);
const opts = mockedCreateHaiAgent.mock.calls[0][0];
expect(opts.defaultProvider).toBe("google");
expect(opts.defaultModelId).toBe("gemini-2.5");
});
it("falls back to execution default when no validator lanes are set", async () => {
mockedCreateHaiAgent.mockResolvedValue(
createMockSession("### Verdict: APPROVE\n### Summary\nLooks good."),
);
await reviewStep(
"/tmp/worktree", "FN-100", 1, "Test Step", "plan", "# prompt",
undefined,
{
defaultProvider: "openai",
defaultModelId: "gpt-4o",
// No validator lanes set
},
);
expect(mockedCreateHaiAgent).toHaveBeenCalledTimes(1);
const opts = mockedCreateHaiAgent.mock.calls[0][0];
expect(opts.defaultProvider).toBe("openai");
expect(opts.defaultModelId).toBe("gpt-4o");
});
});
describe("REVIEWER_SYSTEM_PROMPT", () => {

View File

@@ -191,18 +191,26 @@ export interface ReviewOptions {
defaultProvider?: string;
/** Default model ID within the provider (e.g. "claude-sonnet-4-5"). When set with `defaultProvider`, overrides the reviewer's model selection. */
defaultModelId?: string;
/** Validator model provider override. When both `validatorModelProvider` and `validatorModelId` are set, they take precedence over `defaultProvider`/`defaultModelId`. */
validatorModelProvider?: string;
/** Validator model ID override. When both `validatorModelProvider` and `validatorModelId` are set, they take precedence over `defaultProvider`/`defaultModelId`. */
validatorModelId?: string;
/** Task-level validator model provider override. When both provider and modelId are set, takes precedence over project/global lanes. */
taskValidatorProvider?: string;
/** Task-level validator model ID override. When both provider and modelId are set, takes precedence over project/global lanes. */
taskValidatorModelId?: string;
/** Project-level validator model provider override. Takes precedence over global validator lane. */
projectValidatorProvider?: string;
/** Project-level validator model ID override. Takes precedence over global validator lane. */
projectValidatorModelId?: string;
/** Global validator lane provider. Takes precedence over execution defaults. */
globalValidatorProvider?: string;
/** Global validator lane model ID. Takes precedence over execution defaults. */
globalValidatorModelId?: string;
/** Fallback model provider used when the primary reviewer model hits a retryable provider-side error. */
fallbackProvider?: string;
/** Fallback model ID used with `fallbackProvider`. */
fallbackModelId?: string;
/** Validator fallback model provider override. When both validator fallback fields are set, they take precedence over fallbackProvider/fallbackModelId. */
validatorFallbackModelProvider?: string;
/** Validator fallback model ID override. When both validator fallback fields are set, they take precedence over fallbackProvider/fallbackModelId. */
validatorFallbackModelId?: string;
/** Project-level validator fallback provider override. Takes precedence over global fallback. */
projectValidatorFallbackProvider?: string;
/** Project-level validator fallback model ID override. Takes precedence over global fallback. */
projectValidatorFallbackModelId?: string;
/** Default thinking effort level for the reviewer agent session. */
defaultThinkingLevel?: string;
/** Task store for persisting agent log entries. When provided with `taskId`, enables full conversation logging. */
@@ -251,19 +259,34 @@ export async function reviewStep(
})
: null;
// Resolve validator model settings: use per-task overrides if both provider and modelId are set,
// otherwise fall back to defaultProvider/defaultModelId
const validatorProvider = options.validatorModelProvider && options.validatorModelId
? options.validatorModelProvider
: options.defaultProvider;
const validatorModelId = options.validatorModelProvider && options.validatorModelId
? options.validatorModelId
: options.defaultModelId;
const validatorFallbackProvider = options.validatorFallbackModelProvider && options.validatorFallbackModelId
? options.validatorFallbackModelProvider
// Resolve validator model settings using canonical lane hierarchy:
// 1. Task-level validator override pair (taskValidatorProvider + taskValidatorModelId)
// 2. Project-level validator override pair (projectValidatorProvider + projectValidatorModelId)
// 3. Global validator lane pair (globalValidatorProvider + globalValidatorModelId)
// 4. Execution default pair (defaultProvider + defaultModelId)
const validatorProvider = options.taskValidatorProvider && options.taskValidatorModelId
? options.taskValidatorProvider
: (options.projectValidatorProvider && options.projectValidatorModelId
? options.projectValidatorProvider
: (options.globalValidatorProvider && options.globalValidatorModelId
? options.globalValidatorProvider
: options.defaultProvider));
const validatorModelId = options.taskValidatorProvider && options.taskValidatorModelId
? options.taskValidatorModelId
: (options.projectValidatorProvider && options.projectValidatorModelId
? options.projectValidatorModelId
: (options.globalValidatorProvider && options.globalValidatorModelId
? options.globalValidatorModelId
: options.defaultModelId));
// Resolve validator fallback using lane hierarchy:
// 1. Project-level validator fallback (projectValidatorFallbackProvider + projectValidatorFallbackModelId)
// 2. Execution fallback (fallbackProvider + fallbackModelId)
const validatorFallbackProvider = options.projectValidatorFallbackProvider && options.projectValidatorFallbackModelId
? options.projectValidatorFallbackProvider
: options.fallbackProvider;
const validatorFallbackModelId = options.validatorFallbackModelProvider && options.validatorFallbackModelId
? options.validatorFallbackModelId
const validatorFallbackModelId = options.projectValidatorFallbackProvider && options.projectValidatorFallbackModelId
? options.projectValidatorFallbackModelId
: options.fallbackModelId;
// Resolve per-agent custom instructions for the reviewer role

View File

@@ -788,12 +788,34 @@ export class StepSessionExecutor {
: [];
// Create fresh agent session for this attempt
// Resolve executor model using canonical lane hierarchy:
// 1. Task override pair (taskDetail.modelProvider + taskDetail.modelId)
// 2. Project execution override pair (settings.executionProvider + settings.executionModelId)
// 3. Global execution lane pair (settings.executionGlobalProvider + settings.executionGlobalModelId)
// 4. Default pair (settings.defaultProvider + settings.defaultModelId)
const executorProvider = taskDetail.modelProvider && taskDetail.modelId
? taskDetail.modelProvider
: (settings.executionProvider && settings.executionModelId
? settings.executionProvider
: (settings.executionGlobalProvider && settings.executionGlobalModelId
? settings.executionGlobalProvider
: settings.defaultProvider));
const executorModelId = taskDetail.modelProvider && taskDetail.modelId
? taskDetail.modelId
: (settings.executionProvider && settings.executionModelId
? settings.executionModelId
: (settings.executionGlobalProvider && settings.executionGlobalModelId
? settings.executionGlobalModelId
: settings.defaultModelId));
const createResult = await createKbAgent({
cwd: worktreePath,
systemPrompt: `You are an AI agent executing step ${stepIndex} of task ${taskDetail.id}. Follow instructions precisely.`,
defaultProvider: taskDetail.modelProvider,
defaultModelId: taskDetail.modelId,
defaultThinkingLevel: taskDetail.thinkingLevel,
defaultProvider: executorProvider,
defaultModelId: executorModelId,
fallbackProvider: settings.fallbackProvider,
fallbackModelId: settings.fallbackModelId,
defaultThinkingLevel: taskDetail.thinkingLevel ?? settings.defaultThinkingLevel,
customTools: [...pluginTools, ...documentTools],
onText: (delta) => {
agentLogger.onText(delta);

View File

@@ -732,8 +732,8 @@ describe("TriageProcessor", () => {
{
defaultProvider: "anthropic",
defaultModelId: "claude-opus-4-6",
validatorProvider: "anthropic",
validatorModelId: "claude-opus-4-6",
projectValidatorProvider: "anthropic",
projectValidatorModelId: "claude-opus-4-6",
},
);
@@ -751,8 +751,8 @@ describe("TriageProcessor", () => {
expect.objectContaining({
defaultProvider: "openai-codex",
defaultModelId: "gpt-5.4",
validatorModelProvider: "zai",
validatorModelId: "glm-5.1",
projectValidatorProvider: "zai",
projectValidatorModelId: "glm-5.1",
userComments: undefined,
}),
);

View File

@@ -697,17 +697,25 @@ export class TriageProcessor {
onThinking: agentLogger.onThinking,
onToolStart: agentLogger.onToolStart,
onToolEnd: agentLogger.onToolEnd,
// Per-task planning model override takes precedence, then project settings, then global defaults
// Resolve planning model using canonical lane hierarchy:
// 1. Task planning override pair (planningModelProvider + planningModelId)
// 2. Project planning override pair (planningProvider + planningModelId)
// 3. Global planning lane pair (planningGlobalProvider + planningGlobalModelId)
// 4. Default pair (defaultProvider + defaultModelId)
defaultProvider: task.planningModelProvider && task.planningModelId
? task.planningModelProvider
: (settings.planningProvider && settings.planningModelId
? settings.planningProvider
: settings.defaultProvider),
? settings.planningProvider
: (settings.planningGlobalProvider && settings.planningGlobalModelId
? settings.planningGlobalProvider
: settings.defaultProvider)),
defaultModelId: task.planningModelProvider && task.planningModelId
? task.planningModelId
: (settings.planningProvider && settings.planningModelId
? settings.planningModelId
: settings.defaultModelId),
? settings.planningModelId
: (settings.planningGlobalProvider && settings.planningGlobalModelId
? settings.planningGlobalModelId
: settings.defaultModelId)),
fallbackProvider: settings.planningFallbackProvider && settings.planningFallbackModelId
? settings.planningFallbackProvider
: settings.fallbackProvider,
@@ -1191,10 +1199,18 @@ export class TriageProcessor {
undefined,
{
onText: (delta) => options.onAgentText?.(taskId, delta),
// Execution defaults as final fallback
defaultProvider: currentSettings.defaultProvider,
defaultModelId: currentSettings.defaultModelId,
validatorModelProvider: currentSettings.validatorProvider,
validatorModelId: currentSettings.validatorModelId,
// Project-level validator override
projectValidatorProvider: currentSettings.validatorProvider,
projectValidatorModelId: currentSettings.validatorModelId,
// Project-level validator fallback
projectValidatorFallbackProvider: currentSettings.validatorFallbackProvider,
projectValidatorFallbackModelId: currentSettings.validatorFallbackModelId,
// Global validator lane
globalValidatorProvider: currentSettings.validatorGlobalProvider,
globalValidatorModelId: currentSettings.validatorGlobalModelId,
defaultThinkingLevel: currentSettings.defaultThinkingLevel,
store,
taskId,