Premium plugins required. The ai options configure backend transport and UI behavior for AI features. They have no effect until you load and enable the matching premium plugin.
ai.url#
Type: false | string
Default: false
Plugin: AI Assistant, AI Commands
Sync HTTP endpoint for text AI requests.
When false and no jobs transport is configured, AI plugins does not start.
const app = Redactor('#entry', {
ai: {
url: '/api/ai'
}
});
ai.model#
Type: false | string
Default: false
Plugin: AI Assistant, AI Commands
Optional model id sent to the backend as body.model (for example gpt-4o-mini, claude-3-5-sonnet-20241022).
When omitted, the field is not included in the request — your backend can use its own default model.
const app = Redactor('#entry', {
ai: {
url: '/api/ai',
model: 'gpt-4o-mini'
}
});
ai.transport#
Type: 'sync' | 'jobs' | 'custom'
Default: 'sync'
Plugin: AI Assistant
How text/image requests reach your backend:
| Value | Behavior |
|---|---|
sync |
Single HTTP request to ai.url (or ai.image.url for images) |
jobs |
Create a job via ai.jobs.createUrl, then poll until complete |
custom |
Your handler in ai.request / ai.image.request; no default fetch to ai.url |
const app = Redactor('#entry', {
ai: {
transport: 'jobs',
jobs: {
createUrl: '/api/ai/jobs'
}
}
});
ai.request#
Type: false | (ctx, app) => Promise<{ raw } | { images }>
Default: false
Plugin: AI Assistant
Custom transport for text requests.
The handler receives a context object with kind, action, prompt, context, body, headers, signal, and app.
Return { raw } for text/review/report responses, or { images } for image generation.
Required when transport is custom and no handler returns a result.
const app = Redactor('#entry', {
ai: {
transport: 'custom',
request: async (ctx) => {
const res = await fetch('/api/ai', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(ctx.body),
signal: ctx.signal
});
return { raw: await res.json() };
}
}
});
ai.headers#
Type: object
Default: {}
Plugin: AI Assistant, AI Commands
Extra headers for text requests.
const app = Redactor('#entry', {
ai: {
url: '/api/ai',
headers: {
'X-Api-Key': 'your-key'
}
}
});
ai.batchBlocks#
Type: number
Default: 10
Plugin: AI Assistant
Maximum blocks per request when a review operation is split into batches.
Used only in review mode when batching is enabled.
const app = Redactor('#entry', {
ai: {
url: '/api/ai',
batchBlocks: 5
}
});
ai.batchStrategy#
Type: 'fallback' | 'always' | 'never'
Default: 'fallback'
Plugin: AI Assistant
Controls batching for review requests in sync transport:
| Value | Behavior |
|---|---|
fallback |
Try one request first; split into batches on server/network errors (5xx, timeout, fetch failure) |
always |
Always send review requests in batches of ai.batchBlocks |
never |
Never batch |
const app = Redactor('#entry', {
ai: {
url: '/api/ai',
batchStrategy: 'always',
batchBlocks: 8
}
});
ai.jobs#
Plugin: AI Assistant
Async job transport settings. Used when ai.transport is 'jobs'.
const app = Redactor('#entry', {
ai: {
transport: 'jobs',
jobs: {
createUrl: '/api/ai/jobs'
}
}
});
ai.jobs.createUrl
Type: false | string
Default: false
Endpoint that creates a job and returns { jobId } (alias: ai.jobs.url).
const app = Redactor('#entry', {
ai: {
transport: 'jobs',
jobs: {
createUrl: '/api/ai/jobs'
}
}
});
ai.jobs.pollInterval
Type: number
Default: 1500
Polling interval in milliseconds between status checks.
const app = Redactor('#entry', {
ai: {
transport: 'jobs',
jobs: {
createUrl: '/api/ai/jobs',
pollInterval: 2000
}
}
});
ai.jobs.pollMaxWait
Type: number
Default: 120000
Maximum time in milliseconds to wait for job completion.
const app = Redactor('#entry', {
ai: {
transport: 'jobs',
jobs: {
createUrl: '/api/ai/jobs',
pollMaxWait: 300000
}
}
});
ai.jobs.headers
Type: object
Default: {}
Extra headers for job create and poll requests.
const app = Redactor('#entry', {
ai: {
transport: 'jobs',
jobs: {
createUrl: '/api/ai/jobs',
headers: {
'X-Api-Key': 'your-key'
}
}
}
});
ai.jobs.getAuth
Type: false | () => Promise<object> | object
Default: false
Optional async provider for auth headers (for example { Authorization: 'Bearer …' }). Merged with ai.jobs.headers on each jobs request.
const app = Redactor('#entry', {
ai: {
transport: 'jobs',
jobs: {
createUrl: '/api/ai/jobs',
getAuth: async () => ({
Authorization: `Bearer ${await getToken()}`
})
}
}
});
ai.actions#
Type: object
Default: built-in action map from the loaded AI plugin (merged with your overrides)
Plugin: AI Assistant, AI Commands
Defines the AI dropdown menu: top-level commands, nested submenus, labels, icons, and prompts sent to the backend.
Your ai.actions object is deep-merged into the plugin defaults.
Matching keys override built-in entries; new keys add menu items.
Pass { __replace: true, ... } as the root actions value to drop all built-in items and use only yours.
Action fields
| Field | Description |
|---|---|
title |
Menu label. Supports ## lang.key ## tokens. |
icon |
Optional SVG/HTML icon for the menu row. |
prompt |
Instruction sent to the backend (AI Commands and custom actions). |
items |
Nested submenu. Keys become submenu entries; paths use dots (translate.en). |
group |
AI Assistant toolbar group: edit, review, insights, generate. |
mode |
AI Assistant pipeline: review (default), report, report-review, apply. |
diff |
AI Assistant — open AI Review with a token diff (true). |
language |
AI Assistant — target language for translate sub-items. |
tone |
AI Assistant — tone instruction for tone sub-items. |
documentContext |
AI Assistant — run on the whole document; hidden from the context toolbar. |
Leaf vs submenu
- Leaf action — has
prompt(AI Commands) ormode/language/tone(Assistant). Click runs the command immediately. - Submenu — has
itemswith child actions. The parent usually has onlytitleandicon; children hold prompts or nesteditems.
Override a built-in action
Change the label, icon, or prompt without rebuilding the menu:
// AI Commands
const app = Redactor('#entry', {
ai: {
url: '/api/ai',
actions: {
improve: {
title: 'Polish text',
icon: '<svg>...</svg>',
prompt: 'Polish the text. Keep HTML structure. Return HTML only.'
}
}
}
});
// AI Assistant
const app = Redactor('#entry', {
ai: {
url: '/api/ai',
actions: {
improve: {
title: 'Polish text',
icon: '<svg>...</svg>'
}
}
}
});
Nested actions
Built-in translate and tone entries are submenus. Override the parent title/icon, add a language, or replace the whole submenu:
const app = Redactor('#entry', {
ai: {
url: '/api/ai',
actions: {
translate: {
title: 'Translate to…',
items: {
pl: {
title: 'Polish',
prompt: 'Translate to Polish. Preserve HTML. Return HTML only.'
},
en: {
title: 'English',
language: 'English'
}
}
},
tone: {
items: {
friendly: {
title: 'Friendlier',
tone: 'Rewrite in a warm, friendly tone. Preserve HTML. Return HTML only.'
}
}
}
}
}
});
Use prompt in nested AI Commands items. In AI Assistant translate children use language; tone children use tone.
Add a custom action
Top-level keys become new menu rows:
const app = Redactor('#entry', {
ai: {
url: '/api/ai',
actions: {
seo: {
title: 'SEO rewrite',
icon: '<svg>...</svg>',
prompt: 'Rewrite for SEO. Keep meaning and HTML structure. Return HTML only.'
}
}
}
});
AI Assistant — assign a toolbar group:
actions: {
seo: {
title: 'SEO rewrite',
group: 'edit',
prompt: 'Rewrite for SEO. Return HTML only.'
}
}
Replace the whole menu
const app = Redactor('#entry', {
ai: {
url: '/api/ai',
actions: {
__replace: true,
rewrite: {
title: 'Rewrite',
prompt: 'Rewrite the selection. Return HTML only.'
},
shorten: {
title: 'Shorten',
prompt: 'Make it shorter. Return HTML only.'
}
}
}
});
Hide a built-in action
const app = Redactor('#entry', {
ai: {
actions: {
tone: false
}
}
});
ai.image#
Type: object
Plugin: AI Assistant, AI Commands
Image generation settings shared by both plugins. When ai.image.url is set, the image button appears in the addbar (if the plugin is enabled).
const app = Redactor('#entry', {
ai: {
image: {
url: '/api/ai/image'
}
}
});
ai.image.url
Type: false | string
Default: false
Dedicated image generation endpoint. When false, the image UI is disabled.
const app = Redactor('#entry', {
ai: {
image: {
url: '/api/ai/image'
}
}
});
ai.image.model
Type: false | string
Default: false
Optional image model id (for example dall-e-3, gpt-image-1), sent as body.model.
When omitted, the field is not included in the request — your backend should use its own default image model.
const app = Redactor('#entry', {
ai: {
image: {
url: '/api/ai/image',
model: 'dall-e-3'
}
}
});
ai.image.headers
Type: object
Default: {}
Extra headers for image generation requests.
const app = Redactor('#entry', {
ai: {
image: {
url: '/api/ai/image',
headers: {
'X-Api-Key': 'your-key'
}
}
}
});
ai.image.size
Type: string
Default: '1024x1024'
Default image size sent as body.size.
const app = Redactor('#entry', {
ai: {
image: {
url: '/api/ai/image',
size: '1536x1024'
}
}
});
ai.image.n
Type: number
Default: 1
Number of images to request per generation (body.n).
const app = Redactor('#entry', {
ai: {
image: {
url: '/api/ai/image',
n: 2
}
}
});
ai.image.request
Type: false | (ctx, app) => Promise<{ images }>
Default: false
Optional image-only custom handler. When set, it takes priority over ai.request for kind: 'image'. Falls back to ai.request if not set.
const app = Redactor('#entry', {
ai: {
transport: 'custom',
image: {
request: async (ctx) => {
const res = await fetch('/api/ai/image', {
method: 'POST',
body: JSON.stringify(ctx.body),
signal: ctx.signal
});
const data = await res.json();
return { images: data.images };
}
}
}
});
ai.report.handler#
Type: false | (report) => void
Default: false
Plugin: AI Assistant
Called when a report-mode AI action returns HTML. Use it to render results in your own panel instead of the default report UI (host tabs).
The handler receives a report object:
| Field | Type | Description |
|---|---|---|
key |
string |
Tab/section id (raw.tab, raw.key, raw.section, or action name). |
title |
string |
Report title from the backend or the default lang string. |
html |
string |
Report HTML to display. |
action |
string |
Action id that produced the report (for example summarize). |
raw |
object |
Full backend response. |
app |
object |
Redactor editor instance. |
const app = Redactor('#entry', {
ai: {
report: {
handler: (report) => {
document.querySelector('#ai-report').innerHTML = report.html;
}
}
}
});
ai.review.diffClasses#
Type: { original: string, replacement: string }
Default:
{
original: 'rx-ai-diff-original',
replacement: 'rx-ai-diff-replacement'
}
Plugin: AI Assistant
CSS class names used to wrap changed tokens in the Original / Suggestion diff panels inside AI Review.
const app = Redactor('#entry', {
ai: {
review: {
diffClasses: {
original: 'my-diff-old',
replacement: 'my-diff-new'
}
}
}
});
ai.review.refine#
Type: Array<object>
Default: built-in list (rephrase, refine-prompt, …)
Plugin: AI Assistant
Preset entries for the Refine dropdown in AI Review. Each item:
| Field | Description |
|---|---|
id |
Unique entry id |
title |
Label (supports ## lang.key ##) |
icon |
Optional SVG icon HTML |
action |
AI action name (for preset actions) |
type: 'prompt' |
Inline prompt field instead of a fixed action |
hideOnDiff |
Hide when diff view is active |
const app = Redactor('#entry', {
ai: {
review: {
refine: [
{
id: 'shorter',
action: 'shorter',
title: '## ai.shorter ##',
reviewOnly: true
},
{
id: 'custom-prompt',
type: 'prompt',
title: '## ai.refine-prompt ##',
hideOnDiff: true
}
]
}
}
});