mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
[eric] ui: dead Create Custom connector entry removed, browser AI badge removed, and choice widgets show their question title and description
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import InputBase from '@mui/material/InputBase';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import ArrowUpwardRoundedIcon from '@mui/icons-material/ArrowUpwardRounded';
|
||||
@@ -116,8 +117,28 @@ function AskUiBubble({ pair, sessionId, isPending, suppressReveal }: AskUiBubble
|
||||
);
|
||||
}
|
||||
|
||||
// The vendored choice contracts carry no question field, so agents' title/description props silently vanish and the user sees options with no question; render them as a host header instead (ENG-227).
|
||||
const rawProps = (payload.props ?? {}) as Record<string, unknown>;
|
||||
const questionTitle: string = [rawProps.title, rawProps.question, rawProps.prompt, rawProps.heading]
|
||||
.find((v): v is string => typeof v === 'string' && v.trim().length > 0) ?? '';
|
||||
const questionDesc: string = typeof rawProps.description === 'string' && rawProps.description !== questionTitle
|
||||
? rawProps.description : '';
|
||||
return (
|
||||
<Box sx={{ my: 1, contain: 'layout style' }} data-select-type="tool-ui-ask" data-select-id={pair.id} data-select-meta={JSON.stringify({ component: payload.name })}>
|
||||
{(questionTitle || questionDesc) && (
|
||||
<Box sx={{ mb: 0.75, px: 0.5 }}>
|
||||
{questionTitle && (
|
||||
<Typography sx={{ fontSize: '0.9375rem', fontWeight: 600, color: 'text.primary', lineHeight: 1.35 }}>
|
||||
{questionTitle}
|
||||
</Typography>
|
||||
)}
|
||||
{questionDesc && (
|
||||
<Typography sx={{ fontSize: '0.8125rem', color: 'text.secondary', mt: 0.25, lineHeight: 1.4 }}>
|
||||
{questionDesc}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
<VendoredToolUi name={payload.name} props={payload.props} extraProps={extraProps} />
|
||||
{waiting && FREE_TEXT_COMPONENTS.has(payload.name) && (
|
||||
<Box
|
||||
|
||||
@@ -12,7 +12,24 @@ function ShowUiWidgetView({ payload, ambient }: { payload: ShowUiPayload; ambien
|
||||
if (payload.component === 'plan') return <PlanWidget props={payload.props} />;
|
||||
if (payload.component === 'stats') return <StatsWidget props={payload.props} />;
|
||||
if (payload.component === 'links') return <LinksWidget props={payload.props} />;
|
||||
if (payload.component === 'vendored') return <VendoredToolUi name={payload.name} props={payload.props} quietFail={ambient} />;
|
||||
if (payload.component === 'vendored') {
|
||||
// The vendored contracts carry no question/title field, so agent-supplied ones silently vanish and a choice widget renders with no visible question; surface them as a host header (ENG-227).
|
||||
const raw = (payload.props ?? {}) as Record<string, unknown>;
|
||||
const title = [raw.title, raw.question, raw.prompt, raw.heading]
|
||||
.find((v): v is string => typeof v === 'string' && v.trim().length > 0) ?? '';
|
||||
const desc = typeof raw.description === 'string' && raw.description !== title ? raw.description : '';
|
||||
const widget = <VendoredToolUi name={payload.name} props={payload.props} quietFail={ambient} />;
|
||||
if (!title && !desc) return widget;
|
||||
return (
|
||||
<div>
|
||||
<div style={{ marginBottom: 6, paddingLeft: 4, paddingRight: 4 }}>
|
||||
{title && <div style={{ fontSize: '0.9375rem', fontWeight: 600, lineHeight: 1.35 }}>{title}</div>}
|
||||
{desc && <div style={{ fontSize: '0.8125rem', opacity: 0.72, marginTop: 2, lineHeight: 1.4 }}>{desc}</div>}
|
||||
</div>
|
||||
{widget}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1466,42 +1466,6 @@ const BrowserCard: React.FC<Props> = ({
|
||||
|
||||
{/* Right side controls */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.25, px: 0.5, flexShrink: 0 }}>
|
||||
{/* Agent activity badge */}
|
||||
{agentActive && (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: 0.5,
|
||||
px: 0.75,
|
||||
py: 0.25,
|
||||
borderRadius: '6px',
|
||||
bgcolor: `${accentColor}18`,
|
||||
animation: 'badge-fade-in 0.25s ease-out',
|
||||
'@keyframes badge-fade-in': {
|
||||
'0%': { opacity: 0, transform: 'scale(0.85)' },
|
||||
'100%': { opacity: 1, transform: 'scale(1)' },
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: '50%',
|
||||
bgcolor: accentColor,
|
||||
animation: 'badge-dot-pulse 1.4s ease-in-out infinite',
|
||||
'@keyframes badge-dot-pulse': {
|
||||
'0%, 100%': { opacity: 0.5, transform: 'scale(0.8)' },
|
||||
'50%': { opacity: 1, transform: 'scale(1.3)' },
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Typography sx={{ fontSize: '0.625rem', fontWeight: 600, color: accentColor, lineHeight: 1 }}>
|
||||
AI
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -137,7 +137,6 @@ const Tools: React.FC<ToolsProps> = ({ onBrowseConnectors, expandToolId }) => {
|
||||
<ToolsAddMenu
|
||||
devMode={!!devMode}
|
||||
onBrowseConnectors={onBrowseConnectors}
|
||||
onOpenCreate={a.openCreate}
|
||||
onOpenRegistry={a.openRegistryBrowser}
|
||||
onSnackbar={(message, severity) => a.setSnackbar({ open: true, message, severity: severity === 'error' ? 'error' : undefined })}
|
||||
/>
|
||||
|
||||
@@ -3,7 +3,6 @@ import Button from '@mui/material/Button';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import BuildIcon from '@mui/icons-material/Build';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import StorefrontIcon from '@mui/icons-material/Storefront';
|
||||
import AddLinkIcon from '@mui/icons-material/AddLink';
|
||||
@@ -13,13 +12,12 @@ import AddCustomConnectorDialog from '../../Directory/dialogs/AddCustomConnector
|
||||
interface Props {
|
||||
devMode: boolean;
|
||||
onBrowseConnectors?: () => void;
|
||||
onOpenCreate: () => void;
|
||||
onOpenRegistry: () => void;
|
||||
onSnackbar: (message: string, severity: 'success' | 'error') => void;
|
||||
}
|
||||
|
||||
// The Tools page's Add button (claude.ai's Connectors-page grammar) plus the custom-connector dialog it opens.
|
||||
const ToolsAddMenu: React.FC<Props> = ({ devMode, onBrowseConnectors, onOpenCreate, onOpenRegistry, onSnackbar }) => {
|
||||
const ToolsAddMenu: React.FC<Props> = ({ devMode, onBrowseConnectors, onOpenRegistry, onSnackbar }) => {
|
||||
const c = useClaudeTokens();
|
||||
const [menuAnchor, setMenuAnchor] = useState<null | HTMLElement>(null);
|
||||
const [customConnectorOpen, setCustomConnectorOpen] = useState(false);
|
||||
@@ -51,10 +49,6 @@ const ToolsAddMenu: React.FC<Props> = ({ devMode, onBrowseConnectors, onOpenCrea
|
||||
<AddLinkIcon sx={{ fontSize: 16, color: c.text.tertiary }} />
|
||||
Add custom connector
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => { closeMenu(); onOpenCreate(); }} sx={{ color: c.text.primary, fontSize: '0.875rem', gap: 1.5, '&:hover': { bgcolor: c.bg.secondary } }}>
|
||||
<BuildIcon sx={{ fontSize: 16, color: c.text.tertiary }} />
|
||||
Create Custom
|
||||
</MenuItem>
|
||||
{devMode && (
|
||||
<MenuItem onClick={() => { closeMenu(); onOpenRegistry(); }} sx={{ color: c.text.primary, fontSize: '0.875rem', gap: 1.5, '&:hover': { bgcolor: c.bg.secondary } }}>
|
||||
<StorefrontIcon sx={{ fontSize: 16, color: c.text.tertiary }} />
|
||||
|
||||
Reference in New Issue
Block a user