mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
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:
@@ -16,6 +16,8 @@ import type {
|
||||
ModelProvider,
|
||||
PipelineConfig,
|
||||
PipelineStep,
|
||||
ThinkingLevel,
|
||||
PlanningMode,
|
||||
} from '@automaker/types';
|
||||
import { DEFAULT_PHASE_MODELS } from '@automaker/types';
|
||||
import {
|
||||
@@ -24,7 +26,7 @@ import {
|
||||
classifyError,
|
||||
loadContextFiles,
|
||||
} from '@automaker/utils';
|
||||
import { resolveModelString, DEFAULT_MODELS } from '@automaker/model-resolver';
|
||||
import { resolveModelString, resolvePhaseModel, DEFAULT_MODELS } from '@automaker/model-resolver';
|
||||
import { resolveDependencies, areDependenciesSatisfied } from '@automaker/dependency-resolver';
|
||||
import { getFeatureDir, getAutomakerDir, getFeaturesDir } from '@automaker/platform';
|
||||
import { exec } from 'child_process';
|
||||
@@ -51,8 +53,7 @@ import {
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
// Planning mode types for spec-driven development
|
||||
type PlanningMode = 'skip' | 'lite' | 'spec' | 'full';
|
||||
// PlanningMode type is imported from @automaker/types
|
||||
|
||||
interface ParsedTask {
|
||||
id: string; // e.g., "T001"
|
||||
@@ -576,6 +577,7 @@ export class AutoModeService {
|
||||
requirePlanApproval: feature.requirePlanApproval,
|
||||
systemPrompt: contextFilesPrompt || undefined,
|
||||
autoLoadClaudeMd,
|
||||
thinkingLevel: feature.thinkingLevel,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -734,6 +736,7 @@ export class AutoModeService {
|
||||
previousContent: previousContext,
|
||||
systemPrompt: contextFilesPrompt || undefined,
|
||||
autoLoadClaudeMd,
|
||||
thinkingLevel: feature.thinkingLevel,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1049,6 +1052,7 @@ Address the follow-up instructions above. Review the previous work and make the
|
||||
previousContent: previousContext || undefined,
|
||||
systemPrompt: contextFilesPrompt || undefined,
|
||||
autoLoadClaudeMd,
|
||||
thinkingLevel: feature?.thinkingLevel,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1278,9 +1282,10 @@ Format your response as a structured markdown document.`;
|
||||
try {
|
||||
// Get model from phase settings
|
||||
const settings = await this.settingsService?.getGlobalSettings();
|
||||
const projectAnalysisModel =
|
||||
const phaseModelEntry =
|
||||
settings?.phaseModels?.projectAnalysisModel || DEFAULT_PHASE_MODELS.projectAnalysisModel;
|
||||
const analysisModel = resolveModelString(projectAnalysisModel, DEFAULT_MODELS.claude);
|
||||
const { model: analysisModel, thinkingLevel: analysisThinkingLevel } =
|
||||
resolvePhaseModel(phaseModelEntry);
|
||||
console.log('[AutoMode] Using model for project analysis:', analysisModel);
|
||||
|
||||
const provider = ProviderFactory.getProviderForModel(analysisModel);
|
||||
@@ -1300,6 +1305,7 @@ Format your response as a structured markdown document.`;
|
||||
allowedTools: ['Read', 'Glob', 'Grep'],
|
||||
abortController,
|
||||
autoLoadClaudeMd,
|
||||
thinkingLevel: analysisThinkingLevel,
|
||||
});
|
||||
|
||||
const options: ExecuteOptions = {
|
||||
@@ -1311,6 +1317,7 @@ Format your response as a structured markdown document.`;
|
||||
abortController,
|
||||
settingSources: sdkOptions.settingSources,
|
||||
sandbox: sdkOptions.sandbox, // Pass sandbox configuration
|
||||
thinkingLevel: analysisThinkingLevel, // Pass thinking level
|
||||
};
|
||||
|
||||
const stream = provider.executeQuery(options);
|
||||
@@ -1954,6 +1961,7 @@ This helps parse your summary correctly in the output logs.`;
|
||||
previousContent?: string;
|
||||
systemPrompt?: string;
|
||||
autoLoadClaudeMd?: boolean;
|
||||
thinkingLevel?: ThinkingLevel;
|
||||
}
|
||||
): Promise<void> {
|
||||
const finalProjectPath = options?.projectPath || projectPath;
|
||||
@@ -2052,6 +2060,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
mcpServers: Object.keys(mcpServers).length > 0 ? mcpServers : undefined,
|
||||
mcpAutoApproveTools: mcpPermissions.mcpAutoApproveTools,
|
||||
mcpUnrestrictedTools: mcpPermissions.mcpUnrestrictedTools,
|
||||
thinkingLevel: options?.thinkingLevel,
|
||||
});
|
||||
|
||||
// Extract model, maxTurns, and allowedTools from SDK options
|
||||
@@ -2096,6 +2105,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
mcpServers: Object.keys(mcpServers).length > 0 ? mcpServers : undefined, // Pass MCP servers configuration
|
||||
mcpAutoApproveTools: mcpPermissions.mcpAutoApproveTools, // Pass MCP auto-approve setting
|
||||
mcpUnrestrictedTools: mcpPermissions.mcpUnrestrictedTools, // Pass MCP unrestricted tools setting
|
||||
thinkingLevel: options?.thinkingLevel, // Pass thinking level for extended thinking
|
||||
};
|
||||
|
||||
// Execute via provider
|
||||
|
||||
@@ -28,6 +28,7 @@ import type {
|
||||
BoardBackgroundSettings,
|
||||
WorktreeInfo,
|
||||
PhaseModelConfig,
|
||||
PhaseModelEntry,
|
||||
} from '../types/settings.js';
|
||||
import {
|
||||
DEFAULT_GLOBAL_SETTINGS,
|
||||
@@ -157,10 +158,23 @@ export class SettingsService {
|
||||
if (storedVersion < 2) {
|
||||
logger.info('Migrating settings from v1 to v2: disabling sandbox mode');
|
||||
result.enableSandboxMode = false;
|
||||
result.version = SETTINGS_VERSION;
|
||||
needsSave = true;
|
||||
}
|
||||
|
||||
// Migration v2 -> v3: Convert string phase models to PhaseModelEntry objects
|
||||
// Note: migratePhaseModels() handles the actual conversion for both v1 and v2 formats
|
||||
if (storedVersion < 3) {
|
||||
logger.info(
|
||||
`Migrating settings from v${storedVersion} to v3: converting phase models to PhaseModelEntry format`
|
||||
);
|
||||
needsSave = true;
|
||||
}
|
||||
|
||||
// Update version if any migration occurred
|
||||
if (needsSave) {
|
||||
result.version = SETTINGS_VERSION;
|
||||
}
|
||||
|
||||
// Save migrated settings if needed
|
||||
if (needsSave) {
|
||||
try {
|
||||
@@ -179,6 +193,7 @@ export class SettingsService {
|
||||
* Migrate legacy enhancementModel/validationModel fields to phaseModels structure
|
||||
*
|
||||
* Handles backwards compatibility for settings created before phaseModels existed.
|
||||
* Also handles migration from string phase models (v2) to PhaseModelEntry objects (v3).
|
||||
* Legacy fields take precedence over defaults but phaseModels takes precedence over legacy.
|
||||
*
|
||||
* @param settings - Raw settings from file
|
||||
@@ -190,26 +205,51 @@ export class SettingsService {
|
||||
|
||||
// If phaseModels exists, use it (with defaults for any missing fields)
|
||||
if (settings.phaseModels) {
|
||||
return {
|
||||
...DEFAULT_PHASE_MODELS,
|
||||
...settings.phaseModels,
|
||||
};
|
||||
// Merge with defaults and convert any string values to PhaseModelEntry
|
||||
const merged: PhaseModelConfig = { ...DEFAULT_PHASE_MODELS };
|
||||
for (const key of Object.keys(settings.phaseModels) as Array<keyof PhaseModelConfig>) {
|
||||
const value = settings.phaseModels[key];
|
||||
if (value !== undefined) {
|
||||
// Convert string to PhaseModelEntry if needed (v2 -> v3 migration)
|
||||
merged[key] = this.toPhaseModelEntry(value);
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
// Migrate legacy fields if phaseModels doesn't exist
|
||||
// These were the only two legacy fields that existed
|
||||
if (settings.enhancementModel) {
|
||||
result.enhancementModel = settings.enhancementModel;
|
||||
result.enhancementModel = this.toPhaseModelEntry(settings.enhancementModel);
|
||||
logger.debug(`Migrated legacy enhancementModel: ${settings.enhancementModel}`);
|
||||
}
|
||||
if (settings.validationModel) {
|
||||
result.validationModel = settings.validationModel;
|
||||
result.validationModel = this.toPhaseModelEntry(settings.validationModel);
|
||||
logger.debug(`Migrated legacy validationModel: ${settings.validationModel}`);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a phase model value to PhaseModelEntry format
|
||||
*
|
||||
* Handles migration from string format (v2) to object format (v3).
|
||||
* - String values like 'sonnet' become { model: 'sonnet' }
|
||||
* - Object values are returned as-is (with type assertion)
|
||||
*
|
||||
* @param value - Phase model value (string or PhaseModelEntry)
|
||||
* @returns PhaseModelEntry object
|
||||
*/
|
||||
private toPhaseModelEntry(value: string | PhaseModelEntry): PhaseModelEntry {
|
||||
if (typeof value === 'string') {
|
||||
// v2 format: just a model string
|
||||
return { model: value as PhaseModelEntry['model'] };
|
||||
}
|
||||
// v3 format: already a PhaseModelEntry object
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update global settings with partial changes
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user