Skip to main content

🚀 Embeddable Agents: Architecture & Development Roadmap

Executive Summary

Embeddable Agents transform Bike4Mind from a platform into AI infrastructure for the internet. This roadmap leverages our existing API key system, agent infrastructure, and WebSocket architecture to enable agents to be embedded anywhere on the web.

🏗️ Architecture Overview

Core Embedding Stack

graph TB
subgraph "Host Website"
SDK[Bike4Mind SDK]
Widget[Agent Widget]
Context[Page Context]
end

subgraph "Authentication Layer"
APIKey[API Key Validation]
Domain[Domain Whitelist]
RateLimit[Rate Limiting]
end

subgraph "Bike4Mind Platform"
AgentAPI[Agent API]
WebSocket[WebSocket Server]
Tools[MCP Tools]
Memory[Agent Memory]
end

SDK --> APIKey
APIKey --> Domain
Domain --> RateLimit
RateLimit --> AgentAPI
Widget --> WebSocket
Context --> AgentAPI
AgentAPI --> Tools
AgentAPI --> Memory

Leveraging Existing Infrastructure

ComponentCurrent StateEmbedding Enhancement
API Keysb4m_live_ format with scopesAdd AGENT_EMBED scope
Rate Limiting✅ Per-key limitsAdd embed-specific limits
WebSocket✅ Real-time communicationAdd embed session handling
Agent System✅ Full personality systemAdd embed configuration
MCP Tools✅ Function callingAdd host-provided tools
AuthenticationapiKeyAuth middlewareAdd domain validation

📋 Phase 1: Foundation (Sprint 1-2)

1.1 Extend API Key System

New Scopes

// b4m-core/packages/core/common/types/entities/UserApiKeyTypes.ts
export enum ApiKeyScope {
// Existing scopes...
READ_NOTEBOOKS = 'notebooks:read',
WRITE_NOTEBOOKS = 'notebooks:write',
READ_FILES = 'files:read',
WRITE_FILES = 'files:write',
AI_GENERATE = 'ai:generate',
AI_CHAT = 'ai:chat',
READ_PROJECTS = 'projects:read',
WRITE_PROJECTS = 'projects:write',
ADMIN = 'admin:*',

// New embedding scopes
AGENT_EMBED = 'agents:embed', // Basic embedding
AGENT_EMBED_VOICE = 'agents:embed:voice', // Voice features
AGENT_EMBED_TOOLS = 'agents:embed:tools', // Tool execution
AGENT_EMBED_MEMORY = 'agents:embed:memory', // Cross-session memory
}

Domain Whitelist in Metadata

// Extend IUserApiKeyMetadata
export interface IUserApiKeyMetadata {
clientIP?: string;
userAgent?: string;
createdFrom: 'dashboard' | 'cli' | 'api' | 'embed-setup';

// New fields for embedding
embedConfig?: {
allowedDomains: string[]; // ['*.company.com', 'app.partner.com']
allowedAgents: string[]; // Specific agent IDs
embedType: 'widget' | 'full' | 'inline';
corsOrigins?: string[]; // CORS configuration
};
}

1.2 Domain Validation Middleware

// packages/client/server/middlewares/embedAuth.ts
import { apiKeyAuth } from './apiKeyAuth';
import { ForbiddenError } from '@server/utils/errors';

export const embedAuth = (requiredScopes?: ApiKeyScope[]) => {
return async (req: Request, res: Response, next: NextFunction) => {
// First validate API key
await apiKeyAuth(requiredScopes)(req, res, () => {});

// Then validate domain
const origin = req.headers.origin || req.headers.referer;
const apiKeyInfo = (req as any).apiKeyInfo;
const embedConfig = apiKeyInfo?.metadata?.embedConfig;

if (!embedConfig) {
throw new ForbiddenError('API key not configured for embedding');
}

if (!matchesDomain(origin, embedConfig.allowedDomains)) {
throw new ForbiddenError('Domain not authorized for this API key');
}

// Add CORS headers
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');

next();
};
};

function matchesDomain(origin: string, allowedDomains: string[]): boolean {
const url = new URL(origin);
const hostname = url.hostname;

return allowedDomains.some(pattern => {
if (pattern.startsWith('*.')) {
const domain = pattern.slice(2);
return hostname.endsWith(domain);
}
return hostname === pattern;
});
}

1.3 Embed Session Management

