@gajae-code/ai 0.13.3 → 0.14.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/CHANGELOG.md +45 -2
- package/dist/types/auth-broker/client.d.ts +9 -1
- package/dist/types/auth-broker/redact.d.ts +7 -0
- package/dist/types/auth-broker/remote-store.d.ts +50 -9
- package/dist/types/auth-broker/types.d.ts +14 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +25 -0
- package/dist/types/auth-storage.d.ts +200 -6
- package/dist/types/core.d.ts +1 -0
- package/dist/types/model-cache.d.ts +4 -1
- package/dist/types/model-manager.d.ts +11 -0
- package/dist/types/provider-models/openai-compat.d.ts +5 -0
- package/dist/types/providers/anthropic.d.ts +31 -0
- package/dist/types/providers/cursor.d.ts +9 -1
- package/dist/types/providers/mock.d.ts +7 -1
- package/dist/types/providers/transform-messages.d.ts +18 -0
- package/dist/types/types.d.ts +28 -14
- package/dist/types/usage/grok-cli.d.ts +5 -0
- package/dist/types/usage.d.ts +6 -0
- package/dist/types/utils/discovery/openai-compatible.d.ts +5 -0
- package/dist/types/utils/event-stream.d.ts +4 -2
- package/dist/types/utils/fallback-transport.d.ts +10 -0
- package/dist/types/utils/http-inspector.d.ts +1 -0
- package/dist/types/utils/idle-iterator.d.ts +13 -1
- package/dist/types/utils/oauth/callback-server.d.ts +13 -0
- package/dist/types/utils/parse-bind.d.ts +8 -5
- package/dist/types/utils/tool-call-healing.d.ts +7 -0
- package/dist/types/utils/tool-choice-capability.d.ts +11 -0
- package/package.json +3 -2
- package/src/auth-broker/client.ts +30 -0
- package/src/auth-broker/redact.ts +15 -0
- package/src/auth-broker/refresher.ts +4 -2
- package/src/auth-broker/remote-store.ts +693 -70
- package/src/auth-broker/server.ts +57 -12
- package/src/auth-broker/types.ts +16 -0
- package/src/auth-broker/wire-schemas.ts +21 -0
- package/src/auth-gateway/server.ts +84 -19
- package/src/auth-storage.ts +985 -41
- package/src/core.ts +1 -0
- package/src/model-cache.ts +23 -4
- package/src/model-manager.ts +70 -11
- package/src/model-thinking.ts +21 -1
- package/src/models.json +1733 -392
- package/src/provider-models/descriptors.ts +5 -1
- package/src/provider-models/openai-compat.ts +52 -28
- package/src/providers/amazon-bedrock.ts +2 -1
- package/src/providers/anthropic.ts +824 -29
- package/src/providers/cursor.ts +83 -3
- package/src/providers/mock.ts +13 -3
- package/src/providers/ollama.ts +9 -2
- package/src/providers/openai-codex-responses.ts +16 -9
- package/src/providers/openai-completions.ts +5 -3
- package/src/providers/openai-responses-shared.ts +175 -21
- package/src/providers/register-builtins.ts +5 -2
- package/src/providers/transform-messages.ts +64 -1
- package/src/stream.ts +12 -2
- package/src/types.ts +28 -13
- package/src/usage/grok-cli.ts +86 -1
- package/src/usage.ts +7 -0
- package/src/utils/discovery/openai-compatible.ts +89 -4
- package/src/utils/event-stream.ts +11 -2
- package/src/utils/fallback-transport.ts +44 -2
- package/src/utils/http-inspector.ts +1 -0
- package/src/utils/idle-iterator.ts +29 -6
- package/src/utils/oauth/callback-server.ts +31 -1
- package/src/utils/parse-bind.ts +27 -0
- package/src/utils/tool-call-healing.ts +13 -2
- package/src/utils/tool-choice-capability.ts +386 -6
package/src/core.ts
CHANGED
|
@@ -23,6 +23,7 @@ export {
|
|
|
23
23
|
PROVIDER_RUNTIME_DESCRIPTORS,
|
|
24
24
|
type ProviderRuntimeDescriptor,
|
|
25
25
|
} from "./providers/register-builtins";
|
|
26
|
+
export { hasAdjacentPrivateThinkingBlocks } from "./providers/transform-messages";
|
|
26
27
|
export * from "./rate-limit-utils";
|
|
27
28
|
export * from "./stream";
|
|
28
29
|
export * from "./types";
|
package/src/model-cache.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Database } from "bun:sqlite";
|
|
|
6
6
|
import { getModelDbPath } from "@gajae-code/utils/dirs";
|
|
7
7
|
import type { Api, Model } from "./types";
|
|
8
8
|
|
|
9
|
-
const CACHE_SCHEMA_VERSION =
|
|
9
|
+
const CACHE_SCHEMA_VERSION = 5;
|
|
10
10
|
|
|
11
11
|
interface CacheRow {
|
|
12
12
|
provider_id: string;
|
|
@@ -14,6 +14,8 @@ interface CacheRow {
|
|
|
14
14
|
updated_at: number;
|
|
15
15
|
authoritative: number;
|
|
16
16
|
static_fingerprint: string;
|
|
17
|
+
dynamic_model_ids: string | null;
|
|
18
|
+
dynamic_model_provenance: string | null;
|
|
17
19
|
models: string;
|
|
18
20
|
}
|
|
19
21
|
|
|
@@ -33,6 +35,9 @@ interface CacheEntry<TApi extends Api = Api> {
|
|
|
33
35
|
* match — the cache already incorporates the same static state.
|
|
34
36
|
*/
|
|
35
37
|
staticFingerprint: string;
|
|
38
|
+
/** IDs returned by the authoritative dynamic provider catalog, when retained. */
|
|
39
|
+
dynamicModelIds: string[] | undefined;
|
|
40
|
+
dynamicModelProvenance: string | undefined;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
let sharedDb: Database | null = null;
|
|
@@ -56,6 +61,8 @@ function getDb(dbPath?: string): Database {
|
|
|
56
61
|
updated_at INTEGER NOT NULL,
|
|
57
62
|
authoritative INTEGER NOT NULL DEFAULT 0,
|
|
58
63
|
static_fingerprint TEXT NOT NULL DEFAULT '',
|
|
64
|
+
dynamic_model_ids TEXT,
|
|
65
|
+
dynamic_model_provenance TEXT,
|
|
59
66
|
models TEXT NOT NULL
|
|
60
67
|
)
|
|
61
68
|
`);
|
|
@@ -81,7 +88,13 @@ function migrateCacheSchema(db: Database): void {
|
|
|
81
88
|
if (!columns.some(column => column.name === "static_fingerprint")) {
|
|
82
89
|
db.run("ALTER TABLE model_cache ADD COLUMN static_fingerprint TEXT NOT NULL DEFAULT ''");
|
|
83
90
|
}
|
|
84
|
-
|
|
91
|
+
if (!columns.some(column => column.name === "dynamic_model_ids")) {
|
|
92
|
+
db.run("ALTER TABLE model_cache ADD COLUMN dynamic_model_ids TEXT");
|
|
93
|
+
}
|
|
94
|
+
if (!columns.some(column => column.name === "dynamic_model_provenance")) {
|
|
95
|
+
db.run("ALTER TABLE model_cache ADD COLUMN dynamic_model_provenance TEXT");
|
|
96
|
+
}
|
|
97
|
+
db.run("UPDATE model_cache SET version = ? WHERE version IN (2, 3, 4)", [CACHE_SCHEMA_VERSION]);
|
|
85
98
|
}
|
|
86
99
|
|
|
87
100
|
export function readModelCache<TApi extends Api>(
|
|
@@ -105,6 +118,8 @@ export function readModelCache<TApi extends Api>(
|
|
|
105
118
|
authoritative: row.authoritative === 1,
|
|
106
119
|
updatedAt: row.updated_at,
|
|
107
120
|
staticFingerprint: row.static_fingerprint ?? "",
|
|
121
|
+
dynamicModelIds: row.dynamic_model_ids === null ? undefined : (JSON.parse(row.dynamic_model_ids) as string[]),
|
|
122
|
+
dynamicModelProvenance: row.dynamic_model_provenance ?? undefined,
|
|
108
123
|
};
|
|
109
124
|
} catch {
|
|
110
125
|
return null;
|
|
@@ -118,18 +133,22 @@ export function writeModelCache<TApi extends Api>(
|
|
|
118
133
|
authoritative: boolean,
|
|
119
134
|
staticFingerprint: string,
|
|
120
135
|
dbPath?: string,
|
|
136
|
+
dynamicModelIds?: readonly string[],
|
|
137
|
+
dynamicModelProvenance?: string,
|
|
121
138
|
): void {
|
|
122
139
|
try {
|
|
123
140
|
const db = getDb(dbPath);
|
|
124
141
|
db.run(
|
|
125
|
-
`INSERT OR REPLACE INTO model_cache (provider_id, version, updated_at, authoritative, static_fingerprint, models)
|
|
126
|
-
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
142
|
+
`INSERT OR REPLACE INTO model_cache (provider_id, version, updated_at, authoritative, static_fingerprint, dynamic_model_ids, dynamic_model_provenance, models)
|
|
143
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
127
144
|
[
|
|
128
145
|
providerId,
|
|
129
146
|
CACHE_SCHEMA_VERSION,
|
|
130
147
|
updatedAt,
|
|
131
148
|
authoritative ? 1 : 0,
|
|
132
149
|
staticFingerprint,
|
|
150
|
+
dynamicModelIds === undefined ? null : JSON.stringify(dynamicModelIds),
|
|
151
|
+
dynamicModelProvenance ?? null,
|
|
133
152
|
JSON.stringify(models),
|
|
134
153
|
],
|
|
135
154
|
);
|
package/src/model-manager.ts
CHANGED
|
@@ -43,6 +43,8 @@ export interface ModelManagerOptions<TApi extends Api = Api, TModelsDevPayload =
|
|
|
43
43
|
now?: () => number;
|
|
44
44
|
/** Optional guard that must permit cache publication. Default: writes are permitted. */
|
|
45
45
|
canPublishCache?: () => boolean;
|
|
46
|
+
/** Credential-and-endpoint identity required to reuse dynamic catalog IDs. */
|
|
47
|
+
cacheDynamicModelProvenance?: string;
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
/**
|
|
@@ -56,8 +58,17 @@ export interface ModelManagerOptions<TApi extends Api = Api, TModelsDevPayload =
|
|
|
56
58
|
export interface ModelResolutionResult<TApi extends Api = Api> {
|
|
57
59
|
models: Model<TApi>[];
|
|
58
60
|
stale: boolean;
|
|
61
|
+
/** Whether the cache row consulted for this resolution was still within its TTL. */
|
|
62
|
+
cacheFresh: boolean;
|
|
63
|
+
/** Whether the consulted cache row was authoritative. */
|
|
64
|
+
cacheAuthoritative: boolean;
|
|
59
65
|
/** Whether this resolution successfully fetched dynamic models. */
|
|
60
66
|
fetched: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* IDs returned by a current authoritative dynamic provider catalog. This is
|
|
69
|
+
* deliberately distinct from `models`, which merges static and cached data.
|
|
70
|
+
*/
|
|
71
|
+
dynamicModelIds?: readonly string[];
|
|
61
72
|
}
|
|
62
73
|
|
|
63
74
|
/**
|
|
@@ -125,14 +136,19 @@ export async function resolveProviderModels<TApi extends Api = Api, TModelsDevPa
|
|
|
125
136
|
const cache = readModelCache<TApi>(options.providerId, ttlMs, now, dbPath);
|
|
126
137
|
const dynamicFetcher = options.fetchDynamicModels;
|
|
127
138
|
const hasDynamicFetcher = typeof dynamicFetcher === "function";
|
|
128
|
-
const
|
|
139
|
+
const cacheDynamicModelIdsCurrent =
|
|
140
|
+
cache?.dynamicModelIds !== undefined &&
|
|
141
|
+
cache.dynamicModelProvenance !== undefined &&
|
|
142
|
+
cache.dynamicModelProvenance === options.cacheDynamicModelProvenance;
|
|
143
|
+
const cacheProvenanceMismatch = cache?.dynamicModelIds !== undefined && !cacheDynamicModelIdsCurrent;
|
|
144
|
+
const hasAuthoritativeCache =
|
|
145
|
+
!hasDynamicFetcher ||
|
|
146
|
+
((cache?.authoritative ?? false) && (cache?.dynamicModelIds === undefined || cacheDynamicModelIdsCurrent));
|
|
129
147
|
const cacheAgeMs = cache ? now() - cache.updatedAt : Number.POSITIVE_INFINITY;
|
|
130
|
-
const shouldFetchFromNetwork =
|
|
131
|
-
strategy
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
cacheAgeMs,
|
|
135
|
-
);
|
|
148
|
+
const shouldFetchFromNetwork =
|
|
149
|
+
cacheProvenanceMismatch && strategy !== "offline"
|
|
150
|
+
? true
|
|
151
|
+
: shouldFetchRemoteSources(strategy, cache?.fresh ?? false, hasAuthoritativeCache, cacheAgeMs);
|
|
136
152
|
const staticFingerprint = fingerprintStatic(staticModels);
|
|
137
153
|
|
|
138
154
|
// Cold-start fast path: when a fresh, authoritative cache exists, the network
|
|
@@ -149,13 +165,38 @@ export async function resolveProviderModels<TApi extends Api = Api, TModelsDevPa
|
|
|
149
165
|
) {
|
|
150
166
|
const cachedModels = passModelList<TApi>(cache.models);
|
|
151
167
|
if (!hasStaticTransportDrift(staticModels, cachedModels)) {
|
|
152
|
-
return {
|
|
168
|
+
return {
|
|
169
|
+
models: cachedModels,
|
|
170
|
+
stale: false,
|
|
171
|
+
cacheFresh: true,
|
|
172
|
+
cacheAuthoritative: true,
|
|
173
|
+
fetched: false,
|
|
174
|
+
dynamicModelIds:
|
|
175
|
+
strategy === "online-if-uncached" && cacheDynamicModelIdsCurrent ? cache.dynamicModelIds : undefined,
|
|
176
|
+
};
|
|
153
177
|
}
|
|
154
178
|
const repairedModels = mergeDynamicModels(staticModels, cachedModels);
|
|
155
179
|
if (options.canPublishCache?.() ?? true) {
|
|
156
|
-
writeModelCache(
|
|
180
|
+
writeModelCache(
|
|
181
|
+
options.providerId,
|
|
182
|
+
now(),
|
|
183
|
+
repairedModels,
|
|
184
|
+
true,
|
|
185
|
+
staticFingerprint,
|
|
186
|
+
dbPath,
|
|
187
|
+
cache.dynamicModelIds,
|
|
188
|
+
cache.dynamicModelProvenance,
|
|
189
|
+
);
|
|
157
190
|
}
|
|
158
|
-
return {
|
|
191
|
+
return {
|
|
192
|
+
models: repairedModels,
|
|
193
|
+
stale: false,
|
|
194
|
+
cacheFresh: true,
|
|
195
|
+
cacheAuthoritative: true,
|
|
196
|
+
fetched: false,
|
|
197
|
+
dynamicModelIds:
|
|
198
|
+
strategy === "online-if-uncached" && cacheDynamicModelIdsCurrent ? cache.dynamicModelIds : undefined,
|
|
199
|
+
};
|
|
159
200
|
}
|
|
160
201
|
|
|
161
202
|
const [fetchedModelsDevModels, fetchedDynamicModels] = shouldFetchFromNetwork
|
|
@@ -176,7 +217,16 @@ export async function resolveProviderModels<TApi extends Api = Api, TModelsDevPa
|
|
|
176
217
|
mergeDynamicModels(mergeModelSources(staticModels, modelsDevModels), dynamicModels),
|
|
177
218
|
);
|
|
178
219
|
if (options.canPublishCache?.() ?? true) {
|
|
179
|
-
writeModelCache(
|
|
220
|
+
writeModelCache(
|
|
221
|
+
options.providerId,
|
|
222
|
+
now(),
|
|
223
|
+
snapshotModels,
|
|
224
|
+
true,
|
|
225
|
+
staticFingerprint,
|
|
226
|
+
dbPath,
|
|
227
|
+
dynamicModels.map(model => model.id),
|
|
228
|
+
options.cacheDynamicModelProvenance,
|
|
229
|
+
);
|
|
180
230
|
}
|
|
181
231
|
} else {
|
|
182
232
|
// Dynamic fetch failed — update cache with a non-authoritative snapshot so
|
|
@@ -202,7 +252,16 @@ export async function resolveProviderModels<TApi extends Api = Api, TModelsDevPa
|
|
|
202
252
|
return {
|
|
203
253
|
models,
|
|
204
254
|
stale: !dynamicAuthoritative,
|
|
255
|
+
cacheFresh: cache?.fresh ?? false,
|
|
256
|
+
cacheAuthoritative: cache?.authoritative ?? false,
|
|
205
257
|
fetched: shouldFetchFromNetwork && dynamicFetchSucceeded,
|
|
258
|
+
dynamicModelIds: dynamicFetchSucceeded
|
|
259
|
+
? dynamicModels.map(model => model.id)
|
|
260
|
+
: shouldUseFreshCacheAsAuthoritative
|
|
261
|
+
? cacheDynamicModelIdsCurrent
|
|
262
|
+
? cache?.dynamicModelIds
|
|
263
|
+
: undefined
|
|
264
|
+
: undefined,
|
|
206
265
|
};
|
|
207
266
|
}
|
|
208
267
|
|
package/src/model-thinking.ts
CHANGED
|
@@ -53,6 +53,9 @@ const DEFAULT_REASONING_EFFORTS_WITH_XHIGH_AND_MAX: readonly Effort[] = [
|
|
|
53
53
|
];
|
|
54
54
|
const GEMINI_3_PRO_EFFORTS: readonly Effort[] = [Effort.Low, Effort.High];
|
|
55
55
|
const GEMINI_3_FLASH_EFFORTS: readonly Effort[] = [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High];
|
|
56
|
+
// Gemini 3.7 Flash dropped `minimal`; the official API returns an error for it.
|
|
57
|
+
// https://ai.google.dev/gemini-api/docs/models/gemini-3.7-flash
|
|
58
|
+
const GEMINI_3_7_FLASH_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High];
|
|
56
59
|
const GPT_5_2_PLUS_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High, Effort.XHigh];
|
|
57
60
|
const GPT_5_6_PLUS_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High, Effort.XHigh, Effort.Max];
|
|
58
61
|
const GPT_5_5_DEFAULT_EFFORT = Effort.XHigh;
|
|
@@ -468,6 +471,17 @@ function applyGeneratedModelPolicy(model: ApiModel<Api>): void {
|
|
|
468
471
|
if (model.provider === "zai" && model.id === "glm-5.2") {
|
|
469
472
|
model.contextWindow = 1_000_000;
|
|
470
473
|
}
|
|
474
|
+
// GLM-5.3 always thinks and exposes only low/high/max reasoning_effort.
|
|
475
|
+
// https://z.ai/blog/glm-5.3#api-changes-in-glm-5-3
|
|
476
|
+
if (model.provider === "zai" && model.id === "glm-5.3") {
|
|
477
|
+
model.thinking = {
|
|
478
|
+
mode: "effort",
|
|
479
|
+
minLevel: Effort.Low,
|
|
480
|
+
maxLevel: Effort.Max,
|
|
481
|
+
defaultLevel: Effort.Max,
|
|
482
|
+
levels: [Effort.Low, Effort.High, Effort.Max],
|
|
483
|
+
};
|
|
484
|
+
}
|
|
471
485
|
if (model.provider === "alibaba-token-plan" && model.id === "deepseek-v4-flash-0731") {
|
|
472
486
|
model.contextWindow = 1_000_000;
|
|
473
487
|
model.maxTokens = 384_000;
|
|
@@ -716,7 +730,13 @@ function inferGeminiSupportedEfforts(model: GeminiModel): readonly Effort[] {
|
|
|
716
730
|
if (!semverGte(model.version, "3.0")) {
|
|
717
731
|
return DEFAULT_REASONING_EFFORTS;
|
|
718
732
|
}
|
|
719
|
-
|
|
733
|
+
if (model.kind === "pro") {
|
|
734
|
+
return GEMINI_3_PRO_EFFORTS;
|
|
735
|
+
}
|
|
736
|
+
if (semverGte(model.version, "3.7")) {
|
|
737
|
+
return GEMINI_3_7_FLASH_EFFORTS;
|
|
738
|
+
}
|
|
739
|
+
return GEMINI_3_FLASH_EFFORTS;
|
|
720
740
|
}
|
|
721
741
|
|
|
722
742
|
function inferAnthropicSupportedEfforts<TApi extends Api>(
|