feat: remove tool chips above input, add Auto model option
- Remove selected-tool chip/tag area above the input textarea; tool selection state is now shown only via button highlight in the tools panel - Add "Auto" as a third model option between Flash and Pro (default) - Auto maps to "flash" when sent to the backend (which only accepts flash|pro) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
8c7fe84a3d
commit
a1ae32713d
@@ -72,13 +72,16 @@ export function GeminiChat() {
|
||||
const [extensions, setExtensions] = useState<Extension[]>(INITIAL_EXTENSIONS);
|
||||
const [ticketSummary, setTicketSummary] = useState<TicketSummaryData | null>(null);
|
||||
const [activeTools, setActiveTools] = useState<Set<string>>(new Set());
|
||||
const [selectedModel, setSelectedModel] = useState<"flash" | "pro">("pro");
|
||||
const [selectedModel, setSelectedModel] = useState<"flash" | "auto" | "pro">("auto");
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||
const abortRef = useRef<AbortController | null>(null);
|
||||
|
||||
const activeConversation = conversations.find((c) => c.id === activeConvId) ?? null;
|
||||
const messages = activeConversation?.messages ?? [];
|
||||
|
||||
// Map UI model to backend model ("auto" -> "flash")
|
||||
const apiModel: "flash" | "pro" = selectedModel === "pro" ? "pro" : "flash";
|
||||
|
||||
// 检查工单系统是否已连接
|
||||
const ticketSystemConnected = extensions.find((e) => e.id === "ticket")?.connected ?? false;
|
||||
|
||||
@@ -200,7 +203,7 @@ export function GeminiChat() {
|
||||
text,
|
||||
streamConvId,
|
||||
Array.from(activeTools),
|
||||
selectedModel,
|
||||
apiModel,
|
||||
(event) => {
|
||||
if (event.type === "token" && event.content) {
|
||||
setConversations((prev) =>
|
||||
@@ -244,7 +247,7 @@ export function GeminiChat() {
|
||||
setIsLoading(false);
|
||||
}
|
||||
);
|
||||
}, [inputValue, isLoading, activeConvId, activeTools, selectedModel]);
|
||||
}, [inputValue, isLoading, activeConvId, activeTools, apiModel]);
|
||||
|
||||
const handleRegenerate = useCallback(
|
||||
async (msgId: string) => {
|
||||
@@ -283,7 +286,7 @@ export function GeminiChat() {
|
||||
userMsg.content,
|
||||
regenConvId,
|
||||
Array.from(activeTools),
|
||||
selectedModel,
|
||||
apiModel,
|
||||
(event) => {
|
||||
if (event.type === "token" && event.content) {
|
||||
setConversations((prev) =>
|
||||
@@ -309,7 +312,7 @@ export function GeminiChat() {
|
||||
}
|
||||
);
|
||||
},
|
||||
[activeConvId, conversations, isLoading, activeTools, selectedModel]
|
||||
[activeConvId, conversations, isLoading, activeTools, apiModel]
|
||||
);
|
||||
|
||||
const handleSuggestionClick = useCallback((text: string) => {
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
Database,
|
||||
FileText,
|
||||
Code2,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -27,8 +26,8 @@ interface GeminiInputProps {
|
||||
isLoading?: boolean;
|
||||
activeTools: Set<string>;
|
||||
onActiveToolsChange: (tools: Set<string>) => void;
|
||||
selectedModel: "flash" | "pro";
|
||||
onSelectedModelChange: (model: "flash" | "pro") => void;
|
||||
selectedModel: "flash" | "auto" | "pro";
|
||||
onSelectedModelChange: (model: "flash" | "auto" | "pro") => void;
|
||||
}
|
||||
|
||||
const TOOLS: Tool[] = [
|
||||
@@ -77,12 +76,6 @@ export function GeminiInput({
|
||||
onActiveToolsChange(next);
|
||||
};
|
||||
|
||||
const removeTool = (id: string) => {
|
||||
const next = new Set(activeTools);
|
||||
next.delete(id);
|
||||
onActiveToolsChange(next);
|
||||
};
|
||||
|
||||
const canSend = value.trim().length > 0 && !isLoading;
|
||||
|
||||
const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -98,33 +91,6 @@ export function GeminiInput({
|
||||
<div className="max-w-3xl mx-auto px-4 pointer-events-auto">
|
||||
{/* Input container */}
|
||||
<div className="bg-[var(--gem-surface)] border border-[var(--gem-border)] rounded-3xl shadow-lg focus-within:border-[var(--gem-border-hover)] transition-colors duration-150">
|
||||
{/* Selected tools chips (auto show when has active tools) */}
|
||||
{activeTools.size > 0 && (
|
||||
<div className="flex items-center gap-2 px-4 pt-3 pb-1 flex-wrap">
|
||||
{Array.from(activeTools).map((toolId) => {
|
||||
const tool = TOOLS.find((t) => t.id === toolId);
|
||||
if (!tool) return null;
|
||||
const Icon = tool.icon;
|
||||
return (
|
||||
<span
|
||||
key={tool.id}
|
||||
className="flex items-center gap-2 px-2.5 py-1.5 rounded-lg text-xs font-medium bg-[var(--gem-blue)] text-white border border-[var(--gem-blue)]"
|
||||
>
|
||||
<Icon size={14} />
|
||||
<span>{tool.label}</span>
|
||||
<button
|
||||
onClick={() => removeTool(tool.id)}
|
||||
className="ml-1 hover:opacity-80 transition-opacity cursor-pointer"
|
||||
aria-label={`移除${tool.label}`}
|
||||
>
|
||||
<X size={12} />
|
||||
</button>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Main input row */}
|
||||
<div className="flex items-end gap-2 px-4 py-3">
|
||||
{/* Left: File upload button */}
|
||||
@@ -218,6 +184,18 @@ export function GeminiInput({
|
||||
>
|
||||
Flash
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onSelectedModelChange("auto")}
|
||||
className={cn(
|
||||
"px-3 py-1.5 rounded-full text-xs font-medium transition-all duration-150 cursor-pointer",
|
||||
selectedModel === "auto"
|
||||
? "bg-[var(--gem-blue)] text-white"
|
||||
: "bg-[var(--gem-surface-2)] text-[var(--gem-text-muted)] hover:bg-[var(--gem-surface-3)] hover:text-[var(--gem-text)]"
|
||||
)}
|
||||
aria-pressed={selectedModel === "auto"}
|
||||
>
|
||||
Auto
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onSelectedModelChange("pro")}
|
||||
className={cn(
|
||||
|
||||
Reference in New Issue
Block a user