@0xmaxma/claude-gateway 1.3.4 → 1.3.6
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 +1 -1
- package/config.template.json +9 -7
- package/dist/agent/runner.d.ts +20 -0
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +94 -1
- package/dist/agent/runner.js.map +1 -1
- package/dist/api/gateway-router.d.ts +14 -0
- package/dist/api/gateway-router.d.ts.map +1 -1
- package/dist/api/gateway-router.js +279 -7
- package/dist/api/gateway-router.js.map +1 -1
- package/dist/discord/receiver.d.ts +1 -0
- package/dist/discord/receiver.d.ts.map +1 -1
- package/dist/discord/receiver.js +7 -1
- package/dist/discord/receiver.js.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 +34 -0
- package/dist/session/process.js.map +1 -1
- package/dist/shell/claude-pty-shell.js +211 -4
- package/dist/shell/claude-pty-shell.js.map +1 -1
- package/dist/shell/emitter.d.ts +13 -0
- package/dist/shell/emitter.d.ts.map +1 -1
- package/dist/shell/emitter.js +16 -0
- package/dist/shell/emitter.js.map +1 -1
- package/dist/shell/menu-cancel.d.ts +50 -0
- package/dist/shell/menu-cancel.d.ts.map +1 -0
- package/dist/shell/menu-cancel.js +62 -0
- package/dist/shell/menu-cancel.js.map +1 -0
- package/dist/shell/pty-serialize.d.ts +23 -0
- package/dist/shell/pty-serialize.d.ts.map +1 -0
- package/dist/shell/pty-serialize.js +131 -0
- package/dist/shell/pty-serialize.js.map +1 -0
- package/dist/shell/pty-stream-registry.d.ts +59 -0
- package/dist/shell/pty-stream-registry.d.ts.map +1 -0
- package/dist/shell/pty-stream-registry.js +279 -0
- package/dist/shell/pty-stream-registry.js.map +1 -0
- package/dist/shell/screen.d.ts +43 -0
- package/dist/shell/screen.d.ts.map +1 -1
- package/dist/shell/screen.js +91 -1
- package/dist/shell/screen.js.map +1 -1
- package/dist/telegram/receiver.d.ts +1 -0
- package/dist/telegram/receiver.d.ts.map +1 -1
- package/dist/telegram/receiver.js +7 -1
- package/dist/telegram/receiver.js.map +1 -1
- package/dist/ui/web-ui.d.ts +2 -2
- package/dist/ui/web-ui.d.ts.map +1 -1
- package/dist/ui/web-ui.js +682 -114
- package/dist/ui/web-ui.js.map +1 -1
- package/mcp/tools/discord/module.ts +88 -1
- package/mcp/tools/discord/outbound.ts +36 -0
- package/mcp/tools/discord/types.ts +2 -0
- package/mcp/tools/telegram/menu-parser.ts +37 -0
- package/mcp/tools/telegram/receiver-server.ts +83 -0
- package/mcp/tools/telegram/typing.ts +7 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ A self-hosted multi-agent gateway for Claude Code. Connect Claude agents to Tele
|
|
|
29
29
|
- **App Store** — install, update, and host Docker-compose apps on the gateway; apps get a reverse proxy at `/app/:name/:portName/*`, optional Unix socket bridge for host scripts, and optional AI agent injection
|
|
30
30
|
- **Self-update API** — check for newer versions of `claude-gateway` and `claude-code` and trigger an update via a single API call; no SSH or shell access needed
|
|
31
31
|
- **Session persistence** — conversation history saved and restored across restarts
|
|
32
|
-
- **PTY
|
|
32
|
+
- **PTY shell (wrap-shell mode)** — optional interactive pseudo-terminal backend (`gateway.headless: false`) for tools that require a real TTY; includes a live browser viewer (xterm.js) and a `/api/v1/sessions/:sessionId/screen` endpoint that returns the visible screen as plain text — agents can poll it to detect hang states, menus, or unexpected output without parsing ANSI escape codes; app-agents always stay headless
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
package/config.template.json
CHANGED
|
@@ -10,17 +10,19 @@
|
|
|
10
10
|
"claude.dangerouslySkipPermissions"
|
|
11
11
|
]
|
|
12
12
|
},
|
|
13
|
-
"configVersion": "1.0.
|
|
13
|
+
"configVersion": "1.0.9",
|
|
14
14
|
"gateway": {
|
|
15
15
|
"logDir": "~/.claude-gateway/logs",
|
|
16
16
|
"timezone": "Asia/Bangkok",
|
|
17
17
|
"models": [
|
|
18
|
-
{ "id": "claude-fable-5", "label": "Fable 5",
|
|
19
|
-
{ "id": "claude-opus-4-8",
|
|
20
|
-
{ "id": "claude-
|
|
21
|
-
{ "id": "claude-opus-4-
|
|
22
|
-
{ "id": "claude-
|
|
23
|
-
{ "id": "claude-
|
|
18
|
+
{ "id": "claude-fable-5", "label": "Fable 5", "alias": "fable", "contextWindow": 1000000 },
|
|
19
|
+
{ "id": "claude-opus-4-8[1m]", "label": "Opus 4.8 (1M)", "alias": "opus[1m]", "contextWindow": 1000000 },
|
|
20
|
+
{ "id": "claude-sonnet-4-6[1m]", "label": "Sonnet 4.6 (1M)", "alias": "sonnet[1m]", "contextWindow": 1000000 },
|
|
21
|
+
{ "id": "claude-opus-4-8", "label": "Opus 4.8", "alias": "opus", "contextWindow": 200000 },
|
|
22
|
+
{ "id": "claude-opus-4-7", "label": "Opus 4.7", "alias": "opus47", "contextWindow": 200000 },
|
|
23
|
+
{ "id": "claude-opus-4-6", "label": "Opus 4.6", "alias": "opus46", "contextWindow": 200000 },
|
|
24
|
+
{ "id": "claude-sonnet-4-6", "label": "Sonnet 4.6", "alias": "sonnet", "contextWindow": 200000 },
|
|
25
|
+
{ "id": "claude-haiku-4-5-20251001", "label": "Haiku 4.5", "alias": "haiku", "contextWindow": 200000 }
|
|
24
26
|
],
|
|
25
27
|
"api": {
|
|
26
28
|
"keys": [
|
package/dist/agent/runner.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
29
29
|
private readonly sessionSpawnLocks;
|
|
30
30
|
private readonly pendingImagePaths;
|
|
31
31
|
private readonly pendingApiAttachments;
|
|
32
|
+
private readonly sessionHistory;
|
|
33
|
+
private readonly apiChatIds;
|
|
32
34
|
private skillRegistry;
|
|
33
35
|
private readonly configPath;
|
|
34
36
|
private readonly historyDb;
|
|
@@ -133,6 +135,13 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
133
135
|
private writeTypingDone;
|
|
134
136
|
private triggerSummaryAndRestart;
|
|
135
137
|
private writeAutoForward;
|
|
138
|
+
/**
|
|
139
|
+
* Signal the channel receiver to render an interactive menu as native UI
|
|
140
|
+
* (inline buttons on Telegram/Discord). The receiver maps each option to a
|
|
141
|
+
* `choice:N` callback whose tap arrives back as a normal "N" message — the
|
|
142
|
+
* same as the user typing the number.
|
|
143
|
+
*/
|
|
144
|
+
private writeMenuForward;
|
|
136
145
|
private startIdleCleaner;
|
|
137
146
|
start(): Promise<void>;
|
|
138
147
|
updateAgentConfig(newConfig: AgentConfig): void;
|
|
@@ -145,6 +154,17 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
145
154
|
private _startCleanupScheduler;
|
|
146
155
|
restart(): Promise<void>;
|
|
147
156
|
isRunning(): boolean;
|
|
157
|
+
getSessionsSummary(): Array<{
|
|
158
|
+
chatId: string;
|
|
159
|
+
sessionId: string;
|
|
160
|
+
source: string;
|
|
161
|
+
mode: string;
|
|
162
|
+
model: string;
|
|
163
|
+
isRunning: boolean;
|
|
164
|
+
spawnedAt: number;
|
|
165
|
+
uptimeSec: number;
|
|
166
|
+
tokens: number;
|
|
167
|
+
}>;
|
|
148
168
|
/**
|
|
149
169
|
* Send a message to an API session and wait for the response.
|
|
150
170
|
*
|
|
@@ -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;AAEvF,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAQ1C,eAAO,MAAM,oBAAoB,QAAmB,CAAC;AAErD,eAAO,MAAM,cAAc,EAAE,WAAW,EAMvC,CAAC;AAoDF,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,CAA6C;IAC9E,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,eAAe,CAAgC;IACvD,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;IAGhF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA+B;IAGjE,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA+B;IAGrE,OAAO,CAAC,aAAa,CAAwC;IAG7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAGpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IAGtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAGlC,OAAO,CAAC,aAAa,CAA6B;gBAEtC,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM;IAsBnF;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAI/C,gBAAgB,IAAI,aAAa;IAIjC,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED;;;OAGG;YACW,mBAAmB;IAuJjC;;;OAGG;YACW,oBAAoB;IAqLlC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,MAAM,CAAC,aAAa;IAI5B,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,MAAM,CAAC,eAAe;YAwChB,iBAAiB;YAgDjB,YAAY;
|
|
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
|
@@ -128,6 +128,12 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
128
128
|
this.pendingImagePaths = new Map();
|
|
129
129
|
// Buffers attachment file paths registered via api_reply tool for the current API session turn.
|
|
130
130
|
this.pendingApiAttachments = new Map();
|
|
131
|
+
// Session history ring-buffer (last 10 spawned, newest first)
|
|
132
|
+
this.sessionHistory = [];
|
|
133
|
+
// For API sessions the map key is the sessionId, so the real caller chatId
|
|
134
|
+
// (e.g. the app/agent identifier) is not captured at spawn. Record it here
|
|
135
|
+
// keyed by sessionId so the dashboard can show the actual chat id.
|
|
136
|
+
this.apiChatIds = new Map();
|
|
131
137
|
// Skill registry for detecting /skill-name commands in user messages
|
|
132
138
|
this.skillRegistry = { skills: new Map() };
|
|
133
139
|
// Cancel function for the daily history cleanup timer
|
|
@@ -619,6 +625,9 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
619
625
|
// Auto-forward result text to channel if agent didn't call reply tool.
|
|
620
626
|
let replyCalled = false;
|
|
621
627
|
let replyToolUseId = null; // track id to detect failed tool calls
|
|
628
|
+
// Set when an interactive-menu prompt was rendered to the channel this turn,
|
|
629
|
+
// so the result's plain-text auto-forward is skipped (no duplicate message).
|
|
630
|
+
let menuSentThisTurn = false;
|
|
622
631
|
let typingDoneTimer = null;
|
|
623
632
|
const TYPING_DONE_DELAY_MS = 3000;
|
|
624
633
|
const replyToolName = source === 'discord' ? 'mcp__gateway__discord_reply' : 'mcp__gateway__telegram_reply';
|
|
@@ -667,6 +676,31 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
667
676
|
}
|
|
668
677
|
}
|
|
669
678
|
}
|
|
679
|
+
// Interactive select menu blocking the PTY: render it as channel-native
|
|
680
|
+
// UI (inline buttons). This output handler only runs for Telegram/Discord
|
|
681
|
+
// sessions; API uses a separate path and falls back to the result text's
|
|
682
|
+
// numbered list (no buttons), as intended.
|
|
683
|
+
if (obj['type'] === 'system' && obj['subtype'] === 'menu_prompt') {
|
|
684
|
+
const promptText = typeof obj['prompt'] === 'string' ? obj['prompt'] : '';
|
|
685
|
+
const rawOptions = Array.isArray(obj['options']) ? obj['options'] : [];
|
|
686
|
+
const options = rawOptions
|
|
687
|
+
.map((o) => ({ label: typeof o?.label === 'string' ? o.label : '' }))
|
|
688
|
+
.filter((o) => o.label);
|
|
689
|
+
if (promptText && options.length) {
|
|
690
|
+
this.writeMenuForward(mapKey, promptText, options);
|
|
691
|
+
menuSentThisTurn = true;
|
|
692
|
+
// Persist the question to chat history so it's visible in the transcript.
|
|
693
|
+
const channelSrc = this.channelSourceMap.get(mapKey) ?? 'telegram';
|
|
694
|
+
this.historyDb.insertMessage({
|
|
695
|
+
chatId: `${channelSrc}-${mapKey}`,
|
|
696
|
+
sessionId: actualSessionId,
|
|
697
|
+
source: channelSrc,
|
|
698
|
+
role: 'assistant',
|
|
699
|
+
content: promptText,
|
|
700
|
+
ts: Date.now(),
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
}
|
|
670
704
|
if (obj['type'] === 'result') {
|
|
671
705
|
proc.setProcessing(false);
|
|
672
706
|
// Telegram: accumulate image size via stat of local file (FIFO, one per turn)
|
|
@@ -699,7 +733,9 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
699
733
|
// Suppress the corrupted-thinking 400: the session auto-respawns to recover,
|
|
700
734
|
// so the raw API error must not reach the user's chat or the history DB.
|
|
701
735
|
const isThinkingCorruption = obj['is_error'] === true && process_1.SessionProcess.isThinkingCorruptionError(resultText);
|
|
702
|
-
|
|
736
|
+
// Skip when a menu was rendered to buttons this turn — the result
|
|
737
|
+
// text is the same numbered list and would duplicate the menu message.
|
|
738
|
+
if (resultText.trim() && !proc.queryMode && !replyCalled && !isThinkingCorruption && !menuSentThisTurn) {
|
|
703
739
|
const text = resultText.trim();
|
|
704
740
|
const channelSrcForResult = this.channelSourceMap.get(mapKey) ?? 'telegram';
|
|
705
741
|
// Persist assistant reply to permanent history DB
|
|
@@ -721,6 +757,7 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
721
757
|
}
|
|
722
758
|
replyCalled = false; // reset for next turn
|
|
723
759
|
replyToolUseId = null;
|
|
760
|
+
menuSentThisTurn = false;
|
|
724
761
|
// Delay typing done — agent may continue with more work
|
|
725
762
|
typingDoneTimer = setTimeout(() => {
|
|
726
763
|
this.writeTypingDone(mapKey);
|
|
@@ -775,6 +812,9 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
775
812
|
});
|
|
776
813
|
}
|
|
777
814
|
this.sessions.set(mapKey, proc);
|
|
815
|
+
this.sessionHistory.unshift({ chatId: mapKey, sessionId: proc.sessionId, source: proc.source, mode: proc.backend, model: proc.model, spawnedAt: proc.spawnedAt });
|
|
816
|
+
if (this.sessionHistory.length > 10)
|
|
817
|
+
this.sessionHistory.length = 10;
|
|
778
818
|
if (source === 'telegram' || source === 'discord') {
|
|
779
819
|
this.channelSourceMap.set(mapKey, source);
|
|
780
820
|
}
|
|
@@ -1112,6 +1152,27 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1112
1152
|
// Non-fatal
|
|
1113
1153
|
}
|
|
1114
1154
|
}
|
|
1155
|
+
/**
|
|
1156
|
+
* Signal the channel receiver to render an interactive menu as native UI
|
|
1157
|
+
* (inline buttons on Telegram/Discord). The receiver maps each option to a
|
|
1158
|
+
* `choice:N` callback whose tap arrives back as a normal "N" message — the
|
|
1159
|
+
* same as the user typing the number.
|
|
1160
|
+
*/
|
|
1161
|
+
writeMenuForward(chatId, text, options) {
|
|
1162
|
+
const typingDir = this.getTypingDir(chatId);
|
|
1163
|
+
try {
|
|
1164
|
+
fs.mkdirSync(typingDir, { recursive: true });
|
|
1165
|
+
// Write atomically (tmp + rename): the receiver polls this directory every
|
|
1166
|
+
// second, so a non-atomic write could be read mid-flush as truncated JSON.
|
|
1167
|
+
const finalPath = path.join(typingDir, `${chatId}.menu`);
|
|
1168
|
+
const tmpPath = `${finalPath}.tmp`;
|
|
1169
|
+
fs.writeFileSync(tmpPath, JSON.stringify({ text, options }));
|
|
1170
|
+
fs.renameSync(tmpPath, finalPath);
|
|
1171
|
+
}
|
|
1172
|
+
catch {
|
|
1173
|
+
// Non-fatal — the result text still carries the numbered list as a fallback.
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1115
1176
|
startIdleCleaner() {
|
|
1116
1177
|
this.idleCleanerTimer = setInterval(async () => {
|
|
1117
1178
|
for (const [id, proc] of this.sessions) {
|
|
@@ -1220,6 +1281,34 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1220
1281
|
isRunning() {
|
|
1221
1282
|
return this.receiver?.isRunning() ?? false;
|
|
1222
1283
|
}
|
|
1284
|
+
getSessionsSummary() {
|
|
1285
|
+
const now = Date.now();
|
|
1286
|
+
// A single logical session can appear multiple times in the ring buffer: a
|
|
1287
|
+
// restart / model-switch / error-recovery respawn pushes a fresh entry with
|
|
1288
|
+
// the SAME sessionId but a new spawnedAt. History is newest-first (unshift),
|
|
1289
|
+
// so the first occurrence of a (source, sessionId, chatId) is the current
|
|
1290
|
+
// incarnation — collapse to it so the dashboard shows one row per session
|
|
1291
|
+
// instead of duplicating it.
|
|
1292
|
+
const seen = new Set();
|
|
1293
|
+
const out = [];
|
|
1294
|
+
for (const e of this.sessionHistory) {
|
|
1295
|
+
const dedupKey = `${e.source}:${e.sessionId}:${e.chatId}`;
|
|
1296
|
+
if (seen.has(dedupKey))
|
|
1297
|
+
continue;
|
|
1298
|
+
seen.add(dedupKey);
|
|
1299
|
+
const proc = this.sessions.get(e.chatId);
|
|
1300
|
+
// Running only when the live process IS this incarnation: a stale entry
|
|
1301
|
+
// from before a respawn must not borrow the new process's running state.
|
|
1302
|
+
const isRunning = !!proc && proc.spawnedAt === e.spawnedAt;
|
|
1303
|
+
// For API sessions the ring-buffer chatId equals the sessionId (the map key);
|
|
1304
|
+
// surface the real caller chatId instead when we have it.
|
|
1305
|
+
const chatId = e.source === 'api' ? (this.apiChatIds.get(e.sessionId) ?? e.chatId) : e.chatId;
|
|
1306
|
+
// Live context-window token usage from the running process (0 when stopped).
|
|
1307
|
+
const tokens = isRunning ? (proc?.totalTokens ?? 0) : 0;
|
|
1308
|
+
out.push({ ...e, chatId, isRunning, uptimeSec: Math.floor((now - e.spawnedAt) / 1000), tokens });
|
|
1309
|
+
}
|
|
1310
|
+
return out;
|
|
1311
|
+
}
|
|
1223
1312
|
/**
|
|
1224
1313
|
* Send a message to an API session and wait for the response.
|
|
1225
1314
|
*
|
|
@@ -1239,6 +1328,7 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1239
1328
|
});
|
|
1240
1329
|
// Use model from request body if provided, otherwise use agent default
|
|
1241
1330
|
const session = await this.getOrSpawnSession(sessionId, 'api', undefined, opts.model);
|
|
1331
|
+
this.apiChatIds.set(sessionId, chatId);
|
|
1242
1332
|
// Promote UI-uploaded files from staging to permanent per-session storage
|
|
1243
1333
|
const finalMediaFiles = opts.mediaFiles?.length
|
|
1244
1334
|
? await promoteUiUploads(this.agentsBaseDir, this.agentConfig.id, sessionId, opts.mediaFiles, this.logger)
|
|
@@ -1411,6 +1501,7 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1411
1501
|
});
|
|
1412
1502
|
// Use model from request body if provided, otherwise use agent default
|
|
1413
1503
|
const session = await this.getOrSpawnSession(sessionId, 'api', undefined, opts.model);
|
|
1504
|
+
this.apiChatIds.set(sessionId, chatId);
|
|
1414
1505
|
// Promote UI-uploaded files from staging to permanent per-session storage
|
|
1415
1506
|
const finalMediaFilesStream = opts.mediaFiles?.length
|
|
1416
1507
|
? await promoteUiUploads(this.agentsBaseDir, this.agentConfig.id, sessionId, opts.mediaFiles, this.logger)
|
|
@@ -1631,6 +1722,8 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1631
1722
|
.filter((a) => a !== null);
|
|
1632
1723
|
}
|
|
1633
1724
|
cleanupApiSessionMediaDir(sessionId, source) {
|
|
1725
|
+
// Always evict the chat-id mapping — safe no-op for non-api sessions.
|
|
1726
|
+
this.apiChatIds.delete(sessionId);
|
|
1634
1727
|
if (source !== 'api')
|
|
1635
1728
|
return;
|
|
1636
1729
|
const mediaDir = path.join(this.agentsBaseDir, this.agentConfig.id, 'media', `api-${sessionId}`);
|