@0xmaxma/claude-gateway 1.1.10 → 1.2.1
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 +61 -1
- package/dist/agent/builtin-commands.d.ts +10 -0
- package/dist/agent/builtin-commands.d.ts.map +1 -0
- package/dist/agent/builtin-commands.js +38 -0
- package/dist/agent/builtin-commands.js.map +1 -0
- package/dist/agent/runner.d.ts +1 -4
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +25 -30
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/workspace-loader.d.ts.map +1 -1
- package/dist/agent/workspace-loader.js +9 -4
- package/dist/agent/workspace-loader.js.map +1 -1
- package/dist/api/apps-router.d.ts +7 -0
- package/dist/api/apps-router.d.ts.map +1 -0
- package/dist/api/apps-router.js +242 -0
- package/dist/api/apps-router.js.map +1 -0
- package/dist/api/gateway-router.d.ts +17 -1
- package/dist/api/gateway-router.d.ts.map +1 -1
- package/dist/api/gateway-router.js +171 -2
- package/dist/api/gateway-router.js.map +1 -1
- package/dist/api/router.js +2 -2
- package/dist/api/router.js.map +1 -1
- package/dist/apps/agent-manager.d.ts +76 -0
- package/dist/apps/agent-manager.d.ts.map +1 -0
- package/dist/apps/agent-manager.js +311 -0
- package/dist/apps/agent-manager.js.map +1 -0
- package/dist/apps/compose-generator.d.ts +108 -0
- package/dist/apps/compose-generator.d.ts.map +1 -0
- package/dist/apps/compose-generator.js +687 -0
- package/dist/apps/compose-generator.js.map +1 -0
- package/dist/apps/installer.d.ts +101 -0
- package/dist/apps/installer.d.ts.map +1 -0
- package/dist/apps/installer.js +898 -0
- package/dist/apps/installer.js.map +1 -0
- package/dist/apps/registry-client.d.ts +37 -0
- package/dist/apps/registry-client.d.ts.map +1 -0
- package/dist/apps/registry-client.js +106 -0
- package/dist/apps/registry-client.js.map +1 -0
- package/dist/apps/registry.d.ts +54 -0
- package/dist/apps/registry.d.ts.map +1 -0
- package/dist/apps/registry.js +182 -0
- package/dist/apps/registry.js.map +1 -0
- package/dist/apps/socket-server.d.ts +46 -0
- package/dist/apps/socket-server.d.ts.map +1 -0
- package/dist/apps/socket-server.js +297 -0
- package/dist/apps/socket-server.js.map +1 -0
- package/dist/config/watcher.d.ts.map +1 -1
- package/dist/config/watcher.js +35 -0
- package/dist/config/watcher.js.map +1 -1
- package/dist/index.js +145 -1
- package/dist/index.js.map +1 -1
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +47 -6
- package/dist/session/process.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/lib/pairing.ts +326 -0
- package/mcp/server.ts +2 -0
- package/mcp/tools/apps/client.ts +78 -0
- package/mcp/tools/apps/module.ts +211 -0
- package/mcp/tools/apps/skills/app-status/SKILL.md +48 -0
- package/mcp/tools/apps/skills/create-app-yaml/SKILL.md +94 -0
- package/mcp/tools/apps/skills/install-app/SKILL.md +102 -0
- package/mcp/tools/apps/skills/list-apps/SKILL.md +34 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ A self-hosted multi-agent gateway for Claude Code. Connect Claude agents to Tele
|
|
|
26
26
|
- **Config auto-migration** — automatic schema migration when config format changes
|
|
27
27
|
- **Access control** — allowlist, open, or pairing-based Telegram access policies
|
|
28
28
|
- **HTTP API** — REST API with key-based auth for external integrations
|
|
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
|
|
29
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
|
|
30
31
|
- **Session persistence** — conversation history saved and restored across restarts
|
|
31
32
|
|
|
@@ -62,6 +63,10 @@ cat > ~/.claude-gateway/.env << 'EOF'
|
|
|
62
63
|
# HTTP port (default: 10850)
|
|
63
64
|
# PORT=10850
|
|
64
65
|
|
|
66
|
+
# Bind address (default: 0.0.0.0 — all interfaces)
|
|
67
|
+
# Set to 127.0.0.1 if a host-network reverse proxy (e.g. Traefik) is used
|
|
68
|
+
# GATEWAY_BIND=127.0.0.1
|
|
69
|
+
|
|
65
70
|
# Path to gateway config (default: ~/.claude-gateway/config.json)
|
|
66
71
|
# GATEWAY_CONFIG=~/.claude-gateway/config.json
|
|
67
72
|
EOF
|
|
@@ -414,6 +419,15 @@ Pass API key via `X-Api-Key: <key>` or `Authorization: Bearer <key>` header.
|
|
|
414
419
|
| `POST` | `/api/v1/agents/wizard/:wizardId/channel` | Verify bot token and generate pairing code (admin) |
|
|
415
420
|
| `POST` | `/api/v1/agents/wizard/:wizardId/channel/verify` | Poll for pairing code confirmation (admin) |
|
|
416
421
|
| `POST` | `/api/v1/agents/wizard/:wizardId/complete` | Skip channel and finalise wizard (admin) |
|
|
422
|
+
| `GET` | `/api/v1/apps/registry` | Browse community app registry (admin key) |
|
|
423
|
+
| `POST` | `/api/v1/apps/install` | Install app from registry, GitHub, or local path → `jobId` (admin) |
|
|
424
|
+
| `GET` | `/api/v1/apps/jobs/:jobId` | Poll install/update job status and logs |
|
|
425
|
+
| `GET` | `/api/v1/apps` | List installed apps |
|
|
426
|
+
| `GET` | `/api/v1/apps/:name` | Get app info |
|
|
427
|
+
| `DELETE` | `/api/v1/apps/:name` | Uninstall app (admin) |
|
|
428
|
+
| `POST` | `/api/v1/apps/:name/start\|stop\|restart` | Start/stop/restart app containers (admin) |
|
|
429
|
+
| `POST` | `/api/v1/apps/:name/update` | Blue-green update with auto-rollback → `jobId` (admin) |
|
|
430
|
+
| `GET` | `/app/:name/:portName/*` | Reverse proxy to installed app (no auth) |
|
|
417
431
|
|
|
418
432
|
**Wizard API** — create agents programmatically with the same flow as the interactive `make create-agent` terminal wizard. The wizard generates workspace files via Claude, writes them on confirm, and optionally pairs a Telegram/Discord bot. State is in-memory with a 30-minute TTL; nothing is written until `/confirm`. See [API.md](./API.md) for the full wizard flow.
|
|
419
433
|
|
|
@@ -421,6 +435,52 @@ See **[API.md](./API.md)** for full reference with request/response schemas and
|
|
|
421
435
|
|
|
422
436
|
---
|
|
423
437
|
|
|
438
|
+
## App Store
|
|
439
|
+
|
|
440
|
+
Install Docker-compose apps on the gateway. Apps get a reverse-proxied HTTP endpoint, an optional Unix socket bridge for executing host scripts, and optional AI agent injection.
|
|
441
|
+
|
|
442
|
+
**Quick install from registry:**
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
curl -X POST http://localhost:10850/api/v1/apps/install \
|
|
446
|
+
-H "X-Api-Key: <admin-key>" \
|
|
447
|
+
-H "Content-Type: application/json" \
|
|
448
|
+
-d '{"registry_app": "getpod-manager", "env_vars": {"API_KEY": "<secret>"}}'
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**Poll until done:**
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
curl http://localhost:10850/api/v1/apps/jobs/<jobId> -H "X-Api-Key: <key>" | jq .status
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
**App is then live at** `/app/getpod-manager/<portName>/`.
|
|
458
|
+
|
|
459
|
+
Apps can also be installed from a GitHub URL (`github_url` + `commit`) or a local path (`local_path`) for development. Updates use a **blue-green swap with automatic rollback** — the old containers stay intact until the new version passes its healthcheck.
|
|
460
|
+
|
|
461
|
+
**Reverse proxy configuration:**
|
|
462
|
+
|
|
463
|
+
The gateway proxies `/app/:name/:portName/*` to the app containers. Two env vars control how the gateway reaches them:
|
|
464
|
+
|
|
465
|
+
| Env var | Default | Description |
|
|
466
|
+
|---------|---------|-------------|
|
|
467
|
+
| `GATEWAY_BIND` | `0.0.0.0` | Gateway HTTP listen address. Must be `0.0.0.0` (default) when a **containerized** reverse proxy (Caddy, nginx in Docker) needs to reach the gateway. Set to `127.0.0.1` only if using a **host-network** proxy (Traefik on host) — loopback is not reachable across container boundaries. |
|
|
468
|
+
| `DOCKER_HOST` | _(system default)_ | Docker socket/TCP address. When set to `tcp://host:port` (e.g. DinD), the gateway automatically uses the host extracted from `DOCKER_HOST` to proxy to app containers instead of `127.0.0.1`. |
|
|
469
|
+
|
|
470
|
+
Example Caddyfile for apps behind Caddy in Docker:
|
|
471
|
+
|
|
472
|
+
```caddy
|
|
473
|
+
handle /app* {
|
|
474
|
+
reverse_proxy dev-server:10850
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
(`handle`, not `handle_path` — preserve the `/app` prefix so the gateway's router can match it.)
|
|
479
|
+
|
|
480
|
+
See **[API.md — App Store section](./API.md#app-store-api)** for the full reference including `app.yaml` schema, `gateway_api` host-script bridge, and agent injection.
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
424
484
|
## File Structure
|
|
425
485
|
|
|
426
486
|
### Project
|
|
@@ -779,7 +839,7 @@ Once paired, the following bot commands are available in a private chat:
|
|
|
779
839
|
|
|
780
840
|
## Monitoring
|
|
781
841
|
|
|
782
|
-
The gateway runs an HTTP server on port 10850 (set `PORT` env var to change):
|
|
842
|
+
The gateway runs an HTTP server on port 10850 (set `PORT` env var to change, `GATEWAY_BIND` to set the bind address):
|
|
783
843
|
|
|
784
844
|
| Endpoint | Description |
|
|
785
845
|
|----------|-------------|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type CommandChannel = 'telegram' | 'discord' | 'api';
|
|
2
|
+
interface CommandDef {
|
|
3
|
+
channels: CommandChannel[];
|
|
4
|
+
/** word-boundary check: true (default) = /^\/cmd\b/, false = /^\/cmd(\s|$)/ */
|
|
5
|
+
wordBoundary?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const BUILTIN_COMMANDS: Record<string, CommandDef>;
|
|
8
|
+
export declare function isBuiltinCommand(content: string, channel: CommandChannel): boolean;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=builtin-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builtin-commands.d.ts","sourceRoot":"","sources":["../../src/agent/builtin-commands.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,SAAS,GAAG,KAAK,CAAC;AAE5D,UAAU,UAAU;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAcvD,CAAC;AAsBF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAElF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BUILTIN_COMMANDS = void 0;
|
|
4
|
+
exports.isBuiltinCommand = isBuiltinCommand;
|
|
5
|
+
exports.BUILTIN_COMMANDS = {
|
|
6
|
+
session: { channels: ['telegram', 'discord', 'api'] },
|
|
7
|
+
sessions: { channels: ['telegram', 'discord', 'api'] },
|
|
8
|
+
new: { channels: ['telegram', 'discord'], wordBoundary: false },
|
|
9
|
+
rename: { channels: ['telegram'], wordBoundary: false },
|
|
10
|
+
clear: { channels: ['telegram', 'api'] },
|
|
11
|
+
compact: { channels: ['telegram', 'api'] },
|
|
12
|
+
stop: { channels: ['telegram', 'api'], wordBoundary: false },
|
|
13
|
+
model: { channels: ['telegram', 'discord', 'api'] },
|
|
14
|
+
models: { channels: ['telegram'] },
|
|
15
|
+
restart: { channels: ['telegram', 'api'], wordBoundary: false },
|
|
16
|
+
start: { channels: ['telegram'] },
|
|
17
|
+
help: { channels: ['telegram'] },
|
|
18
|
+
status: { channels: ['telegram'] },
|
|
19
|
+
};
|
|
20
|
+
const _cache = new Map();
|
|
21
|
+
function buildRegex(channel) {
|
|
22
|
+
const parts = Object.entries(exports.BUILTIN_COMMANDS)
|
|
23
|
+
.filter(([, def]) => def.channels.includes(channel))
|
|
24
|
+
.map(([cmd, def]) => def.wordBoundary === false ? `^\/${cmd}(\\s|$)` : `^\/${cmd}\\b`);
|
|
25
|
+
return new RegExp(parts.join('|'));
|
|
26
|
+
}
|
|
27
|
+
function getRegex(channel) {
|
|
28
|
+
let re = _cache.get(channel);
|
|
29
|
+
if (!re) {
|
|
30
|
+
re = buildRegex(channel);
|
|
31
|
+
_cache.set(channel, re);
|
|
32
|
+
}
|
|
33
|
+
return re;
|
|
34
|
+
}
|
|
35
|
+
function isBuiltinCommand(content, channel) {
|
|
36
|
+
return getRegex(channel).test(content.trim());
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=builtin-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builtin-commands.js","sourceRoot":"","sources":["../../src/agent/builtin-commands.ts"],"names":[],"mappings":";;;AA4CA,4CAEC;AAtCY,QAAA,gBAAgB,GAA+B;IAC1D,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,GAAG,EAAO,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IACpE,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IACzD,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE;IAC3C,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE;IAC3C,IAAI,EAAM,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IAChE,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IAChE,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,IAAI,EAAM,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;CACrC,CAAC;AAEF,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEjD,SAAS,UAAU,CAAC,OAAuB;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,wBAAgB,CAAC;SAC3C,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SACnD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAClB,GAAG,CAAC,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CACjE,CAAC;IACJ,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,QAAQ,CAAC,OAAuB;IACvC,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAgB,gBAAgB,CAAC,OAAe,EAAE,OAAuB;IACvE,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC"}
|
package/dist/agent/runner.d.ts
CHANGED
|
@@ -59,10 +59,7 @@ export declare class AgentRunner extends EventEmitter {
|
|
|
59
59
|
private static buildChannelXml;
|
|
60
60
|
private getOrSpawnSession;
|
|
61
61
|
private spawnSession;
|
|
62
|
-
|
|
63
|
-
* Returns true if the message content is a session management command.
|
|
64
|
-
*/
|
|
65
|
-
private isSessionCommand;
|
|
62
|
+
static isApiBuiltinCommand(content: string): boolean;
|
|
66
63
|
/**
|
|
67
64
|
* Dispatch a session management command to the appropriate handler.
|
|
68
65
|
*/
|
|
@@ -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,MAAM,UAAU,CAAC;AAQjG,OAAO,EAA0C,KAAK,aAAa,EAAE,MAAM,WAAW,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
|
@@ -47,6 +47,7 @@ const receiver_1 = require("../telegram/receiver");
|
|
|
47
47
|
const receiver_2 = require("../discord/receiver");
|
|
48
48
|
const markdown_1 = require("../telegram/markdown");
|
|
49
49
|
const skills_1 = require("../skills");
|
|
50
|
+
const builtin_commands_1 = require("./builtin-commands");
|
|
50
51
|
const db_1 = require("../history/db");
|
|
51
52
|
const media_store_1 = require("../history/media-store");
|
|
52
53
|
const cleanup_1 = require("../history/cleanup");
|
|
@@ -96,7 +97,7 @@ function buildApiSystemNote(allowTools, imagePaths) {
|
|
|
96
97
|
if (imagePaths?.length) {
|
|
97
98
|
imageNote = ` The user attached ${imagePaths.length} image(s). Read them with the Read tool:\n${imagePaths.map(p => `- ${p}`).join('\n')}`;
|
|
98
99
|
}
|
|
99
|
-
return
|
|
100
|
+
return `<api-context>This is an API request. ${memoryOverride} ${toolNote}${imageNote}</api-context>\n`;
|
|
100
101
|
}
|
|
101
102
|
class AgentRunner extends events_1.EventEmitter {
|
|
102
103
|
imageSize(chatId) { return this.imageSizePerChat.get(chatId) ?? 0; }
|
|
@@ -186,9 +187,9 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
186
187
|
// Set channel early so all handlers (including session commands) have it
|
|
187
188
|
const channelSource = (meta['source'] === 'discord' ? 'discord' : 'telegram');
|
|
188
189
|
this.channelSourceMap.set(chatId, channelSource);
|
|
189
|
-
// Check if this is a
|
|
190
|
+
// Check if this is a built-in channel command
|
|
190
191
|
const trimmedContent = content.trim();
|
|
191
|
-
if (
|
|
192
|
+
if ((0, builtin_commands_1.isBuiltinCommand)(trimmedContent, channelSource)) {
|
|
192
193
|
this.handleSessionCommand(chatId, trimmedContent)
|
|
193
194
|
.then(() => this.writeTypingDone(chatId))
|
|
194
195
|
.catch((err) => {
|
|
@@ -802,11 +803,8 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
802
803
|
});
|
|
803
804
|
return proc;
|
|
804
805
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
*/
|
|
808
|
-
isSessionCommand(content) {
|
|
809
|
-
return /^\/sessions?\b|^\/new(\s|$)|^\/clear\b|^\/compact\b|^\/rename(\s|$)|^\/stop(\s|$)/.test(content);
|
|
806
|
+
static isApiBuiltinCommand(content) {
|
|
807
|
+
return (0, builtin_commands_1.isBuiltinCommand)(content, 'api');
|
|
810
808
|
}
|
|
811
809
|
/**
|
|
812
810
|
* Dispatch a session management command to the appropriate handler.
|
|
@@ -1247,9 +1245,8 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1247
1245
|
const err = Object.assign(new Error(`Session ${sessionId} already has a pending request`), { code: 'CONFLICT' });
|
|
1248
1246
|
throw err;
|
|
1249
1247
|
}
|
|
1250
|
-
// Register session in api-{chatId} index.json on first use
|
|
1251
|
-
|
|
1252
|
-
await this.sessionStore.ensureApiSession(this.agentConfig.id, internalChatIdForSession, sessionId).catch((err) => {
|
|
1248
|
+
// Register session in api-{chatId} index.json on first use (store adds channel prefix internally)
|
|
1249
|
+
await this.sessionStore.ensureApiSession(this.agentConfig.id, chatId, sessionId).catch((err) => {
|
|
1253
1250
|
this.logger.warn('Failed to register API session in index', { agentId: this.agentConfig.id, chatId, sessionId, error: err.message });
|
|
1254
1251
|
});
|
|
1255
1252
|
// Use model from request body if provided, otherwise use agent default
|
|
@@ -1409,9 +1406,8 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1409
1406
|
const err = Object.assign(new Error(`Session ${sessionId} already has a pending request`), { code: 'CONFLICT' });
|
|
1410
1407
|
throw err;
|
|
1411
1408
|
}
|
|
1412
|
-
// Register session in api-{chatId} index.json on first use
|
|
1413
|
-
|
|
1414
|
-
await this.sessionStore.ensureApiSession(this.agentConfig.id, internalChatIdStream, sessionId).catch((err) => {
|
|
1409
|
+
// Register session in api-{chatId} index.json on first use (store adds channel prefix internally)
|
|
1410
|
+
await this.sessionStore.ensureApiSession(this.agentConfig.id, chatId, sessionId).catch((err) => {
|
|
1415
1411
|
this.logger.warn('Failed to register API session in index', { agentId: this.agentConfig.id, chatId, sessionId, error: err.message });
|
|
1416
1412
|
});
|
|
1417
1413
|
// Use model from request body if provided, otherwise use agent default
|
|
@@ -1624,7 +1620,8 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1624
1620
|
}
|
|
1625
1621
|
async executeApiCommand(sessionId, chatId, command) {
|
|
1626
1622
|
const agentId = this.agentConfig.id;
|
|
1627
|
-
const
|
|
1623
|
+
const storeChatId = chatId; // sessionStore adds channel prefix internally
|
|
1624
|
+
const dbChatId = `api-${chatId}`; // historyDb uses full channel-chatId key
|
|
1628
1625
|
if (command === '/model') {
|
|
1629
1626
|
return { model: this.agentConfig.claude.model };
|
|
1630
1627
|
}
|
|
@@ -1638,7 +1635,7 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1638
1635
|
return { restarting: true };
|
|
1639
1636
|
}
|
|
1640
1637
|
if (command === '/session') {
|
|
1641
|
-
const index = await this.sessionStore.listSessions(agentId,
|
|
1638
|
+
const index = await this.sessionStore.listSessions(agentId, storeChatId, 'api').catch(() => null);
|
|
1642
1639
|
const meta = index?.sessions.find((s) => s.id === sessionId);
|
|
1643
1640
|
const effectiveModel = this.agentConfig.claude.model;
|
|
1644
1641
|
if (!meta)
|
|
@@ -1658,15 +1655,15 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1658
1655
|
}
|
|
1659
1656
|
if (command === '/clear') {
|
|
1660
1657
|
const ch = 'api';
|
|
1661
|
-
await this.sessionStore.clearTelegramSessionHistory(agentId,
|
|
1662
|
-
await this.sessionStore.updateSessionMeta(agentId,
|
|
1658
|
+
await this.sessionStore.clearTelegramSessionHistory(agentId, storeChatId, sessionId, ch);
|
|
1659
|
+
await this.sessionStore.updateSessionMeta(agentId, storeChatId, sessionId, {
|
|
1663
1660
|
totalTokensUsed: 0,
|
|
1664
1661
|
lastInputTokens: 0,
|
|
1665
1662
|
archivedCount: 0,
|
|
1666
1663
|
loadedAtSpawn: undefined,
|
|
1667
1664
|
messageCountAtSpawn: undefined,
|
|
1668
1665
|
}, ch);
|
|
1669
|
-
const mediaPaths = this.historyDb.clearSession(
|
|
1666
|
+
const mediaPaths = this.historyDb.clearSession(dbChatId, sessionId);
|
|
1670
1667
|
media_store_1.MediaStore.deleteMediaFiles(this.agentsBaseDir, agentId, mediaPaths);
|
|
1671
1668
|
this.restartProcess(sessionId).catch(() => { });
|
|
1672
1669
|
return { success: true };
|
|
@@ -1678,8 +1675,8 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1678
1675
|
const modelConfig = availableModels.find((m) => m.id === compactEffectiveModel);
|
|
1679
1676
|
const contextWindow = modelConfig?.contextWindow ?? 200000;
|
|
1680
1677
|
const compactor = new compactor_1.SessionCompactor(this.sessionStore);
|
|
1681
|
-
const result = await compactor.compact(agentId,
|
|
1682
|
-
await this.sessionStore.updateSessionMeta(agentId,
|
|
1678
|
+
const result = await compactor.compact(agentId, storeChatId, sessionId, compactEffectiveModel, contextWindow, ch);
|
|
1679
|
+
await this.sessionStore.updateSessionMeta(agentId, storeChatId, sessionId, {
|
|
1683
1680
|
loadedAtSpawn: undefined,
|
|
1684
1681
|
archivedCount: undefined,
|
|
1685
1682
|
messageCountAtSpawn: undefined,
|
|
@@ -1703,7 +1700,7 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1703
1700
|
}
|
|
1704
1701
|
}
|
|
1705
1702
|
async listApiSessions(chatId) {
|
|
1706
|
-
return this.sessionStore.listSessions(this.agentConfig.id,
|
|
1703
|
+
return this.sessionStore.listSessions(this.agentConfig.id, chatId, 'api');
|
|
1707
1704
|
}
|
|
1708
1705
|
async createApiSession(chatId, prompt, name) {
|
|
1709
1706
|
let sessionName = name;
|
|
@@ -1720,10 +1717,10 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1720
1717
|
sessionName = undefined;
|
|
1721
1718
|
}
|
|
1722
1719
|
}
|
|
1723
|
-
return this.sessionStore.createTelegramSession(this.agentConfig.id,
|
|
1720
|
+
return this.sessionStore.createTelegramSession(this.agentConfig.id, chatId, sessionName, 'api');
|
|
1724
1721
|
}
|
|
1725
1722
|
async getApiSessionInfo(chatId, sessionId) {
|
|
1726
|
-
const index = await this.sessionStore.listSessions(this.agentConfig.id,
|
|
1723
|
+
const index = await this.sessionStore.listSessions(this.agentConfig.id, chatId, 'api').catch(() => null);
|
|
1727
1724
|
const meta = index?.sessions.find((s) => s.id === sessionId);
|
|
1728
1725
|
if (!meta)
|
|
1729
1726
|
return null;
|
|
@@ -1743,25 +1740,23 @@ class AgentRunner extends events_1.EventEmitter {
|
|
|
1743
1740
|
}
|
|
1744
1741
|
async updateApiSession(chatId, sessionId, updates) {
|
|
1745
1742
|
if (updates.sessionName) {
|
|
1746
|
-
const internalChatId = `api-${chatId}`;
|
|
1747
1743
|
// Ensure session exists in the file index (may be missing for older sessions stored only in SQLite)
|
|
1748
|
-
await this.sessionStore.ensureApiSession(this.agentConfig.id,
|
|
1744
|
+
await this.sessionStore.ensureApiSession(this.agentConfig.id, chatId, sessionId).catch((err) => {
|
|
1749
1745
|
this.logger.warn('Failed to register API session in index', { agentId: this.agentConfig.id, chatId, sessionId, error: err.message });
|
|
1750
1746
|
});
|
|
1751
|
-
await this.sessionStore.updateSessionMeta(this.agentConfig.id,
|
|
1747
|
+
await this.sessionStore.updateSessionMeta(this.agentConfig.id, chatId, sessionId, { name: updates.sessionName }, 'api');
|
|
1752
1748
|
}
|
|
1753
1749
|
return { sessionId, ...(updates.sessionName ? { sessionName: updates.sessionName } : {}) };
|
|
1754
1750
|
}
|
|
1755
1751
|
async deleteApiSession(chatId, sessionId) {
|
|
1756
|
-
|
|
1757
|
-
await this.sessionStore.deleteTelegramSession(this.agentConfig.id, internalChatId, sessionId, 'api').catch((err) => {
|
|
1752
|
+
await this.sessionStore.deleteTelegramSession(this.agentConfig.id, chatId, sessionId, 'api').catch((err) => {
|
|
1758
1753
|
// Legacy sessions (stored only in SQLite, no file index entry) are treated as already deleted
|
|
1759
1754
|
if (err instanceof store_1.SessionNotInIndexError)
|
|
1760
1755
|
return;
|
|
1761
1756
|
throw err;
|
|
1762
1757
|
});
|
|
1763
1758
|
// Purge from SQLite so the session no longer appears in listSessions()
|
|
1764
|
-
const mediaPaths = this.historyDb.clearSession(
|
|
1759
|
+
const mediaPaths = this.historyDb.clearSession(`api-${chatId}`, sessionId);
|
|
1765
1760
|
media_store_1.MediaStore.deleteMediaFiles(this.agentsBaseDir, this.agentConfig.id, mediaPaths);
|
|
1766
1761
|
}
|
|
1767
1762
|
/**
|