UNPKG

@claytondcruze/chat-sdk

Version:

TypeScript SDK for AgentStable Chat System with CRUD operations and AI streaming

613 lines 21.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChatSDK = void 0; class ChatSDK { constructor(config) { this.config = config; } getHeaders() { return { "Content-Type": "application/json", "x-user-id": this.config.userId, ...(this.config.apiKey && { Authorization: `Bearer ${this.config.apiKey}` }), }; } async fetchAPI(endpoint, options = {}) { const url = `${this.config.baseUrl}/${endpoint}`; const response = await fetch(url, { ...options, headers: { ...this.getHeaders(), ...options.headers, }, signal: AbortSignal.timeout(this.config.timeout || 30000), }); if (!response.ok) { throw new Error(`HTTP Error: ${response.status} ${response.statusText}`); } return response.json(); } // ============================================================================ // CHAT OPERATIONS // ============================================================================ /** * Create a new chat */ async createChat(data) { const response = await this.fetchAPI("chatCrud", { method: "POST", body: JSON.stringify(data), }); if (!response.success) { throw new Error(response.error || "Failed to create chat"); } return response.data; } /** * Get a specific chat by ID */ async getChat(chatId) { const response = await this.fetchAPI(`chatCrud?chatId=${chatId}`, { method: "GET", }); if (!response.success) { throw new Error(response.error || "Failed to get chat"); } return response.data; } /** * List chats with pagination */ async listChats(limit = 20, cursor) { const params = new URLSearchParams({ limit: limit.toString(), ...(cursor && { cursor }), }); const response = await this.fetchAPI(`chatCrud?${params.toString()}`, { method: "GET" }); if (!response.success) { throw new Error(response.error || "Failed to list chats"); } return response.data; } /** * Update a chat */ async updateChat(chatId, updates) { const response = await this.fetchAPI(`chatCrud?chatId=${chatId}`, { method: "PUT", body: JSON.stringify(updates), }); if (!response.success) { throw new Error(response.error || "Failed to update chat"); } return response.data; } /** * Delete a chat */ async deleteChat(chatId) { const response = await this.fetchAPI(`chatCrud?chatId=${chatId}`, { method: "DELETE", }); if (!response.success) { throw new Error(response.error || "Failed to delete chat"); } } // ============================================================================ // MESSAGE OPERATIONS // ============================================================================ /** * Create a new message */ async createMessage(data) { const response = await this.fetchAPI("messageCrud", { method: "POST", body: JSON.stringify(data), }); if (!response.success) { throw new Error(response.error || "Failed to create message"); } return response.data; } /** * Get messages for a chat with pagination */ async getMessages(chatId, limit = 50, cursor) { const params = new URLSearchParams({ chatId, limit: limit.toString(), ...(cursor && { cursor }), }); const response = await this.fetchAPI(`messageCrud?${params.toString()}`, { method: "GET" }); if (!response.success) { throw new Error(response.error || "Failed to get messages"); } return response.data; } /** * Delete a message */ async deleteMessage(messageId) { const response = await this.fetchAPI(`messageCrud?messageId=${messageId}`, { method: "DELETE", }); if (!response.success) { throw new Error(response.error || "Failed to delete message"); } } // ============================================================================ // AI STREAMING OPERATIONS // ============================================================================ /** * Send a message and get streaming AI response */ async streamChat(data) { const url = `${this.config.baseUrl}/aiChatStream`; const abortController = new AbortController(); const response = await fetch(url, { method: "POST", headers: this.getHeaders(), body: JSON.stringify(data), signal: abortController.signal, }); if (!response.ok) { throw new Error(`HTTP Error: ${response.status} ${response.statusText}`); } if (!response.body) { throw new Error("No response body for streaming"); } // Transform the ReadableStream to return strings const stream = new ReadableStream({ start(controller) { const reader = response.body.getReader(); const decoder = new TextDecoder(); function pump() { return reader.read().then(({ done, value }) => { if (done) { controller.close(); return; } const chunk = decoder.decode(value, { stream: true }); controller.enqueue(chunk); return pump(); }); } return pump(); }, }); return { stream, cancel: () => abortController.abort(), }; } // ============================================================================ // UTILITY METHODS // ============================================================================ /** * Helper method to consume a streaming response as a string */ async streamToString(streamResponse) { const reader = streamResponse.stream.getReader(); let result = ""; try { while (true) { const { done, value } = await reader.read(); if (done) break; result += value; } } finally { reader.releaseLock(); } return result; } /** * Helper method to get full chat conversation (all messages) */ async getChatHistory(chatId) { let allMessages = []; let cursor; let hasMore = true; while (hasMore) { const response = await this.getMessages(chatId, 50, cursor); allMessages = allMessages.concat(response.messages); hasMore = response.hasMore; cursor = response.nextCursor; } return allMessages; } /** * Helper method for simple chat completion (create message + get AI response) */ async sendMessage(chatId, message, options = {}) { const streamResponse = await this.streamChat({ chatId, message, ...options, }); return this.streamToString(streamResponse); } // Classification helper methods /** * Get classification data from a message */ getMessageClassification(message) { return message.metadata?.classification || null; } /** * Check if a message was classified as complex */ isComplexMessage(message) { return message.metadata?.classification?.complexity === "COMPLEX_ACTIONABLE" || message.metadata?.classification?.complexity === "COMPLEX_INFORMATIONAL"; } /** * Get topics identified in a message */ getMessageTopics(message) { return message.metadata?.classification?.topics || []; } /** * Get classification statistics for a chat */ async getChatClassificationStats(chatId) { const messages = await this.getMessages(chatId, 100); // Get up to 100 messages const userMessages = messages.messages.filter(m => m.role === 'user'); const classificationsWithData = userMessages .map(m => m.metadata?.classification) .filter(c => c !== undefined); if (classificationsWithData.length === 0) { return { totalMessages: 0, simpleMessages: 0, complexMessages: 0, averageConfidence: 0, topTopics: [] }; } const simpleCount = classificationsWithData.filter(c => c.complexity === 'SIMPLE').length; const complexCount = classificationsWithData.filter(c => c.complexity === 'COMPLEX_ACTIONABLE' || c.complexity === 'COMPLEX_INFORMATIONAL').length; const avgConfidence = classificationsWithData.reduce((sum, c) => sum + c.confidence, 0) / classificationsWithData.length; // Count topics const topicCounts = {}; classificationsWithData.forEach(c => { c.topics.forEach(topic => { topicCounts[topic] = (topicCounts[topic] || 0) + 1; }); }); const topTopics = Object.entries(topicCounts) .sort(([, a], [, b]) => b - a) .slice(0, 10) .map(([topic, count]) => ({ topic, count })); return { totalMessages: classificationsWithData.length, simpleMessages: simpleCount, complexMessages: complexCount, averageConfidence: Math.round(avgConfidence * 100) / 100, topTopics }; } /** * Filter messages by complexity */ filterMessagesByComplexity(messages, complexity) { return messages.filter(m => m.metadata?.classification?.complexity === complexity); } /** * Search messages by topics */ searchMessagesByTopics(messages, topics) { return messages.filter(m => { const messageTopics = m.metadata?.classification?.topics || []; return topics.some(topic => messageTopics.some(mt => mt.toLowerCase().includes(topic.toLowerCase()))); }); } // ============================================================================ // FILESYSTEM OPERATIONS // ============================================================================ /** * Create a new filesystem */ async createFileSystem(data) { const response = await this.fetchAPI("filesystemCrud", { method: "POST", body: JSON.stringify(data), }); if (!response.success) { throw new Error(response.error || "Failed to create filesystem"); } return response.data; } /** * Get a specific filesystem by ID */ async getFileSystem(filesystemId) { const response = await this.fetchAPI(`filesystemCrud?filesystemId=${filesystemId}`, { method: "GET", }); if (!response.success) { throw new Error(response.error || "Failed to get filesystem"); } return response.data; } /** * List all filesystems for the user */ async listFileSystems() { const response = await this.fetchAPI("filesystemCrud", { method: "GET", }); if (!response.success) { throw new Error(response.error || "Failed to list filesystems"); } return response.data; } /** * Update a filesystem */ async updateFileSystem(filesystemId, updates) { const response = await this.fetchAPI(`filesystemCrud?filesystemId=${filesystemId}`, { method: "PUT", body: JSON.stringify(updates), }); if (!response.success) { throw new Error(response.error || "Failed to update filesystem"); } return response.data; } /** * Delete a filesystem */ async deleteFileSystem(filesystemId) { const response = await this.fetchAPI(`filesystemCrud?filesystemId=${filesystemId}`, { method: "DELETE", }); if (!response.success) { throw new Error(response.error || "Failed to delete filesystem"); } } // ============================================================================ // FOLDER OPERATIONS // ============================================================================ /** * Create a new folder */ async createFolder(data) { const response = await this.fetchAPI(`folderCrud/${data.filesystem_id}`, { method: "POST", body: JSON.stringify(data), }); if (!response.success) { throw new Error(response.error || "Failed to create folder"); } return response.data; } /** * Get a specific folder by ID */ async getFolder(filesystemId, folderId) { const response = await this.fetchAPI(`folderCrud/${filesystemId}/${folderId}`, { method: "GET", }); if (!response.success) { throw new Error(response.error || "Failed to get folder"); } return response.data; } /** * List folders in a filesystem */ async listFolders(filesystemId) { const response = await this.fetchAPI(`folderCrud/${filesystemId}`, { method: "GET", }); if (!response.success) { throw new Error(response.error || "Failed to list folders"); } return response.data; } /** * Update a folder */ async updateFolder(filesystemId, folderId, updates) { const response = await this.fetchAPI(`folderCrud/${filesystemId}/${folderId}`, { method: "PUT", body: JSON.stringify(updates), }); if (!response.success) { throw new Error(response.error || "Failed to update folder"); } return response.data; } /** * Delete a folder */ async deleteFolder(filesystemId, folderId) { const response = await this.fetchAPI(`folderCrud/${filesystemId}/${folderId}`, { method: "DELETE", }); if (!response.success) { throw new Error(response.error || "Failed to delete folder"); } } // ============================================================================ // FILE OPERATIONS // ============================================================================ /** * Create a new file */ async createFile(data) { const response = await this.fetchAPI(`fileCrud/${data.filesystem_id}/${data.folder_id}`, { method: "POST", body: JSON.stringify(data), }); if (!response.success) { throw new Error(response.error || "Failed to create file"); } return response.data; } /** * Get a specific file by ID */ async getFile(filesystemId, folderId, fileId) { const response = await this.fetchAPI(`fileCrud/${filesystemId}/${folderId}/${fileId}`, { method: "GET", }); if (!response.success) { throw new Error(response.error || "Failed to get file"); } return response.data; } /** * List files in a folder */ async listFiles(filesystemId, folderId) { const response = await this.fetchAPI(`fileCrud/${filesystemId}/${folderId}`, { method: "GET", }); if (!response.success) { throw new Error(response.error || "Failed to list files"); } return response.data; } /** * Update a file */ async updateFile(filesystemId, folderId, fileId, updates) { const response = await this.fetchAPI(`fileCrud/${filesystemId}/${folderId}/${fileId}`, { method: "PUT", body: JSON.stringify(updates), }); if (!response.success) { throw new Error(response.error || "Failed to update file"); } return response.data; } /** * Delete a file */ async deleteFile(filesystemId, folderId, fileId) { const response = await this.fetchAPI(`fileCrud/${filesystemId}/${folderId}/${fileId}`, { method: "DELETE", }); if (!response.success) { throw new Error(response.error || "Failed to delete file"); } } // ============================================================================ // AI FILESYSTEM PIPELINE // ============================================================================ /** * Use AI to analyze user intent and create intelligent filesystem structures */ async aiFilesystemPipeline(data) { const response = await this.fetchAPI("aiFilesystemPipeline", { method: "POST", body: JSON.stringify(data), }); if (!response.success) { throw new Error(response.error || "Failed to run AI filesystem pipeline"); } // The API returns the result directly in the response, not wrapped in data return { pipeline_results: response.pipeline_results, execution_results: response.execution_result }; } /** * Get user's filesystem context for AI analysis */ async getFilesystemContext() { const response = await this.fetchAPI("filesystemContext", { method: "GET", }); if (!response.success) { throw new Error(response.error || "Failed to get filesystem context"); } return response.data; } // ============================================================================ // UTILITY METHODS FOR FILESYSTEM // ============================================================================ /** * Helper method to create a complete filesystem structure from AI pipeline results */ async createFilesystemFromPipeline(pipelineResult) { const structure = pipelineResult.pipeline_results.proposed_structure; if (!structure) { throw new Error("No proposed structure found in pipeline results"); } // Create filesystem const filesystem = await this.createFileSystem({ name: structure.filesystem_name, description: structure.description, tags: structure.tags, }); // Create folders const folders = []; for (const folderSpec of structure.folders) { const folder = await this.createFolder({ name: folderSpec.name, description: folderSpec.description, filesystem_id: filesystem.id, tags: folderSpec.tags, }); folders.push(folder); } // Create files if specified const files = []; if (structure.files) { for (const fileSpec of structure.files) { // Find the target folder const targetFolder = folders.find(f => f.path === fileSpec.folder_path); if (targetFolder) { const file = await this.createFile({ name: fileSpec.name, description: fileSpec.description, content: fileSpec.content_template, filesystem_id: filesystem.id, folder_id: targetFolder.id, mime_type: fileSpec.mime_type, tags: fileSpec.tags, }); files.push(file); } } } return { filesystem, folders, files, }; } /** * Search for files and folders by tags */ async searchByTags(filesystemId, tags) { const folders = await this.listFolders(filesystemId); const matchingFolders = folders.filter(folder => { const folderTags = Array.isArray(folder.metadata.tags) ? folder.metadata.tags : Object.values(folder.metadata.tags || {}); return tags.some(tag => folderTags.includes(tag)); }); const allFiles = []; for (const folder of folders) { const files = await this.listFiles(filesystemId, folder.id); allFiles.push(...files); } const matchingFiles = allFiles.filter(file => { const fileTags = Array.isArray(file.metadata.tags) ? file.metadata.tags : Object.values(file.metadata.tags || {}); return tags.some(tag => fileTags.includes(tag)); }); return { folders: matchingFolders, files: matchingFiles, }; } } exports.ChatSDK = ChatSDK; //# sourceMappingURL=client.js.map