fix: Gemini deprecated 모델 제거 및 2.5-flash 단일 모델 재시도 로직 적용 - #131
Conversation
fix: Replace deprecated gemini-1.5-flash with gemini-2.0-flash gemini-1.5-flash is no longer available in the v1beta API, causing 404 errors when all prior fallback models also fail. Update the last resort model to gemini-2.0-flash across chatbot, moderation, and judgment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> @
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughChatbot, Judgment, Moderation 세 AI 모듈에서 다중 폴백 모델 순회 패턴을 제거하고, 고정 모델( ChangesAI 모듈 폴백 반복에서 재시도 로직으로 전환
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 OpenGrep (1.23.0)src/lib/ai/chatbot.ts┌──────────────┐ �[32m✔�[39m �[1mOpengrep OSS�[0m [00.21][ERROR]: unable to find a config; path Comment |
fix: Remove deprecated models and add per-model retry for 503/429 gemini-2.0-flash-lite, gemini-2.0-flash, gemini-1.5-flash are all deprecated (404). Replace with gemini-2.5-flash + gemini-2.5-pro fallback. Add per-model retry (up to 2 attempts with backoff) for transient 503/429 errors before switching to next model. Apply to chatbot, moderation, and judgment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> @
fix: Use gemini-2.5-flash only with increased retry count Remove multi-model fallback to avoid gemini-2.5-pro cost overhead. Use gemini-2.5-flash as single model with up to 3 retries on transient 503/429 errors across chatbot, moderation, and judgment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> @
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/ai/judgment.ts`:
- Around line 110-122: The generic Error('JSON') exceptions thrown during JSON
parsing validation (in the jsonMatch check, JSON.parse catch block, and type
validation for title and summary fields) are not being caught by the isRetryable
or shouldFallback logic, causing immediate failure instead of attempting
fallback models. Replace these three Error('JSON') throws with an error type
that will be recognized as retryable by the error handling logic, ensuring that
JSON format issues trigger fallback model attempts rather than immediate
termination.
- Around line 3-5: The retry delay strategy using MAX_RETRIES_PER_MODEL set to 2
with RETRY_DELAY_MS set to 1500 consumes too much of the 10-second timeout
budget (10000ms) allocated in the route handler, leaving insufficient time for
actual API calls. Reduce RETRY_DELAY_MS and/or MAX_RETRIES_PER_MODEL constants
to ensure the total retry wait time across all models in MODEL_FALLBACKS array
stays well below the 10-second timeout limit, preserving adequate time for the
actual API request execution. Aim for a retry strategy that uses no more than
3-4 seconds total across all retry attempts and model fallbacks combined.
In `@src/lib/ai/moderation.ts`:
- Around line 13-14: The moderation retry policy defined by
MAX_RETRIES_PER_MODEL and RETRY_DELAY_MS constants conflicts with the 8-second
timeout in src/app/api/disputes/route.ts. The retry backoff logic in lines
87-124 accumulates to approximately 9 seconds for multiple models, causing the
retry path to exceed the 8-second timeout constraint. Adjust the
MAX_RETRIES_PER_MODEL and RETRY_DELAY_MS constants to ensure the total retry
duration (including all backoff iterations across multiple models) stays well
within the 8-second timeout limit.
- Around line 94-102: The errors thrown at the JSON validation check and JSON
parsing catch block in the Gemini moderation response handling are not being
caught by the shouldFallback or isRetryable conditions, causing immediate
termination instead of triggering the fallback model chain. Instead of throwing
errors directly for invalid JSON and unparseable JSON cases, catch these errors
and handle them in a way that allows the fallback/retry mechanism to work, such
as marking them as retryable errors or wrapping them appropriately so the outer
error handling logic at line 127 can properly detect and route them to the
fallback chain.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: 2def09e8-3959-4418-945a-be2c8797f6df
📒 Files selected for processing (3)
src/lib/ai/chatbot.tssrc/lib/ai/judgment.tssrc/lib/ai/moderation.ts
| const MODEL_FALLBACKS = ['gemini-2.5-flash', 'gemini-2.5-pro'] | ||
| const MAX_RETRIES_PER_MODEL = 2 | ||
| const RETRY_DELAY_MS = 1500 |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
재시도 대기 시간이 라우트 타임아웃 예산을 사실상 소진합니다.
Line 104~Line 141 로직은 모델당 최대 4.5초(1.5s + 3s) 대기를 사용하고, 2개 모델이면 대기만 최대 9초입니다. src/app/api/disputes/route.ts의 withTimeout(extractDisputeMeta(content), 10000)과 결합되면 실제 API 호출 시간을 거의 남기지 못해 폴백 완료 전에 타임아웃으로 실패할 가능성이 큽니다.
제안 수정안
const MAX_RETRIES_PER_MODEL = 2
const RETRY_DELAY_MS = 1500
+const EXTRACT_META_BUDGET_MS = 9500
export async function extractDisputeMeta(statement: string): Promise<DisputeMetaResult> {
+ const deadline = Date.now() + EXTRACT_META_BUDGET_MS
const apiKey = process.env.GEMINI_API_KEY
if (!apiKey) throw new Error('GEMINI_API_KEY is not configured')
@@
if (isRetryable(err) && attempt < MAX_RETRIES_PER_MODEL) {
+ const remaining = deadline - Date.now()
+ if (remaining <= 0) throw err
console.warn(`[extractDisputeMeta] ${modelName} retry ${attempt + 1}/${MAX_RETRIES_PER_MODEL}: ${errMsg}`)
- await sleep(RETRY_DELAY_MS * (attempt + 1))
+ await sleep(Math.min(RETRY_DELAY_MS * (attempt + 1), remaining))
continue
}Also applies to: 104-141
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/ai/judgment.ts` around lines 3 - 5, The retry delay strategy using
MAX_RETRIES_PER_MODEL set to 2 with RETRY_DELAY_MS set to 1500 consumes too much
of the 10-second timeout budget (10000ms) allocated in the route handler,
leaving insufficient time for actual API calls. Reduce RETRY_DELAY_MS and/or
MAX_RETRIES_PER_MODEL constants to ensure the total retry wait time across all
models in MODEL_FALLBACKS array stays well below the 10-second timeout limit,
preserving adequate time for the actual API request execution. Aim for a retry
strategy that uses no more than 3-4 seconds total across all retry attempts and
model fallbacks combined.
| const jsonMatch = text.match(/\{[\s\S]*\}/) | ||
| if (!jsonMatch) throw new Error('JSON') | ||
|
|
||
| let parsed: { title?: unknown; summary?: unknown } | ||
| try { | ||
| parsed = JSON.parse(jsonMatch[0]) | ||
| } catch { | ||
| throw new Error('JSON') | ||
| } | ||
|
|
||
| if (typeof parsed.title !== 'string' || typeof parsed.summary !== 'string') { | ||
| throw new Error('JSON') | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
JSON 포맷 오류에서 즉시 종료되어 다음 폴백 모델을 시도하지 못합니다.
Error('JSON')은 isRetryable/shouldFallback 어느 쪽에도 걸리지 않아 Line 144, Line 288에서 즉시 throw 됩니다. 생성형 응답의 형식 흔들림이 한 번만 나와도 체인이 끊겨, 폴백 모델 도입 효과가 크게 줄어듭니다.
제안 수정안
+function isJsonFormatError(err: unknown): boolean {
+ const msg = err instanceof Error ? err.message : String(err)
+ return msg === 'JSON'
+}
@@
- if (isRetryable(err) && attempt < MAX_RETRIES_PER_MODEL) {
+ if ((isRetryable(err) || isJsonFormatError(err)) && attempt < MAX_RETRIES_PER_MODEL) {
console.warn(`[extractDisputeMeta] ${modelName} retry ${attempt + 1}/${MAX_RETRIES_PER_MODEL}: ${errMsg}`)
await sleep(RETRY_DELAY_MS * (attempt + 1))
continue
}
-
- throw err
+ if (isJsonFormatError(err)) break
+ throw err
@@
- if (isRetryable(err) && attempt < MAX_RETRIES_PER_MODEL) {
+ if ((isRetryable(err) || isJsonFormatError(err)) && attempt < MAX_RETRIES_PER_MODEL) {
console.warn(`[callJudgmentAi] ${modelName} retry ${attempt + 1}/${MAX_RETRIES_PER_MODEL}: ${errMsg}`)
await sleep(RETRY_DELAY_MS * (attempt + 1))
continue
}
-
- throw err
+ if (isJsonFormatError(err)) break
+ throw errAlso applies to: 129-145, 257-270, 273-289
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/ai/judgment.ts` around lines 110 - 122, The generic Error('JSON')
exceptions thrown during JSON parsing validation (in the jsonMatch check,
JSON.parse catch block, and type validation for title and summary fields) are
not being caught by the isRetryable or shouldFallback logic, causing immediate
failure instead of attempting fallback models. Replace these three Error('JSON')
throws with an error type that will be recognized as retryable by the error
handling logic, ensuring that JSON format issues trigger fallback model attempts
rather than immediate termination.
| const MAX_RETRIES_PER_MODEL = 2 | ||
| const RETRY_DELAY_MS = 1500 |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
모더레이션 재시도 정책이 상위 타임아웃(8초)과 충돌합니다.
Line 87~Line 124의 백오프 합은 모델당 4.5초, 2개 모델이면 9초입니다. src/app/api/disputes/route.ts에서 withTimeout(moderateContent(content), 8000)을 사용하므로, 재시도 경로는 타임아웃으로 조기 실패할 확률이 높습니다.
제안 수정안
-const MAX_RETRIES_PER_MODEL = 2
-const RETRY_DELAY_MS = 1500
+const MAX_RETRIES_PER_MODEL = 1
+const RETRY_DELAY_MS = 800Also applies to: 87-124
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/ai/moderation.ts` around lines 13 - 14, The moderation retry policy
defined by MAX_RETRIES_PER_MODEL and RETRY_DELAY_MS constants conflicts with the
8-second timeout in src/app/api/disputes/route.ts. The retry backoff logic in
lines 87-124 accumulates to approximately 9 seconds for multiple models, causing
the retry path to exceed the 8-second timeout constraint. Adjust the
MAX_RETRIES_PER_MODEL and RETRY_DELAY_MS constants to ensure the total retry
duration (including all backoff iterations across multiple models) stays well
within the 8-second timeout limit.
| const jsonMatch = text.match(/\{[\s\S]*\}/) | ||
| if (!jsonMatch) throw new Error('Gemini moderation returned invalid JSON') | ||
|
|
||
| let parsed: { isBlocked?: unknown; reason?: unknown; confidenceScore?: unknown; hasPersonalInfo?: unknown } | ||
| try { | ||
| parsed = JSON.parse(jsonMatch[0]) | ||
| } catch { | ||
| throw new Error('Gemini moderation returned unparseable JSON') | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
JSON 파싱 실패에서 즉시 throw 되어 폴백 모델이 동작하지 않습니다.
Line 95, Line 101에서 던진 JSON 오류는 shouldFallback/isRetryable에 해당하지 않아 Line 127에서 즉시 종료됩니다. 모델 응답 포맷 흔들림에 취약해, 준비한 폴백 체인을 충분히 활용하지 못합니다.
제안 수정안
function shouldFallback(err: unknown): boolean {
@@
}
+function isJsonFormatError(err: unknown): boolean {
+ const msg = err instanceof Error ? err.message : String(err)
+ return (
+ msg.includes('invalid JSON') ||
+ msg.includes('unparseable JSON')
+ )
+}
+
@@
- if (isRetryable(err) && attempt < MAX_RETRIES_PER_MODEL) {
+ if ((isRetryable(err) || isJsonFormatError(err)) && attempt < MAX_RETRIES_PER_MODEL) {
console.warn(`[moderation] ${modelName} retry ${attempt + 1}/${MAX_RETRIES_PER_MODEL}: ${errMsg}`)
await sleep(RETRY_DELAY_MS * (attempt + 1))
continue
}
+ if (isJsonFormatError(err)) break
throw errAlso applies to: 112-128
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/ai/moderation.ts` around lines 94 - 102, The errors thrown at the
JSON validation check and JSON parsing catch block in the Gemini moderation
response handling are not being caught by the shouldFallback or isRetryable
conditions, causing immediate termination instead of triggering the fallback
model chain. Instead of throwing errors directly for invalid JSON and
unparseable JSON cases, catch these errors and handle them in a way that allows
the fallback/retry mechanism to work, such as marking them as retryable errors
or wrapping them appropriately so the outer error handling logic at line 127 can
properly detect and route them to the fallback chain.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (4)
src/lib/ai/moderation.ts (2)
102-112: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winJSON 파싱 실패에서 즉시 throw 되어 재시도가 동작하지 않습니다.
Line 85/91의
'invalid JSON'/'unparseable JSON'오류는isRetryable(503/Service Unavailable/high demand/429)에 해당하지 않아 Line 112에서 곧바로 throw 됩니다. 모델 응답 포맷 흔들림에 취약하므로, 포맷 오류를 재시도 대상에 포함하는 것을 권장합니다.제안 수정안
+function isJsonFormatError(err: unknown): boolean { + const msg = err instanceof Error ? err.message : String(err) + return msg.includes('invalid JSON') || msg.includes('unparseable JSON') +} @@ - if (isRetryable(err) && attempt < MAX_RETRIES) { + if ((isRetryable(err) || isJsonFormatError(err)) && attempt < MAX_RETRIES) { console.warn(`[moderation] ${MODEL_NAME} retry ${attempt + 1}/${MAX_RETRIES}: ${errMsg}`) await sleep(RETRY_DELAY_MS * (attempt + 1)) continue }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/ai/moderation.ts` around lines 102 - 112, JSON parsing errors (invalid JSON/unparseable JSON from lines 85/91) are not being retried because the isRetryable function does not recognize them as retryable conditions, causing them to be immediately thrown at line 112. Modify the isRetryable function to also return true for JSON parsing related errors in addition to the existing retryable conditions (503/Service Unavailable/high demand/429), so that format errors will trigger retries instead of failing immediately.
77-112: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win재시도 지연 합계(9초)가 모더레이션 라우트 타임아웃(8초)을 초과합니다.
MAX_RETRIES = 3+RETRY_DELAY_MS * (attempt + 1)로 재시도 대기만 1.5s + 3s + 4.5s = 9초인데,src/app/api/disputes/route.ts는withTimeout(moderateContent(content), 8000)을 사용합니다. 재시도 경로가 8초 예산을 넘기므로 503/429 발생 시 재시도가 끝나기도 전에 타임아웃으로 실패합니다. 백오프를 줄이거나 데드라인을 반영하세요.#!/bin/bash rg -nP 'RETRY_DELAY_MS|MAX_RETRIES' src/lib/ai/moderation.ts rg -nP 'withTimeout\(\s*moderateContent' src/app/api/disputes/route.ts🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/ai/moderation.ts` around lines 77 - 112, The total retry delay time in the moderation retry loop exceeds the 8-second timeout configured in the disputes route. With MAX_RETRIES set to 3 and RETRY_DELAY_MS multiplied by (attempt + 1) in the sleep call, the cumulative backoff delays (1.5s + 3s + 4.5s = 9s) alone exceed the timeout, leaving no time for actual API calls. Reduce either the MAX_RETRIES constant or the RETRY_DELAY_MS constant (or both) so that the total possible retry duration stays well under 8 seconds, accounting for the exponential backoff formula used in the sleep call.src/lib/ai/judgment.ts (2)
94-133: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win재시도 지연 합계(9초)가 라우트 타임아웃 예산(10초)을 거의 소진합니다.
MAX_RETRIES = 3+RETRY_DELAY_MS * (attempt + 1)조합으로 재시도 대기만 1.5s + 3s + 4.5s = 9초이며, 여기에generateContent4회 호출 시간이 더해집니다.src/app/api/disputes/route.ts의withTimeout(extractDisputeMeta(content), 10000)과 결합되면 실제 호출 시간이 거의 남지 않아 재시도 완료 전에 타임아웃으로 실패할 가능성이 높습니다. 데드라인 인지 백오프(Math.min(delay, remaining))나 더 작은RETRY_DELAY_MS/MAX_RETRIES를 권장합니다.#!/bin/bash rg -nP 'RETRY_DELAY_MS|MAX_RETRIES' src/lib/ai/judgment.ts rg -nP 'withTimeout\(\s*(extractDisputeMeta|callJudgmentAi)' src/app/api/disputes/route.ts🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/ai/judgment.ts` around lines 94 - 133, The exponential backoff delays in the retry loop (RETRY_DELAY_MS multiplied by attempt + 1) accumulate to approximately 9 seconds across 3 retries, leaving almost no time for actual generateContent calls within the 10-second timeout budget of the parent API route. Reduce either the RETRY_DELAY_MS constant or MAX_RETRIES constant (or both) to allow sufficient time for the actual API calls, or implement deadline-aware backoff logic that caps the sleep duration to Math.min(calculatedDelay, remainingTimeUntilTimeout) to ensure retries fail fast when approaching the timeout limit. This applies to the sleep call within the catch block of the retry loop in the extractDisputeMeta function.
119-129: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winJSON 포맷 오류에서 즉시 throw 되어 단일 모델 재시도 이점을 활용하지 못합니다.
Line 101/107/111의
throw new Error('JSON')은isRetryable(503/Service Unavailable/high demand/429)에 해당하지 않아 Line 129에서 즉시 throw 됩니다. 단일 모델 재시도 구조에서는 동일 모델 재호출로 포맷 흔들림이 해소될 수 있으므로, JSON 포맷 오류도 재시도 대상에 포함하는 것이 효과적입니다(callJudgmentAi의 Line 256~266에도 동일 적용).제안 수정안
+function isJsonFormatError(err: unknown): boolean { + const msg = err instanceof Error ? err.message : String(err) + return msg === 'JSON' +} @@ - if (isRetryable(err) && attempt < MAX_RETRIES) { + if ((isRetryable(err) || isJsonFormatError(err)) && attempt < MAX_RETRIES) { console.warn(`[extractDisputeMeta] ${MODEL_NAME} retry ${attempt + 1}/${MAX_RETRIES}: ${errMsg}`) await sleep(RETRY_DELAY_MS * (attempt + 1)) continue }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/ai/judgment.ts` around lines 119 - 129, JSON format errors thrown at lines 101, 107, and 111 are not being retried because they do not match the conditions checked by the isRetryable function, which only handles specific error types like 503 or 429. Modify the isRetryable function or the error handling logic in the catch block to treat JSON format errors as retryable errors so they can be retried within the MAX_RETRIES loop instead of being immediately thrown. Apply the same fix to the callJudgmentAi function around lines 256-266 where similar JSON format error handling exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/ai/chatbot.ts`:
- Around line 106-125: The retry loop uses exponential backoff (RETRY_DELAY_MS *
(attempt + 1)) that, combined with REQUEST_TIMEOUT_MS per request, can
accumulate to over 2 minutes in worst case scenarios, exposing excessive delays
to users. To fix this, implement a maximum cumulative timeout for the entire
retry operation in the retry loop within the chatbot function. Track the total
elapsed time from when the loop starts, and break out of the loop if the
cumulative time exceeds a reasonable maximum (e.g., 60 seconds). Alternatively,
reduce either RETRY_DELAY_MS, MAX_RETRIES, or both to keep total potential delay
within acceptable bounds for user-facing API calls.
---
Duplicate comments:
In `@src/lib/ai/judgment.ts`:
- Around line 94-133: The exponential backoff delays in the retry loop
(RETRY_DELAY_MS multiplied by attempt + 1) accumulate to approximately 9 seconds
across 3 retries, leaving almost no time for actual generateContent calls within
the 10-second timeout budget of the parent API route. Reduce either the
RETRY_DELAY_MS constant or MAX_RETRIES constant (or both) to allow sufficient
time for the actual API calls, or implement deadline-aware backoff logic that
caps the sleep duration to Math.min(calculatedDelay, remainingTimeUntilTimeout)
to ensure retries fail fast when approaching the timeout limit. This applies to
the sleep call within the catch block of the retry loop in the
extractDisputeMeta function.
- Around line 119-129: JSON format errors thrown at lines 101, 107, and 111 are
not being retried because they do not match the conditions checked by the
isRetryable function, which only handles specific error types like 503 or 429.
Modify the isRetryable function or the error handling logic in the catch block
to treat JSON format errors as retryable errors so they can be retried within
the MAX_RETRIES loop instead of being immediately thrown. Apply the same fix to
the callJudgmentAi function around lines 256-266 where similar JSON format error
handling exists.
In `@src/lib/ai/moderation.ts`:
- Around line 102-112: JSON parsing errors (invalid JSON/unparseable JSON from
lines 85/91) are not being retried because the isRetryable function does not
recognize them as retryable conditions, causing them to be immediately thrown at
line 112. Modify the isRetryable function to also return true for JSON parsing
related errors in addition to the existing retryable conditions (503/Service
Unavailable/high demand/429), so that format errors will trigger retries instead
of failing immediately.
- Around line 77-112: The total retry delay time in the moderation retry loop
exceeds the 8-second timeout configured in the disputes route. With MAX_RETRIES
set to 3 and RETRY_DELAY_MS multiplied by (attempt + 1) in the sleep call, the
cumulative backoff delays (1.5s + 3s + 4.5s = 9s) alone exceed the timeout,
leaving no time for actual API calls. Reduce either the MAX_RETRIES constant or
the RETRY_DELAY_MS constant (or both) so that the total possible retry duration
stays well under 8 seconds, accounting for the exponential backoff formula used
in the sleep call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: 1a8c45a6-894b-4816-a373-95e0f7a778a9
📒 Files selected for processing (3)
src/lib/ai/chatbot.tssrc/lib/ai/judgment.tssrc/lib/ai/moderation.ts
| for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) { | ||
| try { | ||
| const model = genAI.getGenerativeModel({ model: modelName }) | ||
| const model = genAI.getGenerativeModel({ model: MODEL_NAME }) | ||
| const chat = model.startChat({ history: chatHistory }) | ||
| const result = await withTimeout(chat.sendMessage(userMessage), REQUEST_TIMEOUT_MS) | ||
| return result.response.text() | ||
| } catch (error) { | ||
| lastError = error | ||
| const errMsg = error instanceof Error ? error.message : String(error) | ||
|
|
||
| if (error instanceof ChatbotTimeoutError) throw error | ||
|
|
||
| if (isFallbackable(error)) { | ||
| console.warn(`[chatbot] ${modelName} unavailable, trying next model...`) | ||
| if (isRetryable(error) && attempt < MAX_RETRIES) { | ||
| console.warn(`[chatbot] ${MODEL_NAME} retry ${attempt + 1}/${MAX_RETRIES}: ${errMsg}`) | ||
| await sleep(RETRY_DELAY_MS * (attempt + 1)) | ||
| continue | ||
| } | ||
|
|
||
| console.warn(`[chatbot] ${MODEL_NAME} failed: ${errMsg}`) | ||
| break |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm RETRY_DELAY_MS / REQUEST_TIMEOUT_MS in chatbot and any route-level timeout
rg -nP 'RETRY_DELAY_MS|REQUEST_TIMEOUT_MS|MAX_RETRIES' src/lib/ai/chatbot.ts
rg -nP 'withTimeout|getChatbotResponse' src/app/api/chatbot/route.tsRepository: I5-Project/TALKY-OWL
Length of output: 790
🏁 Script executed:
cat -n src/app/api/chatbot/route.ts | head -80Repository: I5-Project/TALKY-OWL
Length of output: 3098
🏁 Script executed:
ast-grep outline src/lib/ai/chatbot.ts --view expandedRepository: I5-Project/TALKY-OWL
Length of output: 811
🏁 Script executed:
rg -nP 'category|writing|카테고리|글쓰기' src/lib/ai/chatbot.ts -A 2Repository: I5-Project/TALKY-OWL
Length of output: 234
🏁 Script executed:
sed -n '8,44p' src/lib/ai/chatbot.tsRepository: I5-Project/TALKY-OWL
Length of output: 1011
🏁 Script executed:
rg -nP 'SYSTEM_PROMPT' src/lib/ai/chatbot.ts -A 35Repository: I5-Project/TALKY-OWL
Length of output: 2479
재시도 누적 지연으로 응답 시간이 과도해질 수 있습니다.
현재 설정에서 RETRY_DELAY_MS = 1500, MAX_RETRIES = 3, REQUEST_TIMEOUT_MS = 30000일 때, 재시도 대기만 1.5s + 3s + 4.5s = 9초이고, 여기에 최대 4회의 sendMessage 시도(각 최대 30초)가 더해져 최악의 경우 약 2분까지 누적됩니다. src/app/api/chatbot/route.ts에는 getChatbotResponse 호출을 감싸는 외부 타임아웃이 없으므로, 이 전체 지연이 사용자에게 노출됩니다. 최대 대기 시간을 제한하거나 더 짧은 백오프 전략을 검토하세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/lib/ai/chatbot.ts` around lines 106 - 125, The retry loop uses
exponential backoff (RETRY_DELAY_MS * (attempt + 1)) that, combined with
REQUEST_TIMEOUT_MS per request, can accumulate to over 2 minutes in worst case
scenarios, exposing excessive delays to users. To fix this, implement a maximum
cumulative timeout for the entire retry operation in the retry loop within the
chatbot function. Track the total elapsed time from when the loop starts, and
break out of the loop if the cumulative time exceeds a reasonable maximum (e.g.,
60 seconds). Alternatively, reduce either RETRY_DELAY_MS, MAX_RETRIES, or both
to keep total potential delay within acceptable bounds for user-facing API
calls.
Summary
gemini-2.0-flash-lite,gemini-2.0-flash,gemini-1.5-flash)gemini-2.5-flash단일 모델 사용 + 503/429 시 최대 3회 재시도 (1.5초 → 3초 → 4.5초 백오프)Test plan
🤖 Generated with Claude Code
Summary by CodeRabbit
릴리스 노트