Skip to content

Commit f9046c8

Browse files
quickbeardclaude
andcommitted
feat(provider): rename the SSO identity to AIGW
SSO-issued keys now write the aigw / AIGW provider identity into agent configs. The pre-rename netgate id joins aigateway as a recognition-only legacy id: detection, base_url readback, and the credential scrub still match it, nothing writes it, and installs converge on aigw at their next config rewrite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 937b437 commit f9046c8

9 files changed

Lines changed: 127 additions & 128 deletions

File tree

AGENTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,11 @@ When testing the gate, build CoDev-authored fixtures by calling the real writers
132132

133133
`src/lib/provider.ts` owns the provider id and display name CoDev writes into the OpenAI-compatible agent configs (Codex `model_provider` + `[model_providers.<id>]`, OpenCode/CoDev Code `provider.<id>` plus the `"<id>/<model>"` reference, Continue's `CoDev (<name>)` title). Claude Code has no provider concept — it only gets env vars.
134134

135-
Two built-in identities: **netgate / netGate** for SSO-issued keys (the "Get a new API Key" path, and "Reuse existing API Key" when the saved key carries no provider), and **ai-gateway / AI Gateway** as the manual path's fallback. On "I have my own API Key" the first form field is an optional, ASCII-only **Provider Name**; `providerFromName` slugs it (lowercase, non-alphanumeric runs → `-`, trimmed, capped at 32) and a blank or unusable name falls back to AI Gateway. The slug charset is deliberately `[a-z0-9-]`: TOML bare-key safe so `[model_providers.<id>]` needs no quoting, and slash-free so OpenCode's `"<id>/<model>"` stays parseable.
135+
Two built-in identities: **aigw / AIGW** for SSO-issued keys (the "Get a new API Key" path, and "Reuse existing API Key" when the saved key carries no provider), and **ai-gateway / AI Gateway** as the manual path's fallback. On "I have my own API Key" the first form field is an optional, ASCII-only **Provider Name**; `providerFromName` slugs it (lowercase, non-alphanumeric runs → `-`, trimmed, capped at 32) and a blank or unusable name falls back to AI Gateway. The slug charset is deliberately `[a-z0-9-]`: TOML bare-key safe so `[model_providers.<id>]` needs no quoting, and slash-free so OpenCode's `"<id>/<model>"` stays parseable.
136136

137-
The load-bearing consequence: the provider id **is** CoDev's authorship marker for codex/opencode/codev-code. It gates `detectConfiguredTools` (whose configs `codevhub model` rewrites), `isCodevAuthored` (restore's delete-vs-`kept-live` decision), and `readAgentConfig`'s base_url readback. Since it's no longer a compile-time constant, `codevProviderIds()` returns the candidate set — the id saved in `~/.codev-hub/auth.json`, then `netgate`, `ai-gateway`, and the pre-rename `aigateway` — and `firstNestedKey` resolves the live entry against it. Nothing writes `aigateway` any more; it stays recognized so installs predating the rename keep working, and they converge on the new id at the next config rewrite. Detection is deliberately *saved-id-first*: without auth.json a custom-id config is unattributable and restore keeps it rather than deleting it, matching the module's standing rule that a config we can't attribute is one we don't delete.
137+
The load-bearing consequence: the provider id **is** CoDev's authorship marker for codex/opencode/codev-code. It gates `detectConfiguredTools` (whose configs `codevhub model` rewrites), `isCodevAuthored` (restore's delete-vs-`kept-live` decision), and `readAgentConfig`'s base_url readback. Since it's no longer a compile-time constant, `codevProviderIds()` returns the candidate set — the id saved in `~/.codev-hub/auth.json`, then `aigw`, `ai-gateway`, and the pre-rename `netgate` and `aigateway` — and `firstNestedKey` resolves the live entry against it. Nothing writes the pre-rename ids any more; they stay recognized so installs predating the renames keep working, and they converge on the new id at the next config rewrite. Detection is deliberately *saved-id-first*: without auth.json a custom-id config is unattributable and restore keeps it rather than deleting it, matching the module's standing rule that a config we can't attribute is one we don't delete.
138138

