Show reasoning output automatically when enabled (#1943)
* feat(app): add auto-expand reasoning setting * chore: add cross-env mise tool * fix(app): stabilize web export and settings detail placement * Revert "chore: add cross-env mise tool" This reverts commit f56a367e0cd6766140db2d3b30a1c57bff4d9a14. * perf(app): narrow settings reads in agent stream --------- Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
This commit is contained in:
co-authored by
Mohamed Boudra
parent
29a3261dd6
commit
d96d599466
@@ -303,6 +303,8 @@ npm run build:app-deps # highlight -> protocol -> client -> expo-two-way-aud
|
|||||||
|
|
||||||
Use `npm run build:server` whenever you have changed any daemon/server-facing package and need clean cross-package types or runtime behavior.
|
Use `npm run build:server` whenever you have changed any daemon/server-facing package and need clean cross-package types or runtime behavior.
|
||||||
|
|
||||||
|
The app Metro config disables Watchman and uses Metro's node crawler for exports. Keep that invariant unless you have verified production app exports on machines with and without Watchman installed; distro Watchman builds can differ in capabilities and change Metro's crawl behavior.
|
||||||
|
|
||||||
For tighter loops, you can rebuild a single workspace:
|
For tighter loops, you can rebuild a single workspace:
|
||||||
|
|
||||||
- Changed `packages/protocol/src/*` or `packages/client/src/*`: `npm run build:client`.
|
- Changed `packages/protocol/src/*` or `packages/client/src/*`: `npm run build:client`.
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ const customWebPlatform = (process.env.PASEO_WEB_PLATFORM ?? "")
|
|||||||
|
|
||||||
const config = getDefaultConfig(projectRoot);
|
const config = getDefaultConfig(projectRoot);
|
||||||
const defaultResolveRequest = config.resolver.resolveRequest ?? resolve;
|
const defaultResolveRequest = config.resolver.resolveRequest ?? resolve;
|
||||||
|
|
||||||
|
// Keep app exports deterministic across dev machines and CI. Metro's Watchman
|
||||||
|
// crawler behavior depends on the host Watchman build/capabilities, while the
|
||||||
|
// node crawler is the path used when Watchman is absent.
|
||||||
|
config.resolver.useWatchman = false;
|
||||||
|
|
||||||
const escapedAppSrcRoot = appSrcRoot
|
const escapedAppSrcRoot = appSrcRoot
|
||||||
.split(path.sep)
|
.split(path.sep)
|
||||||
.map((segment) => segment.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&"))
|
.map((segment) => segment.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&"))
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import type { AgentScreenAgent } from "@/hooks/use-agent-screen-state-machine";
|
|||||||
import { useSessionStore } from "@/stores/session-store";
|
import { useSessionStore } from "@/stores/session-store";
|
||||||
import { useFileExplorerActions } from "@/hooks/use-file-explorer-actions";
|
import { useFileExplorerActions } from "@/hooks/use-file-explorer-actions";
|
||||||
import { useLoadOlderAgentHistory } from "@/hooks/use-load-older-agent-history";
|
import { useLoadOlderAgentHistory } from "@/hooks/use-load-older-agent-history";
|
||||||
|
import { useSettings } from "@/hooks/use-settings";
|
||||||
import type { ToastApi } from "@/components/toast-host";
|
import type { ToastApi } from "@/components/toast-host";
|
||||||
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
|
import type { DaemonClient } from "@getpaseo/client/internal/daemon-client";
|
||||||
import { ToolCallDetailsContent } from "@/components/tool-call-details";
|
import { ToolCallDetailsContent } from "@/components/tool-call-details";
|
||||||
@@ -318,6 +319,7 @@ const AgentStreamViewComponent = forwardRef<AgentStreamViewHandle, AgentStreamVi
|
|||||||
) {
|
) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const autoExpandReasoning = useSettings((settings) => settings.autoExpandReasoning);
|
||||||
const viewportRef = useRef<StreamViewportHandle | null>(null);
|
const viewportRef = useRef<StreamViewportHandle | null>(null);
|
||||||
const isMobile = useIsCompactFormFactor();
|
const isMobile = useIsCompactFormFactor();
|
||||||
const streamRenderStrategy = useMemo(
|
const streamRenderStrategy = useMemo(
|
||||||
@@ -633,10 +635,12 @@ const AgentStreamViewComponent = forwardRef<AgentStreamViewHandle, AgentStreamVi
|
|||||||
args={item.text}
|
args={item.text}
|
||||||
status={item.status === "ready" ? "completed" : "executing"}
|
status={item.status === "ready" ? "completed" : "executing"}
|
||||||
isLastInSequence={layoutItem.isLastInToolSequence}
|
isLastInSequence={layoutItem.isLastInToolSequence}
|
||||||
|
defaultExpanded={autoExpandReasoning}
|
||||||
|
forceInline={autoExpandReasoning}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[setInlineDetailsExpanded],
|
[autoExpandReasoning, setInlineDetailsExpanded],
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderToolCallItem = useCallback(
|
const renderToolCallItem = useCallback(
|
||||||
|
|||||||
@@ -3038,6 +3038,8 @@ interface ToolCallProps {
|
|||||||
onInlineDetailsHoverChange?: (hovered: boolean) => void;
|
onInlineDetailsHoverChange?: (hovered: boolean) => void;
|
||||||
onInlineDetailsExpandedChange?: (expanded: boolean) => void;
|
onInlineDetailsExpandedChange?: (expanded: boolean) => void;
|
||||||
onOpenFilePath?: (filePath: string) => void;
|
onOpenFilePath?: (filePath: string) => void;
|
||||||
|
defaultExpanded?: boolean;
|
||||||
|
forceInline?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ToolCall = memo(function ToolCall({
|
export const ToolCall = memo(function ToolCall({
|
||||||
@@ -3054,11 +3056,14 @@ export const ToolCall = memo(function ToolCall({
|
|||||||
onInlineDetailsHoverChange,
|
onInlineDetailsHoverChange,
|
||||||
onInlineDetailsExpandedChange,
|
onInlineDetailsExpandedChange,
|
||||||
onOpenFilePath,
|
onOpenFilePath,
|
||||||
|
defaultExpanded,
|
||||||
|
forceInline = false,
|
||||||
}: ToolCallProps) {
|
}: ToolCallProps) {
|
||||||
const { openToolCall } = useToolCallSheet();
|
const { openToolCall } = useToolCallSheet();
|
||||||
const [isExpanded, setIsExpanded] = useState(false);
|
const [isExpanded, setIsExpanded] = useState(defaultExpanded ?? false);
|
||||||
|
|
||||||
const isMobile = useIsCompactFormFactor();
|
const isMobile = useIsCompactFormFactor();
|
||||||
|
const shouldRenderInline = !isMobile || forceInline;
|
||||||
|
|
||||||
const effectiveDetail = useMemo<ToolCallDetail | undefined>(() => {
|
const effectiveDetail = useMemo<ToolCallDetail | undefined>(() => {
|
||||||
if (detail) {
|
if (detail) {
|
||||||
@@ -3096,7 +3101,7 @@ export const ToolCall = memo(function ToolCall({
|
|||||||
}, [presentation.openFilePath, onOpenFilePath]);
|
}, [presentation.openFilePath, onOpenFilePath]);
|
||||||
|
|
||||||
const handleToggle = useCallback(() => {
|
const handleToggle = useCallback(() => {
|
||||||
if (isMobile) {
|
if (!shouldRenderInline) {
|
||||||
openToolCall({
|
openToolCall({
|
||||||
displayName: presentation.displayName,
|
displayName: presentation.displayName,
|
||||||
summary: presentation.summary,
|
summary: presentation.summary,
|
||||||
@@ -3109,7 +3114,7 @@ export const ToolCall = memo(function ToolCall({
|
|||||||
setIsExpanded((prev) => !prev);
|
setIsExpanded((prev) => !prev);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
isMobile,
|
shouldRenderInline,
|
||||||
openToolCall,
|
openToolCall,
|
||||||
presentation.displayName,
|
presentation.displayName,
|
||||||
presentation.summary,
|
presentation.summary,
|
||||||
@@ -3120,22 +3125,22 @@ export const ToolCall = memo(function ToolCall({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!onInlineDetailsHoverChange || isMobile || isExpanded) {
|
if (!onInlineDetailsHoverChange || !shouldRenderInline || isExpanded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onInlineDetailsHoverChange(false);
|
onInlineDetailsHoverChange(false);
|
||||||
}, [isExpanded, isMobile, onInlineDetailsHoverChange]);
|
}, [isExpanded, shouldRenderInline, onInlineDetailsHoverChange]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!onInlineDetailsExpandedChange) {
|
if (!onInlineDetailsExpandedChange) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isMobile) {
|
if (!shouldRenderInline) {
|
||||||
onInlineDetailsExpandedChange(false);
|
onInlineDetailsExpandedChange(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onInlineDetailsExpandedChange(isExpanded);
|
onInlineDetailsExpandedChange(isExpanded);
|
||||||
}, [isExpanded, isMobile, onInlineDetailsExpandedChange]);
|
}, [isExpanded, shouldRenderInline, onInlineDetailsExpandedChange]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!onInlineDetailsExpandedChange) {
|
if (!onInlineDetailsExpandedChange) {
|
||||||
@@ -3148,7 +3153,7 @@ export const ToolCall = memo(function ToolCall({
|
|||||||
|
|
||||||
// Render inline details for desktop
|
// Render inline details for desktop
|
||||||
const renderDetails = useCallback(() => {
|
const renderDetails = useCallback(() => {
|
||||||
if (isMobile) return null;
|
if (!shouldRenderInline) return null;
|
||||||
return (
|
return (
|
||||||
<ToolCallDetailsContent
|
<ToolCallDetailsContent
|
||||||
detail={effectiveDetail}
|
detail={effectiveDetail}
|
||||||
@@ -3157,7 +3162,7 @@ export const ToolCall = memo(function ToolCall({
|
|||||||
showLoadingSkeleton={presentation.isLoadingDetails}
|
showLoadingSkeleton={presentation.isLoadingDetails}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}, [isMobile, effectiveDetail, presentation.errorText, presentation.isLoadingDetails]);
|
}, [shouldRenderInline, effectiveDetail, presentation.errorText, presentation.isLoadingDetails]);
|
||||||
|
|
||||||
if (presentation.isPlan && effectiveDetail?.type === "plan") {
|
if (presentation.isPlan && effectiveDetail?.type === "plan") {
|
||||||
return (
|
return (
|
||||||
@@ -3175,10 +3180,10 @@ export const ToolCall = memo(function ToolCall({
|
|||||||
label={presentation.displayName}
|
label={presentation.displayName}
|
||||||
secondaryLabel={presentation.summary}
|
secondaryLabel={presentation.summary}
|
||||||
icon={presentation.icon}
|
icon={presentation.icon}
|
||||||
isExpanded={!isMobile && isExpanded}
|
isExpanded={shouldRenderInline && isExpanded}
|
||||||
onToggle={presentation.canOpenDetails ? handleToggle : undefined}
|
onToggle={presentation.canOpenDetails ? handleToggle : undefined}
|
||||||
onOpenFile={handleOpenFile}
|
onOpenFile={handleOpenFile}
|
||||||
renderDetails={presentation.canOpenDetails && !isMobile ? renderDetails : undefined}
|
renderDetails={presentation.canOpenDetails && shouldRenderInline ? renderDetails : undefined}
|
||||||
isLoading={status === "running" || status === "executing"}
|
isLoading={status === "running" || status === "executing"}
|
||||||
isError={status === "failed"}
|
isError={status === "failed"}
|
||||||
isLastInSequence={isLastInSequence}
|
isLastInSequence={isLastInSequence}
|
||||||
@@ -3200,5 +3205,7 @@ function areToolCallPropsEqual(previous: ToolCallProps, next: ToolCallProps) {
|
|||||||
if (previous.isLastInSequence !== next.isLastInSequence) return false;
|
if (previous.isLastInSequence !== next.isLastInSequence) return false;
|
||||||
if (previous.disableOuterSpacing !== next.disableOuterSpacing) return false;
|
if (previous.disableOuterSpacing !== next.disableOuterSpacing) return false;
|
||||||
if (previous.onOpenFilePath !== next.onOpenFilePath) return false;
|
if (previous.onOpenFilePath !== next.onOpenFilePath) return false;
|
||||||
|
if (previous.defaultExpanded !== next.defaultExpanded) return false;
|
||||||
|
if (previous.forceInline !== next.forceInline) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,8 @@ export interface UseSettingsReturn {
|
|||||||
resetSettings: () => Promise<void>;
|
resetSettings: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SettingsSelector<TSelected> = (settings: Settings) => TSelected;
|
||||||
|
|
||||||
export function useAppSettings(): UseAppSettingsReturn {
|
export function useAppSettings(): UseAppSettingsReturn {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { data, isPending, error } = useQuery({
|
const { data, isPending, error } = useQuery({
|
||||||
@@ -137,7 +139,11 @@ export function useAppSettings(): UseAppSettingsReturn {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useSettings(): UseSettingsReturn {
|
export function useSettings(): UseSettingsReturn;
|
||||||
|
export function useSettings<TSelected>(selector: SettingsSelector<TSelected>): TSelected;
|
||||||
|
export function useSettings<TSelected>(
|
||||||
|
selector?: SettingsSelector<TSelected>,
|
||||||
|
): UseSettingsReturn | TSelected {
|
||||||
const appSettings = useAppSettings();
|
const appSettings = useAppSettings();
|
||||||
const desktopSettings = useDesktopSettings();
|
const desktopSettings = useDesktopSettings();
|
||||||
|
|
||||||
@@ -177,6 +183,9 @@ export function useSettings(): UseSettingsReturn {
|
|||||||
if (updates.workspaceTitleSource !== undefined) {
|
if (updates.workspaceTitleSource !== undefined) {
|
||||||
appUpdates.workspaceTitleSource = updates.workspaceTitleSource;
|
appUpdates.workspaceTitleSource = updates.workspaceTitleSource;
|
||||||
}
|
}
|
||||||
|
if (updates.autoExpandReasoning !== undefined) {
|
||||||
|
appUpdates.autoExpandReasoning = updates.autoExpandReasoning;
|
||||||
|
}
|
||||||
const promises: Promise<void>[] = [];
|
const promises: Promise<void>[] = [];
|
||||||
if (Object.keys(appUpdates).length > 0) {
|
if (Object.keys(appUpdates).length > 0) {
|
||||||
promises.push(appSettings.updateSettings(appUpdates));
|
promises.push(appSettings.updateSettings(appUpdates));
|
||||||
@@ -210,13 +219,19 @@ export function useSettings(): UseSettingsReturn {
|
|||||||
await Promise.all(resets);
|
await Promise.all(resets);
|
||||||
}, [appSettings, desktopSettings]);
|
}, [appSettings, desktopSettings]);
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
...DEFAULT_APP_SETTINGS,
|
||||||
|
...appSettings.settings,
|
||||||
|
manageBuiltInDaemon: desktopSettings.settings.daemon.manageBuiltInDaemon,
|
||||||
|
releaseChannel: desktopSettings.settings.releaseChannel,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (selector) {
|
||||||
|
return selector(settings);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
settings: {
|
settings,
|
||||||
...DEFAULT_APP_SETTINGS,
|
|
||||||
...appSettings.settings,
|
|
||||||
manageBuiltInDaemon: desktopSettings.settings.daemon.manageBuiltInDaemon,
|
|
||||||
releaseChannel: desktopSettings.settings.releaseChannel,
|
|
||||||
},
|
|
||||||
isLoading: appSettings.isLoading || desktopSettings.isLoading,
|
isLoading: appSettings.isLoading || desktopSettings.isLoading,
|
||||||
error: appSettings.error ?? desktopSettings.error,
|
error: appSettings.error ?? desktopSettings.error,
|
||||||
updateSettings,
|
updateSettings,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export interface AppSettings {
|
|||||||
codeFontSize: number; // clamped px, default 12
|
codeFontSize: number; // clamped px, default 12
|
||||||
syntaxTheme: SyntaxThemeId; // default "one"
|
syntaxTheme: SyntaxThemeId; // default "one"
|
||||||
workspaceTitleSource: WorkspaceTitleSource;
|
workspaceTitleSource: WorkspaceTitleSource;
|
||||||
|
autoExpandReasoning: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Settings extends AppSettings {
|
export interface Settings extends AppSettings {
|
||||||
@@ -58,6 +59,7 @@ export const DEFAULT_CLIENT_SETTINGS: AppSettings = {
|
|||||||
codeFontSize: DEFAULT_CODE_FONT_SIZE,
|
codeFontSize: DEFAULT_CODE_FONT_SIZE,
|
||||||
syntaxTheme: "one",
|
syntaxTheme: "one",
|
||||||
workspaceTitleSource: "title",
|
workspaceTitleSource: "title",
|
||||||
|
autoExpandReasoning: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_APP_SETTINGS: Settings = {
|
export const DEFAULT_APP_SETTINGS: Settings = {
|
||||||
@@ -204,6 +206,9 @@ function pickAppSettings(stored: Partial<AppSettings>): Partial<AppSettings> {
|
|||||||
) {
|
) {
|
||||||
result.workspaceTitleSource = stored.workspaceTitleSource;
|
result.workspaceTitleSource = stored.workspaceTitleSource;
|
||||||
}
|
}
|
||||||
|
if (typeof stored.autoExpandReasoning === "boolean") {
|
||||||
|
result.autoExpandReasoning = stored.autoExpandReasoning;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1471,6 +1471,10 @@ export const ar: TranslationResources = {
|
|||||||
description: "يتم الاحتفاظ بالخطوط في المخزن المؤقت الطرفي المدمج",
|
description: "يتم الاحتفاظ بالخطوط في المخزن المؤقت الطرفي المدمج",
|
||||||
accessibilityLabel: "خطوط التمرير Terminal",
|
accessibilityLabel: "خطوط التمرير Terminal",
|
||||||
},
|
},
|
||||||
|
autoExpandReasoning: {
|
||||||
|
label: "عرض التفكير دائماً",
|
||||||
|
description: "إظهار تفكير الوكيل وخطوات الاستدلال بشكل كامل بشكل افتراضي",
|
||||||
|
},
|
||||||
language: {
|
language: {
|
||||||
label: "لغة",
|
label: "لغة",
|
||||||
description: "لغة التطبيق",
|
description: "لغة التطبيق",
|
||||||
@@ -1552,6 +1556,9 @@ export const ar: TranslationResources = {
|
|||||||
auto: "نظام",
|
auto: "نظام",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
detailLevel: {
|
||||||
|
title: "مستوى التفاصيل",
|
||||||
|
},
|
||||||
fonts: {
|
fonts: {
|
||||||
title: "الخطوط",
|
title: "الخطوط",
|
||||||
systemDefault: "الافتراضي للنظام",
|
systemDefault: "الافتراضي للنظام",
|
||||||
|
|||||||
@@ -1478,6 +1478,10 @@ export const en = {
|
|||||||
description: "Lines kept in the built-in terminal buffer",
|
description: "Lines kept in the built-in terminal buffer",
|
||||||
accessibilityLabel: "Terminal scrollback lines",
|
accessibilityLabel: "Terminal scrollback lines",
|
||||||
},
|
},
|
||||||
|
autoExpandReasoning: {
|
||||||
|
label: "Always expand reasoning",
|
||||||
|
description: "Show agent thinking and chain-of-thought blocks fully expanded by default",
|
||||||
|
},
|
||||||
language: {
|
language: {
|
||||||
label: "Language",
|
label: "Language",
|
||||||
description: "App language",
|
description: "App language",
|
||||||
@@ -1559,6 +1563,9 @@ export const en = {
|
|||||||
auto: "System",
|
auto: "System",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
detailLevel: {
|
||||||
|
title: "Detail level",
|
||||||
|
},
|
||||||
fonts: {
|
fonts: {
|
||||||
title: "Fonts",
|
title: "Fonts",
|
||||||
systemDefault: "System default",
|
systemDefault: "System default",
|
||||||
|
|||||||
@@ -1511,6 +1511,11 @@ export const es: TranslationResources = {
|
|||||||
description: "Líneas mantenidas en el búfer de terminal incorporado",
|
description: "Líneas mantenidas en el búfer de terminal incorporado",
|
||||||
accessibilityLabel: "Líneas del historial de terminal",
|
accessibilityLabel: "Líneas del historial de terminal",
|
||||||
},
|
},
|
||||||
|
autoExpandReasoning: {
|
||||||
|
label: "Siempre expandir razonamiento",
|
||||||
|
description:
|
||||||
|
"Mostrar los bloques de pensamiento y razonamiento del agente totalmente expandidos de forma predeterminada",
|
||||||
|
},
|
||||||
language: {
|
language: {
|
||||||
label: "Idioma",
|
label: "Idioma",
|
||||||
description: "Idioma de la aplicación",
|
description: "Idioma de la aplicación",
|
||||||
@@ -1592,6 +1597,9 @@ export const es: TranslationResources = {
|
|||||||
auto: "Sistema",
|
auto: "Sistema",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
detailLevel: {
|
||||||
|
title: "Nivel de detalle",
|
||||||
|
},
|
||||||
fonts: {
|
fonts: {
|
||||||
title: "Fuentes",
|
title: "Fuentes",
|
||||||
systemDefault: "Valor predeterminado del sistema",
|
systemDefault: "Valor predeterminado del sistema",
|
||||||
|
|||||||
@@ -1514,6 +1514,10 @@ export const fr: TranslationResources = {
|
|||||||
description: "Lignes conservées dans le tampon du terminal intégré",
|
description: "Lignes conservées dans le tampon du terminal intégré",
|
||||||
accessibilityLabel: "Lignes de défilementTerminal",
|
accessibilityLabel: "Lignes de défilementTerminal",
|
||||||
},
|
},
|
||||||
|
autoExpandReasoning: {
|
||||||
|
label: "Toujours afficher le raisonnement",
|
||||||
|
description: "Afficher le raisonnement de l'agent entièrement développé par défaut",
|
||||||
|
},
|
||||||
language: {
|
language: {
|
||||||
label: "Langue",
|
label: "Langue",
|
||||||
description: "Langue de l'application",
|
description: "Langue de l'application",
|
||||||
@@ -1596,6 +1600,9 @@ export const fr: TranslationResources = {
|
|||||||
auto: "Système",
|
auto: "Système",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
detailLevel: {
|
||||||
|
title: "Niveau de détail",
|
||||||
|
},
|
||||||
fonts: {
|
fonts: {
|
||||||
title: "Polices",
|
title: "Polices",
|
||||||
systemDefault: "Valeur par défaut du système",
|
systemDefault: "Valeur par défaut du système",
|
||||||
|
|||||||
@@ -1487,6 +1487,10 @@ export const ja: TranslationResources = {
|
|||||||
description: "組み込みターミナルバッファに保持する行数",
|
description: "組み込みターミナルバッファに保持する行数",
|
||||||
accessibilityLabel: "ターミナルスクロールバック行数",
|
accessibilityLabel: "ターミナルスクロールバック行数",
|
||||||
},
|
},
|
||||||
|
autoExpandReasoning: {
|
||||||
|
label: "常に思考プロセスを展開",
|
||||||
|
description: "デフォルトでAIのエージェント思考・推論ブロックを完全に展開して表示します",
|
||||||
|
},
|
||||||
language: {
|
language: {
|
||||||
label: "言語",
|
label: "言語",
|
||||||
description: "アプリの言語",
|
description: "アプリの言語",
|
||||||
@@ -1568,6 +1572,9 @@ export const ja: TranslationResources = {
|
|||||||
auto: "システム",
|
auto: "システム",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
detailLevel: {
|
||||||
|
title: "詳細レベル",
|
||||||
|
},
|
||||||
fonts: {
|
fonts: {
|
||||||
title: "フォント",
|
title: "フォント",
|
||||||
systemDefault: "システムデフォルト",
|
systemDefault: "システムデフォルト",
|
||||||
|
|||||||
@@ -1496,6 +1496,11 @@ export const ptBR: TranslationResources = {
|
|||||||
description: "Linhas mantidas no buffer do terminal integrado",
|
description: "Linhas mantidas no buffer do terminal integrado",
|
||||||
accessibilityLabel: "Linhas do scrollback do terminal",
|
accessibilityLabel: "Linhas do scrollback do terminal",
|
||||||
},
|
},
|
||||||
|
autoExpandReasoning: {
|
||||||
|
label: "Sempre expandir raciocínio",
|
||||||
|
description:
|
||||||
|
"Mostrar os blocos de pensamento e raciocínio do agente totalmente expandidos por padrão",
|
||||||
|
},
|
||||||
language: {
|
language: {
|
||||||
label: "Idioma",
|
label: "Idioma",
|
||||||
description: "Idioma do app",
|
description: "Idioma do app",
|
||||||
@@ -1577,6 +1582,9 @@ export const ptBR: TranslationResources = {
|
|||||||
auto: "Sistema",
|
auto: "Sistema",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
detailLevel: {
|
||||||
|
title: "Nível de detalhe",
|
||||||
|
},
|
||||||
fonts: {
|
fonts: {
|
||||||
title: "Fontes",
|
title: "Fontes",
|
||||||
systemDefault: "Sistema padrão",
|
systemDefault: "Sistema padrão",
|
||||||
|
|||||||
@@ -1501,6 +1501,11 @@ export const ru: TranslationResources = {
|
|||||||
description: "Строки, хранящиеся во встроенном буфере терминала.",
|
description: "Строки, хранящиеся во встроенном буфере терминала.",
|
||||||
accessibilityLabel: "Линии прокрутки Terminal",
|
accessibilityLabel: "Линии прокрутки Terminal",
|
||||||
},
|
},
|
||||||
|
autoExpandReasoning: {
|
||||||
|
label: "Всегда разворачивать размышления",
|
||||||
|
description:
|
||||||
|
"По умолчанию показывать блоки размышлений и логики агента полностью развернутыми",
|
||||||
|
},
|
||||||
language: {
|
language: {
|
||||||
label: "Язык",
|
label: "Язык",
|
||||||
description: "Язык приложения",
|
description: "Язык приложения",
|
||||||
@@ -1583,6 +1588,9 @@ export const ru: TranslationResources = {
|
|||||||
auto: "Система",
|
auto: "Система",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
detailLevel: {
|
||||||
|
title: "Уровень детализации",
|
||||||
|
},
|
||||||
fonts: {
|
fonts: {
|
||||||
title: "Шрифты",
|
title: "Шрифты",
|
||||||
systemDefault: "Система по умолчанию",
|
systemDefault: "Система по умолчанию",
|
||||||
|
|||||||
@@ -1453,6 +1453,10 @@ export const zhCN: TranslationResources = {
|
|||||||
description: "内置终端缓冲区保留的行数",
|
description: "内置终端缓冲区保留的行数",
|
||||||
accessibilityLabel: "终端回滚行数",
|
accessibilityLabel: "终端回滚行数",
|
||||||
},
|
},
|
||||||
|
autoExpandReasoning: {
|
||||||
|
label: "始终展开推理过程",
|
||||||
|
description: "默认情况下完全展开 AI 的思考和推理过程",
|
||||||
|
},
|
||||||
language: {
|
language: {
|
||||||
label: "语言",
|
label: "语言",
|
||||||
description: "应用语言",
|
description: "应用语言",
|
||||||
@@ -1534,6 +1538,9 @@ export const zhCN: TranslationResources = {
|
|||||||
auto: "系统",
|
auto: "系统",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
detailLevel: {
|
||||||
|
title: "详细程度",
|
||||||
|
},
|
||||||
fonts: {
|
fonts: {
|
||||||
title: "字体",
|
title: "字体",
|
||||||
systemDefault: "系统默认",
|
systemDefault: "系统默认",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { SettingsSection } from "@/screens/settings/settings-section";
|
import { SettingsSection } from "@/screens/settings/settings-section";
|
||||||
import {
|
import {
|
||||||
MAX_CODE_FONT_SIZE,
|
MAX_CODE_FONT_SIZE,
|
||||||
@@ -189,6 +190,28 @@ function ThemeRow({ value, onChange }: ThemeRowProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AutoExpandReasoningRowProps {
|
||||||
|
value: boolean;
|
||||||
|
onChange: (value: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function AutoExpandReasoningRow({ value, onChange }: AutoExpandReasoningRowProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<View style={settingsStyles.row}>
|
||||||
|
<View style={settingsStyles.rowContent}>
|
||||||
|
<Text style={settingsStyles.rowTitle}>
|
||||||
|
{t("settings.general.autoExpandReasoning.label")}
|
||||||
|
</Text>
|
||||||
|
<Text style={settingsStyles.rowHint}>
|
||||||
|
{t("settings.general.autoExpandReasoning.description")}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Switch value={value} onValueChange={onChange} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Fonts: family text fields + numeric size fields (commit on blur/submit)
|
// Fonts: family text fields + numeric size fields (commit on blur/submit)
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -397,6 +420,13 @@ export function AppearanceSection() {
|
|||||||
[updateSettings],
|
[updateSettings],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleAutoExpandReasoningChange = useCallback(
|
||||||
|
(autoExpandReasoning: boolean) => {
|
||||||
|
void updateSettings({ autoExpandReasoning });
|
||||||
|
},
|
||||||
|
[updateSettings],
|
||||||
|
);
|
||||||
|
|
||||||
const commitUiFontFamily = useCallback(
|
const commitUiFontFamily = useCallback(
|
||||||
(value: string) => {
|
(value: string) => {
|
||||||
const sanitized = sanitizeFontFamily(value);
|
const sanitized = sanitizeFontFamily(value);
|
||||||
@@ -477,6 +507,14 @@ export function AppearanceSection() {
|
|||||||
<ThemeRow value={settings.theme} onChange={handleThemeChange} />
|
<ThemeRow value={settings.theme} onChange={handleThemeChange} />
|
||||||
</View>
|
</View>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
<SettingsSection title={t("settings.appearance.detailLevel.title")}>
|
||||||
|
<View style={settingsStyles.card}>
|
||||||
|
<AutoExpandReasoningRow
|
||||||
|
value={settings.autoExpandReasoning}
|
||||||
|
onChange={handleAutoExpandReasoningChange}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</SettingsSection>
|
||||||
<SettingsSection title={t("settings.appearance.fonts.title")}>
|
<SettingsSection title={t("settings.appearance.fonts.title")}>
|
||||||
<View style={settingsStyles.card}>
|
<View style={settingsStyles.card}>
|
||||||
{showFontFamilyRows ? (
|
{showFontFamilyRows ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user