1
0
Fork 0

System instruction override

This commit is contained in:
Pabloader 2026-04-07 07:52:59 +00:00
parent 64b913374e
commit d93e3c812e
3 changed files with 26 additions and 4 deletions

View File

@ -11,7 +11,7 @@ import { LoreEditor } from "./lore-editor";
import { Menu } from "./menu";
import { useInputCallback } from "@common/hooks/useInputCallback";
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
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: "characters", label: "Characters", icon: Users },
{ id: "locations", label: "Locations", icon: MapPin },
{ id: "system", label: "System", icon: BrainCircuit },
];
export const Editor = () => {
@ -47,6 +48,11 @@ export const Editor = () => {
dispatch({ type: 'EDIT_SCRATCHPAD', worldId: currentWorld.id, id: currentStory.id, text });
}, [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) => {
dispatch({ type: 'SET_CURRENT_TAB', tab });
};
@ -150,6 +156,14 @@ export const Editor = () => {
{currentTab === "prompt" && currentStory && (
<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 class={styles.tabs}>
{tabs.filter(tab => hasSelection || tab.id === 'menu').map((tab) => (

View File

@ -11,7 +11,7 @@ export type ChatMessage = LLM.ChatMessage & {
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 {
Protagonist = 'protagonist',
@ -84,6 +84,7 @@ export interface World {
characters: Character[];
locations: Location[];
stories: Story[];
systemInstructionOverride?: string;
}
// ─── State ───────────────────────────────────────────────────────────────────
@ -124,6 +125,7 @@ type Action =
| { type: 'REORDER_LORE_ENTRIES'; worldId: string; storyId: string | null; entryIds: string[] }
// Settings
| { 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_CHAT_OPEN'; open: boolean }
// Chat
@ -357,6 +359,9 @@ function reducer(state: IState, action: Action): IState {
case 'SET_SYSTEM_INSTRUCTION': {
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': {
return { ...state, currentTab: action.tab };
}
@ -513,6 +518,8 @@ export interface AppState {
enableThinking: boolean;
bannedTokens: string[];
systemInstruction: string;
/** Effective system instruction: world override if set, otherwise global */
effectiveSystemInstruction: string;
dispatch: (action: Action) => void;
}
@ -557,6 +564,7 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
enableThinking: state.enableThinking,
bannedTokens: state.bannedTokens ?? [],
systemInstruction: state.systemInstruction ?? '',
effectiveSystemInstruction: currentWorld?.systemInstructionOverride ?? state.systemInstruction ?? '',
dispatch,
};
}, [state]);

View File

@ -277,10 +277,10 @@ namespace Prompt {
export function formatSystemPrompt(state: AppState, storyTokenBudget: number = 0): string {
const { currentStory } = state;
if (!currentStory) {
return state.systemInstruction;
return state.effectiveSystemInstruction;
}
const parts: string[] = [state.systemInstruction];
const parts: string[] = [state.effectiveSystemInstruction];
parts.push(`# Story Title: ${currentStory.title}`);