Skip to content

Fly3-r/SecretsEnabled

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SecretsEnabled for AI Dungeon

SecretsEnabled Cover Image

SecretsEnabled is an AI Dungeon script for handling hidden character secrets without exposing raw secret text in normal story context.

Go to Install

Made by Fly3_r

How does it work?

SecretsEnabled keeps character secrets out of normal story context so the AI is much less likely to blurt them out too early. Instead of feeding the secret itself to the model right away, it only feeds the character's hidden behavior. The AI is guided without being directly told to reveal why.

A secret becomes active when the script sees the right character and the right trigger in the scene. Once activated, it stays active for a short time, so the hidden behavior can continue naturally across the next few turns instead of disappearing immediately. If the same character and trigger show up again, that timer refreshes.

While a secret is active, the script also checks whether the scene seems to satisfy the reveal condition. Each time that reveal condition is judged true, the card's Matches progress goes up by one. Once that progress reaches the required number, the real Secret: text is finally allowed into hidden context for the AI to use.

To summarise:

  • The secret itself stays hidden.
  • Only the hidden behavior is applied at first.
  • The secret becomes warm for a few turns after it is triggered.
  • The script watches for reveal-condition moments while it is warm.
  • After enough matching reveal moments, the real secret is unlocked for the AI.

Install

Within your scenario go to the details tab and select EDIT SCRIPTS, then:

  1. Inside the Input script screen paste:
const modifier = (text) => {
  if (typeof SecretsEnabled !== "function") {
    return { text };
  }
  return { text: SecretsEnabled("input", text) };
};
modifier(text);
  1. Inside the Context script screen paste:
const modifier = (text) => {
  if (typeof SecretsEnabled !== "function") {
    return { text, stop: false };
  }
  const currentStop = typeof stop === "undefined" ? false : stop;
  const result = SecretsEnabled("context", text, currentStop);
  return {
    text: result[0],
    stop: result[1],
  };
};
modifier(text);
  1. Inside the Output script screen paste:
const modifier = (text) => {
  if (typeof SecretsEnabled !== "function") {
    return { text };
  }
  return { text: SecretsEnabled("output", text) };
};
modifier(text);
  1. Copy the entire text from SecretsEnabled/src/Library.js (GitHub link) and paste it into the Library script screen.

Secret story cards

The story card should use the custom type Secret, and the body can just contain the key/value lines.

SecretsEnabled Secret Card Example

Character: Mira
SecretId: afraid_of_water
Triggers: water, river, lake, ocean, drowning, boat, bridge, storm
Secret: Mira almost drowned as child and now has a phobia of water
Behavior: Avoids getting close to deep water, hesitates before crossing, downplays discomfort, redirects the conversation
Reveal: Do not state the reason unless she is cornered, forced, or directly confronted.
Matches: 3
Aliases: Mira Vale

Supported fields:

  • Character
  • SecretId
  • Secret
  • Triggers
  • Behavior
  • Reveal
  • Matches
  • Aliases
  • Threshold

Required fields:

  • story card type: Secret
  • Character
  • Triggers
  • Behavior

Notes:

  • Matches is the reveal threshold.
  • Stage is still accepted as a legacy fallback.
  • Secret: is only forwarded to the AI after the reveal threshold is reached.
  • The story card description field is now used as a persistent notes area for secret runtime state.

Settings story card

SecretsEnabled uses a dedicated settings story card as the main user-facing config surface.

If use_settings_storycard is enabled in the script defaults and no settings card exists yet, the script will create one automatically using this shape:

SecretsEnabledSettings:
enabled: true
use_settings_storycard: true
activation_duration_in_turns: 3
max_active_secrets: 4
min_trigger_score: 1
history_turns_check: 3
use_ai_reveal_judge: true
fallback_keyword_judge: true
diag_output: false
max_judge_log_entries: 25

The script reads the settings card every turn and rebuilds its runtime config from it.

Important behavior:

  • If the settings card exists and use_settings_storycard: true, the card values are applied.
  • If the settings card exists and use_settings_storycard: false, the script falls back to the built-in defaults in Library.js.
  • If no settings card exists and use_settings_storycard is enabled in the built-in defaults, the script attempts to create one automatically.
  • debug_output is not read from the settings story card.

Library.js-only debug toggle

