mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-03 08:53:36 +00:00
Merge pull request #682 from AutoMaker-Org/feature/bug-fix-app-spec-generation-for-non-claude-models-dgq0
fix: Add structured output fallback for non-Claude models in app spec generation
This commit is contained in:
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -272,6 +272,7 @@ export {
|
||||
getBareModelId,
|
||||
normalizeModelString,
|
||||
validateBareModelId,
|
||||
supportsStructuredOutput,
|
||||
} from './provider-utils.js';
|
||||
|
||||
// Model migration utilities
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import type { ModelProvider } from './settings.js';
|
||||
import { CURSOR_MODEL_MAP, LEGACY_CURSOR_MODEL_MAP } from './cursor-models.js';
|
||||
import { LEGACY_CURSOR_MODEL_MAP } from './cursor-models.js';
|
||||
import { CLAUDE_MODEL_MAP, CODEX_MODEL_MAP } from './model.js';
|
||||
import { OPENCODE_MODEL_CONFIG_MAP, LEGACY_OPENCODE_MODEL_MAP } from './opencode-models.js';
|
||||
import { GEMINI_MODEL_MAP } from './gemini-models.js';
|
||||
@@ -345,6 +345,44 @@ export function normalizeModelString(model: string | undefined | null): string {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a model supports structured output (JSON schema)
|
||||
*
|
||||
* Structured output is a feature that allows the model to return responses
|
||||
* conforming to a JSON schema. Currently supported by:
|
||||
* - Claude models (native Anthropic API support)
|
||||
* - Codex/OpenAI models (via response_format with json_schema)
|
||||
*
|
||||
* Models that do NOT support structured output:
|
||||
* - Cursor models (uses different API format)
|
||||
* - OpenCode models (various backend providers)
|
||||
* - Gemini models (different API)
|
||||
* - Copilot models (proxy to various backends)
|
||||
*
|
||||
* @param model - Model string to check
|
||||
* @returns true if the model supports structured output
|
||||
*
|
||||
* @example
|
||||
* supportsStructuredOutput('sonnet') // true (Claude)
|
||||
* supportsStructuredOutput('claude-sonnet-4-20250514') // true (Claude)
|
||||
* supportsStructuredOutput('codex-gpt-5.2') // true (Codex/OpenAI)
|
||||
* supportsStructuredOutput('cursor-auto') // false
|
||||
* supportsStructuredOutput('gemini-2.5-pro') // false
|
||||
*/
|
||||
export function supportsStructuredOutput(model: string | undefined | null): boolean {
|
||||
// Exclude proxy providers first - they may have Claude/Codex in the model name
|
||||
// but route through different APIs that don't support structured output
|
||||
if (
|
||||
isCursorModel(model) ||
|
||||
isGeminiModel(model) ||
|
||||
isOpencodeModel(model) ||
|
||||
isCopilotModel(model)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return isClaudeModel(model) || isCodexModel(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a model ID does not contain a provider prefix
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user