mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-22 12:42:22 +02:00
[eric] composer: web-search toggle (globe) forces WebSearch/WebFetch while on, like a search mode
This commit is contained in:
@@ -113,6 +113,10 @@ const ChatInput = forwardRef<ChatInputHandle, Props>(({ onSend, disabled, mode,
|
||||
}, [prefillPrompt]);
|
||||
|
||||
const [hasContent, setHasContent] = useState(() => !!loadDraft(ownerId));
|
||||
// Web-search mode: a conversation-level toggle (like Open WebUI's search switch). While on, every
|
||||
// send forces the WebSearch/WebFetch tools so the model actually searches instead of answering
|
||||
// from memory. Merged into forcedTools at send time so it doesn't clutter the attachment chips.
|
||||
const [webSearchOn, setWebSearchOn] = useState(false);
|
||||
const [attachedSkills, setAttachedSkills] = useState<Record<string, AttachedSkill>>({});
|
||||
const [previewPasteId, setPreviewPasteId] = useState<string | null>(null);
|
||||
const attachedSkillsRef = useRef(attachedSkills);
|
||||
@@ -253,6 +257,11 @@ const ChatInput = forwardRef<ChatInputHandle, Props>(({ onSend, disabled, mode,
|
||||
|
||||
const sendImages = allImages.length > 0 ? allImages : undefined;
|
||||
const allForcedToolNames = forcedTools.flatMap((ft) => ft.tools);
|
||||
if (webSearchOn) {
|
||||
for (const t of ['WebSearch', 'WebFetch']) {
|
||||
if (!allForcedToolNames.includes(t)) allForcedToolNames.push(t);
|
||||
}
|
||||
}
|
||||
const currentSkills = Object.values(attachedSkillsRef.current);
|
||||
const sendSkills = currentSkills.length > 0
|
||||
? currentSkills.map((s) => ({ id: s.id, name: s.name, content: s.content }))
|
||||
@@ -290,7 +299,7 @@ const ChatInput = forwardRef<ChatInputHandle, Props>(({ onSend, disabled, mode,
|
||||
setAttachedSkills({});
|
||||
setHasContent(false);
|
||||
elementSelection?.clearOwnerElements(ownerId);
|
||||
}, [disabled, images, contextPaths, forcedTools, onSend, elementSelection, ownerId, summarizingPath, summarizingAll, oversizeQueue, pendingSendRef, sessionId, currentModelCtx, contextEstimate, sessionFrameworkOverhead, setSendBlock, onActivityLabelChange]);
|
||||
}, [disabled, images, contextPaths, forcedTools, webSearchOn, onSend, elementSelection, ownerId, summarizingPath, summarizingAll, oversizeQueue, pendingSendRef, sessionId, currentModelCtx, contextEstimate, sessionFrameworkOverhead, setSendBlock, onActivityLabelChange]);
|
||||
|
||||
const {
|
||||
picker: editorPicker, setPicker,
|
||||
@@ -358,6 +367,8 @@ const ChatInput = forwardRef<ChatInputHandle, Props>(({ onSend, disabled, mode,
|
||||
isRunning={isRunning}
|
||||
queueLength={queueLength}
|
||||
modeConf={modeConf}
|
||||
webSearchOn={webSearchOn}
|
||||
onToggleWebSearch={() => setWebSearchOn((v) => !v)}
|
||||
placeholderOverride={placeholderOverride}
|
||||
ghostSuggestion={ghostSuggestion}
|
||||
runContext={runContext}
|
||||
|
||||
@@ -50,6 +50,8 @@ interface Props {
|
||||
isRunning?: boolean;
|
||||
onStop?: () => void;
|
||||
handleSend: () => void;
|
||||
webSearchOn?: boolean;
|
||||
onToggleWebSearch?: () => void;
|
||||
}
|
||||
|
||||
export const ChatInputToolbar: React.FC<Props> = (p) => {
|
||||
@@ -58,7 +60,7 @@ export const ChatInputToolbar: React.FC<Props> = (p) => {
|
||||
allModelFlat, model, onModelChange, onProviderChange, picker, pendingKinds, pendingPayloadEstimate,
|
||||
thinkingLevel, onThinkingLevelChange, contextEstimate, elementSelection, autoRunMode,
|
||||
ownerId, sessionId, generalFileInputRef, addImageFiles, uploadAndAttachFiles,
|
||||
hasContent, disabled, isRunning, onStop, handleSend,
|
||||
hasContent, disabled, isRunning, onStop, handleSend, webSearchOn, onToggleWebSearch,
|
||||
} = p;
|
||||
|
||||
const menuPaperProps = {
|
||||
@@ -172,6 +174,8 @@ export const ChatInputToolbar: React.FC<Props> = (p) => {
|
||||
isRunning={isRunning}
|
||||
onStop={onStop}
|
||||
handleSend={handleSend}
|
||||
webSearchOn={webSearchOn}
|
||||
onToggleWebSearch={onToggleWebSearch}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
|
||||
import StopIcon from '@mui/icons-material/Stop';
|
||||
import AttachFileIcon from '@mui/icons-material/AttachFile';
|
||||
import AdsClickIcon from '@mui/icons-material/AdsClick';
|
||||
import LanguageIcon from '@mui/icons-material/Language';
|
||||
import { useElementSelection } from '@/app/components/editor/ElementSelectionContext';
|
||||
import { ClaudeTokens } from '@/shared/styles/claudeTokens';
|
||||
|
||||
@@ -24,14 +25,44 @@ interface Props {
|
||||
isRunning?: boolean;
|
||||
onStop?: () => void;
|
||||
handleSend: () => void;
|
||||
webSearchOn?: boolean;
|
||||
onToggleWebSearch?: () => void;
|
||||
}
|
||||
|
||||
export const ToolbarActions: React.FC<Props> = ({
|
||||
c, elementSelection, autoRunMode, ownerId, sessionId, generalFileInputRef,
|
||||
addImageFiles, uploadAndAttachFiles, hasContent, disabled, isRunning, onStop, handleSend,
|
||||
webSearchOn, onToggleWebSearch,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{onToggleWebSearch && !autoRunMode && (
|
||||
<Tooltip title={webSearchOn ? 'Web search on: replies search the web' : 'Search the web'}>
|
||||
<IconButton
|
||||
size="small"
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
onClick={onToggleWebSearch}
|
||||
sx={{
|
||||
p: 0.5,
|
||||
...(webSearchOn
|
||||
? {
|
||||
bgcolor: '#3b82f6',
|
||||
color: '#fff',
|
||||
'&:hover': { bgcolor: '#2563eb' },
|
||||
boxShadow: '0 0 0 3px rgba(59,130,246,0.18)',
|
||||
}
|
||||
: {
|
||||
color: c.text.tertiary,
|
||||
'&:hover': { color: c.text.secondary, bgcolor: 'rgba(0,0,0,0.04)' },
|
||||
}),
|
||||
transition: 'background-color 0.15s, color 0.15s',
|
||||
}}
|
||||
>
|
||||
<LanguageIcon sx={{ fontSize: 18 }} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{elementSelection && !autoRunMode && (() => {
|
||||
const isMySelectMode = elementSelection.selectMode && elementSelection.activeOwnerId === ownerId;
|
||||
return (
|
||||
|
||||
@@ -60,6 +60,8 @@ interface Props {
|
||||
isRunning?: boolean;
|
||||
queueLength: number;
|
||||
modeConf: ModeConf;
|
||||
webSearchOn?: boolean;
|
||||
onToggleWebSearch?: () => void;
|
||||
placeholderOverride?: string;
|
||||
ghostSuggestion?: string;
|
||||
runContext?: WorkflowsRunContext;
|
||||
@@ -281,6 +283,8 @@ export const ChatInputView: React.FC<Props> = (p) => {
|
||||
isRunning={p.isRunning}
|
||||
onStop={p.onStop}
|
||||
handleSend={p.handleSend}
|
||||
webSearchOn={p.webSearchOn}
|
||||
onToggleWebSearch={p.onToggleWebSearch}
|
||||
/>
|
||||
|
||||
<ChatInputOverlays
|
||||
|
||||
Reference in New Issue
Block a user