System instruction override
This commit is contained in:
parent
64b913374e
commit
d93e3c812e
|
|
@ -11,7 +11,7 @@ import { LoreEditor } from "./lore-editor";
|
||||||
import { Menu } from "./menu";
|
import { Menu } from "./menu";
|
||||||
import { useInputCallback } from "@common/hooks/useInputCallback";
|
import { useInputCallback } from "@common/hooks/useInputCallback";
|
||||||
import Prompt from "../utils/prompt";
|
import Prompt from "../utils/prompt";
|
||||||
import { BookOpen, List, Users, MapPin, BookMarked, FileText, Code, Layers, MessageSquare, Globe, type LucideIcon } from "lucide-preact";
|
import { BookOpen, List, Users, MapPin, BookMarked, FileText, Code, Layers, MessageSquare, Globe, BrainCircuit, type LucideIcon } from "lucide-preact";
|
||||||
|
|
||||||
// Tabs available when a story is selected
|
// Tabs available when a story is selected
|
||||||
const STORY_TABS: { id: Tab; label: string; icon: LucideIcon; right?: boolean }[] = [
|
const STORY_TABS: { id: Tab; label: string; icon: LucideIcon; right?: boolean }[] = [
|
||||||
|
|
@ -31,6 +31,7 @@ const WORLD_TABS: { id: Tab; label: string; icon: LucideIcon; right?: boolean }[
|
||||||
{ id: "lore", label: "Lore", icon: BookMarked },
|
{ id: "lore", label: "Lore", icon: BookMarked },
|
||||||
{ id: "characters", label: "Characters", icon: Users },
|
{ id: "characters", label: "Characters", icon: Users },
|
||||||
{ id: "locations", label: "Locations", icon: MapPin },
|
{ id: "locations", label: "Locations", icon: MapPin },
|
||||||
|
{ id: "system", label: "System", icon: BrainCircuit },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const Editor = () => {
|
export const Editor = () => {
|
||||||
|
|
@ -47,6 +48,11 @@ export const Editor = () => {
|
||||||
dispatch({ type: 'EDIT_SCRATCHPAD', worldId: currentWorld.id, id: currentStory.id, text });
|
dispatch({ type: 'EDIT_SCRATCHPAD', worldId: currentWorld.id, id: currentStory.id, text });
|
||||||
}, [currentStory?.id, currentWorld?.id]);
|
}, [currentStory?.id, currentWorld?.id]);
|
||||||
|
|
||||||
|
const handleSystemOverrideInput = useInputCallback((text: string) => {
|
||||||
|
if (!currentWorld) return;
|
||||||
|
dispatch({ type: 'SET_WORLD_SYSTEM_INSTRUCTION_OVERRIDE', worldId: currentWorld.id, systemInstructionOverride: text || undefined });
|
||||||
|
}, [currentWorld?.id]);
|
||||||
|
|
||||||
const handleTabChange = (tab: Tab) => {
|
const handleTabChange = (tab: Tab) => {
|
||||||
dispatch({ type: 'SET_CURRENT_TAB', tab });
|
dispatch({ type: 'SET_CURRENT_TAB', tab });
|
||||||
};
|
};
|
||||||
|
|
@ -150,6 +156,14 @@ export const Editor = () => {
|
||||||
{currentTab === "prompt" && currentStory && (
|
{currentTab === "prompt" && currentStory && (
|
||||||
<div class={styles.promptPreview} dangerouslySetInnerHTML={{ __html: promptPreview }} />
|
<div class={styles.promptPreview} dangerouslySetInnerHTML={{ __html: promptPreview }} />
|
||||||
)}
|
)}
|
||||||
|
{currentTab === "system" && currentWorld && (
|
||||||
|
<ContentEditable
|
||||||
|
class={styles.editable}
|
||||||
|
value={currentWorld.systemInstructionOverride ?? ''}
|
||||||
|
onInput={handleSystemOverrideInput}
|
||||||
|
placeholder="Override the global system instruction for this world. Leave empty to use the global setting."
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div class={styles.tabs}>
|
<div class={styles.tabs}>
|
||||||
{tabs.filter(tab => hasSelection || tab.id === 'menu').map((tab) => (
|
{tabs.filter(tab => hasSelection || tab.id === 'menu').map((tab) => (
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ export type ChatMessage = LLM.ChatMessage & {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Tab = "story" | "lore" | "characters" | "locations" | "chapters" | "scratchpad" | "prompt" | "menu";
|
export type Tab = "story" | "lore" | "characters" | "locations" | "chapters" | "scratchpad" | "prompt" | "menu" | "system";
|
||||||
|
|
||||||
export enum CharacterRole {
|
export enum CharacterRole {
|
||||||
Protagonist = 'protagonist',
|
Protagonist = 'protagonist',
|
||||||
|
|
@ -84,6 +84,7 @@ export interface World {
|
||||||
characters: Character[];
|
characters: Character[];
|
||||||
locations: Location[];
|
locations: Location[];
|
||||||
stories: Story[];
|
stories: Story[];
|
||||||
|
systemInstructionOverride?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── State ───────────────────────────────────────────────────────────────────
|
// ─── State ───────────────────────────────────────────────────────────────────
|
||||||
|
|
@ -124,6 +125,7 @@ type Action =
|
||||||
| { type: 'REORDER_LORE_ENTRIES'; worldId: string; storyId: string | null; entryIds: string[] }
|
| { type: 'REORDER_LORE_ENTRIES'; worldId: string; storyId: string | null; entryIds: string[] }
|
||||||
// Settings
|
// Settings
|
||||||
| { type: 'SET_SYSTEM_INSTRUCTION'; systemInstruction: string }
|
| { type: 'SET_SYSTEM_INSTRUCTION'; systemInstruction: string }
|
||||||
|
| { type: 'SET_WORLD_SYSTEM_INSTRUCTION_OVERRIDE'; worldId: string; systemInstructionOverride: string | undefined }
|
||||||
| { type: 'SET_CURRENT_TAB'; tab: Tab }
|
| { type: 'SET_CURRENT_TAB'; tab: Tab }
|
||||||
| { type: 'SET_CHAT_OPEN'; open: boolean }
|
| { type: 'SET_CHAT_OPEN'; open: boolean }
|
||||||
// Chat
|
// Chat
|
||||||
|
|
@ -357,6 +359,9 @@ function reducer(state: IState, action: Action): IState {
|
||||||
case 'SET_SYSTEM_INSTRUCTION': {
|
case 'SET_SYSTEM_INSTRUCTION': {
|
||||||
return { ...state, systemInstruction: action.systemInstruction };
|
return { ...state, systemInstruction: action.systemInstruction };
|
||||||
}
|
}
|
||||||
|
case 'SET_WORLD_SYSTEM_INSTRUCTION_OVERRIDE': {
|
||||||
|
return updateWorld(state, action.worldId, w => ({ ...w, systemInstructionOverride: action.systemInstructionOverride }));
|
||||||
|
}
|
||||||
case 'SET_CURRENT_TAB': {
|
case 'SET_CURRENT_TAB': {
|
||||||
return { ...state, currentTab: action.tab };
|
return { ...state, currentTab: action.tab };
|
||||||
}
|
}
|
||||||
|
|
@ -513,6 +518,8 @@ export interface AppState {
|
||||||
enableThinking: boolean;
|
enableThinking: boolean;
|
||||||
bannedTokens: string[];
|
bannedTokens: string[];
|
||||||
systemInstruction: string;
|
systemInstruction: string;
|
||||||
|
/** Effective system instruction: world override if set, otherwise global */
|
||||||
|
effectiveSystemInstruction: string;
|
||||||
dispatch: (action: Action) => void;
|
dispatch: (action: Action) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -557,6 +564,7 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
||||||
enableThinking: state.enableThinking,
|
enableThinking: state.enableThinking,
|
||||||
bannedTokens: state.bannedTokens ?? [],
|
bannedTokens: state.bannedTokens ?? [],
|
||||||
systemInstruction: state.systemInstruction ?? '',
|
systemInstruction: state.systemInstruction ?? '',
|
||||||
|
effectiveSystemInstruction: currentWorld?.systemInstructionOverride ?? state.systemInstruction ?? '',
|
||||||
dispatch,
|
dispatch,
|
||||||
};
|
};
|
||||||
}, [state]);
|
}, [state]);
|
||||||
|
|
|
||||||
|
|
@ -277,10 +277,10 @@ namespace Prompt {
|
||||||
export function formatSystemPrompt(state: AppState, storyTokenBudget: number = 0): string {
|
export function formatSystemPrompt(state: AppState, storyTokenBudget: number = 0): string {
|
||||||
const { currentStory } = state;
|
const { currentStory } = state;
|
||||||
if (!currentStory) {
|
if (!currentStory) {
|
||||||
return state.systemInstruction;
|
return state.effectiveSystemInstruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parts: string[] = [state.systemInstruction];
|
const parts: string[] = [state.effectiveSystemInstruction];
|
||||||
|
|
||||||
parts.push(`# Story Title: ${currentStory.title}`);
|
parts.push(`# Story Title: ${currentStory.title}`);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue