# @e-llm-studio/instant-learning

> Reusable React components for Instant Learning.

Latest version **1.3.13** (published 2026-10-20) · MIT license · 0 weekly downloads

## Install

```sh
npm install @e-llm-studio/instant-learning
pnpm add @e-llm-studio/instant-learning
yarn add @e-llm-studio/instant-learning
bun add @e-llm-studio/instant-learning
```

## Health

**Score 55/100 (C)** — status: active.

Positive: no vulnerabilities; recently updated; high maintenance score.

Warnings: low downloads; no types; no esm support.

## Facts

| | |
|---|---|
| Version | 1.3.13 |
| Published | 2026-10-20 |
| First published | 2025-07-08 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Devesh Patel |
| Maintainers | mkathyayani, viswakoduru, omkareshwar_techolution, akashmishra-dev7, yash27verma, rishabh-sonal, saurabhgathade, priyanshu-g13, bhaskar.dekaraja, amber_techo, deveshpatel, neeraj82, sabithpocker, sanket-tehco, ram_vilash, saptyadeep, hitesh_rathi_02, vikas_as, nadeenshaik, mdfaiz-tech, soubhik-techolution, mugdhatanu, techorai, soham-jain-dev, sagniktecholution, ritikguptatecho, sumit.jaiswal, shivendra12131, mujtaba12131, yaksh-patel, abhay-techo |
| Keywords | bpa-ai, instant-learning, react |

## Links

- npm: https://www.npmjs.com/package/@e-llm-studio/instant-learning
- Repository: https://github.com/Techolution/bpa-ai
- npm.io page: https://npm.io/package/@e-llm-studio/instant-learning

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 1.3.13 (latest) — 2026-10-20
- 1.3.0-alpha.300 (alpha) — 2026-10-09
- 1.3.0-alpha.288 (test) — 2026-09-15
- 1.3.0-beta.2 (beta) — 2026-09-02
- 1.3.12 — 2026-10-16
- 1.3.11 — 2026-10-15
- 1.3.10 — 2026-10-15
- 1.3.9 — 2026-10-15
- 1.3.8 — 2026-10-12
- 1.3.7 — 2026-10-09
- 1.3.6 — 2026-10-09
- 1.3.0-alpha.299 — 2026-10-08
- 1.3.0-alpha.298 — 2026-10-08
- 1.3.5 — 2026-10-05
- 1.3.4 — 2026-09-30
- … 687 more at https://npm.io/package/@e-llm-studio/instant-learning/versions

## README

# Instant Learning Library

## Usage & Integration

The library exposes two independently consumable components:

- **`LearningManagement`** — renders the full Learning Management screen (scope tree, learnings, access, change history).
- **`TeachMePlugin`** — renders the *Teach Me* popup, an AI-assisted rule/learning creation interface. Can be mounted on its own, anywhere.

Install:

```bash
npm install @e-llm-studio/instant-learning
```

The library works without Creative Workspace. Its built-in scope tree and the
shared original `@e-llm-studio/prompt-editor` are used by default. Hosts can override
either component when host-specific behavior is required:

```tsx
import {
  CreativeWorkspaceAdapterProvider,
  LearningManagement,
} from '@e-llm-studio/instant-learning';

<CreativeWorkspaceAdapterProvider value={{ TreeSidebar, AIPromptEditor }}>
  <LearningManagement {...props} />
</CreativeWorkspaceAdapterProvider>
```

This adapter is optional. In the monorepo, `cw-core` supplies it from the
composition root so Instant Learning and Creative Workspace remain independent.

---

### 1. `LearningManagement`

Renders the Learning Management screen. It uses `@tanstack/react-query` internally, so it **must be wrapped in a `QueryClientProvider`** by the consumer.

#### Import & sample usage

```tsx
import LearningManagement from '@e-llm-studio/instant-learning';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <LearningManagement
        userDetails={userDetails}                 // logged-in user + access token
        llmStudioUrl="https://devllmstudio.creativeworkspace.ai"
        audacyBackendUrl="https://dev-audacy-traffic-manager.techo.camp"
        config={config}                           // runtime config (BASE_URL, ASSISTANT_NAME, …)
        rbacConfig={rbacConfig}                   // RBAC / AppSec identifiers
        auditLogConfig={{ configId: '6a1825e9fb722c37637b9490' }}
        ilLabels={{
          setupLabel: 'Learning Setup',
          ruleTitle: 'Learning Title',
          ruleDescriptionTitle: 'Learning Description',
        }}
        app_integration_id="019eb639-8eca-715a-95c1-efe0ee237ecc"
        backwardCompatibility={false}
        cognitiveCompareCompatibility={false}
        modeDetails={{
          activeModeName: 'Instant Learning Mode',
          modeNameFromURL: 'Instant Learning Mode',
          submodeNameFromURL: '',
        }}
      />
    </QueryClientProvider>
  );
}
```

#### Props

