@jacobbd/relay-ai 0.2.7 → 0.3.0
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/.gemini/xai-models.json +165 -0
- package/AGENTS.md +4 -3
- package/CHANGELOG.md +46 -0
- package/README.md +30 -4
- package/assets/demo-part1-thumbnail.png +0 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +13654 -0
- package/coverage/coverage-final.json +106 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +221 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/scripts/index.html +116 -0
- package/coverage/scripts/refresh-models-dev-cache.mjs.html +187 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/cli.js +2891 -893
- package/package.json +8 -3
- package/test-proxy.ts +19 -0
- package/test-split.js +1 -0
- package/vitest.log +33 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": [
|
|
3
|
+
{
|
|
4
|
+
"id": "grok-4.20-0309-non-reasoning",
|
|
5
|
+
"aliases": [
|
|
6
|
+
"grok-4.20-non-reasoning",
|
|
7
|
+
"grok-4.20-non-reasoning-latest",
|
|
8
|
+
"grok-4.20-beta-non-reasoning",
|
|
9
|
+
"grok-4.20-beta-latest-non-reasoning",
|
|
10
|
+
"grok-4.20-experimental-beta-0304-non-reasoning",
|
|
11
|
+
"grok-4.20-experimental-beta-non-reasoning-latest",
|
|
12
|
+
"grok-4.20-beta-0309-non-reasoning",
|
|
13
|
+
"grok-4.20-non-reasoning-gv2"
|
|
14
|
+
],
|
|
15
|
+
"context_length": 1000000,
|
|
16
|
+
"created": 1773014400,
|
|
17
|
+
"object": "model",
|
|
18
|
+
"owned_by": "xai",
|
|
19
|
+
"prompt_text_token_price": 12500,
|
|
20
|
+
"cached_prompt_text_token_price": 2000,
|
|
21
|
+
"prompt_image_token_price": 12500,
|
|
22
|
+
"completion_text_token_price": 25000,
|
|
23
|
+
"prompt_text_token_price_long_context": 25000,
|
|
24
|
+
"cached_prompt_text_token_price_long_context": 4000,
|
|
25
|
+
"completion_text_token_price_long_context": 50000,
|
|
26
|
+
"long_context_threshold": 200000
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "grok-4.20-0309-reasoning",
|
|
30
|
+
"aliases": [
|
|
31
|
+
"grok-4.20-reasoning-latest",
|
|
32
|
+
"grok-4.20",
|
|
33
|
+
"grok-4.20-reasoning",
|
|
34
|
+
"grok-4.20-0309",
|
|
35
|
+
"grok-4.20-beta-0309-reasoning",
|
|
36
|
+
"grok-4.20-beta",
|
|
37
|
+
"grok-4.20-beta-0309",
|
|
38
|
+
"grok-4.20-beta-latest",
|
|
39
|
+
"grok-4.20-beta-latest-reasoning",
|
|
40
|
+
"grok-4.20-beta-reasoning",
|
|
41
|
+
"grok-4.20-experimental-beta-0304-reasoning",
|
|
42
|
+
"grok-4.20-experimental-beta-0304",
|
|
43
|
+
"grok-4.20-experimental-beta-reasoning-latest",
|
|
44
|
+
"grok-4.20-experimental-beta-latest",
|
|
45
|
+
"grok-4.20-reasoning-gv2"
|
|
46
|
+
],
|
|
47
|
+
"context_length": 1000000,
|
|
48
|
+
"created": 1773014400,
|
|
49
|
+
"object": "model",
|
|
50
|
+
"owned_by": "xai",
|
|
51
|
+
"prompt_text_token_price": 12500,
|
|
52
|
+
"cached_prompt_text_token_price": 2000,
|
|
53
|
+
"prompt_image_token_price": 12500,
|
|
54
|
+
"completion_text_token_price": 25000,
|
|
55
|
+
"prompt_text_token_price_long_context": 25000,
|
|
56
|
+
"cached_prompt_text_token_price_long_context": 4000,
|
|
57
|
+
"completion_text_token_price_long_context": 50000,
|
|
58
|
+
"long_context_threshold": 200000
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "grok-4.20-multi-agent-0309",
|
|
62
|
+
"aliases": [
|
|
63
|
+
"grok-4.20-multi-agent",
|
|
64
|
+
"grok-4.20-multi-agent-latest",
|
|
65
|
+
"grok-4.20-multi-agent-beta-latest",
|
|
66
|
+
"grok-4.20-multi-agent-experimental-beta-0304",
|
|
67
|
+
"grok-4.20-multi-agent-experimental-beta-latest",
|
|
68
|
+
"grok-4.20-multi-agent-beta-0309"
|
|
69
|
+
],
|
|
70
|
+
"context_length": 1000000,
|
|
71
|
+
"created": 1773014400,
|
|
72
|
+
"object": "model",
|
|
73
|
+
"owned_by": "xai",
|
|
74
|
+
"prompt_text_token_price": 12500,
|
|
75
|
+
"cached_prompt_text_token_price": 2000,
|
|
76
|
+
"prompt_image_token_price": 12500,
|
|
77
|
+
"completion_text_token_price": 25000,
|
|
78
|
+
"prompt_text_token_price_long_context": 25000,
|
|
79
|
+
"cached_prompt_text_token_price_long_context": 4000,
|
|
80
|
+
"completion_text_token_price_long_context": 50000,
|
|
81
|
+
"long_context_threshold": 200000
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id": "grok-4.3",
|
|
85
|
+
"aliases": [
|
|
86
|
+
"grok-4.3-latest",
|
|
87
|
+
"grok-latest"
|
|
88
|
+
],
|
|
89
|
+
"context_length": 1000000,
|
|
90
|
+
"created": 1776384000,
|
|
91
|
+
"object": "model",
|
|
92
|
+
"owned_by": "xai",
|
|
93
|
+
"prompt_text_token_price": 12500,
|
|
94
|
+
"cached_prompt_text_token_price": 2000,
|
|
95
|
+
"prompt_image_token_price": 12500,
|
|
96
|
+
"completion_text_token_price": 25000,
|
|
97
|
+
"prompt_text_token_price_long_context": 25000,
|
|
98
|
+
"cached_prompt_text_token_price_long_context": 4000,
|
|
99
|
+
"completion_text_token_price_long_context": 50000,
|
|
100
|
+
"long_context_threshold": 200000
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"id": "grok-build-0.1",
|
|
104
|
+
"aliases": [
|
|
105
|
+
"grok-code-fast-1",
|
|
106
|
+
"grok-code-fast",
|
|
107
|
+
"grok-code-fast-1-0825"
|
|
108
|
+
],
|
|
109
|
+
"context_length": 256000,
|
|
110
|
+
"created": 1776297600,
|
|
111
|
+
"object": "model",
|
|
112
|
+
"owned_by": "xai",
|
|
113
|
+
"prompt_text_token_price": 10000,
|
|
114
|
+
"cached_prompt_text_token_price": 2000,
|
|
115
|
+
"prompt_image_token_price": 10000,
|
|
116
|
+
"completion_text_token_price": 20000,
|
|
117
|
+
"prompt_text_token_price_long_context": 20000,
|
|
118
|
+
"cached_prompt_text_token_price_long_context": 4000,
|
|
119
|
+
"completion_text_token_price_long_context": 40000,
|
|
120
|
+
"long_context_threshold": 200000
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": "grok-imagine-image",
|
|
124
|
+
"aliases": [
|
|
125
|
+
"grok-imagine-image-2026-03-02"
|
|
126
|
+
],
|
|
127
|
+
"context_length": 8000,
|
|
128
|
+
"created": 1769558400,
|
|
129
|
+
"object": "model",
|
|
130
|
+
"owned_by": "xai",
|
|
131
|
+
"image_price": 200000000
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "grok-imagine-image-quality",
|
|
135
|
+
"aliases": [
|
|
136
|
+
"grok-imagine-image-quality-20260403",
|
|
137
|
+
"grok-imagine-image-quality-latest",
|
|
138
|
+
"grok-imagine-image-pro"
|
|
139
|
+
],
|
|
140
|
+
"context_length": 8000,
|
|
141
|
+
"created": 1775174400,
|
|
142
|
+
"object": "model",
|
|
143
|
+
"owned_by": "xai",
|
|
144
|
+
"image_price": 500000000
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"id": "grok-imagine-video",
|
|
148
|
+
"aliases": [],
|
|
149
|
+
"created": 1769558400,
|
|
150
|
+
"object": "model",
|
|
151
|
+
"owned_by": "xai"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"id": "grok-imagine-video-1.5",
|
|
155
|
+
"aliases": [
|
|
156
|
+
"grok-imagine-video-1.5-preview",
|
|
157
|
+
"grok-imagine-video-1.5-2026-05-30"
|
|
158
|
+
],
|
|
159
|
+
"created": 1779840000,
|
|
160
|
+
"object": "model",
|
|
161
|
+
"owned_by": "xai"
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
"object": "list"
|
|
165
|
+
}
|
package/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
|
|
3
|
+
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository. Note that the codebase supports Claude Code, OpenAI Codex, and Google Gemini CLI.
|
|
4
4
|
|
|
5
5
|
## Commands
|
|
6
6
|
|
|
@@ -24,6 +24,7 @@ relay-ai server # foreground OpenCode/registry API gateway
|
|
|
24
24
|
relay-ai server --vertex # foreground Vertex AI gateway (gcloud ADC)
|
|
25
25
|
relay-ai codex # Codex CLI with registry providers (see docs/CODEX.md)
|
|
26
26
|
relay-ai codex-app # Codex desktop app (macOS/Windows; see docs/CODEX.md)
|
|
27
|
+
relay-ai gemini # Gemini CLI with registry providers (see docs/GEMINI.md)
|
|
27
28
|
|
|
28
29
|
# Rebuild after code changes before testing manually
|
|
29
30
|
npm run build && relay-ai --version
|
|
@@ -150,9 +151,9 @@ In all cases `process.env['OPENCODE_API_KEY']` is set immediately so the key is
|
|
|
150
151
|
- `--restore` globs `models-*.json` (CLI) and `app-models-*.json` (App); the new files are `models-favorites.json` and `app-models-favorites.json`.
|
|
151
152
|
- Zen/Go favorites are skipped in Codex (use Claude or Desktop gateway).
|
|
152
153
|
|
|
153
|
-
## Release status (v0.
|
|
154
|
+
## Release status (v0.3.0)
|
|
154
155
|
|
|
155
|
-
Current version is **v0.
|
|
156
|
+
Current version is **v0.3.0** — official launch release with the native provider registry, complete Claude/Codex app help, unified OpenCode Zen / Go setup, duplicate-provider migration, stable post-import refreshes, agent boot flags (`--provider` / `--model`), `relay-ai --ai`, favorites catalogs, reasoning capability metadata, and new native Chinese provider templates (DeepSeek, Zhipu, Moonshot) with improved models endpoint routing.
|
|
156
157
|
|
|
157
158
|
**Known limitations (by design):**
|
|
158
159
|
- Cost display in Codex is always inaccurate for non-Anthropic models.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.0] - 2026-06-21
|
|
4
|
+
|
|
5
|
+
*Happy Father's Day!* 👨👦
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- **New Native Providers** — Added native provider templates and registry support for DeepSeek (`deepseek`), Zhipu (`zhipu`), and Moonshot (`moonshot`), facilitating direct integration of Chinese LLM providers.
|
|
10
|
+
- **Experimental Gemini Support** — Introduced experimental support for Google Gemini models via a custom SDK adapter and local proxy, enabling `relay-ai gemini`.
|
|
11
|
+
- **Kimi/Moonshot Reasoning Level Selection** — Enabled support for Codex's native "Select Reasoning Level" UI for Kimi models by exposing `supported_reasoning_levels` in the proxy catalog and translating reasoning effort parameters.
|
|
12
|
+
- **Provider Documentation** — Created a dedicated [PROVIDERS.md](file:///Users/jbendavi/dev_projects/relay-ai/docs/PROVIDERS.md) documentation file explaining the differences between Kimi, Kimi Global, and Moonshot models, and linked it from the main README.
|
|
13
|
+
|
|
14
|
+
## [0.2.8] - 2026-06-20
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- **xAI OAuth provider (`xai-oauth`)** — SuperGrok OAuth now gets its own registry slot and coexists with an API-key xAI provider; both can be active simultaneously without overwriting each other.
|
|
18
|
+
- **OpenAI OAuth provider (`openai-oauth`)** — ChatGPT Plus/Pro OAuth now gets its own registry slot and coexists with an API-key OpenAI provider; both can be active simultaneously without overwriting each other.
|
|
19
|
+
- **Browser auto-open during OAuth sign-in** — the device-code URL opens automatically in the default browser on all platforms (macOS, Windows, Linux desktop) so you don't have to copy-paste the link.
|
|
20
|
+
- **3-tier model refresh for OpenAI OAuth** — on `providers refresh-models`, relay-ai first queries the ChatGPT Codex-specific endpoint for models guaranteed to work, falls back to the filtered general ChatGPT list, and uses a static seed only when both network tiers are unreachable.
|
|
21
|
+
- **Static xAI OAuth seed** — `buildXaiOAuthModels()` provides a fallback Grok model list (Grok 3 and 4 families) when the live `api.x.ai/v1/models` endpoint rejects the SuperGrok JWT.
|
|
22
|
+
- **Registry migration** — existing `{id: 'openai', authType: 'oauth'}` and `{id: 'xai', authType: 'oauth'}` entries are automatically renamed to `openai-oauth` and `xai-oauth` respectively on next load, preserving credentials and the original keyring slot.
|
|
23
|
+
- **Richer SDK error logging in proxy** — SDK errors now include the full response body alongside the message, making Codex inference failures easier to diagnose.
|
|
24
|
+
- **Fuzzy multi-token model search** — model search now supports multi-token AND matching and punctuation normalization. Queries like `"QWEN 3.7"` or `"qwen 2.5 32"` now successfully match models like `qwen3-7b` and `qwen2.5-coder-32b`.
|
|
25
|
+
- **Multi-model selection in favorites manager** — allow users to select and add multiple favorite models from a single provider in one step using `p.multiselect` with a dimmed visual cue `(Space to select, Enter to confirm)`.
|
|
26
|
+
- **Back-button navigation in launcher model selectors** — added `← Go back` options and handled cancellations to loop back to the provider selection menu (with the chosen provider pre-selected) in `relay-ai claude`, `relay-ai codex`, `relay-ai codex-app`, and the favorites addition wizard.
|
|
27
|
+
- **Alphabetical sorting of providers and models** — sorted the launcher and wizard selection lists alphabetically using natural collation for cleaner readability and easier scanning.
|
|
28
|
+
- **Server model catalog printout** — `relay-ai server` and `relay-ai server --vertex` now print a structured, grouped, and copy-pasteable catalog of model names along with their exact ID strings to copy-paste for `anthropic` and `openai` formats, respecting gateway masking.
|
|
29
|
+
- **Unified OpenAI Endpoint Support** — `relay-ai server` now supports a native OpenAI completions endpoint (`/openai/v1/chat/completions`) for all model types (Anthropic, Google Gemini, Grok, etc.) using a bidirectional translation adapter, allowing OpenAI-compatible clients to connect to any model.
|
|
30
|
+
- **API Server Guide & THE AI Counsel setup documentation** — added a comprehensive setup guide (`docs/API_SERVER.md`) explaining server startup outputs, network IPs, and detailed integration steps for connecting THE AI Counsel to the server gateway.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- **OpenAI OAuth model retrieval** — restored live model discovery for ChatGPT accounts by explicitly sending the installed `claude` version (`?client_version=`) and a standard `User-Agent`, which the Codex backend now strictly requires.
|
|
35
|
+
- **OpenAI OAuth "Instructions are required" error** — the ChatGPT Codex backend requires the system prompt in `openai.instructions` inside `providerOptions`, not the standard `system` field; this caused every Claude Code tool-use step to fail when using an OpenAI OAuth provider.
|
|
36
|
+
- **OpenAI OAuth token expiry** — `oauthCredentialShouldRefresh` now applies the pre-emptive 2-minute JWT expiry buffer to `openai` and `openai-oauth` providers, matching the existing behaviour for xAI and GitHub Copilot. Previously, OpenAI OAuth access tokens (1-hour TTL) were only checked against the hard `expires` wall-clock, not the JWT claim.
|
|
37
|
+
- **Broken provider state after `relay-ai providers auth openai-oauth`** — if a user passed the registry ID instead of the canonical `openai` to the auth command, `upsertOAuthProvider` would store `templateId: 'openai-oauth'` and all subsequent model refreshes would throw "unsupported template". Fixed by stripping the `-oauth` suffix when deriving `templateId`; the `else` branch also now updates `templateId` on existing entries, healing any already-broken providers on next auth.
|
|
38
|
+
- **xAI live model metadata gaps** — newly-discovered Grok models not yet in the static seed were built without `contextWindow`, `reasoning`, and using the raw ID prefix for `brand` instead of `deriveBrand`. This showed as 0 context window in Claude Code's status bar and incorrect brand metadata.
|
|
39
|
+
- **Speculative OpenAI model IDs removed from seed** — `gpt-5-pro`, `gpt-5-mini`, `gpt-5-codex`, `gpt-5.2`, `gpt-5.2-pro`, and `gpt-5.2-codex` were in the static seed but are not confirmed available on the ChatGPT Codex backend. They would surface in the model picker when the network was unreachable (Tier 3 path) and then fail at inference time.
|
|
40
|
+
- **Codex direct-tier routing** — `resolveCodexRoute` now keys on `model.npm === '@ai-sdk/openai'` instead of `provider.id === 'openai'`, correctly routing standard OpenAI models to the direct tier regardless of which provider ID variant is in use.
|
|
41
|
+
- **Proxy token loopback security** — hardened local proxy endpoints (`startProxyCatalog` and `codex-proxy`) against malicious cross-origin access by generating a unique `proxyToken` per session and enforcing `Origin`/`Referer` checks (`127.0.0.1`/`localhost`) as a defense-in-depth measure. (Thanks to @wnstfy)
|
|
42
|
+
- **Server password storage** — replaced plaintext file storage for LAN network passwords with system keyring storage (`@napi-rs/keyring`), hardened dotfolder permissions, and suppressed console output in `relay-ai server` mode. (Thanks to @wnstfy)
|
|
43
|
+
- **Dependency vulnerabilities** — replaced the deprecated `smol-toml` package, enforced a `ws` version override to resolve upstream security advisories, and aligned the root package-lock.json version. (Thanks to @wnstfy)
|
|
44
|
+
- **PowerShell launch corruption** — fixed command-line argument escaping logic in `relay-ai codex-app` and `claude-app` on Windows to use single-quoted string literals, preventing `\` path corruption. (Thanks to @sewersydah)
|
|
45
|
+
- **Codex-App favorites proxy routing and model validation** — resolved model ID mapping collisions by routing favorites through provider-prefixed slugs (e.g. `xai__grok-build-0.1`), resolving `Custom` model loading and Claude Haiku gateway routing errors in the favorites proxy. Skipped unsupported OAuth favorites and added diagnostics logs.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
3
49
|
## [0.2.7] - 2026-06-19 (Official Launch Release)
|
|
4
50
|
|
|
5
51
|
### Added
|
package/README.md
CHANGED
|
@@ -11,7 +11,15 @@
|
|
|
11
11
|
[](LICENSE)
|
|
12
12
|
[](https://buymeacoffee.com/jacobbd)
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://youtu.be/IvsUPHLhX0o">
|
|
16
|
+
<img src="assets/demo-part1-thumbnail.png" alt="relay-ai demo — installation, configuration, Claude Code, Claude Cowork & Claude Code Desktop (Part 1)" width="100%">
|
|
17
|
+
</a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
> **Demo (Part 1):** Installation · Configuration · Claude Code · Claude Cowork · Claude Code Desktop — [watch on YouTube](https://youtu.be/IvsUPHLhX0o)
|
|
21
|
+
|
|
22
|
+
**relay-ai** is an interactive CLI that launches AI coding tools and runs local API gateways on your machine. Currently, it supports **Claude Code**, **Claude Desktop (Cowork + Code)**, the **OpenAI Codex CLI**, the **Codex desktop app (macOS + Windows)**, and the **Google Gemini CLI**.
|
|
15
23
|
|
|
16
24
|
Pick your backend:
|
|
17
25
|
|
|
@@ -33,13 +41,14 @@ Pick your backend:
|
|
|
33
41
|
| `relay-ai claude-app` | Launch Claude Desktop app with registry providers ([guide](docs/CLAUDE_DESKTOP_SETUP.md)) |
|
|
34
42
|
| `relay-ai codex` | Launch OpenAI Codex CLI with registry providers ([guide](docs/CODEX.md)) |
|
|
35
43
|
| `relay-ai codex-app` | Launch Codex desktop app with registry providers ([guide](docs/CODEX.md)) |
|
|
44
|
+
| `relay-ai gemini` | Launch Google Gemini CLI with registry providers |
|
|
36
45
|
| `relay-ai --ai` | Full agent reference for scripts and alef-agent ([guide](docs/AI-AGENTS.md)) |
|
|
37
46
|
|
|
38
47
|
Bare `relay-ai` prints help and migration guidance. Use `relay-ai claude` for the wizard.
|
|
39
48
|
|
|
40
49
|
## Features
|
|
41
50
|
|
|
42
|
-
- **Native provider registry:** `relay-ai providers` stores config in `~/.relay-ai/providers.json` and secrets in the OS keychain — no OpenCode binary required at launch
|
|
51
|
+
- **Native provider registry:** `relay-ai providers` stores config in `~/.relay-ai/providers.json` and secrets in the OS keychain — no OpenCode binary required at launch. See **[docs/PROVIDERS.md](docs/PROVIDERS.md)** for a full list of providers and known issues.
|
|
43
52
|
- **Provider templates:** Add Groq, Mistral, Together, OpenRouter, and 15+ SDK-backed providers, plus custom OpenAI/Anthropic-compatible endpoints
|
|
44
53
|
- **OpenCode import:** One-time migration from OpenCode (`providers import`); validates API keys and skips placeholders like `anything`
|
|
45
54
|
- **OpenCode Zen / Go:** Optional cloud backends when you have an OpenCode API key
|
|
@@ -61,7 +70,7 @@ Bare `relay-ai` prints help and migration guidance. Use `relay-ai claude` for th
|
|
|
61
70
|
|
|
62
71
|
| Tool | Command | Status |
|
|
63
72
|
|------|---------|--------|
|
|
64
|
-
| Provider registry | `relay-ai providers` | ✅ Supported |
|
|
73
|
+
| Provider registry | `relay-ai providers` | ✅ Supported ([guide](docs/PROVIDERS.md)) |
|
|
65
74
|
| Claude Code | `relay-ai claude` | ✅ Supported |
|
|
66
75
|
| Favorite models | `relay-ai models` | ✅ Supported |
|
|
67
76
|
| OpenCode API server | `relay-ai server` | ✅ Supported |
|
|
@@ -69,11 +78,12 @@ Bare `relay-ai` prints help and migration guidance. Use `relay-ai claude` for th
|
|
|
69
78
|
| Claude Desktop (Cowork + Code) | `relay-ai claude-app` | ✅ Supported macOS + Windows ([guide](docs/CLAUDE_DESKTOP_SETUP.md)) |
|
|
70
79
|
| Codex CLI | `relay-ai codex` | ✅ Supported ([guide](docs/CODEX.md)) |
|
|
71
80
|
| Codex desktop app | `relay-ai codex-app` | ✅ Supported macOS + Windows ([guide](docs/CODEX.md)) |
|
|
81
|
+
| Google Gemini CLI | `relay-ai gemini` | ✅ Supported |
|
|
72
82
|
|
|
73
83
|
## Prerequisites
|
|
74
84
|
|
|
75
85
|
- Node.js 18+
|
|
76
|
-
- A supported AI coding tool installed (e.g. [Claude Code](https://www.npmjs.com/package/@anthropic-ai/claude-code)
|
|
86
|
+
- A supported AI coding tool installed (e.g. [Claude Code](https://www.npmjs.com/package/@anthropic-ai/claude-code), [OpenAI Codex](https://www.npmjs.com/package/@openai/codex), or [Google Gemini CLI](https://www.npmjs.com/package/@google/gemini-cli))
|
|
77
87
|
- At least one provider configured via `relay-ai providers add` or `import` — **or** an [OpenCode API key](https://opencode.ai/auth) for Zen/Go cloud backends
|
|
78
88
|
- [OpenCode CLI](https://opencode.ai) only if you want **one-time import** from an existing OpenCode setup (optional)
|
|
79
89
|
- For **Vertex gateway:** [Google Cloud SDK](https://cloud.google.com/sdk) with `gcloud auth application-default login`, a GCP project with Vertex AI enabled, and Claude partner models enabled in that project
|
|
@@ -359,6 +369,22 @@ See **[docs/CODEX.md](docs/CODEX.md)** for CLI vs app differences, file ownershi
|
|
|
359
369
|
|
|
360
370
|
**Reasoning effort:** Capable models show Codex's native reasoning picker (low/medium/high, etc.). relay-ai maps your choice to each provider's SDK options and preserves existing `model_reasoning_effort` in Codex config. Claude Code `/effort` and the `relay-ai server` gateway use the same mapping — see the [reasoning section in docs/CODEX.md](docs/CODEX.md#reasoning-effort).
|
|
361
371
|
|
|
372
|
+
### Google Gemini CLI (`relay-ai gemini`)
|
|
373
|
+
|
|
374
|
+
Launch the [Google Gemini CLI](https://www.npmjs.com/package/@google/gemini-cli) with registry providers.
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
relay-ai gemini
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Pick provider → pick model → Gemini prompt loop opens. Non-interactive tasks with streaming NDJSON are also fully supported:
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
relay-ai gemini --provider google --model gemini-2.5-flash -p "Review this file" -o stream-json
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
For agent / alef-agent integration (boot flags, NDJSON): **[docs/AI-AGENTS.md](docs/AI-AGENTS.md)** and `relay-ai --ai`.
|
|
387
|
+
|
|
362
388
|
## How it works
|
|
363
389
|
|
|
364
390
|
### OpenCode Zen / Go filtering
|
|
Binary file
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
body, html {
|
|
2
|
+
margin:0; padding: 0;
|
|
3
|
+
height: 100%;
|
|
4
|
+
}
|
|
5
|
+
body {
|
|
6
|
+
font-family: Helvetica Neue, Helvetica, Arial;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
color:#333;
|
|
9
|
+
}
|
|
10
|
+
.small { font-size: 12px; }
|
|
11
|
+
*, *:after, *:before {
|
|
12
|
+
-webkit-box-sizing:border-box;
|
|
13
|
+
-moz-box-sizing:border-box;
|
|
14
|
+
box-sizing:border-box;
|
|
15
|
+
}
|
|
16
|
+
h1 { font-size: 20px; margin: 0;}
|
|
17
|
+
h2 { font-size: 14px; }
|
|
18
|
+
pre {
|
|
19
|
+
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 0;
|
|
22
|
+
-moz-tab-size: 2;
|
|
23
|
+
-o-tab-size: 2;
|
|
24
|
+
tab-size: 2;
|
|
25
|
+
}
|
|
26
|
+
a { color:#0074D9; text-decoration:none; }
|
|
27
|
+
a:hover { text-decoration:underline; }
|
|
28
|
+
.strong { font-weight: bold; }
|
|
29
|
+
.space-top1 { padding: 10px 0 0 0; }
|
|
30
|
+
.pad2y { padding: 20px 0; }
|
|
31
|
+
.pad1y { padding: 10px 0; }
|
|
32
|
+
.pad2x { padding: 0 20px; }
|
|
33
|
+
.pad2 { padding: 20px; }
|
|
34
|
+
.pad1 { padding: 10px; }
|
|
35
|
+
.space-left2 { padding-left:55px; }
|
|
36
|
+
.space-right2 { padding-right:20px; }
|
|
37
|
+
.center { text-align:center; }
|
|
38
|
+
.clearfix { display:block; }
|
|
39
|
+
.clearfix:after {
|
|
40
|
+
content:'';
|
|
41
|
+
display:block;
|
|
42
|
+
height:0;
|
|
43
|
+
clear:both;
|
|
44
|
+
visibility:hidden;
|
|
45
|
+
}
|
|
46
|
+
.fl { float: left; }
|
|
47
|
+
@media only screen and (max-width:640px) {
|
|
48
|
+
.col3 { width:100%; max-width:100%; }
|
|
49
|
+
.hide-mobile { display:none!important; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.quiet {
|
|
53
|
+
color: #7f7f7f;
|
|
54
|
+
color: rgba(0,0,0,0.5);
|
|
55
|
+
}
|
|
56
|
+
.quiet a { opacity: 0.7; }
|
|
57
|
+
|
|
58
|
+
.fraction {
|
|
59
|
+
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
|
60
|
+
font-size: 10px;
|
|
61
|
+
color: #555;
|
|
62
|
+
background: #E8E8E8;
|
|
63
|
+
padding: 4px 5px;
|
|
64
|
+
border-radius: 3px;
|
|
65
|
+
vertical-align: middle;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
div.path a:link, div.path a:visited { color: #333; }
|
|
69
|
+
table.coverage {
|
|
70
|
+
border-collapse: collapse;
|
|
71
|
+
margin: 10px 0 0 0;
|
|
72
|
+
padding: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
table.coverage td {
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 0;
|
|
78
|
+
vertical-align: top;
|
|
79
|
+
}
|
|
80
|
+
table.coverage td.line-count {
|
|
81
|
+
text-align: right;
|
|
82
|
+
padding: 0 5px 0 20px;
|
|
83
|
+
}
|
|
84
|
+
table.coverage td.line-coverage {
|
|
85
|
+
text-align: right;
|
|
86
|
+
padding-right: 10px;
|
|
87
|
+
min-width:20px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
table.coverage td span.cline-any {
|
|
91
|
+
display: inline-block;
|
|
92
|
+
padding: 0 5px;
|
|
93
|
+
width: 100%;
|
|
94
|
+
}
|
|
95
|
+
.missing-if-branch {
|
|
96
|
+
display: inline-block;
|
|
97
|
+
margin-right: 5px;
|
|
98
|
+
border-radius: 3px;
|
|
99
|
+
position: relative;
|
|
100
|
+
padding: 0 4px;
|
|
101
|
+
background: #333;
|
|
102
|
+
color: yellow;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.skip-if-branch {
|
|
106
|
+
display: none;
|
|
107
|
+
margin-right: 10px;
|
|
108
|
+
position: relative;
|
|
109
|
+
padding: 0 4px;
|
|
110
|
+
background: #ccc;
|
|
111
|
+
color: white;
|
|
112
|
+
}
|
|
113
|
+
.missing-if-branch .typ, .skip-if-branch .typ {
|
|
114
|
+
color: inherit !important;
|
|
115
|
+
}
|
|
116
|
+
.coverage-summary {
|
|
117
|
+
border-collapse: collapse;
|
|
118
|
+
width: 100%;
|
|
119
|
+
}
|
|
120
|
+
.coverage-summary tr { border-bottom: 1px solid #bbb; }
|
|
121
|
+
.keyline-all { border: 1px solid #ddd; }
|
|
122
|
+
.coverage-summary td, .coverage-summary th { padding: 10px; }
|
|
123
|
+
.coverage-summary tbody { border: 1px solid #bbb; }
|
|
124
|
+
.coverage-summary td { border-right: 1px solid #bbb; }
|
|
125
|
+
.coverage-summary td:last-child { border-right: none; }
|
|
126
|
+
.coverage-summary th {
|
|
127
|
+
text-align: left;
|
|
128
|
+
font-weight: normal;
|
|
129
|
+
white-space: nowrap;
|
|
130
|
+
}
|
|
131
|
+
.coverage-summary th.file { border-right: none !important; }
|
|
132
|
+
.coverage-summary th.pct { }
|
|
133
|
+
.coverage-summary th.pic,
|
|
134
|
+
.coverage-summary th.abs,
|
|
135
|
+
.coverage-summary td.pct,
|
|
136
|
+
.coverage-summary td.abs { text-align: right; }
|
|
137
|
+
.coverage-summary td.file { white-space: nowrap; }
|
|
138
|
+
.coverage-summary td.pic { min-width: 120px !important; }
|
|
139
|
+
.coverage-summary tfoot td { }
|
|
140
|
+
|
|
141
|
+
.coverage-summary .sorter {
|
|
142
|
+
height: 10px;
|
|
143
|
+
width: 7px;
|
|
144
|
+
display: inline-block;
|
|
145
|
+
margin-left: 0.5em;
|
|
146
|
+
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
|
|
147
|
+
}
|
|
148
|
+
.coverage-summary .sorted .sorter {
|
|
149
|
+
background-position: 0 -20px;
|
|
150
|
+
}
|
|
151
|
+
.coverage-summary .sorted-desc .sorter {
|
|
152
|
+
background-position: 0 -10px;
|
|
153
|
+
}
|
|
154
|
+
.status-line { height: 10px; }
|
|
155
|
+
/* yellow */
|
|
156
|
+
.cbranch-no { background: yellow !important; color: #111; }
|
|
157
|
+
/* dark red */
|
|
158
|
+
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
|
|
159
|
+
.low .chart { border:1px solid #C21F39 }
|
|
160
|
+
.highlighted,
|
|
161
|
+
.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
|
|
162
|
+
background: #C21F39 !important;
|
|
163
|
+
}
|
|
164
|
+
/* medium red */
|
|
165
|
+
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
|
|
166
|
+
/* light red */
|
|
167
|
+
.low, .cline-no { background:#FCE1E5 }
|
|
168
|
+
/* light green */
|
|
169
|
+
.high, .cline-yes { background:rgb(230,245,208) }
|
|
170
|
+
/* medium green */
|
|
171
|
+
.cstat-yes { background:rgb(161,215,106) }
|
|
172
|
+
/* dark green */
|
|
173
|
+
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
|
|
174
|
+
.high .chart { border:1px solid rgb(77,146,33) }
|
|
175
|
+
/* dark yellow (gold) */
|
|
176
|
+
.status-line.medium, .medium .cover-fill { background: #f9cd0b; }
|
|
177
|
+
.medium .chart { border:1px solid #f9cd0b; }
|
|
178
|
+
/* light yellow */
|
|
179
|
+
.medium { background: #fff4c2; }
|
|
180
|
+
|
|
181
|
+
.cstat-skip { background: #ddd; color: #111; }
|
|
182
|
+
.fstat-skip { background: #ddd; color: #111 !important; }
|
|
183
|
+
.cbranch-skip { background: #ddd !important; color: #111; }
|
|
184
|
+
|
|
185
|
+
span.cline-neutral { background: #eaeaea; }
|
|
186
|
+
|
|
187
|
+
.coverage-summary td.empty {
|
|
188
|
+
opacity: .5;
|
|
189
|
+
padding-top: 4px;
|
|
190
|
+
padding-bottom: 4px;
|
|
191
|
+
line-height: 1;
|
|
192
|
+
color: #888;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.cover-fill, .cover-empty {
|
|
196
|
+
display:inline-block;
|
|
197
|
+
height: 12px;
|
|
198
|
+
}
|
|
199
|
+
.chart {
|
|
200
|
+
line-height: 0;
|
|
201
|
+
}
|
|
202
|
+
.cover-empty {
|
|
203
|
+
background: white;
|
|
204
|
+
}
|
|
205
|
+
.cover-full {
|
|
206
|
+
border-right: none !important;
|
|
207
|
+
}
|
|
208
|
+
pre.prettyprint {
|
|
209
|
+
border: none !important;
|
|
210
|
+
padding: 0 !important;
|
|
211
|
+
margin: 0 !important;
|
|
212
|
+
}
|
|
213
|
+
.com { color: #999 !important; }
|
|
214
|
+
.ignore-none { color: #999; font-weight: normal; }
|
|
215
|
+
|
|
216
|
+
.wrapper {
|
|
217
|
+
min-height: 100%;
|
|
218
|
+
height: auto !important;
|
|
219
|
+
height: 100%;
|
|
220
|
+
margin: 0 auto -48px;
|
|
221
|
+
}
|
|
222
|
+
.footer, .push {
|
|
223
|
+
height: 48px;
|
|
224
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
var jumpToCode = (function init() {
|
|
3
|
+
// Classes of code we would like to highlight in the file view
|
|
4
|
+
var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
|
|
5
|
+
|
|
6
|
+
// Elements to highlight in the file listing view
|
|
7
|
+
var fileListingElements = ['td.pct.low'];
|
|
8
|
+
|
|
9
|
+
// We don't want to select elements that are direct descendants of another match
|
|
10
|
+
var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
|
|
11
|
+
|
|
12
|
+
// Selector that finds elements on the page to which we can jump
|
|
13
|
+
var selector =
|
|
14
|
+
fileListingElements.join(', ') +
|
|
15
|
+
', ' +
|
|
16
|
+
notSelector +
|
|
17
|
+
missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
|
|
18
|
+
|
|
19
|
+
// The NodeList of matching elements
|
|
20
|
+
var missingCoverageElements = document.querySelectorAll(selector);
|
|
21
|
+
|
|
22
|
+
var currentIndex;
|
|
23
|
+
|
|
24
|
+
function toggleClass(index) {
|
|
25
|
+
missingCoverageElements
|
|
26
|
+
.item(currentIndex)
|
|
27
|
+
.classList.remove('highlighted');
|
|
28
|
+
missingCoverageElements.item(index).classList.add('highlighted');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function makeCurrent(index) {
|
|
32
|
+
toggleClass(index);
|
|
33
|
+
currentIndex = index;
|
|
34
|
+
missingCoverageElements.item(index).scrollIntoView({
|
|
35
|
+
behavior: 'smooth',
|
|
36
|
+
block: 'center',
|
|
37
|
+
inline: 'center'
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function goToPrevious() {
|
|
42
|
+
var nextIndex = 0;
|
|
43
|
+
if (typeof currentIndex !== 'number' || currentIndex === 0) {
|
|
44
|
+
nextIndex = missingCoverageElements.length - 1;
|
|
45
|
+
} else if (missingCoverageElements.length > 1) {
|
|
46
|
+
nextIndex = currentIndex - 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
makeCurrent(nextIndex);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function goToNext() {
|
|
53
|
+
var nextIndex = 0;
|
|
54
|
+
|
|
55
|
+
if (
|
|
56
|
+
typeof currentIndex === 'number' &&
|
|
57
|
+
currentIndex < missingCoverageElements.length - 1
|
|
58
|
+
) {
|
|
59
|
+
nextIndex = currentIndex + 1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
makeCurrent(nextIndex);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return function jump(event) {
|
|
66
|
+
if (
|
|
67
|
+
document.getElementById('fileSearch') === document.activeElement &&
|
|
68
|
+
document.activeElement != null
|
|
69
|
+
) {
|
|
70
|
+
// if we're currently focused on the search input, we don't want to navigate
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
switch (event.which) {
|
|
75
|
+
case 78: // n
|
|
76
|
+
case 74: // j
|
|
77
|
+
goToNext();
|
|
78
|
+
break;
|
|
79
|
+
case 66: // b
|
|
80
|
+
case 75: // k
|
|
81
|
+
case 80: // p
|
|
82
|
+
goToPrevious();
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
})();
|
|
87
|
+
window.addEventListener('keydown', jumpToCode);
|