From 456dfaa9f2a518463473213821034fb7df2e3813 Mon Sep 17 00:00:00 2001 From: hyungi Date: Tue, 16 Jun 2026 13:38:46 +0900 Subject: [PATCH] =?UTF-8?q?fix(ai):=20=5Fcall=5Fchat=20=EB=AC=B4=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20Claude=20egress=20=EC=9E=90=EB=8F=99=ED=8F=B4?= =?UTF-8?q?=EB=B0=B1=20=EC=A0=9C=EA=B1=B0=20(R6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit primary(맥미니) Timeout/ConnectError 시 동의·과금 통제 없이 ai.fallback(Claude API)으로 자동 전환 → 개인 문서/쿼리/메모가 Anthropic 으로 silent egress 되던 프라이버시 결함 봉쇄. 실패는 전파 — 배치 워커는 재시도/StageDeferred(R3), interactive 는 호출자 5xx 표면화 (documents.analyze 이미 502/504). 클라우드는 premium explicit-trigger / call_fallback 명시 호출로만 (자동 진입 금지). 참고: uncoordinated-mlx-semaphores 는 gitea/main 최신에서 digest/briefing 이 이미 acquire_mlx_gate 사용(감사 20커밋 stale 탓 오탐) — 변경 불요. rerank silent-identity 의 rerank_skipped notes 플래그는 시그니처 변경 동반이라 별도 후속(Low). 검증: py_compile 통과. Co-Authored-By: Claude Opus 4.8 (1M context) --- app/ai/client.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/ai/client.py b/app/ai/client.py index 6ff06b5..887c7ff 100644 --- a/app/ai/client.py +++ b/app/ai/client.py @@ -289,13 +289,16 @@ class AIClient: return response.json() async def _call_chat(self, model_config, prompt: str) -> str: - """OpenAI 호환 API 호출 + 자동 폴백""" - try: - return await self._request(model_config, prompt) - except (httpx.TimeoutException, httpx.ConnectError): - if model_config == self.ai.primary: - return await self._request(self.ai.fallback, prompt) - raise + """OpenAI 호환 API 호출 (R6: 무동의 클라우드 폴백 제거). + + 이전엔 primary(맥미니) TimeoutException/ConnectError 시 동의·과금 통제 없이 + self.ai.fallback(Claude API)로 자동 전환 → 개인 문서/쿼리/메모가 Anthropic 으로 + silent egress. on-prem 추론 프라이버시 계약 위반이라 봉쇄한다. 실패는 그대로 전파: + 배치 워커는 재시도/StageDeferred(R3·queue_consumer), interactive 호출자는 5xx 표면화 + (documents.analyze 등 이미 502/504 변환). 클라우드는 premium explicit-trigger + (summarize force_premium) 또는 call_fallback 명시 호출로만 — 자동 진입 금지. + """ + return await self._request(model_config, prompt) async def _request(self, model_config, prompt: str, system: str | None = None) -> str: """단일 모델 API 호출 (OpenAI 호환 + Anthropic Messages API).