@gajae-code/ai 0.7.3 → 0.7.4

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 CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.7.4] - 2026-06-27
6
+
7
+ ### Fixed
8
+
9
+ - Treated `openai-codex-device` as an auth-storage alias for `openai-codex`, so headless/device Codex logins show as authenticated and logout/remove the stored Codex credential instead of appearing unsaved (#1151).
10
+ - Disabled thinking for OpenCode Go forced tool calls so forced-tool turns no longer emit unsupported thinking content (#1185).
11
+ - Restored the GPT-5.5 context window to its correct size (#1186).
12
+
5
13
  ## [0.7.3] - 2026-06-25
6
14
  ### Added
7
15
 
@@ -41,7 +41,7 @@ export declare function applyGeneratedModelPolicies(models: ApiModel<Api>[]): vo
41
41
  * model with a larger context window on the same provider:
42
42
  * - `OpenAI code backend-spark` variants promote to `gpt-5.5`.
43
43
  *
44
- * `gpt-5.5` itself is a 400K-context model and is not demoted to `gpt-5.4`
44
+ * `gpt-5.5` itself is a 1M-context model and is not demoted to `gpt-5.4`
45
45
  * (which has a smaller window), so it has no promotion target.
46
46
  */
47
47
  export declare function linkOpenAIPromotionTargets(models: ApiModel<Api>[]): void;
@@ -32,6 +32,7 @@ export declare function getOAuthApiKey(provider: OAuthProvider, credentials: Rec
32
32
  newCredentials: OAuthCredentials;
33
33
  apiKey: string;
34
34
  } | null>;
35
+ export declare function resolveOAuthStorageProvider(provider: OAuthProviderId): OAuthProviderId;
35
36
  /**
36
37
  * Get list of OAuth providers.
37
38
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/ai",
4
- "version": "0.7.3",
4
+ "version": "0.7.4",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://gaebal-gajae.dev",
7
7
  "author": "Yeachan-Heo",
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@anthropic-ai/sdk": "^0.94.0",
45
45
  "@bufbuild/protobuf": "^2.12.0",
46
- "@gajae-code/utils": "0.7.3",
46
+ "@gajae-code/utils": "0.7.4",
47
47
  "openai": "^6.36.0",
48
48
  "partial-json": "^0.1.7",
49
49
  "zod": "4.4.3"
@@ -31,7 +31,7 @@ import { grokCliRankingStrategy, grokCliUsageProvider } from "./usage/grok-cli";
31
31
  import { kimiUsageProvider } from "./usage/kimi";
32
32
  import { codexRankingStrategy, openaiCodexUsageProvider } from "./usage/openai-codex";
33
33
  import { zaiUsageProvider } from "./usage/zai";
34
- import { getOAuthApiKey, getOAuthProvider, refreshOAuthToken } from "./utils/oauth";
34
+ import { getOAuthApiKey, getOAuthProvider, refreshOAuthToken, resolveOAuthStorageProvider } from "./utils/oauth";
35
35
  import { loginDeepSeek } from "./utils/oauth/deepseek";
36
36
  import { loginOpenAICodexDevice } from "./utils/oauth/openai-codex";
37
37
  import type { OAuthController, OAuthCredentials, OAuthProvider, OAuthProviderId } from "./utils/oauth/types";
@@ -918,7 +918,8 @@ export class AuthStorage {
918
918
  * @returns Array of stored credentials, empty if none exist
919
919
  */
920
920
  #getStoredCredentials(provider: string): StoredCredential[] {
921
- return this.#data.get(provider) ?? [];
921
+ const storageProvider = resolveOAuthStorageProvider(provider);
922
+ return this.#data.get(storageProvider) ?? [];
922
923
  }
923
924
 
924
925
  /**
@@ -1250,16 +1251,17 @@ export class AuthStorage {
1250
1251
  * Set credential for a provider.
1251
1252
  */
1252
1253
  async set(provider: string, credential: AuthCredentialEntry): Promise<void> {
1254
+ const storageProvider = resolveOAuthStorageProvider(provider);
1253
1255
  const normalized = Array.isArray(credential) ? credential : [credential];
1254
- const deduped = this.#dedupeOAuthCredentials(provider, normalized);
1256
+ const deduped = this.#dedupeOAuthCredentials(storageProvider, normalized);
1255
1257
  const stored = this.#store.replaceAuthCredentialsRemote
1256
- ? await this.#store.replaceAuthCredentialsRemote(provider, deduped)
1257
- : this.#store.replaceAuthCredentialsForProvider(provider, deduped);
1258
+ ? await this.#store.replaceAuthCredentialsRemote(storageProvider, deduped)
1259
+ : this.#store.replaceAuthCredentialsForProvider(storageProvider, deduped);
1258
1260
  this.#setStoredCredentials(
1259
- provider,
1261
+ storageProvider,
1260
1262
  stored.map(record => ({ id: record.id, credential: record.credential })),
1261
1263
  );
1262
- this.#resetProviderAssignments(provider);
1264
+ this.#resetProviderAssignments(storageProvider);
1263
1265
  }
1264
1266
 
1265
1267
  #toSnapshotEntries(provider: string, stored: StoredAuthCredential[]): AuthCredentialSnapshotEntry[] {
@@ -1289,26 +1291,30 @@ export class AuthStorage {
1289
1291
  provider: string,
1290
1292
  credential: AuthCredential,
1291
1293
  ): Promise<AuthCredentialIfAbsentSnapshotResult> {
1292
- if (this.#runtimeOverrides.has(provider)) return this.#snapshotSkipResult(provider, "skipped-existing-runtime");
1293
- if (this.#configOverrides.has(provider)) return this.#snapshotSkipResult(provider, "skipped-existing-config");
1294
- if (this.#getCredentialsForProvider(provider).length > 0)
1295
- return this.#snapshotSkipResult(provider, "skipped-existing");
1296
- if (getEnvApiKey(provider)) return this.#snapshotSkipResult(provider, "skipped-existing-env");
1297
- if (this.#fallbackResolver?.(provider)) return this.#snapshotSkipResult(provider, "skipped-existing-fallback");
1294
+ const storageProvider = resolveOAuthStorageProvider(provider);
1295
+ if (this.#runtimeOverrides.has(storageProvider))
1296
+ return this.#snapshotSkipResult(storageProvider, "skipped-existing-runtime");
1297
+ if (this.#configOverrides.has(storageProvider))
1298
+ return this.#snapshotSkipResult(storageProvider, "skipped-existing-config");
1299
+ if (this.#getCredentialsForProvider(storageProvider).length > 0)
1300
+ return this.#snapshotSkipResult(storageProvider, "skipped-existing");
1301
+ if (getEnvApiKey(storageProvider)) return this.#snapshotSkipResult(storageProvider, "skipped-existing-env");
1302
+ if (this.#fallbackResolver?.(storageProvider))
1303
+ return this.#snapshotSkipResult(storageProvider, "skipped-existing-fallback");
1298
1304
 
1299
1305
  const result = this.#store.upsertAuthCredentialRemoteIfAbsent
1300
- ? await this.#store.upsertAuthCredentialRemoteIfAbsent(provider, credential)
1301
- : this.#store.upsertAuthCredentialForProviderIfAbsent(provider, credential);
1306
+ ? await this.#store.upsertAuthCredentialRemoteIfAbsent(storageProvider, credential)
1307
+ : this.#store.upsertAuthCredentialForProviderIfAbsent(storageProvider, credential);
1302
1308
  this.#setStoredCredentials(
1303
- provider,
1309
+ storageProvider,
1304
1310
  result.entries.map(entry => ({ id: entry.id, credential: entry.credential })),
1305
1311
  );
1306
- this.#resetProviderAssignments(provider);
1312
+ this.#resetProviderAssignments(storageProvider);
1307
1313
  return {
1308
1314
  inserted: result.inserted,
1309
1315
  reason: result.reason,
1310
1316
  provider: result.provider,
1311
- entries: this.#toSnapshotEntries(provider, result.entries),
1317
+ entries: this.#toSnapshotEntries(storageProvider, result.entries),
1312
1318
  };
1313
1319
  }
1314
1320
 
@@ -1327,13 +1333,14 @@ export class AuthStorage {
1327
1333
  * Remove credential for a provider.
1328
1334
  */
1329
1335
  async remove(provider: string): Promise<void> {
1336
+ const storageProvider = resolveOAuthStorageProvider(provider);
1330
1337
  if (this.#store.deleteAuthCredentialsRemote) {
1331
- await this.#store.deleteAuthCredentialsRemote(provider, "deleted by user");
1338
+ await this.#store.deleteAuthCredentialsRemote(storageProvider, "deleted by user");
1332
1339
  } else {
1333
- this.#store.deleteAuthCredentialsForProvider(provider, "deleted by user");
1340
+ this.#store.deleteAuthCredentialsForProvider(storageProvider, "deleted by user");
1334
1341
  }
1335
- this.#setStoredCredentials(provider, []);
1336
- this.#resetProviderAssignments(provider);
1342
+ this.#setStoredCredentials(storageProvider, []);
1343
+ this.#resetProviderAssignments(storageProvider);
1337
1344
  }
1338
1345
 
1339
1346
  /**
@@ -1355,11 +1362,12 @@ export class AuthStorage {
1355
1362
  * Unlike getApiKey(), this doesn't refresh OAuth tokens.
1356
1363
  */
1357
1364
  hasAuth(provider: string): boolean {
1358
- if (this.#runtimeOverrides.has(provider)) return true;
1359
- if (this.#configOverrides.has(provider)) return true;
1360
- if (this.#getCredentialsForProvider(provider).length > 0) return true;
1361
- if (getEnvApiKey(provider)) return true;
1362
- if (this.#fallbackResolver?.(provider)) return true;
1365
+ const storageProvider = resolveOAuthStorageProvider(provider);
1366
+ if (this.#runtimeOverrides.has(storageProvider)) return true;
1367
+ if (this.#configOverrides.has(storageProvider)) return true;
1368
+ if (this.#getCredentialsForProvider(storageProvider).length > 0) return true;
1369
+ if (getEnvApiKey(storageProvider)) return true;
1370
+ if (this.#fallbackResolver?.(storageProvider)) return true;
1363
1371
  return false;
1364
1372
  }
1365
1373
 
@@ -197,7 +197,7 @@ export function applyGeneratedModelPolicies(models: ApiModel<Api>[]): void {
197
197
  * model with a larger context window on the same provider:
198
198
  * - `OpenAI code backend-spark` variants promote to `gpt-5.5`.
199
199
  *
200
- * `gpt-5.5` itself is a 400K-context model and is not demoted to `gpt-5.4`
200
+ * `gpt-5.5` itself is a 1M-context model and is not demoted to `gpt-5.4`
201
201
  * (which has a smaller window), so it has no promotion target.
202
202
  */
203
203
  export function linkOpenAIPromotionTargets(models: ApiModel<Api>[]): void {
@@ -453,15 +453,8 @@ function inferGeneratedApplyPatchToolType(
453
453
  }
454
454
 
455
455
  function applyGpt55ContextWindow(model: ApiModel<Api>, parsedModel: OpenAIModel): boolean {
456
- // OpenAI Codex reports GPT-5.5 with a 272K prompt budget. Keep the generated
457
- // bundle aligned with the backend limit so compaction fires before the prompt
458
- // crosses the usable Codex window instead of trusting stale 400K snapshots.
459
- if (model.provider === "openai-codex" && parsedModel.variant === "base" && semverEqual(parsedModel.version, "5.5")) {
460
- model.contextWindow = 272000;
461
- return true;
462
- }
463
456
  if (parsedModel.variant === "base" && semverEqual(parsedModel.version, "5.5")) {
464
- model.contextWindow = 400000;
457
+ model.contextWindow = 1_000_000;
465
458
  return true;
466
459
  }
467
460
  return false;
package/src/models.json CHANGED
@@ -56310,7 +56310,7 @@
56310
56310
  "cacheRead": 0.5,
56311
56311
  "cacheWrite": 0
56312
56312
  },
56313
- "contextWindow": 272000,
56313
+ "contextWindow": 1000000,
56314
56314
  "maxTokens": 128000,
56315
56315
  "preferWebsockets": true,
56316
56316
  "priority": 9,
@@ -103,6 +103,7 @@ export function detectOpenAICompat(model: Model<"openai-completions">, resolvedB
103
103
  provider === "opencode-go" ||
104
104
  baseUrl.includes("opencode.ai");
105
105
  const isOpenCodeProvider = provider === "opencode-go" || provider === "opencode-zen";
106
+ const isOpenCodeGoReasoning = provider === "opencode-go" && Boolean(model.reasoning);
106
107
 
107
108
  const useMaxTokens =
108
109
  provider === "mistral" ||
@@ -194,7 +195,7 @@ export function detectOpenAICompat(model: Model<"openai-completions">, resolvedB
194
195
  supportsReasoningEffort: !isGrok && !isZai,
195
196
  reasoningEffortMap,
196
197
  supportsUsageInStreaming: !isCerebras,
197
- disableReasoningOnForcedToolChoice: isKimiModel || isAnthropicModel,
198
+ disableReasoningOnForcedToolChoice: isKimiModel || isAnthropicModel || isOpenCodeGoReasoning,
198
199
  disableReasoningOnToolChoice: isDeepseekFamily && Boolean(model.reasoning) && !isOpenRouter,
199
200
  supportsToolChoice: !isDirectDeepseekReasoning,
200
201
  supportsForcedToolChoice: true,
@@ -472,6 +472,9 @@ export async function getOAuthApiKey(
472
472
  return { newCredentials: creds, apiKey };
473
473
  }
474
474
 
475
+ export function resolveOAuthStorageProvider(provider: OAuthProviderId): OAuthProviderId {
476
+ return provider === "openai-codex-device" ? "openai-codex" : provider;
477
+ }
475
478
  /**
476
479
  * Get list of OAuth providers.
477
480
  */