| Prop | Type | Required | Description |
|---|---|:---:|---|
| `userDetails` | `User` | ✅ | Logged-in user object. Must include `accessToken` (used for all API calls and as the GraphQL `userDetails` param). |
| `llmStudioUrl` | `string` | ✅ | Base URL of LLM Studio; used for tiers, IL instance, and rule APIs. |
| `audacyBackendUrl` | `string` | ✅ | Base URL of the client/product backend. |
| `config` | `object` (`any`) | ✅ | Runtime config consumed by the rule-creation flow (`BASE_URL`, `BASE_WEBSOCKET_URL`, `ASSISTANT_NAME`, `ORGANIZATION_NAME`, `CHAT_TITLE`, `SOCKET_TIMEOUT`, etc.). |
| `rbacConfig` | `RbacConfig` | ✅ | RBAC/AppSec identifiers: `applicationName`, `applicationId`, `moduleId`, `applicationModuleId`, `applicationResourceId`, `appsecRbacUrl`, `appsecBaseUrl`. Drives permission resolution. |
| `auditLogConfig` | `AuditLogConfig` | ✅ | Audit log config — `{ configId: string }`. |
| `ilLabels` | `{ setupLabel; ruleTitle; ruleDescriptionTitle }` | ✅ | Label overrides for the rule setup form (all three strings required). |
| `app_integration_id` | `string` | ⚠️ Optional* | Integration context used to load the per-integration remote JSON config (`dt()`/`dtt()` values) and scoped API calls. *Effectively required in non-backward-compat mode — without it the remote config won't load. |
| `backwardCompatibility` | `boolean` | ❌ Optional | Enables legacy mode (legacy create modal, legacy inherit API). Default `false`. |
| `cognitiveCompareCompatibility` | `boolean` | ❌ Optional | Enables cognitive-compare behavior. Default `false`. |
| `modeId` | `string` | ❌ Optional | Mode identifier passed through to the layout / rule content. |
| `modeDetails` | `{ activeModeName; modeNameFromURL; submodeNameFromURL }` | ❌ Optional | Active mode metadata used for base-mode naming. |

> **Note:** When `backwardCompatibility={false}`, the screen reads its labels/dialogs from the remote config resolved via `app_integration_id` using the `dt()` helper. Missing keys fall back to built-in defaults.

---

### 2. `TeachMePlugin`

Renders the AI-assisted *Teach Me* rule-creation popup. Unlike `LearningManagement`, it **provides its own `QueryClientProvider` internally** — no extra wrapper needed.

#### Import & sample usage

```tsx
import TeachMePlugin from '@e-llm-studio/instant-learning';

// Required config fields for TeachMePlugin
const configuration = {
  BASE_URL: 'https://devllmstudio.creativeworkspace.ai',
  BASE_WEBSOCKET_URL: 'wss://devllmstudio.creativeworkspace.ai/graphql',
  ORGANIZATION_NAME: 'techolution',
  ASSISTANT_NAME: 'preview',
};

function CreateLearningButton({ open, setOpen, token }) {
  return (
    <TeachMePlugin
      app_integration_id="019ecbcf-98c9-71bb-a663-ea962085c118"
      isOpen={open}
      onClose={() => setOpen(false)}
      token={token}                 // bearer token for API calls
      mode="ADD"                    // "ADD" | "EDIT"
      config={configuration}        // required runtime config (see table below)
      pluginPayload={{
        initialScope: 'global',     // {scope} value for titles
        ruleSet: selectedRuleSet,   // optional ruleset context
        // renderer-specific context (Radio Traffic, etc.):
        editingRule: null,
        editingTier: null,
        editingVariants: null,
        // optionally inline the config instead of remote-loading:
        // teachMe: { teachMe, template, learningManagement, agents },
        // tiers: [...],
      }}
    />
  );
}
```

#### Props