// packages/database/src/models/EmbedSessionModel.ts
export interface IEmbedSession {
id: string;
apiKeyId: string;
agentId: string;
domain: string;
sessionToken: string; // Short-lived session token
parentSessionId?: string; // Link to main B4M session if exists
context: {
pageUrl: string;
pageTitle?: string;
customContext?: Record<string, any>;
};
usage: {
messages: number;
audioMinutes: number;
toolCalls: number;
};
expiresAt: Date;
createdAt: Date;
lastActivityAt: Date;
}

📋 Phase 2: Core SDK (Sprint 3-4)

2.1 JavaScript SDK Structure

// @bike4mind/agent-sdk/src/index.ts
export class BikeAgent {
private apiKey: string;
private agentId: string;
private ws: WebSocket | null = null;
private sessionToken: string | null = null;

constructor(config: BikeAgentConfig) {
this.apiKey = config.apiKey;
this.agentId = config.agentId;
this.config = config;
}

async init(): Promise<void> {
// 1. Validate API key and get session token
const session = await this.createEmbedSession();
this.sessionToken = session.token;

// 2. Connect WebSocket
await this.connectWebSocket();

// 3. Initialize UI
if (this.config.ui !== false) {
await this.initializeUI();
}

// 4. Set up context providers
if (this.config.contextProviders) {
this.setupContextProviders();
}
}

private async createEmbedSession(): Promise<EmbedSession> {
const response = await fetch(`${this.config.baseUrl}/api/agents/embed/session`, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({
agentId: this.agentId,
context: {
pageUrl: window.location.href,
pageTitle: document.title,
customContext: this.config.context,
},
}),
});

if (!response.ok) {
throw new Error(`Failed to create embed session: ${response.statusText}`);
}

return response.json();
}

// ... WebSocket, UI, and other methods
}

2.2 Embed API Endpoints

// packages/client/pages/api/agents/embed/session.ts
import { embedAuth } from '@server/middlewares/embedAuth';
import { ApiKeyScope } from '@b4m-core/common';

const handler = baseApi()
.use(embedAuth([ApiKeyScope.AGENT_EMBED]))
.post(async (req, res) => {
const { agentId, context } = req.body;
const apiKeyInfo = (req as any).apiKeyInfo;

// Validate agent access
const embedConfig = apiKeyInfo.metadata?.embedConfig;
if (!embedConfig?.allowedAgents.includes(agentId)) {
throw new ForbiddenError('Agent not authorized for this API key');
}

// Create embed session
const session = await embedSessionService.create({
apiKeyId: apiKeyInfo.keyId,
agentId,
domain: req.headers.origin!,
context,
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), // 24 hours
});

// Return session token for WebSocket auth
res.json({
token: generateSessionToken(session.id),
sessionId: session.id,
wsUrl: process.env.NEXT_PUBLIC_WS_URL,
expiresAt: session.expiresAt,
});
});

2.3 WebSocket Handler for Embeds

// packages/client/server/websocket/handlers/embedHandlers.ts
export const embedHandlers = {
'embed:connect': {
function: {
handler: async (data: { sessionToken: string }, ws: WebSocket) => {
// Validate session token
const session = await embedSessionService.validateToken(data.sessionToken);
if (!session) {
throw new UnauthorizedError('Invalid session token');
}

// Attach session to WebSocket
(ws as any).embedSession = session;

// Join agent-specific room
await joinRoom(ws, `agent:${session.agentId}`);

return { status: 'connected', sessionId: session.id };
},
},
},

'embed:message': {
function: {
handler: async (data: { message: string, context?: any }, ws: WebSocket) => {
const session = (ws as any).embedSession;
if (!session) throw new UnauthorizedError('No embed session');

// Track usage
await embedSessionService.incrementUsage(session.id, 'messages');

// Process message with agent
const agent = await agentRepository.findById(session.agentId);
const response = await processAgentMessage(agent, data.message, {
embedContext: session.context,
customContext: data.context,
});

return response;
},
},
},
};

📋 Phase 3: UI Components (Sprint 5-6)

3.1 React Components Package

// @bike4mind/react/src/BikeAgent.tsx
import { BikeAgent as SDK } from '@bike4mind/agent-sdk';
import { useEffect, useRef, useState } from 'react';

export interface BikeAgentProps {
apiKey: string;
agentId: string;
position?: 'bottom-right' | 'bottom-left' | 'inline';
theme?: 'light' | 'dark' | 'auto';
onMessage?: (message: AgentMessage) => void;
contextProviders?: ContextProvider[];
}

