Vanilla JavaScript Integration
This guide covers integrating Diosc without any framework - pure HTML, CSS, and JavaScript.
Quick Start
CDN (Simplest)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My App with AI</title>
<!-- Load Diosc -->
<script type="module" src="https://unpkg.com/@diosc-ai/assistant-kit@latest/dist/assistant-kit/assistant-kit.esm.js"></script>
</head>
<body>
<h1>My Application</h1>
<!-- AI Chat Component -->
<diosc-chat></diosc-chat>
<script type="module">
import { diosc } from 'https://unpkg.com/@diosc-ai/assistant-kit@latest/dist/assistant-kit/assistant-kit.esm.js';
// Configure
diosc('config', {
backendUrl: 'https://your-hub.example.com',
apiKey: 'your-api-key',
autoConnect: true
});
</script>
</body>
</html>
NPM with Bundler
If using a bundler like Webpack, Rollup, or Parcel:
npm install @diosc-ai/assistant-kit
import { diosc } from '@diosc-ai/assistant-kit';
diosc('config', {
backendUrl: 'https://your-hub.example.com',
apiKey: 'your-api-key'
});
Configuration
Basic Configuration
diosc('config', {
// Required
backendUrl: 'https://your-hub.example.com',
apiKey: 'your-api-key',
// Optional
autoConnect: true, // Connect immediately (default: true)
verbose: false, // Debug logging (default: false)
reconnect: true, // Auto-reconnect on disconnect (default: true)
reconnectDelay: 1000 // Delay between reconnect attempts (ms)
});
Authentication
diosc('auth', async () => {
// Get current user's token
const token = localStorage.getItem('access_token');
// Optionally refresh if expired
if (isTokenExpired(token)) {
const newToken = await refreshToken();
localStorage.setItem('access_token', newToken);
return {
headers: { 'Authorization': `Bearer ${newToken}` }
};
}
return {
headers: { 'Authorization': `Bearer ${token}` },
userId: parseJwt(token).sub
};
});
function isTokenExpired(token) {
if (!token) return true;
const payload = parseJwt(token);
return payload.exp * 1000 < Date.now();
}
function parseJwt(token) {
const base64 = token.split('.')[1];
return JSON.parse(atob(base64));
}
Event Handling
Listening to Events
// Connection events
diosc('on', 'connected', () => {
console.log('Connected to Diosc Hub');
document.getElementById('status').textContent = 'Connected';
});
diosc('on', 'disconnected', () => {
console.log('Disconnected');
document.getElementById('status').textContent = 'Disconnected';
});
diosc('on', 'reconnecting', (attempt) => {
console.log(`Reconnecting... attempt ${attempt}`);
});
// Message events
diosc('on', 'message', (msg) => {
console.log('AI:', msg.content);
appendMessage('assistant', msg.content);
});
diosc('on', 'streaming', (chunk) => {
// Handle streaming text
appendToLastMessage(chunk);
});
diosc('on', 'streaming_end', () => {
// Streaming complete
finalizeLastMessage();
});
// Tool events
diosc('on', 'tool_start', (tool) => {
console.log(`Executing: ${tool.name}`);
showToolIndicator(tool.name);
});
diosc('on', 'tool_end', (result) => {
console.log('Tool result:', result);
hideToolIndicator();
});
// Error handling
diosc('on', 'error', (error) => {
console.error('Error:', error);
showError(error.message);
});
// Approval workflow
diosc('on', 'approval_required', (request) => {
showApprovalDialog(request);
});
Removing Listeners
// Store the unsubscribe function
const unsubscribe = diosc('on', 'message', handleMessage);
// Later, remove the listener
unsubscribe();
Sending Messages
Programmatic Messages
// Send a message
diosc('send', 'Hello, AI!');
// Send with context
diosc('send', 'Help me with this order', {
context: {
orderId: '12345',
page: 'order-details'
}
});
Form Integration
<form id="chat-form">
<input type="text" id="message-input" placeholder="Type a message...">
<button type="submit">Send</button>
</form>
<script>
document.getElementById('chat-form').addEventListener('submit', (e) => {
e.preventDefault();
const input = document.getElementById('message-input');
const message = input.value.trim();
if (message) {
diosc('send', message);
input.value = '';
}
});
</script>
Page Context
Update context when the page changes:
// Update page context
function updatePageContext() {
diosc('pageContext', {
path: window.location.pathname,
search: window.location.search,
pageType: document.body.dataset.pageType,
pageData: getPageData()
});
}
// Call on page load
updatePageContext();
// Call on navigation (for SPAs)
window.addEventListener('popstate', updatePageContext);
// Or hook into your router
function navigateTo(path) {
history.pushState(null, '', path);
loadPage(path);
updatePageContext();
}
Custom Chat UI
Build your own chat interface:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Custom Chat</title>
<style>
.chat-container {
max-width: 600px;
margin: 0 auto;
height: 80vh;
display: flex;
flex-direction: column;
border: 1px solid #e0e0e0;
border-radius: 8px;
}
.messages {
flex: 1;
overflow-y: auto;
padding: 1rem;
}
.message {
margin-bottom: 1rem;
padding: 0.75rem 1rem;
border-radius: 8px;
max-width: 80%;
}
.message.user {
background: #0066cc;
color: white;
margin-left: auto;
}
.message.assistant {
background: #f0f0f0;
}
.message.loading {
opacity: 0.7;
}
.input-area {
display: flex;
padding: 1rem;
border-top: 1px solid #e0e0e0;
}
.input-area input {
flex: 1;
padding: 0.75rem;
border: 1px solid #e0e0e0;
border-radius: 4px;
margin-right: 0.5rem;
}
.input-area button {
padding: 0.75rem 1.5rem;
background: #0066cc;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.input-area button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.status {
padding: 0.5rem 1rem;
font-size: 0.875rem;
color: #666;
border-bottom: 1px solid #e0e0e0;
}
.status.connected { color: green; }
.status.disconnected { color: red; }
</style>
</head>
<body>
<div class="chat-container">
<div id="status" class="status disconnected">Connecting...</div>
<div id="messages" class="messages"></div>
<div class="input-area">
<input type="text" id="input" placeholder="Type a message..." disabled>
<button id="send-btn" disabled>Send</button>
</div>
</div>
<!-- Headless agent for connection management -->
<diosc-agent></diosc-agent>
<script type="module">
import { diosc } from 'https://unpkg.com/@diosc-ai/assistant-kit@latest/dist/assistant-kit/assistant-kit.esm.js';
// Elements
const messagesEl = document.getElementById('messages');
const inputEl = document.getElementById('input');
const sendBtn = document.getElementById('send-btn');
const statusEl = document.getElementById('status');
// State
let isLoading = false;
let currentStreamingEl = null;
// Configure
diosc('config', {
backendUrl: 'https://your-hub.example.com',
apiKey: 'your-api-key',
autoConnect: true
});
// Connection events
diosc('on', 'connected', () => {
statusEl.textContent = 'Connected';
statusEl.className = 'status connected';
inputEl.disabled = false;
sendBtn.disabled = false;
});
diosc('on', 'disconnected', () => {
statusEl.textContent = 'Disconnected';
statusEl.className = 'status disconnected';
inputEl.disabled = true;
sendBtn.disabled = true;
});
// Message events
diosc('on', 'message', (msg) => {
if (currentStreamingEl) {
currentStreamingEl.classList.remove('loading');
currentStreamingEl = null;
}
appendMessage('assistant', msg.content);
isLoading = false;
updateSendButton();
});
diosc('on', 'streaming', (chunk) => {
if (!currentStreamingEl) {
currentStreamingEl = appendMessage('assistant', '', true);
}
currentStreamingEl.textContent += chunk;
scrollToBottom();
});
diosc('on', 'streaming_end', () => {
if (currentStreamingEl) {
currentStreamingEl.classList.remove('loading');
currentStreamingEl = null;
}
isLoading = false;
updateSendButton();
});
diosc('on', 'error', (error) => {
appendMessage('assistant', `Error: ${error.message}`);
isLoading = false;
updateSendButton();
});
// Helper functions
function appendMessage(role, content, isStreaming = false) {
const msgEl = document.createElement('div');
msgEl.className = `message ${role}${isStreaming ? ' loading' : ''}`;
msgEl.textContent = content;
messagesEl.appendChild(msgEl);
scrollToBottom();
return msgEl;
}
function scrollToBottom() {
messagesEl.scrollTop = messagesEl.scrollHeight;
}
function updateSendButton() {
sendBtn.disabled = isLoading || !inputEl.value.trim();
}
function sendMessage() {
const content = inputEl.value.trim();
if (!content || isLoading) return;
appendMessage('user', content);
inputEl.value = '';
isLoading = true;
updateSendButton();
diosc('send', content);
}
// Event listeners
sendBtn.addEventListener('click', sendMessage);
inputEl.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
inputEl.addEventListener('input', updateSendButton);
</script>
</body>
</html>
Multiple Chat Instances
While you can only have one diosc configuration, you can have multiple UI instances:
<!-- Main chat -->
<diosc-chat id="main-chat"></diosc-chat>
<!-- Embedded in a modal -->
<div id="modal" class="modal">
<diosc-chat id="modal-chat"></diosc-chat>
</div>
Both will share the same connection and session.
Styling
CSS Custom Properties
diosc-chat {
/* Colors */
--diosc-primary-color: #0066cc;
--diosc-primary-hover: #0052a3;
--diosc-background: #ffffff;
--diosc-surface: #f5f5f5;
--diosc-text-color: #333333;
--diosc-text-secondary: #666666;
--diosc-border-color: #e0e0e0;
/* Typography */
--diosc-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--diosc-font-size: 14px;
--diosc-line-height: 1.5;
/* Spacing */
--diosc-spacing-xs: 4px;
--diosc-spacing-sm: 8px;
--diosc-spacing-md: 16px;
--diosc-spacing-lg: 24px;
/* Layout */
--diosc-border-radius: 8px;
--diosc-chat-width: 380px;
--diosc-chat-height: 600px;
--diosc-chat-max-height: 80vh;
/* Shadows */
--diosc-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--diosc-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
--diosc-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.15);
}
Dark Mode
@media (prefers-color-scheme: dark) {
diosc-chat {
--diosc-background: #1a1a1a;
--diosc-surface: #2d2d2d;
--diosc-text-color: #ffffff;
--diosc-text-secondary: #a0a0a0;
--diosc-border-color: #404040;
}
}
/* Or with a class */
.dark-mode diosc-chat {
--diosc-background: #1a1a1a;
/* ... */
}
Positioning
/* Floating bottom-right (default) */
diosc-chat {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
}
/* Full-width embed */
diosc-chat.embedded {
position: relative;
width: 100%;
height: 100%;
--diosc-chat-width: 100%;
--diosc-chat-height: 100%;
}
Browser Compatibility
Diosc web components work in all modern browsers:
| Browser | Minimum Version |
|---|---|
| Chrome | 67+ |
| Firefox | 63+ |
| Safari | 12+ |
| Edge | 79+ |
For older browsers, you may need polyfills:
<script src="https://unpkg.com/@webcomponents/webcomponentsjs@2/webcomponents-loader.js"></script>
Troubleshooting
Component Not Rendering
Check if the script loaded:
if (typeof diosc === 'undefined') {
console.error('Diosc not loaded');
}
Check browser console for errors.
CORS Errors
Your Diosc Hub needs to allow requests from your domain:
Access-Control-Allow-Origin: https://your-domain.com
WebSocket Connection Failed
Check if WebSocket is supported and not blocked:
if (!window.WebSocket) {
console.error('WebSocket not supported');
}
Check firewall/proxy settings.
Events Not Firing
Ensure you're subscribing before the event occurs:
// Subscribe first
diosc('on', 'connected', () => { ... });
// Then configure (which triggers connect)
diosc('config', { ... });
Next Steps
- Common Integration Patterns - Framework-agnostic patterns
- Core Concepts - Understand Diosc architecture
- MCP Development - Connect your APIs