Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions src/components/tunaflow/MetaAgentSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useRef, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { invoke } from "@tauri-apps/api/core";
import { CheckCircle2, Loader2, AlertTriangle, ChevronDown, ExternalLink } from "lucide-react";
import { CheckCircle2, Loader2, AlertTriangle, ChevronDown, ExternalLink, RefreshCw } from "lucide-react";
import { useTranslation } from "react-i18next";
import { cn } from "@/lib/utils";
import { useChatStore } from "@/stores/chatStore";
Expand Down Expand Up @@ -65,7 +65,6 @@ export function MetaAgentSelector({ onProceed, onSkip, projectName }: Props) {
const [modelByEngine, setModelByEngine] = useState<Record<string, string>>({});

const [skipConfirm, setSkipConfirm] = useState(false);
const debounceRef = useRef<number | null>(null);

// Dynamic model discovery — shared with Settings AgentsSection.
// `engineModels` is populated by `list_engine_models` (Rust) and refreshed
Expand Down Expand Up @@ -132,16 +131,12 @@ export function MetaAgentSelector({ onProceed, onSkip, projectName }: Props) {
});
}, [detections, engineModels]);

// 외부 사용자 보고 (e.g. LM Studio endpoint 에 `192.168.1.1` 입력 중 `.` 칠
// 때마다 자동 detect 가 발동) — onChange 는 local state 만 갱신하고, 실제
// detect 는 Enter 키 또는 옆 새로고침 버튼 같은 명시 액션으로만 트리거한다.
const onEndpointChange = (engine: "ollama" | "lmstudio", value: string) => {
if (engine === "ollama") setOllamaEndpoint(value);
else setLmstudioEndpoint(value);

if (debounceRef.current) window.clearTimeout(debounceRef.current);
debounceRef.current = window.setTimeout(() => {
const o = engine === "ollama" ? value : ollamaEndpoint;
const l = engine === "lmstudio" ? value : lmstudioEndpoint;
runDetect(o, l);
}, 600);
};

const canProceed = useMemo(() => {
Expand Down Expand Up @@ -247,16 +242,34 @@ export function MetaAgentSelector({ onProceed, onSkip, projectName }: Props) {
<div className="text-[10px] text-muted-foreground/70 font-mono truncate">{d.path}</div>
)}

{/* HTTP endpoint editor */}
{/* HTTP endpoint editor — Enter 키 또는 새로고침 버튼으로만
detect 트리거. onChange 는 local state 갱신만 한다. */}
{d.kind === "http" && (
<div className="flex items-center gap-2">
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

HTTP 엔드포인트 입력 필드와 새로고침 버튼이 <label> 태그 내부에 중첩되어 있습니다. HTML 표준상 <label> 내부에 라디오 버튼 외의 다른 대화형 요소(Interactive elements)가 존재하면, 해당 요소를 클릭했을 때 이벤트가 버블링되어 라디오 버튼이 원치 않게 선택되는 부작용이 발생합니다.\n\n예를 들어, 현재 다른 에이전트(예: Claude)가 선택된 상태에서 Ollama 엔드포인트의 새로고침 버튼을 클릭하면, Ollama 에이전트가 자동으로 선택되어 버립니다.\n\n이를 방지하기 위해 엔드포인트 에디터 컨테이너(div)에 onClick={(e) => e.stopPropagation()}을 추가하여 클릭 이벤트가 <label>로 전파되는 것을 차단하는 것이 좋습니다.

Suggested change
<div className="flex items-center gap-2">
<div className="flex items-center gap-2" onClick={(e) => e.stopPropagation()}>

<span className="text-[10px] text-muted-foreground/60 shrink-0">Endpoint</span>
<input
type="text"
value={d.engine === "ollama" ? ollamaEndpoint : lmstudioEndpoint}
onChange={(e) => onEndpointChange(d.engine as "ollama" | "lmstudio", e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
runDetect(ollamaEndpoint, lmstudioEndpoint);
}
}}
className="flex-1 text-[10px] font-mono bg-background border border-border/60 rounded px-2 py-1 focus:outline-none focus:border-primary/60"
data-testid={`meta-agent-endpoint-${d.engine}`}
/>
<button
type="button"
onClick={() => runDetect(ollamaEndpoint, lmstudioEndpoint)}
title={t("meta_agent.endpoint_refresh")}
aria-label={t("meta_agent.endpoint_refresh")}
className="shrink-0 p-1 rounded border border-border/60 text-muted-foreground hover:text-foreground hover:border-primary/60 focus:outline-none focus:border-primary/60 transition-colors"
data-testid={`meta-agent-endpoint-refresh-${d.engine}`}
>
<RefreshCw className="w-3 h-3" />
</button>
</div>
)}

Expand Down
3 changes: 2 additions & 1 deletion src/locales/en/dialog.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@
"ollama_install_hint": "Install from https://ollama.com/download then run `ollama serve`",
"lmstudio_install_hint": "Install from https://lmstudio.ai then start the Local Server",
"model_loading": "Loading models...",
"model_empty": "No models — install or refresh via Settings → Runtime"
"model_empty": "No models — install or refresh via Settings → Runtime",
"endpoint_refresh": "Re-detect endpoint (Enter or click)"
},
"meta_chat": {
"new_notification_title": "New notification",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/ko/dialog.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@
"ollama_install_hint": "https://ollama.com/download 에서 설치 후 `ollama serve`",
"lmstudio_install_hint": "https://lmstudio.ai 에서 설치 후 Local Server 시작",
"model_loading": "모델 목록 로딩 중...",
"model_empty": "모델 없음 — 설치 또는 Settings → Runtime 에서 새로고침"
"model_empty": "모델 없음 — 설치 또는 Settings → Runtime 에서 새로고침",
"endpoint_refresh": "엔드포인트 다시 감지 (Enter 또는 클릭)"
},
"meta_chat": {
"new_notification_title": "새 알림",
Expand Down