Skip to main content

Client SDK

The JavaScript SDK is available as soon as you integrate your application with either the Web SDK or via Canvas Theme. It enables client-side automation with your Digital Twin—such as sending messages, listing favorites, and running assistant instructions.
To use the JavaScript SDK, your Digital Twin must be integrated into a web application using the Web SDK or injected into Canvas via Theme.

Integration Options

Integrate your Digital Twin in one of these ways to access the SDK:
  • Web SDK: Embed the Digital Twin directly in your web app by installing the Web SDK for easy setup, user management, and customization.
  • Canvas Theme: Inject the Digital Twin into Canvas using the Theme for direct access to SDK features within the Canvas LMS.
Both methods offer secure, flexible options to maximize your Digital Twin’s functionality. Select the approach that best fits your environment.

Global Window Object

When your Digital Twin is integrated, the pria object is injected directly onto the global window (DOM), making it the central access point for all Pria SDK API calls from anywhere in your application. This allows you to easily interact with Pria’s messaging, UI control, and event management methods without additional imports or setup—simply reference window.pria.
const pria = {
    load: priasdk,                // Initialize the Pria SDK and establish middleware connection
    send: priaSend,               // Send API requests/messages to Pria
    subscribe: priaSubscribe,     // Listen for Pria responses or callback events
    unsubscribe: priaUnsubscribe, // Remove listeners or callbacks from Pria
    setVisible: priaSetVisible,   // Show or hide Pria’s UI components in your app
	display: priaDisplay,         // Trigger a buton click to open or close the UI
	priaObj: priaObj,             // Backing property bag that contains current cached user identity
    isReady: priaIsReady,         // True when Pria is ready to recieve messages
    version: 1                    // Indicates the current SDK version
}
By being attached to the DOM, pria acts as your always-available gateway for secure and seamless integration with all Pria interfaces and backend services—enabling features like messaging, automation, and UI control from any context in your client-side code.

Messaging Technology

Communication between your web application and the Praxis AI Middleware via the Web SDK is powered by browser messaging, which securely enables cross-origin interactions between window objects, such as between a main application and an embedded iframe or pop-up. Requests are sent to the backend middleware server using the pria.send() API method, ensuring safe and reliable message delivery for seamless integration and robust application workflows.

Sending a Request

Request Message

To make a request, simply compose a Javascript object containing the command and arguments like below:
const request = {
    command: '<command>',
    ...arguments
}

Available Commands

CommandDescriptionParameters
post.messageSend text message to Priainputs: [Array of strings]
convo.startStart speech-to-speech conversationNone
convo.stopStop speech-to-speech conversationNone
assistants.listGet available assistantsNone
favorites.listGet list of user’s favoritesNone
conversations.listGet list of user’s conversationsNone

Sample Requests

  • Post Message
  • Conversation Mode
  • List
Send a text message to your digital twin:
const request = {
    command: 'post.message',
    inputs: ['How are you?', 'Today is my birthday!']
}

pria.send(request)

Error Handling

The pria.send() function may throw these errors:
  • “Connect Pria first, then retry” - Pria is not properly initialized
  • “Function requires valid JSON” - Invalid request format
  • “Unauthorized” - Request unauthorized for user

Receiving Responses

Subscribe to Responses

To receive responses from Pria, you must first subscribe:
const handlePriaResponse = (response) => {
    console.log('Received from Pria:', response)
    // Process the response here
}

pria.subscribe(handlePriaResponse)

Response Message

A response message from the Pria AI Middleware follows a clear and structured format to ensure consistent integration and robust client parsing. Each response includes standard fields that define its source, content, format, and compatibility.
{
    "type": "pria-response",
    "response": {
        "command": "post.message",
        "content": {} | "",
        "isError": false,
        "type": "object"
    },
    "version": 1
}
Response Fields
FieldTypeDescription
typeStringAlways "pria-response". This identifies the message as originating from Pria AI Middleware.
responseObjectContains the actual payload and control attributes for the message.
response.contentMixedThe content of the response—can be a String (error, status) or an Object (structured output).
response.typeStringIndicates the type of content. "object" for JavaScript objects, "string" otherwise.
response.isErrorBooleantrue if the message represents an error, false otherwise.
response.commandStringIndicates the command handled (e.g., post.message, convo.stop).
versionIntegerThe message version number for client compatibility management.
type The literal string constant "pria-response". Use as a filter or discriminator in your message handling logic. response Top-level object that wraps all core response details from Pria AI Middleware.
SubfieldDescription
contentThe main body of the response. Can be a JavaScript object (structured data) or a string (simple message or error).
typeSpecifies the JavaScript type of content. Values are "object" (for JSON objects) or "string" (for plain text).
isErrorBoolean signaling error (true for errors, false for normal responses).
commandString describing the executed command (e.g., post.message, convo.start, or convo.stop).
version Integer value indicating the version of the response structure. Used for ensuring compatibility with various client parsers.
Always check the version field to ensure your parser correctly supports all required fields and response shapes.

