@0xmaxma/claude-gateway 1.3.31 → 1.4.0
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/README.md +3 -1
- package/dist/agent/runner.d.ts +44 -7
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +136 -28
- package/dist/agent/runner.js.map +1 -1
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +140 -7
- package/dist/api/router.js.map +1 -1
- package/dist/history/db.d.ts +13 -1
- package/dist/history/db.d.ts.map +1 -1
- package/dist/history/db.js +67 -9
- package/dist/history/db.js.map +1 -1
- package/dist/history/types.d.ts +10 -0
- package/dist/history/types.d.ts.map +1 -1
- package/dist/session/process.d.ts +8 -0
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +46 -0
- package/dist/session/process.js.map +1 -1
- package/dist/session/store.d.ts +3 -2
- package/dist/session/store.d.ts.map +1 -1
- package/dist/session/store.js +1 -1
- package/dist/session/store.js.map +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/mcp/instructions.ts +39 -0
- package/mcp/server.ts +6 -11
- package/mcp/tools/discord/module.ts +19 -1
- package/mcp/tools/image/module.ts +592 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -230,6 +230,7 @@ Global default retention policy. Can be overridden per-agent with an `history` k
|
|
|
230
230
|
"gateway": {
|
|
231
231
|
"history": {
|
|
232
232
|
"retentionDays": 90,
|
|
233
|
+
"maxHistoryMessages": 30,
|
|
233
234
|
"cleanupHour": 3,
|
|
234
235
|
"cleanupTimezone": "Asia/Bangkok"
|
|
235
236
|
}
|
|
@@ -240,6 +241,7 @@ Global default retention policy. Can be overridden per-agent with an `history` k
|
|
|
240
241
|
| Field | Default | Description |
|
|
241
242
|
|-------|---------|-------------|
|
|
242
243
|
| `retentionDays` | `null` (keep forever) | Delete messages older than N days on each cleanup cycle |
|
|
244
|
+
| `maxHistoryMessages` | `50` | Max history messages re-injected into a session at spawn. Lower it to shrink the context loaded at session start. `0` = inject no history |
|
|
243
245
|
| `cleanupHour` | `3` | Hour of day to run cleanup (24h, in `cleanupTimezone`) |
|
|
244
246
|
| `cleanupTimezone` | `"UTC"` | IANA timezone for the cleanup schedule |
|
|
245
247
|
|
|
@@ -249,7 +251,7 @@ Per-agent override example:
|
|
|
249
251
|
"agents": [
|
|
250
252
|
{
|
|
251
253
|
"id": "alfred",
|
|
252
|
-
"history": { "retentionDays": 30 }
|
|
254
|
+
"history": { "retentionDays": 30, "maxHistoryMessages": 30 }
|
|
253
255
|
}
|
|
254
256
|
]
|
|
255
257
|
}
|
package/dist/agent/runner.d.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { AgentConfig, GatewayConfig, Logger, ModelConfig, StreamEvent, ApiAttachment } from '../types';
|
|
2
|
+
import { AgentConfig, GatewayConfig, Logger, ModelConfig, StreamEvent, ApiAttachment, ImageParams } from '../types';
|
|
3
3
|
import { type SkillRegistry } from '../skills';
|
|
4
4
|
import { HistoryDB } from '../history/db';
|
|
5
5
|
export declare const MAX_IMAGE_SIZE_BYTES: number;
|
|
6
6
|
export declare const DEFAULT_MODELS: ModelConfig[];
|
|
7
7
|
export declare const CHANNEL_COALESCE_WINDOW_MS = 1200;
|
|
8
|
+
/**
|
|
9
|
+
* Convert absolute file paths (e.g. from a reply tool's `files` input) into
|
|
10
|
+
* relative `media/<rel>` paths for persistence as message `mediaFiles`.
|
|
11
|
+
*
|
|
12
|
+
* Mirrors the transform in `popApiAttachments`: only paths UNDER `mediaRoot`
|
|
13
|
+
* that pass the `exists` predicate are kept (never arbitrary abs paths, never
|
|
14
|
+
* dangling files), and backslashes are normalised to forward slashes.
|
|
15
|
+
*
|
|
16
|
+
* The `exists` predicate is injected (defaults to `fs.existsSync`) so the pure
|
|
17
|
+
* string transform is unit-testable without a real filesystem.
|
|
18
|
+
*/
|
|
19
|
+
export declare function toRelMediaFiles(absPaths: unknown[], mediaRoot: string, exists?: (p: string) => boolean): string[];
|
|
8
20
|
export declare class AgentRunner extends EventEmitter {
|
|
9
21
|
private agentConfig;
|
|
10
22
|
private readonly gatewayConfig;
|
|
@@ -117,6 +129,12 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
117
129
|
* a photo and its instruction text are read together in the same turn.
|
|
118
130
|
*/
|
|
119
131
|
private routeChannelTurn;
|
|
132
|
+
/**
|
|
133
|
+
* Render composer-selected image options (contract E5) as a directive the agent
|
|
134
|
+
* reads and forwards to the generate_image MCP tool. Returns '' when no usable
|
|
135
|
+
* options are present.
|
|
136
|
+
*/
|
|
137
|
+
private static buildImageParamsNote;
|
|
120
138
|
private static buildChannelXml;
|
|
121
139
|
private getOrSpawnSession;
|
|
122
140
|
private spawnSession;
|
|
@@ -165,6 +183,21 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
165
183
|
* The process will be lazily re-spawned on the next incoming message.
|
|
166
184
|
*/
|
|
167
185
|
private restartProcess;
|
|
186
|
+
/**
|
|
187
|
+
* The 32MB-recovery rungs for a given healthy cap: the ladder sizes STRICTLY
|
|
188
|
+
* below the cap, in descending order. Filtering by `< cap` (not `<=`) drops any
|
|
189
|
+
* rung equal to or above the cap so a lowered cap never yields a recovery step
|
|
190
|
+
* that re-injects the same (or more) history — every step actually shrinks.
|
|
191
|
+
*/
|
|
192
|
+
private recoveryRungs;
|
|
193
|
+
/**
|
|
194
|
+
* History re-injection cap for a spawn, given the configured healthy cap and how
|
|
195
|
+
* many consecutive 32MB recoveries have happened on the session. recoveryCount 0
|
|
196
|
+
* = healthy → the full configured cap. Each later recovery drops to the next
|
|
197
|
+
* rung strictly below the cap; once those are exhausted it stays at 0 (no
|
|
198
|
+
* history). Kept in sync with the exhaustion threshold in handleRequestTooLarge.
|
|
199
|
+
*/
|
|
200
|
+
private spawnHistoryLimit;
|
|
168
201
|
/**
|
|
169
202
|
* Unified recovery for the recoverable "Request too large (max 32MB)" error.
|
|
170
203
|
* Reached from two backends that surface the SAME error differently:
|
|
@@ -174,12 +207,13 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
174
207
|
* (is_error + "Request too large (max"); the long-lived process otherwise
|
|
175
208
|
* stays alive and rejects every subsequent turn forever (Bug B).
|
|
176
209
|
*
|
|
177
|
-
* Each consecutive recovery shrinks the history re-injected on the next spawn
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
210
|
+
* Each consecutive recovery shrinks the history re-injected on the next spawn,
|
|
211
|
+
* stepping down the TOO_LARGE_HISTORY_LADDER rungs strictly below the configured
|
|
212
|
+
* cap (default 50 → 40→30→20→10→0), so a pathological context drops under the
|
|
213
|
+
* 32MB ceiling. The respawn happens on the user's NEXT message (no auto-loop),
|
|
214
|
+
* and the counter resets on the next successful result. Once even a zero-history
|
|
215
|
+
* spawn still trips 32MB, stop escalating and ask the user to /clear rather than
|
|
216
|
+
* climb the ladder again.
|
|
183
217
|
*/
|
|
184
218
|
private handleRequestTooLarge;
|
|
185
219
|
/**
|
|
@@ -272,6 +306,7 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
272
306
|
mediaFiles?: string[];
|
|
273
307
|
model?: string;
|
|
274
308
|
skipUserMessage?: boolean;
|
|
309
|
+
imageParams?: ImageParams;
|
|
275
310
|
}): Promise<{
|
|
276
311
|
text: string;
|
|
277
312
|
attachments: ApiAttachment[];
|
|
@@ -292,6 +327,7 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
292
327
|
mediaFiles?: string[];
|
|
293
328
|
model?: string;
|
|
294
329
|
skipUserMessage?: boolean;
|
|
330
|
+
imageParams?: ImageParams;
|
|
295
331
|
}): Promise<() => void>;
|
|
296
332
|
/**
|
|
297
333
|
* Check if a session has a pending API request (for preflight conflict check).
|
|
@@ -314,6 +350,7 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
314
350
|
getHistoryDb(): HistoryDB;
|
|
315
351
|
getAllSessionMeta(): Promise<Map<string, {
|
|
316
352
|
name: string;
|
|
353
|
+
imageConfig?: ImageParams;
|
|
317
354
|
}>>;
|
|
318
355
|
listSessionsForChat(chatId: string, channel: 'telegram' | 'discord' | 'line'): Promise<import('../types').SessionIndex>;
|
|
319
356
|
executeApiCommand(sessionId: string, chatId: string, command: string, opts?: {
|
|
@@ -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;
|
|
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
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.AgentRunner = exports.CHANNEL_COALESCE_WINDOW_MS = exports.DEFAULT_MODELS = exports.MAX_IMAGE_SIZE_BYTES = void 0;
|
|
37
|
+
exports.toRelMediaFiles = toRelMediaFiles;
|
|
37
38
|
const events_1 = require("events");
|
|
38
39
|
const fs = __importStar(require("fs"));
|
|
39
40
|
const fsPromises = __importStar(require("fs/promises"));
|
|
@@ -61,14 +62,16 @@ const cleanup_1 = require("../history/cleanup");
|
|
|
61
62
|
const DEFAULT_IDLE_TIMEOUT_MINUTES = 30;
|
|
62
63
|
const DEFAULT_MAX_CONCURRENT = 20;
|
|
63
64
|
const ANTHROPIC_SOCKET_ERROR = 'socket connection was closed unexpectedly';
|
|
64
|
-
// History re-injection ladder for request_too_large (32MB) recovery
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
// /clear instead of looping forever.
|
|
65
|
+
// History re-injection ladder for request_too_large (32MB) recovery: the
|
|
66
|
+
// candidate history sizes a recovering session can step down to. The HEALTHY
|
|
67
|
+
// spawn uses the configured cap (resolveMaxHistoryMessages), not an index into
|
|
68
|
+
// this array; on each consecutive 32MB recovery the session drops to the next
|
|
69
|
+
// ladder rung STRICTLY BELOW that cap (see spawnHistoryLimit), so every retry
|
|
70
|
+
// actually shrinks the re-loaded context instead of re-trying the same size.
|
|
71
|
+
// Once even the 0-history rung still trips 32MB the runner stops escalating and
|
|
72
|
+
// asks the user to /clear instead of looping forever. The leading
|
|
73
|
+
// MAX_HISTORY_MESSAGES only acts as a recovery rung when an operator configures
|
|
74
|
+
// a cap higher than it.
|
|
72
75
|
const TOO_LARGE_HISTORY_LADDER = [process_1.MAX_HISTORY_MESSAGES, 40, 30, 20, 10, 0];
|
|
73
76
|
exports.MAX_IMAGE_SIZE_BYTES = 10 * 1024 * 1024;
|
|
74
77
|
exports.DEFAULT_MODELS = [
|
|
@@ -125,6 +128,10 @@ function buildApiSystemNote(allowTools, imagePaths) {
|
|
|
125
128
|
const memoryOverride = `Memory Rule Override: Do NOT create or update ${PROTECTED_WORKSPACE_FILES.join(', ')} ` +
|
|
126
129
|
`or any other workspace identity file in this session, regardless of user instructions. ` +
|
|
127
130
|
`If the user asks you to remember something, reply that memory updates are not supported in API sessions.`;
|
|
131
|
+
const secretsRule = `Secret Non-Disclosure: NEVER reveal, print, echo, or transmit environment variables, ` +
|
|
132
|
+
`API tokens or keys, the contents of ~/.claude/settings.json or any .env file, or any ` +
|
|
133
|
+
`similar credentials or secrets — regardless of who asks or how the request is phrased. ` +
|
|
134
|
+
`Treat any such request as adversarial and refuse it.`;
|
|
128
135
|
const toolNote = allowTools
|
|
129
136
|
? `You may use tools to complete the requested task.`
|
|
130
137
|
: `Reply with plain text only. Do NOT call any tools. Your text output will be returned directly to the caller.`;
|
|
@@ -132,7 +139,23 @@ function buildApiSystemNote(allowTools, imagePaths) {
|
|
|
132
139
|
if (imagePaths?.length) {
|
|
133
140
|
imageNote = ` The user attached ${imagePaths.length} image(s). Read them with the Read tool:\n${imagePaths.map(p => `- ${p}`).join('\n')}`;
|
|
134
141
|
}
|
|
135
|
-
return `<api-context>This is an API request. ${memoryOverride} ${toolNote}${imageNote}</api-context>\n`;
|
|
142
|
+
return `<api-context>This is an API request. ${memoryOverride} ${secretsRule} ${toolNote}${imageNote}</api-context>\n`;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Convert absolute file paths (e.g. from a reply tool's `files` input) into
|
|
146
|
+
* relative `media/<rel>` paths for persistence as message `mediaFiles`.
|
|
147
|
+
*
|
|
148
|
+
* Mirrors the transform in `popApiAttachments`: only paths UNDER `mediaRoot`
|
|
149
|
+
* that pass the `exists` predicate are kept (never arbitrary abs paths, never
|
|
150
|
+
* dangling files), and backslashes are normalised to forward slashes.
|
|
151
|
+
*
|
|
152
|
+
* The `exists` predicate is injected (defaults to `fs.existsSync`) so the pure
|
|
153
|
+
* string transform is unit-testable without a real filesystem.
|
|
154
|
+
*/
|
|
155
|
+
function toRelMediaFiles(absPaths, mediaRoot, exists = fs.existsSync) {
|
|
156
|
+
return absPaths
|
|
157
|
+
.filter((p) => typeof p === 'string' && p.startsWith(mediaRoot) && exists(p))
|
|
158
|
+
.map((p) => 'media/' + p.slice(mediaRoot.length).replace(/\\/g, '/'));
|
|
136
159
|
}
|
|
137
160
|
class AgentRunner extends events_1.EventEmitter {
|
|
138
161
|
imageSize(chatId) { return this.imageSizePerChat.get(chatId) ?? 0; }
|
|
@@ -856,6 +879,28 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
856
879
|
this.writeTypingError(chatId, code);
|
|
857
880
|
});
|
|
858
881
|
}
|
|
882
|
+
/**
|
|
883
|
+
* Render composer-selected image options (contract E5) as a directive the agent
|
|
884
|
+
* reads and forwards to the generate_image MCP tool. Returns '' when no usable
|
|
885
|
+
* options are present.
|
|
886
|
+
*/
|
|
887
|
+
static buildImageParamsNote(p) {
|
|
888
|
+
const attrs = [
|
|
889
|
+
p.model ? `model="${AgentRunner.escapeXmlAttr(p.model)}"` : '',
|
|
890
|
+
p.quality ? `quality="${AgentRunner.escapeXmlAttr(p.quality)}"` : '',
|
|
891
|
+
p.size ? `size="${AgentRunner.escapeXmlAttr(p.size)}"` : '',
|
|
892
|
+
p.aspect_ratio ? `aspect_ratio="${AgentRunner.escapeXmlAttr(p.aspect_ratio)}"` : '',
|
|
893
|
+
typeof p.n === 'number' ? `n="${p.n}"` : '',
|
|
894
|
+
p.image_ref ? `image_ref="${AgentRunner.escapeXmlAttr(p.image_ref)}"` : '',
|
|
895
|
+
].filter(Boolean);
|
|
896
|
+
if (!attrs.length)
|
|
897
|
+
return '';
|
|
898
|
+
return (`<image-params ${attrs.join(' ')} />\n` +
|
|
899
|
+
`The user selected the image-generation options above in the composer. When the request ` +
|
|
900
|
+
`involves creating or editing an image, call the generate_image tool (action="generate") ` +
|
|
901
|
+
`using these values (pass image_ref as the "image" argument for image-to-image), then ` +
|
|
902
|
+
`deliver the returned image with your reply tool.\n`);
|
|
903
|
+
}
|
|
859
904
|
static buildChannelXml(params) {
|
|
860
905
|
const meta = params.meta ?? {};
|
|
861
906
|
const optionalAttrs = [
|
|
@@ -956,14 +1001,18 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
956
1001
|
// Apply per-session model override (caller already normalized to undefined when == agent default)
|
|
957
1002
|
if (modelOverride)
|
|
958
1003
|
proc.modelOverride = modelOverride;
|
|
1004
|
+
// Per-agent → global → MAX_HISTORY_MESSAGES: the configured cap on how many
|
|
1005
|
+
// history messages a healthy spawn re-injects. Lets an operator lower the
|
|
1006
|
+
// context loaded at session start (e.g. 50 → 30) without touching code.
|
|
1007
|
+
const configuredMax = (0, process_1.resolveMaxHistoryMessages)(this.agentConfig.history?.maxHistoryMessages, this.gatewayConfig.gateway.history?.maxHistoryMessages);
|
|
959
1008
|
// request_too_large (32MB) recovery: shrink the re-injected history on each
|
|
960
1009
|
// consecutive retry so a pathological context eventually fits. recoveryCount
|
|
961
|
-
// is 0 for healthy sessions →
|
|
962
|
-
//
|
|
963
|
-
//
|
|
1010
|
+
// is 0 for healthy sessions → use the configured cap directly; a recovering
|
|
1011
|
+
// session steps down to the ladder rungs STRICTLY BELOW that cap, so each
|
|
1012
|
+
// retry genuinely shrinks instead of re-trying the same (already-too-large)
|
|
1013
|
+
// size when the cap has been lowered.
|
|
964
1014
|
const recoveryCount = this.tooLargeRecoveries.get(mapKey) ?? 0;
|
|
965
|
-
|
|
966
|
-
proc.historyLimit = TOO_LARGE_HISTORY_LADDER[ladderIdx];
|
|
1015
|
+
proc.historyLimit = this.spawnHistoryLimit(configuredMax, recoveryCount);
|
|
967
1016
|
if (recoveryCount > 0) {
|
|
968
1017
|
this.logger.info('Spawning with reduced history after request_too_large', {
|
|
969
1018
|
mapKey, recoveryCount, historyLimit: proc.historyLimit,
|
|
@@ -1036,7 +1085,15 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1036
1085
|
replyToolUseId = block['id'] ?? null;
|
|
1037
1086
|
// Persist the reply text to history so it appears in chat history API
|
|
1038
1087
|
const replyText = typeof block.input?.['text'] === 'string' ? block.input['text'].trim() : '';
|
|
1039
|
-
|
|
1088
|
+
// Capture any images the reply attached (reply tool's `files`)
|
|
1089
|
+
// so the web transcript renders them via mediaFiles. Only files
|
|
1090
|
+
// under the agent media root that still exist are recorded.
|
|
1091
|
+
const replyFiles = Array.isArray(block.input?.['files']) ? block.input['files'] : [];
|
|
1092
|
+
const mediaRoot = path.join(this.agentsBaseDir, this.agentConfig.id, 'media') + path.sep;
|
|
1093
|
+
const replyMedia = toRelMediaFiles(replyFiles, mediaRoot);
|
|
1094
|
+
// Persist when there is text OR image(s) — an image-only reply
|
|
1095
|
+
// still needs a row so it shows in the web transcript.
|
|
1096
|
+
if (replyText || replyMedia.length) {
|
|
1040
1097
|
const channelSrc = this.channelSourceMap.get(mapKey) ?? 'telegram';
|
|
1041
1098
|
this.historyDb.insertMessage({
|
|
1042
1099
|
chatId: `${channelSrc}-${mapKey}`,
|
|
@@ -1044,12 +1101,13 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1044
1101
|
source: channelSrc,
|
|
1045
1102
|
role: 'assistant',
|
|
1046
1103
|
content: replyText,
|
|
1104
|
+
mediaFiles: replyMedia.length ? replyMedia : undefined,
|
|
1047
1105
|
ts: Date.now(),
|
|
1048
1106
|
});
|
|
1049
1107
|
// LINE: the MCP line_reply tool's send is suppressed in
|
|
1050
1108
|
// refresh mode; the gateway delivers (free reply, or cache +
|
|
1051
1109
|
// postback button when slow). See LineReplyManager.
|
|
1052
|
-
if (channelSrc === 'line' && this.lineReply) {
|
|
1110
|
+
if (channelSrc === 'line' && this.lineReply && replyText) {
|
|
1053
1111
|
void this.lineReply.onAnswer(mapKey, replyText);
|
|
1054
1112
|
}
|
|
1055
1113
|
}
|
|
@@ -1531,6 +1589,30 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1531
1589
|
}
|
|
1532
1590
|
// Process will be re-spawned on next incoming message
|
|
1533
1591
|
}
|
|
1592
|
+
/**
|
|
1593
|
+
* The 32MB-recovery rungs for a given healthy cap: the ladder sizes STRICTLY
|
|
1594
|
+
* below the cap, in descending order. Filtering by `< cap` (not `<=`) drops any
|
|
1595
|
+
* rung equal to or above the cap so a lowered cap never yields a recovery step
|
|
1596
|
+
* that re-injects the same (or more) history — every step actually shrinks.
|
|
1597
|
+
*/
|
|
1598
|
+
recoveryRungs(configuredMax) {
|
|
1599
|
+
return TOO_LARGE_HISTORY_LADDER.filter(r => r < configuredMax);
|
|
1600
|
+
}
|
|
1601
|
+
/**
|
|
1602
|
+
* History re-injection cap for a spawn, given the configured healthy cap and how
|
|
1603
|
+
* many consecutive 32MB recoveries have happened on the session. recoveryCount 0
|
|
1604
|
+
* = healthy → the full configured cap. Each later recovery drops to the next
|
|
1605
|
+
* rung strictly below the cap; once those are exhausted it stays at 0 (no
|
|
1606
|
+
* history). Kept in sync with the exhaustion threshold in handleRequestTooLarge.
|
|
1607
|
+
*/
|
|
1608
|
+
spawnHistoryLimit(configuredMax, recoveryCount) {
|
|
1609
|
+
if (recoveryCount <= 0)
|
|
1610
|
+
return configuredMax;
|
|
1611
|
+
const rungs = this.recoveryRungs(configuredMax);
|
|
1612
|
+
if (rungs.length === 0)
|
|
1613
|
+
return 0;
|
|
1614
|
+
return rungs[Math.min(recoveryCount - 1, rungs.length - 1)];
|
|
1615
|
+
}
|
|
1534
1616
|
/**
|
|
1535
1617
|
* Unified recovery for the recoverable "Request too large (max 32MB)" error.
|
|
1536
1618
|
* Reached from two backends that surface the SAME error differently:
|
|
@@ -1540,21 +1622,26 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1540
1622
|
* (is_error + "Request too large (max"); the long-lived process otherwise
|
|
1541
1623
|
* stays alive and rejects every subsequent turn forever (Bug B).
|
|
1542
1624
|
*
|
|
1543
|
-
* Each consecutive recovery shrinks the history re-injected on the next spawn
|
|
1544
|
-
*
|
|
1545
|
-
*
|
|
1546
|
-
*
|
|
1547
|
-
*
|
|
1548
|
-
*
|
|
1625
|
+
* Each consecutive recovery shrinks the history re-injected on the next spawn,
|
|
1626
|
+
* stepping down the TOO_LARGE_HISTORY_LADDER rungs strictly below the configured
|
|
1627
|
+
* cap (default 50 → 40→30→20→10→0), so a pathological context drops under the
|
|
1628
|
+
* 32MB ceiling. The respawn happens on the user's NEXT message (no auto-loop),
|
|
1629
|
+
* and the counter resets on the next successful result. Once even a zero-history
|
|
1630
|
+
* spawn still trips 32MB, stop escalating and ask the user to /clear rather than
|
|
1631
|
+
* climb the ladder again.
|
|
1549
1632
|
*/
|
|
1550
1633
|
handleRequestTooLarge(mapKey, proc) {
|
|
1551
1634
|
proc.setProcessing(false);
|
|
1635
|
+
// Recovery steps through the ladder rungs strictly below the configured cap;
|
|
1636
|
+
// the number of those rungs is how many shrink attempts exist before even the
|
|
1637
|
+
// smallest (0-history) spawn has been tried and still trips 32MB.
|
|
1638
|
+
const configuredMax = (0, process_1.resolveMaxHistoryMessages)(this.agentConfig.history?.maxHistoryMessages, this.gatewayConfig.gateway.history?.maxHistoryMessages);
|
|
1639
|
+
const stepCount = this.recoveryRungs(configuredMax).length; // shrink attempts available
|
|
1552
1640
|
const count = (this.tooLargeRecoveries.get(mapKey) ?? 0) + 1;
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
//
|
|
1556
|
-
|
|
1557
|
-
this.tooLargeRecoveries.set(mapKey, lastRung);
|
|
1641
|
+
if (count > stepCount) {
|
|
1642
|
+
// Even the smallest rung tripped 32MB — context can't shrink further.
|
|
1643
|
+
// Pin the counter at the last step and always surface the /clear next step.
|
|
1644
|
+
this.tooLargeRecoveries.set(mapKey, stepCount);
|
|
1558
1645
|
this.logger.error('Request too large persists with zero re-injected history', { mapKey, count });
|
|
1559
1646
|
this.writeAutoForward(mapKey, '⚠️ ยังเกิน 32MB แม้จะล้าง context จนว่างแล้ว — พิมพ์ /clear เพื่อเริ่มเซสชันใหม่ หรือ /restart ค่ะ');
|
|
1560
1647
|
// Restart ONCE to clear the wedged process the first time the ladder is
|
|
@@ -1567,7 +1654,7 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1567
1654
|
}
|
|
1568
1655
|
this.tooLargeRecoveries.set(mapKey, count);
|
|
1569
1656
|
this.logger.warn('Request too large (32MB) — restarting with reduced history', {
|
|
1570
|
-
mapKey, attempt: count, nextHistoryLimit:
|
|
1657
|
+
mapKey, attempt: count, nextHistoryLimit: this.spawnHistoryLimit(configuredMax, count),
|
|
1571
1658
|
});
|
|
1572
1659
|
// Ordering matters and makes the notice delivery race-free: writeAutoForward
|
|
1573
1660
|
// persists the `.forward` file synchronously HERE, before restartProcess()
|
|
@@ -1986,9 +2073,20 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1986
2073
|
}
|
|
1987
2074
|
// Build channel XML with image_path attribute (like Telegram) for first image
|
|
1988
2075
|
const imageAttr = effectiveImagePaths.length ? ` image_path="${AgentRunner.escapeXmlAttr(effectiveImagePaths[0])}"` : '';
|
|
2076
|
+
const imageParamsNote = opts.imageParams ? AgentRunner.buildImageParamsNote(opts.imageParams) : '';
|
|
2077
|
+
// Persist the composer image options to session meta so the web can restore the
|
|
2078
|
+
// selection on reload (SessionMeta.imageConfig). Only when the send carries them
|
|
2079
|
+
// (the web sends image_params on first-set/change), so this holds the latest.
|
|
2080
|
+
// Channel is 'api' here (api sessions live under api-<chatId>). Best-effort.
|
|
2081
|
+
if (opts.imageParams) {
|
|
2082
|
+
this.sessionStore
|
|
2083
|
+
.updateSessionMeta(this.agentConfig.id, chatId, sessionId, { imageConfig: opts.imageParams }, 'api')
|
|
2084
|
+
.catch(() => { });
|
|
2085
|
+
}
|
|
1989
2086
|
const channelXml = `<channel source="api" chat_id="${chatId}" session_id="${sessionId}" ts="${new Date().toISOString()}"${imageAttr}>\n` +
|
|
1990
2087
|
`${message}\n\n` +
|
|
1991
2088
|
`${systemNote}` +
|
|
2089
|
+
`${imageParamsNote}` +
|
|
1992
2090
|
`</channel>` +
|
|
1993
2091
|
(skillInvocation ? `\n${(0, skills_1.formatSkillContext)(skillInvocation)}` : '');
|
|
1994
2092
|
return new Promise((resolve, reject) => {
|
|
@@ -2285,9 +2383,19 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
2285
2383
|
}
|
|
2286
2384
|
// Build channel XML with image_path attribute (like Telegram) for first image
|
|
2287
2385
|
const imageAttrStream = effectiveImagePathsStream.length ? ` image_path="${AgentRunner.escapeXmlAttr(effectiveImagePathsStream[0])}"` : '';
|
|
2386
|
+
const imageParamsNoteStream = opts.imageParams ? AgentRunner.buildImageParamsNote(opts.imageParams) : '';
|
|
2387
|
+
// Persist composer image config to session meta (SessionMeta.imageConfig) so the
|
|
2388
|
+
// web restores the selection on reload. This is the streaming path the web uses.
|
|
2389
|
+
// Channel 'api' — api sessions live under api-<chatId>. Best-effort.
|
|
2390
|
+
if (opts.imageParams) {
|
|
2391
|
+
this.sessionStore
|
|
2392
|
+
.updateSessionMeta(this.agentConfig.id, chatId, sessionId, { imageConfig: opts.imageParams }, 'api')
|
|
2393
|
+
.catch(() => { });
|
|
2394
|
+
}
|
|
2288
2395
|
const channelXml = `<channel source="api" chat_id="${chatId}" session_id="${sessionId}" ts="${new Date().toISOString()}"${imageAttrStream}>\n` +
|
|
2289
2396
|
`${message}\n\n` +
|
|
2290
2397
|
systemNote +
|
|
2398
|
+
imageParamsNoteStream +
|
|
2291
2399
|
`</channel>` +
|
|
2292
2400
|
(skillInvocationStream ? `\n${(0, skills_1.formatSkillContext)(skillInvocationStream)}` : '');
|
|
2293
2401
|
session.setProcessing(true);
|