Fabric Down Under show 9 with guest Devang Shah now available!
November 23, 2024Azure Firewall Deep Dive Training
November 24, 2024When building agents using Semantic Kernel that integrate with SLMs (Small Language Models) /LLMs (Large Language Models), you typically send and receive multiple responses.
A common pattern is to add all user and agent message to the ChatHistory
object.
In the past, I have done this by implementing a service class to handle these in .NET web applications.
You can see an example of a controller which creates the chat history object for unique sessions for a webchat experience here:
[HttpPost] public async Task Post([FromBody] ChatRequest chatRequest) { // Use a fixed session ID for simplicity, or generate a unique one per user/session var sessionId = "default-session"; var history = _chatHistoryService.GetOrCreateHistory(sessionId); // Add user input history.AddUserMessage(chatRequest.Message); var openAIPromptExecutionSettings = new OpenAIPromptExecutionSettings { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions, }; // Get the response from the AI var result = await _chatCompletionService.GetChatMessageContentAsync( history, executionSettings: openAIPromptExecutionSettings, kernel: _kernel ); // Add the message from the agent to the chat history history.AddAssistantMessage(result.Content ?? string.Empty); return new JsonResult(new { reply = result.Content }); }
In the above code, you will see that we add user messages to the history when they are received.
We add add the agent/assistant reply to the history when they are received by the model.
We also send the history with each request in the above code.
Whilst this is ok for short interactions, more complex interactions can involve multiple iterations and prompts.
This can increase the likelihood of the code hitting a language model maximum number of tokens (words) for a given context window, thereby meaning the model cannot process the request and will return an error.
I have personally seen this on client projects.
Ultimately, we need to find ways to reduce the size of the request sent to a SLM or LLM whilst ensuring the AI still behaves in a way that we expect.
~
Managing Chat History
Several approaches can be implemented to help you reduce the chat history during your agentic AI development.
The Semantic Kernel Team recently published a blog post and shared a GitHub repo detailing some examples of how this can be achieved.
The main concepts in that blog post centred around:
- Sending only the last number of N messages
- Limiting messages based on token count
- Summarising older messages
You can see the interface for chat history reduction contains only 1 method:
////// Interface for reducing the chat history before sending it to the chat completion provider. /// public interface IChatHistoryReducer { ////// Reduce the before sending it to the . /// /// Instance of to be reduced. /// Cancellation token. /// An optional which contains the reduced chat messages or null if chat history can be used as is. Task<IEnumerable?> ReduceAsync(ChatHistory chatHistory, CancellationToken cancellationToken); }
.. an implementation :
////// Implementation of which trim to the specified max token count. /// /// /// This reducer requires that the ChatMessageContent.MetaData contains a TokenCount property. /// public sealed class MaxTokensChatHistoryReducer : IChatHistoryReducer { private readonly int _maxTokenCount; ////// Creates a new instance of . /// /// Max token count to send to the model. public MaxTokensChatHistoryReducer(int maxTokenCount) { if (maxTokenCount <= 0) { throw new ArgumentException("Maximum token count must be greater than zero.", nameof(maxTokenCount)); } this._maxTokenCount = maxTokenCount; } /// public Task<IEnumerable?> ReduceAsync(ChatHistory chatHistory, CancellationToken cancellationToken = default) { var systemMessage = chatHistory.GetSystemMessage(); var truncationIndex = ComputeTruncationIndex(chatHistory, systemMessage); IEnumerable? truncatedHistory = null; if (truncationIndex > 0) { truncatedHistory = chatHistory.Extract(truncationIndex, systemMessage: systemMessage); } return Task.FromResult<IEnumerable?>(truncatedHistory); } #region private ////// Compute the index truncation where truncation should begin using the current truncation threshold. /// /// ChatHistory instance to be truncated /// The system message private int ComputeTruncationIndex(ChatHistory chatHistory, ChatMessageContent? systemMessage) { var truncationIndex = -1; var totalTokenCount = (int)(systemMessage?.Metadata?["TokenCount"] ?? 0); for (int i = chatHistory.Count - 1; i >= 0; i--) { truncationIndex = i; var tokenCount = (int)(chatHistory[i].Metadata?["TokenCount"] ?? 0); if (tokenCount + totalTokenCount > this._maxTokenCount) { break; } totalTokenCount += tokenCount; } // Skip function related content while (truncationIndex i is FunctionCallContent || i is FunctionResultContent)) { truncationIndex++; } else { break; } } return truncationIndex; } #endregion }
Note how in the above, function calling methods are excluded from truncation.
Here we see how this could be integrated with a ChatCompletions
service such as OpenAI:
public sealed class ChatCompletionServiceWithReducer(IChatCompletionService service, IChatHistoryReducer reducer) : IChatCompletionService { private static IReadOnlyDictionary EmptyAttributes { get; } = new Dictionary(); public IReadOnlyDictionary Attributes => EmptyAttributes; /// public async Task<IReadOnlyList> GetChatMessageContentsAsync( ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, CancellationToken cancellationToken = default) { var reducedMessages = await reducer.ReduceAsync(chatHistory, cancellationToken).ConfigureAwait(false); var reducedHistory = reducedMessages is null ? chatHistory : new ChatHistory(reducedMessages); return await service.GetChatMessageContentsAsync(reducedHistory, executionSettings, kernel, cancellationToken).ConfigureAwait(false); } /// public async IAsyncEnumerable GetStreamingChatMessageContentsAsync( ChatHistory chatHistory, PromptExecutionSettings? executionSettings = null, Kernel? kernel = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { var reducedMessages = await reducer.ReduceAsync(chatHistory, cancellationToken).ConfigureAwait(false); var history = reducedMessages is null ? chatHistory : new ChatHistory(reducedMessages); var messages = service.GetStreamingChatMessageContentsAsync(history, executionSettings, kernel, cancellationToken); await foreach (var message in messages) { yield return message; } } }
At the time of writing, the Semantic Kernel blog post samples are not officially supported by the Semantic Kernel API.
My understanding is the SK Team will be collaborating with the .NET Team to create a set of abstractions and get them added to the Microsoft.Extensions.AI namespace.
You can find the Semantic Kernel blog post here. The related GitHub repo is available here.
~
Don’t Over Optimise
When trying to optimise it’s important not to over-optimise.
Messages that you don’t want to remove from that chat history include:
- system prompts -these define how the agent should behave
- function-calling -these provide essential information related to actions the agent has taken, or must consider
- key topics and contextual – that define the user’s goals or context
- high priority – critical to the conversation’s success. Use labels to identify these messages
- clarifications and confirmations -to ensure smooth, coherent dialogue
- summarised inputs -to condense and replace lengthy history where possible
- policy and/or security -to maintain compliance and transparency
- feedback from the human – for better adaptation and learning
Preserving these will ensure your agent is useful and behaves how you expect. To help you identify some of the above, you can consider injecting calls to additional AI Service such as Azure AI Language / Text Analytics.
Use the capabilities found in these endpoints to perform Named Entity Recognition (NER), or Sentiment Analysis to detect and label a message.
Use Document Summarisation to summarise content in messages, thereby letting you further optimise and enrich data being sent between the Semantic Kernel and language model integration.
~
Further Thoughts
You might choose to go deep and remove redundant tokens within a stream of text.
Redundant tokens are also known as “stop words”.
Some of my earlier blog posts discuss NLP (natural language processing) in detail:
Stop words in computing terms, are words which are filtered out prior to or after processing of natural language data and text.
Unfortunately, there is not one definitive list of stop words which can be used and any group of words can be chosen as stop words in terms of sentiment analysis. They are sometimes known as “noise words”.
Search engines for example do not record common stop words in order to save disk space or to speed up searches. (Sullivan) – i.e. search engines “stop” looking at them.
A common list of stop words could contain something like the following:
a,able,about,across,after,all,almost,also,am,among,an,and,any,are,as,at,be,because,been,but,by,can,cannot,could,dear,did,do,does,either,else,ever,every,for,from,get,got,had,has,have,he,her,hers,him,his,how,however,i,if,in,into,is,it,its,just,least,let,like,likely,may,me,might,most,must,my,neither,no,nor,not,of,off,often,on,only,or,other,our,own,rather,said,say,says,she,should,since,so,some,than,that,the,their,them,then,there,these,they,this,tis,to,too,twas,us,wants,was,we,were,what,when,where,which,while,who,whom,why,will,with,would,yet,you,your
Find the entire blog post from 2016 where I talk about the difficulties of sentiment analysis and solutions here.
~
Further Reading and Resources
You can learn more about managing chat history with Semantic Kernel and language model integration here:
- Managing Chat History – https://devblogs.microsoft.com/semantic-kernel/managing-chat-history-for-large-language-models-llms/
- Github Repo – https://github.com/microsoft/semantic-kernel/tree/6b20b9821b90d03525754e0170f2acfd4acced76/dotnet/samples/Concepts/ChatCompletion/ChatHistoryReducers
- Text Analytics – https://jamiemaguire.net/index.php/category/text-analytics/
Enjoy what you’ve read, have questions about this content, or would like to see another topic? Drop me a note below.
You can schedule a call using my Calendly link to discuss consulting and development services.
~
.fca_eoi_form{ margin: auto; } .fca_eoi_form p { width: auto; } #fca_eoi_form_560 input{ max-width: 9999px; }#fca_eoi_form_560 .fca_eoi_layout_name_field_wrapper {display: none !important;}#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_email_field_wrapper {float:none;margin-left:auto;margin-right:auto;}#fca_eoi_form_560 .fca_eoi_form_input_element::-webkit-input-placeholder {opacity:0.6;color:#000000;}#fca_eoi_form_560 .fca_eoi_form_input_element::-moz-placeholder {opacity:0.6;color:#000000;}#fca_eoi_form_560 .fca_eoi_form_input_element:-ms-input-placeholder {opacity:0.6;color:#000000;}#fca_eoi_form_560 .fca_eoi_form_input_element:-moz-placeholder {opacity:0.6;color:#000000;}#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_submit_button_wrapper:hover, #fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_submit_button_wrapper input:hover {background-color:#1e73be !important;}#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox {width:100%;}#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_name_field_wrapper {width:100%;}#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_email_field_wrapper {width:100%;}#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_submit_button_wrapper input {width:100%;}div.fca_eoi_form_text_element,input.fca_eoi_form_input_element,input.fca_eoi_form_button_element{display:block;margin:0;padding:0;line-height:normal;font-size:14px;letter-spacing:normal;word-spacing:normal;text-indent:0;text-shadow:none;text-decoration:none;text-transform:none;white-space:normal;width:inherit;height:inherit;background-image:none;border:none;border-radius:0;box-shadow:none;box-sizing:border-box;transition:none;outline:none;-webkit-transition:none;-webkit-appearance:none;-moz-appearance:none;color:#000;font-family:”Open Sans”, sans-serif;font-weight:normal;transition:background 350ms linear;}div.fca_eoi_form_text_element{text-align:center;}div.fca_eoi_layout_headline_copy_wrapper{font-weight:bold;}div.fca_eoi_layout_0,form.fca_eoi_layout_0{display:inline-block;}div.fca_eoi_layout_0.fca_eoi_layout_widget,form.fca_eoi_layout_0.fca_eoi_layout_widget{max-width:300px;}div.fca_eoi_layout_0.fca_eoi_layout_postbox,form.fca_eoi_layout_0.fca_eoi_layout_postbox{max-width:600px;}div.fca_eoi_layout_0.fca_eoi_layout_popup,form.fca_eoi_layout_0.fca_eoi_layout_popup{max-width:650px;}div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_field_wrapper,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_field_wrapper{float:none;width:100%;}div.fca_eoi_layout_0 div.fca_eoi_layout_content_wrapper,form.fca_eoi_layout_0 div.fca_eoi_layout_content_wrapper{margin:20px;}div.fca_eoi_layout_0 div.fca_eoi_layout_field_wrapper,form.fca_eoi_layout_0 div.fca_eoi_layout_field_wrapper{border:solid 1px transparent;width:49%;border-radius:3px;margin-bottom:10px;position:relative;}div.fca_eoi_layout_0 div.fca_eoi_layout_name_field_wrapper,form.fca_eoi_layout_0 div.fca_eoi_layout_name_field_wrapper{float:left;box-sizing:border-box;display:inline-block;}div.fca_eoi_layout_0 div.fca_eoi_layout_email_field_wrapper,form.fca_eoi_layout_0 div.fca_eoi_layout_email_field_wrapper{float:right;box-sizing:border-box;display:inline-block;}div.fca_eoi_layout_0 div.fca_eoi_layout_inputs_wrapper_no_name div.fca_eoi_layout_field_wrapper,form.fca_eoi_layout_0 div.fca_eoi_layout_inputs_wrapper_no_name div.fca_eoi_layout_field_wrapper{float:none;width:100%;}div.fca_eoi_layout_0 div.fca_eoi_layout_field_wrapper input,form.fca_eoi_layout_0 div.fca_eoi_layout_field_wrapper input,div.fca_eoi_layout_0 div.fca_eoi_layout_field_wrapper input:focus,form.fca_eoi_layout_0 div.fca_eoi_layout_field_wrapper input:focus{border:none !important;width:100%;height:auto;font-size:16px;line-height:1.2em;padding:7px 0;outline:none;background:none !important;box-shadow:none;}div.fca_eoi_layout_0 div.fca_eoi_layout_submit_button_wrapper,form.fca_eoi_layout_0 div.fca_eoi_layout_submit_button_wrapper{clear:both;transition:background 350ms linear, border-color 350ms linear;margin-left:auto;margin-right:auto;}div.fca_eoi_layout_0 div.fca_eoi_layout_fatcatapps_link_wrapper a,form.fca_eoi_layout_0 div.fca_eoi_layout_fatcatapps_link_wrapper a{display:block;margin:10px 0 0;font-size:12px;}@media (min-width:1px) and (max-width:450px),(min-height:1px) and (max-height:450px){div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a{font-size:13px !important;}}@media (min-width:1px) and (max-width:320px),(min-height:1px) and (max-height:320px){div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_description_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper i.fa:before,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_field_wrapper div.fca_eoi_layout_field_inner input:focus,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_submit_button_wrapper input:focus,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_form_text_element.fca_eoi_layout_privacy_copy_wrapper div,div.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a,form.fca_eoi_layout_0.fca_eoi_layout_popup div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a,div.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a,form.fca_eoi_layout_0.fca_eoi_layout_widget div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a,div.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a,form.fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_content_wrapper div.fca_eoi_layout_fatcatapps_link_wrapper a{font-size:12px !important;}}@media (min-width:1px) and (max-width:450px),(min-height:1px) and (max-height:450px){div.fca_eoi_layout_0 div.fca_eoi_layout_content_wrapper,form.fca_eoi_layout_0 div.fca_eoi_layout_content_wrapper{margin:8px 13px;}div.fca_eoi_layout_0 div.fca_eoi_layout_fatcatapps_link_wrapper a,form.fca_eoi_layout_0 div.fca_eoi_layout_fatcatapps_link_wrapper a{margin:0;}div.fca_eoi_layout_0 div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper,form.fca_eoi_layout_0 div.fca_eoi_form_text_element.fca_eoi_layout_headline_copy_wrapper{margin-bottom:5px;}}@media (min-width:1px) and (max-width:768px){div.fca_eoi_layout_0 div.fca_eoi_layout_field_wrapper,form.fca_eoi_layout_0 div.fca_eoi_layout_field_wrapper{float:none;width:100%;}}div.fca_eoi_layout_0 div.fca_eoi_layout_submit_button_wrapper,form.fca_eoi_layout_0 div.fca_eoi_layout_submit_button_wrapper{text-align:center;width:100%;}div.fca_eoi_layout_0 div.fca_eoi_layout_submit_button_wrapper input,form.fca_eoi_layout_0 div.fca_eoi_layout_submit_button_wrapper input{width:100%;border:0 !important;}#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox { background-color: #ffffff !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox { border-color: #000000 !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_headline_copy_wrapper div { font-size: 25px !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_headline_copy_wrapper div { color: #000000 !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_description_copy_wrapper p, .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_description_copy_wrapper div { font-size: 14px !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_description_copy_wrapper p, .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_description_copy_wrapper div { color: #000000 !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_name_field_wrapper, .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_name_field_wrapper input { font-size: 14px !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_name_field_wrapper, .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_name_field_wrapper input { color: #000000 !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_name_field_wrapper { border-color: #000000 !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_email_field_wrapper, .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_email_field_wrapper input { font-size: 14px !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_email_field_wrapper, .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_email_field_wrapper input { color: #000000 !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_email_field_wrapper { border-color: #000000 !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_submit_button_wrapper input { font-size: 23px !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_submit_button_wrapper input { color: #ffffff !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_submit_button_wrapper input { background-color: #000000 !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_privacy_copy_wrapper div { font-size: 14px !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_privacy_copy_wrapper div { color: #000000 !important; }#fca_eoi_form_560 .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_fatcatapps_link_wrapper a, .fca_eoi_layout_0.fca_eoi_layout_postbox div.fca_eoi_layout_fatcatapps_link_wrapper a:hover { color: #3197e1 !important; }