Communitygithub.com

MidMeantime/novel-ai-scripting

Umfassende Anleitung und Referenz für NovelAI-Benutzerskripte, TypeScript-Skriptingregeln, API v1-Referenz, UI-Erweiterungen, Generierungs-Hooks und Textgenerierungskonfiguration. Verwenden Sie dies beim Schreiben, Debuggen, Refaktorieren oder Überprüfen von NovelAI-Skripten, Lorebook-Integration, Kontexterstellung oder NovelAI-TypeScript-Code.

Was ist novel-ai-scripting?

Dieses Skill bietet eine vollständige Anleitung für die Entwicklung von NovelAI-Benutzerskripten mit TypeScript, einschließlich API-Referenzen, Typprüfungsregeln und Architekturrichtlinien. Es ist für Entwickler und Benutzer gedacht, die mit der NovelAI-Textgenerierungsumgebung interagieren, und unterstützt Plattformen wie Claude Code, Cursor und Codex, die auf NovelAI-Integration abzielen. Das Skill erklärt die isolierte Web-Worker-Laufzeitumgebung, die Verwendung des `api.v1`-Namespaces für Speicher, Hooks, UI, Dokumentbearbeitung und Lorebook sowie die wesentlichen TypeScript-Regeln (z. B. explizite Parameterannotationen, Casting bei Object.entries) zur Vermeidung von Laufzeitabstürzen. Es enthält Verweise auf detaillierte Referenzdateien im `references/`-Verzeichnis, offizielle Beispiele und bewährte Methoden für die Zustandspersistenz, Fehlerbehandlung und UI-Erstellung mit deklarativen UI-Part-Objekten und Design-Token. Das Skill betont die Bedeutung der Verwendung von `api.v1.storage` anstelle von globalen Variablen, die Registrierung von Lebenszyklus-Hooks und die Befolgung der Standard-Skript-Boilerplate für zuverlässiges Scripting.

Funktioniert mit~Claude Code✓Codex CLI~Cursor
npx skills add MidMeantime/nai-scripting-skill

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Leitfaden für NovelAI-Scripting & TypeScript-Skill

Dieses Skill bietet umfassende Anweisungen, API-Referenzen, Typisierungsregeln und Architekturrichtlinien für die Entwicklung von NovelAI-Benutzerskripten und die Interaktion mit der NovelAI-Textgenerierungsengine.


1. Kurzreferenz & Dokumentationsdateien