Sample Responses

  • Successful Message
  • Error Response
  • Conversation Control
{
    "type": "pria-response",
    "response": {
        "command": "post.message",
        "content": {
            "success": true,
            "outputs": ["I am doing great! Happy birthday by the way.."],
            "usage": 12048,
            "query_duration_ms": 9404,
            "model": "us.anthropic.claude-3-5-sonnet-20240620-v1:0"
        },
        "isError": false,
        "type": "object"
    },
    "version": 1
}
See Object Definitions for a comple list of responses

Toggle visibility

Control the client UI visibility with
pria.setVisible(true|false)

Working with the SDK

Authentication & Security

The SDK uses the identity of the user currently connected to the digital twin. Ensure proper authentication is in place before making requests.

Requirements

  • Pria must be properly configured and fully connected
  • User must be authenticated with appropriate permissions
  • Valid session must be established

Content Format

Pria outputs content in Markdown format. Parse responses accordingly in your application.

Error Handling

It is best practices to wrap function calls in a try/catch block to avoid unhandled exceptions
const sendMessage = async (message) => {
    try {
        const request = {
            command: 'post.message',
            inputs: [message]
        }
        
        pria.send(request)
    } catch (error) {
        console.error('Failed to send message:', error)
        // Handle error appropriately
    }
}

Response Processing

It is best practive to handle responses from Pria by looking at response message type, isError, command, etc to handle responses for all situations
const handleResponse = (responseMessage) => {
    
    if (responseMessage?.type !=="pria-response") return 

    const response = responseMessage?.response 
    if (!response) return;

    if (response.isError) {
        console.error('Pria error:', response.content)
        return
    }

    // handle content as String 
    if (response.type==='string') {
        
        console.log("Response:", response.response.content)

    }
    // handle response as object 
    else {
        

        // handling  response from messape.post
        if (response.command == "post.message"){
        
            const outputs = response.content?.outputs
            if (outputs){
                outputs.forEach(output => {
                    // Display or process each output
                    console.log(output)
                })
            }
        }
    }
}

Cleanup

Consider removing the event handlers you have declared when subscribing to receive response messages before your application terminates
// Unsubscribe when component unmounts or page unloads
window.addEventListener('beforeunload', () => {
    pria.unsubscribe(handleResponse)
})

Troubleshooting

Common Issues

IssueSolution
”Connect Pria first” errorEnsure SDK is loaded and initialized
No responses receivedCheck if you’ve subscribed to responses
Unauthorized errorsVerify user authentication and permissions
Invalid JSON errorsValidate request format and structure

Debug Mode

Enable debug logging to troubleshoot integration issues:
// Add to your configuration
var displayOptions = {
    // ... other options
    debug: true  // Enable debug logging
}

SDK Playground Example

You can take a look at a running example at SDK Playground Example.
https://pria.praxislxp.com/pria-sdk-web-sample.html
SDK Playground Example This example demonstrates how to cleanly initialize the integration, detects when sucessfully connected, execute specific commands; such as starting conversation, listing favorites, conversations or assistants, posting a new message, and more.

API Class Example

This example is provided AS IS to demonstrate how you can cleanly integrate a Digital Twin in your Web Application and sendvarious commands programatically in response to user actions on the page. It is extracted from the playground example code.
/**
* Pria SDK Test Harness Application
* Enhanced version with modern JavaScript patterns and professional UI
*/
class PriaTestHarness {
    constructor() {
        this.pria = null;
        this.waitForPriaTimer = null;
        this.uiDisplayed = false;
        this.isConnected = false;
        
        // Configuration
        this.config = {
            displayOptions: {
                buttonPositionRight: 'calc(50% - 40px)',
                buttonPositionBottom: '80px'
            },
            instanceConfig: {
                publicIdguest: '41407647-248c-4f0e-a317-71fc151ba8fb', 
                publicId: 'f831501f-b645-481a-9cbb-331509aaf8c1',
                pictureUrl: 'https://ca.slack-edge.com/T08Q47N2NUT-U08PZ8CUVDK-d32d2c5679ad-512'
            },
            userConfig: {
                email: 'alex@praxis-ai.com',
                profilename: 'Alex Lebegue',
                usertype: 1,
                userid: 110,
                roleid: 123,               
                rolename: "Course ABC",
                partnerid: 1,              
                partnername: "ABC Global Inc." 
            },
            conversation: {
                id: 777,
                name: "My Conversation"
            }
        };
        
        this.init();
    }
    
