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 (vonhttps://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()undapi.v1.document.transaction(), geschützt hinter der EinstellungexperimentalScriptingApides 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
- 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/clearTimeoutsind nicht verfügbar. Verwenden Sieawait api.v1.timers.setTimeout(...),api.v1.timers.clearTimeout(...)undapi.v1.timers.sleep(ms).
- 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.
- Stille Promise-Ablehnungen:
- Nicht behandelte abgelehnte Promises im Worker werden nicht in der Konsole oder UI angezeigt.
- Umgeben Sie asynchrone Aufrufe immer mit
try/catchoder fügen Sie.catch((err) => ...)-Handler hinzu.
- Notfallwiederherstellung:
- Wenn ein Skript Instabilität verursacht, hängen Sie
?noscript=truean die NovelAI-URL an, um die Skriptausführung beim Laden zu deaktivieren.
- Wenn ein Skript Instabilität verursacht, hängen Sie
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 / Methode | Zweck |
|---|---|
api.v1.storage | Persistenter Schlüssel-Wert-Speicher: get, getOrDefault, set, setIfAbsent, has, remove, list (auch storyStorage, historyStorage, tempStorage). |
api.v1.hooks | Lebenszyklus-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.ui | UI-Erweiterungen erstellen (scriptPanel, sidebarPanel, lorebookPanel, toolbarButton, contextMenuButton, toolboxOption), Modals, Fenster, Toasts; updateParts() um einzelne Teile nach id zu ändern. |
api.v1.document | Das 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.editor | generate(), isBlocked(), selection.get() und editor.decorations (Hervorhebungen, Markierungen, Widgets). |
api.v1.memory / systemPrompt / prefill | Den 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.lorebook | Lorebook-Einträge und -Kategorien abfragen, aktualisieren, erstellen oder löschen. |
api.v1.an | Den 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.config | await api.v1.config.get('name') liest einen benutzerkonfigurierbaren Wert, der im Skriptkopf deklariert ist (siehe unten). |
api.v1.permissions | has() / 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:
- Namespace und Token:
NS+id(),COLOR-Theme-Token-Karte,SPACE/RADIUS-Konstanten- Stilvorlagen kombiniert mit
sx()- Komponentenfabriken, die auf
api.v1.ui.part.*mit Optionsobjekten und Varianten aufbauenfield()-Bindungen, diestorageKey-Präfixe und Speicher-APIs synchron halten- Ein
render(), mitupdateParts/{{templates}}für kleine Aktualisierungen- Wiederverwendbare
confirm()/notify()-DialogeDie 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.)
| Token | Rolle |
|---|---|
'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 voncolor: '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, neuergenerateWithStory()-Aufruf, Änderungen anonContextBuilt/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.