Die gesamte ausführliche Dokumentation und Typen befinden sich im Verzeichnis references/:

  • TypeScript-Richtlinien — Kritische Regeln, um Laufzeitabstürze im Web-Worker-Interpreter zu vermeiden, Typisierungsmuster, Ereignisbehandlung und Casting.
  • Vollständige Scripting-API-Dokumentation — Vollständige Referenz für alle api.v1-Namespaces (Storage, UI, Document, Hooks, Generation, Lorebook, TTS usw.).
  • Textgenerierungsdokumentation — Hintergrundinformationen zu den Editor- und Website-Funktionen von NovelAI (Modelle, Kontexteinstellungen, Sampler, Lorebook-UI, ATTG, Text Adventure). Wird selten für Skriptcode benötigt; konsultieren Sie dies, wenn ein Skript darüber nachdenken muss, wie der Editor den Kontext aufbaut oder was eine Einstellung bedeutet.
  • Skript-Typdefinition (.d.ts) — Die offiziellen TypeScript-Definitionen (von https://novelai.net/scripting/types/script-types.d.ts). Dies ist die Quelle der Wahrheit für Eigenschaftsnamen und zulässige Werte. Wenn es mit der Prosa-Dokumentation in Konflikt steht, vertrauen Sie den Typen.
  • JSX-Leitfaden + JSX-Typen — Preact-basierte jsx-UI-Teile für benutzerdefinierte visuelle Elemente (Tabellen, SVG/Canvas-Diagramme, Live-Widgets): Globalen (h, render, Hooks, createStore), Element/Attribut-Whitelist, Ereignisse, Canvas und Typüberprüfung. Nur bei Opt-in: Verwenden Sie JSX nur, wenn der Benutzer explizit danach fragt. Andernfalls bauen Sie die UI aus Standardteilen auf, selbst für komplexe Layouts, und erwähnen Sie höchstens, dass JSX helfen könnte.
  • Experimentelle Typen — api.v1.editor.block() und api.v1.document.transaction(), geschützt hinter der Einstellung experimentalScriptingApi des Benutzers (siehe Abschnitt 18 der API-Dokumentation). Verwenden Sie diese nicht, es sei denn, der Benutzer sagt, dass er sie aktiviert hat.
  • UI-Komponentensystem — Wie man wiederverwendbare, skalierbare UI erstellt: Token, Stilvorlagen, typisierte Komponentenfabriken, speichergebundene Felder, Render-/Aktualisierungsstrategie, wiederverwendbare Dialoge. Verwenden Sie dies als Standardstruktur für jedes Skript mit UI.
  • Skriptkopf & Konfigurationsbeispiel — Der /*--- ... ---*/-Skriptkopf mit jedem Konfigurationstyp (Zeichenkette, mehrzeilige Zeichenkette, Zahl, Boolean, Auswahl).
  • Offizielle Beispiele: https://github.com/NovelAI/novelai-script-examples. Das Scripting Demo-Szenario und Skripte wie Find & Replace, Notes und Smart Summarizer zeigen reale Muster.

2. Kernarchitektur & Laufzeitumgebung

  1. Isolierte Web-Worker-Ausführung:
    • Skripte werden in einem isolierten JavaScript-Interpreter innerhalb eines Web Workers ausgeführt.
    • Skripte können nicht auf beliebige DOM-Elemente zugreifen oder rohe Netzwerkanfragen stellen.
    • Alle Interaktionen mit NovelAI erfolgen über die versionierte asynchrone Schnittstelle api.v1.
    • Die globalen setTimeout/clearTimeout sind nicht verfügbar. Verwenden Sie await api.v1.timers.setTimeout(...), api.v1.timers.clearTimeout(...) und api.v1.timers.sleep(ms).
  2. Skripte sind temporär:
    • Skripte können neu geladen oder entladen werden, wenn Geschichten wechseln, wenn das Modal für Benutzerskripte geschlossen wird oder wenn sie umgeschaltet werden.
    • Speichern Sie persistenten Zustand niemals in globalen Speichervariablen. Persistieren Sie Zustand immer mit api.v1.storage.
  3. Stille Promise-Ablehnungen:
    • Nicht behandelte abgelehnte Promises im Worker werden nicht in der Konsole oder UI angezeigt.
    • Umgeben Sie asynchrone Aufrufe immer mit try/catch oder fügen Sie .catch((err) => ...)-Handler hinzu.
  4. Notfallwiederherstellung:
    • Wenn ein Skript Instabilität verursacht, hängen Sie ?noscript=true an die NovelAI-URL an, um die Skriptausführung beim Laden zu deaktivieren.

3. Kritische TypeScript-Richtlinien für NovelAI-Skripte

Der Web-Worker-Interpreter erfordert saubere, streng annotierte TypeScript-Code, um Kompilierungs-/Laufzeitfehler zu vermeiden:

A. Explizite Parameterannotationen

Typisieren Sie immer alle Parameter in Standardfunktionen und Pfeil-Callbacks:

// ❌ FALSCH
function processEntry(id, data) { ... }
items.filter(item => item.active);

// ✅ RICHTIG
function processEntry(id: string, data: any): void { ... }
items.filter((item: any) => item.active);

B. Casting bei Objektiteration

Object.entries() und Object.values() müssen explizit gecastet werden:

// ✅ RICHTIG
for (const [key, value] of Object.entries(myObj) as [string, any][]) { ... }
for (const val of Object.values(myObj) as any[]) { ... }

C. Undefiniert-Prüfungen bei Array-Shifts

Array.prototype.shift() gibt T | undefined zurück:

// ✅ RICHTIG
const item = queue.shift();
if (!item) return;

D. Await nur in asynchronen Kontexten

UI-Builder und Hilfsfunktionen, die asynchrone API-Methoden aufrufen, müssen async sein:

// ✅ RICHTIG
async function loadUserData(): Promise<void> {
    const hasData = await api.v1.storage.has('userData');
    if (hasData) {
        const data = await api.v1.storage.get('userData');
    }
}

4. Wichtige API-Namespaces (api.v1)

Namespace / MethodeZweck
api.v1.storagePersistenter Schlüssel-Wert-Speicher: get, getOrDefault, set, setIfAbsent, has, remove, list (auch storyStorage, historyStorage, tempStorage).
api.v1.hooksLebenszyklus-Hooks für Ereignisse registrieren (onGenerationRequested, onBeforeContextBuild, onContextBuilt, onResponse, onGenerationEnd, onScriptsLoaded, onLorebookEntrySelected, onTextAdventureInput, onHistoryNavigated, onDocumentConvertedToText). Ein Callback pro Hook pro Skript; erneutes Registrieren ersetzt den vorherigen.
api.v1.uiUI-Erweiterungen erstellen (scriptPanel, sidebarPanel, lorebookPanel, toolbarButton, contextMenuButton, toolboxOption), Modals, Fenster, Toasts; updateParts() um einzelne Teile nach id zu ändern.
api.v1.documentDas Geschichtsdokument nach Abschnitts-ID (Paragraf) lesen und bearbeiten: scan(), sectionIds(), textFromSelection(), append(), appendParagraph(s)(), insertParagraph(s)After(), updateParagraph(s)(), removeParagraph(s)(), sowie document.history.
api.v1.editorgenerate(), isBlocked(), selection.get() und editor.decorations (Hervorhebungen, Markierungen, Widgets).
api.v1.memory / systemPrompt / prefillDen Memory, System-Prompt und Prefill der Geschichte abrufen oder setzen (Setzen erfordert storyEdit).
api.v1.generate()Direkte Textgenerierung mit benutzerdefinierten Parametern und Kontext ausführen.
api.v1.generateWithStory()Generierung mit dem aktuellen Geschichtskontext und den Einstellungen ausführen.
api.v1.lorebookLorebook-Einträge und -Kategorien abfragen, aktualisieren, erstellen oder löschen.
api.v1.anDen Text der Autorennotiz abrufen oder setzen.
api.v1.buildContext()Auf die Kontextzusammenstellung zugreifen und sie überprüfen, bevor sie an die KI gesendet wird.
api.v1.configawait api.v1.config.get('name') liest einen benutzerkonfigurierbaren Wert, der im Skriptkopf deklariert ist (siehe unten).
api.v1.permissionshas() / request() / list(). Fordern Sie documentEdit, storyEdit, lorebookEdit, editorDecorations, clipboardWrite, fileInput, fileDownload (und presetEdit) an, bevor Sie die geschützten APIs verwenden.

Skriptkopf & Konfiguration

Jedes .naiscript beginnt mit einem YAML-Kopf in einem /*--- ... ---*/-Kommentar (compatibilityVersion: naiscript-1.0, id, name, version, author, description, memoryLimit, optional config). config-Einträge (name, prettyName, type, default, description) erscheinen im Config-Tab des Benutzerskript-Modals, sodass Benutzer sie ändern können, ohne Code zu bearbeiten. Typen sind string (optional multiline: true), number (optional min/max/decimal), boolean und select (options: [{ label, value }]; Standard ist die erste Option). Siehe script_config_examples.ts. Lesen Sie Werte zur Laufzeit mit einem Fallback:

const openOnCreate: boolean = (await api.v1.config.get('open_on_create')) ?? true;

5. Standard-Skript-Boilerplate

Folgen Sie beim Erstellen eines neuen NovelAI-Skripts dieser Struktur:

(async () => {
    try {
        const STORAGE_KEY = "my_custom_script_data";

        // 1. Persistenten Zustand initialisieren
        const state = await api.v1.storage.getOrDefault(STORAGE_KEY, { enabled: true, count: 0 });
        await api.v1.storage.setIfAbsent(STORAGE_KEY, state);

        // 2. Lebenszyklus-Hooks registrieren
        // onGenerationRequested wird vor der Kontexterstellung ausgeführt; es kann nur die Generierung stoppen oder den Zustand vorbereiten.
        api.v1.hooks.register('onGenerationRequested', async (params: any) => {
            if (!state.enabled) return;
            // Bereiten Sie hier den Zustand für spätere Hooks vor, oder geben Sie { stopGeneration: true } zurück, um sie zu blockieren
        });

        // Verwenden Sie onBeforeContextBuild (Memory, Lorebook, AN...), um zu ändern, was das Modell sieht,
        // oder onContextBuilt (return { messages } mit dem bearbeiteten Nachrichtenarray).
        api.v1.hooks.register('onContextBuilt', async (params: any) => {
            if (!state.enabled || params.dryRun) return;
            return { messages: params.messages };
        });

        // 3. UI registrieren — immer update(), NICHT register() verwenden
        api.v1.hooks.register('onScriptsLoaded', async () => {
            await api.v1.ui.update([{
                type: 'sidebarPanel' as const,
                id: 'my-script-panel',
                name: 'Custom Tool',
                content: [
                    { type: 'text' as const, text: `Status: ${state.enabled ? 'Active' : 'Disabled'}` } as any
                ]
            }]);
        });

    } catch (err: any) {
        api.v1.error("Script Initialization Error:", err);
    }
})();

6. Styling, Theme-Token & Factory-Funktionen

NovelAI-Skripte laufen in einem isolierten Web Worker mit keinem Zugriff auf das DOM. Verwenden Sie niemals document.createElement, document.head, cloneNode oder eine andere Browser-API, die direkt die Seite berührt. Die gesamte UI wird aus deklarativen UI-Part-Objekten erstellt, die an api.v1.ui.update() übergeben werden.

Standardarchitektur für jedes Skript mit UI: Befolgen Sie NovelAI_UI_Component_System.md. Es hat eine wiederverwendbare, skalierbare Schichtung, die gegen die offiziellen Typen typgeprüft wird:

  1. Namespace und Token: NS + id(), COLOR-Theme-Token-Karte, SPACE/RADIUS-Konstanten
  2. Stilvorlagen kombiniert mit sx()
  3. Komponentenfabriken, die auf api.v1.ui.part.* mit Optionsobjekten und Varianten aufbauen
  4. field()-Bindungen, die storageKey-Präfixe und Speicher-APIs synchron halten
  5. Ein render(), mit updateParts/{{templates}} für kleine Aktualisierungen
  6. Wiederverwendbare confirm()/notify()-Dialoge

Die folgenden Code-Snippets sind die minimale Version derselben Idee. Wenn der Benutzer nach JSX fragt, siehe NovelAI_JSX_Guide.md. JSX-Stile verwenden normales CSS und var(--theme-*), keine Token-Namen. Wechseln Sie nicht aus eigener Initiative zu JSX.

Stilobjekt-Vorlagen

Definieren Sie typisierte Stilobjekte am Anfang Ihres Skripts und verteilen Sie sie auf UI-Teile:

const CARD_STYLE: Record<string, string> = {
    backgroundColor: 'bg1',      // Theme-Token
    border: '1px solid bg2',     // Theme-Token
    borderRadius: '6px',
    padding: '10px',
    margin: '6px 0',
};

const DANGER_STYLE: Record<string, string> = {
    ...CARD_STYLE,
    borderColor: 'warning',
};

// Anwenden per Spread in einem UI-Teil:
{ type: 'container' as const, style: CARD_STYLE, content: [...] } as any

Theme-Token

Anstatt Hex-Farben fest zu codieren, verwenden Sie NovelAI-Theme-Token-Zeichenfolgen direkt als Werte in style-Objekten. Zur Renderzeit wird jedes Token durch den aktiven Theme-Wert des Benutzers als wörtlicher Inline-Wert ersetzt (z.B. wird 'bg1' zu einem rgb(...)-Code). Dies sind keine CSS-Variablen: Es gibt keine --theme-*-Custom-Properties zur Verwendung mit var(), und benutzerdefiniertes CSS an anderer Stelle auf der Seite kann nicht darauf verweisen. Für rohe Theme-Werte innerhalb eines Skripts verwenden Sie api.v1.theme.get(). (Ausnahme: laut den offiziellen Typen erhalten JSX-UI-Teile --theme-*-Custom-Properties in ihrem eigenen Shadow-DOM.)

TokenRolle
'bg0'Tiefster / äußerster Hintergrund
'bg1'Standard-Panel-Hintergrund
'bg2'Erhöhte Oberfläche / Rahmen / Button-Hintergrund
'bg3'Hervorgehobene / ausgewählte Oberfläche
'textHeadings'Kontrastreiche Überschriften und Titeltexte
'textMain'Standard-Textkörper
'textDisabled'Deaktivierter / abgeschwächter Text
'textPlaceholder'Platzhaltertext in Eingabefeldern
'textHighlight'Such- / Hervorhebungsfarbe
'warning'Warn- / Alarmstatus
'textPrompt', 'textUser', 'textAI', 'textEdit'Geschichtstextfarben
'lowIntensityColor', 'midIntensityColor', 'highIntensityColor'Niedrig-/Mittel-/Hochwahrscheinlichkeitsfarben (wie bei Token-Wahrscheinlichkeiten verwendet)
'default'Schriftfamilie für Textkörper (in fontFamily verwenden)
'headings'Schriftfamilie für Überschriften (in fontFamily verwenden)
'code'Monospace-Schriftfamilie für Code
'field'Schriftfamilie für Formular-/Eingabefelder

⚠️ Hinweis zu 'primary': NovelAI hat KEINEN 'primary'- oder 'error'-Theme-Token. Die Verwendung von color: 'primary' erzeugt ungültiges CSS, das von Browsern ignoriert wird. Verwenden Sie für aktive/hervorgehobene Oberflächen 'bg3', für kontrastreiche Akzente 'textHeadings' oder geben Sie explizite Hex-/RGBA-Farbzeichenfolgen an (z.B. '#90caf9').

Factory-Funktionen (Ersetzt cloneNode / Vorlagen)

Schreiben Sie Factory-Funktionen am Anfang Ihres Skripts, die vorgestylte, vorkonfigurierte UI-Part-Objekte zurückgeben. Dies vermeidet wiederholte Inline-Stilobjekte im gesamten Skript.

// Wiederverwendbare Factory für gestylte Buttons
function makeButton(
    text: string,
    onClick: () => Promise<void>,
    disabled: boolean = false
): any {
    return {
        type: 'button' as const,
        label: text,
        disabled: disabled,
        style: {
            backgroundColor: 'bg2',
            color: 'textMain',
            border: '1px solid bg3',
            borderRadius: '4px',
            padding: '6px 12px',
            cursor: disabled ? 'not-allowed' : 'pointer',
        },
        onClick: disabled ? undefined : onClick,
    };
}

7. Relevante Konzepte aus der Textgenerierungsdokumentation

Für Skripte, die Generierungseinstellungen analysieren oder ändern, beachten Sie die folgenden Konzepte aus der Textgenerierungsdokumentation:

  • Modelle: Kayra, Clio, Krake, Euterpe, Sigurd, Hype-Bot – jedes hat unterschiedliche Kontextlängen und Fähigkeiten.
  • Parameter: temperature, top_p, top_k, top_a, tail_free_sampling, repetition_penalty, repetition_penalty_range, repetition_penalty_frequency, repetition_penalty_presence, mirostat_tau, mirostat_lr, order (Sampler-Reihenfolge-Array).
  • Einstellungen: model, max_length, min_length, num_outputs, phrase_rep_pen, bad_words_ids, stop_sequences, generate_until_sentence, use_cache, use_string, logit_bias_exp, repetition_penalty_whitelist, repetition_penalty_whitelist_character, temperature_last, skew, smoothing_factor, smoothing_factor_2, prefix_bias, repetition_penalty_range_bias.

8. Verweise für Benutzerskripte & API

Lorebook-Integration: api.v1.lorebook bietet entries(), get(), create(), update(), delete(), categories(), sowie keys() und entries() mit Filterung nach Kategorie, aktiviertem Zustand, Bereichen und Teilzeichenfolgen. Hooks onLorebookEntrySelected (wird ausgelöst, wenn ein Eintrag im Lorebook-Modal ausgewählt wird) und onBeforeContextBuild (um die Lorebook-Entry-Liste vor der Kontexterstellung zu ändern) bieten Ereignisgesteuerte Integration.

Nützliche Skriptbeispiele: Siehe das offizielle Repository https://github.com/NovelAI/novelai-script-examples. Die Datei script-panel.ts zeigt die Panel-Erstellung, toolbar-button.ts zeigt die Menüschaltflächenerstellung und generation-countdown.ts zeigt die Verwendung von Timern und Einstellungspersistenz.

API-Änderungen protokollieren (aus dem offiziellen Repository von NovelAI):

  • 23. Mai 2024: Scripting-Update, das Ereignisse und Hooks hinzufügt.
  • 8. April 2024: Verbesserungen des Konglomeratsystems, D&D-Anpassungen, Korrektur-Logging.
  • 18. März 2024: Veralteter currentGenerationRequest, neuer generateWithStory()-Aufruf, Änderungen an onContextBuilt/onResponse.
  • 22. Februar 2024: Erstes Scripting-Update.

Häufige Fehlerbehandlung

Verwenden Sie innerhalb von Skripten dedizierte Catch-Blöcke:

try {
    const result = await someRiskyCall();
} catch (err: any) {
    api.v1.error("Fehler in riskyCall:", err.toString());
}

Zusammenfassung: Dieses Skill bietet das vollständige Wissen, das zum Schreiben zuverlässiger NovelAI-Benutzerskripte erforderlich ist. Konsultieren Sie die verlinkten Dateien in references/ für ausführliche Informationen zu bestimmten Namespaces, JSX-Stilen und erweiterten UI-Mustern. Bitten Sie den Benutzer bei Bedarf um Klärung der Anforderungen.

Verwandte Skills