@openclueo/sdk
Version:
Official JavaScript SDK for Clueo AI Personality API with Big Five model integration
325 lines (274 loc) • 9.27 kB
JavaScript
/**
* Clueo JavaScript SDK
* Simple integration for personality transformation API
*
* @version 1.0.0
* @author Clueo Team
*/
class Clueo {
constructor(apiKey, options = {}) {
if (!apiKey) {
throw new Error('API key is required. Get yours at https://clueo.dev');
}
this.apiKey = apiKey;
this.baseUrl = options.baseUrl || 'https://backend.clueoai.com';
this.timeout = options.timeout || 10000;
}
/**
* Inject personality into a prompt using Big Five model
* @param {string} prompt - The prompt to inject personality into
* @param {Object} options - Big Five personality configuration (1-10 scale)
* @returns {Promise<Object>} Injection result
*/
async inject(prompt, options = {}) {
if (!prompt || typeof prompt !== 'string') {
throw new Error('Prompt must be a non-empty string');
}
const {
openness = 5,
conscientiousness = 5,
extraversion = 5,
agreeableness = 5,
neuroticism = 5,
openaiKey = null
} = options;
// Validate Big Five values (1-10 scale)
const bigFiveValues = { openness, conscientiousness, extraversion, agreeableness, neuroticism };
for (const [trait, value] of Object.entries(bigFiveValues)) {
if (!Number.isInteger(value) || value < 1 || value > 10) {
throw new Error(`${trait} must be an integer between 1 and 10`);
}
}
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
const payload = {
prompt: prompt.trim(),
personalityConfig: {
openness,
conscientiousness,
extraversion,
agreeableness,
neuroticism
}
};
const headers = {
'x-api-key': this.apiKey,
'Content-Type': 'application/json',
};
if (openaiKey) {
headers['x-openai-key'] = openaiKey;
}
const response = await fetch(`${this.baseUrl}/api/enhanced/inject`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.message || `HTTP ${response.status}: ${response.statusText}`);
}
const result = await response.json();
if (!result.success) {
throw new Error(result.message || 'Personality injection failed');
}
return {
injected_prompt: result.data.injected_prompt,
personality_config: result.data.personalityConfig,
usage: result.data.usage,
timestamp: new Date().toISOString()
};
} catch (error) {
if (error.name === 'AbortError') {
throw new Error(`Request timeout after ${this.timeout}ms`);
}
throw error;
}
}
/**
* Transform a message with AI personality
* @param {string} message - The message to transform
* @param {string} tone - Personality tone: 'Professional', 'Sarcastic', 'Empathetic'
* @returns {Promise<Object>} Transformation result
*/
async transform(message, tone = 'Professional') {
if (!message || typeof message !== 'string') {
throw new Error('Message must be a non-empty string');
}
const validTones = ['Professional', 'Sarcastic', 'Empathetic'];
if (!validTones.includes(tone)) {
throw new Error(`Invalid tone. Must be one of: ${validTones.join(', ')}`);
}
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
const response = await fetch(`${this.baseUrl}/transform`, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: message.trim(),
tone: tone
}),
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.message || `HTTP ${response.status}: ${response.statusText}`);
}
const result = await response.json();
if (!result.success) {
throw new Error(result.message || 'Transformation failed');
}
return {
original: result.data.original,
transformed: result.data.transformed,
tone: result.data.tone,
usage: result.data.usage,
meta: result.data.meta
};
} catch (error) {
if (error.name === 'AbortError') {
throw new Error(`Request timeout after ${this.timeout}ms`);
}
throw error;
}
}
/**
* Simulate a conversation response with personality
* @param {string} message - The user message
* @param {Object} options - Big Five personality configuration
* @returns {Promise<Object>} Simulation result
*/
async simulate(message, options = {}) {
if (!message || typeof message !== 'string') {
throw new Error('Message must be a non-empty string');
}
const {
openness = 5,
conscientiousness = 5,
extraversion = 5,
agreeableness = 5,
neuroticism = 5,
openaiKey = null
} = options;
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
const payload = {
message: message.trim(),
personalityConfig: {
openness,
conscientiousness,
extraversion,
agreeableness,
neuroticism
}
};
const headers = {
'x-api-key': this.apiKey,
'Content-Type': 'application/json',
};
if (openaiKey) {
headers['x-openai-key'] = openaiKey;
}
const response = await fetch(`${this.baseUrl}/api/enhanced/simulate`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.message || `HTTP ${response.status}: ${response.statusText}`);
}
const result = await response.json();
if (!result.success) {
throw new Error(result.message || 'Simulation failed');
}
return {
original_message: result.data.originalMessage,
response: result.data.response,
personality_config: result.data.personalityConfig,
usage: result.data.usage,
timestamp: new Date().toISOString()
};
} catch (error) {
if (error.name === 'AbortError') {
throw new Error(`Request timeout after ${this.timeout}ms`);
}
throw error;
}
}
/**
* Batch transform multiple messages
* @param {Array} messages - Array of {message, tone} objects
* @returns {Promise<Array>} Array of transformation results
*/
async batchTransform(messages) {
if (!Array.isArray(messages) || messages.length === 0) {
throw new Error('Messages must be a non-empty array');
}
const results = [];
for (const item of messages) {
try {
const result = await this.transform(item.message, item.tone);
results.push({ success: true, ...result });
} catch (error) {
results.push({ success: false, error: error.message, original: item.message });
}
}
return results;
}
}
// Node.js module export (ES modules)
export default Clueo;
// Node.js module export (CommonJS - for backward compatibility)
if (typeof module !== 'undefined' && module.exports) {
module.exports = Clueo;
}
// Browser global
if (typeof window !== 'undefined') {
window.Clueo = Clueo;
}
// Example usage:
/*
// Node.js
const Clueo = require('./clueo.js');
const clueo = new Clueo('ck_your_api_key_here');
// Browser
const clueo = new Clueo('ck_your_api_key_here');
// Inject personality into prompt using Big Five model
const injectionResult = await clueo.inject('How do I scale my startup?', {
openness: 8, // Creative, open to new ideas
conscientiousness: 7, // Organized, disciplined
extraversion: 6, // Moderately outgoing
agreeableness: 5, // Balanced cooperation
neuroticism: 3, // Calm, stable
openaiKey: 'sk_your_openai_key' // Optional: use your own OpenAI key
});
console.log(injectionResult.injected_prompt);
// Simulate conversation response with personality
const simulationResult = await clueo.simulate('What should I focus on first?', {
openness: 9, // Highly creative
conscientiousness: 8, // Very organized
extraversion: 7, // Outgoing
agreeableness: 6, // Cooperative
neuroticism: 2 // Very calm
});
console.log(simulationResult.response);
// Transform message (legacy method - still works)
const transformResult = await clueo.transform('Hello there!', 'Professional');
console.log(transformResult.transformed);
// Batch transform multiple messages
const batchResults = await clueo.batchTransform([
{ message: 'Hello!', tone: 'Professional' },
{ message: 'Thanks!', tone: 'Empathetic' }
]);
*/