mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-11 14:10:15 -07:00
AIX: Inspector: Quick Toggle
This commit is contained in:
@@ -199,7 +199,7 @@ export function SettingsModal(props: {
|
||||
|
||||
const { setTab } = props;
|
||||
const isToolsTab = props.tab === 'tools';
|
||||
const enableAixDebugger = Is.Deployment.Localhost;
|
||||
const enableAixDebuggerDialog = true;
|
||||
|
||||
const handleSetTab = React.useCallback((_event: any, value: string | number | null) => {
|
||||
setTab((value ?? undefined) as PreferencesTabId);
|
||||
@@ -221,12 +221,12 @@ export function SettingsModal(props: {
|
||||
{!isMobile && !isToolsTab && <Button variant='soft' color='neutral' onClick={props.onOpenShortcuts} startDecorator={<KeyboardCommandKeyOutlinedIcon color='primary' />} sx={darkModeToggleButtonSx}>
|
||||
Shortcuts
|
||||
</Button>}
|
||||
{isToolsTab && <Button variant='soft' color='neutral' disabled={!enableAixDebuggerDialog} onClick={optimaActions().openAIXDebugger} startDecorator={<TerminalOutlinedIcon color={enableAixDebuggerDialog ? 'primary' : undefined} />} sx={darkModeToggleButtonSx}>
|
||||
AI Inspector
|
||||
</Button>}
|
||||
{isToolsTab && <Button variant='soft' color='neutral' onClick={optimaActions().openLogger} startDecorator={<TerminalOutlinedIcon color='primary' />} sx={darkModeToggleButtonSx}>
|
||||
Logs Viewer
|
||||
</Button>}
|
||||
{isToolsTab && <Button variant='soft' color='neutral' disabled={!enableAixDebugger} onClick={optimaActions().openAIXDebugger} startDecorator={<TerminalOutlinedIcon color={enableAixDebugger ? 'primary' : undefined} />} sx={darkModeToggleButtonSx}>
|
||||
AIX Debugger
|
||||
</Button>}
|
||||
</Box>
|
||||
}
|
||||
sx={_styles.modal}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { persist } from 'zustand/middleware';
|
||||
|
||||
import type { ContentScaling, UIComplexityMode } from '~/common/app.theme';
|
||||
import { BrowserLang } from '~/common/util/pwaUtils';
|
||||
import { Release } from '~/common/app.release';
|
||||
|
||||
|
||||
// UI Preferences
|
||||
@@ -47,6 +48,11 @@ interface UIPreferencesStore {
|
||||
composerQuickButton: 'off' | 'call' | 'beam';
|
||||
setComposerQuickButton: (composerQuickButton: 'off' | 'call' | 'beam') => void;
|
||||
|
||||
// Advanced features
|
||||
|
||||
aixInspector: boolean;
|
||||
toggleAixInspector: () => void;
|
||||
|
||||
// UI Dismissals
|
||||
|
||||
dismissals: Record<string, boolean>;
|
||||
@@ -103,6 +109,11 @@ export const useUIPreferencesStore = create<UIPreferencesStore>()(
|
||||
composerQuickButton: 'beam',
|
||||
setComposerQuickButton: (composerQuickButton: 'off' | 'call' | 'beam') => set({ composerQuickButton }),
|
||||
|
||||
// Advanced features
|
||||
|
||||
aixInspector: false,
|
||||
toggleAixInspector: () => set((state) => ({ aixInspector: !state.aixInspector })),
|
||||
|
||||
// UI Dismissals
|
||||
|
||||
dismissals: {},
|
||||
@@ -133,6 +144,13 @@ export const useUIPreferencesStore = create<UIPreferencesStore>()(
|
||||
*/
|
||||
version: 3,
|
||||
|
||||
partialize: (state) => {
|
||||
if (Release.IsNodeDevBuild) return state; // in dev, persist everything
|
||||
// In production, exclude aixInspector from persistence
|
||||
const { aixInspector, ...rest } = state;
|
||||
return rest;
|
||||
},
|
||||
|
||||
migrate: (state: any, fromVersion: number): UIPreferencesStore => {
|
||||
|
||||
// 1: rename 'enterToSend' to 'enterIsNewline' (flip the meaning)
|
||||
@@ -169,6 +187,10 @@ export function useUIContentScaling(): ContentScaling {
|
||||
return useUIPreferencesStore((state) => state.contentScaling);
|
||||
}
|
||||
|
||||
export function getAixInspector(): boolean {
|
||||
return useUIPreferencesStore.getState().aixInspector;
|
||||
}
|
||||
|
||||
|
||||
export function useUIIsDismissed(key: string | null): boolean | undefined {
|
||||
return useUIPreferencesStore((state) => !key ? undefined : Boolean(state.dismissals[key]));
|
||||
|
||||
@@ -10,7 +10,8 @@ import { DMetricsChatGenerate_Lg, metricsChatGenerateLgToMd, metricsComputeChatG
|
||||
import { DModelParameterValues, getAllModelParameterValues } from '~/common/stores/llms/llms.parameters';
|
||||
import { createErrorContentFragment, DMessageContentFragment, DMessageErrorPart, DMessageVoidFragment, isContentFragment, isErrorPart } from '~/common/stores/chat/chat.fragments';
|
||||
import { findLLMOrThrow } from '~/common/stores/llms/store-llms';
|
||||
import { getLabsDevMode, getLabsDevNoStreaming } from '~/common/stores/store-ux-labs';
|
||||
import { getAixInspector } from '~/common/stores/store-ui';
|
||||
import { getLabsDevNoStreaming } from '~/common/stores/store-ux-labs';
|
||||
import { metricsStoreAddChatGenerate } from '~/common/stores/metrics/store-metrics';
|
||||
import { presentErrorToHumans } from '~/common/util/errorUtils';
|
||||
import { webGeolocationCached } from '~/common/util/webGeolocationUtils';
|
||||
@@ -631,7 +632,7 @@ async function _aixChatGenerateContent_LL(
|
||||
* - AIX inspector is now independent from sudo mode
|
||||
* - every request thereafter both sends back the Aix server-side dispatch packet, and appends all the particles received by the client side
|
||||
*/
|
||||
const requestServerDebugging = getLabsDevMode();
|
||||
const requestServerDebugging = getAixInspector();
|
||||
const debugContext = !requestServerDebugging ? undefined : { contextName: aixContext.name, contextRef: aixContext.ref };
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
|
||||
import { Box, Button, Divider, FormControl, FormLabel, Option, Select, Typography } from '@mui/joy';
|
||||
import { Box, Button, Divider, FormControl, FormLabel, Link, Option, Select, Switch, Typography } from '@mui/joy';
|
||||
import ClearAllIcon from '@mui/icons-material/ClearAll';
|
||||
|
||||
import { GoodModal } from '~/common/components/modals/GoodModal';
|
||||
import { useIsMobile } from '~/common/components/useMatchMedia';
|
||||
import { useUIPreferencesStore } from '~/common/stores/store-ui';
|
||||
|
||||
import { AixDebuggerFrame } from './AixDebuggerFrame';
|
||||
import { aixClientDebuggerActions, useAixClientDebuggerStore } from './memstore-aix-client-debugger';
|
||||
@@ -15,8 +16,10 @@ export function AixDebuggerDialog(props: {
|
||||
onClose: () => void;
|
||||
}) {
|
||||
|
||||
// external state - we subscribe to Any update - it's a temp debugger anyway
|
||||
// external state
|
||||
const isMobile = useIsMobile();
|
||||
const aixInspector = useUIPreferencesStore(state => state.aixInspector);
|
||||
// NOTE: we subscribe to Any update - which can be ultra noisy
|
||||
const { frames, activeFrameId, maxFrames } = useAixClientDebuggerStore(useShallow((state) => ({
|
||||
frames: state.frames,
|
||||
activeFrameId: state.activeFrameId,
|
||||
@@ -42,7 +45,14 @@ export function AixDebuggerDialog(props: {
|
||||
<GoodModal
|
||||
open
|
||||
onClose={props.onClose}
|
||||
title='AIX API Debugger'
|
||||
title='AI Request Inspector'
|
||||
titleStartDecorator={
|
||||
<Switch
|
||||
checked={aixInspector}
|
||||
onChange={useUIPreferencesStore.getState().toggleAixInspector}
|
||||
sx={{ mr: 1 }}
|
||||
/>
|
||||
}
|
||||
autoOverflow
|
||||
fullscreen={isMobile}
|
||||
sx={{ maxWidth: undefined }}
|
||||
@@ -74,7 +84,7 @@ export function AixDebuggerDialog(props: {
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
{/* History Size Preferenes */}
|
||||
{/* History Size Preferences */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'flex-end', gap: 2 }}>
|
||||
<FormControl>
|
||||
<FormLabel>History Size</FormLabel>
|
||||
@@ -111,11 +121,20 @@ export function AixDebuggerDialog(props: {
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '200px' }}>
|
||||
{!frames.length && <>
|
||||
<Typography level='title-lg'>
|
||||
No AIX API requests recorded yet
|
||||
{aixInspector ? 'Ready to capture' : 'AI Request Inspector'}
|
||||
</Typography>
|
||||
<Typography level='body-sm' sx={{ mt: 2, maxWidth: 468 }}>
|
||||
Ensure AIX debugging is active (Settings -> Labs -> Developer Mode)
|
||||
and you are running your own localhost:3000 installation.
|
||||
<Typography level='body-sm' sx={{ mt: 2, maxWidth: 468, textAlign: 'center' }}>
|
||||
{aixInspector
|
||||
? 'Your next AI request will be captured here.'
|
||||
: <>
|
||||
<Link
|
||||
component='button'
|
||||
level='body-sm'
|
||||
onClick={useUIPreferencesStore.getState().toggleAixInspector}
|
||||
>
|
||||
Turn on inspector
|
||||
</Link> to see the exact requests to AI models.
|
||||
</>}
|
||||
</Typography>
|
||||
</>}
|
||||
{!activeFrame && !!frames.length && (
|
||||
|
||||
@@ -94,8 +94,9 @@ export function AixDebuggerFrame(props: {
|
||||
|
||||
{/* Body */}
|
||||
<Card variant='soft' color='primary' sx={_styles.requestCard}>
|
||||
<Typography color='primary' variant='soft' level='title-sm'>
|
||||
-> Body {frame.bodySize > 0 && `(${frame.bodySize.toLocaleString()} chars)`}
|
||||
<Typography color='primary' variant='soft' level='title-sm' sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<span>-> Body</span>
|
||||
{frame.bodySize > 0 && <span>{frame.bodySize.toLocaleString()} bytes</span>}
|
||||
</Typography>
|
||||
<Divider />
|
||||
<Box sx={_styles.requestCardText}>
|
||||
|
||||
Reference in New Issue
Block a user