feat: enhance SDK options with thinking level support

- Introduced a new function, buildThinkingOptions, to handle the conversion of ThinkingLevel to maxThinkingTokens for the Claude SDK.
- Updated existing SDK option creation functions to incorporate thinking options, ensuring that maxThinkingTokens are included based on the specified thinking level.
- Enhanced the settings service to support migration of phase models to include thinking levels, improving compatibility with new configurations.
- Added comprehensive tests for thinking level integration and migration logic, ensuring robust functionality across the application.

This update significantly improves the SDK's configurability and performance by allowing for more nuanced control over reasoning capabilities.
This commit is contained in:
Shirone
2026-01-02 14:55:52 +01:00
parent 914734cff6
commit 81d300391d
27 changed files with 1134 additions and 101 deletions

View File

@@ -4,10 +4,22 @@ import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { useAppStore } from '@/store/app-store';
import type { ModelAlias, CursorModelId, PhaseModelKey } from '@automaker/types';
import type { ModelAlias, CursorModelId, PhaseModelKey, PhaseModelEntry } from '@automaker/types';
import { PROVIDER_PREFIXES, stripProviderPrefix } from '@automaker/types';
import { CLAUDE_MODELS, CURSOR_MODELS } from '@/components/views/board-view/shared/model-constants';
/**
* Extract model string from PhaseModelEntry or string
*/
function extractModel(entry: PhaseModelEntry | string | null): ModelAlias | CursorModelId | null {
if (!entry) return null;
if (typeof entry === 'string') {
return entry as ModelAlias | CursorModelId;
}
return entry.model;
}
export interface ModelOverrideTriggerProps {
/** Current effective model (from global settings or explicit override) */
currentModel: ModelAlias | CursorModelId;
@@ -53,8 +65,8 @@ export function ModelOverrideTrigger({
const [open, setOpen] = useState(false);
const { phaseModels, enabledCursorModels } = useAppStore();
// Get the global default for this phase
const globalDefault = phase ? phaseModels[phase] : null;
// Get the global default for this phase (extract model string from PhaseModelEntry)
const globalDefault = phase ? extractModel(phaseModels[phase]) : null;
// Filter Cursor models to only show enabled ones
const availableCursorModels = CURSOR_MODELS.filter((model) => {

View File

@@ -1,6 +1,6 @@
import { useState, useCallback, useMemo } from 'react';
import { useAppStore } from '@/store/app-store';
import type { ModelAlias, CursorModelId, PhaseModelKey } from '@automaker/types';
import type { ModelAlias, CursorModelId, PhaseModelKey, PhaseModelEntry } from '@automaker/types';
export interface UseModelOverrideOptions {
/** Which phase this override is for */
@@ -24,6 +24,16 @@ export interface UseModelOverrideResult {
override: ModelAlias | CursorModelId | null;
}
/**
* Extract model string from PhaseModelEntry or string
*/
function extractModel(entry: PhaseModelEntry | string): ModelAlias | CursorModelId {
if (typeof entry === 'string') {
return entry as ModelAlias | CursorModelId;
}
return entry.model;
}
/**
* Hook for managing model overrides per phase
*
@@ -55,7 +65,8 @@ export function useModelOverride({
const { phaseModels } = useAppStore();
const [override, setOverrideState] = useState<ModelAlias | CursorModelId | null>(initialOverride);
const globalDefault = phaseModels[phase];
// Extract model string from PhaseModelEntry (handles both old string format and new object format)
const globalDefault = extractModel(phaseModels[phase]);
const effectiveModel = useMemo(() => {
return override ?? globalDefault;