Communitygithub.com

MidMeantime/novel-ai-scripting

Guía completa y referencia para scripts de usuario de NovelAI, reglas de TypeScript, referencia de API v1, extensiones de UI, ganchos de generación y configuración de generación de texto. Úsalo al escribir, depurar, refactorizar o revisar scripts de NovelAI, integración con Lorebook, construcción de contexto o código TypeScript de NovelAI.

¿Qué es novel-ai-scripting?

Esta habilidad proporciona instrucciones integrales, referencias de API, reglas de tipado y pautas arquitectónicas para desarrollar **Scripts de Usuario de NovelAI** e interactuar con el motor de generación de texto de NovelAI. Cubre desde la configuración básica del entorno de ejecución (Web Worker aislado) hasta las reglas críticas de TypeScript para evitar errores de compilación, pasando por los espacios de nombres clave de `api.v1` como Storage, UI, Document, Hooks, Generation y Lorebook. También incluye pautas para construir UI sin acceso al DOM utilizando objetos de parte, tokens de tema y fábricas de componentes, así como la estructura estándar de un script con cabecera YAML y registro de ganchos. Es especialmente útil para desarrolladores que necesitan crear, depurar o refactorizar scripts complejos de NovelAI, garantizando que sigan las mejores prácticas y eviten errores comunes como promesas rechazadas en silencio o estado persistente mal gestionado. Soporta todas las versiones de NovelAI que utilizan la API v1 y el entorno de scripts basado en TypeScript.

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Guía de Scripting y TypeScript para NovelAI

Esta habilidad proporciona instrucciones integrales, referencias de API, reglas de tipado y pautas arquitectónicas para desarrollar Scripts de Usuario de NovelAI e interactuar con el motor de generación de texto de NovelAI.


1. Referencia Rápida y Archivos de Documentación

