@0xmaxma/claude-gateway 1.3.2 → 1.3.4
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 +6 -1
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +180 -67
- package/dist/agent/runner.js.map +1 -1
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +52 -32
- package/dist/api/router.js.map +1 -1
- package/dist/session/store.d.ts.map +1 -1
- package/dist/session/store.js +46 -0
- package/dist/session/store.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/agent/runner.d.ts
CHANGED
|
@@ -203,7 +203,12 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
203
203
|
name: string;
|
|
204
204
|
}>>;
|
|
205
205
|
listSessionsForChat(chatId: string, channel: 'telegram' | 'discord'): Promise<import('../types').SessionIndex>;
|
|
206
|
-
executeApiCommand(sessionId: string, chatId: string, command: string
|
|
206
|
+
executeApiCommand(sessionId: string, chatId: string, command: string, opts?: {
|
|
207
|
+
skipPersist?: boolean;
|
|
208
|
+
}): Promise<{
|
|
209
|
+
result: Record<string, unknown>;
|
|
210
|
+
responseText: string;
|
|
211
|
+
}>;
|
|
207
212
|
setModel(newModel: string): Promise<void>;
|
|
208
213
|
listApiSessions(chatId: string): Promise<import('../types').SessionIndex>;
|
|
209
214
|
createApiSession(chatId: string, prompt?: string, name?: string): Promise<import('../types').SessionMeta>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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
|
|
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
|
@@ -1302,8 +1302,9 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1302
1302
|
const done = (result) => {
|
|
1303
1303
|
cleanup();
|
|
1304
1304
|
const attachments = this.popApiAttachments(sessionId);
|
|
1305
|
-
// Persist assistant reply
|
|
1306
|
-
|
|
1305
|
+
// Persist assistant reply. Image-only replies (empty text but attachments
|
|
1306
|
+
// present) must also persist — otherwise the screenshot vanishes from history.
|
|
1307
|
+
if (result.trim() || attachments.length) {
|
|
1307
1308
|
const apiAssistantTs = Date.now();
|
|
1308
1309
|
this.sessionStore
|
|
1309
1310
|
.appendMessage(this.agentConfig.id, sessionId, {
|
|
@@ -1318,6 +1319,7 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1318
1319
|
source: 'api',
|
|
1319
1320
|
role: 'assistant',
|
|
1320
1321
|
content: result.trim(),
|
|
1322
|
+
mediaFiles: attachments.length ? attachments.map((a) => `media/${a.relPath}`) : undefined,
|
|
1321
1323
|
ts: apiAssistantTs,
|
|
1322
1324
|
});
|
|
1323
1325
|
}
|
|
@@ -1449,8 +1451,10 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1449
1451
|
settled = true;
|
|
1450
1452
|
cleanup();
|
|
1451
1453
|
const attachments = this.popApiAttachments(sessionId);
|
|
1452
|
-
// Persist assistant reply regardless of whether the SSE client is still connected
|
|
1453
|
-
|
|
1454
|
+
// Persist assistant reply regardless of whether the SSE client is still connected.
|
|
1455
|
+
// Image-only replies (empty text but attachments present) must also persist —
|
|
1456
|
+
// otherwise the screenshot vanishes from history once the stream ends.
|
|
1457
|
+
if (result.trim() || attachments.length) {
|
|
1454
1458
|
const streamAssistantTs = Date.now();
|
|
1455
1459
|
this.sessionStore
|
|
1456
1460
|
.appendMessage(this.agentConfig.id, sessionId, {
|
|
@@ -1465,6 +1469,7 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1465
1469
|
source: 'api',
|
|
1466
1470
|
role: 'assistant',
|
|
1467
1471
|
content: result.trim(),
|
|
1472
|
+
mediaFiles: attachments.length ? attachments.map((a) => `media/${a.relPath}`) : undefined,
|
|
1468
1473
|
ts: streamAssistantTs,
|
|
1469
1474
|
});
|
|
1470
1475
|
}
|
|
@@ -1497,6 +1502,11 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1497
1502
|
for (const block of msg.content) {
|
|
1498
1503
|
if (block.type === 'text' && block.text)
|
|
1499
1504
|
fullText += block.text;
|
|
1505
|
+
// PTY mode (headless=false) emits tool_use blocks inside assistant messages
|
|
1506
|
+
if (block.type === 'tool_use' && block.name && block.id) {
|
|
1507
|
+
if (!clientGone)
|
|
1508
|
+
callbacks.onChunk({ type: 'tool_use', name: block.name, id: block.id, input: block.input });
|
|
1509
|
+
}
|
|
1500
1510
|
}
|
|
1501
1511
|
if (fullText.length > lastPartialText.length) {
|
|
1502
1512
|
const delta = fullText.slice(lastPartialText.length);
|
|
@@ -1616,7 +1626,7 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1616
1626
|
if (!fs.existsSync(absPath))
|
|
1617
1627
|
return null;
|
|
1618
1628
|
const rel = absPath.slice(mediaRoot.length).replace(/\\/g, '/');
|
|
1619
|
-
return { type: 'image', url: `/v1/agents/${encodeURIComponent(this.agentConfig.id)}/media/${rel}
|
|
1629
|
+
return { type: 'image', url: `/v1/agents/${encodeURIComponent(this.agentConfig.id)}/media/${rel}`, relPath: rel };
|
|
1620
1630
|
})
|
|
1621
1631
|
.filter((a) => a !== null);
|
|
1622
1632
|
}
|
|
@@ -1646,73 +1656,171 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1646
1656
|
async listSessionsForChat(chatId, channel) {
|
|
1647
1657
|
return this.sessionStore.listSessions(this.agentConfig.id, chatId, channel);
|
|
1648
1658
|
}
|
|
1649
|
-
async executeApiCommand(sessionId, chatId, command) {
|
|
1659
|
+
async executeApiCommand(sessionId, chatId, command, opts) {
|
|
1650
1660
|
const agentId = this.agentConfig.id;
|
|
1651
1661
|
const storeChatId = chatId; // sessionStore adds channel prefix internally
|
|
1652
1662
|
const dbChatId = `api-${chatId}`; // historyDb uses full channel-chatId key
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1663
|
+
const skipPersist = opts?.skipPersist ?? false;
|
|
1664
|
+
// Dispatch on the first token so commands with arguments (e.g. "/model sonnet",
|
|
1665
|
+
// "/stop now") resolve to their base command instead of falling through to the
|
|
1666
|
+
// unknown-command branch. The router gate is prefix-based, so these already pass.
|
|
1667
|
+
const cmd = command.trim().split(/\s+/)[0] ?? '';
|
|
1668
|
+
// Validate BEFORE persisting anything. Reuse the same api-channel gate as the router
|
|
1669
|
+
// so an unknown command throws with nothing written — no orphan user row is left, and
|
|
1670
|
+
// the router surfaces the error/500 exactly as before. After token dispatch + the
|
|
1671
|
+
// /sessions branch below, this is only reachable on a direct caller passing garbage.
|
|
1672
|
+
if (!AgentRunner.isApiBuiltinCommand(cmd)) {
|
|
1673
|
+
throw new Error(`Unknown command: ${cmd}`);
|
|
1674
|
+
}
|
|
1675
|
+
// Register session in the api-{chatId} index on first use (same as sendApiMessageStream)
|
|
1676
|
+
await this.sessionStore.ensureApiSession(agentId, storeChatId, sessionId).catch((err) => {
|
|
1677
|
+
this.logger.warn('Failed to register API session in index for command', { agentId, chatId, sessionId, error: err.message });
|
|
1678
|
+
});
|
|
1679
|
+
// Persist a command message to the permanent history DB ONLY — not the model's session
|
|
1680
|
+
// context (sessionStore). historyDb is what the web history endpoint reads, so this is
|
|
1681
|
+
// all the display + spinner fix needs. Keeping commands out of the JSONL context means
|
|
1682
|
+
// /model replies aren't replayed into the model, /compact counts stay accurate, /clear
|
|
1683
|
+
// leaves no dangling turn, and the api channel matches telegram (which persists commands
|
|
1684
|
+
// nowhere).
|
|
1685
|
+
//
|
|
1686
|
+
// skipPersist (wire param store_user_message=false) suppresses BOTH the user command and
|
|
1687
|
+
// the assistant reply: programmatic REST callers leave no trace in chat history at all.
|
|
1688
|
+
const persist = (role, content) => {
|
|
1689
|
+
if (skipPersist || !content)
|
|
1690
|
+
return;
|
|
1691
|
+
this.historyDb.insertMessage({ chatId: dbChatId, sessionId, source: 'api', role, content, ts: Date.now() });
|
|
1692
|
+
};
|
|
1693
|
+
// Persist the full user command before executing so it appears in history.
|
|
1694
|
+
// Skip for /clear — clearSession() below wipes the table anyway; only the response survives.
|
|
1695
|
+
if (cmd !== '/clear') {
|
|
1696
|
+
persist('user', command);
|
|
1683
1697
|
}
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1698
|
+
let result;
|
|
1699
|
+
let responseText;
|
|
1700
|
+
try {
|
|
1701
|
+
if (cmd === '/model') {
|
|
1702
|
+
const model = this.agentConfig.claude.model;
|
|
1703
|
+
const hasArg = command.trim().includes(' ');
|
|
1704
|
+
result = { model };
|
|
1705
|
+
responseText = hasArg
|
|
1706
|
+
? `Current model: ${model}\n(To switch models use the model picker or the /api/v1/agents/:id/model endpoint — argument ignored.)`
|
|
1707
|
+
: `Current model: ${model}`;
|
|
1708
|
+
}
|
|
1709
|
+
else if (cmd === '/stop') {
|
|
1710
|
+
const session = this.sessions.get(sessionId);
|
|
1711
|
+
const stopped = session ? session.interrupt() : false;
|
|
1712
|
+
result = { stopped };
|
|
1713
|
+
responseText = stopped ? 'Session interrupted.' : 'No active session to stop.';
|
|
1714
|
+
}
|
|
1715
|
+
else if (cmd === '/restart') {
|
|
1716
|
+
this.restartProcess(sessionId).catch(() => { });
|
|
1717
|
+
result = { restarting: true };
|
|
1718
|
+
responseText = 'Session is restarting.';
|
|
1719
|
+
}
|
|
1720
|
+
else if (cmd === '/session') {
|
|
1721
|
+
const index = await this.sessionStore.listSessions(agentId, storeChatId, 'api').catch(() => null);
|
|
1722
|
+
const meta = index?.sessions.find((s) => s.id === sessionId);
|
|
1723
|
+
const effectiveModel = this.agentConfig.claude.model;
|
|
1724
|
+
// The api append path doesn't maintain the index messageCount, so count the flat store
|
|
1725
|
+
// (the real conversation) directly rather than trusting meta.messageCount.
|
|
1726
|
+
const messageCount = (await this.sessionStore.loadSession(agentId, sessionId).catch(() => [])).length;
|
|
1727
|
+
if (!meta) {
|
|
1728
|
+
result = { sessionId, sessionName: null, messageCount, archivedCount: 0, contextUsedPct: 0, model: effectiveModel };
|
|
1729
|
+
responseText = `Session: (unnamed)\nMessages: ${messageCount}\nContext used: 0%\nModel: ${effectiveModel}`;
|
|
1730
|
+
}
|
|
1731
|
+
else {
|
|
1732
|
+
const availableModels = this.gatewayConfig.gateway.models ?? exports.DEFAULT_MODELS;
|
|
1733
|
+
const modelConfig = availableModels.find((m) => m.id === effectiveModel);
|
|
1734
|
+
const contextWindow = modelConfig?.contextWindow ?? 200000;
|
|
1735
|
+
const contextUsedPct = Math.round(((meta.lastInputTokens ?? 0) / contextWindow) * 100);
|
|
1736
|
+
result = { sessionId, sessionName: meta.name, messageCount, archivedCount: meta.archivedCount ?? 0, contextUsedPct, model: effectiveModel };
|
|
1737
|
+
responseText = [
|
|
1738
|
+
`Session: ${meta.name ?? '(unnamed)'}`,
|
|
1739
|
+
`Messages: ${messageCount}${(meta.archivedCount ?? 0) > 0 ? ` (${meta.archivedCount} archived)` : ''}`,
|
|
1740
|
+
`Context used: ${contextUsedPct}%`,
|
|
1741
|
+
`Model: ${effectiveModel}`,
|
|
1742
|
+
].join('\n');
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
else if (cmd === '/sessions') {
|
|
1746
|
+
// Advertised for the api channel (BUILTIN_COMMANDS), so handle it here — mirrors the
|
|
1747
|
+
// telegram /sessions list. Marks the session this command runs in as (current).
|
|
1748
|
+
const index = await this.sessionStore.listSessions(agentId, storeChatId, 'api').catch(() => null);
|
|
1749
|
+
const list = index?.sessions ?? [];
|
|
1750
|
+
// Count each session's flat store directly — the api append path doesn't keep the
|
|
1751
|
+
// index messageCount in sync.
|
|
1752
|
+
const withCounts = await Promise.all(list.map(async (s) => ({
|
|
1753
|
+
id: s.id,
|
|
1754
|
+
name: s.name,
|
|
1755
|
+
messageCount: (await this.sessionStore.loadSession(agentId, s.id).catch(() => [])).length,
|
|
1756
|
+
current: s.id === sessionId,
|
|
1757
|
+
})));
|
|
1758
|
+
result = { sessions: withCounts, count: withCounts.length };
|
|
1759
|
+
if (!withCounts.length) {
|
|
1760
|
+
responseText = 'No sessions.';
|
|
1761
|
+
}
|
|
1762
|
+
else {
|
|
1763
|
+
const lines = withCounts.map((s) => {
|
|
1764
|
+
const n = s.messageCount;
|
|
1765
|
+
const marker = s.current ? ' (current)' : '';
|
|
1766
|
+
return `• ${s.name ?? '(unnamed)'} — ${n} message${n === 1 ? '' : 's'}${marker}`;
|
|
1767
|
+
});
|
|
1768
|
+
responseText = `Sessions (${withCounts.length}):\n${lines.join('\n')}`;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
else if (cmd === '/clear') {
|
|
1772
|
+
const ch = 'api';
|
|
1773
|
+
await this.sessionStore.clearTelegramSessionHistory(agentId, storeChatId, sessionId, ch);
|
|
1774
|
+
await this.sessionStore.updateSessionMeta(agentId, storeChatId, sessionId, {
|
|
1775
|
+
totalTokensUsed: 0,
|
|
1776
|
+
lastInputTokens: 0,
|
|
1777
|
+
archivedCount: 0,
|
|
1778
|
+
loadedAtSpawn: undefined,
|
|
1779
|
+
messageCountAtSpawn: undefined,
|
|
1780
|
+
}, ch);
|
|
1781
|
+
const mediaPaths = this.historyDb.clearSession(dbChatId, sessionId);
|
|
1782
|
+
media_store_1.MediaStore.deleteMediaFiles(this.agentsBaseDir, agentId, mediaPaths);
|
|
1783
|
+
this.restartProcess(sessionId).catch(() => { });
|
|
1784
|
+
result = { success: true };
|
|
1785
|
+
responseText = 'Session cleared.';
|
|
1786
|
+
}
|
|
1787
|
+
else if (cmd === '/compact') {
|
|
1788
|
+
const ch = 'api';
|
|
1789
|
+
const compactEffectiveModel = this.agentConfig.claude.model;
|
|
1790
|
+
const availableModels = this.gatewayConfig.gateway.models ?? exports.DEFAULT_MODELS;
|
|
1791
|
+
const modelConfig = availableModels.find((m) => m.id === compactEffectiveModel);
|
|
1792
|
+
const contextWindow = modelConfig?.contextWindow ?? 200000;
|
|
1793
|
+
const compactor = new compactor_1.SessionCompactor(this.sessionStore);
|
|
1794
|
+
const compactResult = await compactor.compact(agentId, storeChatId, sessionId, compactEffectiveModel, contextWindow, ch);
|
|
1795
|
+
await this.sessionStore.updateSessionMeta(agentId, storeChatId, sessionId, {
|
|
1796
|
+
loadedAtSpawn: undefined,
|
|
1797
|
+
archivedCount: undefined,
|
|
1798
|
+
messageCountAtSpawn: undefined,
|
|
1799
|
+
}, ch);
|
|
1800
|
+
await this.restartProcess(sessionId);
|
|
1801
|
+
result = { success: true, keptMessages: compactResult.afterMessages, archivedMessages: compactResult.beforeMessages - compactResult.afterMessages };
|
|
1802
|
+
responseText = `Session compacted. Kept ${compactResult.afterMessages} messages, archived ${compactResult.beforeMessages - compactResult.afterMessages}.`;
|
|
1803
|
+
}
|
|
1804
|
+
else {
|
|
1805
|
+
// Passed the gate but has no dispatch branch — BUILTIN_COMMANDS drifted from this
|
|
1806
|
+
// table. Throw so the failure surfaces (and ends history with an assistant turn via
|
|
1807
|
+
// the catch below) rather than returning an empty response.
|
|
1808
|
+
throw new Error(`Unhandled command: ${cmd}`);
|
|
1809
|
+
}
|
|
1714
1810
|
}
|
|
1715
|
-
|
|
1811
|
+
catch (err) {
|
|
1812
|
+
// Ensure history always ends with an assistant turn, even when execution fails midway
|
|
1813
|
+
// (e.g. /compact throws after the user row is persisted). Otherwise the trailing user
|
|
1814
|
+
// row re-triggers the web's stuck-spinner condition on reload. Rethrow so the router
|
|
1815
|
+
// still emits its SSE error event / REST 500.
|
|
1816
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1817
|
+
persist('assistant', `Command failed: ${errMsg}`);
|
|
1818
|
+
throw err;
|
|
1819
|
+
}
|
|
1820
|
+
// Persist the human-readable response as an assistant turn so the conversation ends with
|
|
1821
|
+
// an assistant message (the web's computeIsPendingResponse needs last.role !== 'user').
|
|
1822
|
+
persist('assistant', responseText);
|
|
1823
|
+
return { result, responseText };
|
|
1716
1824
|
}
|
|
1717
1825
|
async setModel(newModel) {
|
|
1718
1826
|
// Allow any model string through — BYOK/third-party models (openrouter/* etc.)
|
|
@@ -1874,6 +1982,11 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1874
1982
|
for (const block of msg.content) {
|
|
1875
1983
|
if (block.type === 'text' && block.text)
|
|
1876
1984
|
fullText += block.text;
|
|
1985
|
+
// PTY mode (headless=false) emits tool_use blocks inside assistant messages
|
|
1986
|
+
if (block.type === 'tool_use' && block.name && block.id) {
|
|
1987
|
+
if (!clientGone)
|
|
1988
|
+
callbacks.onChunk({ type: 'tool_use', name: block.name, id: block.id, input: block.input });
|
|
1989
|
+
}
|
|
1877
1990
|
}
|
|
1878
1991
|
if (fullText.length > lastPartialText.length) {
|
|
1879
1992
|
const delta = fullText.slice(lastPartialText.length);
|