Add prompt suppression and FIFO
This commit is contained in:
		
							parent
							
								
									b396bb818d
								
							
						
					
					
						commit
						9165480dfb
					
				| 
						 | 
					@ -529,7 +529,11 @@ aside.menu.main-menu .menu-expanse {
 | 
				
			||||||
.chat-message.summarized {
 | 
					.chat-message.summarized {
 | 
				
			||||||
  opacity: 0.6;
 | 
					  opacity: 0.6;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					.chat-message.suppress .message-body {
 | 
				
			||||||
 | 
					  opacity: 0.4;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
.tool-drawer, .tool-drawer-mask {
 | 
					.tool-drawer, .tool-drawer-mask {
 | 
				
			||||||
 | 
					  z-index: 1;
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
  visibility: hidden;
 | 
					  visibility: hidden;
 | 
				
			||||||
  width: 0%;
 | 
					  width: 0%;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -154,8 +154,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let response: Response
 | 
					    let response: Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const messageFilter = (m) => !m.suppress && m.role !== 'error' && m.content && !m.summarized
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Submit only the role and content of the messages, provide the previous messages as well for context
 | 
					    // Submit only the role and content of the messages, provide the previous messages as well for context
 | 
				
			||||||
    const filtered = messages.filter((message) => message.role !== 'error' && message.content && !message.summarized)
 | 
					    let filtered = messages.filter(messageFilter)
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
    // Get an estimate of the total prompt size we're sending
 | 
					    // Get an estimate of the total prompt size we're sending
 | 
				
			||||||
    const promptTokenCount:number = countPromptTokens(filtered, model)
 | 
					    const promptTokenCount:number = countPromptTokens(filtered, model)
 | 
				
			||||||
| 
						 | 
					@ -176,7 +178,8 @@
 | 
				
			||||||
      const systemPad = (filtered[0] || {} as Message).role === 'system' ? 1 : 0
 | 
					      const systemPad = (filtered[0] || {} as Message).role === 'system' ? 1 : 0
 | 
				
			||||||
      const mlen = filtered.length - systemPad // always keep system prompt
 | 
					      const mlen = filtered.length - systemPad // always keep system prompt
 | 
				
			||||||
      let diff = mlen - (pinTop + pinBottom)
 | 
					      let diff = mlen - (pinTop + pinBottom)
 | 
				
			||||||
      while (diff <= 3 && (pinTop > 0 || pinBottom > 1)) {
 | 
					      const useRollMode = !prepareSummaryPrompt(chatId, 0)
 | 
				
			||||||
 | 
					      while (!useRollMode && diff <= 3 && (pinTop > 0 || pinBottom > 1)) {
 | 
				
			||||||
        // Not enough prompts exposed to summarize
 | 
					        // Not enough prompts exposed to summarize
 | 
				
			||||||
        // try to open up pinTop and pinBottom to see if we can get more to summarize
 | 
					        // try to open up pinTop and pinBottom to see if we can get more to summarize
 | 
				
			||||||
        if (pinTop === 1 && pinBottom > 1) {
 | 
					        if (pinTop === 1 && pinBottom > 1) {
 | 
				
			||||||
| 
						 | 
					@ -188,7 +191,7 @@
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        diff = mlen - (pinTop + pinBottom)
 | 
					        diff = mlen - (pinTop + pinBottom)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (diff > 0) {
 | 
					      if (!useRollMode && diff > 0) {
 | 
				
			||||||
        // We've found at least one prompt we can try to summarize
 | 
					        // We've found at least one prompt we can try to summarize
 | 
				
			||||||
        // Reduce to prompts we'll send in for summary
 | 
					        // Reduce to prompts we'll send in for summary
 | 
				
			||||||
        // (we may need to update this to not include the pin-top, but the context it provides seems to help in the accuracy of the summary)
 | 
					        // (we may need to update this to not include the pin-top, but the context it provides seems to help in the accuracy of the summary)
 | 
				
			||||||
| 
						 | 
					@ -197,6 +200,7 @@
 | 
				
			||||||
        let sourceTokenCount = countPromptTokens(summarize, model)
 | 
					        let sourceTokenCount = countPromptTokens(summarize, model)
 | 
				
			||||||
        // build summary prompt message
 | 
					        // build summary prompt message
 | 
				
			||||||
        let summaryPrompt = prepareSummaryPrompt(chatId, sourceTokenCount)
 | 
					        let summaryPrompt = prepareSummaryPrompt(chatId, sourceTokenCount)
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        const summaryMessage = {
 | 
					        const summaryMessage = {
 | 
				
			||||||
          role: 'user',
 | 
					          role: 'user',
 | 
				
			||||||
          content: summaryPrompt
 | 
					          content: summaryPrompt
 | 
				
			||||||
| 
						 | 
					@ -279,8 +283,23 @@
 | 
				
			||||||
        } else if (sourceTokenCount <= 20) {
 | 
					        } else if (sourceTokenCount <= 20) {
 | 
				
			||||||
          addMessage(chatId, { role: 'error', content: 'Unable to summarize. Not enough words in past content to summarize.', uuid: uuidv4() })
 | 
					          addMessage(chatId, { role: 'error', content: 'Unable to summarize. Not enough words in past content to summarize.', uuid: uuidv4() })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else {
 | 
					      } else if (!useRollMode && diff < 1) {
 | 
				
			||||||
        addMessage(chatId, { role: 'error', content: 'Unable to summarize. Not enough messages in past content to summarize.', uuid: uuidv4() })
 | 
					        addMessage(chatId, { role: 'error', content: 'Unable to summarize. Not enough messages in past content to summarize.', uuid: uuidv4() })
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        // roll-off mode
 | 
				
			||||||
 | 
					        const top = filtered.slice(0,pinTop+systemPad)
 | 
				
			||||||
 | 
					        let rollaway = filtered.slice(pinTop+systemPad)
 | 
				
			||||||
 | 
					        let promptTokenCount = countPromptTokens(top.concat(rollaway), model)
 | 
				
			||||||
 | 
					        // suppress messages we're rolling off
 | 
				
			||||||
 | 
					        while (rollaway.length > (((promptTokenCount + (chatSettings.max_tokens||1)) > maxTokens) ? pinBottom||1 : 1) 
 | 
				
			||||||
 | 
					            && promptTokenCount >= chatSettings.summaryThreshold) {
 | 
				
			||||||
 | 
					          const rollOff = rollaway.shift()
 | 
				
			||||||
 | 
					          if (rollOff) rollOff.suppress = true
 | 
				
			||||||
 | 
					          promptTokenCount = countPromptTokens(top.concat(rollaway), model)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        saveChatStore()
 | 
				
			||||||
 | 
					        // get a new list now excluding them
 | 
				
			||||||
 | 
					        filtered = messages.filter(messageFilter)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,12 @@
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
  import Code from './Code.svelte'
 | 
					  import Code from './Code.svelte'
 | 
				
			||||||
  import { createEventDispatcher, onMount } from 'svelte'
 | 
					  import { createEventDispatcher, onMount } from 'svelte'
 | 
				
			||||||
  import { deleteMessage, chatsStorage, deleteSummaryMessage, truncateFromMessage, submitExitingPromptsNow } from './Storage.svelte'
 | 
					  import { deleteMessage, chatsStorage, deleteSummaryMessage, truncateFromMessage, submitExitingPromptsNow, saveChatStore } from './Storage.svelte'
 | 
				
			||||||
  import { getPrice } from './Stats.svelte'
 | 
					  import { getPrice } from './Stats.svelte'
 | 
				
			||||||
  import SvelteMarkdown from 'svelte-markdown'
 | 
					  import SvelteMarkdown from 'svelte-markdown'
 | 
				
			||||||
  import type { Message, Model, Chat } from './Types.svelte'
 | 
					  import type { Message, Model, Chat } from './Types.svelte'
 | 
				
			||||||
  import Fa from 'svelte-fa/src/fa.svelte'
 | 
					  import Fa from 'svelte-fa/src/fa.svelte'
 | 
				
			||||||
  import { faTrash, faDiagramPredecessor, faDiagramNext, faCircleCheck, faPaperPlane } from '@fortawesome/free-solid-svg-icons/index'
 | 
					  import { faTrash, faDiagramPredecessor, faDiagramNext, faCircleCheck, faPaperPlane, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons/index'
 | 
				
			||||||
  import { scrollIntoViewWithOffset } from './Util.svelte'
 | 
					  import { scrollIntoViewWithOffset } from './Util.svelte'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let message:Message
 | 
					  export let message:Message
 | 
				
			||||||
| 
						 | 
					@ -155,6 +155,28 @@
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let waitingForSuppressConfirm:any = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const setSuppress = (value:boolean) => {
 | 
				
			||||||
 | 
					    // clearTimeout(waitingForSuppressConfirm); waitingForSuppressConfirm = 0
 | 
				
			||||||
 | 
					    // if (value && !waitingForSuppressConfirm) {
 | 
				
			||||||
 | 
					    //   // wait a second for another click to avoid accidental deletes
 | 
				
			||||||
 | 
					    //   waitingForSuppressConfirm = setTimeout(() => { waitingForSuppressConfirm = 0 }, 1000)
 | 
				
			||||||
 | 
					    //   return
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					    // clearTimeout(waitingForSuppressConfirm)
 | 
				
			||||||
 | 
					    waitingForTruncateConfirm = 0
 | 
				
			||||||
 | 
					    if (message.summarized) {
 | 
				
			||||||
 | 
					      // is in a summary, so we're summarized
 | 
				
			||||||
 | 
					      window.alert('Sorry, you can\'t suppress a summarized message')
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    message.suppress = value
 | 
				
			||||||
 | 
					    saveChatStore()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{#key message.uuid}
 | 
					{#key message.uuid}
 | 
				
			||||||
| 
						 | 
					@ -168,6 +190,7 @@
 | 
				
			||||||
  class:user-message={message.role === 'user' || message.role === 'system'}
 | 
					  class:user-message={message.role === 'user' || message.role === 'system'}
 | 
				
			||||||
  class:assistant-message={message.role === 'error' || message.role === 'assistant'}
 | 
					  class:assistant-message={message.role === 'error' || message.role === 'assistant'}
 | 
				
			||||||
  class:summarized={message.summarized} 
 | 
					  class:summarized={message.summarized} 
 | 
				
			||||||
 | 
					  class:suppress={message.suppress} 
 | 
				
			||||||
  class:editing={editing}
 | 
					  class:editing={editing}
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
  <div class="message-body content">
 | 
					  <div class="message-body content">
 | 
				
			||||||
| 
						 | 
					@ -259,6 +282,24 @@
 | 
				
			||||||
        {/if}
 | 
					        {/if}
 | 
				
			||||||
        </a>
 | 
					        </a>
 | 
				
			||||||
      {/if}
 | 
					      {/if}
 | 
				
			||||||
 | 
					      {#if !message.summarized && message.role !== 'system'}
 | 
				
			||||||
 | 
					        <a
 | 
				
			||||||
 | 
					          href={'#'}
 | 
				
			||||||
 | 
					          title={(message.suppress ? 'Uns' : 'S') + 'uppress message from submission'}
 | 
				
			||||||
 | 
					          class=" msg-delete-button button is-small is-info"
 | 
				
			||||||
 | 
					          on:click|preventDefault={() => {
 | 
				
			||||||
 | 
					            setSuppress(!message.suppress)
 | 
				
			||||||
 | 
					          }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					        {#if waitingForSuppressConfirm}
 | 
				
			||||||
 | 
					        <span class="icon"><Fa icon={faCircleCheck} /></span>
 | 
				
			||||||
 | 
					        {:else if message.suppress}
 | 
				
			||||||
 | 
					        <span class="icon"><Fa icon={faEye} /></span>
 | 
				
			||||||
 | 
					        {:else}
 | 
				
			||||||
 | 
					        <span class="icon"><Fa icon={faEyeSlash} /></span>
 | 
				
			||||||
 | 
					        {/if}
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					      {/if}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{#each messages as message, i}
 | 
					{#each messages as message, i}
 | 
				
			||||||
  {#if !(message.summarized && $globalStorage.hideSummarized) && !(i === 0 && message.role === 'system' && !chatSettings.useSystemPrompt)}
 | 
					  {#if !((message.summarized) && $globalStorage.hideSummarized) && !(i === 0 && message.role === 'system' && !chatSettings.useSystemPrompt)}
 | 
				
			||||||
  <EditMessage bind:message={message} chatId={chatId} />
 | 
					  <EditMessage bind:message={message} chatId={chatId} />
 | 
				
			||||||
  {/if}
 | 
					  {/if}
 | 
				
			||||||
{/each}
 | 
					{/each}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,7 +100,10 @@ const profileSetting: ChatSetting & SettingSelect = {
 | 
				
			||||||
      afterChange: (chatId, setting) => {
 | 
					      afterChange: (chatId, setting) => {
 | 
				
			||||||
        applyProfile(chatId, '', !getChat(chatId).sessionStarted)
 | 
					        applyProfile(chatId, '', !getChat(chatId).sessionStarted)
 | 
				
			||||||
        return true // Signal we should refresh the setting modal
 | 
					        return true // Signal we should refresh the setting modal
 | 
				
			||||||
      }
 | 
					      },
 | 
				
			||||||
 | 
					      setDefault: (chatId, setting, value) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Settings that will not be part of the API request
 | 
					// Settings that will not be part of the API request
 | 
				
			||||||
| 
						 | 
					@ -159,16 +162,16 @@ const nonRequestSettings: ChatSetting[] = [
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        key: 'useSummarization',
 | 
					        key: 'useSummarization',
 | 
				
			||||||
        name: 'Enable Auto Summarize',
 | 
					        name: 'Enable Continuous Chat',
 | 
				
			||||||
        header: 'Continuous Chat - Summarization',
 | 
					        header: 'Continuous Chat - (Summarize or FIFO)',
 | 
				
			||||||
        headerClass: 'is-info',
 | 
					        headerClass: 'is-info',
 | 
				
			||||||
        title: 'When out of token space, summarize past tokens and keep going.',
 | 
					        title: 'When out of token space, summarize or remove past prompts and keep going.',
 | 
				
			||||||
        type: 'boolean'
 | 
					        type: 'boolean'
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        key: 'summaryThreshold',
 | 
					        key: 'summaryThreshold',
 | 
				
			||||||
        name: 'Summary Threshold',
 | 
					        name: 'Token Threshold',
 | 
				
			||||||
        title: 'When prompt history breaks this threshold, past prompts will be summarized to create space. 0 to disable.',
 | 
					        title: 'When prompt history breaks this threshold, past prompts will be summarized or rolled off to create space.',
 | 
				
			||||||
        min: 0,
 | 
					        min: 0,
 | 
				
			||||||
        max: 32000,
 | 
					        max: 32000,
 | 
				
			||||||
        step: 1,
 | 
					        step: 1,
 | 
				
			||||||
| 
						 | 
					@ -178,7 +181,7 @@ const nonRequestSettings: ChatSetting[] = [
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        key: 'summarySize',
 | 
					        key: 'summarySize',
 | 
				
			||||||
        name: 'Max Summary Size',
 | 
					        name: 'Max Summary Size',
 | 
				
			||||||
        title: 'Maximum number of tokens to use for summarization response.',
 | 
					        title: 'Maximum number of tokens allowed for summary response.',
 | 
				
			||||||
        min: 128,
 | 
					        min: 128,
 | 
				
			||||||
        max: 2048,
 | 
					        max: 2048,
 | 
				
			||||||
        step: 1,
 | 
					        step: 1,
 | 
				
			||||||
| 
						 | 
					@ -187,7 +190,7 @@ const nonRequestSettings: ChatSetting[] = [
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        key: 'pinTop',
 | 
					        key: 'pinTop',
 | 
				
			||||||
        name: 'Keep First Prompts During Summary',
 | 
					        name: 'Keep First Prompts',
 | 
				
			||||||
        title: 'When we run out of space and need to summarize prompts, the top number of prompts will not be removed after summarization.',
 | 
					        title: 'When we run out of space and need to summarize prompts, the top number of prompts will not be removed after summarization.',
 | 
				
			||||||
        min: 0,
 | 
					        min: 0,
 | 
				
			||||||
        max: 4,
 | 
					        max: 4,
 | 
				
			||||||
| 
						 | 
					@ -198,7 +201,7 @@ const nonRequestSettings: ChatSetting[] = [
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        key: 'pinBottom',
 | 
					        key: 'pinBottom',
 | 
				
			||||||
        name: 'Exclude Bottom Prompts From Summary',
 | 
					        name: 'Exclude Bottom Prompts',
 | 
				
			||||||
        title: 'When we run out of space and need to summarize prompts, do not summarize the the last number prompts you set here.',
 | 
					        title: 'When we run out of space and need to summarize prompts, do not summarize the the last number prompts you set here.',
 | 
				
			||||||
        min: 0,
 | 
					        min: 0,
 | 
				
			||||||
        max: 20, // Will be auto adjusted down if needs more
 | 
					        max: 20, // Will be auto adjusted down if needs more
 | 
				
			||||||
| 
						 | 
					@ -209,7 +212,7 @@ const nonRequestSettings: ChatSetting[] = [
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        key: 'summaryPrompt',
 | 
					        key: 'summaryPrompt',
 | 
				
			||||||
        name: 'Summary Generation Prompt',
 | 
					        name: 'Summary Generation Prompt (Empty will use FIFO instead.)',
 | 
				
			||||||
        title: 'A prompt used to summarize past prompts.',
 | 
					        title: 'A prompt used to summarize past prompts.',
 | 
				
			||||||
        placeholder: 'Enter a prompt that will be used to summarize past prompts here.',
 | 
					        placeholder: 'Enter a prompt that will be used to summarize past prompts here.',
 | 
				
			||||||
        type: 'textarea',
 | 
					        type: 'textarea',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@
 | 
				
			||||||
    removed?: boolean;
 | 
					    removed?: boolean;
 | 
				
			||||||
    summarized?: string[];
 | 
					    summarized?: string[];
 | 
				
			||||||
    summary?: string[];
 | 
					    summary?: string[];
 | 
				
			||||||
 | 
					    suppress?: boolean;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export type Request = {
 | 
					  export type Request = {
 | 
				
			||||||
| 
						 | 
					@ -41,7 +42,6 @@
 | 
				
			||||||
    frequency_penalty?: number;
 | 
					    frequency_penalty?: number;
 | 
				
			||||||
    logit_bias?: Record<string, any> | null;
 | 
					    logit_bias?: Record<string, any> | null;
 | 
				
			||||||
    user?: string;
 | 
					    user?: string;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export type ChatSettings = {
 | 
					  export type ChatSettings = {
 | 
				
			||||||
| 
						 | 
					@ -154,6 +154,7 @@ type SettingBoolean = {
 | 
				
			||||||
    placeholder?: string;
 | 
					    placeholder?: string;
 | 
				
			||||||
    hide?: (chatId:number) => boolean;
 | 
					    hide?: (chatId:number) => boolean;
 | 
				
			||||||
    apiTransform?: (chatId:number, setting:ChatSetting, value:any) => any;
 | 
					    apiTransform?: (chatId:number, setting:ChatSetting, value:any) => any;
 | 
				
			||||||
 | 
					    setDefault?: (chatId:number, setting:ChatSetting, value:any) => any;
 | 
				
			||||||
    beforeChange?: (chatId:number, setting:ChatSetting, value:any) => boolean;
 | 
					    beforeChange?: (chatId:number, setting:ChatSetting, value:any) => boolean;
 | 
				
			||||||
    afterChange?: (chatId:number, setting:ChatSetting, value:any) => boolean;
 | 
					    afterChange?: (chatId:number, setting:ChatSetting, value:any) => boolean;
 | 
				
			||||||
  } & (SettingNumber | SettingSelect | SettingBoolean | SettingText | SettingTextArea | SettingOther);
 | 
					  } & (SettingNumber | SettingSelect | SettingBoolean | SettingText | SettingTextArea | SettingOther);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue