qwen-code/packages/cli/src/ui/components/arena/ArenaStartDialog.tsx
tanzhenxin fa2f2fd5ce feat(arena): Short worktree names and UX improvements
- Use 8-char short names derived from session UUID for worktrees
- Fix cleanup to use short worktreeDirName
- Simplify model display names (remove authType prefix)
- Improve messaging when <2 models available
- Show agent worktree paths in startup output

Prevents long path issues and provides clearer model setup guidance.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-09 16:21:28 +08:00

161 lines
4.6 KiB
TypeScript

/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import type React from 'react';
import { useMemo, useState } from 'react';
import { Box, Text } from 'ink';
import Link from 'ink-link';
import { AuthType } from '@qwen-code/qwen-code-core';
import { useConfig } from '../../contexts/ConfigContext.js';
import { theme } from '../../semantic-colors.js';
import { useKeypress } from '../../hooks/useKeypress.js';
import { MultiSelect } from '../shared/MultiSelect.js';
import { t } from '../../../i18n/index.js';
interface ArenaStartDialogProps {
onClose: () => void;
onConfirm: (selectedModels: string[]) => void;
}
const MODEL_PROVIDERS_DOCUMENTATION_URL =
'https://qwenlm.github.io/qwen-code-docs/en/users/configuration/settings/#modelproviders';
export function ArenaStartDialog({
onClose,
onConfirm,
}: ArenaStartDialogProps): React.JSX.Element {
const config = useConfig();
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const modelItems = useMemo(() => {
const allModels = config.getAllConfiguredModels();
const selectableModels = allModels.filter((model) => !model.isRuntimeModel);
return selectableModels.map((model) => {
const token = `${model.authType}:${model.id}`;
const isQwenOauth = model.authType === AuthType.QWEN_OAUTH;
return {
key: token,
value: token,
label: `[${model.authType}] ${model.label}`,
disabled: isQwenOauth,
};
});
}, [config]);
const hasDisabledQwenOauth = modelItems.some((item) => item.disabled);
const selectableModelCount = modelItems.filter(
(item) => !item.disabled,
).length;
const needsMoreModels = selectableModelCount < 2;
const shouldShowMoreModelsHint =
selectableModelCount >= 2 && selectableModelCount < 3;
useKeypress(
(key) => {
if (key.name === 'escape') {
onClose();
}
},
{ isActive: true },
);
const handleConfirm = (values: string[]) => {
if (values.length < 2) {
setErrorMessage(
t('Please select at least 2 models to start an Arena session.'),
);
return;
}
setErrorMessage(null);
onConfirm(values);
};
return (
<Box
borderStyle="round"
borderColor={theme.border.default}
flexDirection="column"
padding={1}
width="100%"
>
<Text bold>{t('Select Models')}</Text>
{modelItems.length === 0 ? (
<Box marginTop={1} flexDirection="column">
<Text color={theme.status.warning}>
{t('No models available. Please configure models first.')}
</Text>
</Box>
) : (
<Box marginTop={1}>
<MultiSelect
items={modelItems}
initialIndex={0}
onConfirm={handleConfirm}
showNumbers
showScrollArrows
maxItemsToShow={10}
/>
</Box>
)}
{errorMessage && (
<Box marginTop={1}>
<Text color={theme.status.error}>{errorMessage}</Text>
</Box>
)}
{(hasDisabledQwenOauth || needsMoreModels) && (
<Box marginTop={1} flexDirection="column">
{hasDisabledQwenOauth && (
<Text color={theme.status.warning}>
{t('Note: qwen-oauth models are not supported in Arena.')}
</Text>
)}
{needsMoreModels && (
<>
<Text color={theme.status.warning}>
{t('Arena requires at least 2 models. To add more:')}
</Text>
<Text color={theme.status.warning}>
{t(
' - Run /auth to set up a Coding Plan (includes multiple models)',
)}
</Text>
<Text color={theme.status.warning}>
{t(' - Or configure modelProviders in settings.json')}
</Text>
</>
)}
</Box>
)}
{shouldShowMoreModelsHint && (
<>
<Box marginTop={1}>
<Text color={theme.text.secondary}>
{t('Configure more models with the modelProviders guide:')}
</Text>
</Box>
<Box marginTop={0}>
<Link url={MODEL_PROVIDERS_DOCUMENTATION_URL} fallback={false}>
<Text color={theme.text.secondary} underline>
{MODEL_PROVIDERS_DOCUMENTATION_URL}
</Text>
</Link>
</Box>
</>
)}
<Box marginTop={1} flexDirection="column">
<Text color={theme.text.secondary}>
{t('Space to toggle, Enter to confirm, Esc to cancel')}
</Text>
</Box>
</Box>
);
}