@0xmaxma/claude-gateway 1.3.13 → 1.3.14
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 +19 -0
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +103 -19
- package/dist/agent/runner.js.map +1 -1
- package/dist/session/process.d.ts +2 -0
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +26 -7
- package/dist/session/process.js.map +1 -1
- package/dist/shell/claude-pty-shell.js +41 -20
- package/dist/shell/claude-pty-shell.js.map +1 -1
- package/dist/shell/screen.d.ts +51 -2
- package/dist/shell/screen.d.ts.map +1 -1
- package/dist/shell/screen.js +82 -5
- package/dist/shell/screen.js.map +1 -1
- package/dist/shell/tailer.d.ts +24 -0
- package/dist/shell/tailer.d.ts.map +1 -1
- package/dist/shell/tailer.js +53 -0
- package/dist/shell/tailer.js.map +1 -1
- package/package.json +1 -1
package/dist/agent/runner.d.ts
CHANGED
|
@@ -28,6 +28,8 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
28
28
|
private idleCleanerTimer;
|
|
29
29
|
private readonly pendingApiSessions;
|
|
30
30
|
private readonly sessionSpawnLocks;
|
|
31
|
+
private readonly tooLargeRecoveries;
|
|
32
|
+
private readonly tooLargeExhausted;
|
|
31
33
|
private readonly pendingImagePaths;
|
|
32
34
|
private readonly channelCoalesce;
|
|
33
35
|
private readonly coalesceWindowMs;
|
|
@@ -118,6 +120,23 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
118
120
|
* The process will be lazily re-spawned on the next incoming message.
|
|
119
121
|
*/
|
|
120
122
|
private restartProcess;
|
|
123
|
+
/**
|
|
124
|
+
* Unified recovery for the recoverable "Request too large (max 32MB)" error.
|
|
125
|
+
* Reached from two backends that surface the SAME error differently:
|
|
126
|
+
* - PTY shell (headless=false): a `system/request_too_large` event emitted by
|
|
127
|
+
* the transcript tailer from the authoritative <synthetic> record (Bug A).
|
|
128
|
+
* - Headless (headless=true): claude --print emits a synthetic `result`
|
|
129
|
+
* (is_error + "Request too large (max"); the long-lived process otherwise
|
|
130
|
+
* stays alive and rejects every subsequent turn forever (Bug B).
|
|
131
|
+
*
|
|
132
|
+
* Each consecutive recovery shrinks the history re-injected on the next spawn
|
|
133
|
+
* (TOO_LARGE_HISTORY_LADDER: 50→40→30→20→10→0) so a pathological context drops
|
|
134
|
+
* under the 32MB ceiling. The respawn happens on the user's NEXT message (no
|
|
135
|
+
* auto-loop), and the counter resets on the next successful result. Once even a
|
|
136
|
+
* zero-history spawn still trips 32MB, stop escalating and ask the user to
|
|
137
|
+
* /clear rather than climb the ladder again.
|
|
138
|
+
*/
|
|
139
|
+
private handleRequestTooLarge;
|
|
121
140
|
/**
|
|
122
141
|
* Stop all idle session subprocesses so they re-spawn with the latest
|
|
123
142
|
* system prompt on the next incoming message.
|
|
@@ -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,MAAM,UAAU,CAAC;AAQhH,OAAO,EAA0C,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAGvF,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;
|
|
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
|
@@ -55,6 +55,15 @@ const cleanup_1 = require("../history/cleanup");
|
|
|
55
55
|
const DEFAULT_IDLE_TIMEOUT_MINUTES = 30;
|
|
56
56
|
const DEFAULT_MAX_CONCURRENT = 20;
|
|
57
57
|
const ANTHROPIC_SOCKET_ERROR = 'socket connection was closed unexpectedly';
|
|
58
|
+
// History re-injection ladder for request_too_large (32MB) recovery. Index =
|
|
59
|
+
// number of consecutive 32MB recoveries on a session; the value is how many
|
|
60
|
+
// history messages the NEXT spawn re-injects. Index 0 is the healthy default
|
|
61
|
+
// (= MAX_HISTORY_MESSAGES, sourced from it so the two never drift); each retry
|
|
62
|
+
// steps down a rung, shrinking the re-loaded context until it drops under
|
|
63
|
+
// Anthropic's 32MB request ceiling. Past the last rung (0 history) the context
|
|
64
|
+
// can't shrink further, so the runner stops escalating and asks the user to
|
|
65
|
+
// /clear instead of looping forever.
|
|
66
|
+
const TOO_LARGE_HISTORY_LADDER = [process_1.MAX_HISTORY_MESSAGES, 40, 30, 20, 10, 0];
|
|
58
67
|
exports.MAX_IMAGE_SIZE_BYTES = 10 * 1024 * 1024;
|
|
59
68
|
exports.DEFAULT_MODELS = [
|
|
60
69
|
{ id: 'claude-opus-4-8', label: 'Opus 4.8', alias: 'opus', contextWindow: 1000000 },
|
|
@@ -131,6 +140,16 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
131
140
|
this.pendingApiSessions = new Set();
|
|
132
141
|
// Serialises concurrent getOrSpawnSession calls for the same key to prevent double-spawn
|
|
133
142
|
this.sessionSpawnLocks = new Map();
|
|
143
|
+
// Consecutive request_too_large (32MB) recoveries per mapKey. Survives the
|
|
144
|
+
// session respawn (SessionProcess is recreated on each restart) so the history
|
|
145
|
+
// re-injection can escalate-shrink across retries (TOO_LARGE_HISTORY_LADDER).
|
|
146
|
+
// Reset to 0 on the next successful result; read by spawnSession.
|
|
147
|
+
this.tooLargeRecoveries = new Map();
|
|
148
|
+
// mapKeys that exhausted the ladder (zero-history spawn still tripped 32MB).
|
|
149
|
+
// Once here, further 32MB events only re-notify "/clear" and do NOT restart —
|
|
150
|
+
// restarting would just churn a context that cannot shrink. Cleared together
|
|
151
|
+
// with the counter on a successful result and on /clear.
|
|
152
|
+
this.tooLargeExhausted = new Set();
|
|
134
153
|
// Tracks pending Telegram image paths per chatId (queue) for size accumulation after each turn.
|
|
135
154
|
this.pendingImagePaths = new Map();
|
|
136
155
|
// Coalescing buffer: collects channel messages that arrive close together so a
|
|
@@ -674,6 +693,19 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
674
693
|
// Apply per-session model override (caller already normalized to undefined when == agent default)
|
|
675
694
|
if (modelOverride)
|
|
676
695
|
proc.modelOverride = modelOverride;
|
|
696
|
+
// request_too_large (32MB) recovery: shrink the re-injected history on each
|
|
697
|
+
// consecutive retry so a pathological context eventually fits. recoveryCount
|
|
698
|
+
// is 0 for healthy sessions → ladder rung 0 = MAX_HISTORY_MESSAGES (same as
|
|
699
|
+
// the SessionProcess default), so applying it unconditionally is a no-op for
|
|
700
|
+
// healthy sessions and the only path that sets historyLimit for recovering ones.
|
|
701
|
+
const recoveryCount = this.tooLargeRecoveries.get(mapKey) ?? 0;
|
|
702
|
+
const ladderIdx = Math.min(recoveryCount, TOO_LARGE_HISTORY_LADDER.length - 1);
|
|
703
|
+
proc.historyLimit = TOO_LARGE_HISTORY_LADDER[ladderIdx];
|
|
704
|
+
if (recoveryCount > 0) {
|
|
705
|
+
this.logger.info('Spawning with reduced history after request_too_large', {
|
|
706
|
+
mapKey, recoveryCount, historyLimit: proc.historyLimit,
|
|
707
|
+
});
|
|
708
|
+
}
|
|
677
709
|
await proc.start();
|
|
678
710
|
// Forward all session output lines so listeners on AgentRunner (GatewayRouter,
|
|
679
711
|
// CronScheduler, tests) receive them without needing individual session references.
|
|
@@ -767,23 +799,11 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
767
799
|
}
|
|
768
800
|
}
|
|
769
801
|
// PTY shell hit the recoverable "Request too large (max 32MB)" error.
|
|
770
|
-
// The
|
|
771
|
-
//
|
|
772
|
-
//
|
|
773
|
-
// from the store, so the next message isn't doomed to re-hit 32MB. The
|
|
774
|
-
// proc exit handler clears the typing indicator; tell the user to resend.
|
|
802
|
+
// The transcript tailer emits this from the authoritative <synthetic>
|
|
803
|
+
// record (Bug A fix). Recovery is unified in handleRequestTooLarge()
|
|
804
|
+
// so the headless path (Bug B) gets identical treatment.
|
|
775
805
|
if (obj['type'] === 'system' && obj['subtype'] === 'request_too_large') {
|
|
776
|
-
this.
|
|
777
|
-
proc.setProcessing(false);
|
|
778
|
-
// Ordering matters and makes the notice delivery race-free: writeAutoForward
|
|
779
|
-
// persists the `.forward` file synchronously HERE, before restartProcess()
|
|
780
|
-
// begins its async stop/kill. The typing-loop tear-down (stop() in typing.ts)
|
|
781
|
-
// drains and sends `.forward` synchronously before it removes the typing
|
|
782
|
-
// signal, so by the time the proc exit fires and the loop stops, the file is
|
|
783
|
-
// already on disk and is delivered — no dependency on poll timing. Do not
|
|
784
|
-
// reorder restartProcess() ahead of writeAutoForward().
|
|
785
|
-
this.writeAutoForward(mapKey, '⚠️ Context too large — hit Anthropic\'s 32MB request limit (usually from large images or files in context). Restarting this session with a fresh context. Your last message was not processed — please resend it.');
|
|
786
|
-
void this.restartProcess(mapKey);
|
|
806
|
+
this.handleRequestTooLarge(mapKey, proc);
|
|
787
807
|
}
|
|
788
808
|
if (obj['type'] === 'result') {
|
|
789
809
|
proc.setProcessing(false);
|
|
@@ -825,10 +845,22 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
825
845
|
if (isSocketError) {
|
|
826
846
|
this.writeAutoForward(mapKey, '⚡ Connection to Anthropic API dropped. Please resend your message.');
|
|
827
847
|
}
|
|
828
|
-
//
|
|
829
|
-
//
|
|
830
|
-
//
|
|
848
|
+
// Bug B: headless (claude --print) reports a too-large request as a
|
|
849
|
+
// synthetic `result` (is_error + "Request too large (max"), NOT as the
|
|
850
|
+
// PTY `system/request_too_large` event. Previously this result was only
|
|
851
|
+
// suppressed — the long-lived process stayed alive and rejected every
|
|
852
|
+
// turn forever ("typing then silent"). Route it through the SAME unified
|
|
853
|
+
// recovery (notify + escalate-shrink history + restart) as the PTY path.
|
|
831
854
|
const isRequestTooLarge = obj['is_error'] === true && resultText.includes(screen_1.TUI_REQUEST_TOO_LARGE);
|
|
855
|
+
if (isRequestTooLarge) {
|
|
856
|
+
this.handleRequestTooLarge(mapKey, proc);
|
|
857
|
+
}
|
|
858
|
+
else if (obj['is_error'] !== true) {
|
|
859
|
+
// Genuine successful turn — clear any request_too_large escalation so
|
|
860
|
+
// the next 32MB (if any) starts fresh at the top of the ladder.
|
|
861
|
+
this.tooLargeRecoveries.delete(mapKey);
|
|
862
|
+
this.tooLargeExhausted.delete(mapKey);
|
|
863
|
+
}
|
|
832
864
|
// Skip when a menu was rendered to buttons this turn — the result
|
|
833
865
|
// text is the same numbered list and would duplicate the menu message.
|
|
834
866
|
if (!isSocketError && !isRequestTooLarge && resultText.trim() && !proc.queryMode && !replyCalled && !isThinkingCorruption && !menuSentThisTurn) {
|
|
@@ -1085,6 +1117,10 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1085
1117
|
this.historyDb.clearChat(historyChatId);
|
|
1086
1118
|
// Delete persisted media files for this chat
|
|
1087
1119
|
media_store_1.MediaStore.clearChatMedia(this.agentsBaseDir, agentId, historyChatId);
|
|
1120
|
+
// Reset any request_too_large escalation — the context is now empty, so the
|
|
1121
|
+
// next spawn should start fresh at the top of the history ladder.
|
|
1122
|
+
this.tooLargeRecoveries.delete(chatId);
|
|
1123
|
+
this.tooLargeExhausted.delete(chatId);
|
|
1088
1124
|
// Kill old process so next message spawns fresh
|
|
1089
1125
|
this.restartProcess(chatId).catch(() => { });
|
|
1090
1126
|
}
|
|
@@ -1156,6 +1192,54 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1156
1192
|
}
|
|
1157
1193
|
// Process will be re-spawned on next incoming message
|
|
1158
1194
|
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Unified recovery for the recoverable "Request too large (max 32MB)" error.
|
|
1197
|
+
* Reached from two backends that surface the SAME error differently:
|
|
1198
|
+
* - PTY shell (headless=false): a `system/request_too_large` event emitted by
|
|
1199
|
+
* the transcript tailer from the authoritative <synthetic> record (Bug A).
|
|
1200
|
+
* - Headless (headless=true): claude --print emits a synthetic `result`
|
|
1201
|
+
* (is_error + "Request too large (max"); the long-lived process otherwise
|
|
1202
|
+
* stays alive and rejects every subsequent turn forever (Bug B).
|
|
1203
|
+
*
|
|
1204
|
+
* Each consecutive recovery shrinks the history re-injected on the next spawn
|
|
1205
|
+
* (TOO_LARGE_HISTORY_LADDER: 50→40→30→20→10→0) so a pathological context drops
|
|
1206
|
+
* under the 32MB ceiling. The respawn happens on the user's NEXT message (no
|
|
1207
|
+
* auto-loop), and the counter resets on the next successful result. Once even a
|
|
1208
|
+
* zero-history spawn still trips 32MB, stop escalating and ask the user to
|
|
1209
|
+
* /clear rather than climb the ladder again.
|
|
1210
|
+
*/
|
|
1211
|
+
handleRequestTooLarge(mapKey, proc) {
|
|
1212
|
+
proc.setProcessing(false);
|
|
1213
|
+
const count = (this.tooLargeRecoveries.get(mapKey) ?? 0) + 1;
|
|
1214
|
+
const lastRung = TOO_LARGE_HISTORY_LADDER.length - 1; // index of the 0-history rung
|
|
1215
|
+
if (count > lastRung) {
|
|
1216
|
+
// Even the zero-history spawn tripped 32MB — context can't shrink further.
|
|
1217
|
+
// Pin the counter at the last rung and always surface the /clear next step.
|
|
1218
|
+
this.tooLargeRecoveries.set(mapKey, lastRung);
|
|
1219
|
+
this.logger.error('Request too large persists with zero re-injected history', { mapKey, count });
|
|
1220
|
+
this.writeAutoForward(mapKey, '⚠️ ยังเกิน 32MB แม้จะล้าง context จนว่างแล้ว — พิมพ์ /clear เพื่อเริ่มเซสชันใหม่ หรือ /restart ค่ะ');
|
|
1221
|
+
// Restart ONCE to clear the wedged process the first time the ladder is
|
|
1222
|
+
// exhausted; thereafter stop restarting (no churn) and let the user /clear.
|
|
1223
|
+
if (!this.tooLargeExhausted.has(mapKey)) {
|
|
1224
|
+
this.tooLargeExhausted.add(mapKey);
|
|
1225
|
+
void this.restartProcess(mapKey);
|
|
1226
|
+
}
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
this.tooLargeRecoveries.set(mapKey, count);
|
|
1230
|
+
this.logger.warn('Request too large (32MB) — restarting with reduced history', {
|
|
1231
|
+
mapKey, attempt: count, nextHistoryLimit: TOO_LARGE_HISTORY_LADDER[count],
|
|
1232
|
+
});
|
|
1233
|
+
// Ordering matters and makes the notice delivery race-free: writeAutoForward
|
|
1234
|
+
// persists the `.forward` file synchronously HERE, before restartProcess()
|
|
1235
|
+
// begins its async stop/kill. The typing-loop tear-down (stop() in typing.ts)
|
|
1236
|
+
// drains and sends `.forward` synchronously before it removes the typing
|
|
1237
|
+
// signal, so by the time the proc exit fires and the loop stops, the file is
|
|
1238
|
+
// already on disk and is delivered — no dependency on poll timing. Do not
|
|
1239
|
+
// reorder restartProcess() ahead of writeAutoForward().
|
|
1240
|
+
this.writeAutoForward(mapKey, '⚠️ Context too large — hit Anthropic\'s 32MB request limit (usually from large images or files in context). Restarting this session with a fresh context. Your last message was not processed — please resend it.');
|
|
1241
|
+
void this.restartProcess(mapKey);
|
|
1242
|
+
}
|
|
1159
1243
|
/**
|
|
1160
1244
|
* Stop all idle session subprocesses so they re-spawn with the latest
|
|
1161
1245
|
* system prompt on the next incoming message.
|