139-
`Credentials`/`ApiKeyCreds` carry `providerId`/`providerName` (persisted as `provider_id`/`provider_name`), and `resolveProvider` supplies the netGate default when they're absent. **`saveApiKey` writes the whole api-key block, so an omitted provider pair clears it** — every re-save site (`ModelApp`'s two re-auth branches and its model switch, `refresh.ts#ensureFreshGatewayKey`, `SetupApp`'s model-choice) must thread it through, or a manually-named provider silently reverts to netGate on the next model switch or launch-time key refresh. `logout()` is the same hazard by a different route: it rebuilds the surviving file field-by-field rather than deleting SSO keys from it, so anything not listed in its `preserved` object is dropped. The provider pair was missing there and had to be added back — a field added to `AuthFileContents` is not automatically a field that survives sign-out.
139+
`Credentials`/`ApiKeyCreds` carry `providerId`/`providerName` (persisted as `provider_id`/`provider_name`), and `resolveProvider` supplies the AIGW default when they're absent. **`saveApiKey` writes the whole api-key block, so an omitted provider pair clears it** — every re-save site (`ModelApp`'s two re-auth branches and its model switch, `refresh.ts#ensureFreshGatewayKey`, `SetupApp`'s model-choice) must thread it through, or a manually-named provider silently reverts to AIGW on the next model switch or launch-time key refresh. `logout()` is the same hazard by a different route: it rebuilds the surviving file field-by-field rather than deleting SSO keys from it, so anything not listed in its `preserved` object is dropped. The provider pair was missing there and had to be added back — a field added to `AuthFileContents` is not automatically a field that survives sign-out.
140140

141141
## Context windows and auto-compaction
142142

