@0xmaxma/claude-gateway 1.6.2 → 1.6.3
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/agent/runner.d.ts +24 -2
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +148 -31
- package/dist/agent/runner.js.map +1 -1
- package/dist/apps/agent-manager.d.ts.map +1 -1
- package/dist/apps/agent-manager.js +16 -2
- package/dist/apps/agent-manager.js.map +1 -1
- package/dist/shell/claude-pty-shell.js +7 -0
- package/dist/shell/claude-pty-shell.js.map +1 -1
- package/dist/shell/screen.d.ts +21 -1
- package/dist/shell/screen.d.ts.map +1 -1
- package/dist/shell/screen.js +21 -1
- package/dist/shell/screen.js.map +1 -1
- package/package.json +1 -1
package/dist/agent/runner.d.ts
CHANGED
|
@@ -50,6 +50,9 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
50
50
|
private readonly pendingImagePaths;
|
|
51
51
|
private readonly channelCoalesce;
|
|
52
52
|
private readonly coalesceWindowMs;
|
|
53
|
+
private readonly turnActive;
|
|
54
|
+
private readonly turnQueue;
|
|
55
|
+
private readonly stopEpoch;
|
|
53
56
|
private readonly pendingApiAttachments;
|
|
54
57
|
private readonly sessionHistory;
|
|
55
58
|
private readonly apiChatIds;
|
|
@@ -143,6 +146,19 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
143
146
|
* a photo and its instruction text are read together in the same turn.
|
|
144
147
|
*/
|
|
145
148
|
private routeChannelTurn;
|
|
149
|
+
/**
|
|
150
|
+
* Inject the next queued turn for this chat, or release the active slot when the
|
|
151
|
+
* queue is empty. Called when a turn truly ends — `result` (headless), or
|
|
152
|
+
* `session_idle` (pty-shell), or on process exit. `turnActive` is kept set while
|
|
153
|
+
* a queued turn exists so no incoming message can inject concurrently.
|
|
154
|
+
*/
|
|
155
|
+
private flushNextTurn;
|
|
156
|
+
/**
|
|
157
|
+
* Inject one coalesced turn into the session immediately. The caller must have
|
|
158
|
+
* already marked the chat active in `turnActive`. Records each buffered message
|
|
159
|
+
* individually in history, then writes the merged turn to the subprocess.
|
|
160
|
+
*/
|
|
161
|
+
private injectTurn;
|
|
146
162
|
/**
|
|
147
163
|
* Render composer-selected image options (contract E5) as a directive the agent
|
|
148
164
|
* reads and forwards to the generate_image MCP tool. Returns '' when no usable
|
|
@@ -191,8 +207,14 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
191
207
|
*/
|
|
192
208
|
private handleCommandRename;
|
|
193
209
|
/**
|
|
194
|
-
* /stop — interrupt the in-flight turn for this chat
|
|
195
|
-
*
|
|
210
|
+
* /stop — interrupt the in-flight turn for this chat and cancel anything queued
|
|
211
|
+
* behind it. Drops the coalesce buffer (messages not yet routed) and the turn
|
|
212
|
+
* queue (turns waiting behind the active one), bumps the per-chat stop epoch so
|
|
213
|
+
* a turn still mid-spawn aborts before it submits (closing the spawn-race), and
|
|
214
|
+
* sends SIGINT to interrupt an actively-processing turn. Session history/metadata
|
|
215
|
+
* are left intact. Reports Stopped whenever there was work to cancel — an active
|
|
216
|
+
* turn, a spawning turn, or queued/buffered messages — rather than the old
|
|
217
|
+
* "No turn in progress." that fired whenever interrupt() no-op'd mid-spawn.
|
|
196
218
|
*/
|
|
197
219
|
private handleCommandStop;
|
|
198
220
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAMtC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAW,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAS7H,OAAO,EAA0C,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAOvF,OAAO,EAAiC,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAG7F,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAqB1C,eAAO,MAAM,oBAAoB,QAAmB,CAAC;AAErD,eAAO,MAAM,cAAc,EAAE,WAAW,EAYvC,CAAC;AA0BF,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAkD/C;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,OAAO,EAAE,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAuB,GAC7C,MAAM,EAAE,CAIV;AAED,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA6B;IAC9D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,SAAS,CAAoC;IAErD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IACjC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAEvC,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsD;IACvF,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,eAAe,CAAgC;IAEvD,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,gBAAgB,CAA+C;IAGvE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IAGxD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA8C;IAMhF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA6B;IAKhE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAqB;IAOvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAQtB;IAIH,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkC;IAKlE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4E;IAGrG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA+B;IAOjE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAO5B;IAIJ,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/runner.js
CHANGED
|
@@ -231,6 +231,22 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
231
231
|
// injected as ONE turn instead of two. Keyed by chatId. A trailing-edge timer
|
|
232
232
|
// flushes the buffer once no new related update has arrived for the window.
|
|
233
233
|
this.channelCoalesce = new Map();
|
|
234
|
+
// Gateway-layer turn queue (both backends). A chat is "active" from the moment
|
|
235
|
+
// we inject a turn until its TRUE end signal arrives — `result` on the headless
|
|
236
|
+
// backend (one per user message) or `session_idle` on pty-shell (fires only when
|
|
237
|
+
// the wrapper's `this.turn` is null, i.e. after turn_duration, so it never fires
|
|
238
|
+
// between PTY sub-turns). While active, further channel turns are enqueued here
|
|
239
|
+
// instead of being written straight to stdin, then flushed one at a time on the
|
|
240
|
+
// end signal. Without this, a mid-turn message is merged by the headless CLI as
|
|
241
|
+
// steering (2 messages → 1 result, non-deterministic) or races the PTY paste.
|
|
242
|
+
this.turnActive = new Set();
|
|
243
|
+
this.turnQueue = new Map();
|
|
244
|
+
// Per-chat monotonic epoch bumped by /stop. injectTurn() captures it at entry and
|
|
245
|
+
// re-checks just before submitting; a mismatch means /stop landed during the
|
|
246
|
+
// async spawn/persist window, so the injection aborts instead of submitting the
|
|
247
|
+
// very turn the user asked to cancel (spawn-race close). Using an epoch (not a
|
|
248
|
+
// boolean flag) avoids a stale /stop poisoning a turn the user starts afterwards.
|
|
249
|
+
this.stopEpoch = new Map();
|
|
234
250
|
// Buffers attachment file paths registered via api_reply tool for the current API session turn.
|
|
235
251
|
this.pendingApiAttachments = new Map();
|
|
236
252
|
// Session history ring-buffer (last 10 spawned, newest first)
|
|
@@ -383,33 +399,32 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
383
399
|
});
|
|
384
400
|
return;
|
|
385
401
|
}
|
|
386
|
-
// Coalesce messages that
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
buf.timer
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
this.routeChannelTurn(chatId, channelSource, [params]);
|
|
402
|
+
// Coalesce channel messages that arrive close together into ONE turn:
|
|
403
|
+
// a photo and its caption (Telegram may split them across updates —
|
|
404
|
+
// long-caption split, album burst, or photo sent just before/after the
|
|
405
|
+
// text), OR consecutive text messages that are conceptually a single
|
|
406
|
+
// prompt (A1). Each message is still recorded individually in history
|
|
407
|
+
// by routeChannelTurn(); only the injected turn is merged. A
|
|
408
|
+
// trailing-edge timer flushes the buffer once the window passes with no
|
|
409
|
+
// new message; the gateway turn queue then serialises this merged turn
|
|
410
|
+
// behind any turn already in flight.
|
|
411
|
+
const buf = this.channelCoalesce.get(chatId) ?? {
|
|
412
|
+
channelSource,
|
|
413
|
+
entries: [],
|
|
414
|
+
timer: undefined,
|
|
415
|
+
};
|
|
416
|
+
buf.channelSource = channelSource;
|
|
417
|
+
buf.entries.push(params);
|
|
418
|
+
if (buf.timer)
|
|
419
|
+
clearTimeout(buf.timer);
|
|
420
|
+
buf.timer = setTimeout(() => {
|
|
421
|
+
const flushed = this.channelCoalesce.get(chatId);
|
|
422
|
+
this.channelCoalesce.delete(chatId);
|
|
423
|
+
if (flushed)
|
|
424
|
+
this.routeChannelTurn(chatId, flushed.channelSource, flushed.entries);
|
|
425
|
+
}, this.coalesceWindowMs);
|
|
426
|
+
this.channelCoalesce.set(chatId, buf);
|
|
427
|
+
return;
|
|
413
428
|
}
|
|
414
429
|
catch (err) {
|
|
415
430
|
this.logger.warn('Failed to parse channel callback body', {
|
|
@@ -850,6 +865,49 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
850
865
|
routeChannelTurn(chatId, channelSource, entries) {
|
|
851
866
|
if (entries.length === 0)
|
|
852
867
|
return;
|
|
868
|
+
// Gateway turn queue: if a turn is already in flight for this chat, enqueue
|
|
869
|
+
// this one and return. It is injected when the active turn truly ends
|
|
870
|
+
// (flushNextTurn, wired to the backend-aware end signal). The check-and-set
|
|
871
|
+
// is synchronous, so two near-simultaneous routes cannot both inject, and
|
|
872
|
+
// the active flag stays set continuously across a flush (no re-entrancy gap).
|
|
873
|
+
if (this.turnActive.has(chatId)) {
|
|
874
|
+
const q = this.turnQueue.get(chatId) ?? [];
|
|
875
|
+
q.push({ channelSource, entries });
|
|
876
|
+
this.turnQueue.set(chatId, q);
|
|
877
|
+
this.logger.debug('Turn queued behind in-flight turn', { chatId, queued: q.length });
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
this.turnActive.add(chatId);
|
|
881
|
+
this.injectTurn(chatId, channelSource, entries);
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Inject the next queued turn for this chat, or release the active slot when the
|
|
885
|
+
* queue is empty. Called when a turn truly ends — `result` (headless), or
|
|
886
|
+
* `session_idle` (pty-shell), or on process exit. `turnActive` is kept set while
|
|
887
|
+
* a queued turn exists so no incoming message can inject concurrently.
|
|
888
|
+
*/
|
|
889
|
+
flushNextTurn(chatId) {
|
|
890
|
+
const q = this.turnQueue.get(chatId);
|
|
891
|
+
if (q && q.length > 0) {
|
|
892
|
+
const next = q.shift();
|
|
893
|
+
if (q.length === 0)
|
|
894
|
+
this.turnQueue.delete(chatId);
|
|
895
|
+
this.injectTurn(chatId, next.channelSource, next.entries);
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
this.turnActive.delete(chatId);
|
|
899
|
+
this.turnQueue.delete(chatId);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* Inject one coalesced turn into the session immediately. The caller must have
|
|
904
|
+
* already marked the chat active in `turnActive`. Records each buffered message
|
|
905
|
+
* individually in history, then writes the merged turn to the subprocess.
|
|
906
|
+
*/
|
|
907
|
+
injectTurn(chatId, channelSource, entries) {
|
|
908
|
+
// Snapshot the stop epoch: if /stop bumps it during the async window below, we
|
|
909
|
+
// abort just before submitting (see the check before setProcessing/sendMessage).
|
|
910
|
+
const stopEpochAtStart = this.stopEpoch.get(chatId) ?? 0;
|
|
853
911
|
this.sessionStore.getActiveSessionId(this.agentConfig.id, chatId, channelSource)
|
|
854
912
|
.then(async (sessionId) => {
|
|
855
913
|
// Record each buffered message individually (history + session context).
|
|
@@ -869,9 +927,16 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
869
927
|
try {
|
|
870
928
|
const rel = media_store_1.MediaStore.copyToMedia(this.agentsBaseDir, this.agentConfig.id, `${channelSource}-${chatId}`, meta['image_path']);
|
|
871
929
|
mediaFiles.push(rel);
|
|
930
|
+
// Surface the MediaStore copy to the agent instead of the raw staging
|
|
931
|
+
// path. app-agents run in a container where only the MediaStore dir is
|
|
932
|
+
// bind-mounted at an identical absolute path; the raw source (/tmp for
|
|
933
|
+
// LINE, <workspace>/.*-state for TG/Discord) is invisible inside it.
|
|
934
|
+
// Mutating meta['image_path'] here (same object as entry.meta) makes the
|
|
935
|
+
// channel XML and image-size tracker below both use the readable path.
|
|
936
|
+
meta['image_path'] = media_store_1.MediaStore.resolvePath(this.agentsBaseDir, this.agentConfig.id, rel);
|
|
872
937
|
}
|
|
873
938
|
catch {
|
|
874
|
-
// Non-fatal —
|
|
939
|
+
// Non-fatal — leave the original path so host agents still read it
|
|
875
940
|
}
|
|
876
941
|
}
|
|
877
942
|
this.historyDb.insertMessage({
|
|
@@ -922,6 +987,15 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
922
987
|
this.pendingImagePaths.set(chatId, queue);
|
|
923
988
|
}
|
|
924
989
|
}
|
|
990
|
+
// Spawn-race close: if /stop bumped the stop epoch during the async
|
|
991
|
+
// getActiveSessionId/spawn window above, abort before submitting — do not
|
|
992
|
+
// inject the very turn the user just asked to cancel. flushNextTurn()
|
|
993
|
+
// releases the (now empty, /stop cleared it) queue and the active slot.
|
|
994
|
+
if ((this.stopEpoch.get(chatId) ?? 0) !== stopEpochAtStart) {
|
|
995
|
+
this.logger.info('Turn injection aborted — /stop landed during spawn', { chatId });
|
|
996
|
+
this.flushNextTurn(chatId);
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
925
999
|
session.setProcessing(true);
|
|
926
1000
|
const turnText = blocks.join('\n');
|
|
927
1001
|
session.sendMessage(turnText);
|
|
@@ -943,6 +1017,10 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
943
1017
|
});
|
|
944
1018
|
const code = err.message.includes('pool full') ? 'POOL_FULL' : 'SPAWN_FAILED';
|
|
945
1019
|
this.writeTypingError(chatId, code);
|
|
1020
|
+
// This turn never reached the subprocess, so no end signal will fire —
|
|
1021
|
+
// release the active slot and inject the next queued turn so the queue
|
|
1022
|
+
// cannot wedge on a spawn error.
|
|
1023
|
+
this.flushNextTurn(chatId);
|
|
946
1024
|
});
|
|
947
1025
|
}
|
|
948
1026
|
/**
|
|
@@ -1348,6 +1426,15 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1348
1426
|
}
|
|
1349
1427
|
if (obj['type'] === 'result') {
|
|
1350
1428
|
proc.setProcessing(false);
|
|
1429
|
+
// Gateway turn queue: on the headless backend `result` is the true end
|
|
1430
|
+
// of the user's turn (exactly one per message), so flush the next
|
|
1431
|
+
// queued turn here. On pty-shell `result` fires per sub-turn (across
|
|
1432
|
+
// tool-call gaps), so its flush is driven by `session_idle` instead
|
|
1433
|
+
// (below) — flushing on every sub-turn `result` would inject the next
|
|
1434
|
+
// message mid-work.
|
|
1435
|
+
if (proc.backend !== 'pty-shell') {
|
|
1436
|
+
this.flushNextTurn(mapKey);
|
|
1437
|
+
}
|
|
1351
1438
|
// Telegram: accumulate image size via stat of local file (FIFO, one per turn)
|
|
1352
1439
|
const queue = this.pendingImagePaths.get(mapKey);
|
|
1353
1440
|
const imgPath = queue?.shift();
|
|
@@ -1479,6 +1566,10 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1479
1566
|
// event. Start the typing-done timer here so the indicator stays alive
|
|
1480
1567
|
// through multi-turn tool-call sequences and only stops when all work is done.
|
|
1481
1568
|
if (obj['type'] === 'session_idle' && proc.backend === 'pty-shell') {
|
|
1569
|
+
// Gateway turn queue: on pty-shell this is the true end of the user's
|
|
1570
|
+
// turn (the wrapper only emits it when its own `this.turn` is null, so
|
|
1571
|
+
// it never fires between sub-turns) — flush the next queued turn.
|
|
1572
|
+
this.flushNextTurn(mapKey);
|
|
1482
1573
|
typingDoneTimer = setTimeout(() => {
|
|
1483
1574
|
this.writeTypingDone(mapKey);
|
|
1484
1575
|
typingDoneTimer = null;
|
|
@@ -1529,6 +1620,11 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1529
1620
|
typingDoneTimer = null;
|
|
1530
1621
|
}
|
|
1531
1622
|
this.writeTypingDone(mapKey);
|
|
1623
|
+
// Gateway turn queue: the in-flight turn's end signal will never arrive
|
|
1624
|
+
// now, so release the active slot. If turns were queued behind it, deliver
|
|
1625
|
+
// the next one (injectTurn respawns the session) so a crash mid-turn does
|
|
1626
|
+
// not strand the messages the user already sent.
|
|
1627
|
+
this.flushNextTurn(mapKey);
|
|
1532
1628
|
// LINE: a process exit with a button whose answer never arrived (crash /
|
|
1533
1629
|
// teardown mid-turn) → surface the interrupted notice so a tap returns it
|
|
1534
1630
|
// instead of a stale "still thinking". markInterrupted no-ops on a READY
|
|
@@ -1674,12 +1770,33 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1674
1770
|
this.writeAutoForward(chatId, `✅ Session renamed to "${name}"`);
|
|
1675
1771
|
}
|
|
1676
1772
|
/**
|
|
1677
|
-
* /stop — interrupt the in-flight turn for this chat
|
|
1678
|
-
*
|
|
1773
|
+
* /stop — interrupt the in-flight turn for this chat and cancel anything queued
|
|
1774
|
+
* behind it. Drops the coalesce buffer (messages not yet routed) and the turn
|
|
1775
|
+
* queue (turns waiting behind the active one), bumps the per-chat stop epoch so
|
|
1776
|
+
* a turn still mid-spawn aborts before it submits (closing the spawn-race), and
|
|
1777
|
+
* sends SIGINT to interrupt an actively-processing turn. Session history/metadata
|
|
1778
|
+
* are left intact. Reports Stopped whenever there was work to cancel — an active
|
|
1779
|
+
* turn, a spawning turn, or queued/buffered messages — rather than the old
|
|
1780
|
+
* "No turn in progress." that fired whenever interrupt() no-op'd mid-spawn.
|
|
1679
1781
|
*/
|
|
1680
1782
|
async handleCommandStop(chatId) {
|
|
1783
|
+
// Cancel queued + buffered work first so nothing flushes in behind the interrupt.
|
|
1784
|
+
const buffered = this.channelCoalesce.get(chatId);
|
|
1785
|
+
if (buffered?.timer)
|
|
1786
|
+
clearTimeout(buffered.timer);
|
|
1787
|
+
this.channelCoalesce.delete(chatId);
|
|
1788
|
+
const hadQueued = (this.turnQueue.get(chatId)?.length ?? 0) > 0;
|
|
1789
|
+
this.turnQueue.delete(chatId);
|
|
1790
|
+
// Bump the stop epoch: any injectTurn() that began before this point detects
|
|
1791
|
+
// the mismatch just before submitting and aborts (spawn-race close). The
|
|
1792
|
+
// turnActive slot is released by that abort's flushNextTurn(), or by the
|
|
1793
|
+
// interrupted turn's end signal — never cleared here, to avoid racing a
|
|
1794
|
+
// stale end signal against a turn the user starts right after /stop.
|
|
1795
|
+
const hadActive = this.turnActive.has(chatId);
|
|
1796
|
+
this.stopEpoch.set(chatId, (this.stopEpoch.get(chatId) ?? 0) + 1);
|
|
1681
1797
|
const session = this.sessions.get(chatId);
|
|
1682
|
-
const
|
|
1798
|
+
const interrupted = session ? session.interrupt() : false;
|
|
1799
|
+
const stopped = interrupted || hadActive || hadQueued || !!buffered;
|
|
1683
1800
|
this.writeAutoForward(chatId, stopped ? 'Stopped.' : 'No turn in progress.');
|
|
1684
1801
|
}
|
|
1685
1802
|
/**
|