myapikey 0.19.0 → 0.19.2

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 CHANGED
@@ -2,311 +2,134 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/myapikey?logo=npm)](https://www.npmjs.com/package/myapikey)
4
4
  [![license](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
5
- [![node](https://img.shields.io/badge/node.js-%3E%3D18-339933?logo=node.js&logoColor=white)](#quick-start)
5
+ [![node](https://img.shields.io/badge/node.js-%3E%3E18-339933?logo=node.js&logoColor=white)](#up-and-running-in-60-seconds)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript&logoColor=white)](#development)
7
7
 
8
8
  English | [简体中文](README.zh-CN.md)
9
9
 
10
- **One address, one key, all your models without translation.**
10
+ **One address, one key, every AI tool you use.** A tiny self-hosted LLM gateway for your home server: keep your provider keys in one place, point every tool at the same URL with the same key, and fail over automatically when a backend breaks.
11
11
 
12
- MyAPIKey is a personal LLM gateway. Point every AI tool you use (Claude Code, OpenAI-compatible CLIs, editors, scripts) at a single local address with a single API key. Each call is forwarded **as-is** to a backend that speaks the same wire format, with automatic failover when a backend is down. Nothing is converted between OpenAI and Anthropic formats — what you send is exactly what reaches the backend.
12
+ ## Sound familiar?
13
13
 
14
- > Built for a home server / LAN. No database, no TLS by default, no translation layer just a thin, transparent forwarder you fully control.
14
+ - You use **Claude Code, a few OpenAI-compatible CLIs, editor plugins, scripts** and each one needs its own base URL + API key pasted in.
15
+ - Your **real keys** (OpenAI, Anthropic, OpenRouter, a local Ollama…) are scattered across a dozen config files. Rotating one means remembering everywhere it's pasted.
16
+ - Your **main provider 429s or goes down** mid-task and the tool just dies. Switching to a backup means re-editing configs.
17
+ - You tried **one-api / new-api-style gateways**, which *translate* between formats — and drop fields, mangle streams, or hold new upstream parameters hostage until someone updates the gateway.
15
18
 
16
- ---
19
+ MyAPIKey is built to end exactly this.
17
20
 
18
- ## Table of contents
21
+ ## What you get
19
22
 
20
- - [What is this, and who is it for?](#what-is-this-and-who-is-it-for)
21
- - [Quick start](#quick-start)
22
- - [Add your first backend](#add-your-first-backend)
23
- - [Connect a tool](#connect-a-tool)
24
- - [How routing works](#how-routing-works)
25
- - [Model name mapping](#model-name-mapping)
26
- - [Web UI](#web-ui)
27
- - [CLI reference](#cli-reference)
28
- - [API surface](#api-surface)
29
- - [Storage](#storage)
30
- - [Development](#development)
31
- - [Notes and non-goals](#notes-and-non-goals)
23
+ - **One address, one key.** Every tool points at `http://<your-server>:7800` with a single `sk-myapikey-…` key. Real provider keys live only inside the gateway — rotate one, swap a backend, and no tool config ever changes again.
24
+ - **Automatic failover + circuit breaker.** Give a model an ordered chain of backends. On `429` / `5xx` / timeout the next one takes over; a source that keeps failing cools down (30 s → 5 min) so later calls skip it. Your agent never notices.
25
+ - **Pure passthrough, zero translation.** OpenAI-format calls reach OpenAI-speaking backends, Anthropic-format calls reach Anthropic-speaking backends — bodies forwarded byte-for-byte, streaming straight through. New upstream fields and parameters work without the gateway "supporting" them first.
26
+ - **Rate limiting that queues instead of 429ing.** Cap each backend's rpm, or give a model an even per-minute pace; excess calls wait in the gateway instead of coming straight back as `429`.
27
+ - **Model name mapping.** Expose a friendly name to your tools (`claude-sonnet-4`); each backend maps it to its own real id (`claude-sonnet-4-20250514` here, something else there).
28
+ - **A default thinking level per slot.** Pin a reasoning effort / token budget on a route; it overrides whatever the request carried — handy for taming Claude Code.
29
+ - **See everything.** Web UI (English / 简体中文): live call log, success rate, p50/p95 latency, per-model / per-backend / per-day stats. The CLI can do all of it too.
30
+ - **Featherweight.** No database — one `data.json` plus a `logs.jsonl`. Runs with `npx`. Built for LAN / home-server use.
32
31
 
33
- ---
32
+ ## Up and running in 60 seconds
34
33
 
35
- ## What is this, and who is it for?
36
-
37
- If any of these sound familiar, MyAPIKey is for you:
38
-
39
- - You juggle **several API keys** across OpenAI, Anthropic, OpenRouter, a local model, etc., and you're tired of pasting a different one into every tool.
40
- - You want **one stable address** for your agents, even when the provider behind it changes.
41
- - You want **automatic fallback** — if your primary backend rate-limits or goes down, the next one takes over.
42
- - You want to **rename or swap a model** without editing every tool's config.
43
- - You'd like a **log of every call** (latency, status, which backend served it).
44
-
45
- MyAPIKey gives you all of that. You keep your real provider keys inside the gateway; your tools only ever know `http://<host>:7800` and one `sk-myapikey-…` key.
46
-
47
- **The one thing to know up front:** the gateway **forwards in your tool's native format and never translates**. A call to the OpenAI endpoint reaches an OpenAI-speaking backend; a call to the Anthropic endpoint reaches an Anthropic-speaking backend. This keeps your requests and responses lossless. (See [How routing works](#how-routing-works) once you're set up.)
48
-
49
- ---
50
-
51
- ## Quick start
52
-
53
- Requires **Node.js 18+**. No install needed — run it straight from npm:
34
+ Requires Node.js 18+.
54
35
 
55
36
  ```bash
56
37
  npx myapikey serve # → http://localhost:7800
57
38
  ```
58
39
 
59
- Or install it globally:
60
-
61
- ```bash
62
- npm install -g myapikey
63
- myapikey serve
64
- ```
65
-
66
- On first run it prints generated credentials **and saves them to a file** so you can't lose them:
67
-
68
- ```
69
- First run — here are your credentials (save them):
70
- username : <random> (web login)
71
- password : <random> (web login)
72
- api key : sk-myapikey-… (put this in the tool's "api key" field)
73
- ↳ also written to ~/.myapikey/credentials.txt
74
- ```
75
-
76
- Open `http://localhost:7800` in a browser and sign in with the **username / password** to reach the web UI. The **API key** is separate — that's what your AI tools use later.
77
-
78
- > Forgot the credentials? `cat ~/.myapikey/credentials.txt` (regenerated on every start). Override the data location with `--data-dir <path>` or the `MYAPIKEY_DATA_DIR` env var.
40
+ First run prints your credentials and also saves them to `~/.myapikey/credentials.txt`:
79
41
 
80
- That's the gateway running. Next, give it a backend to forward to.
81
-
82
- ---
83
-
84
- ## Add your first backend
85
-
86
- A **backend** (provider) is one upstream API: OpenAI, Anthropic, OpenRouter, a local Ollama, a vendor like Volcengine Ark, etc. You add it once with its real key, then enable models through it.
87
-
88
- ### Easiest: the web UI
89
-
90
- 1. Open the **Models** tab → **Add backend**.
91
- 2. Enter a name, the backend's base URL(s), and its API key.
92
- 3. Pick the wire format(s) it speaks: `openai`, `anthropic` (or both).
93
- 4. Save, then click **discover** to pull its model list.
94
- 5. **Enable** the models you want, per format slot.
95
-
96
- ### Or, the CLI
97
-
98
- ```bash
99
- # An OpenAI-compatible backend. The OpenAI base includes the version segment
100
- # (e.g. /v1, or a vendor's own like Ark's /api/v3).
101
- myapikey provider add openai-direct \
102
- --base-url-openai https://api.openai.com/v1 \
103
- --key sk-... \
104
- --formats openai
105
-
106
- # An Anthropic backend. The Anthropic base EXCLUDES /v1
107
- # (https://api.anthropic.com, or Ark's /api/plan).
108
- myapikey provider add anthropic-direct \
109
- --base-url-anthropic https://api.anthropic.com \
110
- --key sk-ant-... \
111
- --formats anthropic
112
-
113
- # See what each offers, then enable a model on a slot:
114
- myapikey provider models openai-direct
115
- myapikey model enable gpt-4o-mini --format openai --via openai-direct
116
- ```
117
-
118
- That model is now reachable through the gateway. To add a **fallback** for the same model (used when the first one fails), add another backend and chain it:
42
+ 1. Open `http://localhost:7800` and sign in with the printed **username / password** (web login).
43
+ 2. **Models** tab → **Add backend**: paste the backend's base URL + its real API key, tick the formats it speaks (`openai` / `anthropic`), then **discover** → **enable** the models you want.
44
+ 3. Point your tools at the gateway — every tool's "API key" field gets the **gateway key**, not your web password:
119
45
 
120
46
  ```bash
121
- myapikey provider add backup --base-url-openai https://api.openrouter.ai/api/v1 --key sk-or-... --formats openai
122
- myapikey model add-provider gpt-4o-mini backup --format openai
123
- myapikey model prioritize gpt-4o-mini openai-direct backup --format openai # left = primary
124
- myapikey model list # see the routing table
125
- ```
126
-
127
- > `--format` selects the routing **slot**: `openai` (for `/openai/v1/chat/completions`), `anthropic` (for `/anthropic/v1/messages`), or `responses` (for `/openai/v1/responses`). The `responses` slot only accepts backends you've marked **supportsResponses** — set that toggle in the web UI (the CLI doesn't expose it yet).
128
-
129
- ---
130
-
131
- ## Connect a tool
132
-
133
- Once a model is enabled, point any agent at the gateway. Get your connection info:
134
-
135
- ```bash
136
- myapikey whoami # prints base url + api key + ready-to-paste env lines
137
- ```
138
-
139
- For an **OpenAI-compatible** tool (covers `/chat/completions` *and* `/responses`):
47
+ # Claude Code / anything Anthropic
48
+ export ANTHROPIC_BASE_URL=http://localhost:7800/anthropic
49
+ export ANTHROPIC_API_KEY=sk-myapikey-…
140
50
 
141
- ```bash
51
+ # OpenAI-compatible tools (Codex, CLIs, plugins)
142
52
  export OPENAI_BASE_URL=http://localhost:7800/openai/v1
143
- export OPENAI_API_KEY=<gateway api key>
144
- ```
145
-
146
- For **Anthropic / Claude Code**:
147
-
148
- ```bash
149
- export ANTHROPIC_BASE_URL=http://localhost:7800/anthropic
150
- export ANTHROPIC_API_KEY=<gateway api key>
53
+ export OPENAI_API_KEY=sk-myapikey-…
151
54
  ```
152
55
 
153
- > Whatever a tool calls its "API key" field, put the **gateway API key** there *not* your web login password. The login password is only for the web UI and CLI admin commands.
56
+ > Why `…/openai/v1` but `…/anthropic`? Each SDK appends its own paths (OpenAI adds `/chat/completions`, Anthropic adds `/v1/messages`), so the gateway follows each ecosystem's own convention. Each surface also has its own `/models`, listing only models enabled for that format. `myapikey whoami` prints all of this ready to paste, anytime.
154
57
 
155
- Quick smoke test without any tool:
58
+ 4. Smoke test without any tool:
156
59
 
157
60
  ```bash
158
61
  myapikey call gpt-4o-mini "Say hello in one sentence."
159
62
  ```
160
63
 
161
- **Why two base URLs?** The gateway exposes two separate agent surfaces — `/openai/v1` and `/anthropic/v1` each with its own `GET /models` (an OpenAI client discovers only openai-enabled models, an Anthropic client only anthropic-enabled ones). Each ecosystem's SDK appends its own paths, so the OpenAI SDK points at `…/openai/v1` (it appends `/chat/completions`, `/responses`, `/models`) and the Anthropic SDK / Claude Code points at `…/anthropic` (it appends `/v1/messages`, `/v1/models`).
162
-
163
- **Raw HTTP** (no SDK) — hit either surface directly with the gateway API key as a `Bearer` token:
164
-
165
- ```bash
166
- # OpenAI family
167
- curl http://localhost:7800/openai/v1/chat/completions \
168
- -H "Authorization: Bearer <gateway api key>" -H "Content-Type: application/json" \
169
- -d '{"model":"<model>","messages":[{"role":"user","content":"hi"}]}'
170
-
171
- # Anthropic family
172
- curl http://localhost:7800/anthropic/v1/messages \
173
- -H "Authorization: Bearer <gateway api key>" -H "Content-Type: application/json" \
174
- -d '{"model":"<model>","max_tokens":16,"messages":[{"role":"user","content":"hi"}]}'
175
- ```
176
-
177
- Whichever endpoint you point a tool at, the gateway forwards in that format and never translates — so make sure each model you call is backed by at least one source on the matching slot ([see below](#how-routing-works)).
178
-
179
- ---
64
+ Prefer the terminal? `provider add` `provider models` `model enable` does the same job cheat sheet below.
180
65
 
181
- ## How routing works
66
+ ## How routing works (the whole story)
182
67
 
183
- The gateway is a **directional forwarder, not a translator**. Four rules explain everything:
68
+ - The gateway has two entrances: `/openai/v1/*` (chat completions, responses, models) and `/anthropic/v1/*` (messages, models). A request is forwarded in the entrance's format, **never translated**.
69
+ - Each model has an independent, ordered backend chain **per format**. Within a chain, `429` / `5xx` / timeouts fail over to the next backend; other `4xx` errors come back as-is (they're the caller's fault, not the backend's). No failover once streaming has started. If no backend serves that model on that format, you get a `404` — a clear failure beats a silent translation.
70
+ - Anything that speaks either format works: OpenAI, Anthropic, OpenRouter, Ollama / vLLM, Volcengine Ark, your company's internal gateway…
184
71
 
185
- 1. **The endpoint picks the slot.** `/openai/v1/chat/completions` → the **openai** slot. `/openai/v1/responses` → the **responses** slot. `/anthropic/v1/messages` → the **anthropic** slot. Each is a distinct wire format, and the body is forwarded verbatim — nothing is converted.
72
+ ## Why no translation?
186
73
 
187
- 2. **Each model has three independent slots.** For one model you can enable `openai`, `responses`, and `anthropic` separately, and each has its own ordered source chain. Enable a model only on the slots its backends actually speak.
74
+ one-api / new-api convert OpenAI Anthropic shapes. Convenient, until a field gets dropped, a stream gets mangled, or a new upstream parameter needs a gateway update before you can send it. OpenRouter is hosted and takes a cut per call. MyAPIKey's answer is to not have a translation layer at all:
188
75
 
189
- 3. **A source qualifies per slot.** The `openai` and `anthropic` slots accept sources carrying that wire format; the `responses` slot only accepts sources marked `supportsResponses` (most OpenAI-compatible backends don't implement the Responses API). A `supportsResponses` source can sit in the **openai** chain *and* the **responses** chain at once.
76
+ | | MyAPIKey | one-api / new-api | OpenRouter |
77
+ |---|---|---|---|
78
+ | Deploy | self-hosted, one `npx` | self-hosted, heavier | hosted service |
79
+ | Cost | free | free | markup per call |
80
+ | Formats | passthrough, byte-for-byte | translated | translated |
81
+ | New upstream params | work immediately | wait for gateway support | wait for platform support |
82
+ | Provider keys | on your machine | on your machine | on their platform |
190
83
 
191
- 4. **Priority + failover, within a slot.** Candidates are tried in your priority order. On `429` / `5xx` / timeout, the gateway tries the next one — and the failing source enters a brief **circuit-breaker cooldown** (exponential, 30 s → 5 min) so later calls skip it until it recovers; a success closes the circuit. Other `4xx` errors are returned as-is (they're the caller's fault, not the backend's). Once streaming has started, there's no failover.
84
+ The trade-off, stated plainly: an Anthropic-format backend cannot be called through the OpenAI entrance. If what you want is format conversion, this isn't your tool (yet).
192
85
 
193
- **The trade-off this buys you:** call an endpoint no source serves for that model and you get a `404` — not a silent translation. That's the price of zero-loss passthrough. (Translation could be layered on later without changing the agent-facing endpoints.)
86
+ ## Managing it
194
87
 
195
- This is the core difference from aggregators like OpenRouter or one-api, which convert between OpenAI and Anthropic request/response shapes.
88
+ **Web UI** `http://localhost:7800`, English + 简体中文. Five tabs: **Connect** (copy-paste-ready env lines), **Models** (backends, discovery, per-format enable, drag-to-order chains, name mapping, test call), **Logs** (live timeline), **Stats** (counts, success rate, p50/p95 by model / backend / day), **Settings** (rotate API key, change password, circuit-breaker state, storage paths).
196
89
 
197
- ---
90
+ **CLI cheat sheet** (same admin API as the web UI — the two never drift apart):
198
91
 
199
- ## Model name mapping
200
-
201
- Sometimes the name a tool asks for isn't the name the backend expects. MyAPIKey can **rewrite the model name per source**, on the way through — still pure passthrough, no format translation.
202
-
203
- Set it in the web UI (**Models** tab): when adding a source, there's an **upstream model** field; or edit it inline on any chain member. (Not exposed in the CLI yet.)
204
-
205
- Use it to:
206
-
207
- - **Alias a friendly name to a versioned id** — expose `claude-sonnet-4` to your tools, while the gateway sends `claude-sonnet-4-20250514` upstream.
208
- - **Point one public name at different real models per source** — e.g. your `gpt-4` slot's primary source sends `gpt-4o`, its fallback sends `gpt-4-turbo`.
209
- - **Bridge naming quirks** between two backends that implement the "same" model under different ids.
210
-
211
- If no mapping is set for a source, the public model name is sent unchanged.
212
-
213
- ---
214
-
215
- ## Web UI
216
-
217
- Visit `http://localhost:7800`, sign in with your username/password. Ships in **English and Chinese** (toggle in the top bar). Five tabs:
218
-
219
- - **Connect** — copy-paste base URL / API key / login, plus ready-to-use SDK env lines.
220
- - **Models** — full CRUD: add sources, discover & enable models per slot, drag-order priority, toggle each slot, set [model name mapping](#model-name-mapping), and run an end-to-end **test** call against any model + slot.
221
- - **Logs** — live recent-calls timeline (latency, status, source, format), with circuit-breaker cooldown events shown alongside the failures that triggered them.
222
- - **Stats** — aggregate call counts / success rate / latency (p50, p95) by model, source, format, and day, over a selectable range (24h / 7d / 30d / 90d / all).
223
- - **Settings** — rotate the API key, change the account password, view/reset circuit-breaker state, and see where `data.json` + `logs.jsonl` live.
92
+ | I want to… | Command |
93
+ |---|---|
94
+ | run the gateway | `myapikey serve [--port 7800] [--data-dir <dir>]` |
95
+ | print what to paste into tools | `myapikey whoami` |
96
+ | add a backend | `myapikey provider add <name> --base-url-openai https://api.openai.com/v1 --key sk-… --formats openai` |
97
+ | see a backend's models | `myapikey provider models <name>` |
98
+ | enable a model | `myapikey model enable <model> --format openai --via <backend>` |
99
+ | add a fallback + set order | `myapikey model add-provider <model> <backend> --format openai` · `myapikey model prioritize <model> <primary> <backup> --format openai` |
100
+ | see the routing table | `myapikey model list` |
101
+ | pace a model | `myapikey model pace <model> <rpm\|0>` |
102
+ | pin a slot's thinking level | `myapikey model thinking <model> <index> [value] --format <fmt>` |
103
+ | quick test | `myapikey call <model> "hi"` |
224
104
 
225
- It's the same admin API the CLI uses configure either way.
105
+ > OpenAI base URLs **include** the version segment (`/v1`, Ark's `/api/v3`); Anthropic base URLs **exclude** it (`https://api.anthropic.com`). The `responses` format only accepts backends you've marked `supportsResponses` (web UI toggle).
106
+ > CLI global flags: `-u/--url`, `--user`, `--pass`, `--api-key`, or env `MYAPIKEY_URL` / `MYAPIKEY_USER` / `MYAPIKEY_PASS` / `MYAPIKEY_API_KEY`.
226
107
 
227
- ---
108
+ ## Where your data lives
228
109
 
229
- ## CLI reference
110
+ One directory (default `~/.myapikey`, override with `--data-dir` or `MYAPIKEY_DATA_DIR`):
230
111
 
231
- | Command | |
112
+ | File | What |
232
113
  |---|---|
233
- | `serve [--port 7800] [--data-dir <dir>] [--web-dir <path>]` | run the gateway |
234
- | `whoami` | print connection info for agents (base url, api key, login, example env) |
235
- | `provider add <name> --base-url-openai URL [--base-url-anthropic URL] --key KEY --formats openai,anthropic` | add a backend (set `supportsResponses` in the web UI) |
236
- | `provider list` | list backends |
237
- | `provider models <ref>` | discover models offered by a backend |
238
- | `provider remove <ref>` | remove a backend (id or name) |
239
- | `model enable <name> --format <fmt> [--via <ref>]` | enable a model on a slot (openai / anthropic / responses) |
240
- | `model disable <name> --format <fmt>` | disable one slot (keeps config) |
241
- | `model list` | show the per-slot routing table |
242
- | `model add-provider <name> <ref> --format <fmt>` | add a fallback source for a slot |
243
- | `model remove-provider <name> <ref> --format <fmt>` | remove a source from a slot |
244
- | `model prioritize <name> <ref>... --format <fmt>` | set source order for a slot (left = primary) |
245
- | `model remove <name>` | remove a model entirely (all slots) |
246
- | `call <model> [prompt...]` | quick test through the gateway (OpenAI path) |
247
-
248
- `<ref>` is a provider id or name. Global flags: `-u/--url`, `--user`, `--pass`, `--api-key` (or `MYAPIKEY_URL` / `MYAPIKEY_USER` / `MYAPIKEY_PASS` / `MYAPIKEY_API_KEY` env vars).
249
-
250
- ---
251
-
252
- ## API surface
253
-
254
- **Agent-facing (two surfaces, one API key — `Authorization: Bearer` or `x-api-key`):**
255
-
256
- - `POST /openai/v1/chat/completions` — OpenAI-format proxy
257
- - `POST /openai/v1/responses` — OpenAI Responses API (only sources marked `supportsResponses`)
258
- - `GET /openai/v1/models` — models enabled on the **openai** slot, OpenAI list shape (public — no key needed)
259
- - `POST /anthropic/v1/messages` — Anthropic-format proxy
260
- - `GET /anthropic/v1/models` — models enabled on the **anthropic** slot, Anthropic list shape (public — no key needed)
261
- - `GET /health` — public liveness check
262
-
263
- **Admin (`/admin`, account password — HTTP Basic):**
264
-
265
- - `/admin/account` `GET` / `PUT` — read or change username/password (either field optional)
266
- - `/admin/api-key` `GET`, `/admin/api-key/rotate` `POST` — the key agents use
267
- - `/admin/connection` `GET` — detected LAN IP (for pointing other machines at the gateway)
268
- - `/admin/providers`, `/admin/providers/:id` `POST`/`PUT`/`DELETE`, `/admin/providers/:id/discover` `POST` — backend CRUD + model discovery
269
- - `/admin/models`, `/admin/models/:name/{providers,priority,map,disable,test}` — routing-table CRUD, [per-source name mapping](#model-name-mapping), and end-to-end test
270
- - `/admin/logs` `GET` — recent calls (tail of the on-disk log)
271
- - `/admin/stats?range=24h|7d|30d|90d|all` `GET` — aggregate stats over retained history
272
- - `/admin/storage` `GET` — where `data.json` + `logs.jsonl` live
273
- - `/admin/circuit` `GET`, `/admin/circuit/:id/reset` `POST` — circuit-breaker snapshot + manual reset
274
-
275
- ---
276
-
277
- ## Storage
278
-
279
- Everything lives in one data directory (default `~/.myapikey`):
280
-
281
- | File | Contents |
282
- |---|---|
283
- | `data.json` | all config — providers, the per-model routing table, account, API key |
284
- | `logs.jsonl` | call history, one JSON object per line (retained ~90 days / 1 M lines) |
285
- | `credentials.txt` | human-readable web login + API key, regenerated on every startup |
286
- | `client.json` | CLI client profile (base url + login + API key) |
287
-
288
- Override the directory with `--data-dir <path>` or `MYAPIKEY_DATA_DIR`. Call logs are never held in memory: the Logs timeline tail-reads the newest ~200 entries, and stats stream over the full retained file on demand.
289
-
290
- ---
114
+ | `data.json` | all config: backends, routing table, account, API key |
115
+ | `logs.jsonl` | call history (kept ~90 days / 1 M lines) |
116
+ | `credentials.txt` | your login + API key in plain text, rewritten every start |
117
+ | `client.json` | the CLI's saved connection profile |
291
118
 
292
119
  ## Development
293
120
 
294
121
  ```bash
295
122
  npm install
296
- npm run build:web # build the Vue UI into packages/web/dist (one time, and after UI changes)
297
- npm start # tsx ... serve (gateway on :7800)
298
- npm run dev # gateway, with watch reload
299
- npm run dev:web # vite dev server (proxies /openai, /anthropic, and /admin to :7800)
300
- npm run typecheck # tsc (core) + vue-tsc (web)
123
+ npm run build:web # build the Vue UI into packages/web/dist
124
+ npm run dev # gateway with watch reload
125
+ npm run dev:web # vite dev server (proxies API calls to :7800)
126
+ npm test # vitest unit + integration
127
+ npm run test:e2e # playwright against a real gateway process
128
+ npm run typecheck # tsc + vue-tsc
301
129
  ```
302
130
 
303
- Testing the gateway by hand: spin up a mock upstream and run `serve` on a scratch port with `--data-dir /tmp/myapikey`.
304
-
305
- ---
306
-
307
- ## Notes and non-goals
131
+ ## Honest limits
308
132
 
309
- - **No OpenAI↔Anthropic translation.** If a backend doesn't speak the format an agent used, that call fails (`404`). Addable later without changing the agent contract.
310
- - **No database.** One `data.json` for config; `logs.jsonl` for retained call history.
311
- - **No TLS.** Intended for LAN / home-server use on your own network. Put it behind a reverse proxy with TLS if you expose it beyond that.
312
- - **The login password and the API key are separate.** The API key is what agents use; rotate it (`POST /admin/api-key/rotate` or the web UI) if a tool's config leaks. Don't hand either to untrusted code.
133
+ - **No OpenAI↔Anthropic translation.** Wrong entrance for a model `404`.
134
+ - **Single user, no TLS.** Meant for your own network; put a reverse proxy in front if you expose it.
135
+ - **Web password ≠ API key.** The password administers the UI/CLI; agents use the `sk-myapikey-…` key. If a tool config leaks, rotate the key (Settings, or `POST /admin/api-key/rotate`) and nothing else changes.