Show usernames in chat
This commit is contained in:
parent
ed83c9a0b8
commit
ae0d232331
|
|
@ -2,7 +2,7 @@ import { ContentEditable } from "@common/components/ContentEditable";
|
|||
import { highlight } from "@common/highlight";
|
||||
import { useInputState } from "@common/hooks/useInputState";
|
||||
import clsx from "clsx";
|
||||
import { Check, ChevronsRight, Edit2, RefreshCw, Sparkles, Trash2, X } from "lucide-preact";
|
||||
import { Check, ChevronsRight, Edit2, GitFork, RefreshCw, Sparkles, Trash2, X } from "lucide-preact";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
import styles from '../assets/chat-sidebar.module.css';
|
||||
import sidebarStyles from '../assets/sidebar.module.css';
|
||||
|
|
@ -20,6 +20,8 @@ interface RoleHeaderProps {
|
|||
}
|
||||
|
||||
const RoleHeader = ({ message, chatMessages }: RoleHeaderProps) => {
|
||||
const { currentWorld, userName } = useAppState();
|
||||
|
||||
const toolName = useMemo(() => {
|
||||
if (message.role !== 'tool') return;
|
||||
for (const m of chatMessages.toReversed()) {
|
||||
|
|
@ -29,12 +31,28 @@ const RoleHeader = ({ message, chatMessages }: RoleHeaderProps) => {
|
|||
}
|
||||
}, [message, chatMessages]);
|
||||
|
||||
let displayName: string = message.role;
|
||||
let roleLabel = null;
|
||||
|
||||
if (message.role === 'tool' && toolName) {
|
||||
displayName = toolName;
|
||||
roleLabel = message.role;
|
||||
} else if (currentWorld?.chatOnly) {
|
||||
if (message.role === 'user' && userName) {
|
||||
displayName = userName;
|
||||
roleLabel = message.role;
|
||||
} else if (message.role === 'assistant' && currentWorld.title) {
|
||||
displayName = currentWorld.title;
|
||||
roleLabel = message.role;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={styles.role}>
|
||||
{message.role}
|
||||
{toolName && (
|
||||
{displayName}
|
||||
{roleLabel && (
|
||||
<span class={styles.toolBadge}>
|
||||
{toolName}
|
||||
{message.role}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -362,6 +380,16 @@ export const ChatPanel = () => {
|
|||
});
|
||||
}, [currentStory, currentWorld, dispatch]);
|
||||
|
||||
const handleForkChat = useCallback((messageId: string) => {
|
||||
if (!currentStory || !currentWorld) return;
|
||||
dispatch({
|
||||
type: 'DUPLICATE_STORY',
|
||||
worldId: currentWorld.id,
|
||||
id: currentStory.id,
|
||||
upToMessageId: messageId,
|
||||
});
|
||||
}, [currentStory, currentWorld, dispatch]);
|
||||
|
||||
const handleStartEdit = useCallback((message: ChatMessage) => {
|
||||
setEditingMessageId(message.id);
|
||||
setEditingContent(message.content);
|
||||
|
|
@ -416,6 +444,15 @@ export const ChatPanel = () => {
|
|||
|
||||
{!isLoading && canEdit && (
|
||||
<div class={styles.messageActions}>
|
||||
{currentWorld?.chatOnly && (
|
||||
<button
|
||||
class={styles.iconButton}
|
||||
onClick={() => handleForkChat(message.id)}
|
||||
title="Fork chat up to this message"
|
||||
>
|
||||
<GitFork size={12} />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
class={styles.iconButton}
|
||||
onClick={() => handleStartEdit(message)}
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ const WorldItem = ({
|
|||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div class={clsx(styles.itemWrapper, isWorldActive && styles.active)}>
|
||||
<div class={clsx(styles.itemWrapper, isWorldActive && styles.active)} onClick={isExpanded.setTrue}>
|
||||
<button class={styles.expandButton} onClick={toggleExpand} title={isExpanded.value ? 'Collapse' : 'Expand'}>
|
||||
{isExpanded.value ? <ChevronDown size={12} /> : <ChevronRight size={12} />}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ type Action =
|
|||
| { type: 'EDIT_SCRATCHPAD'; worldId: string; id: string; text: string }
|
||||
| { type: 'DELETE_STORY'; worldId: string; id: string }
|
||||
| { type: 'SELECT_STORY'; worldId: string; id: string }
|
||||
| { type: 'DUPLICATE_STORY'; worldId: string; id: string }
|
||||
| { type: 'DUPLICATE_STORY'; worldId: string; id: string; upToMessageId?: string }
|
||||
// Story lore
|
||||
| { type: 'ADD_LORE_ENTRY'; worldId: string; storyId: string | null; entry: LoreEntry }
|
||||
| { type: 'EDIT_LORE_ENTRY'; worldId: string; storyId: string | null; entryId: string; updates: Partial<LoreEntry> }
|
||||
|
|
@ -278,7 +278,6 @@ function reducer(state: IState, action: Action): IState {
|
|||
worlds: [...state.worlds, world],
|
||||
currentWorldId: world.id,
|
||||
currentStoryId: null,
|
||||
currentTab: 'menu',
|
||||
};
|
||||
}
|
||||
case 'RENAME_WORLD': {
|
||||
|
|
@ -299,7 +298,6 @@ function reducer(state: IState, action: Action): IState {
|
|||
...state,
|
||||
currentWorldId: action.worldId,
|
||||
currentStoryId: null,
|
||||
currentTab: 'menu',
|
||||
};
|
||||
}
|
||||
case 'CREATE_STORY': {
|
||||
|
|
@ -320,7 +318,6 @@ function reducer(state: IState, action: Action): IState {
|
|||
...updateWorld(state, action.worldId, w => ({ ...w, stories: [...w.stories, story] })),
|
||||
currentWorldId: action.worldId,
|
||||
currentStoryId: story.id,
|
||||
currentTab: 'menu',
|
||||
};
|
||||
}
|
||||
case 'RENAME_STORY': {
|
||||
|
|
@ -347,20 +344,24 @@ function reducer(state: IState, action: Action): IState {
|
|||
};
|
||||
}
|
||||
case 'SELECT_STORY': {
|
||||
const world = state.worlds.find(w => w.id === action.worldId);
|
||||
return {
|
||||
...state,
|
||||
currentWorldId: action.worldId,
|
||||
currentStoryId: action.id,
|
||||
currentTab: 'menu',
|
||||
};
|
||||
}
|
||||
case 'DUPLICATE_STORY': {
|
||||
const world = state.worlds.find(w => w.id === action.worldId);
|
||||
const original = world?.stories.find(s => s.id === action.id);
|
||||
if (!original) return state;
|
||||
const firstMessage = original.chatMessages[0];
|
||||
const chatMessages = world?.chatOnly && firstMessage && firstMessage.role === 'assistant' ? [firstMessage] : [];
|
||||
let chatMessages: ChatMessage[];
|
||||
if (action.upToMessageId) {
|
||||
const idx = original.chatMessages.findIndex(m => m.id === action.upToMessageId);
|
||||
chatMessages = idx !== -1 ? original.chatMessages.slice(0, idx + 1) : [...original.chatMessages];
|
||||
} else {
|
||||
const firstMessage = original.chatMessages[0];
|
||||
chatMessages = world?.chatOnly && firstMessage && firstMessage.role === 'assistant' ? [firstMessage] : [];
|
||||
}
|
||||
const newStory: Story = {
|
||||
id: crypto.randomUUID(),
|
||||
title: `${original.title} (Copy)`,
|
||||
|
|
@ -375,7 +376,6 @@ function reducer(state: IState, action: Action): IState {
|
|||
return {
|
||||
...updateWorld(state, action.worldId, w => ({ ...w, stories: [...w.stories, newStory] })),
|
||||
currentStoryId: newStory.id,
|
||||
currentTab: 'menu',
|
||||
};
|
||||
}
|
||||
case 'ADD_LORE_ENTRY': {
|
||||
|
|
@ -582,7 +582,6 @@ function reducer(state: IState, action: Action): IState {
|
|||
worlds: [...state.worlds, world],
|
||||
currentWorldId: world.id,
|
||||
currentStoryId: null,
|
||||
currentTab: 'menu',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue