@adecore/agents 0.27.3 → 0.27.5
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/dist/chat/backend.d.ts +2 -0
- package/dist/chat/chat-session.d.ts +1 -0
- package/dist/chat/chat-session.js +8 -1
- package/dist/chat/claude-backend.js +1 -1
- package/dist/chat/claude-protocol.d.ts +4 -1
- package/dist/chat/claude-protocol.js +34 -5
- package/package.json +3 -3
- package/src/chat/backend.ts +4 -0
- package/src/chat/chat-session.ts +8 -1
- package/src/chat/claude-backend.ts +1 -1
- package/src/chat/claude-protocol.ts +34 -5
package/dist/chat/backend.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface BackendLaunch {
|
|
|
10
10
|
runtimeMode: RuntimeMode;
|
|
11
11
|
resume: string | null;
|
|
12
12
|
generation: number;
|
|
13
|
+
now?(): number;
|
|
13
14
|
instructions: string | null;
|
|
14
15
|
resumeNote: string | null;
|
|
15
16
|
resumeInstructions?: string | null;
|
|
@@ -197,6 +198,7 @@ export type BackendEvent = {
|
|
|
197
198
|
lastUuid?: string;
|
|
198
199
|
};
|
|
199
200
|
limit?: ChatTurnLimit;
|
|
201
|
+
replaceProcess?: boolean;
|
|
200
202
|
} | {
|
|
201
203
|
type: 'failed';
|
|
202
204
|
message: string;
|
|
@@ -43,6 +43,7 @@ export class ChatSession {
|
|
|
43
43
|
options;
|
|
44
44
|
projector;
|
|
45
45
|
backend = null;
|
|
46
|
+
replaceProcess = false;
|
|
46
47
|
starting = null;
|
|
47
48
|
pendingStart = null;
|
|
48
49
|
sendAfterStop = false;
|
|
@@ -1564,7 +1565,8 @@ export class ChatSession {
|
|
|
1564
1565
|
}
|
|
1565
1566
|
requiresReplacement() {
|
|
1566
1567
|
return (this.backend !== null &&
|
|
1567
|
-
(
|
|
1568
|
+
(this.replaceProcess ||
|
|
1569
|
+
JSON.stringify(this.info.selection) !== JSON.stringify(this.launchedSelection) ||
|
|
1568
1570
|
this.info.runtimeMode !== this.launchedRuntimeMode ||
|
|
1569
1571
|
this.info.account !== this.launchedAccount ||
|
|
1570
1572
|
this.info.cwd !== this.launchedCwd ||
|
|
@@ -1626,6 +1628,7 @@ export class ChatSession {
|
|
|
1626
1628
|
runtimeMode: info.runtimeMode,
|
|
1627
1629
|
resume: info.agentSessionId,
|
|
1628
1630
|
generation,
|
|
1631
|
+
now: () => this.options.limitResume?.now() ?? (this.options.clock ?? systemClock).now(),
|
|
1629
1632
|
saveGeneratedImage: this.options.saveGeneratedImage,
|
|
1630
1633
|
instructions: this.options.instructions?.() ?? null,
|
|
1631
1634
|
resumeNote: this.options.resumeNote?.() ?? null,
|
|
@@ -1650,6 +1653,7 @@ export class ChatSession {
|
|
|
1650
1653
|
}
|
|
1651
1654
|
const backend = made.backend;
|
|
1652
1655
|
this.backend = backend;
|
|
1656
|
+
this.replaceProcess = false;
|
|
1653
1657
|
this.emit([this.thread.patchInfo({ running: true, effectiveRuntimeMode: undefined, permissionMode: undefined })]);
|
|
1654
1658
|
let started;
|
|
1655
1659
|
try {
|
|
@@ -1730,6 +1734,9 @@ export class ChatSession {
|
|
|
1730
1734
|
if (event.promptId !== undefined) {
|
|
1731
1735
|
this.staleResults = 0;
|
|
1732
1736
|
}
|
|
1737
|
+
if (event.replaceProcess === true) {
|
|
1738
|
+
this.replaceProcess = true;
|
|
1739
|
+
}
|
|
1733
1740
|
const promptId = event.promptId ?? this.submission?.input.promptId;
|
|
1734
1741
|
if (promptId !== undefined) {
|
|
1735
1742
|
this.acceptPrompt(promptId);
|
|
@@ -32,7 +32,7 @@ export class ClaudeBackend {
|
|
|
32
32
|
this.launch = launch;
|
|
33
33
|
this.host = host;
|
|
34
34
|
this.allowedTools = options.allowedTools ?? [];
|
|
35
|
-
this.protocol = new ClaudeProtocol(launch.goal ?? null);
|
|
35
|
+
this.protocol = new ClaudeProtocol(launch.goal ?? null, launch.now);
|
|
36
36
|
}
|
|
37
37
|
get running() {
|
|
38
38
|
return this.child !== null;
|
|
@@ -3,6 +3,7 @@ import type { ApprovalDecision, BackendEvent } from './backend.ts';
|
|
|
3
3
|
export declare function claudeGoalFromCommand(text: string, current: ChatGoal | null): ChatGoal | null | undefined;
|
|
4
4
|
export declare function claudeGoalCheck(text: string, current: ChatGoal | null): ChatGoal | undefined;
|
|
5
5
|
export declare class ClaudeProtocol {
|
|
6
|
+
private readonly now;
|
|
6
7
|
private promptId;
|
|
7
8
|
private readonly pending;
|
|
8
9
|
private streamMessageId;
|
|
@@ -18,13 +19,14 @@ export declare class ClaudeProtocol {
|
|
|
18
19
|
private readonly subagentModels;
|
|
19
20
|
private apiError;
|
|
20
21
|
private readonly refusedWindows;
|
|
22
|
+
private readonly refusedResets;
|
|
21
23
|
private readonly stopRequests;
|
|
22
24
|
private readonly steerIds;
|
|
23
25
|
private goal;
|
|
24
26
|
private goalAnswered;
|
|
25
27
|
private interrupting;
|
|
26
28
|
private readonly backgroundAgents;
|
|
27
|
-
constructor(goal?: ChatGoal | null);
|
|
29
|
+
constructor(goal?: ChatGoal | null, now?: () => number);
|
|
28
30
|
noteInterrupt(): void;
|
|
29
31
|
private setGoal;
|
|
30
32
|
beginSteer(promptId: string): void;
|
|
@@ -50,6 +52,7 @@ export declare class ClaudeProtocol {
|
|
|
50
52
|
private handleUser;
|
|
51
53
|
private handleResult;
|
|
52
54
|
private noteRefusal;
|
|
55
|
+
private expireRefusedResets;
|
|
53
56
|
private limit;
|
|
54
57
|
private handleControlRequest;
|
|
55
58
|
private textRef;
|
|
@@ -153,6 +153,7 @@ export function claudeGoalCheck(text, current) {
|
|
|
153
153
|
* belongs to one process, so a resumed CLI that numbers its messages from the start gets its own.
|
|
154
154
|
*/
|
|
155
155
|
export class ClaudeProtocol {
|
|
156
|
+
now;
|
|
156
157
|
promptId = null;
|
|
157
158
|
pending = new Map();
|
|
158
159
|
streamMessageId = null;
|
|
@@ -174,6 +175,8 @@ export class ClaudeProtocol {
|
|
|
174
175
|
// Only main-chain errors classify the turn; each plan window can refuse it independently.
|
|
175
176
|
apiError = null;
|
|
176
177
|
refusedWindows = new Map();
|
|
178
|
+
// Sparse refusals can omit a reset; cached metadata alone must never classify a later 429.
|
|
179
|
+
refusedResets = new Map();
|
|
177
180
|
// The task each `stop_task` request named, so an error answer finds it again.
|
|
178
181
|
stopRequests = new Map();
|
|
179
182
|
steerIds = new Set();
|
|
@@ -184,8 +187,9 @@ export class ClaudeProtocol {
|
|
|
184
187
|
interrupting = false;
|
|
185
188
|
// Background subagents still at work; Claude Code holds a goal's check until they report.
|
|
186
189
|
backgroundAgents = new Set();
|
|
187
|
-
constructor(goal = null) {
|
|
190
|
+
constructor(goal = null, now = () => Date.now()) {
|
|
188
191
|
this.goal = goal;
|
|
192
|
+
this.now = now;
|
|
189
193
|
}
|
|
190
194
|
/* A stop is on its way; the turn it ends leaves the goal set but nobody working on it. */
|
|
191
195
|
noteInterrupt() {
|
|
@@ -204,6 +208,7 @@ export class ClaudeProtocol {
|
|
|
204
208
|
this.promptId = promptId;
|
|
205
209
|
this.apiError = null;
|
|
206
210
|
this.refusedWindows.clear();
|
|
211
|
+
this.expireRefusedResets();
|
|
207
212
|
this.lastUuid = null;
|
|
208
213
|
}
|
|
209
214
|
handle(frame) {
|
|
@@ -713,6 +718,10 @@ export class ClaudeProtocol {
|
|
|
713
718
|
const lastUuid = this.lastUuid;
|
|
714
719
|
this.lastUuid = null;
|
|
715
720
|
const limit = failed ? this.limit() : null;
|
|
721
|
+
const replaceProcess = failed && this.apiError === 'authentication_failed';
|
|
722
|
+
if (limit?.kind !== 'usage') {
|
|
723
|
+
this.refusedResets.clear();
|
|
724
|
+
}
|
|
716
725
|
this.apiError = null;
|
|
717
726
|
this.refusedWindows.clear();
|
|
718
727
|
// Before the turn ends, so whoever settles work on that end already reads where the goal stands.
|
|
@@ -724,21 +733,41 @@ export class ClaudeProtocol {
|
|
|
724
733
|
costUsd: num(frame.total_cost_usd),
|
|
725
734
|
...(failed ? { error: errors[0] ?? str(frame.result) ?? `The turn ended with ${str(frame.subtype) ?? 'an error'}` } : {}),
|
|
726
735
|
...(lastUuid === null ? {} : { native: { lastUuid } }),
|
|
727
|
-
...(limit === null ? {} : { limit })
|
|
736
|
+
...(limit === null ? {} : { limit }),
|
|
737
|
+
...(replaceProcess ? { replaceProcess: true } : {})
|
|
728
738
|
});
|
|
729
739
|
}
|
|
730
740
|
noteRefusal(info) {
|
|
731
741
|
if (!isRecord(info) || typeof info.status !== 'string') {
|
|
732
742
|
return;
|
|
733
743
|
}
|
|
734
|
-
|
|
744
|
+
this.expireRefusedResets();
|
|
745
|
+
const namedWindow = str(info.rateLimitType);
|
|
746
|
+
const window = namedWindow ?? 'unknown';
|
|
735
747
|
const overageAllowed = info.overageStatus === 'allowed' || info.overageStatus === 'allowed_warning' || info.isUsingOverage === true || info.overageInUse === true;
|
|
736
748
|
if (info.status === 'rejected' && !overageAllowed) {
|
|
737
749
|
const resetsAt = typeof info.resetsAt === 'number' ? info.resetsAt * 1000 : NaN;
|
|
738
|
-
|
|
750
|
+
const validReset = Number.isFinite(resetsAt) && resetsAt > this.now() && resetsAt < 8.64e15 ? resetsAt : null;
|
|
751
|
+
const reset = validReset ?? (info.resetsAt === undefined && namedWindow ? (this.refusedResets.get(window) ?? null) : null);
|
|
752
|
+
this.refusedWindows.set(window, reset);
|
|
753
|
+
if (namedWindow && reset !== null && reset > this.now()) {
|
|
754
|
+
this.refusedResets.set(window, reset);
|
|
755
|
+
}
|
|
756
|
+
else {
|
|
757
|
+
this.refusedResets.delete(window);
|
|
758
|
+
}
|
|
739
759
|
}
|
|
740
760
|
else if (info.status === 'allowed' || info.status === 'allowed_warning' || overageAllowed) {
|
|
741
761
|
this.refusedWindows.delete(window);
|
|
762
|
+
this.refusedResets.delete(window);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
expireRefusedResets() {
|
|
766
|
+
const now = this.now();
|
|
767
|
+
for (const [window, reset] of this.refusedResets) {
|
|
768
|
+
if (reset <= now) {
|
|
769
|
+
this.refusedResets.delete(window);
|
|
770
|
+
}
|
|
742
771
|
}
|
|
743
772
|
}
|
|
744
773
|
/*
|
|
@@ -750,7 +779,7 @@ export class ClaudeProtocol {
|
|
|
750
779
|
if (this.refusedWindows.size > 0) {
|
|
751
780
|
let resetsAt = 0;
|
|
752
781
|
for (const reset of this.refusedWindows.values()) {
|
|
753
|
-
if (reset === null) {
|
|
782
|
+
if (reset === null || reset <= this.now()) {
|
|
754
783
|
return { kind: 'usage' };
|
|
755
784
|
}
|
|
756
785
|
resetsAt = Math.max(resetsAt, reset);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adecore/agents",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.5",
|
|
4
4
|
"description": "Node-compatible agent chat hosts, providers, accounts, usage and durable task coordination.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
"test": "bun --conditions=source test"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@adecore/agent-contracts": "0.27.
|
|
85
|
-
"@adecore/intelligent-ui": "0.27.
|
|
84
|
+
"@adecore/agent-contracts": "0.27.5",
|
|
85
|
+
"@adecore/intelligent-ui": "0.27.5",
|
|
86
86
|
"zod": "^4.6.5"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
package/src/chat/backend.ts
CHANGED
|
@@ -35,6 +35,8 @@ export interface BackendLaunch {
|
|
|
35
35
|
// How often this chat started a CLI; a protocol that numbers its own requests from zero
|
|
36
36
|
// needs it to keep the ids of one process apart from those of the one before.
|
|
37
37
|
generation: number;
|
|
38
|
+
// Shares the host clock with expiry checks when a test advances time by hand.
|
|
39
|
+
now?(): number;
|
|
38
40
|
// What the agent is told once, at the start of a process: a system prompt, or a new thread's developer instructions.
|
|
39
41
|
instructions: string | null;
|
|
40
42
|
// The part of it a resumed thread has to hear again in front of its next prompt, for a CLI that ignores new
|
|
@@ -182,6 +184,8 @@ export type BackendEvent =
|
|
|
182
184
|
error?: string;
|
|
183
185
|
native?: { turnId?: string; lastUuid?: string };
|
|
184
186
|
limit?: ChatTurnLimit;
|
|
187
|
+
// The next prompt needs fresh process credentials, once native work and requests have settled.
|
|
188
|
+
replaceProcess?: boolean;
|
|
185
189
|
}
|
|
186
190
|
// The CLI could not be reached or refused the request; the turn ends and the chat needs a new one.
|
|
187
191
|
| { type: 'failed'; message: string; processAlive?: boolean }
|
package/src/chat/chat-session.ts
CHANGED
|
@@ -170,6 +170,7 @@ export class ChatSession {
|
|
|
170
170
|
private readonly options: ChatSessionOptions;
|
|
171
171
|
private readonly projector: ThreadProjector;
|
|
172
172
|
private backend: ChatBackend | null = null;
|
|
173
|
+
private replaceProcess = false;
|
|
173
174
|
private starting: Promise<ChatBackend> | null = null;
|
|
174
175
|
private pendingStart: { turnId: string; warning: unknown } | null = null;
|
|
175
176
|
private sendAfterStop = false;
|
|
@@ -1805,7 +1806,8 @@ export class ChatSession {
|
|
|
1805
1806
|
private requiresReplacement(): boolean {
|
|
1806
1807
|
return (
|
|
1807
1808
|
this.backend !== null &&
|
|
1808
|
-
(
|
|
1809
|
+
(this.replaceProcess ||
|
|
1810
|
+
JSON.stringify(this.info.selection) !== JSON.stringify(this.launchedSelection) ||
|
|
1809
1811
|
this.info.runtimeMode !== this.launchedRuntimeMode ||
|
|
1810
1812
|
this.info.account !== this.launchedAccount ||
|
|
1811
1813
|
this.info.cwd !== this.launchedCwd ||
|
|
@@ -1874,6 +1876,7 @@ export class ChatSession {
|
|
|
1874
1876
|
runtimeMode: info.runtimeMode,
|
|
1875
1877
|
resume: info.agentSessionId,
|
|
1876
1878
|
generation,
|
|
1879
|
+
now: () => this.options.limitResume?.now() ?? (this.options.clock ?? systemClock).now(),
|
|
1877
1880
|
saveGeneratedImage: this.options.saveGeneratedImage,
|
|
1878
1881
|
instructions: this.options.instructions?.() ?? null,
|
|
1879
1882
|
resumeNote: this.options.resumeNote?.() ?? null,
|
|
@@ -1897,6 +1900,7 @@ export class ChatSession {
|
|
|
1897
1900
|
}
|
|
1898
1901
|
const backend = made.backend;
|
|
1899
1902
|
this.backend = backend;
|
|
1903
|
+
this.replaceProcess = false;
|
|
1900
1904
|
this.emit([this.thread.patchInfo({ running: true, effectiveRuntimeMode: undefined, permissionMode: undefined })]);
|
|
1901
1905
|
let started: Promise<void>;
|
|
1902
1906
|
try {
|
|
@@ -1980,6 +1984,9 @@ export class ChatSession {
|
|
|
1980
1984
|
if (event.promptId !== undefined) {
|
|
1981
1985
|
this.staleResults = 0;
|
|
1982
1986
|
}
|
|
1987
|
+
if (event.replaceProcess === true) {
|
|
1988
|
+
this.replaceProcess = true;
|
|
1989
|
+
}
|
|
1983
1990
|
const promptId = event.promptId ?? this.submission?.input.promptId;
|
|
1984
1991
|
if (promptId !== undefined) {
|
|
1985
1992
|
this.acceptPrompt(promptId);
|
|
@@ -41,7 +41,7 @@ export class ClaudeBackend implements ChatBackend {
|
|
|
41
41
|
this.launch = launch;
|
|
42
42
|
this.host = host;
|
|
43
43
|
this.allowedTools = options.allowedTools ?? [];
|
|
44
|
-
this.protocol = new ClaudeProtocol(launch.goal ?? null);
|
|
44
|
+
this.protocol = new ClaudeProtocol(launch.goal ?? null, launch.now);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
get running(): boolean {
|
|
@@ -187,6 +187,7 @@ export function claudeGoalCheck(text: string, current: ChatGoal | null): ChatGoa
|
|
|
187
187
|
* belongs to one process, so a resumed CLI that numbers its messages from the start gets its own.
|
|
188
188
|
*/
|
|
189
189
|
export class ClaudeProtocol {
|
|
190
|
+
private readonly now: () => number;
|
|
190
191
|
private promptId: string | null = null;
|
|
191
192
|
private readonly pending = new Map<string, Pending>();
|
|
192
193
|
private streamMessageId: string | null = null;
|
|
@@ -208,6 +209,8 @@ export class ClaudeProtocol {
|
|
|
208
209
|
// Only main-chain errors classify the turn; each plan window can refuse it independently.
|
|
209
210
|
private apiError: string | null = null;
|
|
210
211
|
private readonly refusedWindows = new Map<string, number | null>();
|
|
212
|
+
// Sparse refusals can omit a reset; cached metadata alone must never classify a later 429.
|
|
213
|
+
private readonly refusedResets = new Map<string, number>();
|
|
211
214
|
|
|
212
215
|
// The task each `stop_task` request named, so an error answer finds it again.
|
|
213
216
|
private readonly stopRequests = new Map<string, string>();
|
|
@@ -221,8 +224,9 @@ export class ClaudeProtocol {
|
|
|
221
224
|
// Background subagents still at work; Claude Code holds a goal's check until they report.
|
|
222
225
|
private readonly backgroundAgents = new Set<string>();
|
|
223
226
|
|
|
224
|
-
constructor(goal: ChatGoal | null = null) {
|
|
227
|
+
constructor(goal: ChatGoal | null = null, now: () => number = () => Date.now()) {
|
|
225
228
|
this.goal = goal;
|
|
229
|
+
this.now = now;
|
|
226
230
|
}
|
|
227
231
|
|
|
228
232
|
/* A stop is on its way; the turn it ends leaves the goal set but nobody working on it. */
|
|
@@ -245,6 +249,7 @@ export class ClaudeProtocol {
|
|
|
245
249
|
this.promptId = promptId;
|
|
246
250
|
this.apiError = null;
|
|
247
251
|
this.refusedWindows.clear();
|
|
252
|
+
this.expireRefusedResets();
|
|
248
253
|
this.lastUuid = null;
|
|
249
254
|
}
|
|
250
255
|
|
|
@@ -765,6 +770,10 @@ export class ClaudeProtocol {
|
|
|
765
770
|
const lastUuid = this.lastUuid;
|
|
766
771
|
this.lastUuid = null;
|
|
767
772
|
const limit = failed ? this.limit() : null;
|
|
773
|
+
const replaceProcess = failed && this.apiError === 'authentication_failed';
|
|
774
|
+
if (limit?.kind !== 'usage') {
|
|
775
|
+
this.refusedResets.clear();
|
|
776
|
+
}
|
|
768
777
|
this.apiError = null;
|
|
769
778
|
this.refusedWindows.clear();
|
|
770
779
|
// Before the turn ends, so whoever settles work on that end already reads where the goal stands.
|
|
@@ -776,7 +785,8 @@ export class ClaudeProtocol {
|
|
|
776
785
|
costUsd: num(frame.total_cost_usd),
|
|
777
786
|
...(failed ? { error: errors[0] ?? str(frame.result) ?? `The turn ended with ${str(frame.subtype) ?? 'an error'}` } : {}),
|
|
778
787
|
...(lastUuid === null ? {} : { native: { lastUuid } }),
|
|
779
|
-
...(limit === null ? {} : { limit })
|
|
788
|
+
...(limit === null ? {} : { limit }),
|
|
789
|
+
...(replaceProcess ? { replaceProcess: true } : {})
|
|
780
790
|
});
|
|
781
791
|
}
|
|
782
792
|
|
|
@@ -784,14 +794,33 @@ export class ClaudeProtocol {
|
|
|
784
794
|
if (!isRecord(info) || typeof info.status !== 'string') {
|
|
785
795
|
return;
|
|
786
796
|
}
|
|
787
|
-
|
|
797
|
+
this.expireRefusedResets();
|
|
798
|
+
const namedWindow = str(info.rateLimitType);
|
|
799
|
+
const window = namedWindow ?? 'unknown';
|
|
788
800
|
const overageAllowed =
|
|
789
801
|
info.overageStatus === 'allowed' || info.overageStatus === 'allowed_warning' || info.isUsingOverage === true || info.overageInUse === true;
|
|
790
802
|
if (info.status === 'rejected' && !overageAllowed) {
|
|
791
803
|
const resetsAt = typeof info.resetsAt === 'number' ? info.resetsAt * 1000 : NaN;
|
|
792
|
-
|
|
804
|
+
const validReset = Number.isFinite(resetsAt) && resetsAt > this.now() && resetsAt < 8.64e15 ? resetsAt : null;
|
|
805
|
+
const reset = validReset ?? (info.resetsAt === undefined && namedWindow ? (this.refusedResets.get(window) ?? null) : null);
|
|
806
|
+
this.refusedWindows.set(window, reset);
|
|
807
|
+
if (namedWindow && reset !== null && reset > this.now()) {
|
|
808
|
+
this.refusedResets.set(window, reset);
|
|
809
|
+
} else {
|
|
810
|
+
this.refusedResets.delete(window);
|
|
811
|
+
}
|
|
793
812
|
} else if (info.status === 'allowed' || info.status === 'allowed_warning' || overageAllowed) {
|
|
794
813
|
this.refusedWindows.delete(window);
|
|
814
|
+
this.refusedResets.delete(window);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
private expireRefusedResets(): void {
|
|
819
|
+
const now = this.now();
|
|
820
|
+
for (const [window, reset] of this.refusedResets) {
|
|
821
|
+
if (reset <= now) {
|
|
822
|
+
this.refusedResets.delete(window);
|
|
823
|
+
}
|
|
795
824
|
}
|
|
796
825
|
}
|
|
797
826
|
|
|
@@ -804,7 +833,7 @@ export class ClaudeProtocol {
|
|
|
804
833
|
if (this.refusedWindows.size > 0) {
|
|
805
834
|
let resetsAt = 0;
|
|
806
835
|
for (const reset of this.refusedWindows.values()) {
|
|
807
|
-
if (reset === null) {
|
|
836
|
+
if (reset === null || reset <= this.now()) {
|
|
808
837
|
return { kind: 'usage' };
|
|
809
838
|
}
|
|
810
839
|
resetsAt = Math.max(resetsAt, reset);
|