Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion apps/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,10 @@ app.use('/api/context', createContextRoutes(settingsService));
app.use('/api/backlog-plan', createBacklogPlanRoutes(events, settingsService));
app.use('/api/mcp', createMCPRoutes(mcpTestService));
app.use('/api/pipeline', createPipelineRoutes(pipelineService));
app.use('/api/ideation', createIdeationRoutes(events, ideationService, featureLoader));
app.use(
'/api/ideation',
createIdeationRoutes(events, ideationService, featureLoader, settingsService)
);

// Create HTTP server
const server = createServer(app);
Expand Down
6 changes: 4 additions & 2 deletions apps/server/src/routes/ideation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { EventEmitter } from '../../lib/events.js';
import { validatePathParams } from '../../middleware/validate-paths.js';
import type { IdeationService } from '../../services/ideation-service.js';
import type { FeatureLoader } from '../../services/feature-loader.js';
import type { SettingsService } from '../../services/settings-service.js';

// Route handlers
import { createSessionStartHandler } from './routes/session-start.js';
Expand All @@ -27,7 +28,8 @@ import { createSuggestionsGenerateHandler } from './routes/suggestions-generate.
export function createIdeationRoutes(
events: EventEmitter,
ideationService: IdeationService,
featureLoader: FeatureLoader
featureLoader: FeatureLoader,
settingsService: SettingsService
): Router {
const router = Router();

Expand Down Expand Up @@ -91,7 +93,7 @@ export function createIdeationRoutes(
router.post(
'/add-suggestion',
validatePathParams('projectPath'),
createAddSuggestionHandler(ideationService, featureLoader)
createAddSuggestionHandler(ideationService, featureLoader, settingsService)
);

// Guided prompts (no validation needed - static data)
Expand Down
20 changes: 18 additions & 2 deletions apps/server/src/routes/ideation/routes/add-suggestion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,22 @@
* This endpoint converts an AnalysisSuggestion to a Feature using the
* IdeationService's mapIdeaCategoryToFeatureCategory for consistent category mapping.
* This ensures a single source of truth for the conversion logic.
*
* The feature is created with the user's configured defaultFeatureModel from settings,
* ensuring consistency with manually created features.
*/

import type { Request, Response } from 'express';
import type { IdeationService } from '../../../services/ideation-service.js';
import type { FeatureLoader } from '../../../services/feature-loader.js';
import type { SettingsService } from '../../../services/settings-service.js';
import type { AnalysisSuggestion } from '@automaker/types';
import { getErrorMessage, logError } from '../common.js';

export function createAddSuggestionHandler(
ideationService: IdeationService,
featureLoader: FeatureLoader
featureLoader: FeatureLoader,
settingsService: SettingsService
) {
return async (req: Request, res: Response): Promise<void> => {
try {
Expand Down Expand Up @@ -53,12 +58,23 @@ export function createAddSuggestionHandler(
suggestion.category
);

// Create the feature
// Get the default feature model from user settings
let model: string | undefined;
try {
const settings = await settingsService.getGlobalSettings();
model = settings.defaultFeatureModel?.model;
} catch (error) {
// If settings fail to load, proceed without a model (will use system default)
logError(error, 'Failed to get default feature model from settings');
}

// Create the feature with the configured default model
const feature = await featureLoader.create(projectPath, {
title: suggestion.title,
description,
category: featureCategory,
status: 'backlog',
...(model && { model }), // Only include model if it was retrieved
});

res.json({ success: true, featureId: feature.id });
Expand Down
24 changes: 22 additions & 2 deletions apps/server/src/services/ideation-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,17 @@ export class IdeationService {
);

// Resolve model alias to canonical identifier (with prefix)
const modelId = resolveModelString(options?.model ?? 'sonnet');
let defaultModel = 'sonnet';
if (this.settingsService) {
try {
const settings = await this.settingsService.getGlobalSettings();
defaultModel = settings.phaseModels.ideationModel.model;
} catch (error) {
logger.warn('Failed to get settings for model selection, using default', error);
}
}
Comment on lines +211 to +219
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's an opportunity to reduce code duplication. This block of code for fetching a model from settings is very similar to the one in the generateSuggestions method (lines 676-684).

Consider extracting this logic into a private helper method to improve maintainability. For example:

private async _getModelForPhase(phase: keyof PhaseModelConfig, fallback: string): Promise<string> {
  if (!this.settingsService) {
    return fallback;
  }
  try {
    const settings = await this.settingsService.getGlobalSettings();
    return settings.phaseModels[phase]?.model ?? fallback;
  } catch (error) {
    logger.warn(`Failed to get settings for ${phase} model, using default`, error);
    return fallback;
  }
}

You could then use it like this in sendMessage:

const defaultModel = await this._getModelForPhase('ideationModel', 'sonnet');

And in generateSuggestions:

const modelToUse = await this._getModelForPhase('suggestionsModel', 'sonnet');


const modelId = resolveModelString(options?.model ?? defaultModel);

// Create SDK options
const sdkOptions = createChatOptions({
Expand Down Expand Up @@ -663,7 +673,17 @@ export class IdeationService {
);

// Resolve model alias to canonical identifier (with prefix)
const modelId = resolveModelString('sonnet');
let modelToUse = 'sonnet';
if (this.settingsService) {
try {
const settings = await this.settingsService.getGlobalSettings();
modelToUse = settings.phaseModels.suggestionsModel.model;
} catch (error) {
logger.warn('Failed to get settings for model selection, using default', error);
}
}

const modelId = resolveModelString(modelToUse);

// Create SDK options
const sdkOptions = createChatOptions({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ const GENERATION_TASKS: PhaseConfig[] = [
label: 'AI Suggestions',
description: 'Model for feature, refactoring, security, and performance suggestions',
},
{
key: 'ideationModel',
label: 'Ideation & Brainstorming',
description: 'Interactive brainstorming and idea generation sessions',
},
];

const MEMORY_TASKS: PhaseConfig[] = [
Expand Down
3 changes: 3 additions & 0 deletions libs/types/src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ export interface PhaseModelConfig {
projectAnalysisModel: PhaseModelEntry;
/** Model for AI suggestions (feature, refactoring, security, performance) */
suggestionsModel: PhaseModelEntry;
/** Model for interactive ideation and brainstorming sessions */
ideationModel: PhaseModelEntry;

// Memory tasks - for learning extraction and memory operations
/** Model for extracting learnings from completed agent sessions */
Expand Down Expand Up @@ -777,6 +779,7 @@ export const DEFAULT_PHASE_MODELS: PhaseModelConfig = {
backlogPlanningModel: { model: 'sonnet' },
projectAnalysisModel: { model: 'sonnet' },
suggestionsModel: { model: 'sonnet' },
ideationModel: { model: 'sonnet' },

// Memory - use fast model for learning extraction (cost-effective)
memoryExtractionModel: { model: 'haiku' },
Expand Down
Loading