@gajae-code/ai 0.4.1 → 0.4.2
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 +6 -0
- package/dist/types/model-thinking.d.ts +3 -1
- package/package.json +2 -2
- package/src/model-thinking.ts +18 -3
- package/src/models.json +6 -7
- package/src/utils/idle-iterator.ts +12 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.4.2] - 2026-06-09
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Treated `gpt-5.5` as a 400K-context model wherever context caps / auto-promote thresholds are resolved, so a ~272K session is no longer considered over-cap and no longer demotes to `gpt-5.4`. Pinned the OpenAI Codex `gpt-5.5` context window to 400K and removed its `gpt-5.4` promotion target (the smaller window made it a demotion) ([#428](https://github.com/Yeachan-Heo/gajae-code/issues/428)).
|
|
10
|
+
|
|
5
11
|
## [0.4.0] - 2026-06-06
|
|
6
12
|
|
|
7
13
|
### Added
|
|
@@ -40,7 +40,9 @@ export declare function applyGeneratedModelPolicies(models: ApiModel<Api>[]): vo
|
|
|
40
40
|
* When a model's context is exhausted, the agent can promote to a sibling
|
|
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`
|
|
45
|
+
* (which has a smaller window), so it has no promotion target.
|
|
44
46
|
*/
|
|
45
47
|
export declare function linkOpenAIPromotionTargets(models: ApiModel<Api>[]): void;
|
|
46
48
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/ai",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.2",
|
|
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.4.
|
|
46
|
+
"@gajae-code/utils": "0.4.2",
|
|
47
47
|
"openai": "^6.36.0",
|
|
48
48
|
"partial-json": "^0.1.7",
|
|
49
49
|
"zod": "4.4.3"
|
package/src/model-thinking.ts
CHANGED
|
@@ -195,7 +195,9 @@ export function applyGeneratedModelPolicies(models: ApiModel<Api>[]): void {
|
|
|
195
195
|
* When a model's context is exhausted, the agent can promote to a sibling
|
|
196
196
|
* model with a larger context window on the same provider:
|
|
197
197
|
* - `OpenAI code backend-spark` variants promote to `gpt-5.5`.
|
|
198
|
-
*
|
|
198
|
+
*
|
|
199
|
+
* `gpt-5.5` itself is a 400K-context model and is not demoted to `gpt-5.4`
|
|
200
|
+
* (which has a smaller window), so it has no promotion target.
|
|
199
201
|
*/
|
|
200
202
|
export function linkOpenAIPromotionTargets(models: ApiModel<Api>[]): void {
|
|
201
203
|
for (const candidate of models) {
|
|
@@ -204,8 +206,6 @@ export function linkOpenAIPromotionTargets(models: ApiModel<Api>[]): void {
|
|
|
204
206
|
let targetId: string | undefined;
|
|
205
207
|
if (parsedCandidate.variant === "codex-spark") {
|
|
206
208
|
targetId = "gpt-5.5";
|
|
207
|
-
} else if (parsedCandidate.variant === "base" && semverEqual(parsedCandidate.version, "5.5")) {
|
|
208
|
-
targetId = "gpt-5.4";
|
|
209
209
|
} else {
|
|
210
210
|
continue;
|
|
211
211
|
}
|
|
@@ -430,7 +430,22 @@ function inferGeneratedApplyPatchToolType(
|
|
|
430
430
|
return undefined;
|
|
431
431
|
}
|
|
432
432
|
|
|
433
|
+
function applyGpt55ContextWindow(model: ApiModel<Api>, parsedModel: OpenAIModel): boolean {
|
|
434
|
+
// gpt-5.5 is a 400K-context model. OpenAI code backend discovery can omit the
|
|
435
|
+
// context window, falling back to the 272K default, which incorrectly trips
|
|
436
|
+
// context-cap / auto-promote thresholds (a ~272K session would look over-cap
|
|
437
|
+
// and demote to gpt-5.4). Pin gpt-5.5 to its true 400K window.
|
|
438
|
+
if (parsedModel.variant === "base" && semverEqual(parsedModel.version, "5.5")) {
|
|
439
|
+
model.contextWindow = 400000;
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
|
|
433
445
|
function applyOpenAICatalogPolicy(model: ApiModel<Api>, parsedModel: OpenAIModel): void {
|
|
446
|
+
if (applyGpt55ContextWindow(model, parsedModel)) {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
434
449
|
// OpenAI code backend models: 400K figure includes output budget; input window is 272K.
|
|
435
450
|
if (parsedModel.variant.startsWith("codex") && parsedModel.variant !== "codex-spark") {
|
|
436
451
|
model.contextWindow = 272000;
|
package/src/models.json
CHANGED
|
@@ -34660,7 +34660,7 @@
|
|
|
34660
34660
|
},
|
|
34661
34661
|
"minimax-m3": {
|
|
34662
34662
|
"id": "minimax-m3",
|
|
34663
|
-
"name": "MiniMax
|
|
34663
|
+
"name": "MiniMax-M3",
|
|
34664
34664
|
"api": "anthropic-messages",
|
|
34665
34665
|
"provider": "minimax",
|
|
34666
34666
|
"baseUrl": "https://api.minimax.io/anthropic",
|
|
@@ -34855,7 +34855,7 @@
|
|
|
34855
34855
|
},
|
|
34856
34856
|
"minimax-m3": {
|
|
34857
34857
|
"id": "minimax-m3",
|
|
34858
|
-
"name": "MiniMax
|
|
34858
|
+
"name": "MiniMax-M3",
|
|
34859
34859
|
"api": "anthropic-messages",
|
|
34860
34860
|
"provider": "minimax-cn",
|
|
34861
34861
|
"baseUrl": "https://api.minimaxi.com/anthropic",
|
|
@@ -35122,7 +35122,7 @@
|
|
|
35122
35122
|
},
|
|
35123
35123
|
"minimax-m3": {
|
|
35124
35124
|
"id": "minimax-m3",
|
|
35125
|
-
"name": "MiniMax
|
|
35125
|
+
"name": "MiniMax-M3",
|
|
35126
35126
|
"api": "openai-completions",
|
|
35127
35127
|
"provider": "minimax-code",
|
|
35128
35128
|
"baseUrl": "https://api.minimax.io/v1",
|
|
@@ -35395,7 +35395,7 @@
|
|
|
35395
35395
|
},
|
|
35396
35396
|
"minimax-m3": {
|
|
35397
35397
|
"id": "minimax-m3",
|
|
35398
|
-
"name": "MiniMax
|
|
35398
|
+
"name": "MiniMax-M3",
|
|
35399
35399
|
"api": "openai-completions",
|
|
35400
35400
|
"provider": "minimax-code-cn",
|
|
35401
35401
|
"baseUrl": "https://api.minimaxi.com/v1",
|
|
@@ -53264,7 +53264,7 @@
|
|
|
53264
53264
|
"cacheRead": 0.5,
|
|
53265
53265
|
"cacheWrite": 0
|
|
53266
53266
|
},
|
|
53267
|
-
"contextWindow":
|
|
53267
|
+
"contextWindow": 400000,
|
|
53268
53268
|
"maxTokens": 128000,
|
|
53269
53269
|
"preferWebsockets": true,
|
|
53270
53270
|
"priority": 9,
|
|
@@ -53274,8 +53274,7 @@
|
|
|
53274
53274
|
"maxLevel": "xhigh",
|
|
53275
53275
|
"defaultLevel": "xhigh"
|
|
53276
53276
|
},
|
|
53277
|
-
"applyPatchToolType": "freeform"
|
|
53278
|
-
"contextPromotionTarget": "openai-codex/gpt-5.4"
|
|
53277
|
+
"applyPatchToolType": "freeform"
|
|
53279
53278
|
}
|
|
53280
53279
|
},
|
|
53281
53280
|
"opencode": {
|
|
@@ -157,10 +157,14 @@ export async function* iterateWithIdleTimeout<T>(
|
|
|
157
157
|
activeTimeoutMs = firstItemTimeoutMs;
|
|
158
158
|
} else if (options.idleTimeoutMs !== undefined && options.idleTimeoutMs > 0) {
|
|
159
159
|
activeTimeoutMs = options.idleTimeoutMs - (Date.now() - lastProgressAt);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
// The idle deadline may already have elapsed because the *consumer*
|
|
161
|
+
// was slow, not because the provider stalled — and the next item may
|
|
162
|
+
// already be buffered and ready to deliver. Clamp to 0 instead of
|
|
163
|
+
// throwing eagerly so the next() race below still gets a chance to
|
|
164
|
+
// win (it settles on a microtask, ahead of the 0ms timer). Only a
|
|
165
|
+
// genuinely hung iterator loses that race and surfaces as a stall.
|
|
166
|
+
if (activeTimeoutMs < 0) {
|
|
167
|
+
activeTimeoutMs = 0;
|
|
164
168
|
}
|
|
165
169
|
}
|
|
166
170
|
|
|
@@ -177,7 +181,10 @@ export async function* iterateWithIdleTimeout<T>(
|
|
|
177
181
|
|
|
178
182
|
let timer: NodeJS.Timeout | undefined;
|
|
179
183
|
let resolveTimeout: ((value: { kind: "timeout" }) => void) | undefined;
|
|
180
|
-
const enforceTimeout =
|
|
184
|
+
const enforceTimeout =
|
|
185
|
+
!noTimeoutEnforced &&
|
|
186
|
+
activeTimeoutMs !== undefined &&
|
|
187
|
+
(awaitingFirstItem ? activeTimeoutMs > 0 : activeTimeoutMs >= 0);
|
|
181
188
|
if (enforceTimeout) {
|
|
182
189
|
const { promise, resolve } = Promise.withResolvers<{ kind: "timeout" }>();
|
|
183
190
|
resolveTimeout = resolve;
|