@aichatkit/storage-adapter
Version:
Base storage adapter for Hypermode ChatKit
192 lines (167 loc) • 5.87 kB
text/typescript
/* eslint-disable @typescript-eslint/no-unused-vars */
import { ChatResponseItem, Conversation, Message } from '@aichatkit/types'
export interface StorageAdapterCallbacks {
/**
* Callback to get conversation items from network
* @param agentId The ID of the agent
* @returns Promise with array of response items
*/
getConversationItems?: (agentId: string) => Promise<ChatResponseItem[]>
/**
* Callback to clear conversation history on network
* @param agentId The ID of the agent
* @returns Promise that resolves when cleared
*/
clearConversationHistory?: (agentId: string) => Promise<void>
}
export abstract class StorageAdapter {
protected callbacks?: StorageAdapterCallbacks
/**
* Set network callbacks for syncing with backend
* @param callbacks Network adapter callbacks
*/
setNetworkCallbacks(callbacks: StorageAdapterCallbacks): void {
this.callbacks = callbacks
}
/**
* Saves a conversation to storage
* @param conversation Conversation to save
* @returns Promise that resolves when the operation is complete
*/
abstract saveConversation(conversation: Conversation): Promise<void>
/**
* Retrieves a conversation from storage by ID
* @param id ID of the conversation to retrieve
* @returns Promise that resolves with the conversation or null if not found
*/
abstract getConversation(id: string): Promise<Conversation | null>
/**
* Retrieves all conversations from storage
* @returns Promise that resolves with an array of conversations
*/
abstract getAllConversations(): Promise<Conversation[]>
/**
* Deletes a conversation from storage
* @param id ID of the conversation to delete
* @returns Promise that resolves with a boolean indicating success
*/
abstract deleteConversation(id: string): Promise<boolean>
/**
* Adds a response item to a conversation
* @param conversationId ID of the conversation
* @param item Response item to add
* @returns Promise that resolves with the updated conversation or null if not found
*/
abstract addItem(
conversationId: string,
item: ChatResponseItem,
): Promise<Conversation | null>
/**
* Adds a message to a conversation (convenience method)
* @param conversationId ID of the conversation
* @param message Message to add
* @returns Promise that resolves with the updated conversation or null if not found
*/
async addMessage(
conversationId: string,
message: Message,
): Promise<Conversation | null> {
const messageItem: ChatResponseItem = {
id: message.id,
type: 'message',
content: message.content,
role: message.role,
timestamp: message.timestamp,
} as any
return this.addItem(conversationId, messageItem)
}
/**
* Get conversation items - syncs with backend if callback available
* @param conversationId ID of the conversation
* @returns Promise with array of response items
*/
abstract getConversationItems(
conversationId: string,
): Promise<ChatResponseItem[]>
/**
* Get conversation history (messages only) - syncs with backend if callback available
* @param conversationId ID of the conversation
* @returns Promise with array of messages
*/
async getConversationHistory(conversationId: string): Promise<Message[]> {
const items = await this.getConversationItems(conversationId)
// Filter and convert message items to message format
return items
.filter((item) => item.type === 'message')
.map((item) => {
const msgItem = item as any
return {
id: msgItem.id,
content: msgItem.content,
role: msgItem.role,
timestamp: msgItem.timestamp,
}
})
}
/**
* Clear conversation history - syncs with backend if callback available
* @param conversationId ID of the conversation
* @returns Promise that resolves when history is cleared
*/
abstract clearConversationHistory(conversationId: string): Promise<void>
/**
* Store agent ID for a conversation
* @param conversationId ID of the conversation
* @param agentId ID of the agent
* @returns Promise that resolves when stored
*/
abstract setConversationAgent(
conversationId: string,
agentId: string,
): Promise<void>
/**
* Get agent ID for a conversation
* @param conversationId ID of the conversation
* @returns Promise with agent ID or null if not found
*/
abstract getConversationAgent(conversationId: string): Promise<string | null>
/**
* Sync all conversations with backend to ensure consistency
* @returns Promise that resolves when sync is complete
*/
async syncAllConversationsWithBackend?(): Promise<void> {
if (!this.callbacks?.getConversationItems) {
return Promise.resolve()
}
try {
const conversations = await this.getAllConversations()
for (const conversation of conversations) {
const agentId = await this.getConversationAgent(conversation.id)
if (agentId) {
try {
const backendItems =
await this.callbacks.getConversationItems(agentId)
conversation.items = backendItems
await this.saveConversation(conversation)
} catch (error) {
console.error(
`Failed to sync conversation ${conversation.id}:`,
error,
)
}
}
}
} catch (error) {
console.error('Failed to sync conversations with backend:', error)
}
return Promise.resolve()
}
/**
* Optional method to initialize the adapter
* @param config Optional configuration object
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async initialize(config?: Record<string, any>): Promise<void> {
return Promise.resolve()
}
}