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.
Files changed (216) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/LICENSE +21 -0
  3. package/README.md +302 -0
  4. package/assets/logo.svg +8 -0
  5. package/assets/screenshot.png +0 -0
  6. package/assets/wordmark.svg +9 -0
  7. package/config.example.yaml +56 -0
  8. package/dashboard/.env.example +12 -0
  9. package/dashboard/next-env.d.ts +6 -0
  10. package/dashboard/next.config.ts +12 -0
  11. package/dashboard/package-lock.json +1771 -0
  12. package/dashboard/package.json +29 -0
  13. package/dashboard/postcss.config.mjs +5 -0
  14. package/dashboard/src/app/(console)/combos/page.tsx +10 -0
  15. package/dashboard/src/app/(console)/config/page.tsx +5 -0
  16. package/dashboard/src/app/(console)/console/page.tsx +92 -0
  17. package/dashboard/src/app/(console)/endpoint/page.tsx +5 -0
  18. package/dashboard/src/app/(console)/layout.tsx +17 -0
  19. package/dashboard/src/app/(console)/page.tsx +8 -0
  20. package/dashboard/src/app/(console)/providers/[id]/page.tsx +6 -0
  21. package/dashboard/src/app/(console)/providers/page.tsx +5 -0
  22. package/dashboard/src/app/(console)/quota/page.tsx +5 -0
  23. package/dashboard/src/app/(console)/tools/[id]/page.tsx +6 -0
  24. package/dashboard/src/app/(console)/tools/page.tsx +5 -0
  25. package/dashboard/src/app/(console)/usage/page.tsx +24 -0
  26. package/dashboard/src/app/api/cli-detect/[tool]/route.ts +253 -0
  27. package/dashboard/src/app/api/gw/[...path]/route.ts +89 -0
  28. package/dashboard/src/app/api/login/route.ts +30 -0
  29. package/dashboard/src/app/api/logout/route.ts +9 -0
  30. package/dashboard/src/app/api/password/route.ts +34 -0
  31. package/dashboard/src/app/globals.css +340 -0
  32. package/dashboard/src/app/icon.svg +8 -0
  33. package/dashboard/src/app/layout.tsx +28 -0
  34. package/dashboard/src/app/login/page.tsx +60 -0
  35. package/dashboard/src/components/AreaChart.tsx +115 -0
  36. package/dashboard/src/components/Badge.tsx +32 -0
  37. package/dashboard/src/components/Button.tsx +60 -0
  38. package/dashboard/src/components/CapacityBadges.tsx +40 -0
  39. package/dashboard/src/components/Checkbox.tsx +40 -0
  40. package/dashboard/src/components/CliToolConfig.tsx +63 -0
  41. package/dashboard/src/components/ConfigEditor.tsx +199 -0
  42. package/dashboard/src/components/ConfirmModal.tsx +36 -0
  43. package/dashboard/src/components/CooldownTimer.tsx +42 -0
  44. package/dashboard/src/components/EndpointView.tsx +439 -0
  45. package/dashboard/src/components/Icon.tsx +25 -0
  46. package/dashboard/src/components/KeyReveal.tsx +78 -0
  47. package/dashboard/src/components/Lamp.tsx +8 -0
  48. package/dashboard/src/components/LogTable.tsx +223 -0
  49. package/dashboard/src/components/LogoutButton.tsx +20 -0
  50. package/dashboard/src/components/ModelPicker.tsx +121 -0
  51. package/dashboard/src/components/ModelSelectModal.tsx +126 -0
  52. package/dashboard/src/components/PasswordEditor.tsx +86 -0
  53. package/dashboard/src/components/PricingEditor.tsx +171 -0
  54. package/dashboard/src/components/ProviderDetail.tsx +566 -0
  55. package/dashboard/src/components/ProviderManager.tsx +311 -0
  56. package/dashboard/src/components/QuotaView.tsx +78 -0
  57. package/dashboard/src/components/Rail.tsx +82 -0
  58. package/dashboard/src/components/RichCard.tsx +46 -0
  59. package/dashboard/src/components/RoutingView.tsx +329 -0
  60. package/dashboard/src/components/ThemeProvider.tsx +36 -0
  61. package/dashboard/src/components/ToastProvider.tsx +58 -0
  62. package/dashboard/src/components/ToolDetail.tsx +475 -0
  63. package/dashboard/src/components/TopBar.tsx +128 -0
  64. package/dashboard/src/components/UsageView.tsx +151 -0
  65. package/dashboard/src/components/ui.tsx +54 -0
  66. package/dashboard/src/lib/capabilities.ts +318 -0
  67. package/dashboard/src/lib/cliTools.ts +120 -0
  68. package/dashboard/src/lib/client.ts +190 -0
  69. package/dashboard/src/lib/gateway.ts +269 -0
  70. package/dashboard/src/lib/session.ts +71 -0
  71. package/dashboard/src/middleware.ts +37 -0
  72. package/dashboard/tsconfig.json +21 -0
  73. package/dist/adapters/anthropic.js +289 -0
  74. package/dist/adapters/anthropic.js.map +1 -0
  75. package/dist/adapters/gemini.js +268 -0
  76. package/dist/adapters/gemini.js.map +1 -0
  77. package/dist/adapters/index.js +8 -0
  78. package/dist/adapters/index.js.map +1 -0
  79. package/dist/adapters/openai.js +13 -0
  80. package/dist/adapters/openai.js.map +1 -0
  81. package/dist/cli/tray/autostart.js +152 -0
  82. package/dist/cli/tray/autostart.js.map +1 -0
  83. package/dist/cli/tray/icon.js +4 -0
  84. package/dist/cli/tray/icon.js.map +1 -0
  85. package/dist/cli/tray/tray.js +141 -0
  86. package/dist/cli/tray/tray.js.map +1 -0
  87. package/dist/cli/tray/trayRuntime.js +91 -0
  88. package/dist/cli/tray/trayRuntime.js.map +1 -0
  89. package/dist/cli.js +361 -0
  90. package/dist/cli.js.map +1 -0
  91. package/dist/config.js +728 -0
  92. package/dist/config.js.map +1 -0
  93. package/dist/core/authStore.js +78 -0
  94. package/dist/core/authStore.js.map +1 -0
  95. package/dist/core/canonical.js +9 -0
  96. package/dist/core/canonical.js.map +1 -0
  97. package/dist/core/console-buffer.js +25 -0
  98. package/dist/core/console-buffer.js.map +1 -0
  99. package/dist/core/fallback.js +62 -0
  100. package/dist/core/fallback.js.map +1 -0
  101. package/dist/core/handler.js +174 -0
  102. package/dist/core/handler.js.map +1 -0
  103. package/dist/core/keypool.js +105 -0
  104. package/dist/core/keypool.js.map +1 -0
  105. package/dist/core/quota.js +165 -0
  106. package/dist/core/quota.js.map +1 -0
  107. package/dist/core/state.js +52 -0
  108. package/dist/core/state.js.map +1 -0
  109. package/dist/db.js +193 -0
  110. package/dist/db.js.map +1 -0
  111. package/dist/headroom/compress.js +44 -0
  112. package/dist/headroom/compress.js.map +1 -0
  113. package/dist/headroom/detect.js +108 -0
  114. package/dist/headroom/detect.js.map +1 -0
  115. package/dist/headroom/process.js +158 -0
  116. package/dist/headroom/process.js.map +1 -0
  117. package/dist/inject/caveman.js +30 -0
  118. package/dist/inject/caveman.js.map +1 -0
  119. package/dist/inject/index.js +24 -0
  120. package/dist/inject/index.js.map +1 -0
  121. package/dist/inject/ponytail.js +19 -0
  122. package/dist/inject/ponytail.js.map +1 -0
  123. package/dist/middleware/auth.js +66 -0
  124. package/dist/middleware/auth.js.map +1 -0
  125. package/dist/providers/capabilities.js +246 -0
  126. package/dist/providers/capabilities.js.map +1 -0
  127. package/dist/providers/free.js +43 -0
  128. package/dist/providers/free.js.map +1 -0
  129. package/dist/providers/pricing.js +224 -0
  130. package/dist/providers/pricing.js.map +1 -0
  131. package/dist/providers/vertex.js +97 -0
  132. package/dist/providers/vertex.js.map +1 -0
  133. package/dist/routes/admin.js +622 -0
  134. package/dist/routes/admin.js.map +1 -0
  135. package/dist/routes/health.js +4 -0
  136. package/dist/routes/health.js.map +1 -0
  137. package/dist/routes/index.js +12 -0
  138. package/dist/routes/index.js.map +1 -0
  139. package/dist/routes/v1.js +75 -0
  140. package/dist/routes/v1.js.map +1 -0
  141. package/dist/rtk/detect.js +50 -0
  142. package/dist/rtk/detect.js.map +1 -0
  143. package/dist/rtk/filters.js +85 -0
  144. package/dist/rtk/filters.js.map +1 -0
  145. package/dist/rtk/index.js +39 -0
  146. package/dist/rtk/index.js.map +1 -0
  147. package/dist/server.js +100 -0
  148. package/dist/server.js.map +1 -0
  149. package/dist/stream/anthropic-stream.js +239 -0
  150. package/dist/stream/anthropic-stream.js.map +1 -0
  151. package/dist/stream/chunk.js +7 -0
  152. package/dist/stream/chunk.js.map +1 -0
  153. package/dist/stream/gemini-stream.js +135 -0
  154. package/dist/stream/gemini-stream.js.map +1 -0
  155. package/dist/stream/index.js +12 -0
  156. package/dist/stream/index.js.map +1 -0
  157. package/dist/stream/openai-stream.js +34 -0
  158. package/dist/stream/openai-stream.js.map +1 -0
  159. package/dist/stream/sse.js +64 -0
  160. package/dist/stream/sse.js.map +1 -0
  161. package/dist/translator/thinking.js +70 -0
  162. package/dist/translator/thinking.js.map +1 -0
  163. package/dist/translator/thinkingUnified.js +322 -0
  164. package/dist/translator/thinkingUnified.js.map +1 -0
  165. package/dist/upstream/client.js +120 -0
  166. package/dist/upstream/client.js.map +1 -0
  167. package/package.json +76 -0
  168. package/run.sh +27 -0
  169. package/src/adapters/anthropic.ts +377 -0
  170. package/src/adapters/gemini.ts +341 -0
  171. package/src/adapters/index.ts +17 -0
  172. package/src/adapters/openai.ts +22 -0
  173. package/src/cli/tray/autostart.ts +133 -0
  174. package/src/cli/tray/icon.ts +4 -0
  175. package/src/cli/tray/tray.ts +156 -0
  176. package/src/cli/tray/trayRuntime.ts +90 -0
  177. package/src/cli.ts +379 -0
  178. package/src/config.ts +777 -0
  179. package/src/core/authStore.ts +86 -0
  180. package/src/core/canonical.ts +93 -0
  181. package/src/core/console-buffer.ts +39 -0
  182. package/src/core/fallback.ts +116 -0
  183. package/src/core/handler.ts +236 -0
  184. package/src/core/keypool.ts +152 -0
  185. package/src/core/quota.ts +214 -0
  186. package/src/core/state.ts +65 -0
  187. package/src/db.ts +280 -0
  188. package/src/headroom/compress.ts +78 -0
  189. package/src/headroom/detect.ts +119 -0
  190. package/src/headroom/process.ts +166 -0
  191. package/src/inject/caveman.ts +35 -0
  192. package/src/inject/index.ts +46 -0
  193. package/src/inject/ponytail.ts +31 -0
  194. package/src/middleware/auth.ts +76 -0
  195. package/src/providers/capabilities.ts +297 -0
  196. package/src/providers/free.ts +53 -0
  197. package/src/providers/pricing.ts +261 -0
  198. package/src/providers/vertex.ts +117 -0
  199. package/src/routes/admin.ts +716 -0
  200. package/src/routes/health.ts +5 -0
  201. package/src/routes/index.ts +24 -0
  202. package/src/routes/v1.ts +87 -0
  203. package/src/rtk/detect.ts +55 -0
  204. package/src/rtk/filters.ts +94 -0
  205. package/src/rtk/index.ts +58 -0
  206. package/src/server.ts +108 -0
  207. package/src/stream/anthropic-stream.ts +310 -0
  208. package/src/stream/chunk.ts +46 -0
  209. package/src/stream/gemini-stream.ts +158 -0
  210. package/src/stream/index.ts +23 -0
  211. package/src/stream/openai-stream.ts +41 -0
  212. package/src/stream/sse.ts +72 -0
  213. package/src/translator/thinking.ts +64 -0
  214. package/src/translator/thinkingUnified.ts +319 -0
  215. package/src/upstream/client.ts +155 -0
  216. 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: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
8
+ [![npm](https://img.shields.io/npm/v/aigetwey.svg)](https://www.npmjs.com/package/aigetwey)
9
+ [![Node](https://img.shields.io/badge/node-%3E%3D22-brightgreen.svg)](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 &amp; 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 &amp; 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>
@@ -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,6 @@
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
3
+ import "./.next/types/routes.d.ts";
4
+
5
+ // NOTE: This file should not be edited
6
+ // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
@@ -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;