# SleekWP Documentation > WordPress plugins for AI, code snippets, analytics, data views and programmatic SEO, built on file-backed data and WP-CLI so coding agents can run them too. ## SleekAI Docs ### Overview Section: Getting Started URL: https://sleekwp.com/docs/ai/ Markdown: https://sleekwp.com/docs/ai.md SleekAI is the AI product of SleekWP. It adds a chat for administrators, chatbots for site visitors, alt text for media library images and the Agent, an assistant that works beside the WordPress screen you are on. Requests go to the AI providers with your own API keys, so you pay the providers directly for what you use. #### Where to find it In the suite, SleekAI is **AI** in the workspace sidebar. Its start screen lists your chats and your chatbots, each with a search field and a button to create a new one. Below it, the sidebar lists: - **[Chats](/docs/ai/chat.md)**: conversations with any configured model. - **[Chatbots](/docs/ai/chatbots/general.md)**: chatbots for visitors, shown as a floating widget or an embedded chat. - **[Alt text](/docs/ai/alt-text.md)**: alt text, captions and descriptions for images, generated on demand or on upload. - **Settings**: the default chat model, [custom models](/docs/ai/settings/custom-models.md) and which user roles may use the [Agent](/docs/ai/agent/settings.md); provider [API keys](/docs/ai/settings/api-keys.md) live in the shared AI settings. - **License**: see [Activating](/docs/ai/activating.md). The standalone SleekAI plugin shows the same screens under **SleekWP > AI** in the WordPress admin menu. #### Providers SleekAI works with OpenAI, Anthropic, Google and OpenRouter, and with any endpoint that accepts OpenAI-style chat completion requests through a [custom model](/docs/ai/settings/custom-models.md). A provider's models appear wherever you choose a model once its [API key](/docs/ai/settings/api-keys.md) is stored. #### SleekAI and the workspace assistant The assistant that opens from the workspace header belongs to the workspace, not to SleekAI. It runs on the workspace's own AI service and works with no SleekAI installed. Both read the same provider keys and custom models, so a key entered once serves the assistant, SleekAI and the AI features of every other SleekWP product. When SleekAI is installed, the assistant can also run SleekAI's [WP-CLI commands](/docs/ai/cli.md) for you, such as listing chatbots or generating alt text; it asks before running one that deletes data. Its conversations are kept apart from SleekAI's chats. #### Updating from the standalone plugin The standalone SleekAI plugin updates in place to its next major release from any published version. That release requires PHP 8.2 and WordPress 6.5; a site below either keeps its current version. Chats, chatbots, keys and settings carry over. Stored API keys are sealed again with a key unique to the site, so rolling back to an earlier release means entering the keys again. After updating, purge page caches and CDNs so visitors receive the new chatbot widget. #### Support For support or questions, write to [hi@sleekwp.com](mailto:hi@sleekwp.com). ### Activating Section: Getting Started URL: https://sleekwp.com/docs/ai/activating/ Markdown: https://sleekwp.com/docs/ai/activating.md The license connects the site to SleekWP's store. The standalone SleekAI plugin uses it to receive updates, and [sharing a chat](/docs/ai/chat.md#sharing) needs it, because shares are stored by SleekWP's share service. Chat, chatbots, alt text and the Agent work whether or not a license is active. #### On the License page Open AI's **License** page: in the suite it is the last item below AI in the workspace sidebar, and in the standalone plugin it sits in the same place under **SleekWP > AI**. 1. Enter the key in **License key**. 2. Select **Activate license**. The page asks the store to activate the key for this site and shows the result as **Valid** or **Invalid**, or **Inactive** before any key was activated. Only a valid key is kept; an invalid one is discarded, so the page shows no key afterwards. **Deactivate license** asks the store to release the key for this site and removes it, together with its status. The page is not shown in the network admin, or when the standalone plugin is [white-labelled](/docs/white-label.md). #### With a constant You can provide the key in PHP instead, for example in `wp-config.php`: ```php define( 'SLEEK_AI_LICENSE', 'YOUR LICENSE KEY' ); ``` While the constant holds a non-empty key, the License page shows that key, masked, with its field and buttons disabled, and the server refuses to activate or deactivate another key. Sharing uses the constant's key. The constant does not activate the key with the store by itself. #### Uninstalling Deleting the plugin removes the chats with their messages and files, the Agent conversations and chatbot logs stored with them, the scheduled jobs, the response files under `uploads/sleek-ai/completions`, the [Agent Sync](/docs/ai/agent-sync.md) markers on chatbots, agents and modes, the chatbots' temporary data (inline chatbot settings and visitor rate and budget counters), and what the earlier plugin mode left in uploads, on every site of a network. With a persistent object cache the temporary data lives in the cache instead, where it expires within a week. It keeps the provider keys and custom models, because the other SleekWP products and the workspace assistant use them too, and it keeps the chatbots, agents and modes, the settings, the license and the files Agent Sync wrote to the theme. While another plugin that carries AI is still installed, such as the suite's Pro plugin after you delete the standalone SleekAI plugin, AI's data stays for it and deleting removes nothing. ### API Keys Section: Settings URL: https://sleekwp.com/docs/ai/settings/api-keys/ Markdown: https://sleekwp.com/docs/ai/settings/api-keys.md SleekAI sends requests to the AI providers with your own API keys. Store at least one key before you chat, publish a chatbot, generate alt text or use the Agent. You can store one key each for OpenAI, Anthropic, Google and OpenRouter. Keys are shared: the same stored keys serve SleekAI, the workspace assistant and the AI features of every other SleekWP product, so a key is entered once. #### Where to enter a key The settings button beside the theme selector in the sidebar header opens the settings shared by every installed plugin. Its **AI** section has one field per provider. The standalone SleekAI plugin shows the same **AI** section in its Settings. A key is encrypted before it is stored and is never sent back to the browser. A provider that holds a key shows that a key is saved, with an action to remove it; to replace a key, remove it and save the new one. The section lists the keys you saved yourself. Requests to a provider use a key stored for that provider whoever saved it, so a key saved by one administrator also serves the others. #### Getting a key Each provider issues keys in its own console: | Provider | Where to create a key | | ---------- | -------------------------------------------------------------------- | | OpenAI | [platform.openai.com/api-keys](https://platform.openai.com/api-keys) | | Anthropic | [console.anthropic.com](https://console.anthropic.com/account/keys) | | Google | [Google AI Studio](https://aistudio.google.com/apikey) | | OpenRouter | [openrouter.ai/keys](https://openrouter.ai/keys) | Create a key there, copy it, and paste it into SleekAI. Usage is billed by the provider to the account that owns the key. #### From the command line `wp sleek ai key set` stores a key, `wp sleek ai key list` lists the stored keys without their values, and `wp sleek ai key delete` removes one: ```bash wp sleek ai key set openai sk-... --label=Production --user=admin wp sleek ai key list ``` `key set` also accepts a `custom-` name, such as `custom-gateway`, for a key that only a [custom model](/docs/ai/settings/custom-models.md) uses. The key belongs to the user the command runs as, which matters for custom models: a custom model only finds a key its own user stored. The [CLI reference](/docs/ai/reference/cli.md) lists every option. The workspace assistant can list and delete keys for you but cannot store one. #### Removing SleekAI [Uninstalling SleekAI](/docs/ai/activating.md#uninstalling) keeps the stored keys and custom models. ### Custom Models Section: Settings URL: https://sleekwp.com/docs/ai/settings/custom-models/ Markdown: https://sleekwp.com/docs/ai/settings/custom-models.md A custom model connects SleekAI to an endpoint that accepts OpenAI-style chat completion requests: a provider SleekAI has no built-in support for, a model server you run, or your own gateway. OpenRouter is built in and needs no custom model. Requests to a custom model go through WordPress, which adds the stored API key on the server, so the key never reaches the browser. #### Creating a custom model 1. Store the endpoint's API key. A provider key from [API Keys](/docs/ai/settings/api-keys.md) works for that provider's own API; for any other endpoint, store a separate key with `wp sleek ai key set custom-`. 2. Under AI, open **Settings > Custom models** and select **Create custom model**. `create=1` in the address, before the `#`, opens that dialog directly. 3. Enter a name of lowercase letters, digits and hyphens, such as `my-model`. SleekAI prefixes it with `custom-`, and `custom-my-model` becomes the model's identifier. 4. Fill in the model's fields and save. The **Custom models** list shows every custom model with actions to edit and delete it; an open custom model also has **Delete custom model** beside **Save**. Deleting one cannot be undone. #### Fields **Label** is the name shown in model selectors; without one the identifier is shown. **Model** is the model identifier the endpoint expects. It is not sent on its own: add it to the request body, as below. **Endpoint URL** is the URL that receives chat completion requests, usually ending in `/chat/completions`: ```txt https://api.example.com/v1/chat/completions ``` The endpoint has to be a public address. WordPress refuses one on the site's own machine or private network unless the site allows that host with WordPress's `http_request_host_is_external` filter, and it does not follow redirects. A provider key from API Keys is sent only to its provider's API over HTTPS, such as `api.openai.com` for the OpenAI key, so an endpoint elsewhere needs a `custom-` key. **API key** selects one of the keys you stored. If the provider expects the key in the URL, write `{apiKey}` where it belongs, and SleekAI replaces it on the server: ```txt https://api.example.com/v1/chat/completions?key={apiKey} ``` **Body** is JSON merged into every request. Put the upstream model identifier and any provider-specific fields here: ```json { "model": "provider-model-name" } ``` SleekAI adds the conversation's `messages` and the `stream` flag when it sends the request. The body must be valid JSON, and it may use `{apiKey}` too. **Headers** adds request headers. SleekAI always sends `Content-Type: application/json` and `Authorization: Bearer {apiKey}`; add a header only when the provider needs another one, for example `X-API-Key: {apiKey}`. A header with exactly the same name replaces SleekAI's. **System instruction** is placed before the conversation when you chat with this model in [Chats](/docs/ai/chat.md). **Context limit**, **Max tokens** and **Temperature** are saved with the model but are not sent to the endpoint; put a limit or a temperature in the body to send it. #### Using a custom model Custom models appear in the model selectors of Chats and the [chatbot editor](/docs/ai/chatbots/model.md), grouped apart from the provider models. Alt text needs a vision model from a built-in provider and does not offer custom models. A custom model belongs to the user who created it: it is listed only for that user, and it finds only an API key that user stored. A chatbot that uses a custom model resolves it as the chatbot's author, so visitors can use it. Code that runs without a signed-in user, such as a WP-CLI command without `--user` or a scheduled task, needs a provider model instead. ### Chat Section: Features URL: https://sleekwp.com/docs/ai/chat/ Markdown: https://sleekwp.com/docs/ai/chat.md Chats is a chat with your configured AI models inside WordPress. Open it from **Chats** below AI in the sidebar, or with **New chat** on AI's start screen. It needs at least one [API key](/docs/ai/settings/api-keys.md); until one is stored, the message field reads "Add an AI provider key to start…". #### Conversations Every chat is saved as you write and belongs to you: other users do not see your chats. Sending the first message of a new chat gives it a short title, written by the model, and adds it to the sidebar, where a search field filters your chats. The toolbar above an open chat has these actions: - **New Chat** starts an empty chat. - **Rename** changes the chat's title. - **Duplicate** copies the whole chat into a new one titled "Copy: " and the original title. - **Delete** removes the chat and its messages. #### Choosing a model The model selector in the message field lists the models of every provider with a stored key and your [custom models](/docs/ai/settings/custom-models.md), with a search field. A new chat starts with the default model chosen under **Settings > Chat**, or with the first model listed when none is chosen; an existing chat continues with the model it last used. #### Working with replies A finished reply offers these actions: - **New chat from here** copies the chat up to that reply into a new chat, so you can take the conversation another way and keep the original. - **Regenerate** removes the reply and everything after it and asks the model again. - **Delete from here** removes the reply and everything after it. The first reply of a chat does not offer it. You can stop a reply while it is being written. A reply that failed or was stopped offers **Retry**. #### Images from the media library The attach button in the message field opens the WordPress media library, where you can choose one or more images. They are attached to your next message and sent to the model with it, so use a model that accepts images. #### Sharing The share button in the message field opens **Share chat**. **Share now** uploads the chat as it is to SleekWP's share service and adds a link to the list; each link opens the shared chat read-only on this site's AI screen. **Delete share** removes a shared copy. Sharing needs an active [license](/docs/ai/activating.md), and a share is a copy: messages you add later are not part of it until you share again. #### Chats from earlier versions Chats saved by an earlier SleekAI version are converted the first time Chats opens. A chat that cannot be converted is named in a notice and stays in the database untouched. #### Keeping chats for a limited time SleekAI keeps chats until you delete them. To delete old chats automatically, set the number of days to keep them: ```bash wp sleek ai settings update retention.days 90 ``` Every day after that, chats last updated longer ago are deleted with their messages. The same rule applies to Agent conversations and chatbot logs, which are stored alongside. The `sleekAi/retention/days` filter can set the period in code; see the [hooks reference](/docs/ai/reference/hooks.md). ### Alt text Section: Features URL: https://sleekwp.com/docs/ai/alt-text/ Markdown: https://sleekwp.com/docs/ai/alt-text.md SleekAI describes images in the media library with a vision model and writes the description to the image's alt text, caption or description. It works on images you select in a table, and on new uploads if you turn that on. Alt text sits below AI in the sidebar and has three pages: the model, the generation settings, and the table. #### Model The **Alt text** page chooses the model that looks at the images. It lists the models of every provider with a stored [API key](/docs/ai/settings/api-keys.md); custom models are not offered. Choose a model that accepts images. **System instruction** tells the model how to describe an image. Its placeholder shows the instruction SleekAI uses when the settings hold none: a concise, descriptive alt text of under 125 characters. Along with the image, SleekAI sends the image's title and caption when it has them. Nothing is generated until a model is chosen. #### Generation The **Generation** page has two settings: - **Generate alt text for new uploads** generates a description for every image added to the media library. - **Fields** chooses where the description is written: **Alt text**, **Image caption** and **Image description**. The same text goes into every field you choose, replacing what was there. Choose at least one field; otherwise the description is generated and then discarded. An upload does not wait for the model: SleekAI queues the work as the `sleekAi/altText/generate` action in Action Scheduler and generates the text shortly after. If the action cannot be queued, the text is generated during the upload instead. A callback you add to that action at a priority above 10 runs after SleekAI has written the text; see the [hooks reference](/docs/ai/reference/hooks.md). #### Table The **Table** page lists the media library's images with a thumbnail, their alt text, caption and description, and their date. Select images, or every image on the page with the checkbox in the table's header, and choose **Generate** above the table to describe them one after another with the current model and fields; the button names how many images are selected and stays disabled until you select one. The **Status** column shows each image as processing, completed or failed. The table pages through the library, 10 rows at a time unless you choose up to 500, newest first unless the **Date** column's menu sorts it oldest first. The page keeps that state in its address, before the `#`, as `paged`, `per_page` and `order=oldest`, so a link can open a given page of the table; a page past the last one opens the last. #### From the command line `wp sleek ai alt-text generate` describes images with the same model and fields, by attachment ID or for every image that has no alt text yet: ```bash wp sleek ai alt-text generate 42 43 wp sleek ai alt-text generate --all-missing --dry-run ``` `--dry-run` lists the images without calling the provider. A run handles at most 50 images, or as many as `--limit` names up to 500; run it again for the rest. The [CLI reference](/docs/ai/reference/cli.md) lists every option. ### Streaming Section: Features URL: https://sleekwp.com/docs/ai/streaming/ Markdown: https://sleekwp.com/docs/ai/streaming.md Replies in Chats and in chatbots appear word by word while the model writes them. SleekAI finds out by itself whether your server can deliver them that way, and falls back to polling where it cannot. Nothing needs configuring. #### How SleekAI decides Before the first reply, the browser opens a short test stream from the server. If it arrives intact, replies are streamed as server-sent events; if it does not, as on some shared hosting and behind buffering proxies, replies are polled. The browser reports the result to the server, which keeps it. Chatbot widgets on your pages use the stored result once there is one instead of testing again, and the server answers every reply the same way. #### Polling When replies are polled, the server writes each reply to a temporary file under `uploads/sleek-ai/completions` while the model writes it, and the browser reads that file several times a second until the reply is complete. Each file is served only to the browser that asked for the reply, and only for ten minutes after its last change. An hourly WordPress cron event deletes older ones, and `wp sleek ai cleanup completions` does the same on demand. Both ways show the same reply; polling only adds a little delay. #### Choosing the method yourself The `sleekAi/polling` filter overrides the stored result: return `true` to always poll or `false` to always stream. The server applies it when it answers, and chatbot widgets receive it with the page. ```php add_filter('sleekAi/polling', '__return_true'); ``` `sleekAi_use_polling()` returns the filtered value; see the [Developer API](/docs/ai/api.md) and the [hooks reference](/docs/ai/reference/hooks.md). #### Troubleshooting **A reply never arrives or stops early.** A proxy or cache in front of the site may hold back streamed responses. Exclude the site's REST API (`/wp-json/`) from buffering and caching, or force polling with the filter above. **A request is rejected with "Invalid JSON data" or "Invalid messages."** The conversation did not reach the server intact, usually because a proxy or security plugin rewrote the request body. ### General Section: Chatbots URL: https://sleekwp.com/docs/ai/chatbots/general/ Markdown: https://sleekwp.com/docs/ai/chatbots/general.md A chatbot answers your site's visitors with an AI model. You decide what it knows, from fixed text to the post a visitor is reading, where it appears, and how it looks. It shows as a floating widget with a button in a corner of the page, or as a chat embedded in the content. #### The chatbot list **Chatbots** below AI in the sidebar lists your chatbots, with a search field and actions to edit and delete each; with no chatbot yet it shows a **Create chatbot** action instead. **Create chatbot** asks for a name and opens the new chatbot; `create=1` in the address, before the `#`, opens that dialog directly. A new chatbot starts in the data wizard and appears nowhere until you give it [conditions](/docs/ai/chatbots/conditions.md) or place it with a shortcode. AI's start screen lists the same chatbots with the most recently changed first. #### The chatbot editor A chatbot's editor has five pages, listed in the sidebar while it is open: - **[Data](/docs/ai/chatbots/data.md)**: its name, what it knows and its instruction. - **[Conditions](/docs/ai/chatbots/conditions.md)**: where the widget appears, and the shortcodes that place it. - **[Model](/docs/ai/chatbots/model.md)**: the model that answers. - **[Widget](/docs/ai/chatbots/widget.md)**: the button, the chat window and what visitors may do. - **[Logs](/docs/ai/chatbots/logs.md)**: whether conversations are recorded, and the recorded ones. The pages edit one draft of the chatbot, so changes made on several pages are saved together by the **Save** of any of them, and **Discard** beside it returns every page to the saved chatbot. The draft is kept while you move between pages and other screens; reloading or closing the page with unsaved changes asks first. The preview pane beside the editor shows the chatbot as visitors see it, using the unsaved changes: the Widget page shows the floating widget, and the other pages show the chat. It opens closed; its toggle opens it, and `preview=1` in the address, before the `#`, opens it directly, for example `preview=1` with `#/ai/chatbots/3`. #### What every chatbot does - SleekAI wraps every chatbot's instruction in fixed guidelines for public chatbots, which tell the model to stay in its role, not to reveal its instructions and to protect visitors' privacy. They always apply. - Replies stream, with [polling](/docs/ai/streaming.md) as the fallback on servers that cannot stream. - Chat history stays in the visitor's browser, if the widget keeps it at all; see [storage](/docs/ai/chatbots/widget.md#storage). - Conversations are recorded only when [logging](/docs/ai/chatbots/logs.md) is on. - A chatbot shows nowhere while no [API key](/docs/ai/settings/api-keys.md) is stored, and never inside the workspace except in the editor's preview. #### Other ways to place a chatbot Besides its conditions, a saved chatbot can be placed with a shortcode, shown on its Conditions page. A chatbot can also be built and rendered entirely from PHP, without saving it; see the [Chatbot API](/docs/ai/chatbots/api.md), which also covers the JavaScript methods that open, close, hide and show a widget. ### Data Section: Chatbots URL: https://sleekwp.com/docs/ai/chatbots/data/ Markdown: https://sleekwp.com/docs/ai/chatbots/data.md The **Data** page of a chatbot names it and decides what it knows. Everything the chatbot knows reaches the model in its instruction, the system message sent with every visitor message. You build that instruction either with the wizard or by hand from variables. The **General** card holds the chatbot's **Name** and **Delete chatbot**, which removes the chatbot, its settings and any files it synchronized. #### The wizard **Use the wizard** is on for a new chatbot. The wizard lists the site's post types; switch on each one the chatbot should know about and choose what to **Include** of its posts: **Title**, **Content**, and **Post meta** where the post type has meta fields. **Current user** gives the chatbot the signed-in visitor's display name, email and roles, so it can greet them by name. **System instruction** is your own text, placed before what the wizard generates. Use it for the chatbot's role and tone: ```txt You are a helpful assistant for our website. Be friendly and concise. If you don't know the answer, say so. ``` **Generated instruction** shows the complete instruction the chatbot will use, read-only. The wizard builds it from variables: one query variable per post type, named `query_` and the post type, and a `currentUser` variable. Each post type's template gives every post its public URL and its type beside what you include, so the chatbot can link the posts it recommends. Switching the wizard off keeps those variables and the instruction, so you can start from them by hand. #### Variables With the wizard off, **Variables** lists the chatbot's variables and **Instruction** holds its instruction. A variable is a named value that replaces `{name}` in the instruction when a visitor sends a message. Select **Add variable**, choose its **Source**, and give it a name in **Variable**: ```txt You are an assistant for the page {pageTitle}. The visitor's name is {visitorName}. ``` The sources are: | Source | Value | | ------------------------ | --------------------------------------------------------------- | | Text | Fixed text you enter. | | Query | Posts from a WordPress query, each rendered through a template. | | Post title, Post content | The title or content of a post. | | Post meta | A post's meta. | | Taxonomy, Term | A taxonomy or a term. | | User, User meta | A user's account or their meta. | Plugins can add their own sources; see [Custom sources](#custom-sources). For the post, taxonomy, term and user sources, enter the ID to read, or switch on **Use the current value from the page** to read the post, term or visitor of the page the chatbot is on. **Meta key** picks one value out of the result with dot notation; for example, `data.display_name` on the User source gives the user's display name. Without a meta key, the whole result is sent as JSON; for the User source that is the display name, email and roles, and a key such as `data.user_login` reads any other field. Below a variable with an ID or a query, **Preview** shows the value it currently resolves to. #### Query variables A query variable lists posts. **Post types** shows the post types it reads, which the wizard sets; a query you add yourself reads posts. **Search value** limits it to posts that match a search, and **Match all terms** requires a post to match every term the query names rather than any. **Raw query arguments** replaces all of that with your own `WP_Query` arguments as JSON: ```json { "post_type": "product", "posts_per_page": 20, "orderby": "date" } ``` Raw arguments run as written, so set `posts_per_page`: without it, WordPress returns five posts. **Template** is rendered once for every post, one per line. Write post fields in curly brackets, such as `{ID}`, `{post_title}`, `{post_excerpt}` or `{post_content}`, and reach into the post's meta with a dot, as in `{post_meta.price}`. `{permalink}` is the post's public URL; `{guid}` is the GUID WordPress stored when the post was created, which is not always a working address: ```txt Product: {post_title} URL: {permalink} Price: {post_meta.price} ``` Without raw arguments a query has no limit, so a large post type makes a long instruction, and every visitor message pays for it. #### Synchronizing to OpenAI file search For large queries, **Enable file synchronization** uploads the rendered posts to OpenAI's file search instead of putting them in the instruction. The model then looks up what it needs for each question. It needs an OpenAI model on the chatbot's [Model](/docs/ai/chatbots/model.md) page; with any other model the switch is disabled and says so. A synchronization switched on before the model changed can still be switched off. **Synchronization interval** sets how often the file is refreshed: every minute, every 10 minutes, hourly, daily, weekly or monthly. Saving the chatbot uploads the file at once and schedules the refreshes, which run as the `sleek_ai_chatbot_file_sync` action in Action Scheduler. `wp sleek ai chatbot sync` uploads again on demand, and `wp sleek ai chatbot sync-status` shows whether each file is ready. Until a file is ready, visitors' messages are refused with "Synchronized chatbot data is not available yet. Sync the data and try again." rather than sending the whole query inline, which could cost far more than expected. The editor's preview uses the inline data instead, so you can try the chatbot while the file uploads. #### Retrieval priority With file synchronization, OpenAI's file search decides which content a reply reads. **Retrieval priority** on the Data page lets you weigh that choice instead, so that, for example, your documentation pages win over blog posts that mention the same thing. It needs an OpenAI model and at least one synchronized query; without them the switch is disabled and says what it needs, though a priority switched on before can still be switched off. With it on, every synchronized post is uploaded as a file of its own, with its title, URL and type, into one search index for the chatbot. For each visitor message SleekAI searches that index itself, with the visitor's two previous questions as context, and ranks what it finds: relevance first, raised or lowered by each post's priority. The best eight posts reach the model as reference data, each with its title and URL, so the chatbot links the posts it names. Each synchronized query gets a priority, **Low**, **Normal** or **High**, or an exact weight from 0.5 to 1.5 beside it; Normal is 1. Below the queries, each post type the queries read can take its own priority, which takes precedence over its query's; **Use query priority** leaves it to the query. A priority moves a post past others that are about as relevant, never past a much better match, and never brings in content that does not match at all. Saving the chatbot rebuilds the index; unchanged posts are not uploaded again. Until the first index is ready, visitors' messages are refused as with file synchronization, and a failed rebuild keeps the previous index. Turning the priority off keeps the index, which the chatbot then searches through OpenAI's file search; moving the chatbot to another provider removes it, and moving back builds it again. The `sleek_ai_chatbot_retrieval_weight` filter sets the weight of single posts, for example to raise one product page: ```php add_filter('sleek_ai_chatbot_retrieval_weight', function ($weight, $postId) { return $postId === 42 ? 1.5 : $weight; }, 10, 2); ``` The [hooks reference](/docs/ai/reference/hooks.md) describes the filter's arguments. #### Custom sources The `sleekAi/chatbot/sources` filter adds sources to the list. Each entry has an `id`, a `label` and a string `value`: ```php add_filter('sleekAi/chatbot/sources', function ($sources) { $sources[] = [ 'id' => 'openingHours', 'label' => 'Opening hours', 'value' => get_option('my_opening_hours', 'Mon-Fri 9:00-17:00'), ]; return $sources; }); ``` A variable that uses the source is replaced with its value. SleekAI reads the value while it answers a visitor's message, in a REST request, so the value cannot depend on the page the visitor is on; use the built-in sources for page data. The [hooks reference](/docs/ai/reference/hooks.md) describes the filter's arguments. ### Conditions Section: Chatbots URL: https://sleekwp.com/docs/ai/chatbots/conditions/ Markdown: https://sleekwp.com/docs/ai/chatbots/conditions.md A chatbot's floating widget appears on a page only when its display conditions match. A chatbot without conditions appears nowhere, which lets you place it with a [shortcode](#shortcodes) alone. #### Display conditions The **Conditions** page holds groups of conditions. Conditions inside a group must all match (And); the widget appears when any group matches (Or). Each condition compares one parameter with a value, using `==` (is equal to) or `!=` (is not equal to). | Parameter | Matches | | ---------------------------- | --------------------------------------------------------------------------------------------------------- | | Admin area | Any screen of the WordPress admin. | | Admin page | One admin screen, by its file, such as `edit.php`, or a plugin's page by its slug, such as `woocommerce`. | | Block editor | The block editor. | | Post type | Posts of one post type. | | Post ID | One post, by its ID. | | Post status | Posts with one status. | | Page template | Pages that use one template. | | Taxonomy | Archives of one taxonomy. | | Term | Archives of one term, by its ID or slug. | | User logged in | Visitors who are signed in. | | User role | Signed-in users who hold one role, among any others. | | Home | The blog posts index. | | Front page | The site's front page. | | Page | Static pages. | | Single | A single post of any post type except pages. | | Singular | Any single post, page or attachment. | | Search | Search results. | | Archive | Any archive. | | Post type archive | The archive of a post type. | | Category | Category archives. | | Tag | Tag archives. | | Taxonomy archive | Archives of custom taxonomies. | | Author | Author archives. | | Date, Year, Month, Day, Time | Date-based archives. | | Attachment | Attachment pages. | | Not found | The 404 page. | Admin area, Block editor, User logged in and the yes-or-no parameters such as Home take no value: `==` requires the page to match and `!=` requires it not to. A condition whose parameter no longer exists, such as a custom condition whose plugin was removed, never matches, so its group does not match either. #### Custom conditions The `sleekAi/chatbot/conditions` filter adds parameters to the list. Each entry has an `id`, a `label` and a `value` that SleekAI computes while the page renders: ```php add_filter('sleekAi/chatbot/conditions', function ($conditions) { $conditions[] = [ 'id' => 'isCampaign', 'label' => 'Campaign visitor', 'value' => isset($_GET['utm_campaign']), ]; return $conditions; }); ``` The editor lists the entry by its label. An `id` that starts with `is` or `has` makes a yes-or-no condition like the built-in ones; any other compares its value with the value you enter. The [hooks reference](/docs/ai/reference/hooks.md) describes the filter's arguments. #### Shortcodes The **Shortcodes** card shows the two shortcodes of the chatbot. The first places the floating widget wherever the shortcode is used. A chatbot without conditions shows wherever its shortcode is; a chatbot with conditions shows through its shortcode only on pages where they match, as the floating widget does, and only while the chatbot is published: ```txt [sleek-ai-chatbot id="3"] ``` The second embeds the chat itself, at full width, in the content: ```txt [sleek-ai-chatbot id="3" type="chat"] ``` `type` takes `widget`, the default, or `chat`; `embed` is another name for `chat`. ### Model Section: Chatbots URL: https://sleekwp.com/docs/ai/chatbots/model/ Markdown: https://sleekwp.com/docs/ai/chatbots/model.md The **Model** page chooses the model that answers the chatbot's visitors. Its list holds the models of every provider with a stored [API key](/docs/ai/settings/api-keys.md), and your [custom models](/docs/ai/settings/custom-models.md), with a search field. The editor proposes OpenAI's `gpt-4o-mini` for a new chatbot; save the page to keep the model you choose. Choose with the chatbot's job in mind. A small, fast model answers simple questions about your content well and cheaply, since every visitor message is billed by the provider along with the chatbot's whole instruction. A larger model is worth it for questions that need reasoning across a lot of content. [File search](/docs/ai/chatbots/data.md#synchronizing-to-openai-file-search) needs an OpenAI model. A chatbot that uses a custom model reaches it as the chatbot's author, so the model and its API key have to belong to the user who created the chatbot. #### Limits on visitor requests Visitors' requests are checked before they reach the provider. A request must come from a chatbot rendered on the site, and a conversation larger than 256 KiB, as JSON, is refused as too large. The `sleekAi/chatbot/maxRequestBytes` filter changes that limit; see the [hooks reference](/docs/ai/reference/hooks.md). A visitor can send one chatbot 30 messages in five minutes; further messages are refused until the five minutes are over, and the chatbot shows the reason. Visitors are told apart by their IP address, so on a site behind a proxy that does not pass the visitor's address on, all visitors share one limit. The `sleekAi/chatbot/rateLimit` filter changes the number, per chatbot, and `0` removes the limit. Administrators are not limited. All of a chatbot's visitors together can send it 200 messages an hour and 1,000 a day, which caps what a public chatbot can cost however many visitors, or addresses, its messages come from. The hour starts on the hour and the day at midnight UTC; once either budget is used up, the chatbot tells every visitor to try again later until that window ends. A message the budget refuses does not count against it. The `sleekAi/chatbot/budget` filter changes either number, per chatbot, and `0` removes that budget; administrators' messages are not counted. With a persistent object cache the budget is counted atomically; without one, messages that arrive at the same moment can pass it by a few. ### Widget Section: Chatbots URL: https://sleekwp.com/docs/ai/chatbots/widget/ Markdown: https://sleekwp.com/docs/ai/chatbots/widget.md The **Widget** page designs the chatbot as visitors see it: the button that opens it, the chat window, and what visitors may do. Its settings are grouped in sections that open one by one. The preview pane shows the floating widget with your unsaved changes; **Keep the preview widget open** keeps its chat window open there while you work. **Reset widget settings** returns every setting on the page to its default. The sections you open are kept in the address, before the `#`, as `open`, for example `open=button,chat,storage`. #### General **Allow fullscreen** adds a button to the chat window's header that switches it to fullscreen and back. Small screens do not show it. #### Position **Alignment** places the widget in the bottom left or bottom right corner, and **Distance** sets its distance from the edges, for example `16px` or `1rem`. #### Button **Type** chooses between a **Button** with text and a **Logo**, a button that shows an image. For a logo, **Logo URL** takes an image address or an image chosen from the media library. For a text button, **Text** is its label, **Border radius** rounds its corners, for example `8px`, and **Font size** sets its text size, for example `14px`. **Text color**, **Background color** and **Border color** apply to both types. [Styling](/docs/ai/chatbots/styling.md) explains how these settings reach the page and which other properties you can change in CSS. #### Chat - **Welcome message** is the first message visitors see when the chat opens. - **Theme** chooses **Light**, **Dark** or **Dark (WordPress)**. - **Assistant name** is the title in the chat window's header, unless a [logo](#logo) takes its place. - **Input placeholder** is the hint in the empty message field. #### Storage **Storage mode** decides how a visitor's chat history is kept. History only ever lives in the visitor's browser; SleekAI keeps no conversation on the server unless [logging](/docs/ai/chatbots/logs.md) is on. - **No storage**: the chat starts empty on every page load. - **Session storage**: the chat survives navigation between pages until the browser tab is closed. - **Browser database**: chats are kept in the browser's IndexedDB across visits. The chat window's menu then offers **New Chat** and **Chat history**, so visitors can start new chats and return to earlier ones. #### Message actions These switches let visitors act on the chatbot's replies: - **Allow a new chat from a message** offers **New chat from here**, which starts a new chat from a reply. It needs the **Browser database** storage mode. - **Allow regenerating a reply** offers **Regenerate**, which asks the model for a new reply. - **Allow deleting from a message** offers **Delete from here**, which removes a reply and everything after it. #### Logo **URL** sets an image, by address or from the media library, shown in the chat window's header in place of the assistant name. #### Presets Presets are suggested questions shown as buttons in the chat, so a visitor can start with one click. **Label** heads the group, for example "Quick questions"; **Add preset** adds a question under **Preset questions**. ### Logs Section: Chatbots URL: https://sleekwp.com/docs/ai/chatbots/logs/ Markdown: https://sleekwp.com/docs/ai/chatbots/logs.md The **Logs** page records the conversations visitors have with the chatbot, so you can see what they ask and how the chatbot answers. #### Recording conversations **Enable logging** starts recording; it is off for a new chatbot. From then on SleekAI stores each visitor message and each completed reply on the server, whether the reply was streamed or polled and whether the chatbot uses [file search](/docs/ai/chatbots/data.md#synchronizing-to-openai-file-search). Turning logging off stops recording and keeps what was recorded. #### Reading the logs **Logged conversations** lists the recorded conversations, newest first, 50 to a page, with their date and number of messages. Open a row to read the conversation in the preview pane beside the page, which opens with it. The selected conversation and the page number are kept in the address, before the `#`, as `log` and `paged`, so a link can open one conversation; a page past the last one opens the last. Select conversations and delete them with the button that counts them, such as **Delete 2 logs**; with none selected, **Delete all logs** removes every conversation of the chatbot. Either asks first, since deleted logs cannot be restored. From the command line, `wp sleek ai chatbot logs` lists a chatbot's conversations and `wp sleek ai chatbot logs-delete` removes them; see the [CLI reference](/docs/ai/reference/cli.md). #### Privacy Logged conversations contain whatever visitors type. Before you turn logging on: - tell visitors that conversations are recorded, for example in the welcome message or your privacy policy; - follow the privacy rules that apply to your site; - decide how long to keep them. A retention period set with `wp sleek ai settings update retention.days 30` deletes logs, like chats, once they are older than that; see [Chat](/docs/ai/chat.md#keeping-chats-for-a-limited-time). ### Styling Section: Chatbots URL: https://sleekwp.com/docs/ai/chatbots/styling/ Markdown: https://sleekwp.com/docs/ai/chatbots/styling.md A chatbot has to look the same in every theme, so it stays apart from the page. SleekAI prints a floating chatbot's button on the page and renders the chatbot, its button included, inside a frame that theme styles do not reach. The frame loads only once a visitor reaches for the button and then takes its place ([when chatbots load](/docs/ai/chatbots/api.md#when-chatbots-load)). The button's look comes from CSS custom properties, which both the page's button and the framed button read. #### Widget settings Six properties come from the chatbot's [Widget](/docs/ai/chatbots/widget.md) page, or from the `widget` options of [`sleekAi_render_chatbot()`](/docs/ai/chatbots/api.md#render-a-chatbot-from-php): | Widget setting | Option | CSS custom property | Fallback | | ------------------------- | ------------------------ | ---------------------------------------------- | ---------- | | Position > Distance | `position.distance` | `--sleek-ai--chatbot-position--distance` | `16px` | | Button > Text color | `button.color` | `--sleek-ai--chatbot-button--color` | `#000000` | | Button > Background color | `button.backgroundColor` | `--sleek-ai--chatbot-button--background-color` | `#FFFFFF` | | Button > Border color | `button.borderColor` | `--sleek-ai--chatbot-button--border-color` | `#E4E4E7` | | Button > Border radius | `button.borderRadius` | `--sleek-ai--chatbot-button--border-radius` | `8px` | | Button > Font size | `button.fontSize` | `--sleek-ai--chatbot-button--font-size` | `0.875rem` | A chatbot created in the editor starts with its own values for these settings; the fallback applies when a chatbot has no value, for example when a `sleekAi_render_chatbot()` call leaves the option out, and when a value is not one the property takes. The colours take a hex colour, an `rgb()`, `rgba()`, `hsl()` or `hsla()` value, a `var()` reference or a colour name; the distance, border radius and font size take a number with a unit, such as `16px`, `1rem` or `50%`, `0`, or a `calc()` of those. SleekAI sets these six on the chatbot itself, on the page and in the frame, so change them in the widget settings rather than in CSS. #### Other properties These properties have no widget setting. The framed button reads the four marked "frame"; the placeholder on the page reads all of them. | CSS custom property | Default | Read in | | --------------------------------------------------- | --------------------------------------------------------------- | ----------- | | `--sleek-ai--chatbot-button--box-shadow` | `0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)` | page | | `--sleek-ai--chatbot-button--font-feature-settings` | `normal` | page, frame | | `--sleek-ai--chatbot-button--font-weight` | `500` | page, frame | | `--sleek-ai--chatbot-button--line-height` | `1` | page, frame | | `--sleek-ai--chatbot-button--padding` | `12px 16px` | page, frame | | `--sleek-ai--chatbot-button--position` | `fixed` | page | To change them inside the frame, add a `'; }); ``` Add only `'; }, 10, 2); ``` The [hooks reference](/docs/ai/reference/hooks.md) lists their arguments. #### JavaScript API The script that SleekAI prints with the first chatbot on a page defines `window.SleekAI.chatbot`: ```js // Open the first chatbot on the page, or open it in fullscreen. SleekAI.chatbot.open() SleekAI.chatbot.open({ fullscreen: true }) // Close it again. SleekAI.chatbot.close() // Hide the widget and its button, for example while another modal is open, // and show it again. SleekAI.chatbot.hide() SleekAI.chatbot.show() // Every method takes the chatbot's position on the page. SleekAI.chatbot.hide({ index: 2 }) ``` `index` is not the chatbot's ID. It counts every chatbot on the page, embedded chats included, in the order SleekAI renders them, starting at 1. Shortcodes in the page content render before the saved widget chatbots, which SleekAI adds in the footer. `hide()` and `show()` act on floating widgets only. ##### When chatbots load A visitor who never uses a chatbot downloads only its button and settings. A floating chatbot loads its frame when a pointer moves onto its button, the button takes focus or a finger touches it, so it is usually ready by the time the visitor clicks. A click that arrives sooner shows the button busy and opens the chat as soon as it has loaded. The framed button then replaces the page's button in place and keeps its focus. An embedded chat loads when it comes within 400 pixels of the viewport, in browsers without `IntersectionObserver` at once. `SleekAI.chatbot.open()` loads a chatbot that has not loaded yet and opens it once it has; `close()` acts on loaded chatbots only. #### REST management Administrators can manage saved chatbots through SleekAI's REST operations, with normal WordPress REST authentication such as a REST nonce or an application password: - `Chatbot_list` lists every chatbot. - `Chatbot_create` creates a chatbot. Every call creates another one. - `Chatbot_read` returns one chatbot. - `Chatbot_update` replaces a chatbot's saved definition. - `Chatbot_remove` deletes a chatbot and its synchronized files. The [REST reference](/docs/ai/reference/rest.md) gives their methods and paths, under `sleek-ai/v1/chatbot`. Every one requires the `manage_options` capability. `Chatbot_update` replaces, it does not merge. Always send the full chatbot returned by `Chatbot_read`; omitted sections are removed and the editor shows their defaults. `wp sleek ai chatbot create` and `wp sleek ai chatbot update` do the same from the command line, from a JSON file. ### General Section: Agent URL: https://sleekwp.com/docs/ai/agent/general/ Markdown: https://sleekwp.com/docs/ai/agent/general.md The Agent is an AI assistant that works beside the WordPress screen you are on. It sees that screen and, depending on its [mode](/docs/ai/agent/modes.md), can read and change what is on it: blocks in the block editor, a page in a page builder, or anything a WordPress ability offers. #### Opening the Agent Press `Cmd + Shift + L` on a Mac, or `Ctrl + Shift + L` on Windows and Linux, on any WordPress admin screen. The page reloads with the Agent in a column on the left and your screen, still fully usable, on the right. The same shortcut closes the Agent and returns to the plain screen. The shortcut also works in the Bricks, Breakdance, Beaver Builder, Elementor and Etch editors. It is not available on the workspace screen, which has its own assistant. Only users whose role may use the Agent can open it; by default that is administrators. [Settings](/docs/ai/agent/settings.md) changes which roles may. #### The Agent column The header of the column has three controls: - **Options** starts a **New chat**, and, in a mode that supports it, a new [coding agent](/docs/ai/agent/coding-agents.md) terminal. - The mode button shows the current mode. It opens **Agent modes**, where you pick another mode. A chat keeps the mode it started with, so the button only changes the mode before the first message. In a page builder the builder's mode is fixed. - **History** lists your earlier Agent conversations, to reopen or delete. Below them is the conversation, and at the bottom the message field with its model selector. The selector lists the models of every provider with a stored [API key](/docs/ai/settings/api-keys.md) and remembers your choice. #### What the Agent can do What the Agent can change depends on the mode: - In the block editor and the supported page builders it works on the open page through a virtual copy of its content and tools of the editor, and your changes appear on the right as it makes them. You still save the page yourself. - In every mode it can look for and run WordPress [abilities](/docs/ai/agent/abilities.md), within your own permissions. - Modes that allow it can run JavaScript in the page on the right. Requests go to the AI provider through your site: the Agent's browser never holds an API key, and SleekAI adds the stored key on the server. This relay serves OpenAI, Anthropic, Google and OpenRouter, so the Agent cannot use [custom models](/docs/ai/settings/custom-models.md), although the selector lists them. #### The Agent, Chats, chatbots and the assistant - **The Agent** works beside an admin screen or page builder, with tools that act on it. - **[Chats](/docs/ai/chat.md)** is a plain conversation with a model, in the AI workspace. - **[Chatbots](/docs/ai/chatbots/general.md)** talk to your site's visitors. - **The workspace assistant**, opened from the workspace header, helps inside the workspace itself; it belongs to the workspace and works without SleekAI. Agent conversations are stored per user, apart from your chats, and a [retention period](/docs/ai/chat.md#keeping-chats-for-a-limited-time) deletes them like chats. ### Coding Agents Section: Agent URL: https://sleekwp.com/docs/ai/agent/coding-agents/ Markdown: https://sleekwp.com/docs/ai/agent/coding-agents.md In a page builder, the [Agent](/docs/ai/agent/general.md) can open a terminal that runs **Claude Code** or **Codex** on your own computer. The coding agent works on files that mirror the open page and calls tools of the live builder, so it can make changes that cross structure, content, styles and responsive settings. The terminal needs the local `@sleekwp/agent` bridge, which connects the browser, the coding agent and the builder over `ws://localhost:5733`. #### Supported builders Coding agents are available in the modes of these builders: - Bricks - Breakdance - Beaver Builder - Elementor - Etch Each builder maps its own page structure, settings, CSS and save operations to files and tools, so the files and tools differ from one builder to the next. #### Requirements - Node.js 20 or newer on your computer. - Claude Code, Codex or both, installed and signed in. - The `@sleekwp/agent` bridge running on the same computer as the browser. - A supported builder open in WordPress, with the Agent open beside it. The coding agent uses its own sign-in and billing. The API keys stored in SleekAI are not used by the terminal. #### Starting the bridge Run the bridge before you open a terminal: ```bash npx @sleekwp/agent ``` Or install it once and run it by name: ```bash npm install -g @sleekwp/agent sleekwp-agent ``` The bridge listens on your own computer only. Set `SLEEKWP_AGENT_HOME` before starting it to keep its workspaces somewhere other than `~/.sleekwp/agent`. #### Opening a terminal Open the Agent's **Options** menu. When the bridge runs, it offers **New Claude Code Terminal** and **New Codex Terminal** for each tool it found installed. Otherwise the menu says what is missing: **Start SleekWP Agent** when the browser cannot reach the bridge, or **Install Claude Code or Codex** when neither is installed. A session then works like this: 1. The Agent sends the open page, as files, and the builder's tools to the bridge. 2. The bridge writes the files to a workspace and starts the coding agent there. 3. The coding agent's output streams into the terminal in the Agent column. 4. When it changes a file, the builder's tools apply the change to the open editor, where you see it. 5. Review the result and save the page in the builder. #### Workspace files The workspace represents the open page as ordinary files. Depending on the builder they hold element or node JSON, custom CSS, responsive styles, global classes, schemas and rendered HTML, with instructions for that builder. In Elementor, Beaver Builder and Breakdance, a setting of more than one line, such as an HTML widget's markup, is a plain HTML, CSS, JavaScript or text file in the element's `settings/` folder (`properties/` in Breakdance), which the element's JSON refers to; the coding agent edits it, and you review it, as ordinary text rather than one escaped JSON string. The bridge also writes the coding agent's own configuration: | Coding agent | Files | | ------------ | ---------------------------------------------------------- | | Claude Code | `CLAUDE.md`, `.mcp.json` and `.claude/settings.local.json` | | Codex | `AGENTS.md` and `.codex/config.toml` | Both register a local MCP server named `sleekwp`, through which the coding agent calls the tools of the builder open in your browser, including its unsaved state. The workspace is a working copy of the page's builder data, not your theme or plugin directory. #### Reopening a session Terminal sessions are listed in the Agent's **History** with a terminal icon. Closing the Agent or reloading the page does not stop the coding agent; reopening the session reattaches to it. The workspace also survives a restart of the bridge: Claude Code continues the workspace's conversation, and Codex resumes its matching session, so the history stays with the page. #### Privacy The browser talks to the bridge on your computer directly. The WordPress site can be local or remote, as long as the browser that shows its admin can reach `localhost:5733`. File and terminal traffic stays between the browser and the bridge; the coding agent itself still talks to its own service, under that provider's terms. ### Settings Section: Agent URL: https://sleekwp.com/docs/ai/agent/settings/ Markdown: https://sleekwp.com/docs/ai/agent/settings.md The **Agent** section of AI's **Settings** decides which user roles may use the [Agent](/docs/ai/agent/general.md). Its **Agent access** card lists every role on the site, including roles added by plugins, each with a switch; turn on the roles that may use the Agent and save. The address of the Agent page of earlier releases, `#/ai/agent`, opens the same section. By default only administrators may use the Agent; on a multisite network, super admins always may. On a single site, the Administrator row applies to administrators like any other row. A user with several roles may use the Agent when any of their roles may. For a role that is off, the shortcut does nothing for that user and the Agent does not open. #### What other roles can do A role that may use the Agent loads the models, keeps its own conversations and lists and runs WordPress abilities. Each ability still checks the user's own WordPress capabilities, so an editor's Agent can do only what the editor could. Chatbots, settings, API keys and custom models stay with administrators. #### From the command line `wp sleek ai agent caps list` shows every role's Agent capabilities, and `wp sleek ai agent caps set` changes one: ```bash wp sleek ai agent caps set editor --cap=useAgent=1 ``` Besides `useAgent`, each role stores `createModes`, `shareModes`, `manageAllModes` and `usePluginMode`. The Agent itself uses only `useAgent`; the next three apply to stored custom modes, which the Agent does not offer in this release (see [Modes](/docs/ai/agent/modes.md)), and `usePluginMode` is kept from earlier versions and has no effect. The [CLI reference](/docs/ai/reference/cli.md) lists the options. ### Context Section: Agent URL: https://sleekwp.com/docs/ai/agent/context/ Markdown: https://sleekwp.com/docs/ai/agent/context.md A context tells the [Agent](/docs/ai/agent/general.md) which kind of screen it is on: a normal admin screen, the block editor, or a page builder. The Agent looks for the context of the page on the right whenever that page changes, offers the modes whose `detection` names it, and remembers the mode you chose for each context. A context and a mode are different things. The context is found from the page and you do not choose it; the mode is what you choose, and it decides what the Agent knows and can do. #### Built-in contexts | Context | Recognised by | | ----------------------------------------------------- | ---------------------------------------------------------- | | `wp-admin` | The `wp-admin` class on the page's `body`. | | `block-editor` | The `block-editor-page` class on the page's `body`. | | `bricks`, `breakdance`, `beaver`, `elementor`, `etch` | The page builder's editor, when the Agent is opened in it. | A screen that matches no context counts as `wp-admin`. #### Registering a context `Agent::registerContext()` adds a context for a screen of your own, so that a [mode](/docs/ai/agent/modes-api.md) can be detected there: ```php add_action('sleekAi/init', function () { \SleekAi\Agent\Agent::registerContext([ 'id' => 'my-plugin-admin', 'selector' => [ 'bodyClass' => 'my-plugin-admin-page', ], ]); }); ``` `selector.bodyClass` matches a class of the page's `body`, and `selector.element` a CSS selector of an element on the page. A mode then names the context in its `detection`, and the Agent offers it only where the context's selector matches: ```php 'detection' => ['context' => 'my-plugin-admin'], ``` The Agent decides the screen's own context, which chooses the default mode, from the contexts in the order they were registered, trying `wp-admin` last because every admin screen matches it. A context you register therefore becomes the screen's context wherever its selector matches, and the Agent opens there in your mode. A context may also carry `styling` rules, which earlier versions used to fit the admin screen around the Agent panel. The Agent now shows the page in a frame beside its own column, so it keeps those rules but does not apply them. ### Modes Section: Agent URL: https://sleekwp.com/docs/ai/agent/modes/ Markdown: https://sleekwp.com/docs/ai/agent/modes.md A mode tells the [Agent](/docs/ai/agent/general.md) what it is for and what it may do: its instruction, the tools it has, whether it works on a virtual copy of the page's content, and whether it may run JavaScript in the page. #### Choosing a mode The mode button in the Agent's header opens **Agent modes**, which lists the modes available on the current screen, grouped by category: **General**, **WordPress**, and any category a plugin's modes add. Pick one before you send the first message of a chat; the chat keeps that mode. The Agent remembers the mode you chose for each kind of screen. A mode made for one screen, such as the block editor, is listed only on that screen and is chosen there by default. A page builder's mode is the only mode in that builder and cannot be changed. #### Built-in modes | Mode | Category | Where | What it does | | ----------------------------------------------------------- | --------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Chat | General | Every screen but the page builders | A general assistant. It can run JavaScript in the page. | | Block Editor | WordPress | The block editor | Works on the post's blocks, each a JSON file it reads and writes, can run JavaScript to insert, remove or move blocks, and has a `get_selected_block` tool that names the block you selected. | | Bricks Builder, Breakdance, Beaver Builder, Elementor, Etch | WordPress | Their editor | Works on the open page through a copy of its structure and the builder's own tools, and offers [coding agents](/docs/ai/agent/coding-agents.md). | Every mode can also look for and run WordPress [abilities](/docs/ai/agent/abilities.md). #### Virtual files The Block Editor and page builder modes give the Agent the page as files instead of letting it touch the editor directly. The files are not stored on your server: each one stands for part of the open page, such as one block. When the Agent writes a file, the mode applies the change to the editor, and you see it on the right at once. Nothing is saved until you save the page in the editor. In Bricks, the Agent can also save Bricks' global settings when you ask it to. A save that changes the global custom CSS, the builder CSS, the header and body scripts or Bricks' code execution setting needs a user who may write code on the site: on a network a network administrator, on a single site an administrator who may post unfiltered HTML. For anyone else the save is refused and nothing is written. #### JavaScript Modes that allow it give the Agent a tool that runs JavaScript in the page on the right, with WordPress's `wp` object at hand. It is how the Block Editor mode inserts and removes blocks, which a file cannot express. The code runs in your browser with your permissions, as if you had typed it into the browser's console, and the Agent runs it without asking first. #### Modes that are not offered Custom modes stored on the site, by an earlier SleekAI version or through the `AgentMode_create` REST operation, are kept but not listed. The Agent lists the modes that code registers; [Modes API](/docs/ai/agent/modes-api.md) describes how a plugin adds one. ### Modes API Section: Agent URL: https://sleekwp.com/docs/ai/agent/modes-api/ Markdown: https://sleekwp.com/docs/ai/agent/modes-api.md A plugin can add its own [modes](/docs/ai/agent/modes.md) to the Agent. A mode is declared in PHP with `Agent::registerMode()`, and a script can extend it in the browser with files, tools and an instruction built at run time. The built-in Block Editor mode is made exactly this way. #### Registering a mode Register the mode once SleekAI has booted, on the `sleekAi/init` action: ```php add_action('sleekAi/init', function () { \SleekAi\Agent\Agent::registerMode([ 'id' => 'product-writer', 'label' => 'Product writer', 'description' => 'Writes product descriptions', 'category' => 'Shop', 'detection' => ['bodyClass' => 'post-type-product'], 'agent' => [ 'systemInstruction' => './product-writer.md', 'executeJs' => true, ], 'script' => plugins_url('product-writer.js', __FILE__), ]); }); ``` | Key | Meaning | | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | Required. A unique identifier, in lowercase letters and hyphens. | | `label` | The name in the mode list. Defaults to the `id`. | | `description` | The line under the name in the mode list. | | `category` | The group in the mode list. Defaults to `General`; a new name makes a new group. | | `detection` | Limits the mode to matching screens. `bodyClass` matches a class of the page's `body`, `elementSelector` an element on the page, and `context` a [context](/docs/ai/agent/context.md) by its id; a mode that names the screen's own context is also chosen there by default. Without it, the mode is offered everywhere. | | `requiresCapability` | An Agent role capability the user needs. The Agent knows only `useAgent` in this release, so any other value hides the mode. | | `toolbar` | A toolbar the mode shows. A mode with the `plugin` toolbar is not offered in this release. | | `agent.systemInstruction` | The mode's instruction. A string, or a path starting with `./` to a Markdown file beside the file that registers the mode. | | `agent.canvas` | Gives the Agent virtual files, which a script provides. | | `agent.executeJs` | Lets the Agent run JavaScript in the page. | | `agent.isolated` | Makes the mode the only one where it is detected, as the page builder modes are. | | `agent.claude` | `enabled` and `claudeMd`, the instructions for a [coding agent](/docs/ai/agent/coding-agents.md) terminal. Terminals also need `canvas`. | | `script`, `scripts` | URLs of scripts the Agent loads before it starts, to extend the mode. | The Markdown file of `systemInstruction` and `claudeMd` must lie inside the directory of the registering file; a path outside it gives an empty instruction. #### Extending a mode in the browser A mode's script calls `window.sleekAiAgent.extendMode()` with the mode's id. Whatever it passes under `agent` is merged into the mode. The script runs in the Agent's own document, not in the page on the right; `window.sleekAiAgent.iframeEl()` returns the frame that holds the page: ```js window.sleekAiAgent = window.sleekAiAgent || {} const page = () => window.sleekAiAgent.iframeEl().contentDocument window.sleekAiAgent.extendMode("product-writer", { agent: { systemInstruction: () => "You write product descriptions for " + page().title, tools: [ { name: "get_product_title", description: "Returns the title of the product being edited.", schema: { type: "object", properties: {}, required: [] }, execute: () => ({ title: page().title }), }, ], }, }) ``` - `systemInstruction` may be a function, called for every request, so the instruction can describe the current state of the page. - `tools` are offered to the model by `name`. A tool's `schema` is a JSON Schema of its input, and `execute` receives that input and returns a JSON-compatible result. A tool may not reuse the name of another tool: the request fails if one does. - `fileSystem`, with `canvas`, provides the virtual files. `getInitialFiles()` returns an object of paths and contents at the start of each request, and `onFileChange(path, content)` applies a file the Agent wrote to the page. `onBeforeRead(path)` returns the current content of a file when a coding agent reads it. The built-in Block Editor mode, in SleekAI's `includes/agents/modes/block-editor/script.js`, is a complete example: every block is a `blocks//block.json` file, a written file updates the block's attributes or replaces it, and `get_selected_block` names the block you selected. #### Contexts A context tells the Agent which kind of screen it is on, so that `detection` can name it. [Context](/docs/ai/agent/context.md) describes the built-in ones and `Agent::registerContext()`. ### Abilities Section: Agent URL: https://sleekwp.com/docs/ai/agent/abilities/ Markdown: https://sleekwp.com/docs/ai/agent/abilities.md WordPress 6.9 added the Abilities API: a registry of actions that WordPress, plugins and themes offer, each with a name such as `core/get-site-info`, a description, a schema of its input and output, and its own permission check. The [Agent](/docs/ai/agent/general.md) can find and run them in every mode. On an older WordPress, the Agent answers that abilities are not available. #### How the Agent uses them The Agent has two tools for abilities: - `search_abilities` lists the abilities you may run, optionally filtered by a search term, matched against their name, label and description, and by a category. - `execute_ability` runs one ability by name with its input. Ask for something an ability can do, such as "What is the site's name?", and the Agent searches for a fitting ability, reads what input it needs, runs it and reports the result. #### Permissions The Agent sees and runs only the abilities you may use: each ability's own permission check runs before it is listed and again before it runs. The Agent cannot do through an ability what you could not do yourself. Searching and running abilities also needs the `manage_options` capability, through the `Abilities_list` and `Abilities_run` operations. #### Where abilities come from Any plugin can register abilities, and the Agent gains them without any setting. That includes the SleekWP products: the capabilities they declare for the workspace assistant are registered as WordPress abilities too, so the Agent can find and run them as well. ### Developer API Section: Reference URL: https://sleekwp.com/docs/ai/api/ Markdown: https://sleekwp.com/docs/ai/api.md SleekAI defines a few global PHP functions. They exist only while SleekAI is active, so guard calls with `function_exists()` in code that can run without it. Its hooks, WP-CLI commands and REST operations are listed in the generated references: [hooks](/docs/ai/reference/hooks.md), [CLI](/docs/ai/reference/cli.md) and [REST](/docs/ai/reference/rest.md). #### Generate a response `sleekAi_generate_response()` sends one request to a provider with the stored API key and waits for the complete reply. ```php if (function_exists('sleekAi_generate_response')) { $response = sleekAi_generate_response([ 'model' => 'openai-gpt-4.1-nano', 'messages' => [ [ 'role' => 'system', 'content' => 'You are a helpful assistant.', ], [ 'role' => 'user', 'content' => 'What is 1 + 1?', ], ], ]); if ($response['success']) { $answer = $response['content']; } else { error_log('SleekAI: ' . $response['error']); } } ``` ##### Arguments | Key | Description | | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `model` | The provider and model, see below. Required unless `chatbotId` names a chatbot with a model. | | `messages` | Required. A list of messages, each with a `role` (`system`, `user` or `assistant`) and a `content` string. | | `max_tokens` | The longest reply, in tokens. Without it, OpenRouter requests use `2048` and Anthropic requests `8192`; the other providers use their own default. | | `temperature`, `top_p` | Sent to every provider. | | `frequency_penalty`, `presence_penalty` | Sent to OpenAI, OpenRouter and custom models. | | `chatbotId` | The ID of a saved chatbot. Its instruction, with the fixed chatbot guidelines and its variables filled in, replaces the system message, and its model is used when `model` is missing. | ##### Model `model` is the provider, a hyphen and the provider's model identifier: | Provider | Example | | ------------ | -------------------------------------------------- | | OpenAI | `openai-gpt-4.1-nano` | | Anthropic | `anthropic-claude-sonnet-4-5` | | Google | `google-gemini-2.5-flash` | | OpenRouter | `openrouter-openai/gpt-4.1` | | Custom model | `custom-` followed by the name the model was given | SleekAI turns every underscore into a hyphen before it splits the string, so `openai_gpt-4.1-nano` works too. `wp sleek ai models list` prints the model identifiers available with the stored keys. [Custom models](/docs/ai/settings/custom-models.md) belong to the user who created them, and SleekAI finds one only while that user is the current user. Cron jobs, visitor requests and WP-CLI calls without `--user` therefore need a provider model. ##### Return value The function returns an array. On success it holds the reply text in `content`; on failure it holds a message in `error`, for example `API key not found for provider: openai`, or `HTTP 401: ` followed by the provider's response. ```php $success = [ 'success' => true, 'content' => '1 + 1 equals 2.', ]; $failure = [ 'success' => false, 'error' => 'API key not found for provider: openai', ]; ``` ##### Providers The same `messages` work for every provider: SleekAI converts them to each provider's format. The request does not stream and blocks until the provider answers, so run it in a background task or an admin action rather than on every page view. #### Render a chatbot `sleekAi_render_chatbot()` prints a chatbot built from an array. See the [Chatbot API](/docs/ai/chatbots/api.md). #### Other functions - `sleekAi()` returns the `SleekAi\Plugin` instance, which has `getVersion()`, `getPluginDir()`, `getPluginFile()` and `getPluginUrl()`. - `sleekAi_use_polling()` returns whether replies are polled rather than streamed, after the `sleekAi/polling` filter; see [Streaming](/docs/ai/streaming.md). ```php if (function_exists('sleekAi')) { $version = sleekAi()->getVersion(); $polling = sleekAi_use_polling(); } ``` To run code once SleekAI has booted, use the `sleekAi/init` action, which passes the same instance. SleekAI boots on `plugins_loaded`, so add the callback from a plugin; a theme loads too late to catch it. ### PHP hooks Section: Reference URL: https://sleekwp.com/docs/ai/hooks/php/ Markdown: https://sleekwp.com/docs/ai/hooks/php.md SleekAI fires a few actions and filters for your own code. The [hooks reference](/docs/ai/reference/hooks.md) lists each with its arguments and return value; this page says which to use for what. Register them from a plugin; a theme can use every hook here except `sleekAi/init`, which fires before themes load. SleekAI has no filter that changes a chatbot's instruction, model or widget settings before it renders. To build a chatbot from data that differs per page, render it from PHP with [`sleekAi_render_chatbot()`](/docs/ai/chatbots/api.md#render-a-chatbot-from-php). #### By purpose | To | Use | Explained in | | ------------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | Run code once SleekAI has booted | `sleekAi/init` | [Developer API](/docs/ai/api.md) | | Force polling or streaming | `sleekAi/polling` | [Streaming](/docs/ai/streaming.md) | | Set how long chats are kept | `sleekAi/retention/days` | [Chat](/docs/ai/chat.md#keeping-chats-for-a-limited-time) | | Add chatbot display conditions | `sleekAi/chatbot/conditions` | [Conditions](/docs/ai/chatbots/conditions.md#custom-conditions) | | Add chatbot data sources | `sleekAi/chatbot/sources` | [Data](/docs/ai/chatbots/data.md#custom-sources) | | Add styles to chatbots | `sleekAi/chatbot/markup`, `sleekAi/chatbot/key={key}/markup`, `sleekAi/chatbot/id={id}/markup` | [Styling](/docs/ai/chatbots/styling.md) | | Change the size limit of visitors' requests | `sleekAi/chatbot/maxRequestBytes` | [Model](/docs/ai/chatbots/model.md#limits-on-visitor-requests) | #### Scheduled actions SleekAI runs some work in the background. You can add your own callbacks to these actions, for example to log when they run; SleekAI's own callbacks use the default priority, 10. | Action | When it runs | | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `sleekAi/altText/generate` | Action Scheduler, group `sleek-ai`, once for every image uploaded while automatic alt text is on. Receives the attachment ID. | | `sleekAi/retention/prune` | Action Scheduler, group `sleek-ai`, daily while chats have a retention period. | | `sleek_ai_chatbot_file_sync` | Action Scheduler, group `sleek-ai-chatbot-sync`, for each chatbot query variable with file synchronization on, at its interval. Receives the chatbot ID and the variable's index. | | `sleek_ai_chatbot_vector_store_upgrade` | Action Scheduler, group `sleek-ai-chatbot-sync`, five minutes after an update, until every chatbot with synchronized files has its OpenAI file store; it stops trying after twelve failed runs. | | `sleek_ai_cleanup_completions` | WordPress cron, hourly. Deletes polling files older than ten minutes. | ```php add_action('sleekAi/altText/generate', function ($attachmentId) { error_log('SleekAI described attachment ' . $attachmentId); }, 20); ``` Priority `20` runs the callback after SleekAI has written the text. #### Hooks of the workspace The workspace assistant, the global settings panel and the shared AI service belong to the workspace, and so do their hooks, such as the one that replaces the assistant's completions provider. They are documented with the workspace, not here. ### CLI Section: Reference URL: https://sleekwp.com/docs/ai/cli/ Markdown: https://sleekwp.com/docs/ai/cli.md SleekAI is scriptable under `wp sleek ai`. The terminal does what the screens cannot do headlessly: provisioning API keys, describing every image of a media library, forcing a chatbot's file synchronization or setting options the screens do not show. The [CLI reference](/docs/ai/reference/cli.md) lists every command with its options and examples, and `wp help sleek ai` prints the same. #### The command groups | Commands | For | | ------------------------------- | ---------------------------------------------------------------------------------------------------------- | | `wp sleek ai key` | Storing, listing and deleting provider API keys; see [API Keys](/docs/ai/settings/api-keys.md). | | `wp sleek ai models list` | The model identifiers available with the stored keys. | | `wp sleek ai generate` | One reply from a model, to try a key and a model. | | `wp sleek ai alt-text generate` | Alt text for chosen images or every image without one; see [Alt text](/docs/ai/alt-text.md). | | `wp sleek ai chatbot` | Chatbots from JSON, their logs, and their file synchronization; see [Chatbots](/docs/ai/chatbots/general.md). | | `wp sleek ai settings` | Reading and writing SleekAI's settings by dot path. | | `wp sleek ai agent caps` | The Agent capabilities of each role; see [Agent settings](/docs/ai/agent/settings.md). | | `wp sleek ai cleanup` | The maintenance jobs, on demand. | | `wp sleek ai pt-sync` | [Agent Sync](/docs/ai/agent-sync.md) of chatbots and Agent records to theme files. | Commands that list things take `--format=json` for scripts. #### Settings by dot path `wp sleek ai settings get` and `wp sleek ai settings update` read and write the `sleek-ai_settings` option by dot path. `true`, `false` and numbers are stored as such; anything else as text. ```bash wp sleek ai settings get altText wp sleek ai settings update altText.autoGenerate true wp sleek ai settings update retention.days 30 ``` `retention.days` has no screen: it sets how many days chats, Agent conversations and chatbot logs are kept, and `0`, the default, keeps them all. See [Chat](/docs/ai/chat.md#keeping-chats-for-a-limited-time). #### Maintenance - `wp sleek ai cleanup completions` deletes stale polling files, as the hourly cron event does. - `wp sleek ai cleanup retention` deletes chats older than the retention period now, as the daily action does. #### In the workspace assistant The workspace assistant can run most of these commands for you while SleekAI is installed: listing and reading, generating alt text, synchronizing chatbots, changing settings and Agent capabilities. Before a command that deletes something, such as `wp sleek ai chatbot delete`, it asks you to confirm. It cannot store API keys, run `wp sleek ai generate`, create or update chatbots from files, or run `wp sleek ai pt-sync`. ### Agent Sync Section: Automation URL: https://sleekwp.com/docs/ai/agent-sync/ Markdown: https://sleekwp.com/docs/ai/agent-sync.md Agent Sync mirrors the records of some SleekWP products into JSON files in the active theme. The files stay in step with their WordPress records, so they can be reviewed, versioned, deployed or edited by a coding agent. It works the same in the suite and in a standalone plugin. #### Which products support it | Product | Directory | Records | | ---------- | -------------- | -------------------------------------- | | SleekAI | `sleek/ai/` | `chatbots/`, `agents/`, `agent-modes/` | | SleekPixel | `sleek/pixel/` | `images/` | | SleekRank | `sleek/rank/` | `page-groups/` | | SleekView | `sleek/view/` | `views/`, `pages/` (Admin Pages) | The other products do not sync records to files. #### Turning it on Agent Sync is opt-in for each product. Create the product's directory inside a `sleek` directory of the active theme, for example for SleekAI: ```text wp-content/themes/your-theme/sleek/ai/ ``` A `sleek` directory on its own enables nothing: a product syncs only while its own directory exists. With a child theme, the directory belongs in the child theme. Removing the directory stops the sync and leaves the records in place. On the next WordPress request, which can be any page, admin screen, REST call or WP-CLI command, the product writes its existing records into the directory: ```text sleek/ ├── ai/ │ ├── chatbots/ │ │ ├── AGENTS.md │ │ └── support-bot.json │ ├── agents/ │ └── agent-modes/ ├── pixel/ │ └── images/ ├── rank/ │ └── page-groups/ └── view/ ├── pages/ └── views/ ``` Each record is a file named after its slug, such as `support-bot.json`. A record without a slug is named after its title, or `item-.json` without either. #### AGENTS.md Every record directory also gets an `AGENTS.md`, which tells a coding agent what the records are and how to edit them, followed by the JSON schema of the record's `data`. The product writes it from its own instructions and schema and rewrites it when they change with an update, so do not edit it by hand. #### JSON format Every file holds sync metadata, WordPress post fields and the product's data: ```json { "sync": { "key": "7f7cc7d8-2f7e-4f6c-bd66-5f80a7c9fef4", "updatedAt": "2026-07-19T08:15:00.000Z", "version": 1 }, "post": { "title": "City Pages", "status": "publish" }, "data": { "basePageId": 123, "urlPattern": "services/{slug}" } } ``` - `sync.key` ties the file to its record, so the record keeps its identity when the file is renamed; the record's slug then follows the file name. - `sync.updatedAt` is a UTC timestamp with milliseconds and decides which side is newer. - `post` holds the title and the status. A missing title is made from the file name, and an unknown status becomes `draft`. - `data` holds the product's configuration of that record. A file that lacks part of this shape, such as the `sync` block, is imported and then rewritten in full. #### How changes travel **From the site to the files.** Saving a record, in the workspace or anywhere else, rewrites its file at the end of that request with a new `updatedAt`. **From the files to the site.** Early in every request the product checks whether any of its files changed since it last looked, by name and modification time. A changed file is imported when its `sync.updatedAt` is **later** than the record's. When the record is newer, the record wins and the file is rewritten from it; when both are the same, nothing is imported. So a file edit takes effect only together with a new `updatedAt`: set it to the current time when you or an agent change a file, or remove `updatedAt`, which imports the file as of now. A new file with a slug the site does not have yet creates a new record. Developers can edit and deploy files while editors keep working in the admin; whichever side changed last wins. #### Deletion safeguards Agent Sync is careful with destructive changes: - A missing file does not delete its record. The record is written out again. - A file whose `data` is empty does not overwrite the record. The file is rewritten from the record. - Moving a record to the trash keeps its file, renamed to `__trashed.json` with the status `trash`. Restoring the record writes `.json` again. - Deleting a record permanently deletes its file. If the file is still in version control, deploying it again recreates the record, so delete it from the repository too. These rules keep a temporary branch, an incomplete agent edit or a missing file from silently erasing valid configuration. #### Recommended workflow 1. Create `sleek//` in the active theme for each product to sync. 2. Load the site once, or run any WP-CLI command, to write the existing records. 3. Commit the files with the theme. 4. Let a coding agent edit the files; `AGENTS.md` tells it how. 5. Review the diff and deploy it. The next request on the site imports every file whose `updatedAt` moved forward. SleekAI also has WP-CLI commands that run the import right away and write the exports its own WP-CLI process has queued; its [WP-CLI page](/docs/ai/cli.md) lists them. ### Hooks Section: Reference URL: https://sleekwp.com/docs/ai/reference/hooks/ Markdown: https://sleekwp.com/docs/ai/reference/hooks.md SleekAI fires these hooks for site code. Each is documented by the `@api` docblock on the `apply_filters` or `do_action` call that fires it; a hook without one is internal and may change without notice. #### `sleekAi/altText/generate` Action, fired in `product/includes/classes/AltText.php`. Generates the alt text of an uploaded image. Sleek AI queues it in Action Scheduler, group `sleek-ai`, when an image is uploaded while automatic generation is on, and handles it at the default priority; when it cannot be queued, the text is generated during the upload. | Parameter | Type | Description | | --- | --- | --- | | `$attachmentId` | `int` | The uploaded image's attachment ID. | #### `sleekAi/chatbot/budget` Filter, fired in `product/includes/classes/Rest/Completions.php`. How many messages all visitors together may send one chatbot in an hour and in a day. The hour starts on the hour and the day at midnight UTC; once either budget is used up, further messages are refused until its window ends. Requests from administrators are not counted. | Parameter | Type | Description | | --- | --- | --- | | `$budget` | `array` | The limits by window: `hour` 200 and `day` 1000 by default; a missing window keeps its default and 0 or less removes it. | | `$scope` | `array` | The chatbot the request is for: its `chatbotId`, or the `chatbotKey` of one rendered with sleekAi_render_chatbot(). | **Returns** array The limits by window. #### `sleekAi/chatbot/conditions` Filter, fired in `product/includes/classes/Chatbot/Chatbot.php`. Adds conditions to the chatbot display rules. The editor lists each entry by its label, and a rule compares the entry's value, computed while the page renders, with `==` or `!=`. A rule that names an entry the filter no longer returns fails its group. | Parameter | Type | Description | | --- | --- | --- | | `$conditions` | `array` | Conditions added so far, each an array with an `id`, a `label` and a `value`; an `id` that starts with `is` or `has` makes a yes-or-no condition. | **Returns** array The conditions to offer. #### `sleekAi/chatbot/id=*/markup` Filter, fired in `product/includes/classes/Chatbot/Chatbot.php`. Filters the markup of one saved chatbot, by its post ID, after `sleekAi/chatbot/markup`. | Parameter | Type | Description | | --- | --- | --- | | `$markup` | `string\|false` | The markup so far. | | `$chatbot` | `array` | The chatbot's settings. | **Returns** string\|false Markup to insert into the chatbot's frame. #### `sleekAi/chatbot/key=*/markup` Filter, fired in `product/includes/classes/Chatbot/Chatbot.php`. Filters the markup of one chatbot rendered with sleekAi_render_chatbot(), after `sleekAi/chatbot/markup`. The key is `sleek-ai_chatbot_data_` followed by the `key` passed to the function, or by an MD5 hash of its data without one. | Parameter | Type | Description | | --- | --- | --- | | `$markup` | `string\|false` | The markup so far. | | `$chatbot` | `array` | The chatbot's settings. | **Returns** string\|false Markup to insert into the chatbot's frame. #### `sleekAi/chatbot/markup` Filter, fired in `product/includes/classes/Chatbot/Chatbot.php`. Adds markup, usually `