aigetwey 1.0.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/CHANGELOG.md +84 -0
- package/LICENSE +21 -0
- package/README.md +302 -0
- package/assets/logo.svg +8 -0
- package/assets/screenshot.png +0 -0
- package/assets/wordmark.svg +9 -0
- package/config.example.yaml +56 -0
- package/dashboard/.env.example +12 -0
- package/dashboard/next-env.d.ts +6 -0
- package/dashboard/next.config.ts +12 -0
- package/dashboard/package-lock.json +1771 -0
- package/dashboard/package.json +29 -0
- package/dashboard/postcss.config.mjs +5 -0
- package/dashboard/src/app/(console)/combos/page.tsx +10 -0
- package/dashboard/src/app/(console)/config/page.tsx +5 -0
- package/dashboard/src/app/(console)/console/page.tsx +92 -0
- package/dashboard/src/app/(console)/endpoint/page.tsx +5 -0
- package/dashboard/src/app/(console)/layout.tsx +17 -0
- package/dashboard/src/app/(console)/page.tsx +8 -0
- package/dashboard/src/app/(console)/providers/[id]/page.tsx +6 -0
- package/dashboard/src/app/(console)/providers/page.tsx +5 -0
- package/dashboard/src/app/(console)/quota/page.tsx +5 -0
- package/dashboard/src/app/(console)/tools/[id]/page.tsx +6 -0
- package/dashboard/src/app/(console)/tools/page.tsx +5 -0
- package/dashboard/src/app/(console)/usage/page.tsx +24 -0
- package/dashboard/src/app/api/cli-detect/[tool]/route.ts +253 -0
- package/dashboard/src/app/api/gw/[...path]/route.ts +89 -0
- package/dashboard/src/app/api/login/route.ts +30 -0
- package/dashboard/src/app/api/logout/route.ts +9 -0
- package/dashboard/src/app/api/password/route.ts +34 -0
- package/dashboard/src/app/globals.css +340 -0
- package/dashboard/src/app/icon.svg +8 -0
- package/dashboard/src/app/layout.tsx +28 -0
- package/dashboard/src/app/login/page.tsx +60 -0
- package/dashboard/src/components/AreaChart.tsx +115 -0
- package/dashboard/src/components/Badge.tsx +32 -0
- package/dashboard/src/components/Button.tsx +60 -0
- package/dashboard/src/components/CapacityBadges.tsx +40 -0
- package/dashboard/src/components/Checkbox.tsx +40 -0
- package/dashboard/src/components/CliToolConfig.tsx +63 -0
- package/dashboard/src/components/ConfigEditor.tsx +199 -0
- package/dashboard/src/components/ConfirmModal.tsx +36 -0
- package/dashboard/src/components/CooldownTimer.tsx +42 -0
- package/dashboard/src/components/EndpointView.tsx +439 -0
- package/dashboard/src/components/Icon.tsx +25 -0
- package/dashboard/src/components/KeyReveal.tsx +78 -0
- package/dashboard/src/components/Lamp.tsx +8 -0
- package/dashboard/src/components/LogTable.tsx +223 -0
- package/dashboard/src/components/LogoutButton.tsx +20 -0
- package/dashboard/src/components/ModelPicker.tsx +121 -0
- package/dashboard/src/components/ModelSelectModal.tsx +126 -0
- package/dashboard/src/components/PasswordEditor.tsx +86 -0
- package/dashboard/src/components/PricingEditor.tsx +171 -0
- package/dashboard/src/components/ProviderDetail.tsx +566 -0
- package/dashboard/src/components/ProviderManager.tsx +311 -0
- package/dashboard/src/components/QuotaView.tsx +78 -0
- package/dashboard/src/components/Rail.tsx +82 -0
- package/dashboard/src/components/RichCard.tsx +46 -0
- package/dashboard/src/components/RoutingView.tsx +329 -0
- package/dashboard/src/components/ThemeProvider.tsx +36 -0
- package/dashboard/src/components/ToastProvider.tsx +58 -0
- package/dashboard/src/components/ToolDetail.tsx +475 -0
- package/dashboard/src/components/TopBar.tsx +128 -0
- package/dashboard/src/components/UsageView.tsx +151 -0
- package/dashboard/src/components/ui.tsx +54 -0
- package/dashboard/src/lib/capabilities.ts +318 -0
- package/dashboard/src/lib/cliTools.ts +120 -0
- package/dashboard/src/lib/client.ts +190 -0
- package/dashboard/src/lib/gateway.ts +269 -0
- package/dashboard/src/lib/session.ts +71 -0
- package/dashboard/src/middleware.ts +37 -0
- package/dashboard/tsconfig.json +21 -0
- package/dist/adapters/anthropic.js +289 -0
- package/dist/adapters/anthropic.js.map +1 -0
- package/dist/adapters/gemini.js +268 -0
- package/dist/adapters/gemini.js.map +1 -0
- package/dist/adapters/index.js +8 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/openai.js +13 -0
- package/dist/adapters/openai.js.map +1 -0
- package/dist/cli/tray/autostart.js +152 -0
- package/dist/cli/tray/autostart.js.map +1 -0
- package/dist/cli/tray/icon.js +4 -0
- package/dist/cli/tray/icon.js.map +1 -0
- package/dist/cli/tray/tray.js +141 -0
- package/dist/cli/tray/tray.js.map +1 -0
- package/dist/cli/tray/trayRuntime.js +91 -0
- package/dist/cli/tray/trayRuntime.js.map +1 -0
- package/dist/cli.js +361 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +728 -0
- package/dist/config.js.map +1 -0
- package/dist/core/authStore.js +78 -0
- package/dist/core/authStore.js.map +1 -0
- package/dist/core/canonical.js +9 -0
- package/dist/core/canonical.js.map +1 -0
- package/dist/core/console-buffer.js +25 -0
- package/dist/core/console-buffer.js.map +1 -0
- package/dist/core/fallback.js +62 -0
- package/dist/core/fallback.js.map +1 -0
- package/dist/core/handler.js +174 -0
- package/dist/core/handler.js.map +1 -0
- package/dist/core/keypool.js +105 -0
- package/dist/core/keypool.js.map +1 -0
- package/dist/core/quota.js +165 -0
- package/dist/core/quota.js.map +1 -0
- package/dist/core/state.js +52 -0
- package/dist/core/state.js.map +1 -0
- package/dist/db.js +193 -0
- package/dist/db.js.map +1 -0
- package/dist/headroom/compress.js +44 -0
- package/dist/headroom/compress.js.map +1 -0
- package/dist/headroom/detect.js +108 -0
- package/dist/headroom/detect.js.map +1 -0
- package/dist/headroom/process.js +158 -0
- package/dist/headroom/process.js.map +1 -0
- package/dist/inject/caveman.js +30 -0
- package/dist/inject/caveman.js.map +1 -0
- package/dist/inject/index.js +24 -0
- package/dist/inject/index.js.map +1 -0
- package/dist/inject/ponytail.js +19 -0
- package/dist/inject/ponytail.js.map +1 -0
- package/dist/middleware/auth.js +66 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/providers/capabilities.js +246 -0
- package/dist/providers/capabilities.js.map +1 -0
- package/dist/providers/free.js +43 -0
- package/dist/providers/free.js.map +1 -0
- package/dist/providers/pricing.js +224 -0
- package/dist/providers/pricing.js.map +1 -0
- package/dist/providers/vertex.js +97 -0
- package/dist/providers/vertex.js.map +1 -0
- package/dist/routes/admin.js +622 -0
- package/dist/routes/admin.js.map +1 -0
- package/dist/routes/health.js +4 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/index.js +12 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/v1.js +75 -0
- package/dist/routes/v1.js.map +1 -0
- package/dist/rtk/detect.js +50 -0
- package/dist/rtk/detect.js.map +1 -0
- package/dist/rtk/filters.js +85 -0
- package/dist/rtk/filters.js.map +1 -0
- package/dist/rtk/index.js +39 -0
- package/dist/rtk/index.js.map +1 -0
- package/dist/server.js +100 -0
- package/dist/server.js.map +1 -0
- package/dist/stream/anthropic-stream.js +239 -0
- package/dist/stream/anthropic-stream.js.map +1 -0
- package/dist/stream/chunk.js +7 -0
- package/dist/stream/chunk.js.map +1 -0
- package/dist/stream/gemini-stream.js +135 -0
- package/dist/stream/gemini-stream.js.map +1 -0
- package/dist/stream/index.js +12 -0
- package/dist/stream/index.js.map +1 -0
- package/dist/stream/openai-stream.js +34 -0
- package/dist/stream/openai-stream.js.map +1 -0
- package/dist/stream/sse.js +64 -0
- package/dist/stream/sse.js.map +1 -0
- package/dist/translator/thinking.js +70 -0
- package/dist/translator/thinking.js.map +1 -0
- package/dist/translator/thinkingUnified.js +322 -0
- package/dist/translator/thinkingUnified.js.map +1 -0
- package/dist/upstream/client.js +120 -0
- package/dist/upstream/client.js.map +1 -0
- package/package.json +76 -0
- package/run.sh +27 -0
- package/src/adapters/anthropic.ts +377 -0
- package/src/adapters/gemini.ts +341 -0
- package/src/adapters/index.ts +17 -0
- package/src/adapters/openai.ts +22 -0
- package/src/cli/tray/autostart.ts +133 -0
- package/src/cli/tray/icon.ts +4 -0
- package/src/cli/tray/tray.ts +156 -0
- package/src/cli/tray/trayRuntime.ts +90 -0
- package/src/cli.ts +379 -0
- package/src/config.ts +777 -0
- package/src/core/authStore.ts +86 -0
- package/src/core/canonical.ts +93 -0
- package/src/core/console-buffer.ts +39 -0
- package/src/core/fallback.ts +116 -0
- package/src/core/handler.ts +236 -0
- package/src/core/keypool.ts +152 -0
- package/src/core/quota.ts +214 -0
- package/src/core/state.ts +65 -0
- package/src/db.ts +280 -0
- package/src/headroom/compress.ts +78 -0
- package/src/headroom/detect.ts +119 -0
- package/src/headroom/process.ts +166 -0
- package/src/inject/caveman.ts +35 -0
- package/src/inject/index.ts +46 -0
- package/src/inject/ponytail.ts +31 -0
- package/src/middleware/auth.ts +76 -0
- package/src/providers/capabilities.ts +297 -0
- package/src/providers/free.ts +53 -0
- package/src/providers/pricing.ts +261 -0
- package/src/providers/vertex.ts +117 -0
- package/src/routes/admin.ts +716 -0
- package/src/routes/health.ts +5 -0
- package/src/routes/index.ts +24 -0
- package/src/routes/v1.ts +87 -0
- package/src/rtk/detect.ts +55 -0
- package/src/rtk/filters.ts +94 -0
- package/src/rtk/index.ts +58 -0
- package/src/server.ts +108 -0
- package/src/stream/anthropic-stream.ts +310 -0
- package/src/stream/chunk.ts +46 -0
- package/src/stream/gemini-stream.ts +158 -0
- package/src/stream/index.ts +23 -0
- package/src/stream/openai-stream.ts +41 -0
- package/src/stream/sse.ts +72 -0
- package/src/translator/thinking.ts +64 -0
- package/src/translator/thinkingUnified.ts +319 -0
- package/src/upstream/client.ts +155 -0
- package/tsconfig.json +20 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **aigetwey** are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [1.0.1] — 2026-06-24
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- `--help` no longer says the dashboard runs on a separate port — the gateway
|
|
14
|
+
serves the dashboard + API on one URL.
|
|
15
|
+
- package.json author uses the GitHub noreply email (keeps the real address
|
|
16
|
+
private), and the version-poll comment reflects the now-published package.
|
|
17
|
+
|
|
18
|
+
## [1.0.0] — 2026-06-24
|
|
19
|
+
|
|
20
|
+
First public release. A personal AI gateway that routes, translates, and tracks
|
|
21
|
+
requests across Anthropic / OpenAI / Gemini-compatible providers, with a built-in
|
|
22
|
+
dashboard.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
#### Gateway
|
|
27
|
+
- **Multi-format translation** — one canonical (OpenAI Chat) request shape,
|
|
28
|
+
translated to/from each provider's native wire format (`openai`, `anthropic`,
|
|
29
|
+
`gemini`) on both ingress and egress.
|
|
30
|
+
- **Combos** — alias an ordered provider chain (`fallback` or `round-robin`)
|
|
31
|
+
behind a single model name; the alias *is* the model you call.
|
|
32
|
+
- **Key pool** — multiple keys per provider with health tracking, cooldown on
|
|
33
|
+
failure, automatic retry/fallback, and per-key enable/disable.
|
|
34
|
+
- **Quota tracker** — per-provider token budgets over 5h / daily / weekly /
|
|
35
|
+
monthly windows, exhausted providers skipped in routing.
|
|
36
|
+
- **Pricing** — per-model cost resolved via a fallback table
|
|
37
|
+
(model → provider → glob pattern → default), with per-model overrides.
|
|
38
|
+
- **Capabilities** — vision / reasoning / context-window / thinking-format
|
|
39
|
+
resolved per model from a built-in table.
|
|
40
|
+
- **Thinking normalization** — client thinking intent (model-name suffix like
|
|
41
|
+
`model(high)` or body reasoning params) translated to each provider's native
|
|
42
|
+
thinking format per attempt.
|
|
43
|
+
- **Token savers** — RTK (compress tool output), Caveman (terse output style),
|
|
44
|
+
Ponytail (minimal-code bias), and Headroom (external `/v1/compress` context
|
|
45
|
+
compression), each with intensity levels.
|
|
46
|
+
- **SSE streaming** with keepalive heartbeat and proxy-buffering disabled.
|
|
47
|
+
- **Hot reload** — config changes validate (zod) + persist atomically + rebuild
|
|
48
|
+
the live pool without dropping the process.
|
|
49
|
+
|
|
50
|
+
#### Dashboard
|
|
51
|
+
- Endpoint & Key, Providers, Combos, Usage (with request logs), Quota Tracker,
|
|
52
|
+
CLI Tools, Server Console (live gateway output), and Settings pages.
|
|
53
|
+
- **CLI Tools** — detects and auto-configures local tools (Claude Code,
|
|
54
|
+
opencode) by writing their config files, with a copy-ready manual fallback;
|
|
55
|
+
opencode entries carry per-model `modalities` derived from the capabilities
|
|
56
|
+
table.
|
|
57
|
+
- **Settings** — structured cards: instance summary, an admin-password change
|
|
58
|
+
card, a per-model Pricing editor, config Backup (export/import), and an
|
|
59
|
+
Advanced raw-YAML editor.
|
|
60
|
+
- **Admin password** — changeable at runtime from Settings. The gateway stores it
|
|
61
|
+
as a scrypt hash (`data/auth.json`), seeded from `AIGETWEY_ADMIN_PASSWORD`
|
|
62
|
+
(default `123456`); the dashboard carries the password in an encrypted, signed
|
|
63
|
+
session cookie.
|
|
64
|
+
- Floating icon-rail navigation, light/dark themes, toasts.
|
|
65
|
+
|
|
66
|
+
#### Packaging
|
|
67
|
+
- **Single URL** — the gateway reverse-proxies the dashboard, so the console, the
|
|
68
|
+
API (`/v1`, `/messages`), and `/admin` all live on one address
|
|
69
|
+
(`http://127.0.0.1:18080`). Client API traffic stays direct on Fastify; only
|
|
70
|
+
the dashboard is proxied.
|
|
71
|
+
- Single-command launcher (`aigetwey`) that brings up gateway + dashboard and
|
|
72
|
+
reaps stale dev servers. Interactive launch menu (Web UI / Terminal / Hide to
|
|
73
|
+
Tray / Exit) on a TTY, plus flags: `-p/--port`, `-n/--no-browser`, `-y/--yes`,
|
|
74
|
+
`-t/--tray`, `-h/--help`.
|
|
75
|
+
- **System tray** (macOS/Linux via lazy-installed `systray2`, kept out of the
|
|
76
|
+
tarball; Windows planned): Open Dashboard / Auto-start / Quit, with run-on-OS-
|
|
77
|
+
startup. "Hide to Tray" detaches the stack into the background.
|
|
78
|
+
- Installable as a global npm package; first run self-bootstraps (seeds config,
|
|
79
|
+
installs dashboard deps, builds the dashboard).
|
|
80
|
+
- Brand: `a»` mark (favicon + sidebar) and an `ai»getwey` wordmark.
|
|
81
|
+
|
|
82
|
+
[Unreleased]: https://github.com/xk1ko/aigetwey/compare/v1.0.1...HEAD
|
|
83
|
+
[1.0.1]: https://github.com/xk1ko/aigetwey/compare/v1.0.0...v1.0.1
|
|
84
|
+
[1.0.0]: https://github.com/xk1ko/aigetwey/releases/tag/v1.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xk1ko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./assets/wordmark.svg" width="420" alt="aigetwey">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# aigetwey
|
|
6
|
+
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
[](https://www.npmjs.com/package/aigetwey)
|
|
9
|
+
[](https://nodejs.org)
|
|
10
|
+
|
|
11
|
+
Personal AI gateway. One local endpoint takes requests from your CLI coding
|
|
12
|
+
tools (Claude Code, opencode, Cursor, Cline, Codex), translates between formats,
|
|
13
|
+
routes with fallback across providers, and tracks token usage and cost. Ships
|
|
14
|
+
with a built-in dashboard.
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<img src="./assets/screenshot.png" width="860" alt="aigetwey dashboard — Endpoint & Key">
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
**🌐 Language / Bahasa:** [English](#english) · [Bahasa Indonesia](#bahasa-indonesia)
|
|
21
|
+
|
|
22
|
+
See [CHANGELOG.md](./CHANGELOG.md) for release history.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## English
|
|
27
|
+
|
|
28
|
+
### Highlights
|
|
29
|
+
|
|
30
|
+
- **One endpoint, every format** — clients speak OpenAI (`/v1/chat/completions`)
|
|
31
|
+
or Anthropic (`/v1/messages`); the gateway translates to/from OpenAI,
|
|
32
|
+
Anthropic, or Gemini providers, streaming included.
|
|
33
|
+
- **Routing + fallback** — a client alias resolves to a prioritized provider
|
|
34
|
+
chain; on 429/5xx/timeout it rotates keys and falls through to the next.
|
|
35
|
+
- **Token savers** — RTK compresses bulky `tool_result` blocks; caveman trims
|
|
36
|
+
output prose; ponytail nudges minimal code; headroom compresses context via an
|
|
37
|
+
external `/v1/compress`. All toggle per-endpoint.
|
|
38
|
+
- **Quota + cost** — per-provider token budgets with scheduled-window resets, a
|
|
39
|
+
reset countdown, and SQLite-backed usage/cost tracking.
|
|
40
|
+
- **Dashboard** — providers, combos, usage, quota, CLI tools, a live server
|
|
41
|
+
console, and a settings page with a per-model pricing editor.
|
|
42
|
+
|
|
43
|
+
### Token savers
|
|
44
|
+
|
|
45
|
+
Toggle these per-endpoint in the dashboard. The first three are **built into the
|
|
46
|
+
gateway** — nothing extra to install, they ship with the npm package. Headroom is
|
|
47
|
+
the only one that needs an **external** tool.
|
|
48
|
+
|
|
49
|
+
| Saver | What it does | Upstream | Install |
|
|
50
|
+
| --- | --- | --- | --- |
|
|
51
|
+
| **RTK** | Compresses bulky `tool_result` blocks in the request (git/grep/ls/logs). | [rtk-ai/rtk](https://github.com/rtk-ai/rtk) | built-in |
|
|
52
|
+
| **Caveman** | Terse-output system prompt — cuts output prose tokens. | [JuliusBrussee/caveman](https://github.com/JuliusBrussee/caveman) | built-in |
|
|
53
|
+
| **Ponytail** | Biases the model toward minimal code (YAGNI, reuse, deletion). | [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail) | built-in |
|
|
54
|
+
| **Headroom** | Pipes context through an external `/v1/compress` proxy. | [chopratejas/headroom](https://github.com/chopratejas/headroom) | **external** |
|
|
55
|
+
|
|
56
|
+
**Headroom** is the only external piece — a separate Python tool the gateway just
|
|
57
|
+
detects and calls, never bundled. Install it from
|
|
58
|
+
[chopratejas/headroom](https://github.com/chopratejas/headroom) (Python ≥ 3.10),
|
|
59
|
+
then run `headroom proxy` (default `http://localhost:8787`). With it absent the
|
|
60
|
+
Headroom toggle stays off and everything else works unchanged. The dashboard's
|
|
61
|
+
Endpoint & Key page shows install status and a one-line install hint.
|
|
62
|
+
|
|
63
|
+
### Install
|
|
64
|
+
|
|
65
|
+
**Global (npm):**
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npm install -g aigetwey
|
|
69
|
+
aigetwey
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The first run self-bootstraps: it seeds a `config.yaml`, installs the dashboard's
|
|
73
|
+
dependencies, builds the dashboard, then starts the gateway + dashboard and opens
|
|
74
|
+
your browser. Subsequent runs start instantly.
|
|
75
|
+
|
|
76
|
+
On a terminal a menu lets you choose **Web UI**, **Terminal** (logs only),
|
|
77
|
+
**Hide to Tray** (background with a tray icon: Open Dashboard / Auto-start / Quit,
|
|
78
|
+
macOS + Linux), or **Exit**. Flags: `-p/--port`, `-n/--no-browser`, `-y/--yes`
|
|
79
|
+
(skip the menu), `-t/--tray`, `-h/--help`.
|
|
80
|
+
|
|
81
|
+
**From source:**
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git clone https://github.com/xk1ko/aigetwey.git
|
|
85
|
+
cd aigetwey
|
|
86
|
+
npm install
|
|
87
|
+
cp config.example.yaml config.yaml # then edit: add providers + a server key
|
|
88
|
+
npm install --prefix dashboard
|
|
89
|
+
./run.sh # gateway + dashboard (Ctrl-C stops both)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
An admin password is generated if `AIGETWEY_ADMIN_PASSWORD` isn't set (printed on
|
|
93
|
+
startup). Set it to keep it stable across runs. **One URL serves everything** —
|
|
94
|
+
`http://127.0.0.1:18080`: the dashboard, the API (`/v1`, `/messages`), and the
|
|
95
|
+
admin endpoints. The gateway reverse-proxies the dashboard, so clients and the
|
|
96
|
+
console share a single address.
|
|
97
|
+
|
|
98
|
+
### Configuration
|
|
99
|
+
|
|
100
|
+
`config.yaml` is the source of truth and is **hot-reloaded** — edits via the
|
|
101
|
+
dashboard (or the API) apply without a restart. See `config.example.yaml` for
|
|
102
|
+
every provider shape. The essentials:
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
server:
|
|
106
|
+
host: 127.0.0.1
|
|
107
|
+
port: 18080
|
|
108
|
+
api_keys: [my-key] # keys clients must present. empty = auth OFF (localhost only)
|
|
109
|
+
|
|
110
|
+
endpoint:
|
|
111
|
+
rtk: true # compress tool_result in the request
|
|
112
|
+
caveman: full # off | lite | full | ultra — terser output
|
|
113
|
+
ponytail: lite # off | lite | full | ultra — minimal code
|
|
114
|
+
|
|
115
|
+
providers:
|
|
116
|
+
- id: anthropic
|
|
117
|
+
format: anthropic
|
|
118
|
+
base_url: https://api.anthropic.com/v1
|
|
119
|
+
api_keys: [sk-ant-xxx]
|
|
120
|
+
quota: { window: weekly, reset_at: monday, timezone: Asia/Jakarta }
|
|
121
|
+
- id: opencode-free
|
|
122
|
+
format: openai
|
|
123
|
+
base_url: https://opencode.ai/zen/v1
|
|
124
|
+
free: true # no upstream auth
|
|
125
|
+
auto_models: true # fetch the catalog at runtime
|
|
126
|
+
|
|
127
|
+
models: # routing: client alias -> prioritized provider chain
|
|
128
|
+
- alias: claude-sonnet-4-6
|
|
129
|
+
target: [anthropic, opencode-free] # fallback order
|
|
130
|
+
model: [claude-sonnet-4-6, claude-sonnet-4-5]
|
|
131
|
+
price_in: 3 # USD per 1M tokens (for cost tracking)
|
|
132
|
+
price_out: 15
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
A **combo** is one of these `models` entries: an alias your CLI tool calls,
|
|
136
|
+
routed to an ordered provider chain. `strategy: fallback` (default) tries the
|
|
137
|
+
chain in order, falling through on 429/5xx/timeout; `strategy: round-robin`
|
|
138
|
+
rotates the first provider tried per request to spread load.
|
|
139
|
+
|
|
140
|
+
### Connecting CLI tools
|
|
141
|
+
|
|
142
|
+
The dashboard's **CLI Tools** page detects local tools and writes their config
|
|
143
|
+
for you (Claude Code, opencode), or generates copy-ready env. In short, point the
|
|
144
|
+
tool's base URL + key at the gateway and call a routing alias as the model name:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Claude Code (Anthropic format)
|
|
148
|
+
export ANTHROPIC_BASE_URL=http://127.0.0.1:18080
|
|
149
|
+
export ANTHROPIC_API_KEY=my-key
|
|
150
|
+
|
|
151
|
+
# opencode / Cursor / Cline / Codex (OpenAI format)
|
|
152
|
+
export OPENAI_BASE_URL=http://127.0.0.1:18080/v1
|
|
153
|
+
export OPENAI_API_KEY=my-key
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Naming a model** — the `model` field resolves three ways, in order: (1) a
|
|
157
|
+
**combo alias** → its provider chain; (2) **`provider/model`** (e.g.
|
|
158
|
+
`anthropic/claude-sonnet-4-6`) → straight to that provider; (3) a **bare model
|
|
159
|
+
id** → auto-detected against every provider's catalog.
|
|
160
|
+
|
|
161
|
+
### Environment
|
|
162
|
+
|
|
163
|
+
Gateway: `AIGETWEY_CONFIG` (config path), `AIGETWEY_DATA_DIR` (usage DB dir),
|
|
164
|
+
`AIGETWEY_ADMIN_PASSWORD` (admin + dashboard), `AIGETWEY_PORT` (listen port).
|
|
165
|
+
|
|
166
|
+
Dashboard (`dashboard/.env.local`): `GATEWAY_URL`, `ADMIN_PASSWORD` (must match
|
|
167
|
+
the gateway), `SESSION_SECRET` (`openssl rand -hex 32`).
|
|
168
|
+
|
|
169
|
+
The admin password and provider keys never reach the browser: the dashboard
|
|
170
|
+
proxies `/admin/*` server-side with the Bearer injected, and keys are masked.
|
|
171
|
+
|
|
172
|
+
### Development
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npm run typecheck # tsc, no emit
|
|
176
|
+
npm test # vitest (unit + synthetic E2E)
|
|
177
|
+
npm run build # compile to dist/
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Bahasa Indonesia
|
|
183
|
+
|
|
184
|
+
### Sorotan
|
|
185
|
+
|
|
186
|
+
- **Satu endpoint, semua format** — klien bicara OpenAI (`/v1/chat/completions`)
|
|
187
|
+
atau Anthropic (`/v1/messages`); gateway menerjemahkan ke/dari provider OpenAI,
|
|
188
|
+
Anthropic, atau Gemini, termasuk streaming.
|
|
189
|
+
- **Routing + fallback** — sebuah alias klien diarahkan ke rantai provider
|
|
190
|
+
berprioritas; saat 429/5xx/timeout ia memutar key dan jatuh ke provider
|
|
191
|
+
berikutnya.
|
|
192
|
+
- **Penghemat token** — RTK memampatkan blok `tool_result` besar; caveman
|
|
193
|
+
meringkas prosa output; ponytail mendorong kode minimal; headroom memampatkan
|
|
194
|
+
konteks lewat `/v1/compress` eksternal. Semua bisa di-toggle per-endpoint.
|
|
195
|
+
- **Kuota + biaya** — budget token per-provider dengan reset berjadwal, hitung
|
|
196
|
+
mundur reset, dan pelacakan pemakaian/biaya berbasis SQLite.
|
|
197
|
+
- **Dashboard** — providers, combos, usage, kuota, CLI tools, server console
|
|
198
|
+
live, dan halaman settings dengan editor harga per-model.
|
|
199
|
+
|
|
200
|
+
### Penghemat token
|
|
201
|
+
|
|
202
|
+
**RTK** ([rtk-ai/rtk](https://github.com/rtk-ai/rtk)), **Caveman**
|
|
203
|
+
([JuliusBrussee/caveman](https://github.com/JuliusBrussee/caveman)), **Ponytail**
|
|
204
|
+
([DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail)) =
|
|
205
|
+
**built-in** (ikut paket npm, tak perlu install apa pun). Hanya **Headroom**
|
|
206
|
+
([chopratejas/headroom](https://github.com/chopratejas/headroom)) yang
|
|
207
|
+
**eksternal**: tool Python terpisah (tidak di-bundle — gateway cuma mendeteksi &
|
|
208
|
+
memanggilnya), butuh Python ≥ 3.10, jalankan `headroom proxy` (default
|
|
209
|
+
`http://localhost:8787`). Tanpa Headroom toggle-nya mati & sisanya tetap jalan;
|
|
210
|
+
halaman Endpoint & Key di dashboard menampilkan status install + hint.
|
|
211
|
+
|
|
212
|
+
### Instalasi
|
|
213
|
+
|
|
214
|
+
**Global (npm):**
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
npm install -g aigetwey
|
|
218
|
+
aigetwey
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Saat pertama dijalankan ia bootstrap otomatis: membuat `config.yaml`, meng-install
|
|
222
|
+
dependency dashboard, build dashboard, lalu menjalankan gateway + dashboard dan
|
|
223
|
+
membuka browser. Run berikutnya langsung jalan.
|
|
224
|
+
|
|
225
|
+
**Dari source:**
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
git clone https://github.com/xk1ko/aigetwey.git
|
|
229
|
+
cd aigetwey
|
|
230
|
+
npm install
|
|
231
|
+
cp config.example.yaml config.yaml # lalu edit: tambah provider + server key
|
|
232
|
+
npm install --prefix dashboard
|
|
233
|
+
./run.sh # gateway + dashboard (Ctrl-C hentikan keduanya)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Admin password dibuat otomatis kalau `AIGETWEY_ADMIN_PASSWORD` belum di-set
|
|
237
|
+
(dicetak saat start). Set agar stabil antar run. **Satu URL untuk semuanya** —
|
|
238
|
+
`http://127.0.0.1:18080`: dashboard, API (`/v1`, `/messages`), dan admin. Gateway
|
|
239
|
+
mem-proxy dashboard, jadi client & console pakai satu alamat.
|
|
240
|
+
|
|
241
|
+
### Konfigurasi
|
|
242
|
+
|
|
243
|
+
`config.yaml` adalah sumber kebenaran dan **hot-reload** — perubahan lewat
|
|
244
|
+
dashboard (atau API) langsung berlaku tanpa restart. Lihat `config.example.yaml`
|
|
245
|
+
untuk semua bentuk provider. Intinya sama seperti contoh di bagian English di
|
|
246
|
+
atas (`server`, `endpoint`, `providers`, `models`).
|
|
247
|
+
|
|
248
|
+
Sebuah **combo** adalah satu entry `models`: alias yang dipanggil CLI tool-mu,
|
|
249
|
+
diarahkan ke rantai provider berurutan. `strategy: fallback` (default) mencoba
|
|
250
|
+
rantai berurutan, jatuh saat 429/5xx/timeout; `strategy: round-robin` memutar
|
|
251
|
+
provider pertama tiap request untuk membagi beban.
|
|
252
|
+
|
|
253
|
+
### Menghubungkan CLI tools
|
|
254
|
+
|
|
255
|
+
Halaman **CLI Tools** di dashboard mendeteksi tool lokal dan menulis config-nya
|
|
256
|
+
untukmu (Claude Code, opencode), atau menghasilkan env siap-salin. Singkatnya,
|
|
257
|
+
arahkan base URL + key tool ke gateway dan panggil alias routing sebagai nama
|
|
258
|
+
model:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Claude Code (format Anthropic)
|
|
262
|
+
export ANTHROPIC_BASE_URL=http://127.0.0.1:18080
|
|
263
|
+
export ANTHROPIC_API_KEY=my-key
|
|
264
|
+
|
|
265
|
+
# opencode / Cursor / Cline / Codex (format OpenAI)
|
|
266
|
+
export OPENAI_BASE_URL=http://127.0.0.1:18080/v1
|
|
267
|
+
export OPENAI_API_KEY=my-key
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Penamaan model** — field `model` diselesaikan tiga cara, berurutan: (1) **alias
|
|
271
|
+
combo** → rantai provider-nya; (2) **`provider/model`** (mis.
|
|
272
|
+
`anthropic/claude-sonnet-4-6`) → langsung ke provider itu; (3) **id model polos**
|
|
273
|
+
→ dideteksi otomatis dari katalog tiap provider.
|
|
274
|
+
|
|
275
|
+
### Environment
|
|
276
|
+
|
|
277
|
+
Gateway: `AIGETWEY_CONFIG` (path config), `AIGETWEY_DATA_DIR` (folder DB usage),
|
|
278
|
+
`AIGETWEY_ADMIN_PASSWORD` (admin + dashboard), `AIGETWEY_PORT` (port listen).
|
|
279
|
+
|
|
280
|
+
Dashboard (`dashboard/.env.local`): `GATEWAY_URL`, `ADMIN_PASSWORD` (harus sama
|
|
281
|
+
dengan gateway), `SESSION_SECRET` (`openssl rand -hex 32`).
|
|
282
|
+
|
|
283
|
+
Admin password dan key provider tak pernah sampai ke browser: dashboard
|
|
284
|
+
mem-proxy `/admin/*` di sisi server dengan Bearer disuntik, dan key disamarkan.
|
|
285
|
+
|
|
286
|
+
### Pengembangan
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
npm run typecheck # tsc, tanpa emit
|
|
290
|
+
npm test # vitest (unit + E2E sintetis)
|
|
291
|
+
npm run build # compile ke dist/
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## License
|
|
297
|
+
|
|
298
|
+
[MIT](./LICENSE) © xk1ko
|
|
299
|
+
|
|
300
|
+
## Contributing
|
|
301
|
+
|
|
302
|
+
Issues and ideas welcome: <https://github.com/xk1ko/aigetwey/issues>
|
package/assets/logo.svg
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
|
|
2
|
+
<rect width="512" height="512" rx="116" fill="#0f0f0e"/>
|
|
3
|
+
<text x="120" y="338" font-family="ui-sans-serif, Inter, Arial, sans-serif" font-size="260" font-weight="800" text-anchor="middle" fill="#cbe85a">a</text>
|
|
4
|
+
<g fill="none" stroke="#cbe85a" stroke-width="32" stroke-linecap="round" stroke-linejoin="round">
|
|
5
|
+
<polyline points="270,180 350,256 270,332"/>
|
|
6
|
+
<polyline points="338,180 418,256 338,332"/>
|
|
7
|
+
</g>
|
|
8
|
+
</svg>
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1300 320" width="1300" height="320">
|
|
2
|
+
<rect width="1300" height="320" rx="48" fill="#0f0f0e"/>
|
|
3
|
+
<text x="90" y="222" font-family="ui-sans-serif, Inter, Arial, sans-serif" font-size="200" font-weight="800" letter-spacing="-8" text-anchor="start" fill="#f2f2ec">ai</text>
|
|
4
|
+
<g fill="none" stroke="#cbe85a" stroke-width="34" stroke-linecap="round" stroke-linejoin="round">
|
|
5
|
+
<polyline points="300,96 400,160 300,224"/>
|
|
6
|
+
<polyline points="388,96 488,160 388,224"/>
|
|
7
|
+
</g>
|
|
8
|
+
<text x="540" y="222" font-family="ui-sans-serif, Inter, Arial, sans-serif" font-size="200" font-weight="800" letter-spacing="-8" text-anchor="start" fill="#f2f2ec">getwey</text>
|
|
9
|
+
</svg>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# aigetwey — example config. Copy to config.yaml and fill in.
|
|
2
|
+
# Hot-reloaded: edits via the dashboard apply without a restart.
|
|
3
|
+
|
|
4
|
+
server:
|
|
5
|
+
host: 127.0.0.1
|
|
6
|
+
port: 18080
|
|
7
|
+
# Gateway keys clients must present (Bearer or x-api-key).
|
|
8
|
+
# Empty => auth disabled (localhost only — set before exposing remotely).
|
|
9
|
+
api_keys:
|
|
10
|
+
- my-key
|
|
11
|
+
|
|
12
|
+
# Token-saver toggles, applied per request before routing.
|
|
13
|
+
endpoint:
|
|
14
|
+
rtk: false # compress tool_result blocks in the request
|
|
15
|
+
caveman: off # off | lite | full | ultra — terser model output
|
|
16
|
+
ponytail: off # off | lite | full | ultra — minimal-code system prompt
|
|
17
|
+
|
|
18
|
+
# Upstream providers. Add real ones; see the shapes below.
|
|
19
|
+
providers: []
|
|
20
|
+
# Example shapes (uncomment + fill in):
|
|
21
|
+
#
|
|
22
|
+
# - id: anthropic
|
|
23
|
+
# format: anthropic
|
|
24
|
+
# base_url: https://api.anthropic.com/v1
|
|
25
|
+
# api_keys: [sk-ant-xxx]
|
|
26
|
+
# quota: { window: weekly, reset_at: monday, timezone: Asia/Jakarta }
|
|
27
|
+
#
|
|
28
|
+
# - id: openai
|
|
29
|
+
# format: openai
|
|
30
|
+
# base_url: https://api.openai.com/v1
|
|
31
|
+
# api_key: sk-xxx
|
|
32
|
+
# models:
|
|
33
|
+
# - { id: gpt-4o, price_in: 2.5, price_out: 10 }
|
|
34
|
+
#
|
|
35
|
+
# - id: opencode-free
|
|
36
|
+
# format: openai
|
|
37
|
+
# base_url: https://opencode.ai/zen/v1
|
|
38
|
+
# free: true
|
|
39
|
+
# auto_models: true
|
|
40
|
+
#
|
|
41
|
+
# - id: vertex
|
|
42
|
+
# format: gemini
|
|
43
|
+
# base_url: https://us-central1-aiplatform.googleapis.com/v1
|
|
44
|
+
# service_account: /path/to/sa.json
|
|
45
|
+
# quota: { window: monthly, limit_tokens: 300000000 }
|
|
46
|
+
|
|
47
|
+
# Combos: client-facing alias -> ordered provider chain. Call the alias as the
|
|
48
|
+
# model name from your CLI tool. strategy: fallback (try in order) | round-robin.
|
|
49
|
+
models: []
|
|
50
|
+
# Example:
|
|
51
|
+
# - alias: claude-sonnet-4-6
|
|
52
|
+
# target: [anthropic, opencode-free]
|
|
53
|
+
# model: [claude-sonnet-4-6, claude-sonnet-4-5]
|
|
54
|
+
# strategy: fallback
|
|
55
|
+
# price_in: 3
|
|
56
|
+
# price_out: 15
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# aigetwey dashboard — copy to .env.local and fill in.
|
|
2
|
+
|
|
3
|
+
# where the gateway is reachable from the dashboard SERVER (not the browser).
|
|
4
|
+
GATEWAY_URL=http://127.0.0.1:18080
|
|
5
|
+
|
|
6
|
+
# must match AIGETWEY_ADMIN_PASSWORD set on the gateway. used server-side only
|
|
7
|
+
# to authenticate /admin/* proxy calls — never sent to the browser.
|
|
8
|
+
ADMIN_PASSWORD=change-me
|
|
9
|
+
|
|
10
|
+
# random secret to sign the dashboard session cookie. generate e.g.
|
|
11
|
+
# openssl rand -hex 32
|
|
12
|
+
SESSION_SECRET=change-me-too
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
2
|
+
|
|
3
|
+
const nextConfig: NextConfig = {
|
|
4
|
+
// dashboard talks to the gateway only server-side (route handlers proxy
|
|
5
|
+
// /admin/*), so no rewrites/CORS needed here.
|
|
6
|
+
reactStrictMode: true,
|
|
7
|
+
// allow dev HMR/resource requests from loopback hosts so client hydration
|
|
8
|
+
// works regardless of which host name opens the app (localhost vs 127.0.0.1).
|
|
9
|
+
allowedDevOrigins: ["localhost", "127.0.0.1"],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default nextConfig;
|