mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Drawer: show open beams
This commit is contained in:
@@ -20,6 +20,7 @@ import { autoConversationTitle } from '~/modules/aifn/autotitle/autoTitle';
|
||||
import type { DConversationId } from '~/common/stores/chat/chat.conversation';
|
||||
import type { DFolder } from '~/common/stores/folders/store-chat-folders';
|
||||
import { ANIM_BUSY_TYPING } from '~/common/util/dMessageUtils';
|
||||
import { ChatBeamIcon } from '~/common/components/icons/ChatBeamIcon';
|
||||
import { InlineTextarea } from '~/common/components/InlineTextarea';
|
||||
import { isDeepEqual } from '~/common/util/hooks/useDeep';
|
||||
import { useChatStore } from '~/common/stores/chat/store-chats';
|
||||
@@ -64,6 +65,7 @@ export interface ChatNavigationItemData {
|
||||
containsImageAssets: boolean;
|
||||
folder: DFolder | null | undefined; // null: 'All', undefined: do not show folder select
|
||||
updatedAt: number;
|
||||
hasBeamOpen: boolean;
|
||||
messageCount: number;
|
||||
beingGenerated: boolean;
|
||||
systemPurposeId: SystemPurposeId;
|
||||
@@ -106,6 +108,7 @@ function ChatDrawerItem(props: {
|
||||
containsDocAttachments,
|
||||
containsImageAssets,
|
||||
folder,
|
||||
hasBeamOpen,
|
||||
messageCount,
|
||||
beingGenerated,
|
||||
systemPurposeId,
|
||||
@@ -210,7 +213,9 @@ function ChatDrawerItem(props: {
|
||||
{/* Symbol, if globally enabled */}
|
||||
{(props.showSymbols || isIncognito) && (
|
||||
<ListItemDecorator>
|
||||
{isIncognito ? (
|
||||
{hasBeamOpen ? (
|
||||
<ChatBeamIcon sx={{ fontSize: 'xl' }} />
|
||||
) : isIncognito ? (
|
||||
<VisibilityOffIcon sx={{ fontSize: 'xl' }} />
|
||||
) : (beingGenerated && props.showSymbols === 'gif') ? (
|
||||
<Avatar
|
||||
@@ -286,7 +291,7 @@ function ChatDrawerItem(props: {
|
||||
</Box>
|
||||
) : null}
|
||||
|
||||
</>, [beingGenerated, containsDocAttachments, containsImageAssets, handleTitleEditBegin, handleTitleEditCancel, handleTitleEditChange, isActive, isEditingTitle, isIncognito, isNew, personaImageURI, personaSymbol, props.showSymbols, searchFrequency, title, userFlagsSummary]);
|
||||
</>, [beingGenerated, containsDocAttachments, containsImageAssets, handleTitleEditBegin, handleTitleEditCancel, handleTitleEditChange, hasBeamOpen, isActive, isEditingTitle, isIncognito, isNew, personaImageURI, personaSymbol, props.showSymbols, searchFrequency, title, userFlagsSummary]);
|
||||
|
||||
const progressBarFixedComponent = React.useMemo(() =>
|
||||
progress > 0 && (
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { useModuleBeamStore } from '~/modules/beam/store-module-beam';
|
||||
|
||||
import type { DFolder } from '~/common/stores/folders/store-chat-folders';
|
||||
import { DMessage, DMessageUserFlag, MESSAGE_FLAG_STARRED, messageFragmentsReduceText, messageHasUserFlag, messageUserFlagToEmoji } from '~/common/stores/chat/chat.message';
|
||||
import { conversationTitle, DConversationId } from '~/common/stores/chat/chat.conversation';
|
||||
@@ -94,6 +96,9 @@ export function useChatDrawerRenderItems(
|
||||
// state
|
||||
const [_, setJustAMinuteCounter] = React.useState(0);
|
||||
|
||||
// external state
|
||||
const openBeamConversationIds = useModuleBeamStore(state => state.openBeamConversationIds);
|
||||
|
||||
|
||||
// [effect] Refresh every minute because the `getTimeBucketEn` function uses the current time
|
||||
React.useEffect(() => {
|
||||
@@ -173,6 +178,7 @@ export function useChatDrawerRenderItems(
|
||||
? allFolders.find(folder => folder.conversationIds.includes(_c.id)) ?? null
|
||||
: null,
|
||||
updatedAt: _c.updated || _c.created || 0,
|
||||
hasBeamOpen: !!openBeamConversationIds?.[_c.id],
|
||||
messageCount,
|
||||
beingGenerated: !!_c._abortController, // FIXME: when the AbortController is moved at the message level, derive the state in the conv
|
||||
systemPurposeId: _c.systemPurposeId,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { bareBonesPromptMixer } from '~/modules/persona/pmix/pmix';
|
||||
import { SystemPurposes } from '../../data';
|
||||
|
||||
import { BeamStore, createBeamVanillaStore } from '~/modules/beam/store-beam_vanilla';
|
||||
import { useModuleBeamStore } from '~/modules/beam/store-module-beam';
|
||||
|
||||
import type { DConversationId } from '~/common/stores/chat/chat.conversation';
|
||||
import type { DLLMId } from '~/common/stores/llms/llms.types';
|
||||
@@ -38,6 +39,12 @@ export class ConversationHandler {
|
||||
constructor(private readonly conversationId: DConversationId) {
|
||||
this.beamStore = createBeamVanillaStore();
|
||||
this.overlayStore = createPerChatVanillaStore();
|
||||
|
||||
// track the open status of beams - this is meant to be an accelerator for the UI
|
||||
this.beamStore.subscribe((state, prevState) => {
|
||||
if (state.isOpen === prevState.isOpen) return;
|
||||
useModuleBeamStore.getState().setBeamOpenForConversation(this.conversationId, state.isOpen);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
import type { DConversationId } from '~/common/stores/chat/chat.conversation';
|
||||
import type { DLLMId } from '~/common/stores/llms/llms.types';
|
||||
import { agiUuid } from '~/common/util/idUtils';
|
||||
|
||||
import type { FFactoryId } from './gather/instructions/beam.gather.factories';
|
||||
|
||||
|
||||
/// Presets (persistes as zustand store) ///
|
||||
/// Presets (persisted as zustand store) ///
|
||||
|
||||
export interface BeamConfigSnapshot {
|
||||
id: string;
|
||||
@@ -19,6 +20,8 @@ export interface BeamConfigSnapshot {
|
||||
|
||||
|
||||
interface ModuleBeamState {
|
||||
|
||||
// stored
|
||||
presets: BeamConfigSnapshot[];
|
||||
lastConfig: BeamConfigSnapshot | null;
|
||||
cardAdd: boolean;
|
||||
@@ -27,6 +30,10 @@ interface ModuleBeamState {
|
||||
scatterShowPrevMessages: boolean;
|
||||
gatherAutoStartAfterScatter: boolean;
|
||||
gatherShowAllPrompts: boolean;
|
||||
|
||||
// non-stored, temporary but useful for the UI
|
||||
openBeamConversationIds: Record<string, boolean>;
|
||||
|
||||
}
|
||||
|
||||
interface ModuleBeamStore extends ModuleBeamState {
|
||||
@@ -43,6 +50,9 @@ interface ModuleBeamStore extends ModuleBeamState {
|
||||
toggleScatterShowPrevMessages: () => void;
|
||||
toggleGatherAutoStartAfterScatter: () => void;
|
||||
toggleGatherShowAllPrompts: () => void;
|
||||
|
||||
setBeamOpenForConversation: (conversationId: DConversationId, isOpen: boolean) => void;
|
||||
clearBeamOpenForConversation: (conversationId: DConversationId) => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +67,7 @@ export const useModuleBeamStore = create<ModuleBeamStore>()(persist(
|
||||
scatterShowPrevMessages: false,
|
||||
gatherShowAllPrompts: false,
|
||||
gatherAutoStartAfterScatter: false,
|
||||
openBeamConversationIds: {},
|
||||
|
||||
|
||||
addPreset: (name, rayLlmIds, gatherLlmId, gatherFactoryId) => _set(state => ({
|
||||
@@ -99,11 +110,32 @@ export const useModuleBeamStore = create<ModuleBeamStore>()(persist(
|
||||
|
||||
toggleGatherShowAllPrompts: () => _set(state => ({ gatherShowAllPrompts: !state.gatherShowAllPrompts })),
|
||||
|
||||
setBeamOpenForConversation: (conversationId, isOpen) => _set(state => {
|
||||
const openBeams = { ...state.openBeamConversationIds };
|
||||
if (isOpen)
|
||||
openBeams[conversationId] = true;
|
||||
else
|
||||
delete openBeams[conversationId];
|
||||
return { openBeamConversationIds: openBeams };
|
||||
}),
|
||||
|
||||
clearBeamOpenForConversation: (conversationId) => _set(state => {
|
||||
const openBeams = { ...state.openBeamConversationIds };
|
||||
delete openBeams[conversationId];
|
||||
return { openBeamConversationIds: openBeams };
|
||||
}),
|
||||
|
||||
}), {
|
||||
name: 'app-module-beam',
|
||||
version: 1,
|
||||
|
||||
migrate: (state: any, fromVersion: number): ModuleBeamState => {
|
||||
partialize: (state) => {
|
||||
// exclude openBeamConversationIds from persistence
|
||||
const { openBeamConversationIds, ...persistedState } = state;
|
||||
return persistedState;
|
||||
},
|
||||
|
||||
migrate: (state: any, fromVersion: number): Omit<ModuleBeamState, 'openBeamConversationIds'> => {
|
||||
// 0 -> 1: rename 'scatterPresets' to 'presets'
|
||||
if (state && fromVersion === 0 && !state.presets)
|
||||
return { ...state, presets: state.scatterPresets || [] };
|
||||
@@ -125,6 +157,10 @@ export function useBeamScatterShowLettering() {
|
||||
return useModuleBeamStore((state) => state.scatterShowLettering);
|
||||
}
|
||||
|
||||
export function useIsBeamOpenForConversation(conversationId: DConversationId | null): boolean {
|
||||
return useModuleBeamStore(state => conversationId ? state.openBeamConversationIds[conversationId] ?? false : false);
|
||||
}
|
||||
|
||||
export function updateBeamLastConfig(update: Partial<BeamConfigSnapshot>) {
|
||||
useModuleBeamStore.getState().updateLastConfig(update);
|
||||
}
|
||||
Reference in New Issue
Block a user