Full debugging is controlled only from Library.js.

const DEBUG_OUTPUT = false;

When DEBUG_OUTPUT is set to true:

  • full debug information is written to the console log
  • it is not appended to the player's visible story output
  • !secretsenabled debug still returns a visible one-off debug report when you ask for it

Built-in defaults

These are the built-in defaults in Library.js:

const DEBUG_OUTPUT = false;
const USE_AI_REVEAL_JUDGE = true;

const DEFAULT_CONFIG = {
  enabled: true,
  use_settings_storycard: true,
  activation_duration_in_turns: 3,
  max_active_secrets: 4,
  min_trigger_score: 1,
  history_turns_check: 3,
  use_ai_reveal_judge: USE_AI_REVEAL_JUDGE,
  fallback_keyword_judge: true,
  debug_output: DEBUG_OUTPUT,
  diag_output: false,
  max_judge_log_entries: 25,
};

What they mean:

  • enabled: master on/off switch for secret behavior injection
  • use_settings_storycard: whether the script should use and auto-create the settings story card
  • activation_duration_in_turns: how long a triggered secret stays warm
  • max_active_secrets: maximum number of warm secrets kept and injected into hidden context on a turn
  • min_trigger_score: minimum number of trigger hits needed to activate a secret
  • history_turns_check: how many previous history entries to include when matching secrets and mention recency
  • use_ai_reveal_judge: whether reveal progress is driven by the AI judge output
  • fallback_keyword_judge: whether the keyword-based fallback reveal check is allowed when the AI judge output is missing or malformed
  • debug_output: internal runtime flag sourced from const DEBUG_OUTPUT in Library.js
  • diag_output: whether a compact diagnostic summary is appended to normal AI responses
  • max_judge_log_entries: how many raw judge lines are kept in the secret card notes log before the oldest entries are dropped

AI judge capacity:

  • even if max_active_secrets is higher, only the first 2 active reveal checks use the AI judge
  • any additional active reveal checks fall back to the keyword heuristic for that turn

Matches semantics

Matches means reveal threshold, not reveal state.

In other words:

  • Matches: 3 means the reveal condition must be judged true on 3 separate turns
  • reveal progress increases by at most 1 per turn
  • once progress reaches the threshold, the secret is considered revealed enough to forward

Reveal progress is stored in script state and is also mirrored into the secret card description field so it can persist and be edited by the player.

Runtime notes persistence

Each secret card now uses its description field as a notes area for persistent runtime state.

SecretsEnabled preserves any normal user text already in description, then appends a managed JSON block like this:

Test Info

[SecretsEnabledState]
{
  "secretId": "afraid_of_water",
  "revealProgress": 1,
  "active": true,
  "turnsRemaining": 2,
  "lastTriggeredTurn": 12,
  "lastJudgeRaw": "SEJ|afraid_of_water|yes|She feels cornered around the river.",
  "judgeLog": [
    "SEJ|afraid_of_water|no|She is still avoiding the river.",
    "SEJ|afraid_of_water|yes|She feels cornered around the river."
  ],
  "updatedAt": "2026-03-12T10:15:00.000Z"
}
[/SecretsEnabledState]

How it behaves:

  • The script loads this block back in every turn before processing secrets.
  • In clients that do not persist story card edits from the Output modifier, judge-derived note updates are flushed on the next action.
  • If you manually edit the JSON block, the script will use those edited values.
  • revealProgress, active, and turnsRemaining are the main user-editable fields.
  • judgeLog keeps a rolling history of raw SEJ|... lines, appending new entries at the end.
  • Once judgeLog reaches max_judge_log_entries, the oldest entries are dropped first.
  • If you reset or remove the block, the secret state resets from the story card.
  • The normal secret definition still lives in the card body (value / entry / text).
  • The description field is treated as notes, not as the main secret definition body.

Reveal progress model

By default, reveal progress is driven by an AI-style judge line.

For matched or still-active secrets with a Reveal: field, the script injects a hidden instruction asking the model to begin its output with machine-only prefix lines, then immediately continue into the normal story response, like:

SEJ|afraid_of_her_apartment|yes|She feels directly threatened.

The script strips those prefix lines from visible output, parses them, and if met=yes increments reveal progress by 1 for that turn.

