bunnyquery 1.4.2 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bunnyquery",
3
- "version": "1.4.2",
3
+ "version": "1.4.4",
4
4
  "description": "Embeddable BunnyQuery AI chat widget + its framework-agnostic chat engine",
5
5
  "main": "bunnyquery.js",
6
6
  "exports": {
@@ -138,19 +138,49 @@ export class ChatSession {
138
138
  })
139
139
  .catch(function (err: any) { return { content: getErrorMessage(err), isError: true }; })
140
140
  .then(function (result: any) {
141
- // Append the resolved reply to the shared history cache. This runs
142
- // independently of the view lifecycle, so a reply lands in the cache
143
- // even if the view unmounted mid-request; the view renders it from
144
- // the cache via typewriteLatestReply (and resumePendingRequest on
145
- // remount). The displayed bubble in state.messages is updated by the
146
- // caller's typewriteLatestReply, not here.
147
- var existing = self.aiChatHistoryCache[params.key] || { messages: [], endOfList: false, startKeyHistory: [] };
148
- self.aiChatHistoryCache[params.key] = {
149
- messages: existing.messages.concat([{ role: 'assistant', content: result.content, isError: result.isError }]),
150
- endOfList: existing.endOfList,
151
- startKeyHistory: existing.startKeyHistory,
152
- };
141
+ // Land the resolved reply in the shared history cache. This runs
142
+ // independently of the view lifecycle, so a reply is captured even
143
+ // if the chatbox unmounted mid-request.
153
144
  delete self.pendingAgentRequests[params.key];
145
+ var existing = self.aiChatHistoryCache[params.key] || { messages: [], endOfList: false, startKeyHistory: [] };
146
+ var reply: ChatMessage = { role: 'assistant', content: result.content, isError: result.isError };
147
+
148
+ var onThisVisibleChat = self.host.isViewMounted() && self.getHistoryCacheKey() === params.key;
149
+ if (onThisVisibleChat) {
150
+ // The chatbox is showing THIS chat: its typewriteLatestReply will
151
+ // swap the "Thinking..." bubble in state.messages and re-snapshot
152
+ // the cache. Just append the reply for it to pick up.
153
+ self.aiChatHistoryCache[params.key] = {
154
+ messages: existing.messages.concat([reply]),
155
+ endOfList: existing.endOfList,
156
+ startKeyHistory: existing.startKeyHistory,
157
+ };
158
+ } else {
159
+ // Resolved while this chat is NOT the visible view (the chatbox
160
+ // unmounted, or the user moved to another project). No view
161
+ // typewriter will run, so REPLACE the trailing pending
162
+ // "Thinking..." bubble in the cache with the answer rather than
163
+ // appending a duplicate — otherwise a remount renders a stuck
164
+ // "Thinking..." (whose bubble was never resolved). The next
165
+ // fresh history fetch reconciles it either way.
166
+ var msgs = existing.messages.slice();
167
+ var idx = -1;
168
+ for (var i = msgs.length - 1; i >= 0; i--) {
169
+ var m = msgs[i];
170
+ if (m && m.isPending && m.role === 'assistant' && !m.isBackgroundTask) { idx = i; break; }
171
+ }
172
+ if (idx !== -1) {
173
+ reply._serverItemId = msgs[idx]._serverItemId;
174
+ msgs[idx] = reply;
175
+ } else {
176
+ msgs.push(reply);
177
+ }
178
+ self.aiChatHistoryCache[params.key] = {
179
+ messages: msgs,
180
+ endOfList: existing.endOfList,
181
+ startKeyHistory: existing.startKeyHistory,
182
+ };
183
+ }
154
184
  return result;
155
185
  });
156
186
  this.pendingAgentRequests[params.key] = run;
@@ -238,14 +268,23 @@ export class ChatSession {
238
268
  platform: aiPlatform, model: aiModel, systemPrompt: systemPrompt, serviceId: id.serviceId,
239
269
  history: historyForLlm,
240
270
  });
241
- var requestToken = this.state.gateRefreshToken;
242
271
  var run = this.dispatchAgentRequest({
243
272
  key: key, serviceId: id.serviceId, owner: id.owner, aiPlatform: aiPlatform, aiModel: aiModel,
244
273
  systemPrompt: systemPrompt, text: composed, boundedMessages: bounded.messages, userId: chatQueue,
245
274
  extractContent: extractContent,
246
275
  });
276
+ // Render the reply into the "Thinking..." bubble whenever the chatbox is
277
+ // CURRENTLY showing this chat — even after an unmount/remount. The old
278
+ // guard bailed on `requestToken !== gateRefreshToken`, but EVERY remount
279
+ // bumps gateRefreshToken (refreshGate), so a request that finished after
280
+ // the user navigated away and back left a stuck "Thinking..." (no view
281
+ // typewriter ever ran, and resumePendingRequest bails when a pending
282
+ // bubble is already present). Gate on "is this the visible chat" instead.
283
+ // When it ISN'T (unmounted / another project), dispatchAgentRequest has
284
+ // already replaced the pending bubble with the answer IN THE CACHE, so a
285
+ // later loadChatHistory renders it.
247
286
  Promise.resolve(run).catch(function () { }).then(function () {
248
- if (requestToken !== self.state.gateRefreshToken || self.getHistoryCacheKey() !== key) return;
287
+ if (!(self.host.isViewMounted() && self.getHistoryCacheKey() === key)) return;
249
288
  self.state.sending = false;
250
289
  return Promise.resolve(self.typewriteLatestReply(key)).then(function () { self.host.scrollToBottom(true); });
251
290
  });
@@ -789,7 +828,11 @@ export class ChatSession {
789
828
  if (item.status !== 'running' && item.status !== 'pending') return;
790
829
  if (!item.poll || !item.id) return;
791
830
  if (self.historyItemPolls.has(item.id)) return;
792
- if (item.status === 'running' && self.pendingAgentRequests[self.getHistoryCacheKey()]) return;
831
+ // running OR pending: a live dispatchAgentRequest already polls this
832
+ // item; attaching a second (history) poll would double the interval
833
+ // fetch on a remount (skapi item.poll() loops survive unmount —
834
+ // they're uncancellable, so the dispatch poll is still running).
835
+ if ((item.status === 'running' || item.status === 'pending') && self.pendingAgentRequests[self.getHistoryCacheKey()]) return;
793
836
  self.historyItemPolls.set(item.id, true);
794
837
  var capturedId = item.id;
795
838
  var pp = item.poll({