    /**
    * Initialize the application
    */
    async init() {
        try {
            await this.loadPriaSDK();
            this.bindEventListeners();
            this.showToast('Application initialized successfully', 'success');
        } catch (error) {
            console.error('Failed to initialize application:', error);
            this.showToast('Failed to initialize application', 'error');
        }
    }
    
    /**
    * Load the Pria SDK
    */
    loadPriaSDK() {
        return new Promise((resolve, reject) => {
            const script = document.createElement('script');
            script.src = 'pria-sdk-web.js';
            script.async = true;
            
            script.onload = () => {
                console.log('Web SDK Script loaded');

                const url = 'https://pria.praxislxp.com';
                
                PriaIntegration.loadSdk(
                    url, 
                    this.config.displayOptions, 
                    this.config.instanceConfig, 
                    this.config.userConfig
                );
                
                this.waitForPriaTimer = setInterval(() => this.waitForPria(), 2000);
                resolve();
            };
            
            script.onerror = (error) => {
                console.error('Failed to load Web SDK:', error);
                reject(new Error('Web SDK loading failed'));
            };
            
            document.body.appendChild(script);
        });
    }
    
    /**
    * Wait for Pria to be available and set up subscriptions
    */
    waitForPria() {
        if (!window.pria) {
            console.log("Waiting for Pria to load...");
            return;
        }
        
        // console.log('Pria loaded:', JSON.stringify(window.pria.priaObj, null, 2));
        
        clearInterval(this.waitForPriaTimer);
        this.pria = window.pria;
        this.isConnected = true;
        
        this.updateConnectionStatus(true);
        this.pria.subscribe(this.handlePriaResponse.bind(this));
        this.showToast('Connected to Pria SDK', 'success');

        window.addEventListener('beforeunload', () => {
            this.pria.unsubscribe(handleResponse)
        })
    }
    
    /**
    * Handle responses from Pria
    */
    handlePriaResponse(response) {
        console.log("Response from Pria:", JSON.stringify(response, null, 2));
        this.displayResponse(response);
        this.hideLoading();
    }
    
    /**
    * Bind event listeners to UI elements
    */
    bindEventListeners() {
        // Message sending
        document.getElementById('send-message-btn').addEventListener('click', () => {
            this.sendMessage();
        });
        
        // Quick actions
        document.getElementById('start-conversation-btn').addEventListener('click', () => {
            this.startConversation();
        });
        
        document.getElementById('stop-conversation-btn').addEventListener('click', () => {
            this.stopConversation();
        });
        
        document.getElementById('get-assistants-btn').addEventListener('click', () => {
            this.getAssistants();
        });
        
        document.getElementById('get-conversations-btn').addEventListener('click', () => {
            this.getConversations();
        });
        
        document.getElementById('get-favorites-btn').addEventListener('click', () => {
            this.getFavorites();
        });
        
        // Toggle Pria visibility
        document.getElementById('toggle-pria-btn').addEventListener('click', () => {
            this.togglePriaVisibility();
        });
        
        // Clear response
        document.getElementById('clear-response-btn').addEventListener('click', () => {
            this.clearResponse();
        });
        
        // Enter key support for message input
        document.getElementById('message-input').addEventListener('keydown', (e) => {
            if (e.ctrlKey && e.key === 'Enter') {
                this.sendMessage();
            }
        });
    }
    
    /**
    * Send a message to Pria
    */
    sendMessage() {
        if (!this.ensurePriaConnection()) return;
        
        const message = document.getElementById('message-input').value.trim();
        const assistantId = document.getElementById('assistant-id-input').value.trim();
        
        if (!message) {
            this.showToast('Please enter a message', 'warning');
            return;
        }
        
        if (!assistantId) {
            this.showToast('Please enter an assistant ID', 'warning');
            return;
        }
        
        this.showLoading();
        this.clearResponse();
        
        const request = {
            command: 'message.post',
            inputs: [message],
            assistantId: assistantId,
            selectedCourse: {
                course_id: this.config.conversation.id,
                course_name: this.config.conversation.name
            }
        };
        
        this.pria.send(request);
        this.showPria();
        this.showToast('Message sent', 'info');
    }
    
    /**
    * Start a conversation
    */
    startConversation() {
        if (!this.ensurePriaConnection()) return;
        
        this.showLoading();
        this.clearResponse();
        
        const request = {
            command: 'convo.start',
            assistantId: '674e9fd3d7e18aa82eb49fda',
            selectedCourse: {
                course_id: 22345,
                course_name: 'Conversational Assist'
            }
        };
        
        this.pria.send(request);
        this.showPria();
        this.showToast('Starting conversation', 'info');
    }
    
    /**
    * Stop a conversation
    */
    stopConversation() {
        if (!this.ensurePriaConnection()) return;
        
        const request = {
            command: 'convo.stop'
        };
        
        this.pria.send(request);
        this.showToast('Conversation stopped', 'info');
    }
    
