feat: AI auto-fix + Gemini Flash provider #93
@@ -5,10 +5,13 @@ Supports Gemini (google-genai) and Anthropic (anthropic) as interchangeable
|
||||
backends for JSON generation used by the AI Flow Builder.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from app.core.config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AIProvider(ABC):
|
||||
"""Abstract base class for AI providers."""
|
||||
@@ -74,6 +77,16 @@ class GeminiProvider(AIProvider):
|
||||
config=config,
|
||||
)
|
||||
|
||||
# Log finish reason to detect truncation
|
||||
if response.candidates:
|
||||
finish_reason = getattr(response.candidates[0], "finish_reason", None)
|
||||
logger.info("Gemini finish_reason=%s model=%s", finish_reason, self._model)
|
||||
if str(finish_reason) == "MAX_TOKENS":
|
||||
logger.warning(
|
||||
"Gemini output truncated (MAX_TOKENS). max_output_tokens=%d",
|
||||
max_tokens,
|
||||
)
|
||||
|
||||
text = response.text or ""
|
||||
input_tokens = getattr(response.usage_metadata, "prompt_token_count", 0) or 0
|
||||
output_tokens = (
|
||||
|
||||
@@ -154,15 +154,23 @@ async def scaffold_branches(
|
||||
raw_text, input_tokens, output_tokens = await provider.generate_json(
|
||||
system_prompt=SCAFFOLD_SYSTEM_PROMPT,
|
||||
messages=[{"role": "user", "content": user_message}],
|
||||
max_tokens=1024,
|
||||
max_tokens=2048,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"scaffold raw response (tokens in=%d out=%d, len=%d): %s",
|
||||
input_tokens,
|
||||
output_tokens,
|
||||
len(raw_text),
|
||||
raw_text[:500],
|
||||
)
|
||||
raw_text = _strip_markdown_fences(raw_text)
|
||||
cost = _estimate_cost(input_tokens, output_tokens)
|
||||
|
||||
try:
|
||||
data = json.loads(raw_text)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error("scaffold JSON parse failed. Full text (%d chars): %s", len(raw_text), raw_text)
|
||||
raise ValueError(f"AI returned invalid JSON: {e}")
|
||||
|
||||
branches = data.get("branches", [])
|
||||
@@ -224,6 +232,10 @@ async def generate_branch_detail(
|
||||
try:
|
||||
branch_tree = json.loads(raw_text)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(
|
||||
"branch_detail attempt=%d JSON parse failed (%d chars): %s",
|
||||
attempt, len(raw_text), raw_text[:500],
|
||||
)
|
||||
if attempt < 2:
|
||||
messages.append({"role": "assistant", "content": raw_text})
|
||||
messages.append({
|
||||
|
||||
Reference in New Issue
Block a user