fix: Add structured output fallback for non-Claude models in app spec generation

This fixes the app spec generation failing for non-Claude models (Cursor, Gemini,
OpenCode, Copilot) that don't support structured output capabilities.

Changes:
- Add `supportsStructuredOutput()` utility function in @automaker/types to
  centralize model capability detection
- Update generate-features-from-spec.ts:
  - Add explicit JSON instructions for non-Claude/Codex models
  - Define featuresOutputSchema for structured output
  - Pre-extract JSON from text responses using extractJsonWithArray
  - Handle both structured_output and text responses properly
- Update generate-spec.ts:
  - Replace isCursorModel with supportsStructuredOutput for consistency
- Update sync-spec.ts:
  - Add techStackOutputSchema for structured output
  - Add JSON extraction fallback for text responses
  - Handle both structured_output and text parsing
- Update validate-issue.ts:
  - Use supportsStructuredOutput for cleaner capability detection

The fix follows the same pattern used in generate-spec.ts where non-Claude models
receive explicit JSON formatting instructions in the prompt and responses are
parsed using extractJson utilities.

Fixes #669

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Shirone
2026-01-24 18:25:39 +01:00
parent d8fa5c4cd1
commit 92b1fb3725
6 changed files with 261 additions and 44 deletions

View File

@@ -272,6 +272,7 @@ export {
getBareModelId,
normalizeModelString,
validateBareModelId,
supportsStructuredOutput,
} from './provider-utils.js';
// Model migration utilities

View File

@@ -345,6 +345,34 @@ 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 {
return isClaudeModel(model) || isCodexModel(model);
}
/**
* Validate that a model ID does not contain a provider prefix
*