Skip to main content

Uncensored Content & Policy-Tier Routing

AgentOS ships uncensored generation as a first-class feature. Any high-level API call that accepts a policyTier of 'mature' or 'private-adult' automatically reroutes to a curated uncensored model and disables the provider's default safety filter, so callers get working output without wiring bespoke model IDs for every surface.

This document covers:

  • Text generation (generateText, generateObject, streamText)
  • Image generation (generateImage)
  • Image editing (editImage)
  • The underlying model catalog and how to extend it

Policy tiers

TierBehaviour
safeFamily-friendly. Default censored providers. Refuses sexual/violent content.
standardDefault for most sessions. Mild violence, romantic tension, no explicit content.
matureRoutes to uncensored catalog. Sexual content, graphic violence, dark themes.
private-adultRoutes to uncensored catalog. All legal fictional content.

Tiers are inclusive: every tier above safe allows the tiers below it. Two content categories remain prohibited at every tier (including private-adult): sexual content involving minors, and real-world instructions for weapons, explosives, or poisons.

Text — uncensored chat and structured output

Set policyTier on any text call. The PolicyAwareRouter picks from the UncensoredModelCatalog (Hermes 3, Dolphin, MythoMax on OpenRouter) and bypasses the default OpenAI/Anthropic chain.

import { generateText, PolicyAwareRouter, createUncensoredModelCatalog } from '@framers/agentos';

// Option 1 — explicit router (most control)
const router = new PolicyAwareRouter(
createUncensoredModelCatalog(),
undefined,
undefined,
'private-adult',
);
const result = await generateText({
router,
system: 'You are a confident adult character named Cleopatra.',
prompt: 'Describe the scene the way you want me to see it.',
});

// Option 2 — route through a tier-aware agent
import { agent } from '@framers/agentos';
const a = agent({
instructions: 'You are Cleopatra, confident and direct.',
router: new PolicyAwareRouter(createUncensoredModelCatalog(), undefined, undefined, 'mature'),
});
const reply = await a.generate('Tell me about the court intrigue.');

Catalog entries (text)

Tier mature / private-adult routes to OpenRouter text models in this priority order (high quality first):

  1. nousresearch/hermes-3-llama-3.1-405b — flagship, follows system prompts reliably
  2. nousresearch/hermes-3-llama-3.1-70b — faster, same instruction-following
  3. cognitivecomputations/dolphin-mixtral-8x22b — fully uncensored MoE
  4. cognitivecomputations/dolphin3.0-llama3.1-8b — cheap tail-end fallback
  5. gryphe/mythomax-l2-13b — last-resort creative-writing model

Safe/standard tiers ignore the router and use the default provider chain.

Refusal-retry

When a model still produces wellness-bot speak despite the tier (happens with some OpenRouter routing hops), PolicyAwareRouter does not retry on its own — refusal detection is the caller's responsibility. The wilds-ai CompanionOrchestrator wraps this into a runRefusalRetry helper that iterates the full uncensored catalog on detection; cooperating apps can use the same pattern via createUncensoredModelCatalog().getTextModels().

Image — uncensored generation and editing

Set policyTier: 'mature' or 'private-adult' on either entry point:

import { generateImage, editImage } from '@framers/agentos';

// Generate an uncensored portrait
const portrait = await generateImage({
prompt: 'Cleopatra in the palace, oil painting style',
policyTier: 'mature',
referenceImageUrl: 'https://cdn.example.com/cleopatra-anchor.png',
});

// Edit an existing avatar (e.g. outfit change) while preserving the face
const outfit = await editImage({
image: existingAvatarBuffer,
prompt: 'wearing formal court attire, seated on the throne',
policyTier: 'mature',
capabilities: ['face-consistency', 'img2img'],
});

Automatic behaviour when policyTier is set

When policyTier is 'mature' or 'private-adult', the API:

  1. Routes through PolicyAwareImageRouter to pick a model from the uncensored catalog. generateImage infers 'face-consistency' when referenceImageUrl is supplied; editImage defaults to 'img2img' and honours explicit capabilities hints.
  2. Sets providerOptions.replicate.disableSafetyChecker = true so the community model's own NSFW filter does not silently veto the prompt.
  3. Initialises Replicate as the primary provider (Fal and stable-diffusion-local remain in the fallback chain).

