Conversation History
Edit on GitHubThis document describes how to use conversation history with the AiFoundation module to maintain conversation context across multiple interactions, enabling multi-turn conversations where the AI can reference previous messages and provide contextually relevant responses.
Conversation history is persisted in the database using the spy_ai_conversation_history table, ensuring conversations are stored durably and can be retrieved at any time.
Overview
Conversation history enables you to maintain persistent conversation context across multiple interactions. Instead of sending isolated prompts, you can build conversational experiences where the AI remembers previous messages and maintains state throughout an extended dialogue.
The conversation history feature automatically persists all messages in a conversation to the database. When you include a conversation reference in your prompt request, all exchanges are stored in the spy_ai_conversation_history table and automatically included in subsequent requests to maintain context.
Prerequisites
- AiFoundation module installed and configured. For details, see AiFoundation module Overview.
- Database configured and migrated to include the
spy_ai_conversation_historytable
Key concepts
Conversation Reference
A unique identifier for a conversation. All messages in a conversation are stored together under this reference. You can use any string as a conversation reference, such as a customer ID, session ID, or custom identifier.
Context window
The maximum number of tokens that can be stored in a conversation. Default is 50000 tokens. When a conversation exceeds this limit, the oldest messages are automatically pruned to maintain the window size.
Configure conversation history
Configure the context window for conversation history in your AI configuration.
Default configuration
Update your config/Shared/config_ai.php:
<?php
use Spryker\Shared\AiFoundation\AiFoundationConstants;
$config[AiFoundationConstants::CONVERSATION_HISTORY_CONTEXT_WINDOW] = 50000; // tokens
Per-AI-configuration settings
Configure the context window for specific AI configurations by adding conversation_history settings within AI_CONFIGURATIONS:
<?php
use Spryker\Shared\AiFoundation\AiFoundationConstants;
$config[AiFoundationConstants::AI_CONFIGURATIONS] = [
'customer_support' => [
'provider_name' => AiFoundationConstants::PROVIDER_OPENAI,
'provider_config' => [
'api_key' => getenv('OPENAI_API_KEY'),
'model' => 'gpt-4',
],
'system_prompt' => 'You are a helpful customer support assistant.',
'conversation_history' => [
'context_window' => 100000, // Larger context for complex support cases
],
],
];
Per-configuration settings take precedence over global defaults. If conversation_history is not specified for an AI configuration, it falls back to the global CONVERSATION_HISTORY_CONTEXT_WINDOW value.
Adjust context window based on expected conversation length and token limits of your AI provider. Large context windows provide better conversation history but require more tokens for each AI request.
Use conversation history in conversations
Basic multi-turn conversation
To enable conversation history, include a conversationReference in your PromptRequestTransfer. All messages are automatically persisted and included in future requests:
<?php
namespace Pyz\Zed\YourModule\Business;
use Generated\Shared\Transfer\PromptMessageTransfer;
use Generated\Shared\Transfer\PromptRequestTransfer;
use Spryker\Zed\AiFoundation\Business\AiFoundationFacadeInterface;
class CustomerSupportAssistant
{
public function __construct(
protected AiFoundationFacadeInterface $aiFoundationFacade
) {
}
public function respondToCustomer(string $conversationReference, string $userMessage): string
{
// Create a new prompt request with conversation reference
$promptRequest = (new PromptRequestTransfer())
->setConversationReference($conversationReference) // Enable conversation history
->setPromptMessage(
(new PromptMessageTransfer())->setContent($userMessage)
);
// The AI automatically has access to conversation history
$response = $this->aiFoundationFacade->prompt($promptRequest);
if ($response->getIsSuccessful() === true) {
return $response->getMessage()->getContent();
}
return 'An error occurred processing your request.';
}
}
Manage conversation history
Access the complete conversation history at any time:
<?php
namespace Pyz\Zed\YourModule\Business;
use Generated\Shared\Transfer\ConversationHistoryCriteriaTransfer;
use Generated\Shared\Transfer\ConversationHistoryConditionsTransfer;
use Spryker\Zed\AiFoundation\Business\AiFoundationFacadeInterface;
class ConversationManager
{
public function __construct(
protected AiFoundationFacadeInterface $aiFoundationFacade
) {
}
public function getConversationMessages(string $conversationReference): array
{
$conversationHistoryCriteriaTransfer = (new ConversationHistoryCriteriaTransfer())
->setConversationHistoryConditions(
(new ConversationHistoryConditionsTransfer())
->setConversationReferences([$conversationReference])
);
$conversationHistoryCollectionTransfer = $this->aiFoundationFacade->getConversationHistoryCollection($conversationHistoryCriteriaTransfer);
$conversationHistories = $conversationHistoryCollectionTransfer->getConversationHistories();
if ($conversationHistories->count() === 0) {
return [];
}
$conversationHistoryTransfer = $conversationHistories->offsetGet(0);
$messages = $conversationHistoryTransfer->getMessages();
$formattedMessages = [];
foreach ($messages as $message) {
$formattedMessages[] = [
'type' => $message->getType(), // 'user', 'assistant', 'tool_call', 'tool_result'
'content' => $message->getContent(),
];
}
return $formattedMessages;
}
public function getMultipleConversations(array $conversationReferences): array
{
$conversationHistoryCriteriaTransfer = (new ConversationHistoryCriteriaTransfer())
->setConversationHistoryConditions(
(new ConversationHistoryConditionsTransfer())
->setConversationReferences($conversationReferences)
);
$conversationHistoryCollectionTransfer = $this->aiFoundationFacade->getConversationHistoryCollection($conversationHistoryCriteriaTransfer);
$conversationHistories = $conversationHistoryCollectionTransfer->getConversationHistories();
$result = [];
foreach ($conversationHistories as $conversationHistory) {
$result[$conversationHistory->getConversationReference()] = [
'conversation_reference' => $conversationHistory->getConversationReference(),
'message_count' => $conversationHistory->getMessages()->count(),
'messages' => array_map(function ($message) {
return [
'type' => $message->getType(),
'content' => $message->getContent(),
];
}, $conversationHistory->getMessages()->getArrayCopy()),
];
}
return $result;
}
}
API reference
AiFoundationFacade
prompt()
Sends a message in a conversation. If conversationReference is provided, the message is stored in conversation history and previous messages are automatically included in the AI’s context.
/**
* @param \Generated\Shared\Transfer\PromptRequestTransfer $promptRequest
* @return \Generated\Shared\Transfer\PromptResponseTransfer
*/
public function prompt(PromptRequestTransfer $promptRequest): PromptResponseTransfer
PromptRequestTransfer properties for conversation history:
conversationReference(string, optional): Enable conversation history by providing a unique conversation identifieraiConfigurationName(string, optional): Configuration name to use, defaults toAI_CONFIGURATION_DEFAULTpromptMessage(PromptMessageTransfer, required): The message to sendmaxRetries(int, optional): Number of retry attempts on failure
getConversationHistoryCollection()
Retrieves conversation history collection based on criteria. Allows filtering conversations by conversation IDs.
/**
* @param \Generated\Shared\Transfer\ConversationHistoryCriteriaTransfer $conversationHistoryCriteriaTransfer
* @return \Generated\Shared\Transfer\ConversationHistoryCollectionTransfer
*/
public function getConversationHistoryCollection(
ConversationHistoryCriteriaTransfer $conversationHistoryCriteriaTransfer
): ConversationHistoryCollectionTransfer
ConversationHistoryCriteriaTransfer properties:
conversationHistoryConditions(ConversationHistoryConditionsTransfer): Filter conditions for the queryconversationReferences(string[]): List of conversation references to retrieve (IN operation). If empty, returns empty collection.
Returns: ConversationHistoryCollectionTransfer containing:
conversationHistories(ConversationHistoryTransfer[]): Array of conversation histories matching the criteria- Each ConversationHistoryTransfer contains:
conversationReference(string): The conversation referencemessages(PromptMessageTransfer[]): Array of all messages in the conversation with types (user, assistant, tool_call, tool_result), content, and attachments
- Each ConversationHistoryTransfer contains:
Message types
Messages stored in conversation history have different types:
user- Message sent by the userassistant- Response from the AItool_call- A tool invocation initiated by the AItool_result- Result of a tool execution
Tool-related types are only present when using AI tools with conversation history.
Best practices
1. Use meaningful conversation references
Choose conversation references that align with your business logic:
// Good: Clear relationship to entity
$conversationReference = "customer_conversation_{$customerId}_{$timestamp}";
$conversationReference = "support_ticket_{$ticketId}";
// Avoid: Generic IDs that are hard to track
$conversationReference = "conv_123";
2. Manage conversation cleanup
Implement your own cleanup strategy for old conversations if needed. Unlike Redis-backed storage with automatic expiration, database-persisted conversations remain indefinitely. Consider creating a scheduled task to delete conversations older than a certain date if storage management is important.
3. Handle large conversations
Monitor context window usage. If approaching limits, start a new conversation.
4. Secure conversation access
Validate that users can only access their own conversations by filtering conversation references based on user permissions:
$conversationHistoryCriteriaTransfer = (new ConversationHistoryCriteriaTransfer())
->setConversationHistoryConditions(
(new ConversationHistoryConditionsTransfer())
->setConversationReferences($userAuthorizedConversationReferences) // Only user's conversations
);
$conversationHistoryCollectionTransfer = $this->aiFoundationFacade->getConversationHistoryCollection($conversationHistoryCriteriaTransfer);
Limitations
- Conversation history is stored in the database and requires the
spy_ai_conversation_historytable to be present - Conversations persist indefinitely in the database; implement your own cleanup strategy if needed
- Very large conversations may approach the context window limit, requiring new conversation references
- Tool invocations and results are included in history and count toward context window
Debugging
Conversation history messages are persisted in the spy_ai_conversation_history database table. You can query the database directly to inspect stored conversations and messages for debugging purposes.
Thank you!
For submitting the form