| Prop | Type | Required | Description |
|---|---|:---:|---|
| `isOpen` | `boolean` | ✅ | Controls popup visibility. |
| `onClose` | `() => void` | ✅ | Called when the dialog requests to close. |
| `token` | `string` | ✅ | Bearer token for API calls. |
| `mode` | `"ADD" \| "EDIT"` | ✅ | Whether the popup is creating a new learning or editing an existing one. |
| `config` | `object` | ✅ | Runtime config for the chat/socket. See [required `config` fields](#config-fields) below. |
| `app_integration_id` | `string` | ⚠️ Optional* | Resolves the correct renderer template and remote config. *Optional only in backward-compat mode; otherwise required to load the template/config. |
| `pluginPayload` | `Record<string, any>` | ❌ Optional | Free-form data passed straight through to the active renderer. Recognized keys: `initialScope` (`{scope}` value), `ruleSet`, `tiers` (sets tiers directly), and `teachMe` (`{ teachMe, template, learningManagement, agents }` to inline config instead of remote-loading). Any other keys are forwarded to the renderer (e.g. `editingRule`, `editingTier`, `editingVariants`, `focusedVariantIndex`, `triggerAddVariant`, `triggerFixGaps`, `copiedRule`, `initialDraftMessage`, `modeId`). |

<a id="config-fields"></a>
**Required `config` fields**

| Field | Type | Required | Description |
|---|---|:---:|---|
| `BASE_URL` | `string` | ✅ | LLM Studio base URL; used for the chat/REST calls. |
| `BASE_WEBSOCKET_URL` | `string` | ✅ | WebSocket (GraphQL) endpoint used by the live chat. |
| `ORGANIZATION_NAME` | `string` | ✅ | Organization identifier for the assistant. |
| `ASSISTANT_NAME` | `string` | ✅ | Name of the assistant that powers the Teach Me flow. |

```ts
const configuration = {
  BASE_URL: 'https://devllmstudio.creativeworkspace.ai',
  BASE_WEBSOCKET_URL: 'wss://devllmstudio.creativeworkspace.ai/graphql',
  ORGANIZATION_NAME: 'techolution',
  ASSISTANT_NAME: 'preview',
};
```

> **Template resolution:** The renderer is chosen from the `template` key (in `pluginPayload.teachMe.template` or the remote config) via `TemplateRegistry`. Unknown values fall back to `"Default"`. See the v17 changelog entry below for the registry and full config JSON.

---

## Configuration Reference

Both `LearningManagement` and `TeachMePlugin` are **fully label-driven**. The UI text — titles, buttons, dialog copy, placeholders — comes from a JSON config loaded per `appIntegrationId` (or passed inline via `pluginPayload.teachMe`). Values are resolved at runtime with the `dt()` (LMS) and `dtt()` (TeachMe) helpers; any missing key falls back to a built-in default, so you only need to override what you want to change.

### Top-level structure

```json
{
  "template": "Default",
  "agents": { "LearningTerm": "Instruction" },
  "teachMe": { "...": "TeachMe popup labels" },
  "learningManagement": { "...": "Learning Management screen labels" }
}
```

| Key | Type | Required | Description |
|---|---|:---:|---|
| `template` | `string` | ✅ | Renderer key. **Must** be present for any customisation to apply; must match a `TemplateRegistry` key (`"Default"`, `"Radio Traffic Learning"`, `"Guidelines"`, …). Unknown values fall back to `"Default"`. |
| `agents.LearningTerm` | `string` | ❌ | Word used for a "learning" across the UI (e.g. `"Instruction"`, `"Guideline"`). |
| `teachMe` | `object` | ❌ | Labels for the Teach Me popup. See [`teachMe` fields](#teachme-fields). |
| `learningManagement` | `object` | ❌ | Labels for the Learning Management screen (maps to `LMSConfig`). See [`learningManagement` fields](#learningmanagement-fields). |

Placeholders supported in values: `{scope}` / `{scope_name}` / `{parent}` (names), `{count}` / `{N}` (counts), `{variant_name}` (approve/reject dialogs), `{rule_title}` (enable/disable dialogs). They are interpolated at runtime.

<details>
<summary><strong>📋 Full config JSON (copy-paste starter)</strong> — click to expand</summary>

```json
{
  "template": "Default",
  "agents": {
    "LearningTerm": "Instruction"
  },
  "teachMe": {
    "welcomeMessage": "Hi! 👋 I'm your Instant Learning Concierge.",
    "welcomeMessageSubtitle": "I can help you create and manage instructions.\nSelect an option below or type your requirement.",
    "actions": [
      { "label": "Add new instruction",  "value": "I would want to add a new Instruction" },
      { "label": "Update an instruction", "value": "I would want to edit an existing instruction" }
    ],
    "chatTitle": "Teach Me ILOTJ - {scope} - Add Instruction",
    "chatTitleEdit": "Teach Me ILOTJ - {scope} - Edit Instruction",
    "chatTextareaPlaceholder": "Tell me about the instruction you want to create",
    "formTitle": "Add Instruction",
    "setupLabel": "Configure your IL",
    "ruleTitle": "Main Instruction Name",
    "scopeLabel": "Define Scope",
    "tierLabel": "Select Tiers",
    "ruleDescriptionTitle": "Explanation of the instruction",
    "whenToApplyTitle": "Trigger Events (When to Apply)",
    "addWhenToApplyBtnLabel": "Add WTA",
    "whenNotToApplyTitle": "Exclusion Events (When NOT to Apply)",
    "addWhenNotToApplyBtnLabel": "Add WNTA",
    "configTitle": "Advanced Settings",
    "saveBtnLabel": "Save Instruction",
    "saveBtnLoadingLabel": "Saving Instruction...",
    "showScope": false,
    "showConfiguration": false
  },
  "learningManagement": {
    "pageTitle": "Instruction Management",
    "middleDrawer": {
      "scope": "Scope",
      "addScope": "Add Scope",
      "addSubScope": "Add Subscope",
      "subScope": "Subscope",
      "treeMenu": {
        "search": "Search for scopes",
        "submenu": {
          "learnings": "Instructions",
          "access": "Access",
          "changeHistory": "Change History"
        },
        "contextMenu": {
          "addScope": "Add Scope",
          "rename": "Rename",
          "delete": "Delete {scope}",
          "addSubScope": "Add SubScope"
        }
      },
      "addScopeDialog": {
        "title": "Add Scope",
        "globalTitle": "Add Global Scope",
        "subScopeTitle": "Add Subscope",
        "subtitle": "This scope will be created under {parent} and will inherit its Learnings by default.",
        "globalSubtitle": "This global scope defines base learnings that apply across all scopes.",
        "subScopeSubtitle": "This subscope will be created under {parent} and will inherit its Learnings by default.",
        "scopeName": "Scope Name",
        "submitButton": "Create Scope",
        "cancel": "Cancel",
        "learningApprovalSettings": {
          "title": "Instruction Approval Settings",
          "approvalRequired": {
            "title": "Approval Required before Publishing",
            "subtitle": "Learnings require approval before publishing"
          },
          "publishWithoutApproval": {
            "title": "Publish Without Approval",
            "subtitle": "Instructions can be published directly"
          }
        }
      },
      "scopeDisplayLimit": {
        "enabled": "true",
        "count": "3",
        "compactView": "true",
        "applyToLevels": "",
        "viewMoreText": "show {count} more...",
        "title": "Stations",
        "description": "Manage the stations assigned to the {scope} scope.",
        "searchPlaceholder": "Search station...",
        "onboardBtn": "Onboard a station",
        "viewText": "View"
      }
    },
    "learnings": {
      "header": {
        "title": "{scope} Instructions",
        "exportButton": "Export",
        "addNewLearningButton": "Add New Instruction"
      },
      "tier": {
        "showTierHeader": true,
        "tierHeader": "Tier",
        "subtitle": "These are the system-wide instructions applied across all documents.",
        "tierHeaderNoOfLearnings": "Instructions",
        "deleteDialog": {
          "title": "Delete Tier {N}?",
          "description": "This will permanently delete all rules and variants under this tier, including any inherited rules. This action cannot be undone.",
          "cancel": "Cancel",
          "submit": "Yes, Delete"
        },
        "learning": {
          "inheritance": "Inheritance",
          "actions": {
            "disable": "Disable",
            "enable": "Enable",
            "approve": "Approve All",
            "reject": "Reject All",
            "delete": "Delete"
          },
          "approveDialog": {
            "title": "Approve Guideline",
            "desc": "{variant_name} will be published and become active within the selected scope after approval.",
            "footer": "Take a moment to check the configuration before moving forward.",
            "cancel": "Cancel",
            "approveLearning": "Approve Guideline"
          },
          "rejectDialog": {
            "title": "Reject Guideline",
            "desc": "{variant_name} will not be published or applied within the selected scope. You can provide feedback before rejecting.",
            "feedbackTitle": "Feedback",
            "feedbackPlaceholder": "Add feedback or reason for rejection",
            "deleteCheckboxLabel": "Also delete this guideline",
            "cancel": "Cancel",
            "rejectLearning": "Reject Guideline"
          },
          "deleteDialog": {
            "title": "Delete",
            "desc": "Are you sure you want to delete this rule? This action cannot be undone.",
            "warningText": "This will permanently delete the rule configuration.",
            "cancelText": "Cancel",
            "deleteText": "Delete"
          }
        }
      }
    },
    "emptyStateLearning": {
      "title": "No instructions have been added !",
      "desc": "Start by adding instructions that should apply across all documents.",
      "createNewLearning": "Create New Instruction",
      "createGlobalScope": "Create Global Scope",
      "noAccessTitle": "Access Restricted",
      "noAccessDesc": "You do not have access for this application.",
      "requestAccessButton": "Request Access",
      "requestSentButton": "Request Sent"
    }
  }
}
```

</details>

---

### `teachMe` fields

Drives the LHS of the Teach Me popup (greeting, quick actions, form labels). Resolved via `dtt()`.

```json
"teachMe": {
  "welcomeMessage": "Hi! 👋 I'm your Instant Learning Concierge.",
  "welcomeMessageSubtitle": "I can help you create and manage instructions.\nSelect an option below or type your requirement.",
  "actions": [
    { "label": "Add new instruction",   "value": "I would want to add a new Instruction" },
    { "label": "Update an instruction",  "value": "I would want to edit an existing instruction" }
  ],
  "chatTitle": "Teach Me ILOTJ - {scope} - Add Instruction",
  "chatTitleEdit": "Teach Me ILOTJ - {scope} - Edit Instruction",
  "chatTextareaPlaceholder": "Tell me about the instruction you want to create",
  "formTitle": "Add Instruction",
  "setupLabel": "Configure your IL",
  "ruleTitle": "Main Instruction Name",
  "scopeLabel": "Define Scope",
  "tierLabel": "Select Tiers",
  "ruleDescriptionTitle": "Explanation of the instruction",
  "whenToApplyTitle": "Trigger Events (When to Apply)",
  "addWhenToApplyBtnLabel": "Add WTA",
  "whenNotToApplyTitle": "Exclusion Events (When NOT to Apply)",
  "addWhenNotToApplyBtnLabel": "Add WNTA",
  "configTitle": "Advanced Settings",
  "saveBtnLabel": "Save Instruction",
  "saveBtnLoadingLabel": "Saving Instruction...",
  "showScope": false,
  "showConfiguration": false
}
```

| Field | Type | Description | Default |
|---|---|---|---|
| `welcomeMessage` | `string` | Primary greeting shown at the top of the chat. | `"Hi! 👋 I'm your Instant Learning Concierge."` |
| `welcomeMessageSubtitle` | `string` | Subtitle under the greeting. Supports **Markdown** and `\n` line breaks. | `"How would you like to get started?…"` |
| `actions` | `Array<{ label, value }>` | Quick-action buttons. `label` is the button text; `value` is the message sent to the agent when clicked. | 6 default actions |
| `chatTitle` | `string` | Popup title in **Add** mode. Supports `{scope}`. | `"Teach Me OTJ - {scope} - Add Learning"` |
| `chatTitleEdit` | `string` | Popup title in **Edit** mode. Supports `{scope}`. | `"Teach Me OTJ - {scope} - Edit Learning"` |
| `chatTextareaPlaceholder` | `string` | Placeholder for the freeform chat textarea. | `"Tell me more about this learning.."` |
| `formTitle` | `string` | Title of the inline rule form section. | `"Rule setup"` |
| `setupLabel` | `string` | Label for the setup/configuration area. | `"Configure your IL"` |
| `ruleTitle` | `string` | Label for the rule/learning name field. | `"Main Rule Name"` |
| `scopeLabel` | `string` | Label for the scope selector. | `"Define Scope"` |
| `tierLabel` | `string` | Label for the tier selector. | `"Select Tiers"` |
| `ruleDescriptionTitle` | `string` | Label for the description field. | `"Learning Explanation"` |
| `whenToApplyTitle` | `string` | Section title for trigger events. | `"Trigger Events (When to Apply)"` |
| `addWhenToApplyBtnLabel` | `string` | Button to add a "when to apply" entry. | `"Add WTA"` |
| `whenNotToApplyTitle` | `string` | Section title for exclusion events. | `"Exclusion Events (When NOT to Apply)"` |
| `addWhenNotToApplyBtnLabel` | `string` | Button to add a "when NOT to apply" entry. | `"Add WNTA"` |
| `configTitle` | `string` | Title for the advanced settings area. | `"Advanced Settings"` |
| `saveBtnLabel` | `string` | Save button label. | `"Save Rule"` |
| `saveBtnLoadingLabel` | `string` | Save button label while saving. | `"Saving Rule..."` |
| `showScope` | `boolean` | Whether to show the scope selection section. | `false` |
| `showConfiguration` | `boolean` | Whether to show the advanced configuration section. | `false` |

---

### `learningManagement` fields

Maps to `LMSConfig` and drives the Learning Management screen. Resolved via `dt()`. Grouped below by area.

#### Page & middle drawer

```json
"learningManagement": {
  "pageTitle": "Instruction Management",
  "middleDrawer": {
    "scope": "Scope",
    "addScope": "Add Scope",
    "addSubScope": "Add Subscope",
    "subScope": "Subscope",
    "treeMenu": {
      "search": "Search for scopes",
      "submenu": { "learnings": "Instructions", "access": "Access", "changeHistory": "Change History" },
      "contextMenu": { "addScope": "Add Scope", "rename": "Rename", "delete": "Delete {scope}", "addSubScope": "Add SubScope" }
    },
    "addScopeDialog": {
      "title": "Add Scope",
      "subtitle": "This scope will be created under {parent} and will inherit its Learnings by default.",
      "scopeName": "Scope Name",
      "submitButton": "Create Scope",
      "cancel": "Cancel",
      "learningApprovalSettings": {
        "title": "Instruction Approval Settings",
        "approvalRequired": { "title": "Approval Required before Publishing", "subtitle": "Learnings require approval before publishing" },
        "publishWithoutApproval": { "title": "Publish Without Approval", "subtitle": "Instructions can be published directly" }
      }
    },
    "scopeDisplayLimit": {
      "enabled": "true",
      "count": "3",
      "compactView": "true",
      "applyToLevels": "",
      "viewMoreText": "show {count} more...",
      "title": "Stations",
      "description": "Manage the stations assigned to the {scope} scope.",
      "searchPlaceholder": "Search station...",
      "onboardBtn": "Onboard a station",
      "viewText": "View"
    }
  }
}
```

| Field (path under `middleDrawer`) | Type | Description |
|---|---|---|
| `pageTitle` *(sibling of middleDrawer)* | `string` | Title shown in the LMS header. |
| `scope` | `string` | Heading word for the current scope. |
| `addScope` / `addSubScope` / `subScope` | `string` | Labels for add-scope, add-subscope buttons and the subscope node. |
| `treeMenu.search` | `string` | Placeholder for the scope-tree search input. |
| `treeMenu.submenu.{learnings, access, changeHistory}` | `string` | Tree submenu labels. |
| `treeMenu.contextMenu.{addScope, rename, delete, addSubScope}` | `string` | Right-click context-menu actions. `delete` supports `{scope}`. |
| `addScopeDialog.title` / `globalTitle` / `subScopeTitle` | `string` | Dialog title for creating a scope / global scope / subscope. `subScopeTitle` is used when the dialog is opened with `childType="SUBSCOPE"`; falls back to `middleDrawer.addSubScope` if unset. |
| `addScopeDialog.subtitle` / `globalSubtitle` / `subScopeSubtitle` | `string` | Dialog subtitle. Supports `{parent}`. |
| `addScopeDialog.scopeName` / `subScopeName` | `string` | Label for the scope-name field / subscope-name field. `subScopeName` falls back to `middleDrawer.subScope + " Name"` if unset. |
| `addScopeDialog.submitButton` / `cancel` | `string` | Dialog action buttons. |
| `addScopeDialog.learningApprovalSettings.title` | `string` | Approval-settings section title. |
| `…approvalRequired.{title, subtitle}` | `string` | Copy for the "approval required" option. |
| `…publishWithoutApproval.{title, subtitle}` | `string` | Copy for the "publish without approval" option. |
| `scopeDisplayLimit.enabled` | `string` (`"true"`/`"false"`) | Toggles the per-level display limit. |
| `scopeDisplayLimit.count` | `string` (number) | How many items to show before collapsing. |
| `scopeDisplayLimit.compactView` | `string` (`"true"`/`"false"`) | Enables compact rendering. |
| `scopeDisplayLimit.applyToLevels` | `string` | JSON array of 1-indexed levels to limit, e.g. `"[1,2]"`. Empty = all levels. |
| `scopeDisplayLimit.viewMoreText` | `string` | "See more" toggle text. Supports `{count}`. |
| `scopeDisplayLimit.title` | `string` | Word substituted for "Stations" in headers. Supports `{scope}`. |
| `scopeDisplayLimit.description` | `string` | Description under the Stations header. Supports `{scope}`. |
| `scopeDisplayLimit.searchPlaceholder` | `string` | Station search placeholder. |
| `scopeDisplayLimit.onboardBtn` | `string` | "Onboard a station" button label. |
| `scopeDisplayLimit.viewText` | `string` | Per-station "View" button label. |

#### Learnings, tiers & dialogs

```json
"learnings": {
  "header": { "title": "{scope} Instructions", "exportButton": "Export", "addNewLearningButton": "Add New Instruction" },
  "tier": {
    "showTierHeader": true,
    "tierHeader": "Tier",
    "subtitle": "These are the system-wide instructions applied across all documents.",
    "tierHeaderNoOfLearnings": "Instructions",
    "deleteDialog": { "title": "Delete Tier {N}?", "description": "This will permanently delete all rules…", "cancel": "Cancel", "submit": "Yes, Delete" },
    "learning": {
      "inheritance": "Inheritance",
      "actions": { "disable": "Disable", "enable": "Enable", "approve": "Approve All", "reject": "Reject All", "delete": "Delete" },
      "approveDialog": { "title": "Approve Guideline", "desc": "{variant_name} will be published…", "footer": "Take a moment to check…", "cancel": "Cancel", "approveLearning": "Approve Guideline" },
      "rejectDialog": { "title": "Reject Guideline", "desc": "{variant_name} will not be published…", "feedbackTitle": "Feedback", "feedbackPlaceholder": "Add feedback…", "deleteCheckboxLabel": "Also delete this guideline", "cancel": "Cancel", "rejectLearning": "Reject Guideline" },
      "deleteDialog": { "title": "Delete", "desc": "Are you sure…", "warningText": "This will permanently delete…", "cancelText": "Cancel", "deleteText": "Delete" }
    }
  }
}
```

| Field (path under `learnings`) | Type | Description |
|---|---|---|
| `header.title` | `string` | Learnings page title. Supports `{scope}`. |
| `header.exportButton` | `string` | Export button label. |
| `header.addNewLearningButton` | `string` | "Add new learning" button label. |
| `tier.showTierHeader` | `boolean` | Whether the tier header region is shown. |
| `tier.tierHeader` | `string` | Tier header title. |
| `tier.subtitle` | `string` | Tier subtitle / description. |
| `tier.tierHeaderNoOfLearnings` | `string` | Word for the learnings count label. |
| `tier.deleteDialog.{title, description, cancel, submit}` | `string` | Bulk tier-delete dialog copy. `title` supports `{N}`. |
| `tier.learning.inheritance` | `string` | Label for the inheritance indicator. |
| `tier.learning.actions.{disable, enable, approve, reject, delete}` | `string` | Per-learning action labels. |
| `tier.learning.approveDialog.{title, desc, footer, cancel, approveLearning}` | `string` | Approve dialog copy. `desc` supports `{variant_name}`. |
| `tier.learning.rejectDialog.{title, desc, feedbackTitle, feedbackPlaceholder, deleteCheckboxLabel, cancel, rejectLearning}` | `string` | Reject dialog copy. `desc` supports `{variant_name}`. |
| `tier.learning.deleteDialog.{title, desc, warningText, cancelText, deleteText}` | `string` | Single-learning delete dialog copy. |

#### Empty state

```json
"emptyStateLearning": {
  "title": "No instructions have been added !",
  "desc": "Start by adding instructions that should apply across all documents.",
  "createNewLearning": "Create New Instruction",
  "createGlobalScope": "Create Global Scope",
  "noAccessTitle": "Access Restricted",
  "noAccessDesc": "You do not have access for this application.",
  "requestAccessButton": "Request Access",
  "requestSentButton": "Request Sent"
}
```

| Field | Type | Required | Description |
|---|---|:---:|---|
| `title` | `string` | ✅ | Empty-state heading. |
| `desc` | `string` | ✅ | Empty-state description. |
| `createNewLearning` | `string` | ✅ | CTA to create a learning. |
| `createGlobalScope` | `string` | ✅ | CTA to create a global scope. |
| `noAccessTitle` | `string` | ❌ | Heading when the user has no access. |
| `noAccessDesc` | `string` | ❌ | Description when the user has no access. |
| `requestAccessButton` | `string` | ❌ | "Request access" button label. |
| `requestSentButton` | `string` | ❌ | "Request sent" state label. |

---

## Changelog
### 1.3.0-alpha.31 - 2026, June 10th
-Hide "Copy to Tier" option
-Hide Tier Accordian in Learning Management screen
-Configuring Max hirearchy from ILKB config and its UI changes

### 1.3.0-alpha.31 - 2026, June 10th
Backward Compatibility support for Save from AI changes

### 1.3.0-alpha.21 - 2026, June 8th
**Permissions — Union-based access resolution**

- **Union model**: When a user holds multiple roles on the same resource (e.g. inherited group role + direct assignment), permissions from all roles are merged. If any role grants a permission, the user has it.
- **Removed**: `ROLE_HIERARCHY`, `getRolePrecedence()`, `resolveHighestRolePerResource()`, and the `resolvedData` store field are all gone.
- **`hasPermission()`** and **`hasApplicationAccess()`** now run against the raw `accessData` via a new internal `getUnionPermissionsForResource()` helper that builds a `Set` of all permissions across matching records.
- `fetchPermissions()` no longer calls the resolver — stores raw API response only.

### 1.3.0-alpha.20 - 2026, June 8th
**TeachMe Popup — LHS Customisation via `dtt()`**

- **Chat Title**: Configurable for both Add and Edit modes via `teachMe.chatTitle` and `teachMe.chatTitleEdit`. Both support `{scope}` placeholder which is replaced at runtime with the selected scope name.
- **Welcome Message**: Configurable greeting via `teachMe.welcomeMessage`. Subtitle via `teachMe.welcomeMessageSubtitle` with full **Markdown** support rendered via `ReactMarkdown`.
- **Action Buttons**: Configurable via `teachMe.actions` array — each entry has a `label` (button text) and `value` (message sent to agent on click).
- **Textarea Placeholder**: Configurable via `teachMe.textareaPlaceholder`.
- **Backward Compatibility**: TeachMe popup customisation is supported with `backwardCompatibility` flag.

Keys added in this version:

| JSON Key | Default |
|---|---|
| `teachMe.chatTitle` | `"Teach Me OTJ - {scope} - Add Learning"` |
| `teachMe.chatTitleEdit` | `"Teach Me OTJ - {scope} - Edit Learning"` |
| `teachMe.welcomeMessageSubtitle` | `"How would you like to get started?..."` |
| `teachMe.actions` | Array of `{ label, value }` — see sample JSON in v17 |
| `teachMe.textareaPlaceholder` | `"Tell me more about this learning.."` |

### 1.3.0-alpha.19 - 2026, June 6th
- **Cognitive Compare UI**: Updated comparison UI with visual changes
- **GraphQL Params**: `userDetails` object is now passed through as a GraphQL parameter

### 1.3.0-alpha.18 - 2026, June 6th
Patch Fix: Removal of underscore for all labels

### 1.3.0-alpha.17 - 2026, June 6th
**Without BackwardCompatibiltity Support**
- **TeachMe Renderer**: Added valuetype json support to render teachMe popup and create rule from the same.

  **Configurable UI via `dtt()`** — all LHS labels in the TeachMe popup are driven by `value_type_config.teachMe` JSON loaded per `appIntegrationId` and resolved at runtime through the `dtt()` helper.

  **Supported keys:**

  | JSON Key | Default |
  |---|---|
  | `teachMe.welcomeMessage` | `"Hi! 👋 I'm your Instant Learning Concierge."` |
  | `teachMe.formTitle` | `"Rule setup"` |
  | `teachMe.setupLabel` | `"Configure your IL"` |
  | `teachMe.ruleTitle` | `"Main Rule Name"` |
  | `teachMe.scopeLabel` | `"Define Scope"` |
  | `teachMe.tierLabel` | `"Select Tiers"` |
  | `teachMe.ruleDescriptionTitle` | `"Learning Explanation"` |
  | `teachMe.whenToApplyTitle` | `"Trigger Events (When to Apply)"` |
  | `teachMe.addWhenToApplyBtnLabel` | `"Add WTA"` |
  | `teachMe.whenNotToApplyTitle` | `"Exclusion Events (When NOT to Apply)"` |
  | `teachMe.addWhenNotToApplyBtnLabel` | `"Add WNTA"` |
  | `teachMe.configTitle` | `"Advanced Settings"` |
  | `teachMe.saveBtnLabel` | `"Save Rule"` |
  | `teachMe.saveBtnLoadingLabel` | `"Saving Rule..."` |
  | `teachMe.showConfiguration` | `false` |
  | `teachMe.showScope` | `false` |

  **Full sample `value_type_config` JSON:**

```json
  {
    "template": "Default",
    "teachMe": {
      "welcomeMessage": "Hi! 👋 I'm your Instant Learning Concierge.",
      "welcomeMessageSubtitle": "How would you like to get started?\nYou can select an option below or **describe the rule** you'd like to create.",
      "actions": [
        { "label": "Separation rule",          "value": "I would want to add a separation rule" },
        { "label": "Max priority rule",        "value": "I would want to set a max priority rule" },
        { "label": "Break code matching",      "value": "I would want to add a break code matching rule" },
        { "label": "Inventory code matching",  "value": "I would want to add a inventory window matching rule" },
        { "label": "Enter a rule description", "value": "I want to add a rule description" },
        { "label": "Tester Genie",             "value": "Loading prompt..." }
      ],
      "chatTitle": "Teach Me OTJ - {scope} - Add Learning",
      "chatTitleEdit": "Teach Me OTJ - {scope} - Edit Learning",
      "formTitle": "Rule Setup",
      "setupLabel": "Configure your IL",
      "ruleTitle": "Main Rule Name",
      "scopeLabel": "Define Scope",
      "tierLabel": "Select Tiers",
      "ruleDescriptionTitle": "Learning Explanation",
      "whenToApplyTitle": "Trigger Events (When to Apply)",
      "addWhenToApplyBtnLabel": "Add WTA",
      "whenNotToApplyTitle": "Exclusion Events (When NOT to Apply)",
      "addWhenNotToApplyBtnLabel": "Add WNTA",
      "configTitle": "Advanced Settings",
      "saveBtnLabel": "Save Rule",
      "saveBtnLoadingLabel": "Saving Rule...",
      "textareaPlaceholder": "Tell me more about this learning..",
      "showConfiguration": false,
      "showScope": false
    },
    "learningManagement": {}
  }
```

  > ⚠️ **Important**: The `template` key at the root of `value_type_config` **must** be provided for any JSON customisation to take effect. Without it, the system falls back to resolving the renderer via `value_type_name` from the API, and config values may not be applied.
  >
  > ```json
  > {
  >   "template": "Default"
  > }
  > ```
  >
  > The value must exactly match a key registered in `TemplateRegistry`:
  >
  > | `template` value | Renderer |
  > |---|---|
  > | `"Default"` | `DefaultTeachMeRenderer` |
  > | `"Radio Traffic Learning"` | `RadioTrafficLearningRenderer` |
  > | `"Guidelines"` | `GuidelinesTeachMeRenderer` |
  >
  > For custom plugins, use the exact key you registered in `TemplateRegistry` in `TeachMePlugin.tsx`:
  >
  > ```ts
  > export const TemplateRegistry: Record<string, React.FC<TeachMeWrapperProps>> = {
  >   "Default": DefaultTeachMeRenderer,
  >   "Radio Traffic Learning": RadioTrafficLearningRenderer,
  >   "Guidelines": GuidelinesTeachMeRenderer,
  >   "Your Template Name": YourCustomRenderer, // ← use this exact string in "template"
  > };
  > ```
  >
  > If the provided `template` value is not found in `TemplateRegistry`, the system automatically falls back to `"Default"`.

- **Learning Management Renderer**: Added valuetype json support to render Learning Management Screen and create rule from the same.

  **Configurable UI via `dt()`**

  The LMS UI is driven by a remote JSON config loaded per `appIntegrationId`. Every label, button text, and dialog copy is resolved at runtime through the `dt()` helper instead of being hardcoded.

  `dt()` — read a config value anywhere

```ts
  function dt(
    path: string,                             // dot-notation key into LMSConfig
    fallback?: string,                        // returned when key is missing
    params?: Record<string, string | number>  // fills {placeholder} tokens in the value
  ): string
```

  - Reads directly from the Zustand store (no hook — works outside React components).
  - Returns `fallback ?? path` when the key is not found or config is not loaded.

  **Examples:**

```ts
  dt('pageTitle')
  // → value of lmsConfig.pageTitle

  dt('middleDrawer.addScope', 'Add Scope')
  // → config value or fallback 'Add Scope'

  dt('learnings.tier.deleteDialog.title', 'Delete {N} learnings', { N: 3 })
  // → "Delete 3 learnings"  (placeholder replaced)

  dt('learnings.tier.learning.approveDialog.desc', undefined, { variant_name: 'Rule A' })
  // → config string with {variant_name} replaced by "Rule A"
```

### 1.3.0-alpha.16 - 2026, June 5th
- **Scope Management**: Added appIntegrationId support to scope creation and deletion flows in AddScopeModal and related API endpoints
- **Override History**: Included appIntegrationId when fetching override history to ensure correct integration context
- **Rule Retrieval**: Added appIntegrationId support when fetching rules by ruleId
- **Scope Deletion**: Fixed deletion logic for station scopes so that associated stations are correctly removed when type = station

### 1.3.0-alpha.15 - 2026, June 5th
- **Teach Me Renderer**: Modified default Teach Me renderer — switched from generic renderer to Radio Traffic value type renderer to support rule creation flow

### 1.3.0-alpha.14 - 2026, June 5th
- **IL Mode - Scope Creation**: `parentScopeId` now correctly receives the parent scope's ID (global ID) when creating a new scope from a child node, instead of always being `null`
- **Auth Fallback**: Added optional chaining (`?.`) on `userDetails.accessToken` to prevent crashes on reload
- **Access Section**: Fixed logic that was hiding the Access section — it is now always visible regardless of `backwardCompatibility` flag

---

## Alpha Release Commands

# Create the first alpha version (e.g. 0.1.0-alpha.0)
npm version prerelease --preid=alpha

# Increment the alpha version (e.g. 0.1.0-alpha.1)
npm version prerelease --preid=alpha

# Publish the package under the alpha tag
npm publish --tag alpha

# Install a specific alpha version
npm install @e-llm-studio/instant-learning@0.1.0-alpha.1

---
_Source: https://npm.io/package/@e-llm-studio/instant-learning · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