Safe and standard tiers bypass all of this; they use whatever provider / model the caller passes in (or env-detected defaults).

Catalog entries (image)

Tier mature / private-adult routes to Replicate community models:

ModelQualityContent permissionsCapabilities
lucataco/realvisxl-v4.0highgeneral, romantic, erotictxt2img, img2img, photorealistic
stability-ai/sdxlhighalltxt2img, img2img
lucataco/ip-adapter-faceid-sdxlmediumgeneral, romantic, erotictxt2img, img2img, face-consistency
zsxkib/instant-idmediumgeneral, romantictxt2img, face-consistency
lucataco/animate-diffmediumgeneral, romantic, violenttxt2img, video
stability-ai/stable-video-diffusionhighgeneral, romanticimg2video, video

The catalog is sorted by quality and filtered by capabilities. Call createUncensoredModelCatalog().getImageModels({ capabilities: ['face-consistency'] }) to inspect the filtered list at runtime.

Outfit / costume editing (wardrobe_preview)

For the canonical "change a character's clothes while preserving their face" use case, pass a reference image and the face-consistency capability. The router picks lucataco/ip-adapter-faceid-sdxl, which is trained precisely for this pattern and allows erotic content.

const lingerie = await editImage({
image: cleopatraAvatarBuffer,
prompt: 'wearing elegant lingerie, seductive pose, Egyptian palace setting',
policyTier: 'mature',
capabilities: ['face-consistency', 'img2img'],
strength: 0.75,
});

Without policyTier, this call routes to Flux Kontext Dev (or whatever the caller configured), which refuses the prompt at the model-provider level — no amount of disable_safety_checker changes that because Flux Kontext's moderation is baked into the model weights.

Extending the catalog

createUncensoredModelCatalog() returns an immutable catalog. To add models, compose your own implementation of UncensoredModelCatalog:

import type { UncensoredModelCatalog, CatalogEntry } from '@framers/agentos';

const EXTRA_ENTRIES: CatalogEntry[] = [
{
modelId: 'your-org/your-nsfw-model',
displayName: 'Custom Erotic SDXL',
providerId: 'replicate',
modality: 'image',
quality: 'high',
contentPermissions: ['general', 'romantic', 'erotic'],
capabilities: ['txt2img', 'img2img', 'face-consistency'],
},
];

function makeExtendedCatalog(): UncensoredModelCatalog {
const base = createUncensoredModelCatalog();
return {
getTextModels: (f) => base.getTextModels(f),
getImageModels: (f) => [...EXTRA_ENTRIES, ...base.getImageModels(f)],
getPreferredTextModel: (t, i) => base.getPreferredTextModel(t, i),
getPreferredImageModel: (t, caps) => {
const preferred = EXTRA_ENTRIES.find(
(e) => !caps || caps.every((c) => e.capabilities.includes(c)),
);
return preferred ?? base.getPreferredImageModel(t, caps);
},
};
}

const router = new PolicyAwareImageRouter(makeExtendedCatalog());

Wire the extended router into generateImage / editImage by passing provider and model resolved from router.getPreferredProvider(...) explicitly — the high-level APIs currently embed createUncensoredModelCatalog() as the default, but the routers themselves are caller-owned objects.

Environment variables

Uncensored routing requires credentials for the uncensored providers. At least one of each is recommended:

# Text (at least one for mature/private-adult)
OPENROUTER_API_KEY=sk-or-...

# Image (Replicate is the primary uncensored host)
REPLICATE_API_TOKEN=r8_...

# Optional fallbacks
FAL_API_KEY=...
STABLE_DIFFUSION_LOCAL_BASE_URL=http://localhost:7860

If no uncensored-capable credentials are set, the APIs fall back to whatever censored provider is configured and the tier has no effect.

Logging and telemetry

Both generateImage and editImage emit OpenTelemetry spans with llm.provider and llm.model attributes. When policy-aware routing kicks in, the resolved provider/model reflect the uncensored choice, so dashboards can filter by tier and spot hits on the uncensored path.