src/lib/auth.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export interface ApiKeyCreds {
7373
baseUrl?: string;
7474
model?: string;
7575
// Set only for manually-entered keys, where the user names their own
76-
// provider. Absent ⇒ the key is SSO-issued and takes the netGate default
76+
// provider. Absent ⇒ the key is SSO-issued and takes the AIGW default
7777
// (see lib/provider.ts#resolveProvider).
7878
providerId?: string;
7979
providerName?: string;
@@ -219,7 +219,7 @@ function saveAuth(data: AuthData): void {
219219
// Writes the whole api-key block, so an omitted field *clears* it: callers that
220220
// re-save a key (model switch, re-auth, launch-time refresh) must thread the
221221
// provider pair through, or a manually-named provider silently reverts to the
222-
// netGate default on the next write.
222+
// AIGW default on the next write.
223223
export function saveApiKey(creds: ApiKeyCreds): void {
224224
const existing = readAuthFile() ?? {};
225225
writeAuthFile({
@@ -311,7 +311,7 @@ export async function logout(): Promise<boolean> {
311311
model: raw.model,
312312
// The provider pair belongs to the api-key block above and must travel
313313
// with it. Dropping it here silently re-labels a manually-named
314-
// provider as the netGate default on the next config write — the same
314+
// provider as the AIGW default on the next config write — the same
315315
// failure saveApiKey's whole-block rewrite is documented to cause,
316316
// reached by a different route.
317317
provider_id: raw.provider_id,

src/lib/configure.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export interface Credentials {
7373
// Absent ⇒ treat as [model], so older call sites stay valid.
7474
models?: string[];
7575
// The provider the user named on the manual path. Absent ⇒ SSO-issued key,
76-
// which gets the built-in netGate identity (lib/provider.ts).
76+
// which gets the built-in AIGW identity (lib/provider.ts).
7777
providerId?: string;
7878
providerName?: string;
7979
}
@@ -179,7 +179,7 @@ const OPENCODE_K = {
179179
// Codex → config.toml → model_providers.<provider>.base_url
180180
// OpenCode → opencode.json → provider.<provider>.options.baseURL
181181
//
182-
// <provider> is the netGate default for SSO-issued keys, or the id derived from
182+
// <provider> is the AIGW default for SSO-issued keys, or the id derived from
183183
// the name the user typed on the manual path — so it's resolved at read time
184184
// against codevProviderIds() rather than a fixed key.
185185
//

src/lib/provider.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ export interface ProviderIdentity {
1010
}
1111

1212
// SSO-issued keys ("Get a new API Key", and "Reuse existing API Key" when the
13-
// saved key carries no provider of its own) — "netgate" / "netGate".
13+
// saved key carries no provider of its own) — "aigw" / "AIGW".
1414
const DEFAULT_PROVIDER: ProviderIdentity = {
15-
id: atob("bmV0Z2F0ZQ=="),
16-
name: atob("bmV0R2F0ZQ=="),
15+
id: atob("YWlndw=="),
16+
name: atob("QUlHVw=="),
1717
};
1818

1919
// The manual path's fallback, used when the user leaves the provider name blank
@@ -23,10 +23,11 @@ const MANUAL_PROVIDER: ProviderIdentity = {
2323
name: atob("QUkgR2F0ZXdheQ=="),
2424
};
2525

26-
// Pre-rename installs wrote this id — "aigateway". Kept purely so detection
27-
// (and the base_url readback) still recognizes configs written before the
28-
// netGate rename; nothing writes it any more.
29-
const LEGACY_PROVIDER_ID = atob("YWlnYXRld2F5");
26+
// Pre-rename installs wrote these ids — "netgate" (the SSO identity before the
27+
// AIGW rename) and "aigateway" (before the rename preceding that). Kept purely
28+
// so detection (and the base_url readback) still recognizes configs written
29+
// before the renames; nothing writes them any more.
30+
const LEGACY_PROVIDER_IDS = [atob("bmV0Z2F0ZQ=="), atob("YWlnYXRld2F5")];
3031

3132
// Provider ids end up as TOML bare keys (`[model_providers.<id>]`) and as the
3233
// left half of OpenCode's `"<id>/<model>"` string, so the slug is restricted to
@@ -59,7 +60,7 @@ export function providerFromName(name: string): ProviderIdentity {
5960

6061
// Configure-time resolution. Credentials carry a provider only when they came
6162
// from the manual path (or from a saved manual key being reused); everything
62-
// else is an SSO-issued key and gets the netGate default.
63+
// else is an SSO-issued key and gets the AIGW default.
6364
export function resolveProvider(creds: {
6465
providerId?: string;
6566
providerName?: string;
@@ -78,7 +79,7 @@ export function resolveProvider(creds: {
7879
// which is the conservative direction this module has always taken.
7980
export function codevProviderIds(): string[] {
8081
const saved = loadApiKey()?.providerId;
81-
const ids = [DEFAULT_PROVIDER.id, MANUAL_PROVIDER.id, LEGACY_PROVIDER_ID];
82+
const ids = [DEFAULT_PROVIDER.id, MANUAL_PROVIDER.id, ...LEGACY_PROVIDER_IDS];
8283
if (saved && !ids.includes(saved)) ids.unshift(saved);
8384
return ids;
8485
}

tests/lib/auth.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ describe("logout", () => {
247247
});
248248

249249
// The provider pair identifies a manually-named provider and is what every
250-
// config writer keys off. Losing it here reverts the user to the netGate
250+
// config writer keys off. Losing it here reverts the user to the AIGW
251251
// default on the next model switch or launch-time key refresh, silently.
252252
test("preserves the provider pair alongside the key it belongs to", async () => {
253253
const dir = join(tempDir, ".codev-hub");

0 commit comments

Comments
 (0)