    /**
    * Get list of assistants
    */
    getAssistants() {
        if (!this.ensurePriaConnection()) return;
        
        this.showLoading();
        this.clearResponse();
        
        const request = {
            command: 'assistants.list'
        };
        
        this.pria.send(request);
        this.showToast('Fetching assistants', 'info');
    }
    
    /**
    * Get list of conversations
    */
    getConversations() {
        if (!this.ensurePriaConnection()) return;
        
        this.showLoading();
        this.clearResponse();
        
        const request = {
            command: 'conversations.list'
        };
        
        this.pria.send(request);
        this.showToast('Fetching conversations', 'info');
    }
    
    /**
    * Get list of favorites
    */
    getFavorites() {
        if (!this.ensurePriaConnection()) return;
        
        this.showLoading();
        this.clearResponse();
        
        const request = {
            command: 'favorites.list'
        };
        
        this.pria.send(request);
        this.showToast('Fetching favorites', 'info');
    }
    
    
    /**
    * Toggle Pria visibility
    */
    togglePriaVisibility() {
        if (!this.ensurePriaConnection()) return;
        
        this.uiDisplayed = !this.uiDisplayed;
        this.pria.display(this.uiDisplayed);
        
        const btn = document.getElementById('toggle-pria-btn');
        const icon = btn.querySelector('i');
        const text = btn.querySelector('span');
        
        if (this.uiDisplayed) {
            icon.className = 'fas fa-eye-slash';
            text.textContent = 'Hide Pria';
            this.showToast('Pria UI shown', 'info');
        } else {
            icon.className = 'fas fa-eye';
            text.textContent = 'Show Pria';
            this.showToast('Pria UI hidden', 'info');
        }
    }
    
    /**
    * Show Pria interface
    */
    showPria() {
        if (this.pria && !this.uiDisplayed) {
            this.pria.display(true)
            this.uiDisplayed = true;
        }
    }
    
    /**
    * Display response in the viewer
    */
    displayResponse(data) {
        const viewer = document.getElementById('response-viewer');
        viewer.value = data ? JSON.stringify(data, null, 2) : '';
    }
    
    /**
    * Clear the response viewer
    */
    clearResponse() {
        document.getElementById('response-viewer').value = '';
    }
    
    /**
    * Show loading indicator
    */
    showLoading() {
        document.getElementById('loading-indicator').classList.remove('hidden');
    }
    
    /**
    * Hide loading indicator
    */
    hideLoading() {
        document.getElementById('loading-indicator').classList.add('hidden');
    }
    
    /**
    * Update connection status indicator
    */
    updateConnectionStatus(connected) {
        const statusElement = document.getElementById('connection-status');
        const dot = statusElement.querySelector('div');
        const text = statusElement.querySelector('span');
        
        if (connected) {
            dot.className = 'w-3 h-3 bg-green-500 rounded-full';
            text.textContent = 'Connected';
            text.className = 'text-sm text-green-600';
        } else {
            dot.className = 'w-3 h-3 bg-red-500 rounded-full animate-pulse';
            text.textContent = 'Disconnected';
            text.className = 'text-sm text-red-600';
        }
    }
    
    /**
    * Ensure Pria connection exists
    */
    ensurePriaConnection() {
        if (!this.pria || !this.isConnected) {
            this.showToast('Pria SDK not connected', 'error');
            return false;
        }
        return true;
    }
    
    /**
    * Show toast notification
    */
    showToast(message, type = 'info') {
        const container = document.getElementById('toast-container');
        const toast = document.createElement('div');
        
        const colors = {
            success: 'bg-green-500',
            error: 'bg-red-500',
            warning: 'bg-yellow-500',
            info: 'bg-blue-500'
        };
        
        const icons = {
            success: 'fas fa-check-circle',
            error: 'fas fa-exclamation-circle',
            warning: 'fas fa-exclamation-triangle',
            info: 'fas fa-info-circle'
        };
        
        toast.className = `${colors[type]} text-white px-6 py-3 rounded-lg shadow-lg flex items-center space-x-3 transform transition-all duration-300 translate-x-full`;
        toast.innerHTML = `
            <i class="${icons[type]}"></i>
            <span>${message}</span>
        `;
        
        container.appendChild(toast);
        
        // Animate in
        setTimeout(() => {
            toast.classList.remove('translate-x-full');
        }, 100);
        
        // Auto remove
        setTimeout(() => {
            toast.classList.add('translate-x-full');
            setTimeout(() => {
                if (container.contains(toast)) {
                    container.removeChild(toast);
                }
            }, 300);
        }, 3000);
    }
}

// Initialize the application when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
    new PriaTestHarness();
});