Arm keepalive for regenerated responses
| @@ -60,9 +60,8 @@ let retryTimer = null; | |||
| 60 | let preparingJob = false; | 60 | let preparingJob = false; |
| 61 | let lifecycleVersion = 0; | 61 | let lifecycleVersion = 0; |
| 62 | // Whether keepalive is "armed" for the CURRENT chat. It stays dormant until the user sends a new | 62 | // Whether keepalive is "armed" for the CURRENT chat. It stays dormant until the user sends a new |
| 63 | // message in the open chat — on a freshly loaded or switched-to chat (even with history already | 63 | // message or starts another foreground generation in the open chat. Merely loading a chat does not |
| 64 | // present) we have no way to know whether its prompt is still cached server-side, so pinging would | 64 | // prove that its prompt is cached server-side. Reset on page reload and whenever the chat changes. |
| 65 | // be pointless. Reset on page reload and whenever the chat changes. | ||
| 66 | let armed = false; | 65 | let armed = false; |
| 67 | // Per-profile "time since last message", keyed by connection profile id (or NONE_KEY). | 66 | // Per-profile "time since last message", keyed by connection profile id (or NONE_KEY). |
| 68 | // In-memory only: on reload every profile is treated as freshly active. | 67 | // In-memory only: on reload every profile is treated as freshly active. |
| @@ -152,10 +151,7 @@ function markActivity() { | |||
| 152 | } | 151 | } |
| 153 | 152 | ||
| 154 | /** | 153 | /** |
| 155 | * The user sent a new message in the current chat — the ONLY thing that arms keepalive. | 154 | * A new user message arms keepalive before its foreground generation begins. |
| 156 | * Background/quiet generations, swipes, regenerations, and loading chat history deliberately do | ||
| 157 | * NOT arm it: none of those prove the user is actively continuing THIS chat from a known-cached | ||
| 158 | * prompt (GENERATION_STARTED in particular fires for every quiet/background generation too). | ||
| 159 | */ | 155 | */ |
| 160 | function onMessageSent() { | 156 | function onMessageSent() { |
| 161 | armed = true; | 157 | armed = true; |
| @@ -164,7 +160,7 @@ function onMessageSent() { | |||
| 164 | 160 | ||
| 165 | /** | 161 | /** |
| 166 | * Opening or switching chats disarms keepalive: a freshly loaded chat is not proof its prompt is | 162 | * Opening or switching chats disarms keepalive: a freshly loaded chat is not proof its prompt is |
| 167 | * still cached server-side, so we wait for a new sent message in that chat before running again. | 163 | * still cached server-side, so we wait for a new message or foreground generation before running. |
| 168 | */ | 164 | */ |
| 169 | function onChatChanged() { | 165 | function onChatChanged() { |
| 170 | armed = false; | 166 | armed = false; |
| @@ -454,10 +450,16 @@ function setupListeners() { | |||
| 454 | }); | 450 | }); |
| 455 | } | 451 | } |
| 456 | 452 | ||
| 457 | function onGenerationStarted(_type, _options, dryRun) { | 453 | function onGenerationStarted(type, _options, dryRun) { |
| 458 | if (!dryRun) { | 454 | if (dryRun) { |
| 459 | markActivity(); | 455 | return; |
| 460 | } | 456 | } |
| 457 | // Regenerates, swipes, and continues send the current prompt to the provider without emitting | ||
| 458 | // MESSAGE_SENT. They are just as valid proof of a warm prompt as a newly typed message. | ||
| 459 | if (type !== 'quiet') { | ||
| 460 | armed = true; | ||
| 461 | } | ||
| 462 | markActivity(); | ||
| 461 | } | 463 | } |
| 462 | 464 | ||
| 463 | function onGenerationEnded() { | 465 | function onGenerationEnded() { |
| @@ -493,7 +495,8 @@ async function init() { | |||
| 493 | setupListeners(); | 495 | setupListeners(); |
| 494 | setupHeartbeatLoop(); | 496 | setupHeartbeatLoop(); |
| 495 | 497 | ||
| 496 | // Only the user sending a new message arms keepalive (for the current chat). | 498 | // A new user message arms keepalive before generation starts. Foreground generations that do |
| 499 | // not send a new message (regenerate/swipe/continue) are armed by onGenerationStarted instead. | ||
| 497 | eventSource.on(event_types.MESSAGE_SENT, onMessageSent); | 500 | eventSource.on(event_types.MESSAGE_SENT, onMessageSent); |
| 498 | 501 | ||
| 499 | // Activity resets the backend deadline but never arms keepalive on its own. A completed | 502 | // Activity resets the backend deadline but never arms keepalive on its own. A completed |
| @@ -6,7 +6,7 @@ | |||
| 6 | "js": "index.js", | 6 | "js": "index.js", |
| 7 | "css": "", | 7 | "css": "", |
| 8 | "author": "SillyTavern", | 8 | "author": "SillyTavern", |
| 9 | "version": "1.1.0", | 9 | "version": "1.1.1", |
| 10 | "homePage": "https://github.com/SillyTavern/SillyTavern", | 10 | "homePage": "https://github.com/SillyTavern/SillyTavern", |
| 11 | "hooks": { | 11 | "hooks": { |
| 12 | "activate": "init" | 12 | "activate": "init" |
| @@ -16,7 +16,7 @@ | |||
| 16 | <label for="keepalive_message" data-i18n="ext_keepalive_message">Keepalive message</label> | 16 | <label for="keepalive_message" data-i18n="ext_keepalive_message">Keepalive message</label> |
| 17 | <input id="keepalive_message" class="text_pole" type="text" /> | 17 | <input id="keepalive_message" class="text_pole" type="text" /> |
| 18 | 18 | ||
| 19 | <small data-i18n="ext_keepalive_help">After this many seconds without activity on the active connection profile, the current chat plus this message (sent as a hidden user message) is submitted to that profile to keep its server-side prompt cache warm. The completion is capped to a single token and is never saved to the chat. The server owns the keepalive timer, while this tab renews its lease every 20 seconds; if the tab sleeps or closes, the server continues on schedule for up to five minutes after the last heartbeat. Only the profile you're currently using is pinged. Keepalive stays off until you send a new message in the current chat (opening, switching to, or reloading a chat isn't proof its prompt is still cached).</small> | 19 | <small data-i18n="ext_keepalive_help">After this many seconds without activity on the active connection profile, the current chat plus this message (sent as a hidden user message) is submitted to that profile to keep its server-side prompt cache warm. The completion is capped to a single token and is never saved to the chat. The server owns the keepalive timer, while this tab renews its lease every 20 seconds; if the tab sleeps or closes, the server continues on schedule for up to five minutes after the last heartbeat. Only the profile you're currently using is pinged. Keepalive stays off until you send a message or start a foreground generation (including regenerate, swipe, or continue); merely opening, switching to, or reloading a chat is not proof its prompt is cached.</small> |
| 20 | 20 | ||
| 21 | <hr> | 21 | <hr> |
| 22 | 22 | ||