Toda la documentación detallada y los tipos se encuentran en el directorio references/:

  • Directrices de TypeScript — Reglas críticas para evitar fallos en tiempo de ejecución en el intérprete de Web Worker, patrones de tipado, manejo de eventos y casting.
  • Documentación Completa de la API de Scripting — Referencia completa de todos los espacios de nombres de api.v1 (Storage, UI, Document, Hooks, Generation, Lorebook, TTS, etc.).
  • Documentación de Generación de Texto — Información sobre el editor y las funciones del sitio web de NovelAI (modelos, ajustes de contexto, muestreadores, interfaz de Lorebook, ATTG, Aventura de Texto). Rara vez se necesita para el código del script; consúltalo cuando un script deba razonar sobre cómo el editor construye el contexto o qué significa un ajuste.
  • Definiciones de Tipos de Script (.d.ts) — Las definiciones oficiales de TypeScript (de https://novelai.net/scripting/types/script-types.d.ts). Esta es la fuente de verdad para nombres de propiedades y valores permitidos. Cuando difiera de la documentación en prosa, confía en los tipos.
  • Guía JSX + Tipos JSX — Partes de UI basadas en jsx de Preact para visuales personalizados (tablas, gráficos SVG/canvas, widgets en vivo): globales (h, render, hooks, createStore), la lista blanca de elementos/atributos, eventos, canvas y cómo verificar tipos. Solo opt-in: usa JSX solo cuando el usuario lo solicite explícitamente. De lo contrario, construye la UI a partir de partes estándar, incluso para diseños complejos, y como máximo menciona que JSX podría ayudar.
  • Tipos Experimentales — api.v1.editor.block() y api.v1.document.transaction(), controlados por la configuración experimentalScriptingApi del usuario (consulta la Sección 18 de la documentación de la API). No los uses a menos que el usuario diga que los ha habilitado.
  • Sistema de Componentes de UI — Cómo construir UI reutilizable y escalable: tokens, presets de estilo, fábricas de componentes tipados, campos vinculados al almacenamiento, estrategia de renderizado/actualización, diálogos reutilizables. Úsalo como estructura predeterminada para cualquier script con UI.
  • Encabezado de Script y Ejemplo de Configuración — El encabezado de script /*--- ... ---*/ con cada tipo de opción de configuración (cadena, cadena multilínea, número, booleano, selección).
  • Ejemplos oficiales: https://github.com/NovelAI/novelai-script-examples. El escenario Scripting Demo y scripts como Find & Replace, Notes y Smart Summarizer muestran patrones del mundo real.

2. Arquitectura Central y Entorno de Ejecución

  1. Ejecución Aislada en Web Worker:
    • Los scripts se ejecutan dentro de un intérprete de JavaScript aislado dentro de un Web Worker.
    • Los scripts no pueden acceder a elementos arbitrarios del DOM ni realizar solicitudes de red directas.
    • Todas las interacciones con NovelAI ocurren a través de la interfaz asíncrona versionada api.v1.
    • Los setTimeout/clearTimeout globales no están disponibles. Usa await api.v1.timers.setTimeout(...), api.v1.timers.clearTimeout(...) y api.v1.timers.sleep(ms).
  2. Los Scripts Son Transitorios:
    • Los scripts pueden recargarse o descargarse cuando se cambian las historias, cuando se cierra el modal de Scripts de Usuario o cuando se alternan.
    • Nunca almacenes estado persistente en variables de memoria global. Siempre persiste el estado usando api.v1.storage.
  3. Rechazos Silenciosos de Promesas:
    • Las promesas rechazadas no manejadas en el worker no se imprimen en la consola ni en la UI.
    • Siempre envuelve las llamadas asíncronas con try/catch o adjunta manejadores .catch((err) => ...).
  4. Recuperación de Emergencia:
    • Si un script causa inestabilidad, agrega ?noscript=true a la URL de NovelAI para deshabilitar la ejecución del script al cargar.

3. Directrices Críticas de TypeScript para Scripts de NovelAI

El intérprete de Web Worker requiere código TypeScript limpio y estrictamente anotado para evitar errores de compilación/ejecución:

A. Anotaciones de Parámetros Explícitas

Siempre tipa todos los parámetros en funciones estándar y callbacks de flecha:

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

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

B. Casting en Iteración de Objetos

Object.entries() y Object.values() deben castearse explícitamente:

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

C. Comprobaciones de Undefined en Desplazamientos de Array

Array.prototype.shift() devuelve T | undefined:

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

D. Await Solo en Contextos Async

Los constructores de UI y funciones auxiliares que invocan métodos asíncronos de la API deben ser async:

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

4. Espacios de Nombre Clave de la API (api.v1)

Namespace / MétodoPropósito
api.v1.storageAlmacenamiento persistente clave-valor: get, getOrDefault, set, setIfAbsent, has, remove, list (también storyStorage, historyStorage, tempStorage).
api.v1.hooksRegistrar ganchos del ciclo de vida de eventos (onGenerationRequested, onBeforeContextBuild, onContextBuilt, onResponse, onGenerationEnd, onScriptsLoaded, onLorebookEntrySelected, onTextAdventureInput, onHistoryNavigated, onDocumentConvertedToText). Un callback por gancho por script; registrarlo de nuevo lo reemplaza.
api.v1.uiCrear extensiones de UI (scriptPanel, sidebarPanel, lorebookPanel, toolbarButton, contextMenuButton, toolboxOption), modales, ventanas, toasts; updateParts() para cambiar partes individuales por id.
api.v1.documentLeer y editar el documento de la historia por ID de sección (párrafo): scan(), sectionIds(), textFromSelection(), append(), appendParagraph(s)(), insertParagraph(s)After(), updateParagraph(s)(), removeParagraph(s)(), más document.history.
api.v1.editorgenerate(), isBlocked(), selection.get(), y editor.decorations (resaltados, marcadores, widgets).
api.v1.memory / systemPrompt / prefillObtener o establecer la Memoria, el Prompt del Sistema y el Prefill de la historia (establecer requiere storyEdit).
api.v1.generate()Ejecutar generación de texto directa con parámetros y contexto personalizados.
api.v1.generateWithStory()Ejecutar generación usando el contexto y la configuración de la historia actual.
api.v1.lorebookConsultar, actualizar, crear o eliminar entradas y categorías de Lorebook.
api.v1.anObtener o establecer el texto de la Nota del Autor.
api.v1.buildContext()Acceder e inspeccionar el ensamblaje del contexto antes de que se envíe a la IA.
api.v1.configawait api.v1.config.get('name') lee un valor configurable por el usuario declarado en el encabezado del script (ver más abajo).
api.v1.permissionshas() / request() / list(). Solicita documentEdit, storyEdit, lorebookEdit, editorDecorations, clipboardWrite, fileInput, fileDownload (y presetEdit) antes de usar las APIs restringidas.

Encabezado de Script y Configuración

Cada .naiscript comienza con un encabezado YAML dentro de un comentario /*--- ... ---*/ (compatibilityVersion: naiscript-1.0, id, name, version, author, description, memoryLimit, config opcional). Las entradas de config (name, prettyName, type, default, description) aparecen en la pestaña Configuración del modal de Scripts de Usuario, para que los usuarios puedan cambiarlas sin editar el código. Los tipos son string (opcionalmente multiline: true), number (min/max/decimal opcional), boolean y select (options: [{ label, value }]; por defecto la primera opción). Consulta script_config_examples.ts. Lee los valores en tiempo de ejecución con un valor por defecto:

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

5. Plantilla Estándar de Script

Al crear un nuevo script de NovelAI, sigue esta estructura:

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

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

        // 2. Registrar ganchos del ciclo de vida
        // onGenerationRequested se ejecuta antes de construir el contexto; solo puede detener la generación o preparar el estado.
        api.v1.hooks.register('onGenerationRequested', async (params: any) => {
            if (!state.enabled) return;
            // Preparar estado para ganchos posteriores aquí, o devolver { stopGeneration: true } para bloquearlo
        });

        // Para modificar lo que ve el modelo, usa onBeforeContextBuild (memoria, lorebook, AN...)
        // o onContextBuilt (devolver { messages } con el array de mensajes editado).
        api.v1.hooks.register('onContextBuilt', async (params: any) => {
            if (!state.enabled || params.dryRun) return;
            return { messages: params.messages };
        });

        // 3. Registrar UI — siempre usa update(), NO register()
        api.v1.hooks.register('onScriptsLoaded', async () => {
            await api.v1.ui.update([{
                type: 'sidebarPanel' as const,
                id: 'my-script-panel',
                name: 'Herramienta Personalizada',
                content: [
                    { type: 'text' as const, text: `Estado: ${state.enabled ? 'Activo' : 'Desactivado'}` } as any
                ]
            }]);
        });

    } catch (err: any) {
        api.v1.error("Error de Inicialización del Script:", err);
    }
})();