export function BikeAgent({
apiKey,
agentId,
position = 'bottom-right',
theme = 'auto',
onMessage,
contextProviders,
}: BikeAgentProps) {
const sdkRef = useRef<SDK | null>(null);
const [isOpen, setIsOpen] = useState(false);
const [messages, setMessages] = useState<Message[]>([]);

useEffect(() => {
const sdk = new SDK({
apiKey,
agentId,
ui: false, // We'll handle UI in React
contextProviders,
});

sdk.on('message', (msg) => {
setMessages(prev => [...prev, msg]);
onMessage?.(msg);
});

sdk.init().catch(console.error);
sdkRef.current = sdk;

return () => {
sdk.disconnect();
};
}, [apiKey, agentId]);

// ... UI implementation
}

3.2 Widget Styles and Theming

// @bike4mind/agent-sdk/src/styles.ts
export const defaultTheme = {
light: {
primary: '#0066cc',
background: '#ffffff',
surface: '#f5f5f5',
text: '#333333',
border: '#e0e0e0',
},
dark: {
primary: '#4dabf7',
background: '#1a1a1a',
surface: '#2a2a2a',
text: '#ffffff',
border: '#404040',
},
};

export const widgetStyles = `
.b4m-agent-widget {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 999999;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

.b4m-agent-bubble {
width: 60px;
height: 60px;
border-radius: 30px;
background: var(--b4m-primary);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transition: transform 0.2s;
}

.b4m-agent-bubble:hover {
transform: scale(1.05);
}

.b4m-agent-chat {
position: absolute;
bottom: 80px;
right: 0;
width: 380px;
height: 600px;
background: var(--b4m-background);
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
display: flex;
flex-direction: column;
}
`;

📋 Phase 4: Advanced Features (Sprint 7-8)

4.1 Custom Tools from Host

// Host website can provide custom tools
const agent = new BikeAgent({
apiKey: 'b4m_live_...',
agentId: 'agent_helper',
customTools: [
{
name: 'get_cart_items',
description: 'Get current shopping cart items',
parameters: {
type: 'object',
properties: {},
},
handler: async () => {
return JSON.stringify(getCartItems());
},
},
{
name: 'apply_discount',
description: 'Apply a discount code',
parameters: {
type: 'object',
properties: {
code: { type: 'string', description: 'Discount code' },
},
required: ['code'],
},
handler: async ({ code }) => {
const result = await applyDiscountCode(code);
return JSON.stringify(result);
},
},
],
});

4.2 Context Providers

// @bike4mind/agent-sdk/src/context-providers.ts
export interface ContextProvider {
name: string;
description: string;
getData: () => Promise<any>;
updateInterval?: number; // Auto-refresh context
}

// Built-in providers
export const pageContentProvider: ContextProvider = {
name: 'page_content',
description: 'Current page text content',
getData: async () => {
return {
url: window.location.href,
title: document.title,
content: document.body.innerText.slice(0, 1000),
meta: getMetaTags(),
};
},
};

export const userContextProvider: ContextProvider = {
name: 'user_context',
description: 'Current user information if available',
getData: async () => {
// Host can implement this
return window.BikeAgentUserContext || null;
},
};

4.3 Cross-Domain Memory Sync

// Enable agents to remember users across different embedded sites
interface CrossDomainMemory {
userId: string; // Hashed user identifier
agentMemories: {
[agentId: string]: {
lastInteraction: Date;
conversationCount: number;
preferences: Record<string, any>;
context: Record<string, any>;
};
};
}

// Implement secure cross-domain storage
class MemorySync {
private readonly storageKey = 'b4m_agent_memory';

async syncMemory(agentId: string, memory: AgentMemory): Promise<void> {
// Use secure iframe postMessage for cross-domain sync
const iframe = document.createElement('iframe');
iframe.src = 'https://agents.bike4mind.com/memory-sync';
iframe.style.display = 'none';
document.body.appendChild(iframe);

iframe.contentWindow?.postMessage({
action: 'sync',
agentId,
memory,
domain: window.location.hostname,
}, 'https://agents.bike4mind.com');
}
}

📋 Phase 5: Developer Experience (Sprint 9-10)

5.1 NPM Packages

