Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
4.1 KiB
4.1 KiB
Phase 4 — Scripting (AI Dungeon-compatible JavaScript)
Goal: real AI Dungeon scripts import and run: the three modifier hooks, persistent state,
and the scripting API surface.
JS runtime
- Embed a JS engine in Python: quickjs (preferred; check Windows wheel availability at implementation time; fallback: py-mini-racer, or Node subprocess as last resort).
- Sandbox matching AI Dungeon's documented limits: each hook runs isolated, 16 MB memory cap, 2-second timeout; no filesystem/network/process access; script errors captured and surfaced in the UI, never crash a turn.
AI Dungeon scripting model (compatibility target)
(Per official docs: help.aidungeon.com/faq/how-do-i-write-scripts-and-use-scripting)
Three lifecycle hooks — onInput, onModelContext, onOutput. Each script defines a modifier
and must call it as its last line:
const modifier = (text) => {
// script logic
return { text, stop }
}
modifier(text)
- onInput — modifies player input before context construction.
- onModelContext — modifies the assembled text sent to the model.
- onOutput — modifies the model output before it is shown/stored.
- Shared Library — code prepended to all three slots.
Return contract:
{ text, stop };stop: truefrom onInput prevents the AI call.- Empty-string
textfrom onInput/onOutput → user-facing error (replicate this behavior).
Globals provided (exact names from docs):
text— hook input (player input / context / AI response respectively).state— persisted per adventure across turns (Adventure.script_state); includesstate.memory,state.message(shown as a UI notice),state.placeholders.state.memoryslots:context(prepended to context),authorsNote(near end, before latest response),frontMemory(inserted right after the player's input).history— array of recent actions:{ text, rawText, type }.storyCards— array of{ id, keys, entry, type }, backed by the adventure's story cards.- Story card functions:
addStoryCard(keys, entry, type)→ index (orfalseon duplicate),updateStoryCard(index, keys, entry, type)andremoveStoryCard(index)→ throw if absent. - Legacy aliases for older scripts:
worldInfo/worldEntries,addWorldEntry,updateWorldEntry,removeWorldEntrymapped onto the storyCards implementation. info—{ actionCount, characterNames, memoryLength, maxChars }.log(message)/console.log— captured per turn, shown in a script log panel.
Pipeline integration
player input → INPUT modifier → format & store
context build → CONTEXT modifier → (snapshot includes pre- and post-script versions in Insights)
AI response → OUTPUT modifier → store & render
- Insights (Phase 3) extended: show context before vs after the context modifier (diff view), and script log output per turn.
Script management UI
- Scripts page: create/edit scripts with a code editor (CodeMirror), one tab per slot (Library / Input / Context / Output), description field.
- Attach scripts to scenarios; adventures inherit at creation. Enable/disable per adventure.
- Test-run a script against sample text without an AI call.
Import / Export
- Scripts: export/import as JSON bundle
{ name, library, input, context, output }and as raw.jsfiles per slot (matching how AI Dungeon scripts circulate — paste or file). - Scenarios: export/import JSON including prompt, memory, author's note, story cards, and attached scripts. Accept AI Dungeon scenario export JSON where format is known; map fields best-effort and report anything unmapped.
Exit criteria
Paste a real AI Dungeon script (e.g. a simple input modifier + state counter + world entry manipulation) and it runs unmodified across turns; state persists; export a scenario with scripts, re-import it into a fresh database, and play it.