Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified docs/_static/screenshots/scope_create.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 12 additions & 6 deletions docs/concepts/framework_concepts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ The plugin uses three main configuration concepts:

.. code-block:: yaml

AI_EXTENSIONS:
provider:
API_KEY: "sk-proj-your-api-key"
MODEL: "provider/your-model"
AI_EXTENSIONS:
provider:
API_KEY: "sk-proj-your-api-key"
MODEL: "provider/your-model"

**Profile**
Defines the **what** - what the AI will be instructed to do and which information it will have access to.
Expand All @@ -29,9 +29,15 @@ The plugin uses three main configuration concepts:
:alt: Profile configuration view showing base template and effective configuration

**Scope**
Defines the **where** - the context in which an AI workflow will be visible and usable (LMS/CMS, specific course, location).
Defines the **where** - the context in which an AI workflow will be visible and usable (LMS/CMS, specific course, location, and frontend widget).

Example usage in Django Admin, where a *scope* is defined for a location (blank for all locations, or a :ref:`specific unit <target-specific-units>`) and resource (blank for all courses, or a :ref:`specific course key <target-specific-courses>`).
A scope has three matching dimensions:

- **UI Slot Selector ID**: The ``id`` of the frontend widget that should render the workflow (see :ref:`ui-slot-selector-id`).
- **Course ID**: Optionally limits the scope to a specific course.
- **Location regex**: Optionally limits the scope to specific units within a course.

Example usage in Django Admin, where a *scope* is defined with a widget ID, and optionally for a :ref:`specific course <target-specific-courses>` or :ref:`specific unit <target-specific-units>`.

.. image:: /_static/screenshots/scope_create.png
:alt: Create new scope interface
Expand Down
4 changes: 2 additions & 2 deletions docs/quickstarts/extension_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ In your ``frontend/src/index.tsx`` (or your plugin's entry point):

.. code-block:: tsx

import { registerComponents } from '@openedx/openedx-ai-extensions-ui';
import { registerComponents, REGISTRY_NAMES } from '@openedx/openedx-ai-extensions-ui';
import MyRequestComponent from './components/MyRequestComponent';
import MyIndependentTabComponent from './components/MyIndependentTabComponent';

Expand All @@ -253,7 +253,7 @@ In your ``frontend/src/index.tsx`` (or your plugin's entry point):
});

// Register a specialized entry (for example, a new tab in AI Settings).
registerComponents('settings', {
registerComponents(REGISTRY_NAMES.SETTINGS, {
id: 'my-plugin-id',
label: 'My AI Plugin',
component: MyIndependentTabComponent,
Expand Down
80 changes: 79 additions & 1 deletion docs/quickstarts/usage_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ Creating the Scope
- **Course ID**: Leave empty (applies to all courses), or :ref:`target specific courses <target-specific-courses>`
- **Location regex**: Leave empty (applies to all units), or :ref:`target specific units <target-specific-units>`
- **Profile**: Select the profile you just created using the name you chose in the **Slug** field
- **UI slot selector ID**: Enter the ``id`` of the frontend widget that should render this workflow.
See :ref:`ui-slot-selector-id` for details.
- **Enabled**: Leave checked to activate the scope immediately

3. Click :guilabel:`Save`

Expand Down Expand Up @@ -134,8 +137,11 @@ Creating the Scope

- **Service variant**: Select ``CMS - Studio``
- **Course ID**: Leave empty (applies to all courses in Studio), or :ref:`target specific courses <target-specific-courses>`
- **Location regex**: Leave empty - there is no targeting locations in the Studio context
- **Location regex**: Leave empty — location targeting is not used in the Studio context
- **Profile**: Select the profile you just created
- **UI slot selector ID**: Enter the ``id`` of the frontend widget that should render this workflow.
See :ref:`ui-slot-selector-id` for details.
- **Enabled**: Leave checked to activate the scope immediately

3. Click :guilabel:`Save`

Expand All @@ -150,6 +156,75 @@ Navigate to a course in Studio. You should see the AI assistant interface availa
Advanced Configuration
**********************

.. _ui-slot-selector-id:

Using the UI Slot Selector ID
==============================

The **UI Slot Selector ID** field controls which frontend widget renders a given scope.
It does **not** refer to the Open edX UI slot (e.g. ``openedx.learning.unit.header.slot.v1``).
It refers to the ``id`` property of the widget that is inserted into that slot via the
plugin operations system:

.. code-block:: javascript

op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'ai-assist-button', // ← this is the UI Slot Selector ID
priority: 10,
type: DIRECT_PLUGIN,
RenderWidget: ConfigurableAIAssistance,
}

Every widget sends its own ``id`` with each backend request. The backend only returns a
scope whose **UI Slot Selector ID** exactly matches that value. This guarantees that each
widget on the page receives its own independently configured workflow.

Common widget IDs
-----------------

The most commonly used widget IDs are:

.. code-block:: text

ai-assist-button ← LMS unit-level AI assistant
ai-assist-button-course-outline-sidebar ← Studio course outline sidebar

A less common one is ``ai-extensions-settings-card``. Additional IDs may be in use
Comment thread
felipemontoya marked this conversation as resolved.
Outdated
depending on your installation. The Django admin field auto-suggests all values it finds
in existing scope records, so the available options grow as you configure more scopes.

Wildcards (empty value)
-----------------------

If you leave **UI Slot Selector ID** empty, the scope will match *any* widget that does
not find a more specific scope for its widget ID. This is a convenient shortcut for
simple deployments, but it means any new widget you add later may unexpectedly receive
the same workflow.

For production deployments, always set an explicit **UI Slot Selector ID** so scope
resolution is predictable.

Scope resolution and specificity
---------------------------------

When multiple scopes could match a request, the backend selects the most *specific* one
using a weighted score:

+--------------------+--------+
| Field | Weight |
+====================+========+
| Location regex | +4 |
+--------------------+--------+
| Course ID | +2 |
+--------------------+--------+
| UI Slot Selector | +1 |
+--------------------+--------+

A scope with all three fields set outranks one that only sets two, and so on. The
**Specificity index** column in the Django admin list view shows the computed score for
each scope (read-only; updated automatically on save).

.. _target-specific-courses:

Targeting Specific Courses
Expand Down Expand Up @@ -213,6 +288,9 @@ To target multiple specific units, use the OR operator (``|``):

This matches any unit with one of the three specified block IDs.

.. note::
**Course ID is required** when using Location regex. Saving a scope with Location regex set but Course ID empty will fail with a validation error.

.. warning::
Location regex is a powerful but technical feature. Test your regex patterns carefully to ensure they match the intended units.

Expand Down
Loading