// @bike4mind/agent-sdk/package.json
{
"name": "@bike4mind/agent-sdk",
"version": "1.0.0",
"description": "Embed Bike4Mind AI agents in any website",
"main": "dist/index.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"files": ["dist"],
"scripts": {
"build": "rollup -c",
"test": "jest",
"prepublish": "npm run build"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
},
"dependencies": {
"ws": "^8.0.0"
}
}

5.2 CDN Distribution

<!-- Quick embed via CDN -->
<script src="https://cdn.bike4mind.com/agent-sdk/v1/agent.min.js"></script>
<script>
BikeAgent.init({
apiKey: 'b4m_live_...',
agentId: 'agent_helper',
});
</script>

5.3 Developer Portal UI

// Extend existing API key UI for embedding
const EmbedConfigSection = () => {
return (
<Stack spacing={2}>
<Typography level="title-md">Embedding Configuration</Typography>

<FormControl>
<FormLabel>Allowed Domains</FormLabel>
<DomainsInput
placeholder="*.mycompany.com, app.partner.com"
helperText="Domains where this agent can be embedded"
/>
</FormControl>

<FormControl>
<FormLabel>Allowed Agents</FormLabel>
<AgentMultiSelect
helperText="Select which agents can be embedded with this key"
/>
</FormControl>

<FormControl>
<FormLabel>Embed Type</FormLabel>
<Select defaultValue="widget">
<Option value="widget">Floating Widget</Option>
<Option value="inline">Inline Chat</Option>
<Option value="full">Full Screen</Option>
</Select>
</FormControl>

<Alert color="primary" startDecorator={<InfoIcon />}>
<Stack spacing={1}>
<Typography level="body-sm">Quick Start:</Typography>
<CodeBlock language="html">
{`<script src="https://cdn.bike4mind.com/agent-sdk/v1/agent.min.js"></script>
<script>
BikeAgent.init({
apiKey: '${apiKey}',
agentId: '${selectedAgent.id}',
});
</script>`}
</CodeBlock>
</Stack>
</Alert>
</Stack>
);
};

🚀 Implementation Timeline

Month 1: Foundation

  • Week 1-2: Extend API key system with embedding scopes and domain validation
  • Week 3-4: Build embed session management and core authentication

Month 2: SDK Development

  • Week 5-6: Develop JavaScript SDK with WebSocket integration
  • Week 7-8: Create React/Vue/Angular component packages

Month 3: Advanced Features

  • Week 9-10: Implement custom tools and context providers
  • Week 11-12: Add cross-domain memory and analytics

Month 4: Developer Experience

  • Week 13-14: Publish NPM packages and CDN distribution
  • Week 15-16: Launch developer portal and documentation

📊 Success Metrics

Technical KPIs

  • SDK bundle size < 50KB gzipped
  • WebSocket latency < 100ms
  • Embed initialization < 500ms
  • 99.9% uptime for embed API

Business KPIs

  • 100+ websites using embedded agents within 6 months
  • 1M+ embedded conversations per month
  • 50+ custom agent implementations
  • 90% developer satisfaction score

🔒 Security Considerations

Required Security Measures

  1. Domain Validation: Strict checking against whitelist
  2. Rate Limiting: Per-domain and per-key limits
  3. Content Security Policy: Proper CSP headers
  4. Data Isolation: Embedded agents can't access other users' data
  5. Audit Logging: Complete trail of embedded agent actions

Privacy Compliance

  1. GDPR: User consent for data collection
  2. Cookie Policy: First-party only, with consent
  3. Data Retention: Configurable retention policies
  4. Right to Delete: Users can remove all embedded agent data

🎯 MVP Checklist

Phase 1 MVP (Month 1)

  • API key scopes for embedding
  • Domain whitelist validation
  • Basic embed session creation
  • Simple JavaScript SDK
  • Floating widget UI
  • WebSocket connection
  • Basic message handling

Full Launch (Month 4)

  • All UI components (React, Vue, Angular)
  • Custom tools support
  • Context providers
  • Cross-domain memory
  • Analytics dashboard
  • Developer documentation
  • NPM packages published
  • CDN distribution
  • 10+ example implementations

🚦 Next Steps

  1. Immediate: Create AGENT_EMBED scope and update API key UI
  2. Week 1: Implement domain validation middleware
  3. Week 2: Build embed session endpoints
  4. Week 3: Start JavaScript SDK development
  5. Week 4: Create basic widget UI

This roadmap leverages ALL of your existing infrastructure - API keys, WebSocket, agents, and authentication - to deliver embeddable agents with minimal new code! 🚀