If the model omits or mangles the judge output, the script can fall back to a keyword-based reveal check run against the final turn text if fallback_keyword_judge is enabled.

To keep judge overhead under control:

  • only the first 2 active reveal checks use the AI judge on a turn
  • any remaining active reveal checks use the keyword heuristic instead

Current rules:

  • one reveal increment max per secret per turn
  • the judge answers from the character's perspective
  • if the answer is unclear, the prompt tells the model to answer no
  • if parsing fails or the judge line is missing, the fallback keyword judge may still advance reveal progress

Secret persistence

Matched secrets stay active for activation_duration_in_turns turns after a real trigger match.

If the same secret is triggered again before it expires, the timer resets back to the full duration.

While active, a secret can continue to influence behavior even if the latest turn does not contain a fresh trigger hit or a freshly repeated character mention. This helps the behavior persist naturally across adjacent turns while the secret remains warm.

If the number of warm secrets exceeds max_active_secrets, the script prunes them before injection:

  • secrets whose characters are directly mentioned in the current player input are kept first
  • warm secrets whose characters are not mentioned in the current player input are dropped
  • if too many directly mentioned characters remain, the script keeps the most recently mentioned ones based on the recent history window

Turn progression

SecretsEnabled uses an effective turn counter so secret timers behave properly across player actions, continue, and retry.

The current rules are:

  • normal player input advances the turn in Input
  • continue advances the effective turn in Context
  • retry does not advance the effective turn

That means:

  • turnsRemaining ticks down on continue
  • turnsRemaining does not tick down again on retry
  • revealProgress can only advance once for a given effective turn

The detection rule is:

  • if there is no Input hook and info.actionCount > history.length, treat it as retry
  • if there is no Input hook and info.actionCount == history.length, treat it as continue

When DEBUG_OUTPUT is enabled, the console debug includes:

  • Current turn
  • Detected action kind

What gets injected

When a secret matches, the script injects hidden behavior guidance into context.

By default this includes:

  • behavior lines from Behavior:
  • reveal policy guidance from Reveal:
  • reveal progress like 2 / 4
  • active-turn information while the secret is still warm

If reveal progress has reached the card's threshold and the card has Secret:, the hidden block will also include:

  • Revealed secret: ...

Commands

Recommended commands:

!secretsenabled debug
!secretsenabled on
!secretsenabled off

Supported aliases:

/secretsenabled debug
/secrestsenabled debug
@@secretsenabled debug

Command responses are returned through the Output modifier, so the debug command should appear to the player as plain output text, not only in logs.

Output modes

There are now two separate diagnostics modes:

  • diag_output: player-visible compact diagnostics, controlled from the settings story card
  • DEBUG_OUTPUT: full debug logging to console, controlled from Library.js

When diag_output is enabled, the player sees either a compact summary for each current match:

- Mira / afraid_of_water (triggered) turnsRemaining=3 triggers=[water] presence=[Mira]
Reveal progress: 1 / 3 metThisTurn=yes forwarded=no
AI judge raw: SEJ|afraid_of_water|yes|Directly confronted about going into the water.
Reveal keyword hits: evidence
Pressure hits: reveal

Or, when there are no current matches:

SecretsEnabled: no current matches

When DEBUG_OUTPUT is enabled in Library.js, the full [SecretsEnabled Debug] ... [/SecretsEnabled Debug] report is written to the console log for each turn instead of being appended to player-visible output.

Notes on behavior

What you can inspect:

  • the parsed secret cards
  • the settings card status
  • the match result
  • the behavior block being injected
  • reveal progress
  • the AI judge response
  • whether the literal secret was forwarded
  • the final story response
  • the console log when DEBUG_OUTPUT is enabled

What you cannot directly inspect:

  • the model's internal chain-of-thought or hidden interpretation of the behavior block

Troubleshooting

If a secret lingers too long:

  • reduce history_turns_check
  • or reduce activation_duration_in_turns

If reveal progress never advances:

  • check whether the secret has a Reveal: line
  • set DEBUG_OUTPUT = true in Library.js
  • inspect AI judge status, Judge source, and Heuristic fallback met in the console log

If the settings card does not appear:

  • make sure use_settings_storycard is true in the built-in defaults
  • run any normal do/say/story action so the script gets a turn to initialize

About

AI Dungeon Script to handle secrets

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors