mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
feat: Extend timeout handling for Codex model feature generation
- Introduced a dedicated 5-minute timeout for Codex models during feature generation to accommodate slower response times when generating 50+ features. - Updated the CodexProvider to utilize this extended timeout based on the reasoning effort level. - Enhanced the feature generation logic in generate-features-from-spec.ts to detect Codex models and apply the appropriate timeout. - Modified the model resolver to include reasoning effort in the resolved phase model structure. This change improves the reliability of feature generation for Codex models, ensuring they have sufficient time to process requests effectively.
This commit is contained in:
@@ -98,9 +98,14 @@ const TEXT_ENCODING = 'utf-8';
|
||||
* This is the "no output" timeout - if the CLI doesn't produce any JSONL output
|
||||
* for this duration, the process is killed. For reasoning models with high
|
||||
* reasoning effort, this timeout is dynamically extended via calculateReasoningTimeout().
|
||||
*
|
||||
* For feature generation (which can generate 50+ features), we use a much longer
|
||||
* base timeout (5 minutes) since Codex models are slower at generating large JSON responses.
|
||||
*
|
||||
* @see calculateReasoningTimeout from @automaker/types
|
||||
*/
|
||||
const CODEX_CLI_TIMEOUT_MS = DEFAULT_TIMEOUT_MS;
|
||||
const CODEX_FEATURE_GENERATION_BASE_TIMEOUT_MS = 300000; // 5 minutes for feature generation
|
||||
const CONTEXT_WINDOW_256K = 256000;
|
||||
const MAX_OUTPUT_32K = 32000;
|
||||
const MAX_OUTPUT_16K = 16000;
|
||||
@@ -827,7 +832,14 @@ export class CodexProvider extends BaseProvider {
|
||||
// Higher reasoning effort (e.g., 'xhigh' for "xtra thinking" mode) requires more time
|
||||
// for the model to generate reasoning tokens before producing output.
|
||||
// This fixes GitHub issue #530 where features would get stuck with reasoning models.
|
||||
const timeout = calculateReasoningTimeout(options.reasoningEffort, CODEX_CLI_TIMEOUT_MS);
|
||||
//
|
||||
// For feature generation with 'xhigh', use the extended 5-minute base timeout
|
||||
// since generating 50+ features takes significantly longer than normal operations.
|
||||
const baseTimeout =
|
||||
options.reasoningEffort === 'xhigh'
|
||||
? CODEX_FEATURE_GENERATION_BASE_TIMEOUT_MS
|
||||
: CODEX_CLI_TIMEOUT_MS;
|
||||
const timeout = calculateReasoningTimeout(options.reasoningEffort, baseTimeout);
|
||||
|
||||
const stream = spawnJSONLProcess({
|
||||
command: commandPath,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import * as secureFs from '../../lib/secure-fs.js';
|
||||
import type { EventEmitter } from '../../lib/events.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { DEFAULT_PHASE_MODELS, supportsStructuredOutput } from '@automaker/types';
|
||||
import { DEFAULT_PHASE_MODELS, supportsStructuredOutput, isCodexModel } from '@automaker/types';
|
||||
import { resolvePhaseModel } from '@automaker/model-resolver';
|
||||
import { streamingQuery } from '../../providers/simple-query-service.js';
|
||||
import { parseAndCreateFeatures } from './parse-and-create-features.js';
|
||||
@@ -26,6 +26,12 @@ const logger = createLogger('SpecRegeneration');
|
||||
|
||||
const DEFAULT_MAX_FEATURES = 50;
|
||||
|
||||
/**
|
||||
* Timeout for Codex models when generating features (5 minutes).
|
||||
* Codex models are slower and need more time to generate 50+ features.
|
||||
*/
|
||||
const CODEX_FEATURE_GENERATION_TIMEOUT_MS = 300000; // 5 minutes
|
||||
|
||||
/**
|
||||
* Type for extracted features JSON response
|
||||
*/
|
||||
@@ -189,10 +195,23 @@ Generate ${featureCount} NEW features that build on each other logically. Rememb
|
||||
provider: undefined,
|
||||
credentials: undefined,
|
||||
};
|
||||
const { model, thinkingLevel } = resolvePhaseModel(phaseModelEntry);
|
||||
const { model, thinkingLevel, reasoningEffort } = resolvePhaseModel(phaseModelEntry);
|
||||
|
||||
logger.info('Using model:', model, provider ? `via provider: ${provider.name}` : 'direct API');
|
||||
|
||||
// Codex models need extended timeout for generating many features.
|
||||
// Use 'xhigh' reasoning effort to get 5-minute timeout (300s base * 1.0x = 300s).
|
||||
// The Codex provider has a special 5-minute base timeout for feature generation.
|
||||
const isCodex = isCodexModel(model);
|
||||
const effectiveReasoningEffort = isCodex ? 'xhigh' : reasoningEffort;
|
||||
|
||||
if (isCodex) {
|
||||
logger.info('Codex model detected - using extended timeout (5 minutes for feature generation)');
|
||||
}
|
||||
if (effectiveReasoningEffort) {
|
||||
logger.info('Reasoning effort:', effectiveReasoningEffort);
|
||||
}
|
||||
|
||||
// Determine if we should use structured output based on model type
|
||||
const useStructuredOutput = supportsStructuredOutput(model);
|
||||
logger.info(
|
||||
@@ -239,6 +258,7 @@ Your entire response should be valid JSON starting with { and ending with }. No
|
||||
allowedTools: ['Read', 'Glob', 'Grep'],
|
||||
abortController,
|
||||
thinkingLevel,
|
||||
reasoningEffort: effectiveReasoningEffort, // Extended timeout for Codex models
|
||||
readOnly: true, // Feature generation only reads code, doesn't write
|
||||
settingSources: autoLoadClaudeMd ? ['user', 'project', 'local'] : undefined,
|
||||
claudeCompatibleProvider: provider, // Pass provider for alternative endpoint configuration
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
migrateModelId,
|
||||
type PhaseModelEntry,
|
||||
type ThinkingLevel,
|
||||
type ReasoningEffort,
|
||||
} from '@automaker/types';
|
||||
|
||||
// Pattern definitions for Codex/OpenAI models
|
||||
@@ -162,8 +163,10 @@ export function getEffectiveModel(
|
||||
export interface ResolvedPhaseModel {
|
||||
/** Resolved model string (full model ID) */
|
||||
model: string;
|
||||
/** Optional thinking level for extended thinking */
|
||||
/** Optional thinking level for extended thinking (Claude models) */
|
||||
thinkingLevel?: ThinkingLevel;
|
||||
/** Optional reasoning effort for timeout calculation (Codex models) */
|
||||
reasoningEffort?: ReasoningEffort;
|
||||
/** Provider ID if using a ClaudeCompatibleProvider */
|
||||
providerId?: string;
|
||||
}
|
||||
@@ -205,6 +208,7 @@ export function resolvePhaseModel(
|
||||
return {
|
||||
model: resolveModelString(undefined, defaultModel),
|
||||
thinkingLevel: undefined,
|
||||
reasoningEffort: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -214,12 +218,13 @@ export function resolvePhaseModel(
|
||||
return {
|
||||
model: resolveModelString(phaseModel, defaultModel),
|
||||
thinkingLevel: undefined,
|
||||
reasoningEffort: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
// Handle new PhaseModelEntry object format
|
||||
console.log(
|
||||
`[ModelResolver] phaseModel is object format: model="${phaseModel.model}", thinkingLevel="${phaseModel.thinkingLevel}", providerId="${phaseModel.providerId}"`
|
||||
`[ModelResolver] phaseModel is object format: model="${phaseModel.model}", thinkingLevel="${phaseModel.thinkingLevel}", reasoningEffort="${phaseModel.reasoningEffort}", providerId="${phaseModel.providerId}"`
|
||||
);
|
||||
|
||||
// If providerId is set, pass through the model string unchanged
|
||||
@@ -231,6 +236,7 @@ export function resolvePhaseModel(
|
||||
return {
|
||||
model: phaseModel.model, // Pass through unchanged
|
||||
thinkingLevel: phaseModel.thinkingLevel,
|
||||
reasoningEffort: phaseModel.reasoningEffort,
|
||||
providerId: phaseModel.providerId,
|
||||
};
|
||||
}
|
||||
@@ -239,5 +245,6 @@ export function resolvePhaseModel(
|
||||
return {
|
||||
model: resolveModelString(phaseModel.model, defaultModel),
|
||||
thinkingLevel: phaseModel.thinkingLevel,
|
||||
reasoningEffort: phaseModel.reasoningEffort,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user