bunnyquery 1.10.7 → 1.10.10
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/bunnyquery.js +48 -6
- package/dist/engine.cjs +47 -5
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +19 -1
- package/dist/engine.d.ts +19 -1
- package/dist/engine.mjs +47 -5
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/history.ts +7 -0
- package/src/engine/requests.ts +5 -1
- package/src/engine/session.ts +80 -4
package/package.json
CHANGED
package/src/engine/history.ts
CHANGED
|
@@ -858,6 +858,13 @@ export function mapHistoryListToMessages(list: any[], platform: 'claude' | 'open
|
|
|
858
858
|
if (item._isBgTask) em.isBackgroundTask = true;
|
|
859
859
|
if (serverItemId !== undefined) em._serverItemId = serverItemId;
|
|
860
860
|
if (replyTs !== undefined) em._ts = replyTs;
|
|
861
|
+
// A pass that FAILED still ran, and how long it ran before failing is worth
|
|
862
|
+
// as much as a successful pass's duration -- often more, since that is where
|
|
863
|
+
// a timeout shows itself. `att` is stamped before the upstream call fires,
|
|
864
|
+
// so a failed row carries it exactly as a resolved one does. (Same stamp as
|
|
865
|
+
// the success branch below; the stream-pending branch deliberately has none,
|
|
866
|
+
// having no end time yet.)
|
|
867
|
+
if (indexFile && isFinite(executedTs) && executedTs > 0) em._tsStart = executedTs;
|
|
861
868
|
mapped.push(em);
|
|
862
869
|
} else if (isStreamPending) {
|
|
863
870
|
// The bubble stands for the turn so the merge has something to key on and
|
package/src/engine/requests.ts
CHANGED
|
@@ -1452,7 +1452,11 @@ export type BgTaskEntry = {
|
|
|
1452
1452
|
mime?: string;
|
|
1453
1453
|
size?: number;
|
|
1454
1454
|
status: 'running' | 'pending';
|
|
1455
|
-
|
|
1455
|
+
// `onResponse` receives the settled value plus a `meta` of facts about the
|
|
1456
|
+
// REQUEST rather than the response: `executed` is when the worker began
|
|
1457
|
+
// running it, which rides on a running poll tick's status envelope and is
|
|
1458
|
+
// therefore free to a caller already polling.
|
|
1459
|
+
poll: ((opts: { latency: number; onResponse?: (res: any, meta?: { executed?: number }) => void }) => Promise<any>) | undefined;
|
|
1456
1460
|
/** How many CONTINUE passes have already run for this file (resume-across-passes). */
|
|
1457
1461
|
resumePass?: number;
|
|
1458
1462
|
/** The STAGED chat turn these files were attached to (ChatSession.stageOutgoingMessage).
|
package/src/engine/session.ts
CHANGED
|
@@ -4025,7 +4025,52 @@ export class ChatSession {
|
|
|
4025
4025
|
}
|
|
4026
4026
|
|
|
4027
4027
|
// --- background-task resolution + drain -------------------------------
|
|
4028
|
-
|
|
4028
|
+
/** Record how long a background indexing pass took, on the bubble that just
|
|
4029
|
+
* settled, so the duration shows immediately instead of waiting for whatever
|
|
4030
|
+
* next refetches history.
|
|
4031
|
+
*
|
|
4032
|
+
* `_tsStart` is otherwise written only by the history mapper, which reads the
|
|
4033
|
+
* row's `executed`; a live settle never sees the row at all (the poll resolves
|
|
4034
|
+
* with the destination's body). This is the same value by the other route.
|
|
4035
|
+
*
|
|
4036
|
+
* `_ts` is stamped too when the branch that built the bubble left it without
|
|
4037
|
+
* one: it is the END of the pass, and the pass ended now. A later history load
|
|
4038
|
+
* replaces both with the server's own numbers.
|
|
4039
|
+
*
|
|
4040
|
+
* Indexing passes only: an ordinary turn has no duration to show, and
|
|
4041
|
+
* `_tsStart`'s presence is what both views read to decide. */
|
|
4042
|
+
private _stampPassDuration(itemId: string, executedAt?: number): void {
|
|
4043
|
+
if (!itemId) return;
|
|
4044
|
+
if (!this._indexRefOfItem(itemId)) return;
|
|
4045
|
+
var hasStart = typeof executedAt === 'number' && executedAt > 0;
|
|
4046
|
+
for (var i = this.state.messages.length - 1; i >= 0; i--) {
|
|
4047
|
+
var m: any = this.state.messages[i];
|
|
4048
|
+
if (!m || m.role !== 'assistant' || m._serverItemId !== itemId) continue;
|
|
4049
|
+
if (m.isPending) continue;
|
|
4050
|
+
// `_ts` is stamped whether or not an execution start arrived. The two
|
|
4051
|
+
// background reply builds in applyHistoryItemResolution are the only ones
|
|
4052
|
+
// in the engine that bypass both enqueueTypewrite and insertAtTarget --
|
|
4053
|
+
// they write a literal and return -- so this is where an indexing reply
|
|
4054
|
+
// gets its timestamp at all. Leaving it inside the duration guard meant a
|
|
4055
|
+
// pass with no `executed` (the poll never saw a running tick) rendered with
|
|
4056
|
+
// NO TIME LINE whatsoever, because both clients gate the whole element on
|
|
4057
|
+
// `_ts`. Losing the duration is the intended degradation; losing the
|
|
4058
|
+
// timestamp with it was not.
|
|
4059
|
+
if (typeof m._ts !== 'number') m._ts = Date.now();
|
|
4060
|
+
if (hasStart) m._tsStart = executedAt;
|
|
4061
|
+
// Both of these, because the stamp lands AFTER applyHistoryItemResolution
|
|
4062
|
+
// has already notified and cached. Without the notify the widget never
|
|
4063
|
+
// repaints (its notify() IS the render, so the duration only appeared on
|
|
4064
|
+
// the next unrelated render); without the re-cache the entry written a
|
|
4065
|
+
// moment ago is the one missing `_tsStart`, so a rebuild from cache -- a
|
|
4066
|
+
// remount, a tab return -- silently dropped the duration again.
|
|
4067
|
+
this.host.notify();
|
|
4068
|
+
this.updateHistoryCache();
|
|
4069
|
+
break;
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
|
|
4073
|
+
handleHistoryItemResolution(itemId: string, response: any, platform: string, executedAt?: number): void {
|
|
4029
4074
|
// Which file this turn was indexing, read BEFORE the resolution rewrites the
|
|
4030
4075
|
// bubbles. Every settling turn funnels through here — the bg drain's own
|
|
4031
4076
|
// poll, the history poll, and agent.vue's forked history poll, which calls
|
|
@@ -4033,6 +4078,17 @@ export class ChatSession {
|
|
|
4033
4078
|
// makes it work in both clients without either of them forking a call site.
|
|
4034
4079
|
var indexRef = this._indexRefOfItem(itemId);
|
|
4035
4080
|
this.applyHistoryItemResolution(itemId, response, platform);
|
|
4081
|
+
// After the settle, never inside it: applyHistoryItemResolution builds the
|
|
4082
|
+
// assistant bubble in four separate branches (answer, empty reply, error,
|
|
4083
|
+
// bg) and stamping in each would be four chances to forget one.
|
|
4084
|
+
//
|
|
4085
|
+
// It lives HERE rather than at the call sites because this method is the one
|
|
4086
|
+
// funnel every settle goes through, and the call sites are the thing that
|
|
4087
|
+
// kept getting missed: agent.vue runs its OWN forked history poll, and that
|
|
4088
|
+
// fork -- not the engine's drain -- is what settles a pass uploaded from the
|
|
4089
|
+
// files page, so a stamp wired only into the drain never ran for the exact
|
|
4090
|
+
// case it was written for. A fourth caller added later inherits this for free.
|
|
4091
|
+
this._stampPassDuration(itemId, executedAt);
|
|
4036
4092
|
this.promoteNextBgQueuedToRunning();
|
|
4037
4093
|
// applyHistoryItemResolution just released this item's poll slot. Under
|
|
4038
4094
|
// MAX_CONCURRENT_BG_POLLS that slot is what the next-oldest unpolled entry
|
|
@@ -4678,13 +4734,25 @@ export class ChatSession {
|
|
|
4678
4734
|
var capturedId = entry.id, capturedPlat = plat;
|
|
4679
4735
|
var capturedEntry = entry;
|
|
4680
4736
|
var wasStopped = false;
|
|
4681
|
-
|
|
4737
|
+
// When the worker BEGAN running this pass. It rides on the poll's status
|
|
4738
|
+
// envelope (a running tick), never on the terminal read, which hands back
|
|
4739
|
+
// the destination's own body. Captured here so a settled pass can show how
|
|
4740
|
+
// long it took WITHOUT a second request: the alternative is waiting for
|
|
4741
|
+
// whatever next refetches history, which for a pass that settles in front
|
|
4742
|
+
// of the user is not until they leave the chat and come back.
|
|
4743
|
+
var executedAt: number | undefined;
|
|
4744
|
+
var bp = entry.poll({
|
|
4745
|
+
latency: POLL_INTERVAL,
|
|
4746
|
+
onResponse: function (_res: any, meta: any) {
|
|
4747
|
+
if (meta && typeof meta.executed === 'number' && meta.executed > 0) executedAt = meta.executed;
|
|
4748
|
+
},
|
|
4749
|
+
});
|
|
4682
4750
|
self._trackPoll(entry.id, 'bg', bp);
|
|
4683
4751
|
bp.then(function (response: any) {
|
|
4684
4752
|
// A stopped poll is not a result: leave the bubble and the queue entry
|
|
4685
4753
|
// exactly as they were so resumePolling can re-attach.
|
|
4686
4754
|
if (isPollStopped(response)) { wasStopped = true; return; }
|
|
4687
|
-
self.handleHistoryItemResolution(capturedId, response, capturedPlat);
|
|
4755
|
+
self.handleHistoryItemResolution(capturedId, response, capturedPlat, executedAt);
|
|
4688
4756
|
self.maybeResumeIndexing(capturedEntry, response, capturedPlat);
|
|
4689
4757
|
}).catch(function (err: any) {
|
|
4690
4758
|
self.historyItemPolls.delete(capturedId);
|
|
@@ -5466,7 +5534,15 @@ export class ChatSession {
|
|
|
5466
5534
|
// items keep the flat cadence: nobody is watching, and they are what the
|
|
5467
5535
|
// MAX_CONCURRENT_BG_POLLS budget exists to protect.
|
|
5468
5536
|
var pollOpts = {
|
|
5469
|
-
|
|
5537
|
+
// `meta.executed` rides on the poll's running ticks, so a pass this
|
|
5538
|
+
// path re-attached to (a reload or a remount while its chain was
|
|
5539
|
+
// still going) shows its duration at settle exactly as one polled
|
|
5540
|
+
// from the drain does. Without it, only passes started in this page
|
|
5541
|
+
// life would be stamped.
|
|
5542
|
+
onResponse: function (response: any, meta: any) {
|
|
5543
|
+
if (isPollStopped(response)) return;
|
|
5544
|
+
self.handleHistoryItemResolution(capturedId, response, platform, meta && meta.executed);
|
|
5545
|
+
},
|
|
5470
5546
|
onError: function (err: any) {
|
|
5471
5547
|
self.historyItemPolls.delete(capturedId);
|
|
5472
5548
|
var isNotExists = err && (err.code === 'NOT_EXISTS' || (err.body && err.body.code === 'NOT_EXISTS'));
|