diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts
index 887f41c..707698c 100644
--- a/frontend/src/lib/api.ts
+++ b/frontend/src/lib/api.ts
@@ -84,20 +84,31 @@ export type ApiError = {
detail: string;
errorCode?: string;
errorMessage?: string;
+ /**
+ * PR-DocSrv-Web-Ask-Selector-1: backend_unavailable 503 path 가
+ * body level 에 `error_reason` (예: `macbook_unavailable`) 을 둠. 본 필드는
+ * 그 raw 값. 다른 endpoint 응답에 `error_reason` 이 없으면 undefined.
+ */
+ errorReason?: string;
};
function parseDetail(body: unknown, fallback: string): {
detail: string;
errorCode?: string;
errorMessage?: string;
+ errorReason?: string;
} {
- if (body && typeof body === 'object' && 'detail' in body) {
- const d = (body as { detail: unknown }).detail;
- if (typeof d === 'string' && d) return { detail: d };
- if (d && typeof d === 'object') {
- const obj = d as { error_code?: string; message?: string };
- const message = obj.message || fallback;
- return { detail: message, errorCode: obj.error_code, errorMessage: obj.message };
+ if (body && typeof body === 'object') {
+ const top = body as { detail?: unknown; error_reason?: unknown };
+ const errorReason = typeof top.error_reason === 'string' ? top.error_reason : undefined;
+ if ('detail' in body) {
+ const d = top.detail;
+ if (typeof d === 'string' && d) return { detail: d, errorReason };
+ if (d && typeof d === 'object') {
+ const obj = d as { error_code?: string; message?: string };
+ const message = obj.message || fallback;
+ return { detail: message, errorCode: obj.error_code, errorMessage: obj.message, errorReason };
+ }
}
}
return { detail: fallback };
diff --git a/frontend/src/lib/components/ask/AskAnswer.svelte b/frontend/src/lib/components/ask/AskAnswer.svelte
index e94eed6..d125a63 100644
--- a/frontend/src/lib/components/ask/AskAnswer.svelte
+++ b/frontend/src/lib/components/ask/AskAnswer.svelte
@@ -60,8 +60,20 @@
no_evidence: '근거 없음',
parse_failed: '형식 오류',
llm_error: 'AI 오류',
+ backend_unavailable: 'Backend 비가용',
};
+ /**
+ * backend chip label — `backend_requested` 가 명시 opt-in 인 경우만 표시.
+ * 미지정 (null/undefined) default 호출은 chip 없음 (시각 noise 회피).
+ */
+ function backendChipLabel(backend: string | null | undefined): string | null {
+ if (!backend) return null;
+ if (backend === 'qwen-macbook') return 'Qwen 27B (MacBook)';
+ if (backend === 'gemma-macmini') return 'Gemma 26B (Mac mini)';
+ return backend;
+ }
+
let tokens = $derived(data?.ai_answer ? splitAnswer(data.ai_answer) : []);
let showFullAnswer = $derived(
!!data && !!data.ai_answer && data.completeness === 'full'
@@ -88,6 +100,13 @@