feat(FN-1044): add thinkingLevel and planning model support to task creation

- Add thinkingLevel field to createTask and updateTask in core store
- Accept thinkingLevel and planningModel fields in dashboard task routes
- Send thinkingLevel and planningModel in frontend API calls from task forms
- Add ThinkingLevel selector to ModelSelectorTab component with tests
- Wire up planning model and thinking level in QuickEntryBox, TaskForm, and NewTaskModal
- Add unit tests for store, routes, and ModelSelectorTab coverage
- Add changeset and update AGENTS.md documentation
This commit is contained in:
gsxdsm
2026-04-07 12:18:49 -07:00
parent 825ae1061b
commit 880f29115c
13 changed files with 463 additions and 12 deletions

View File

@@ -22,6 +22,8 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
const [isSubmitting, setIsSubmitting] = useState(false);
const [executorModel, setExecutorModel] = useState("");
const [validatorModel, setValidatorModel] = useState("");
const [planningModel, setPlanningModel] = useState("");
const [thinkingLevel, setThinkingLevel] = useState<string>("off");
const [selectedPresetId, setSelectedPresetId] = useState<string>("");
const [presetMode, setPresetMode] = useState<"default" | "preset" | "custom">("default");
const [hasDirtyState, setHasDirtyState] = useState(false);
@@ -42,15 +44,17 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
// Track dirty state
useEffect(() => {
const isDirty =
const isDirty =
description.trim() !== "" ||
dependencies.length > 0 ||
pendingImages.length > 0 ||
executorModel !== "" ||
validatorModel !== "" ||
planningModel !== "" ||
thinkingLevel !== "off" ||
selectedWorkflowSteps.length > 0;
setHasDirtyState(isDirty);
}, [description, dependencies, pendingImages, executorModel, validatorModel, selectedWorkflowSteps]);
}, [description, dependencies, pendingImages, executorModel, validatorModel, planningModel, thinkingLevel, selectedWorkflowSteps]);
const handleClose = useCallback(() => {
if (hasDirtyState) {
@@ -64,6 +68,8 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
setDependencies([]);
setExecutorModel("");
setValidatorModel("");
setPlanningModel("");
setThinkingLevel("off");
setSelectedPresetId("");
setPresetMode("default");
setSelectedWorkflowSteps([]);
@@ -80,6 +86,7 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
try {
const executorSlashIdx = executorModel.indexOf("/");
const validatorSlashIdx = validatorModel.indexOf("/");
const planningSlashIdx = planningModel.indexOf("/");
const task = await onCreateTask({
title: undefined,
@@ -94,6 +101,9 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
modelId: executorModel && executorSlashIdx !== -1 ? executorModel.slice(executorSlashIdx + 1) : undefined,
validatorModelProvider: validatorModel && validatorSlashIdx !== -1 ? validatorModel.slice(0, validatorSlashIdx) : undefined,
validatorModelId: validatorModel && validatorSlashIdx !== -1 ? validatorModel.slice(validatorSlashIdx + 1) : undefined,
planningModelProvider: planningModel && planningSlashIdx !== -1 ? planningModel.slice(0, planningSlashIdx) : undefined,
planningModelId: planningModel && planningSlashIdx !== -1 ? planningModel.slice(planningSlashIdx + 1) : undefined,
thinkingLevel: thinkingLevel !== "off" ? thinkingLevel as "minimal" | "low" | "medium" | "high" : undefined,
});
// Upload pending images as attachments
@@ -118,6 +128,8 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
setDependencies([]);
setExecutorModel("");
setValidatorModel("");
setPlanningModel("");
setThinkingLevel("off");
setSelectedPresetId("");
setPresetMode("default");
setSelectedWorkflowSteps([]);
@@ -130,7 +142,7 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
} finally {
setIsSubmitting(false);
}
}, [description, dependencies, pendingImages, executorModel, validatorModel, isSubmitting, onCreateTask, addToast, onClose, projectId, presetMode, selectedPresetId, selectedWorkflowSteps, workflowStepsExplicitlySet]);
}, [description, dependencies, pendingImages, executorModel, validatorModel, planningModel, thinkingLevel, isSubmitting, onCreateTask, addToast, onClose, projectId, presetMode, selectedPresetId, selectedWorkflowSteps, workflowStepsExplicitlySet]);
// Handle keyboard shortcuts
const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
@@ -183,6 +195,10 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
onPlanningMode={onPlanningMode}
onSubtaskBreakdown={onSubtaskBreakdown}
onClose={handleClose}
planningModel={planningModel}
onPlanningModelChange={setPlanningModel}
thinkingLevel={thinkingLevel}
onThinkingLevelChange={setThinkingLevel}
/>
</div>