cascade-ai 0.70.0 → 0.71.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/dist/cli.cjs +205 -340
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +205 -340
- package/dist/cli.js.map +1 -1
- package/dist/desktop-core.cjs +164 -294
- package/dist/index.cjs +164 -294
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -15
- package/dist/index.d.ts +45 -15
- package/dist/index.js +164 -292
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/desktop-core.cjs
CHANGED
|
@@ -291781,7 +291781,7 @@ function reconcilePrice(model, live) {
|
|
|
291781
291781
|
}
|
|
291782
291782
|
|
|
291783
291783
|
// src/constants.ts
|
|
291784
|
-
var CASCADE_VERSION = "0.
|
|
291784
|
+
var CASCADE_VERSION = "0.71.0";
|
|
291785
291785
|
var CASCADE_CONFIG_DIR = ".cascade";
|
|
291786
291786
|
var CASCADE_MD_FILE = "CASCADE.md";
|
|
291787
291787
|
var CASCADE_IGNORE_FILE = ".cascadeignore";
|
|
@@ -292188,9 +292188,6 @@ var DEFAULT_THEME = "cascade";
|
|
|
292188
292188
|
var OLLAMA_BASE_URL = "http://localhost:11434";
|
|
292189
292189
|
var LM_STUDIO_BASE_URL = "http://localhost:1234";
|
|
292190
292190
|
var AZURE_BASE_URL_TEMPLATE = "https://{resource}.openai.azure.com";
|
|
292191
|
-
var GITHUB_MODELS_INFERENCE_URL = "https://models.github.ai/inference";
|
|
292192
|
-
var GITHUB_MODELS_CATALOG_URL = "https://models.github.ai/catalog/models";
|
|
292193
|
-
var GITHUB_MODELS_API_VERSION = "2026-03-10";
|
|
292194
292191
|
var TOOL_NAMES = {
|
|
292195
292192
|
SHELL: "shell",
|
|
292196
292193
|
FILE_READ: "file_read",
|
|
@@ -292225,8 +292222,7 @@ var PROVIDER_DISPLAY_NAMES = {
|
|
|
292225
292222
|
gemini: "Google Gemini",
|
|
292226
292223
|
azure: "Azure OpenAI",
|
|
292227
292224
|
"openai-compatible": "OpenAI-Compatible",
|
|
292228
|
-
ollama: "Ollama (Local)"
|
|
292229
|
-
"github-models": "GitHub Models"
|
|
292225
|
+
ollama: "Ollama (Local)"
|
|
292230
292226
|
};
|
|
292231
292227
|
|
|
292232
292228
|
// src/utils/cost.ts
|
|
@@ -319170,206 +319166,6 @@ async function nodeHttpFetch(input, init2 = {}, redirectCount = 0, opts = {}) {
|
|
|
319170
319166
|
});
|
|
319171
319167
|
}
|
|
319172
319168
|
|
|
319173
|
-
// src/providers/github-models.ts
|
|
319174
|
-
var GITHUB_MODELS_MAX_OUTPUT_TOKENS = 4e3;
|
|
319175
|
-
var GITHUB_MODELS_MAX_INPUT_TOKENS = 8e3;
|
|
319176
|
-
var DEFAULT_CONTEXT_WINDOW = 128e3;
|
|
319177
|
-
var GITHUB_MODELS_MAX_CATALOG_PAGES = 20;
|
|
319178
|
-
var GITHUB_MODELS_CATALOG_ORIGIN = new URL(GITHUB_MODELS_CATALOG_URL).origin;
|
|
319179
|
-
function stripModelOwnerPrefix(id) {
|
|
319180
|
-
const slash = (id || "").indexOf("/");
|
|
319181
|
-
return slash === -1 ? id : id.slice(slash + 1);
|
|
319182
|
-
}
|
|
319183
|
-
function pickString(o3, keys2) {
|
|
319184
|
-
for (const k4 of keys2) {
|
|
319185
|
-
const v6 = o3[k4];
|
|
319186
|
-
if (typeof v6 === "string" && v6.length > 0) return v6;
|
|
319187
|
-
}
|
|
319188
|
-
return void 0;
|
|
319189
|
-
}
|
|
319190
|
-
function pickNumber(o3, keys2) {
|
|
319191
|
-
for (const k4 of keys2) {
|
|
319192
|
-
const v6 = k4.includes(".") ? o3[k4.split(".")[0]]?.[k4.split(".")[1]] : o3[k4];
|
|
319193
|
-
if (typeof v6 === "number" && Number.isFinite(v6) && v6 > 0) return v6;
|
|
319194
|
-
}
|
|
319195
|
-
return void 0;
|
|
319196
|
-
}
|
|
319197
|
-
function looksVisionCapable(o3) {
|
|
319198
|
-
for (const k4 of ["supported_input_modalities", "input_modalities", "modalities", "capabilities"]) {
|
|
319199
|
-
const v6 = o3[k4];
|
|
319200
|
-
if (Array.isArray(v6) && v6.some((x5) => typeof x5 === "string" && /image|vision/i.test(x5))) return true;
|
|
319201
|
-
}
|
|
319202
|
-
return false;
|
|
319203
|
-
}
|
|
319204
|
-
function looksToolCapable(o3) {
|
|
319205
|
-
const params = o3["supported_parameters"];
|
|
319206
|
-
if (Array.isArray(params) && params.some((x5) => typeof x5 === "string" && /^tools?$|function.?call/i.test(x5))) {
|
|
319207
|
-
return true;
|
|
319208
|
-
}
|
|
319209
|
-
for (const k4 of ["capabilities", "supported_output_modalities"]) {
|
|
319210
|
-
const v6 = o3[k4];
|
|
319211
|
-
if (Array.isArray(v6) && v6.some((x5) => typeof x5 === "string" && /tool|function.?call/i.test(x5))) return true;
|
|
319212
|
-
}
|
|
319213
|
-
const caps = o3["capabilities"];
|
|
319214
|
-
if (caps && typeof caps === "object" && !Array.isArray(caps)) {
|
|
319215
|
-
const c4 = caps;
|
|
319216
|
-
if (c4["function_calling"] === true || c4["tool_calling"] === true || c4["tools"] === true) return true;
|
|
319217
|
-
}
|
|
319218
|
-
return false;
|
|
319219
|
-
}
|
|
319220
|
-
function parseNextLink(linkHeader) {
|
|
319221
|
-
if (!linkHeader) return null;
|
|
319222
|
-
for (const part of linkHeader.split(",")) {
|
|
319223
|
-
const match = part.match(/<([^>]+)>\s*;\s*rel="next"/);
|
|
319224
|
-
if (match) return match[1];
|
|
319225
|
-
}
|
|
319226
|
-
return null;
|
|
319227
|
-
}
|
|
319228
|
-
var GitHubModelsProvider = class extends OpenAIProvider {
|
|
319229
|
-
constructor(config2, model) {
|
|
319230
|
-
super({ ...config2, apiKey: config2.apiKey ?? "" }, model);
|
|
319231
|
-
this.useMaxCompletionTokens = isReasoningModel(stripModelOwnerPrefix(model.id));
|
|
319232
|
-
this.client = new openai_default({
|
|
319233
|
-
apiKey: config2.apiKey ?? "",
|
|
319234
|
-
baseURL: GITHUB_MODELS_INFERENCE_URL,
|
|
319235
|
-
defaultHeaders: { "X-GitHub-Api-Version": GITHUB_MODELS_API_VERSION, "User-Agent": "Cascade-AI" }
|
|
319236
|
-
});
|
|
319237
|
-
}
|
|
319238
|
-
/**
|
|
319239
|
-
* `OpenAIProvider.generateStream()` builds its request budget as
|
|
319240
|
-
* `options.maxTokens ?? this.model.maxOutputTokens` — an explicit per-call
|
|
319241
|
-
* `maxTokens` (T1Administrator's final compilation asks for 8,000, well
|
|
319242
|
-
* above GitHub's real ~4K hard cap) wins outright and is sent unclamped.
|
|
319243
|
-
* GitHub then rejects the request instead of answering, so a run routed to
|
|
319244
|
-
* this provider for that step fails outright rather than getting a
|
|
319245
|
-
* (perfectly serviceable, just shorter) completion. Clamp here, once, right
|
|
319246
|
-
* before delegating to the inherited implementation, rather than teaching
|
|
319247
|
-
* every caller GitHub's specific cap.
|
|
319248
|
-
*/
|
|
319249
|
-
async generateStream(options, onChunk) {
|
|
319250
|
-
const clamped = options.maxTokens !== void 0 && options.maxTokens > GITHUB_MODELS_MAX_OUTPUT_TOKENS ? { ...options, maxTokens: GITHUB_MODELS_MAX_OUTPUT_TOKENS } : options;
|
|
319251
|
-
return super.generateStream(clamped, onChunk);
|
|
319252
|
-
}
|
|
319253
|
-
/**
|
|
319254
|
-
* The catalog is a GitHub REST resource, not an OpenAI `/models` list, and
|
|
319255
|
-
* wants GitHub's own header trio — the plain `Accept: application/json` the
|
|
319256
|
-
* openai-compatible provider sends is not the same request.
|
|
319257
|
-
*/
|
|
319258
|
-
catalogHeaders() {
|
|
319259
|
-
return {
|
|
319260
|
-
Accept: "application/vnd.github+json",
|
|
319261
|
-
Authorization: `Bearer ${this.config.apiKey ?? ""}`,
|
|
319262
|
-
"X-GitHub-Api-Version": GITHUB_MODELS_API_VERSION,
|
|
319263
|
-
// GitHub's REST API rejects any request with no User-Agent — a plain 403
|
|
319264
|
-
// regardless of how valid the PAT is. nodeHttpFetch is a thin wrapper
|
|
319265
|
-
// over node:http/https, neither of which sets one the way a browser's
|
|
319266
|
-
// fetch or a full HTTP client library would, so this has to be explicit.
|
|
319267
|
-
"User-Agent": "Cascade-AI"
|
|
319268
|
-
};
|
|
319269
|
-
}
|
|
319270
|
-
async listModels() {
|
|
319271
|
-
const raw = [];
|
|
319272
|
-
let url2 = GITHUB_MODELS_CATALOG_URL;
|
|
319273
|
-
let pages = 0;
|
|
319274
|
-
const visited = /* @__PURE__ */ new Set();
|
|
319275
|
-
while (url2 && pages < GITHUB_MODELS_MAX_CATALOG_PAGES) {
|
|
319276
|
-
if (visited.has(url2)) break;
|
|
319277
|
-
visited.add(url2);
|
|
319278
|
-
const res = await nodeHttpFetch(url2, { headers: this.catalogHeaders() }, 0, {
|
|
319279
|
-
allowedRedirectOrigin: GITHUB_MODELS_CATALOG_ORIGIN
|
|
319280
|
-
});
|
|
319281
|
-
if (!res.ok) throw new Error(`GitHub Models catalog ${url2} returned HTTP ${res.status}`);
|
|
319282
|
-
const body = await res.json();
|
|
319283
|
-
const pageItems = Array.isArray(body) ? body : Array.isArray(body?.models) ? body.models : Array.isArray(body?.data) ? body.data : [];
|
|
319284
|
-
raw.push(...pageItems);
|
|
319285
|
-
const next = parseNextLink(res.headers.get("link"));
|
|
319286
|
-
if (next) {
|
|
319287
|
-
const resolved = new URL(next, url2);
|
|
319288
|
-
if (resolved.origin !== GITHUB_MODELS_CATALOG_ORIGIN) {
|
|
319289
|
-
throw new Error(`Refusing cross-origin GitHub Models pagination URL: ${resolved.origin}`);
|
|
319290
|
-
}
|
|
319291
|
-
url2 = resolved.href;
|
|
319292
|
-
} else {
|
|
319293
|
-
url2 = null;
|
|
319294
|
-
}
|
|
319295
|
-
pages++;
|
|
319296
|
-
}
|
|
319297
|
-
const entries = raw.map((m3) => {
|
|
319298
|
-
if (typeof m3 === "string") {
|
|
319299
|
-
return { id: m3, name: m3, contextWindow: DEFAULT_CONTEXT_WINDOW, vision: false, tools: false };
|
|
319300
|
-
}
|
|
319301
|
-
if (!m3 || typeof m3 !== "object") return void 0;
|
|
319302
|
-
const o3 = m3;
|
|
319303
|
-
const id = pickString(o3, ["id", "name", "model"]);
|
|
319304
|
-
if (!id) return void 0;
|
|
319305
|
-
return {
|
|
319306
|
-
id,
|
|
319307
|
-
name: pickString(o3, ["friendly_name", "display_name", "name"]) ?? id,
|
|
319308
|
-
contextWindow: pickNumber(o3, [
|
|
319309
|
-
"context_window",
|
|
319310
|
-
"context_length",
|
|
319311
|
-
"max_input_tokens",
|
|
319312
|
-
"limits.max_input_tokens",
|
|
319313
|
-
"limits.max_context_tokens"
|
|
319314
|
-
]) ?? DEFAULT_CONTEXT_WINDOW,
|
|
319315
|
-
vision: looksVisionCapable(o3),
|
|
319316
|
-
tools: looksToolCapable(o3)
|
|
319317
|
-
};
|
|
319318
|
-
}).filter((e3) => e3 !== void 0);
|
|
319319
|
-
if (entries.length === 0) return [];
|
|
319320
|
-
const chat = entries.filter((e3) => isChatModel(e3.id));
|
|
319321
|
-
return (chat.length ? chat : entries).map((e3) => ({
|
|
319322
|
-
id: e3.id,
|
|
319323
|
-
// full `owner/model` — what the API is addressed by
|
|
319324
|
-
name: e3.name,
|
|
319325
|
-
provider: "github-models",
|
|
319326
|
-
// GitHub's real per-request input cap, not the base model's larger one
|
|
319327
|
-
// (see GITHUB_MODELS_MAX_INPUT_TOKENS above) — the same reasoning
|
|
319328
|
-
// already applied to maxOutputTokens below, for the input side.
|
|
319329
|
-
contextWindow: Math.min(e3.contextWindow, GITHUB_MODELS_MAX_INPUT_TOKENS),
|
|
319330
|
-
isVisionCapable: e3.vision,
|
|
319331
|
-
// A REAL $0, not a missing number — usage is bundled into the quota of
|
|
319332
|
-
// the plan the PAT belongs to and is never billed per token, so
|
|
319333
|
-
// `pricingUnknown: false` is the honest value (see the flag's contract in
|
|
319334
|
-
// core/router/pricing.ts: 0 alone is ambiguous). Set here rather than in
|
|
319335
|
-
// pricing-data.json because resolvePricing() matches exactly on
|
|
319336
|
-
// provider|model|region with no wildcard: every catalog model would need
|
|
319337
|
-
// a hand-curated row, and the next one GitHub adds would read as "cost
|
|
319338
|
-
// unknown" — an inconsistent picture for a billing reality that is
|
|
319339
|
-
// identical across the entire catalog.
|
|
319340
|
-
//
|
|
319341
|
-
// `isLocal` is the OTHER way to reach a real $0, and it is the wrong one:
|
|
319342
|
-
// it means "runs on this machine" and carries consequences that are
|
|
319343
|
-
// simply false for a hosted API — the shared concurrency-1
|
|
319344
|
-
// LocalRequestQueue (serialising these calls behind actual Ollama GPU
|
|
319345
|
-
// inference), the 300s local rather than 120s cloud inference timeout,
|
|
319346
|
-
// and a literal "[local]" tag in `cascade models`.
|
|
319347
|
-
inputCostPer1kTokens: 0,
|
|
319348
|
-
outputCostPer1kTokens: 0,
|
|
319349
|
-
pricingUnknown: false,
|
|
319350
|
-
maxOutputTokens: GITHUB_MODELS_MAX_OUTPUT_TOKENS,
|
|
319351
|
-
supportsStreaming: true,
|
|
319352
|
-
// Not every catalog model supports function/tool calling — a hardcoded
|
|
319353
|
-
// `true` sent `tools` to models that reject the parameter outright and
|
|
319354
|
-
// never engaged t3-worker.ts's existing text-tool fallback (only an
|
|
319355
|
-
// explicit `false` does). See looksToolCapable's own comment for why
|
|
319356
|
-
// "not positively advertised" defaults to false rather than true here.
|
|
319357
|
-
supportsToolUse: e3.tools,
|
|
319358
|
-
isLocal: false
|
|
319359
|
-
}));
|
|
319360
|
-
}
|
|
319361
|
-
async isAvailable() {
|
|
319362
|
-
try {
|
|
319363
|
-
const res = await nodeHttpFetch(GITHUB_MODELS_CATALOG_URL, { headers: this.catalogHeaders() }, 0, {
|
|
319364
|
-
allowedRedirectOrigin: GITHUB_MODELS_CATALOG_ORIGIN
|
|
319365
|
-
});
|
|
319366
|
-
return res.ok;
|
|
319367
|
-
} catch {
|
|
319368
|
-
return false;
|
|
319369
|
-
}
|
|
319370
|
-
}
|
|
319371
|
-
};
|
|
319372
|
-
|
|
319373
319169
|
// src/providers/ollama.ts
|
|
319374
319170
|
var TOOL_CAPABLE_FAMILIES = [
|
|
319375
319171
|
"llama3.1",
|
|
@@ -319880,7 +319676,7 @@ var ModelSelector = class {
|
|
|
319880
319676
|
if (overrideModelId.includes(":")) {
|
|
319881
319677
|
const parts = overrideModelId.split(":");
|
|
319882
319678
|
const prefix = parts[0].toLowerCase();
|
|
319883
|
-
const validProviders = ["anthropic", "openai", "gemini", "azure", "openai-compatible", "ollama"
|
|
319679
|
+
const validProviders = ["anthropic", "openai", "gemini", "azure", "openai-compatible", "ollama"];
|
|
319884
319680
|
if (validProviders.includes(prefix)) {
|
|
319885
319681
|
providerStr = prefix;
|
|
319886
319682
|
actualId = parts.slice(1).join(":");
|
|
@@ -319900,31 +319696,6 @@ var ModelSelector = class {
|
|
|
319900
319696
|
else if (this.availableProviders.has("openai-compatible")) providerStr = "openai-compatible";
|
|
319901
319697
|
else if (this.availableProviders.size === 1) providerStr = Array.from(this.availableProviders)[0];
|
|
319902
319698
|
}
|
|
319903
|
-
if (providerStr === "github-models" && this.availableProviders.has("github-models")) {
|
|
319904
|
-
const dynamicModel = {
|
|
319905
|
-
id: actualId,
|
|
319906
|
-
name: actualId,
|
|
319907
|
-
provider: "github-models",
|
|
319908
|
-
contextWindow: GITHUB_MODELS_MAX_INPUT_TOKENS,
|
|
319909
|
-
isVisionCapable: false,
|
|
319910
|
-
inputCostPer1kTokens: 0,
|
|
319911
|
-
outputCostPer1kTokens: 0,
|
|
319912
|
-
pricingUnknown: false,
|
|
319913
|
-
maxOutputTokens: GITHUB_MODELS_MAX_OUTPUT_TOKENS,
|
|
319914
|
-
supportsStreaming: true,
|
|
319915
|
-
// Unconfirmed (no live catalog entry to read a real capability from)
|
|
319916
|
-
// must default to false, not left undefined: t3-worker.ts's text-tool
|
|
319917
|
-
// fallback only engages on a strict `=== false`, so an undefined
|
|
319918
|
-
// value here sends native `tools` to an unverified multi-vendor
|
|
319919
|
-
// model and any that don't support function calling reject the
|
|
319920
|
-
// request outright. Same default-to-false-when-unconfirmed policy
|
|
319921
|
-
// listModels() already applies for a real catalog entry.
|
|
319922
|
-
supportsToolUse: false,
|
|
319923
|
-
isLocal: false
|
|
319924
|
-
};
|
|
319925
|
-
this.addDynamicModel(dynamicModel);
|
|
319926
|
-
return dynamicModel;
|
|
319927
|
-
}
|
|
319928
319699
|
if (providerStr && this.availableProviders.has(providerStr)) {
|
|
319929
319700
|
const dynamicModel = withResolvedPricing({
|
|
319930
319701
|
id: actualId,
|
|
@@ -320017,20 +319788,7 @@ var DEFAULT_PROVIDER_TPM = {
|
|
|
320017
319788
|
gemini: 6e4,
|
|
320018
319789
|
azure: 3e4,
|
|
320019
319790
|
"openai-compatible": 3e4,
|
|
320020
|
-
ollama: Number.POSITIVE_INFINITY
|
|
320021
|
-
// An order of magnitude below the others, on purpose. GitHub Models is
|
|
320022
|
-
// rate-limited by REQUESTS (Free ≈10 RPM, Pro ≈20, plus low daily caps), and
|
|
320023
|
-
// this bucket meters TOKENS — there is no request-count limiter in this
|
|
320024
|
-
// codebase, and building one is not in scope. The approximation works because
|
|
320025
|
-
// the router reserves `model.maxOutputTokens + 512` per call, and the
|
|
320026
|
-
// provider reports GitHub's real ~4K per-request cap rather than the
|
|
320027
|
-
// underlying model's larger one — so every call withdraws a near-constant
|
|
320028
|
-
// ~4.5K regardless of how short the reply actually turns out to be. At 8K/min
|
|
320029
|
-
// that lands around 1–2 calls per minute of headroom: comfortably inside even
|
|
320030
|
-
// the Free tier, with room for the daily cap to matter more than this does.
|
|
320031
|
-
// Users on a higher tier can raise it with no code change through the generic
|
|
320032
|
-
// `config.rateLimits.providerTpm['github-models']` override.
|
|
320033
|
-
"github-models": 8e3
|
|
319791
|
+
ollama: Number.POSITIVE_INFINITY
|
|
320034
319792
|
};
|
|
320035
319793
|
var TpmLimiter = class {
|
|
320036
319794
|
buckets = /* @__PURE__ */ new Map();
|
|
@@ -320386,7 +320144,6 @@ var ModelProfiler = class {
|
|
|
320386
320144
|
(m3) => !alreadyProfiled.has(m3.id) && !SKIP_PATTERN.test(m3.id) && !SKIP_PATTERN.test(m3.name)
|
|
320387
320145
|
);
|
|
320388
320146
|
if (toProfile.length === 0) return;
|
|
320389
|
-
const probesHitGithubModels = this.router?.getModelForTier("T3")?.provider === "github-models";
|
|
320390
320147
|
const openRouterModels = await fetchOpenRouterModels();
|
|
320391
320148
|
const orByNormalizedId = /* @__PURE__ */ new Map();
|
|
320392
320149
|
for (const m3 of openRouterModels) {
|
|
@@ -320401,7 +320158,7 @@ var ModelProfiler = class {
|
|
|
320401
320158
|
if (orMatch?.description) {
|
|
320402
320159
|
specializations = extractSpecializations(orMatch.description);
|
|
320403
320160
|
}
|
|
320404
|
-
if (specializations.length === 0 && this.router
|
|
320161
|
+
if (specializations.length === 0 && this.router) {
|
|
320405
320162
|
specializations = await queryModelDirectly(this.router);
|
|
320406
320163
|
}
|
|
320407
320164
|
this.store.saveModelProfile(model.id, model.provider, specializations);
|
|
@@ -320621,7 +320378,6 @@ var LiveDataProvider = class {
|
|
|
320621
320378
|
*/
|
|
320622
320379
|
applyLivePricing(models) {
|
|
320623
320380
|
return models.map((m3) => {
|
|
320624
|
-
if (m3.provider === "github-models") return m3;
|
|
320625
320381
|
const p3 = this.getLivePrice(m3.baseModelId ?? m3.id);
|
|
320626
320382
|
if (!p3) return m3;
|
|
320627
320383
|
const reconciled = reconcilePrice(m3, p3);
|
|
@@ -320660,7 +320416,6 @@ var LiveDataProvider = class {
|
|
|
320660
320416
|
*/
|
|
320661
320417
|
applyLiveCapabilities(models) {
|
|
320662
320418
|
return models.map((m3) => {
|
|
320663
|
-
if (m3.provider === "github-models") return m3;
|
|
320664
320419
|
const c4 = this.getCapability(m3.baseModelId ?? m3.id);
|
|
320665
320420
|
if (!c4) return m3;
|
|
320666
320421
|
const next = { ...m3 };
|
|
@@ -320964,16 +320719,13 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
|
|
|
320964
320719
|
for (const model of azureDeployments) this.selector.addDynamicModel(model);
|
|
320965
320720
|
availableProviders.add("azure");
|
|
320966
320721
|
}
|
|
320967
|
-
if (availableProviders.has("github-models")) {
|
|
320968
|
-
await this.discoverGitHubModelsCatalog(config2);
|
|
320969
|
-
}
|
|
320970
320722
|
await this.validateCloudProviderModels(config2);
|
|
320971
320723
|
for (const tier of ["T1", "T2", "T3"]) {
|
|
320972
320724
|
const override = tier === "T1" ? config2.models.t1 : tier === "T2" ? config2.models.t2 : config2.models.t3;
|
|
320973
320725
|
if (!override || override === "auto") continue;
|
|
320974
320726
|
const model = this.selector.selectForTier(tier, override);
|
|
320975
320727
|
if (!model) {
|
|
320976
|
-
const knownProviders = ["anthropic", "openai", "gemini", "azure", "openai-compatible", "ollama"
|
|
320728
|
+
const knownProviders = ["anthropic", "openai", "gemini", "azure", "openai-compatible", "ollama"];
|
|
320977
320729
|
const hasProviderPrefix = override.includes(":") && knownProviders.some((p3) => override.startsWith(p3 + ":"));
|
|
320978
320730
|
if (hasProviderPrefix) {
|
|
320979
320731
|
const provider = override.split(":")[0];
|
|
@@ -321128,7 +320880,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
|
|
|
321128
320880
|
* models without a package upgrade. Mirrors discoverOllamaModels.
|
|
321129
320881
|
*/
|
|
321130
320882
|
async discoverProviderModels() {
|
|
321131
|
-
const cloud = ["anthropic", "openai", "gemini", "azure", "openai-compatible"
|
|
320883
|
+
const cloud = ["anthropic", "openai", "gemini", "azure", "openai-compatible"];
|
|
321132
320884
|
const tasks = cloud.map(async (type) => {
|
|
321133
320885
|
if (!this.selector.isProviderAvailable(type)) return;
|
|
321134
320886
|
const seed = this.getAnyModelForProvider(type);
|
|
@@ -321643,26 +321395,6 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
|
|
|
321643
321395
|
return false;
|
|
321644
321396
|
}
|
|
321645
321397
|
}
|
|
321646
|
-
/**
|
|
321647
|
-
* Registers GitHub Models' real catalog ids via addDynamicModel so init()'s
|
|
321648
|
-
* tier-fill loop can pick one. Registration alone does not create a bound
|
|
321649
|
-
* BaseProvider instance (see ensureProvider) — the tier-fill loop's own
|
|
321650
|
-
* ensureProvider call does that for whichever model it actually selects,
|
|
321651
|
-
* which is why this runs BEFORE that loop rather than only in the
|
|
321652
|
-
* background discoverProviderModels() refresh.
|
|
321653
|
-
*/
|
|
321654
|
-
async discoverGitHubModelsCatalog(config2) {
|
|
321655
|
-
const cfg = config2.providers.find((p3) => p3.type === "github-models") ?? { type: "github-models" };
|
|
321656
|
-
const seed = this.getAnyModelForProvider("github-models");
|
|
321657
|
-
if (!seed) return;
|
|
321658
|
-
try {
|
|
321659
|
-
const provider = new GitHubModelsProvider(cfg, seed);
|
|
321660
|
-
const models = await provider.listModels();
|
|
321661
|
-
for (const m3 of models) this.selector.addDynamicModel(m3);
|
|
321662
|
-
} catch (err) {
|
|
321663
|
-
console.warn("[router] GitHub Models catalog discovery failed:", err instanceof Error ? err.message : err);
|
|
321664
|
-
}
|
|
321665
|
-
}
|
|
321666
321398
|
ensureProvider(model, configs) {
|
|
321667
321399
|
const key = `${model.provider}:${model.id}`;
|
|
321668
321400
|
if (this.providers.has(key)) return;
|
|
@@ -321687,8 +321419,6 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
|
|
|
321687
321419
|
return new OllamaProvider(cfg, model);
|
|
321688
321420
|
case "openai-compatible":
|
|
321689
321421
|
return new OpenAICompatibleProvider(cfg, model);
|
|
321690
|
-
case "github-models":
|
|
321691
|
-
return new GitHubModelsProvider(cfg, model);
|
|
321692
321422
|
default:
|
|
321693
321423
|
throw new Error(`Unsupported provider type: ${String(cfg.type)}`);
|
|
321694
321424
|
}
|
|
@@ -321696,7 +321426,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
|
|
|
321696
321426
|
getAnyModelForProvider(type) {
|
|
321697
321427
|
const fromCatalog = Object.values(MODELS).find((m3) => m3.provider === type);
|
|
321698
321428
|
if (fromCatalog) return fromCatalog;
|
|
321699
|
-
if (type === "openai-compatible" || type === "azure"
|
|
321429
|
+
if (type === "openai-compatible" || type === "azure") {
|
|
321700
321430
|
return {
|
|
321701
321431
|
id: type,
|
|
321702
321432
|
name: type,
|
|
@@ -370123,7 +369853,7 @@ var PermissionEscalator = class extends EventEmitter__default.default {
|
|
|
370123
369853
|
|
|
370124
369854
|
// src/config/schema.ts
|
|
370125
369855
|
var ProviderConfigSchema = external_exports.object({
|
|
370126
|
-
type: external_exports.enum(["anthropic", "openai", "gemini", "azure", "openai-compatible", "ollama"
|
|
369856
|
+
type: external_exports.enum(["anthropic", "openai", "gemini", "azure", "openai-compatible", "ollama"]),
|
|
370127
369857
|
label: external_exports.string().optional(),
|
|
370128
369858
|
apiKey: external_exports.string().optional(),
|
|
370129
369859
|
baseUrl: external_exports.string().url().optional(),
|
|
@@ -375409,6 +375139,19 @@ Original error: ${err.message}`
|
|
|
375409
375139
|
const rows = provider ? this.db.prepare("SELECT metadata FROM model_cache WHERE provider = ?").all(provider) : this.db.prepare("SELECT metadata FROM model_cache").all();
|
|
375410
375140
|
return rows.map((r4) => JSON.parse(r4.metadata));
|
|
375411
375141
|
}
|
|
375142
|
+
/**
|
|
375143
|
+
* Deletes cached rows for a provider type that no longer exists in
|
|
375144
|
+
* `ProviderType`, so it takes a raw string rather than the union.
|
|
375145
|
+
*
|
|
375146
|
+
* Needed because the cache outlives the code: the REPL's loadCache() only
|
|
375147
|
+
* re-discovers when the cache is EMPTY or older than 24h, so rows left
|
|
375148
|
+
* behind by a removed provider read as "cache populated" and suppress
|
|
375149
|
+
* discovery for the providers that replaced it — `/model` then shows a
|
|
375150
|
+
* configured provider with zero models until the rows age out.
|
|
375151
|
+
*/
|
|
375152
|
+
purgeCachedModelsForRetiredProvider(providerType) {
|
|
375153
|
+
return this.db.prepare("DELETE FROM model_cache WHERE provider = ?").run(providerType).changes;
|
|
375154
|
+
}
|
|
375412
375155
|
clearModelCache(provider) {
|
|
375413
375156
|
if (provider) {
|
|
375414
375157
|
this.db.prepare("DELETE FROM model_cache WHERE provider = ?").run(provider);
|
|
@@ -375756,7 +375499,73 @@ function mergeGlobalCredentials(workspaceProviders, globalProviders) {
|
|
|
375756
375499
|
return merged;
|
|
375757
375500
|
}
|
|
375758
375501
|
|
|
375502
|
+
// src/config/retired-providers.ts
|
|
375503
|
+
var RETIRED_PROVIDER_TYPES = {
|
|
375504
|
+
"github-models": "GitHub retired GitHub Models on 30 July 2026; models.github.ai no longer responds."
|
|
375505
|
+
};
|
|
375506
|
+
function isRetiredProviderType(type) {
|
|
375507
|
+
return typeof type === "string" && Object.hasOwn(RETIRED_PROVIDER_TYPES, type);
|
|
375508
|
+
}
|
|
375509
|
+
function didCleanupChangeAnything(c4) {
|
|
375510
|
+
return c4.removed.length > 0 || c4.clearedPins.length > 0;
|
|
375511
|
+
}
|
|
375512
|
+
function stripRetiredProviders(raw) {
|
|
375513
|
+
const cleanup = { removed: [], clearedPins: [] };
|
|
375514
|
+
if (typeof raw !== "object" || raw === null) return cleanup;
|
|
375515
|
+
const cfg = raw;
|
|
375516
|
+
if (Array.isArray(cfg["providers"])) {
|
|
375517
|
+
const kept = cfg["providers"].filter((p3) => {
|
|
375518
|
+
const type = p3?.type;
|
|
375519
|
+
if (!isRetiredProviderType(type)) return true;
|
|
375520
|
+
if (!cleanup.removed.includes(type)) cleanup.removed.push(type);
|
|
375521
|
+
return false;
|
|
375522
|
+
});
|
|
375523
|
+
cfg["providers"] = kept;
|
|
375524
|
+
}
|
|
375525
|
+
cleanup.clearedPins = clearRetiredPins(cfg["models"]);
|
|
375526
|
+
return cleanup;
|
|
375527
|
+
}
|
|
375528
|
+
function clearRetiredPins(models) {
|
|
375529
|
+
const cleared = [];
|
|
375530
|
+
if (typeof models !== "object" || models === null) return cleared;
|
|
375531
|
+
const tiers = models;
|
|
375532
|
+
for (const tier of ["t1", "t2", "t3"]) {
|
|
375533
|
+
const pin = tiers[tier];
|
|
375534
|
+
if (typeof pin !== "string") continue;
|
|
375535
|
+
const prefix = pin.slice(0, pin.indexOf(":")).toLowerCase();
|
|
375536
|
+
if (pin.includes(":") && isRetiredProviderType(prefix)) {
|
|
375537
|
+
delete tiers[tier];
|
|
375538
|
+
cleared.push(tier);
|
|
375539
|
+
}
|
|
375540
|
+
}
|
|
375541
|
+
return cleared;
|
|
375542
|
+
}
|
|
375543
|
+
function filterRetiredCredentials(providers) {
|
|
375544
|
+
const removed = [];
|
|
375545
|
+
const kept = providers.filter((p3) => {
|
|
375546
|
+
if (!isRetiredProviderType(p3.type)) return true;
|
|
375547
|
+
if (!removed.includes(p3.type)) removed.push(p3.type);
|
|
375548
|
+
return false;
|
|
375549
|
+
});
|
|
375550
|
+
return { kept, removed };
|
|
375551
|
+
}
|
|
375552
|
+
function describeCleanup(c4) {
|
|
375553
|
+
const parts = [];
|
|
375554
|
+
for (const type of c4.removed) {
|
|
375555
|
+
parts.push(`removed the retired "${type}" provider (${RETIRED_PROVIDER_TYPES[type]})`);
|
|
375556
|
+
}
|
|
375557
|
+
if (c4.clearedPins.length > 0) {
|
|
375558
|
+
parts.push(`reset ${c4.clearedPins.map((t4) => t4.toUpperCase()).join("/")} to Auto, since the pin named it`);
|
|
375559
|
+
}
|
|
375560
|
+
return `Cascade config migration: ${parts.join("; ")}.`;
|
|
375561
|
+
}
|
|
375562
|
+
|
|
375759
375563
|
// src/config/index.ts
|
|
375564
|
+
var KEY_OPTIONAL_PROVIDER_TYPES = /* @__PURE__ */ new Set(["ollama", "openai-compatible"]);
|
|
375565
|
+
function hasUsableProvider(providers) {
|
|
375566
|
+
if (!providers?.length) return false;
|
|
375567
|
+
return providers.some((p3) => KEY_OPTIONAL_PROVIDER_TYPES.has(p3.type) || !!p3.apiKey || !!p3.authToken);
|
|
375568
|
+
}
|
|
375760
375569
|
var ConfigManager = class {
|
|
375761
375570
|
config;
|
|
375762
375571
|
keystore;
|
|
@@ -375765,6 +375574,29 @@ var ConfigManager = class {
|
|
|
375765
375574
|
cascadeMd = null;
|
|
375766
375575
|
workspacePath;
|
|
375767
375576
|
globalDir;
|
|
375577
|
+
/**
|
|
375578
|
+
* What THIS load migrated out, if anything. Strictly per-load state: reset
|
|
375579
|
+
* at the top of every `load()`, because two places read it as a statement
|
|
375580
|
+
* about the load in progress — `injectEnvKeys()` asks whether an empty
|
|
375581
|
+
* provider list was emptied by a retirement, and the end of `load()` warns
|
|
375582
|
+
* and builds the user-facing notice from it. Left set, a second `load()` on
|
|
375583
|
+
* the same instance (`startRepl()` does one after its setup wizard) would
|
|
375584
|
+
* re-announce a migration that already happened and suppress the Ollama
|
|
375585
|
+
* fallback for a list that is empty for some unrelated reason.
|
|
375586
|
+
*/
|
|
375587
|
+
retiredCleanup;
|
|
375588
|
+
/**
|
|
375589
|
+
* Human-readable migration notice held for a UI to display. `console.warn`
|
|
375590
|
+
* is not sufficient: the REPL clears the TTY immediately after load(), and
|
|
375591
|
+
* the desktop emits from the main process where nothing is rendered.
|
|
375592
|
+
*/
|
|
375593
|
+
pendingRetiredNotice;
|
|
375594
|
+
/** Returns the pending migration notice once, then forgets it. */
|
|
375595
|
+
takeRetiredNotice() {
|
|
375596
|
+
const n8 = this.pendingRetiredNotice;
|
|
375597
|
+
this.pendingRetiredNotice = void 0;
|
|
375598
|
+
return n8;
|
|
375599
|
+
}
|
|
375768
375600
|
/** `globalDirOverride` exists for tests — never point it at the real home dir there. */
|
|
375769
375601
|
constructor(workspacePath = process.cwd(), globalDirOverride) {
|
|
375770
375602
|
this.workspacePath = workspacePath;
|
|
@@ -375784,10 +375616,32 @@ var ConfigManager = class {
|
|
|
375784
375616
|
this.cascadeMd = await loadCascadeMd(this.workspacePath);
|
|
375785
375617
|
this.keystore = new Keystore(path28__namespace.default.join(this.globalDir, GLOBAL_KEYSTORE_FILE));
|
|
375786
375618
|
this.store = new MemoryStore(path28__namespace.default.join(this.workspacePath, CASCADE_DB_FILE));
|
|
375619
|
+
const globalCreds = filterRetiredCredentials(loadGlobalCredentials(this.globalDir));
|
|
375620
|
+
if (globalCreds.removed.length > 0) {
|
|
375621
|
+
try {
|
|
375622
|
+
saveGlobalCredentials(this.globalDir, globalCreds.kept);
|
|
375623
|
+
} catch (err) {
|
|
375624
|
+
console.warn(`Could not rewrite the global credential store: ${err instanceof Error ? err.message : String(err)}`);
|
|
375625
|
+
}
|
|
375626
|
+
this.retiredCleanup = {
|
|
375627
|
+
removed: [.../* @__PURE__ */ new Set([...this.retiredCleanup?.removed ?? [], ...globalCreds.removed])],
|
|
375628
|
+
clearedPins: this.retiredCleanup?.clearedPins ?? []
|
|
375629
|
+
};
|
|
375630
|
+
}
|
|
375787
375631
|
await this.injectEnvKeys();
|
|
375788
|
-
this.config.providers = mergeGlobalCredentials(this.config.providers,
|
|
375632
|
+
this.config.providers = mergeGlobalCredentials(this.config.providers, globalCreds.kept);
|
|
375633
|
+
for (const type of Object.keys(RETIRED_PROVIDER_TYPES)) {
|
|
375634
|
+
try {
|
|
375635
|
+
this.store.purgeCachedModelsForRetiredProvider(type);
|
|
375636
|
+
} catch {
|
|
375637
|
+
}
|
|
375638
|
+
}
|
|
375789
375639
|
await this.ensureDefaultIdentity();
|
|
375790
375640
|
if (mcpNamesChanged) await this.save();
|
|
375641
|
+
if (this.retiredCleanup) {
|
|
375642
|
+
console.warn(describeCleanup(this.retiredCleanup));
|
|
375643
|
+
this.pendingRetiredNotice = describeCleanup(this.retiredCleanup);
|
|
375644
|
+
}
|
|
375791
375645
|
}
|
|
375792
375646
|
getConfig() {
|
|
375793
375647
|
return this.config;
|
|
@@ -375826,14 +375680,13 @@ var ConfigManager = class {
|
|
|
375826
375680
|
anthropic: "ANTHROPIC_API_KEY",
|
|
375827
375681
|
openai: "OPENAI_API_KEY",
|
|
375828
375682
|
gemini: "GOOGLE_API_KEY",
|
|
375829
|
-
azure: "AZURE_OPENAI_KEY"
|
|
375683
|
+
azure: "AZURE_OPENAI_KEY"
|
|
375830
375684
|
// Deliberately NOT `GITHUB_TOKEN`: that one is injected automatically by
|
|
375831
375685
|
// GitHub Actions and is commonly exported in developer shells for `gh`
|
|
375832
375686
|
// and git auth, and it will essentially never carry the fine-grained
|
|
375833
375687
|
// `models: read` scope this provider needs. Adopting it would wire up a
|
|
375834
375688
|
// provider that 403s on its first real call — a confusing failure for
|
|
375835
375689
|
// something that is meant to be explicit opt-in BYOK.
|
|
375836
|
-
"github-models": "GITHUB_MODELS_TOKEN"
|
|
375837
375690
|
};
|
|
375838
375691
|
const envKey = envMap[provider];
|
|
375839
375692
|
if (envKey && process.env[envKey]) return process.env[envKey];
|
|
@@ -375845,10 +375698,21 @@ var ConfigManager = class {
|
|
|
375845
375698
|
return configProvider?.apiKey;
|
|
375846
375699
|
}
|
|
375847
375700
|
async loadConfig() {
|
|
375701
|
+
this.retiredCleanup = void 0;
|
|
375848
375702
|
const configPath = path28__namespace.default.join(this.workspacePath, CASCADE_CONFIG_FILE);
|
|
375849
375703
|
try {
|
|
375850
375704
|
const raw = await fs9__namespace.default.readFile(configPath, "utf-8");
|
|
375851
|
-
|
|
375705
|
+
const parsed = JSON.parse(raw);
|
|
375706
|
+
const cleanup = stripRetiredProviders(parsed);
|
|
375707
|
+
if (didCleanupChangeAnything(cleanup)) {
|
|
375708
|
+
this.retiredCleanup = cleanup;
|
|
375709
|
+
try {
|
|
375710
|
+
await fs9__namespace.default.writeFile(configPath, JSON.stringify(parsed, null, 2), "utf-8");
|
|
375711
|
+
} catch (err) {
|
|
375712
|
+
console.warn(`Could not persist the retired-provider migration: ${err instanceof Error ? err.message : String(err)}`);
|
|
375713
|
+
}
|
|
375714
|
+
}
|
|
375715
|
+
return validateConfig(parsed);
|
|
375852
375716
|
} catch (err) {
|
|
375853
375717
|
if (err.code === "ENOENT") {
|
|
375854
375718
|
return validateConfig({});
|
|
@@ -375857,27 +375721,25 @@ var ConfigManager = class {
|
|
|
375857
375721
|
}
|
|
375858
375722
|
}
|
|
375859
375723
|
async injectEnvKeys() {
|
|
375860
|
-
const
|
|
375724
|
+
const wasEmpty = this.config.providers.length === 0;
|
|
375725
|
+
const emptiedByRetirement = wasEmpty && !!this.retiredCleanup;
|
|
375861
375726
|
const envProviders = [
|
|
375862
375727
|
{ env: "ANTHROPIC_API_KEY", type: "anthropic" },
|
|
375863
375728
|
{ env: "OPENAI_API_KEY", type: "openai" },
|
|
375864
375729
|
{ env: "GOOGLE_API_KEY", type: "gemini" },
|
|
375865
|
-
{ env: "AZURE_OPENAI_KEY", type: "azure" }
|
|
375866
|
-
// See getApiKey() above for why this is GITHUB_MODELS_TOKEN and never
|
|
375867
|
-
// the ambient GITHUB_TOKEN.
|
|
375868
|
-
{ env: "GITHUB_MODELS_TOKEN", type: "github-models" }
|
|
375730
|
+
{ env: "AZURE_OPENAI_KEY", type: "azure" }
|
|
375869
375731
|
];
|
|
375870
375732
|
for (const { env, type } of envProviders) {
|
|
375871
375733
|
const key = process.env[env];
|
|
375872
375734
|
if (!key) continue;
|
|
375873
375735
|
const existing = this.config.providers.find((p3) => p3.type === type);
|
|
375874
|
-
if (!existing &&
|
|
375736
|
+
if (!existing && wasEmpty) {
|
|
375875
375737
|
this.config.providers.push({ type, apiKey: key });
|
|
375876
375738
|
} else if (existing && !existing.apiKey) {
|
|
375877
375739
|
existing.apiKey = key;
|
|
375878
375740
|
}
|
|
375879
375741
|
}
|
|
375880
|
-
if (
|
|
375742
|
+
if (wasEmpty && !emptiedByRetirement && !this.config.providers.find((p3) => p3.type === "ollama")) {
|
|
375881
375743
|
this.config.providers.push({ type: "ollama" });
|
|
375882
375744
|
}
|
|
375883
375745
|
}
|
|
@@ -379298,7 +379160,9 @@ function gatherSyncBundle(config2) {
|
|
|
379298
379160
|
if (Object.keys(prefs).length) bundle.prefs = prefs;
|
|
379299
379161
|
return bundle;
|
|
379300
379162
|
}
|
|
379301
|
-
function applySyncBundle(bundle, config2) {
|
|
379163
|
+
function applySyncBundle(bundle, config2, cleanup) {
|
|
379164
|
+
const dropped = stripRetiredProviders(bundle);
|
|
379165
|
+
if (cleanup) cleanup.removed = dropped.removed;
|
|
379302
379166
|
const next = { ...config2, tools: { ...config2.tools } };
|
|
379303
379167
|
if (bundle.providers) next.providers = mergeByKey(config2.providers, bundle.providers, providerSig) ?? [];
|
|
379304
379168
|
if (bundle.webSearch) next.tools.webSearch = { ...config2.tools?.webSearch, ...bundle.webSearch };
|
|
@@ -379314,6 +379178,14 @@ function applySyncBundle(bundle, config2) {
|
|
|
379314
379178
|
}
|
|
379315
379179
|
if (bundle.models) next.models = { ...config2.models, ...bundle.models };
|
|
379316
379180
|
if (bundle.budget) next.budget = { ...config2.budget, ...bundle.budget };
|
|
379181
|
+
const merged = { ...next.models };
|
|
379182
|
+
const clearedFromMerge = clearRetiredPins(merged);
|
|
379183
|
+
if (clearedFromMerge.length > 0) next.models = merged;
|
|
379184
|
+
if (cleanup) {
|
|
379185
|
+
cleanup.clearedPins = ["t1", "t2", "t3"].filter(
|
|
379186
|
+
(t4) => (dropped.clearedPins.includes(t4) || clearedFromMerge.includes(t4)) && next.models?.[t4] === void 0
|
|
379187
|
+
);
|
|
379188
|
+
}
|
|
379317
379189
|
if (bundle.prefs) {
|
|
379318
379190
|
const p3 = bundle.prefs;
|
|
379319
379191
|
if (p3.autoBias !== void 0) next.autoBias = p3.autoBias;
|
|
@@ -379785,9 +379657,6 @@ exports.DOCUMENT_MIME = DOCUMENT_MIME;
|
|
|
379785
379657
|
exports.DashboardServer = DashboardServer;
|
|
379786
379658
|
exports.DependencyScheduler = DependencyScheduler;
|
|
379787
379659
|
exports.FileMcpOAuthStore = FileMcpOAuthStore;
|
|
379788
|
-
exports.GITHUB_MODELS_API_VERSION = GITHUB_MODELS_API_VERSION;
|
|
379789
|
-
exports.GITHUB_MODELS_CATALOG_URL = GITHUB_MODELS_CATALOG_URL;
|
|
379790
|
-
exports.GITHUB_MODELS_INFERENCE_URL = GITHUB_MODELS_INFERENCE_URL;
|
|
379791
379660
|
exports.GLOBAL_CONFIG_DIR = GLOBAL_CONFIG_DIR;
|
|
379792
379661
|
exports.GLOBAL_CREDENTIALS_FILE = GLOBAL_CREDENTIALS_FILE;
|
|
379793
379662
|
exports.GLOBAL_DB_FILE = GLOBAL_DB_FILE;
|
|
@@ -379860,6 +379729,7 @@ exports.failures = failures;
|
|
|
379860
379729
|
exports.fileExt = fileExt;
|
|
379861
379730
|
exports.fileOAuthProvider = fileOAuthProvider;
|
|
379862
379731
|
exports.gatherSyncBundle = gatherSyncBundle;
|
|
379732
|
+
exports.hasUsableProvider = hasUsableProvider;
|
|
379863
379733
|
exports.hashContent = hashContent;
|
|
379864
379734
|
exports.heuristicCodeChunker = heuristicCodeChunker;
|
|
379865
379735
|
exports.inferAzureBaseModel = inferAzureBaseModel;
|