@0xmaxma/claude-gateway 1.7.10 → 1.8.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 +167 -41
- package/dist/agent/builtin-commands.js +2 -2
- package/dist/agent/builtin-commands.js.map +1 -1
- package/dist/agent/knowledge/config.d.ts.map +1 -1
- package/dist/agent/knowledge/config.js +2 -9
- package/dist/agent/knowledge/config.js.map +1 -1
- package/dist/agent/model-catalog.d.ts +62 -0
- package/dist/agent/model-catalog.d.ts.map +1 -0
- package/dist/agent/model-catalog.js +304 -0
- package/dist/agent/model-catalog.js.map +1 -0
- package/dist/agent/runner.d.ts +76 -0
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +212 -41
- package/dist/agent/runner.js.map +1 -1
- package/dist/api/cron-router.d.ts +12 -8
- package/dist/api/cron-router.d.ts.map +1 -1
- package/dist/api/cron-router.js +82 -16
- package/dist/api/cron-router.js.map +1 -1
- package/dist/api/gateway-router.d.ts +4 -0
- package/dist/api/gateway-router.d.ts.map +1 -1
- package/dist/api/gateway-router.js +14 -0
- package/dist/api/gateway-router.js.map +1 -1
- package/dist/api/manifest-sources.d.ts +15 -0
- package/dist/api/manifest-sources.d.ts.map +1 -0
- package/dist/api/manifest-sources.js +27 -0
- package/dist/api/manifest-sources.js.map +1 -0
- package/dist/api/meta-router.d.ts +13 -0
- package/dist/api/meta-router.d.ts.map +1 -0
- package/dist/api/meta-router.js +26 -0
- package/dist/api/meta-router.js.map +1 -0
- package/dist/api/packages.d.ts.map +1 -1
- package/dist/api/packages.js +18 -198
- package/dist/api/packages.js.map +1 -1
- package/dist/api/route-registry.d.ts +81 -0
- package/dist/api/route-registry.d.ts.map +1 -0
- package/dist/api/route-registry.js +44 -0
- package/dist/api/route-registry.js.map +1 -0
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +21 -3
- package/dist/api/router.js.map +1 -1
- package/dist/apps/installer.d.ts +73 -5
- package/dist/apps/installer.d.ts.map +1 -1
- package/dist/apps/installer.js +237 -22
- package/dist/apps/installer.js.map +1 -1
- package/dist/cli/args.d.ts +25 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +55 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/colors.d.ts +37 -0
- package/dist/cli/colors.d.ts.map +1 -0
- package/dist/cli/colors.js +63 -0
- package/dist/cli/colors.js.map +1 -0
- package/dist/cli/command-names.d.ts +98 -0
- package/dist/cli/command-names.d.ts.map +1 -0
- package/dist/cli/command-names.js +109 -0
- package/dist/cli/command-names.js.map +1 -0
- package/dist/cli/commands/agents.d.ts +28 -0
- package/dist/cli/commands/agents.d.ts.map +1 -0
- package/dist/cli/commands/agents.js +321 -0
- package/dist/cli/commands/agents.js.map +1 -0
- package/dist/cli/commands/channels.d.ts +17 -0
- package/dist/cli/commands/channels.d.ts.map +1 -0
- package/dist/cli/commands/channels.js +101 -0
- package/dist/cli/commands/channels.js.map +1 -0
- package/dist/cli/commands/debug-bundle.d.ts +6 -0
- package/dist/cli/commands/debug-bundle.d.ts.map +1 -0
- package/dist/cli/commands/debug-bundle.js +220 -0
- package/dist/cli/commands/debug-bundle.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +3 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +104 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/gateway.d.ts +12 -0
- package/dist/cli/commands/gateway.d.ts.map +1 -0
- package/dist/cli/commands/gateway.js +145 -0
- package/dist/cli/commands/gateway.js.map +1 -0
- package/dist/cli/commands/service.d.ts +33 -0
- package/dist/cli/commands/service.d.ts.map +1 -0
- package/dist/cli/commands/service.js +513 -0
- package/dist/cli/commands/service.js.map +1 -0
- package/dist/cli/commands/update.d.ts +16 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +149 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/commands.generated.d.ts +4 -0
- package/dist/cli/commands.generated.d.ts.map +1 -0
- package/dist/cli/commands.generated.js +220 -0
- package/dist/cli/commands.generated.js.map +1 -0
- package/dist/cli/health.d.ts +31 -0
- package/dist/cli/health.d.ts.map +1 -0
- package/dist/cli/health.js +49 -0
- package/dist/cli/health.js.map +1 -0
- package/dist/cli/http-client.d.ts +140 -0
- package/dist/cli/http-client.d.ts.map +1 -0
- package/dist/cli/http-client.js +332 -0
- package/dist/cli/http-client.js.map +1 -0
- package/dist/cli/index.d.ts +27 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +372 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/manager.d.ts +64 -0
- package/dist/cli/manager.d.ts.map +1 -0
- package/dist/cli/manager.js +181 -0
- package/dist/cli/manager.js.map +1 -0
- package/dist/cli/output.d.ts +49 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +101 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/prompt.d.ts +29 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +154 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/redact.d.ts +3 -0
- package/dist/cli/redact.d.ts.map +1 -0
- package/dist/cli/redact.js +33 -0
- package/dist/cli/redact.js.map +1 -0
- package/dist/cli/types.d.ts +22 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +4 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/config/bootstrap.d.ts +33 -0
- package/dist/config/bootstrap.d.ts.map +1 -0
- package/dist/config/bootstrap.js +117 -0
- package/dist/config/bootstrap.js.map +1 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +5 -1
- package/dist/config/loader.js.map +1 -1
- package/dist/config/watcher.d.ts.map +1 -1
- package/dist/config/watcher.js +2 -35
- package/dist/config/watcher.js.map +1 -1
- package/dist/discord/receiver.d.ts +6 -1
- package/dist/discord/receiver.d.ts.map +1 -1
- package/dist/discord/receiver.js +9 -1
- package/dist/discord/receiver.js.map +1 -1
- package/dist/entry.d.ts +3 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +83 -0
- package/dist/entry.js.map +1 -0
- package/dist/index.js +160 -46
- package/dist/index.js.map +1 -1
- package/dist/load-dotenv.d.ts +2 -0
- package/dist/load-dotenv.d.ts.map +1 -0
- package/dist/load-dotenv.js +68 -0
- package/dist/load-dotenv.js.map +1 -0
- package/dist/packages/registry.d.ts +50 -0
- package/dist/packages/registry.d.ts.map +1 -0
- package/dist/packages/registry.js +209 -0
- package/dist/packages/registry.js.map +1 -0
- package/dist/session/process.d.ts +14 -5
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +155 -26
- package/dist/session/process.js.map +1 -1
- package/dist/shutdown-signals.d.ts +47 -0
- package/dist/shutdown-signals.d.ts.map +1 -0
- package/dist/shutdown-signals.js +62 -0
- package/dist/shutdown-signals.js.map +1 -0
- package/dist/telegram/receiver.d.ts +6 -1
- package/dist/telegram/receiver.d.ts.map +1 -1
- package/dist/telegram/receiver.js +9 -1
- package/dist/telegram/receiver.js.map +1 -1
- package/dist/utils/orphan-receivers.d.ts +90 -0
- package/dist/utils/orphan-receivers.d.ts.map +1 -0
- package/dist/utils/orphan-receivers.js +218 -0
- package/dist/utils/orphan-receivers.js.map +1 -0
- package/dist/utils/paths.d.ts +16 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +60 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/stop-child.d.ts +21 -0
- package/dist/utils/stop-child.d.ts.map +1 -0
- package/dist/utils/stop-child.js +64 -0
- package/dist/utils/stop-child.js.map +1 -0
- package/lib/pairing.ts +1 -1
- package/mcp/tools/agent/handlers.ts +1 -1
- package/mcp/tools/discord/receiver-server.ts +4 -0
- package/mcp/tools/telegram/receiver-server.ts +152 -29
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ A self-hosted multi-agent gateway for Claude Code — with agents that improve t
|
|
|
30
30
|
- 🔐 **Access control** — allowlist, open, or pairing-based Telegram access policies
|
|
31
31
|
- 🌐 **HTTP API** — REST API with key-based auth for external integrations
|
|
32
32
|
- 🛍️ **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
|
|
33
|
-
- ⬆️ **Self-update
|
|
33
|
+
- ⬆️ **Self-update** — 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), or from the terminal with `claude-gateway update` / `claude-gateway claude update`
|
|
34
34
|
- 💾 **Session persistence** — conversation history saved and restored across restarts
|
|
35
35
|
- 🖥️ **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; a `/cli` chat command (Telegram/Discord/LINE) opens the same viewer for a single agent, agent-scoped and without an admin key; app-agents always stay headless
|
|
36
36
|
|
|
@@ -80,28 +80,64 @@ EOF
|
|
|
80
80
|
|
|
81
81
|
All variables are optional. Full list: [`.env.example`](.env.example)
|
|
82
82
|
|
|
83
|
-
**3.
|
|
83
|
+
**3. Start**
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
```bash
|
|
86
|
+
claude-gateway gateway start
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`claude-gateway` on its own prints help — starting the server is always the explicit
|
|
90
|
+
`gateway start`, so a stray or mistyped command can never leave a gateway listening.
|
|
91
|
+
|
|
92
|
+
No config file needed — on first run, if `~/.claude-gateway/config.json` doesn't exist yet, the gateway creates it automatically with `"agents": []` and a fresh random admin API key, and prints that key once:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
[gateway] No config found — created one at ~/.claude-gateway/config.json
|
|
96
|
+
[gateway] Admin API key (save this now — it will not be shown again):
|
|
97
|
+
[gateway] <random-hex-key>
|
|
98
|
+
[gateway] The CLI (claude-gateway agents create, etc.) picks this up automatically from ~/.claude-gateway/config.json.
|
|
99
|
+
```
|
|
86
100
|
|
|
87
|
-
|
|
101
|
+
Save that key somewhere safe — it isn't shown again (though you can always read it back from `config.json` on disk). See [`config.template.json`](config.template.json) for the full config format (models list, more options) if you want to customize it by hand later.
|
|
102
|
+
|
|
103
|
+
**4. Create an agent**
|
|
88
104
|
|
|
89
105
|
```bash
|
|
90
|
-
claude-gateway
|
|
106
|
+
claude-gateway agents create
|
|
91
107
|
```
|
|
92
108
|
|
|
93
|
-
|
|
109
|
+
Interactive wizard — describe the agent, Claude generates the workspace files, review and accept them, then optionally connect a Telegram or Discord bot. Hot-reloads immediately, no restart needed. The CLI picks up the admin key from `config.json` automatically — no need to pass `--key`. (You can also add an agent entry to `config.json` by hand instead — same template link as above.)
|
|
110
|
+
|
|
111
|
+
**Run as a service (optional)**
|
|
94
112
|
|
|
95
|
-
To keep the gateway running after
|
|
113
|
+
To keep the gateway running after you log out or the machine reboots, let the CLI install the
|
|
114
|
+
service for you. It shows the exact unit it will write, asks before installing, and verifies
|
|
115
|
+
`/health` afterwards:
|
|
96
116
|
|
|
97
117
|
```bash
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
118
|
+
claude-gateway service install # systemd *user* unit — no sudo
|
|
119
|
+
claude-gateway service install --print # just show what it would install
|
|
120
|
+
claude-gateway service status
|
|
121
|
+
claude-gateway service uninstall # asks first — this stops a running gateway
|
|
102
122
|
```
|
|
103
123
|
|
|
104
|
-
|
|
124
|
+
Install and uninstall both prompt before acting; pass `--yes` in scripts (without it, a
|
|
125
|
+
non-interactive run is refused rather than left hanging).
|
|
126
|
+
|
|
127
|
+
The systemd path writes `~/.config/systemd/user/claude-gateway.service`. Run
|
|
128
|
+
`loginctl enable-linger $USER` once if it must keep running while you're logged out.
|
|
129
|
+
Prefer [PM2](https://pm2.keymetrics.io)? `claude-gateway service install --manager pm2` registers
|
|
130
|
+
and saves the process instead (run `pm2 startup` separately for boot-time start).
|
|
131
|
+
|
|
132
|
+
Once installed, drive it through the CLI — it detects whichever manager owns the process:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
claude-gateway gateway status # manager, URL, health
|
|
136
|
+
claude-gateway gateway restart
|
|
137
|
+
claude-gateway gateway stop
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Managing PM2 directly still works too:
|
|
105
141
|
|
|
106
142
|
```bash
|
|
107
143
|
pm2 status # check gateway status
|
|
@@ -122,30 +158,32 @@ npm install # also runs bun install in mcp/
|
|
|
122
158
|
npm run build
|
|
123
159
|
```
|
|
124
160
|
|
|
125
|
-
###
|
|
126
|
-
|
|
127
|
-
The interactive wizard handles everything — workspace files, config, bot token, and pairing:
|
|
161
|
+
### Start the gateway
|
|
128
162
|
|
|
129
163
|
```bash
|
|
130
|
-
|
|
164
|
+
npm start
|
|
131
165
|
```
|
|
132
166
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
3. Review and accept generated files
|
|
137
|
-
4. Choose a channel: **Telegram** or **Discord**
|
|
138
|
-
5. Paste the bot token — wizard verifies it automatically
|
|
139
|
-
6. Send any message to the bot to complete pairing
|
|
140
|
-
7. Agent sends a welcome message
|
|
167
|
+
Config is auto-loaded from `~/.claude-gateway/config.json` — if it doesn't exist yet, `npm start` creates it automatically with `"agents": []` and a fresh admin key (see the Start step in the npm-install path above). Bot tokens are auto-loaded from `~/.claude-gateway/agents/<id>/.env`.
|
|
168
|
+
|
|
169
|
+
### Create an agent
|
|
141
170
|
|
|
142
|
-
|
|
171
|
+
The interactive wizard handles everything — workspace files, bot token, and pairing:
|
|
143
172
|
|
|
144
173
|
```bash
|
|
145
|
-
|
|
174
|
+
claude-gateway agents create
|
|
146
175
|
```
|
|
147
176
|
|
|
148
|
-
|
|
177
|
+
Steps:
|
|
178
|
+
1. Choose an agent id and describe its role — Claude generates workspace files
|
|
179
|
+
2. Review and accept the generated files
|
|
180
|
+
3. Optionally connect a channel: **Telegram** or **Discord** — paste the bot token, wizard verifies it automatically
|
|
181
|
+
4. Agent hot-reloads immediately — send any message to the bot, then approve pairing:
|
|
182
|
+
```bash
|
|
183
|
+
claude-gateway channels approve --agent <id> --channel telegram --code <code>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
To manage an existing agent — regenerate `AGENTS.md`, or connect/update/disconnect Telegram, Discord, LINE, or Slack — run `claude-gateway agents update`.
|
|
149
187
|
|
|
150
188
|
---
|
|
151
189
|
|
|
@@ -295,7 +333,7 @@ Access policy is configured per-channel in the agent's workspace state file, not
|
|
|
295
333
|
|-------|-----------|
|
|
296
334
|
| `allowlist` | Only user IDs in `allowFrom` can DM the agent (**default**) |
|
|
297
335
|
| `open` | Anyone can DM the agent |
|
|
298
|
-
| `pairing` | New users DM the bot to receive a pairing code; approve with `
|
|
336
|
+
| `pairing` | New users DM the bot to receive a pairing code; approve with `claude-gateway channels approve` |
|
|
299
337
|
|
|
300
338
|
### `gateway.headless`
|
|
301
339
|
|
|
@@ -495,6 +533,8 @@ Network interface the HTTP/WebSocket server binds to. Defaults to `127.0.0.1` (l
|
|
|
495
533
|
|
|
496
534
|
Absolute, externally-reachable origin of the gateway (for example `https://gateway.example.com`, or `https://host.example.com/gateway` behind an ingress path prefix). The process cannot infer its own public URL — it binds localhost by default and sits behind a reverse proxy — so it must be set explicitly for features that hand out a phone-openable link. Currently that is the `/cli` terminal viewer; when `publicUrl` is unset, `/cli` replies that the viewer is not configured. Leave it blank to keep `/cli` disabled. A trailing slash is optional. Use an `https://` origin — Telegram Mini Apps require HTTPS.
|
|
497
535
|
|
|
536
|
+
The CLI does **not** route through this URL when it runs on the gateway's own host: both addresses are the same server, and the public one only adds a reverse-proxy hop that may enforce its own authentication. It talks to the local bind instead, keeping `publicUrl` as a fallback if that address cannot be reached. Pass `--url` to exercise the proxy path deliberately. See [CLI.md](./CLI.md) for the full precedence.
|
|
537
|
+
|
|
498
538
|
```json
|
|
499
539
|
{
|
|
500
540
|
"gateway": {
|
|
@@ -607,6 +647,32 @@ Tools are **prefixed by channel name** to avoid collisions. Each module controls
|
|
|
607
647
|
| `TELEGRAM_RECEIVER_MODE` | `receiver-server.ts` | Polls Telegram, handles commands, POSTs to callback — **no MCP** |
|
|
608
648
|
| `TELEGRAM_SEND_ONLY` | `server.ts` | Exposes MCP tools (`telegram_*`, `cron_*`) — **no polling** |
|
|
609
649
|
|
|
650
|
+
#### Receiver lifecycle
|
|
651
|
+
|
|
652
|
+
Receivers are child processes, so they only stop when the gateway runs its
|
|
653
|
+
shutdown path. Two mechanisms keep them from outliving it:
|
|
654
|
+
|
|
655
|
+
- **`SIGTERM`, `SIGINT` and `SIGHUP` all run the same graceful shutdown.**
|
|
656
|
+
`SIGHUP` matters because Node's default action for it terminates the process
|
|
657
|
+
*without* running handlers — so before this was wired, closing a tmux pane or
|
|
658
|
+
dropping an SSH session killed the gateway and left every receiver reparented
|
|
659
|
+
to `init`. Teardown escalates `SIGTERM` → `SIGKILL` after a short grace period,
|
|
660
|
+
so a receiver wedged in an in-flight long-poll cannot survive it.
|
|
661
|
+
|
|
662
|
+
- **A boot-time sweep reclaims leftovers.** `SIGKILL` and the OOM killer can
|
|
663
|
+
never be handled in-process, so at startup the gateway terminates any
|
|
664
|
+
`receiver-server.ts` process that was spawned from *its own* installation and
|
|
665
|
+
has been reparented to `init` (proof that its supervisor is gone), logging how
|
|
666
|
+
many it reclaimed — and separately warning about any it could **not** reclaim,
|
|
667
|
+
since those are still running. Receivers belonging to another checkout on the
|
|
668
|
+
same host, or to a gateway that is still running, are never touched.
|
|
669
|
+
|
|
670
|
+
On a host where an ancestor is a child subreaper (`systemd --user`,
|
|
671
|
+
`docker run --init`/tini, s6), orphans reparent to that subreaper instead of to
|
|
672
|
+
`init` and the sweep finds nothing. Clean shutdown still works; what is lost is
|
|
673
|
+
the `SIGKILL`/OOM recovery — though such a host usually has a supervisor that
|
|
674
|
+
reaps the process group itself.
|
|
675
|
+
|
|
610
676
|
### Session Persistence
|
|
611
677
|
|
|
612
678
|
History is persisted to `SessionStore` (`.jsonl` files) after each message. When a session is spawned after an idle restart, history is injected into the initial prompt so Claude resumes the conversation seamlessly.
|
|
@@ -637,8 +703,49 @@ update at all, and the message is replaced only if it is deleted or becomes uned
|
|
|
637
703
|
|
|
638
704
|
---
|
|
639
705
|
|
|
706
|
+
## Command Line (CLI)
|
|
707
|
+
|
|
708
|
+
The `claude-gateway` binary doubles as a command-line client for a running gateway — a friendlier alternative to hand-built `curl` calls. It works the same whether the gateway was started with `make start`, pm2, or systemd (it resolves the target from your config). Run it with no arguments to see what it can do; **only `gateway start` boots the server**.
|
|
709
|
+
|
|
710
|
+
```bash
|
|
711
|
+
claude-gateway # help (never starts a server)
|
|
712
|
+
claude-gateway gateway start # run the gateway in the foreground
|
|
713
|
+
claude-gateway gateway status # is it running? which manager owns it?
|
|
714
|
+
claude-gateway service install # run it as a systemd-user (or --manager pm2) service
|
|
715
|
+
claude-gateway update check # newer claude-gateway published?
|
|
716
|
+
claude-gateway claude update # update Claude Code via its own updater
|
|
717
|
+
claude-gateway doctor # check config / key / connectivity
|
|
718
|
+
claude-gateway agents create # interactive wizard — new agent + optional channel
|
|
719
|
+
claude-gateway channels pending --agent alfred # incoming Telegram/Discord pairing requests
|
|
720
|
+
claude-gateway crons list # friendly <noun> <verb> commands
|
|
721
|
+
claude-gateway crons run <jobId>
|
|
722
|
+
claude-gateway debug-bundle # small redacted bundle for a stuck session (works even if the server is down)
|
|
723
|
+
claude-gateway api GET /v1/agents # escape hatch: call any endpoint directly
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
> **Upgrading from < 1.8:** a service unit that runs the binary with no command still starts the
|
|
727
|
+
> gateway, with a deprecation warning. Point `ExecStart` at `claude-gateway gateway start`, or
|
|
728
|
+
> reinstall the unit with `claude-gateway service install`.
|
|
729
|
+
|
|
730
|
+
Working on the CLI itself? The globally installed `claude-gateway` is the published npm package, not
|
|
731
|
+
your checkout, so a bare `claude-gateway` still runs whatever version is on your `PATH`. Use `make cli`
|
|
732
|
+
to build and exercise the local sources instead:
|
|
733
|
+
|
|
734
|
+
```bash
|
|
735
|
+
make cli ARGS="--help"
|
|
736
|
+
make cli ARGS="gateway status"
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
Commands are **generated from the same route manifest the server mounts**, so every endpoint exposed as a friendly command stays in sync with the API automatically. Global flags: `--url`, `--key`, `--json`, `--data <json>`, `--help`.
|
|
740
|
+
|
|
741
|
+
See **[CLI.md](./CLI.md)** for the full command reference.
|
|
742
|
+
|
|
743
|
+
---
|
|
744
|
+
|
|
640
745
|
## HTTP API
|
|
641
746
|
|
|
747
|
+
> For day-to-day operation, prefer the **[CLI](#command-line-cli)** above (`claude-gateway <noun> <verb>`) — it resolves the URL and key for you and is easier to read. This section is the **raw HTTP reference** for programmatic clients and integrations.
|
|
748
|
+
|
|
642
749
|
When `gateway.api.keys` is configured, the gateway exposes a REST API for external clients.
|
|
643
750
|
|
|
644
751
|
Pass API key via `X-Api-Key: <key>` or `Authorization: Bearer <key>` header.
|
|
@@ -686,7 +793,7 @@ Pass API key via `X-Api-Key: <key>` or `Authorization: Bearer <key>` header.
|
|
|
686
793
|
| `POST` | `/api/v1/apps/:name/reconfigure` | Change env vars / host ports on an installed app, with rollback → `jobId` (admin) |
|
|
687
794
|
| `GET` | `/app/:name/:portName/*` | Reverse proxy to installed app (no auth) |
|
|
688
795
|
|
|
689
|
-
**Wizard API** — create agents programmatically with the same flow as the interactive `
|
|
796
|
+
**Wizard API** — create agents programmatically with the same flow as the interactive `claude-gateway agents create` 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.
|
|
690
797
|
|
|
691
798
|
See **[API.md](./API.md)** for full reference with request/response schemas and curl examples.
|
|
692
799
|
|
|
@@ -715,6 +822,8 @@ curl http://localhost:10850/api/v1/apps/jobs/<jobId> -H "X-Api-Key: <key>" | jq
|
|
|
715
822
|
|
|
716
823
|
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.
|
|
717
824
|
|
|
825
|
+
The swap carries live bind-mount data forward into the new app directory. A data directory the app's own container created is owned by that image's uid (postgres leaves its `pgdata` mode 0700), and `rename(2)` on a directory needs write permission on the directory itself — so the gateway user cannot move it. Those paths are moved by a throwaway root helper container instead, mounting the nearest common ancestor of the two app directories so the move stays a real rename rather than a copy; each escalation is logged in the job. If a rollback cannot move such a path back, the update does **not** restart the app on a half-restored directory: the `-failed-` directory holding the live data is kept, the job fails with `ROLLBACK FAILED`, and the log names the paths and the directory to recover them from. That directory is kept for good — the boot sweep that reclaims update scratch dirs skips release snapshots, because it deletes with `sudo rm -rf` and a snapshot can hold the only copy of a database. It reports them on the console instead. The pre-update image tags are restored before that decision and the private `cg-rollback-*` tags are kept, so finishing the recovery by hand starts the restored source on its own build, not on the failed release's.
|
|
826
|
+
|
|
718
827
|
**Reverse proxy configuration:**
|
|
719
828
|
|
|
720
829
|
The gateway proxies `/app/:name/:portName/*` to the app containers. Two env vars control how the gateway reaches them:
|
|
@@ -744,7 +853,7 @@ See **[API.md — App Store section](./API.md#app-store-api)** for the full refe
|
|
|
744
853
|
|
|
745
854
|
```
|
|
746
855
|
claude-gateway/
|
|
747
|
-
├── Makefile ← make start /
|
|
856
|
+
├── Makefile ← make start / cli / mcp-install / release / pm2-* / system-*
|
|
748
857
|
├── config.template.json ← config template (source of truth for migration)
|
|
749
858
|
│
|
|
750
859
|
├── src/ ← Gateway core (TypeScript, compiled to dist/)
|
|
@@ -808,12 +917,10 @@ claude-gateway/
|
|
|
808
917
|
│ └── web-ui.ts ← live HTML dashboard
|
|
809
918
|
│
|
|
810
919
|
├── scripts/
|
|
811
|
-
│ ├──
|
|
812
|
-
│ ├──
|
|
813
|
-
│ ├──
|
|
814
|
-
│
|
|
815
|
-
│ ├── pair.ts ← approve channel pairing (Telegram / Discord)
|
|
816
|
-
│ └── setup-claude-settings.js ← enables channelsEnabled in Claude Code
|
|
920
|
+
│ ├── gen-cli.ts ← generates src/cli/commands.generated.ts + CLI.md from the route registry
|
|
921
|
+
│ ├── mock-line-webhook.ts ← local LINE webhook simulator for dev testing
|
|
922
|
+
│ ├── release.sh ← interactive release (make release)
|
|
923
|
+
│ └── setup-claude-settings.js ← enables channelsEnabled in Claude Code
|
|
817
924
|
│
|
|
818
925
|
└── mcp/ ← MCP server (runs in Bun, separate node_modules)
|
|
819
926
|
├── package.json ← dependencies: grammy, @modelcontextprotocol/sdk
|
|
@@ -987,9 +1094,9 @@ toggle **on**, so pairing works out of the box — no setup needed.
|
|
|
987
1094
|
1. Ask the user to DM the bot — they receive a 6-character pairing code
|
|
988
1095
|
2. Approve it:
|
|
989
1096
|
```bash
|
|
990
|
-
|
|
1097
|
+
claude-gateway channels approve --agent alfred --channel discord --code abc123
|
|
991
1098
|
```
|
|
992
|
-
(
|
|
1099
|
+
(use `--channel telegram` for Telegram; omit `--channel` on `channels pending` to check both)
|
|
993
1100
|
3. The bot confirms pairing within 5 seconds
|
|
994
1101
|
4. Lock down after everyone is paired (optional) — turn the pairing toggle off
|
|
995
1102
|
so unknown senders are dropped silently (the base policy is already
|
|
@@ -1006,7 +1113,7 @@ automatically on read to `{ dmPolicy: "allowlist", pairing: true }`.
|
|
|
1006
1113
|
|
|
1007
1114
|
To manage channels (add/remove Telegram or Discord) on an existing agent:
|
|
1008
1115
|
```bash
|
|
1009
|
-
|
|
1116
|
+
claude-gateway agents update # choose "Connect/update a channel" or "Disconnect a channel"
|
|
1010
1117
|
```
|
|
1011
1118
|
|
|
1012
1119
|
---
|
|
@@ -1158,8 +1265,10 @@ paired, the following commands are available in a private chat:
|
|
|
1158
1265
|
|
|
1159
1266
|
| Command | Description |
|
|
1160
1267
|
|---------|-------------|
|
|
1161
|
-
| `/model` | Show the current AI model |
|
|
1162
|
-
| `/models` | Switch AI model
|
|
1268
|
+
| `/model` | Show the current AI model. On Discord and LINE, `/model <id or alias>` also switches to any model in the list — an id the list does not contain is refused rather than written into `config.json`. **Direct messages only**: switching rewrites `config.json` for the whole agent and restarts every session in every chat, and the group access gates check the guild, channel and mention but never the user. Listing is unrestricted |
|
|
1269
|
+
| `/models` | Switch AI model. On Telegram this is an inline keyboard; selecting a model triggers a graceful restart and notifies when back online, and **Dismiss** closes the picker without changing the model. Discord and LINE have no inline keyboard, so they get the same list as text plus `/model <id or alias>` to pick from it |
|
|
1270
|
+
|
|
1271
|
+
The list behind both commands is the live catalog from `{ANTHROPIC_BASE_URL}/v1/models` when a base URL is configured, falling back to `gateway.models` in `config.json` — see [GET /api/v1/models](API.md#get-apiv1models). Before this, `config.json`'s list was written once at provisioning and never re-read, so a catalog that changed upstream could never reach the picker.
|
|
1163
1272
|
|
|
1164
1273
|
**Account**
|
|
1165
1274
|
|
|
@@ -1205,6 +1314,23 @@ npm test
|
|
|
1205
1314
|
npm run typecheck
|
|
1206
1315
|
```
|
|
1207
1316
|
|
|
1317
|
+
### Writing tests that wait
|
|
1318
|
+
|
|
1319
|
+
Two rules, enforced by `tests/unit/test-timing-hygiene.test.ts`:
|
|
1320
|
+
|
|
1321
|
+
- **Wait for a signal, never for a duration.** `createWatcher()` / `watchWorkspace()` /
|
|
1322
|
+
`watchSkills()` return a handle with a `ready` promise; the PTY wrapper announces itself
|
|
1323
|
+
with a `system/init` event. Sleeping "long enough" instead is a bet on how fast the machine
|
|
1324
|
+
is — and chokidar runs with `ignoreInitial: true`, so a write that lands before its initial
|
|
1325
|
+
scan finishes emits *nothing* and the test waits out its whole deadline for an event that
|
|
1326
|
+
will never arrive.
|
|
1327
|
+
- **Poll with the shared helper**, `tests/helpers/wait-for.ts`, rather than a local copy. Its
|
|
1328
|
+
timeout is a safety net sized so only a broken build hits it, and on a timeout it reports
|
|
1329
|
+
the predicate it was waiting on instead of a bare "timeout exceeded".
|
|
1330
|
+
|
|
1331
|
+
A fixed sleep is still fine for asserting that something *doesn't* happen — there the sleep
|
|
1332
|
+
only bounds how hard the test looks, so a slow machine can't turn correct behaviour red.
|
|
1333
|
+
|
|
1208
1334
|
---
|
|
1209
1335
|
|
|
1210
1336
|
## Troubleshooting
|
|
@@ -10,8 +10,8 @@ exports.BUILTIN_COMMANDS = {
|
|
|
10
10
|
clear: { channels: ['telegram', 'api'] },
|
|
11
11
|
compact: { channels: ['telegram', 'api'] },
|
|
12
12
|
stop: { channels: ['telegram', 'api'], wordBoundary: false },
|
|
13
|
-
model: { channels: ['telegram', 'discord', 'api'] },
|
|
14
|
-
models: { channels: ['telegram'] },
|
|
13
|
+
model: { channels: ['telegram', 'discord', 'line', 'api'] },
|
|
14
|
+
models: { channels: ['telegram', 'discord', 'line'] },
|
|
15
15
|
restart: { channels: ['telegram', 'api'], wordBoundary: false },
|
|
16
16
|
start: { channels: ['telegram'] },
|
|
17
17
|
help: { channels: ['telegram'] },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtin-commands.js","sourceRoot":"","sources":["../../src/agent/builtin-commands.ts"],"names":[],"mappings":";;;AAkDA,4CAEC;AA1CY,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;
|
|
1
|
+
{"version":3,"file":"builtin-commands.js","sourceRoot":"","sources":["../../src/agent/builtin-commands.ts"],"names":[],"mappings":";;;AAkDA,4CAEC;AA1CY,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,MAAM,EAAE,KAAK,CAAC,EAAE;IAC9D,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE;IACvD,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,yEAAyE;IACzE,2EAA2E;IAC3E,4DAA4D;IAC5D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACtC,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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/agent/knowledge/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/agent/knowledge/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EACV,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,8BAA8B,EAC/B,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,gBAAgB,EAAE,2BAK9B,CAAC;AAiBF,wBAAgB,oBAAoB,CAClC,QAAQ,CAAC,EAAE,sBAAsB,EACjC,SAAS,CAAC,EAAE,sBAAsB,GACjC,2BAA2B,CAuB7B;AAID,eAAO,MAAM,eAAe,EAAE,0BAO7B,CAAC;AAcF,wBAAgB,mBAAmB,CACjC,QAAQ,CAAC,EAAE,qBAAqB,EAChC,SAAS,CAAC,EAAE,qBAAqB,GAChC,0BAA0B,CAmB5B;AAID,eAAO,MAAM,mBAAmB,EAAE,8BAQjC,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,QAAQ,CAAC,EAAE,yBAAyB,EACpC,SAAS,CAAC,EAAE,yBAAyB,GACpC,8BAA8B,CAiBhC;AAED,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,GAAG,EAAE,0BAA0B,GAAG,MAAM,CAEtE;AAED,4CAA4C;AAC5C,wBAAgB,YAAY,CAAC,GAAG,EAAE,0BAA0B,GAAG,MAAM,CAEpE;AAED,2FAA2F;AAC3F,wBAAgB,cAAc,CAAC,GAAG,EAAE,0BAA0B,GAAG,MAAM,CAEtE"}
|
|
@@ -52,6 +52,7 @@ const os = __importStar(require("os"));
|
|
|
52
52
|
const path = __importStar(require("path"));
|
|
53
53
|
const config_1 = require("../dreaming/config");
|
|
54
54
|
const config_2 = require("../skill-learning/config");
|
|
55
|
+
const paths_1 = require("../../utils/paths");
|
|
55
56
|
exports.ARCHIVE_DEFAULTS = {
|
|
56
57
|
enabled: true,
|
|
57
58
|
tokenizer: 'unicode61', // "trigram" evaluated for Thai/CJK before locking (planning-64 D5)
|
|
@@ -107,14 +108,6 @@ exports.SHARED_DEFAULTS = {
|
|
|
107
108
|
const PROJECT_KEY_RE = /^[A-Za-z0-9._-]{1,64}$/;
|
|
108
109
|
/** Reserved path segments that must never be used as a project key. */
|
|
109
110
|
const RESERVED_PROJECT_KEYS = new Set(['.', '..']);
|
|
110
|
-
/** Expand a leading `~` to the home dir (mirrors config path handling elsewhere). */
|
|
111
|
-
function expandHome(p) {
|
|
112
|
-
if (p === '~')
|
|
113
|
-
return os.homedir();
|
|
114
|
-
if (p.startsWith('~/'))
|
|
115
|
-
return path.join(os.homedir(), p.slice(2));
|
|
116
|
-
return p;
|
|
117
|
-
}
|
|
118
111
|
function resolveSharedConfig(agentCfg, globalCfg) {
|
|
119
112
|
const d = exports.SHARED_DEFAULTS;
|
|
120
113
|
const rawProject = pick(agentCfg?.project, globalCfg?.project, d.project);
|
|
@@ -122,7 +115,7 @@ function resolveSharedConfig(agentCfg, globalCfg) {
|
|
|
122
115
|
? rawProject
|
|
123
116
|
: d.project;
|
|
124
117
|
const rawRoot = pick(agentCfg?.root, globalCfg?.root, d.root);
|
|
125
|
-
const root = typeof rawRoot === 'string' && rawRoot.trim() ? expandHome(rawRoot.trim()) : d.root;
|
|
118
|
+
const root = typeof rawRoot === 'string' && rawRoot.trim() ? (0, paths_1.expandHome)(rawRoot.trim()) : d.root;
|
|
126
119
|
const mode = pick(agentCfg?.mode, globalCfg?.mode, d.mode);
|
|
127
120
|
return {
|
|
128
121
|
enabled: pick(agentCfg?.enabled, globalCfg?.enabled, d.enabled),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/agent/knowledge/config.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/agent/knowledge/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live chat-model catalog (issue #409).
|
|
3
|
+
*
|
|
4
|
+
* The gateway's model list used to come only from `gateway.models` in
|
|
5
|
+
* config.json, written once at provisioning and never touched again — so a
|
|
6
|
+
* catalog that changed upstream could never reach the `/models` picker or
|
|
7
|
+
* `GET /api/v1/models`. This fetches the catalog from the same endpoint the
|
|
8
|
+
* session already talks to, and falls back to the static list.
|
|
9
|
+
*
|
|
10
|
+
* Provider-agnostic by construction: the base URL and token come from env /
|
|
11
|
+
* `~/.claude/settings.json`, never from a hardcoded vendor host. That mirrors
|
|
12
|
+
* the image tool's catalog fetch (`mcp/tools/image/module.ts`), which solved
|
|
13
|
+
* this same problem for image models. The URL-safety check below is a second
|
|
14
|
+
* implementation of that module's `baseUrlIsSecure` rather than a shared one:
|
|
15
|
+
* `tsconfig.json` pins `rootDir` to `src/`, so nothing here can import from
|
|
16
|
+
* `mcp/`. Keep the two in step.
|
|
17
|
+
*/
|
|
18
|
+
import type { ModelConfig } from '../types';
|
|
19
|
+
/** Fallback context window for a model no catalog — live or static — describes. */
|
|
20
|
+
export declare const DEFAULT_CONTEXT_WINDOW = 200000;
|
|
21
|
+
/** Reset module state. Tests only — each case needs a clean cache. */
|
|
22
|
+
export declare function resetModelCatalogCache(): void;
|
|
23
|
+
/** Tests only — the settings file is otherwise re-read at most once per {@link CATALOG_TTL_MS}. */
|
|
24
|
+
export declare function resetSettingsEnvCache(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Where to fetch the catalog from. `MODELS_BASE_URL` lets a deployment point
|
|
27
|
+
* the catalog at a different host than the messages endpoint; otherwise it is
|
|
28
|
+
* the same `ANTHROPIC_BASE_URL` the session process already uses. Empty means
|
|
29
|
+
* "not configured", which is the signal to stay on the static list.
|
|
30
|
+
*/
|
|
31
|
+
export declare function catalogBaseUrl(now?: number): string;
|
|
32
|
+
/**
|
|
33
|
+
* https is required for a public catalog host — the bearer token rides every
|
|
34
|
+
* call. http is tolerated only for a local/internal hop, where cleartext never
|
|
35
|
+
* leaves the machine or network.
|
|
36
|
+
*/
|
|
37
|
+
export declare function baseUrlIsSecure(raw: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Turn a catalog response into `ModelConfig[]`, or null when it carries no
|
|
40
|
+
* usable model.
|
|
41
|
+
*
|
|
42
|
+
* Two response shapes are accepted because two are in the wild: Anthropic's
|
|
43
|
+
* `{ data: [{ id, display_name }] }` and the `{ models: [{ id, label }] }`
|
|
44
|
+
* shape this gateway's own endpoints emit. A proxy may front either.
|
|
45
|
+
*
|
|
46
|
+
* `alias`, `contextWindow` and `multiplier` are not part of any catalog
|
|
47
|
+
* response, so they are carried over from the static entry with the same id.
|
|
48
|
+
* That matters beyond cosmetics: `/session` reports context use as a
|
|
49
|
+
* percentage of `contextWindow`, and `/compact` sizes its window from it — a
|
|
50
|
+
* live model that lost those fields would silently report against 200k.
|
|
51
|
+
*/
|
|
52
|
+
export declare function parseModelCatalog(body: unknown, fallback: ModelConfig[]): ModelConfig[] | null;
|
|
53
|
+
/**
|
|
54
|
+
* Fetch the live catalog, or return null to mean "use the static list".
|
|
55
|
+
*
|
|
56
|
+
* Never throws and never rejects: every caller is a picker or a list endpoint
|
|
57
|
+
* whose correct behaviour on any failure is to show the static list. A cached
|
|
58
|
+
* result is reused for {@link CATALOG_TTL_MS}; concurrent callers share one
|
|
59
|
+
* request.
|
|
60
|
+
*/
|
|
61
|
+
export declare function fetchModelCatalog(fallback: ModelConfig[], now?: number): Promise<ModelConfig[] | null>;
|
|
62
|
+
//# sourceMappingURL=model-catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../../src/agent/model-catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AA4B5C,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,SAAU,CAAC;AAc9C,sEAAsE;AACtE,wBAAgB,sBAAsB,IAAI,IAAI,CAK7C;AA+BD,mGAAmG;AACnG,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAmB,GAAG,MAAM,CAM/D;AAWD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA0BpD;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,GAAG,IAAI,CAkE9F;AAID;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,WAAW,EAAE,EACvB,GAAG,GAAE,MAAmB,GACvB,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAqD/B"}
|