6. Estilos, Tokens de Tema y Funciones Fábrica

Los scripts de NovelAI se ejecutan en un Web Worker aislado sin acceso al DOM. Nunca uses document.createElement, document.head, cloneNode o cualquier API del navegador que toque la página directamente. Toda la UI se construye a partir de objetos de Parte de UI declarativos pasados a api.v1.ui.update().

Arquitectura predeterminada para cualquier script con UI: sigue NovelAI_UI_Component_System.md. Tiene una capa reutilizable y escalable que verifica tipos contra los tipos oficiales:

  1. Namespace y tokens: NS + id(), mapa de tokens de tema COLOR, constantes SPACE/RADIUS
  2. Presets de estilo combinados con sx()
  3. Fábricas de componentes construidas sobre api.v1.ui.part.* con objetos de opciones y variantes
  4. Enlaces field() que mantienen los prefijos de storageKey y las APIs de almacenamiento sincronizados
  5. Un render(), con updateParts/{{templates}} para actualizaciones pequeñas
  6. Diálogos reutilizables confirm()/notify()

Los fragmentos a continuación son la versión mínima de la misma idea. Si el usuario solicita JSX, consulta NovelAI_JSX_Guide.md. Los estilos JSX usan CSS normal y var(--theme-*), no nombres de tokens. No cambies a JSX por tu propia iniciativa.

Presets de Objetos de Estilo

Define objetos de estilo tipados al inicio de tu script y extiéndelos en las partes de UI:

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

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

// Aplicar mediante spread en una Parte de UI:
{ type: 'container' as const, style: CARD_STYLE, content: [...] } as any

Tokens de Tema

En lugar de codificar colores hexadecimales, usa las cadenas de tokens de tema de NovelAI directamente como valores en los objetos style. En tiempo de renderizado, cada token se reemplaza con el valor del tema activo del usuario como un valor literal en línea (por ejemplo, 'bg1' se convierte en un código rgb(...)). Estas no son variables CSS: no hay propiedades personalizadas --theme-* para usar con var(), y el CSS personalizado en otras partes del sitio no puede hacer referencia a ellos. Para valores de tema sin procesar dentro de un script, usa api.v1.theme.get(). (Excepción: según los tipos oficiales, las partes de UI de JSX obtienen propiedades personalizadas --theme-* dentro de su propio shadow DOM).

TokenRol
'bg0'Fondo más profundo/externo
'bg1'Fondo de panel predeterminado
'bg2'Superficie elevada / borde / fondo de botón
'bg3'Superficie resaltada/seleccionada
'textHeadings'Encabezados y texto de título de alto contraste
'textMain'Texto del cuerpo predeterminado
'textDisabled'Texto desactivado/amortiguado
'textPlaceholder'Texto de marcador de posición de entrada
'textHighlight'Color de búsqueda/resaltado
'warning'Estado de advertencia/alerta
'textPrompt', 'textUser', 'textAI', 'textEdit'Colores del texto de la historia
'lowIntensityColor', 'midIntensityColor', 'highIntensityColor'Colores de probabilidad baja/media/alta (como se usan en las probabilidades de tokens)
'default'Familia de fuente del cuerpo (usar en fontFamily)
'headings'Familia de fuente de encabezados (usar en fontFamily)
'code'Familia de fuente de código monoespaciado
'field'Familia de fuente de campo de formulario/entrada

⚠️ Nota sobre 'primary': NovelAI NO tiene un token de tema 'primary' o 'error'. Usar color: 'primary' produce CSS inválido que los navegadores ignoran. Para superficies activas/resaltadas usa 'bg3', para acentos de alto contraste usa 'textHeadings', o proporciona cadenas de color hexadecimal/rgba explícitas (por ejemplo, '#90caf9').

Funciones Fábrica (Reemplaza cloneNode / Plantillas)

Escribe funciones fábrica al inicio de tu script que devuelvan objetos de Parte de UI preestilizados y preconfigurados. Esto evita repetir objetos de estilo en línea en todo el script.

// Fábrica de botón estilizado reutilizable
function makeButton(
    text: string,
    onClick: () => Promise<void>

... [truncado para traducción]

Skills relacionados