@cleocode/core 2026.6.14 → 2026.6.15
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/check/pr-gate.d.ts +6 -2
- package/dist/check/pr-gate.d.ts.map +1 -1
- package/dist/check/pr-gate.js +14 -32
- package/dist/check/pr-gate.js.map +1 -1
- package/dist/config/config-repair.d.ts +70 -0
- package/dist/config/config-repair.d.ts.map +1 -0
- package/dist/config/config-repair.js +248 -0
- package/dist/config/config-repair.js.map +1 -0
- package/dist/config/registry.d.ts.map +1 -1
- package/dist/config/registry.js +4 -4
- package/dist/config/registry.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -10
- package/dist/config.js.map +1 -1
- package/dist/docs/export-document.js +17 -16
- package/dist/docs/export-document.js.map +2 -2
- package/dist/gc/cleanup.d.ts +23 -8
- package/dist/gc/cleanup.d.ts.map +1 -1
- package/dist/gc/cleanup.js +287 -22
- package/dist/gc/cleanup.js.map +1 -1
- package/dist/llm/cli-ops.d.ts +16 -0
- package/dist/llm/cli-ops.d.ts.map +1 -1
- package/dist/llm/cli-ops.js +32 -5
- package/dist/llm/cli-ops.js.map +1 -1
- package/dist/llm/cross-provider-selector.d.ts +249 -0
- package/dist/llm/cross-provider-selector.d.ts.map +1 -0
- package/dist/llm/cross-provider-selector.js +572 -0
- package/dist/llm/cross-provider-selector.js.map +1 -0
- package/dist/llm/index.d.ts +2 -0
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +1 -0
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/local-model-fit.d.ts +260 -0
- package/dist/llm/local-model-fit.d.ts.map +1 -0
- package/dist/llm/local-model-fit.js +563 -0
- package/dist/llm/local-model-fit.js.map +1 -0
- package/dist/llm/plugin-facade.js +761 -230
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/llm/provider-registry/builtin/ollama.d.ts +18 -0
- package/dist/llm/provider-registry/builtin/ollama.d.ts.map +1 -1
- package/dist/llm/provider-registry/builtin/ollama.js +20 -2
- package/dist/llm/provider-registry/builtin/ollama.js.map +1 -1
- package/dist/llm/role-resolver.d.ts.map +1 -1
- package/dist/llm/role-resolver.js +45 -10
- package/dist/llm/role-resolver.js.map +1 -1
- package/dist/llm/transports/codex-responses.d.ts +111 -88
- package/dist/llm/transports/codex-responses.d.ts.map +1 -1
- package/dist/llm/transports/codex-responses.js +456 -258
- package/dist/llm/transports/codex-responses.js.map +1 -1
- package/dist/release/index.d.ts +2 -2
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js +1 -1
- package/dist/release/index.js.map +1 -1
- package/dist/release/reconcile.d.ts +97 -0
- package/dist/release/reconcile.d.ts.map +1 -1
- package/dist/release/reconcile.js +412 -5
- package/dist/release/reconcile.js.map +1 -1
- package/dist/resources/backend.d.ts +155 -0
- package/dist/resources/backend.d.ts.map +1 -0
- package/dist/resources/backend.js +23 -0
- package/dist/resources/backend.js.map +1 -0
- package/dist/resources/linux-backend.d.ts +167 -0
- package/dist/resources/linux-backend.d.ts.map +1 -0
- package/dist/resources/linux-backend.js +259 -0
- package/dist/resources/linux-backend.js.map +1 -0
- package/dist/resources/monitor.d.ts +230 -0
- package/dist/resources/monitor.d.ts.map +1 -0
- package/dist/resources/monitor.js +255 -0
- package/dist/resources/monitor.js.map +1 -0
- package/dist/resources/spawn-wrapper.d.ts +265 -0
- package/dist/resources/spawn-wrapper.d.ts.map +1 -0
- package/dist/resources/spawn-wrapper.js +304 -0
- package/dist/resources/spawn-wrapper.js.map +1 -0
- package/dist/selfimprove/budget.d.ts +11 -2
- package/dist/selfimprove/budget.d.ts.map +1 -1
- package/dist/selfimprove/budget.js +11 -2
- package/dist/selfimprove/budget.js.map +1 -1
- package/dist/selfimprove/fix-gen.d.ts +229 -0
- package/dist/selfimprove/fix-gen.d.ts.map +1 -0
- package/dist/selfimprove/fix-gen.js +266 -0
- package/dist/selfimprove/fix-gen.js.map +1 -0
- package/dist/selfimprove/run-loop.d.ts +44 -4
- package/dist/selfimprove/run-loop.d.ts.map +1 -1
- package/dist/selfimprove/run-loop.js +73 -6
- package/dist/selfimprove/run-loop.js.map +1 -1
- package/dist/sentient/cross-project-hygiene.d.ts +11 -2
- package/dist/sentient/cross-project-hygiene.d.ts.map +1 -1
- package/dist/sentient/cross-project-hygiene.js +73 -10
- package/dist/sentient/cross-project-hygiene.js.map +1 -1
- package/dist/sentient/daemon.d.ts.map +1 -1
- package/dist/sentient/daemon.js +7 -2
- package/dist/sentient/daemon.js.map +1 -1
- package/dist/sentient/worktree-dispatch.d.ts.map +1 -1
- package/dist/sentient/worktree-dispatch.js +8 -1
- package/dist/sentient/worktree-dispatch.js.map +1 -1
- package/dist/spawn/branch-lock.d.ts.map +1 -1
- package/dist/spawn/branch-lock.js +7 -1
- package/dist/spawn/branch-lock.js.map +1 -1
- package/dist/store/attachment-repair.d.ts +110 -0
- package/dist/store/attachment-repair.d.ts.map +1 -0
- package/dist/store/attachment-repair.js +326 -0
- package/dist/store/attachment-repair.js.map +1 -0
- package/dist/store/attachment-store.d.ts.map +1 -1
- package/dist/store/attachment-store.js +24 -7
- package/dist/store/attachment-store.js.map +1 -1
- package/dist/tasks/evidence.d.ts +34 -2
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js +293 -35
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/verification/verify-tools.d.ts.map +1 -1
- package/dist/verification/verify-tools.js +5 -6
- package/dist/verification/verify-tools.js.map +1 -1
- package/package.json +22 -12
- package/templates/workflows/release-prepare.yml.tmpl +48 -2
|
@@ -17608,7 +17608,7 @@ var init_sql = __esm({
|
|
|
17608
17608
|
return new SQL([new StringChunk(str)]);
|
|
17609
17609
|
}
|
|
17610
17610
|
_sql.raw = raw;
|
|
17611
|
-
function
|
|
17611
|
+
function join29(chunks, separator) {
|
|
17612
17612
|
const result = [];
|
|
17613
17613
|
for (const [i, chunk] of chunks.entries()) {
|
|
17614
17614
|
if (i > 0 && separator !== void 0) result.push(separator);
|
|
@@ -17616,7 +17616,7 @@ var init_sql = __esm({
|
|
|
17616
17616
|
}
|
|
17617
17617
|
return new SQL(result);
|
|
17618
17618
|
}
|
|
17619
|
-
_sql.join =
|
|
17619
|
+
_sql.join = join29;
|
|
17620
17620
|
function identifier(value) {
|
|
17621
17621
|
return new Name(value);
|
|
17622
17622
|
}
|
|
@@ -20003,7 +20003,7 @@ var init_select2 = __esm({
|
|
|
20003
20003
|
const baseTableName = this.tableName;
|
|
20004
20004
|
const tableName = getTableLikeName(table);
|
|
20005
20005
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
20006
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
20006
|
+
if (typeof tableName === "string" && this.config.joins?.some((join29) => join29.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
20007
20007
|
if (!this.isPartialSelect) {
|
|
20008
20008
|
if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === "string") this.config.fields = { [baseTableName]: this.config.fields };
|
|
20009
20009
|
if (typeof tableName === "string" && !is(table, SQL)) {
|
|
@@ -23813,7 +23813,7 @@ var init_dialect = __esm({
|
|
|
23813
23813
|
if (!joins2) return;
|
|
23814
23814
|
const withEntries = Object.entries(joins2).filter(([_, v]) => v);
|
|
23815
23815
|
if (!withEntries.length) return;
|
|
23816
|
-
return sql.join(withEntries.map(([k,
|
|
23816
|
+
return sql.join(withEntries.map(([k, join29]) => {
|
|
23817
23817
|
const relation = tableConfig.relations[k];
|
|
23818
23818
|
const isSingle2 = is(relation, One);
|
|
23819
23819
|
const targetTable = aliasedTable(relation.targetTable, `d${currentDepth + 1}`);
|
|
@@ -23824,7 +23824,7 @@ var init_dialect = __esm({
|
|
|
23824
23824
|
table: targetTable,
|
|
23825
23825
|
mode: isSingle2 ? "first" : "many",
|
|
23826
23826
|
schema,
|
|
23827
|
-
queryConfig:
|
|
23827
|
+
queryConfig: join29,
|
|
23828
23828
|
tableConfig: schema[relation.targetTableName],
|
|
23829
23829
|
relationWhere: filter2,
|
|
23830
23830
|
isNested: true,
|
|
@@ -23838,7 +23838,7 @@ var init_dialect = __esm({
|
|
|
23838
23838
|
key: k,
|
|
23839
23839
|
selection: innerQuery.selection,
|
|
23840
23840
|
isArray: !isSingle2,
|
|
23841
|
-
isOptional: (relation.optional ?? false) ||
|
|
23841
|
+
isOptional: (relation.optional ?? false) || join29 !== true && !!join29.where
|
|
23842
23842
|
});
|
|
23843
23843
|
const jsonColumns = sql.join(innerQuery.selection.map((s) => {
|
|
23844
23844
|
return sql`${sql.raw(this.escapeString(s.key))}, ${s.selection ? sql`${jsonb3}(${sql.identifier(s.key)})` : sql.identifier(s.key)}`;
|
|
@@ -24659,7 +24659,7 @@ var init_update = __esm({
|
|
|
24659
24659
|
createJoin(joinType) {
|
|
24660
24660
|
return ((table, on) => {
|
|
24661
24661
|
const tableName = getTableLikeName(table);
|
|
24662
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
24662
|
+
if (typeof tableName === "string" && this.config.joins.some((join29) => join29.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
24663
24663
|
if (typeof on === "function") {
|
|
24664
24664
|
const from = this.config.from ? is(table, SQLiteTable) ? table[Table.Symbol.Columns] : is(table, Subquery) ? table._.selectedFields : is(table, SQLiteViewBase) ? table[ViewBaseConfig].selectedFields : void 0 : void 0;
|
|
24665
24665
|
on = on(new Proxy(this.config.table[Table.Symbol.Columns], new SelectionProxyHandler({
|
|
@@ -25348,10 +25348,10 @@ var init_session4 = __esm({
|
|
|
25348
25348
|
NodeSQLitePreparedQuery = class extends SQLitePreparedQuery {
|
|
25349
25349
|
static [entityKind] = "SQLJsPreparedQuery";
|
|
25350
25350
|
jitMapper;
|
|
25351
|
-
constructor(stmt, query,
|
|
25351
|
+
constructor(stmt, query, logger6, fields, executeMethod, useJitMappers, customResultMapper, isRqbV2Query, rqbConfig) {
|
|
25352
25352
|
super("sync", executeMethod, query);
|
|
25353
25353
|
this.stmt = stmt;
|
|
25354
|
-
this.logger =
|
|
25354
|
+
this.logger = logger6;
|
|
25355
25355
|
this.fields = fields;
|
|
25356
25356
|
this.useJitMappers = useJitMappers;
|
|
25357
25357
|
this.customResultMapper = customResultMapper;
|
|
@@ -25367,10 +25367,10 @@ var init_session4 = __esm({
|
|
|
25367
25367
|
all(placeholderValues = {}) {
|
|
25368
25368
|
if (this.isRqbV2Query) return this.allRqbV2(placeholderValues);
|
|
25369
25369
|
const { stmt } = this;
|
|
25370
|
-
const { fields, joinsNotNullableMap, logger:
|
|
25370
|
+
const { fields, joinsNotNullableMap, logger: logger6, query, customResultMapper } = this;
|
|
25371
25371
|
if (!fields && !customResultMapper) {
|
|
25372
25372
|
const params = fillPlaceholders(query.params, placeholderValues);
|
|
25373
|
-
|
|
25373
|
+
logger6.logQuery(query.sql, params);
|
|
25374
25374
|
stmt.setReturnArrays(false);
|
|
25375
25375
|
return stmt.all(...params);
|
|
25376
25376
|
}
|
|
@@ -25381,9 +25381,9 @@ var init_session4 = __esm({
|
|
|
25381
25381
|
}
|
|
25382
25382
|
allRqbV2(placeholderValues = {}) {
|
|
25383
25383
|
const { stmt } = this;
|
|
25384
|
-
const { logger:
|
|
25384
|
+
const { logger: logger6, query, customResultMapper } = this;
|
|
25385
25385
|
const params = fillPlaceholders(query.params, placeholderValues);
|
|
25386
|
-
|
|
25386
|
+
logger6.logQuery(query.sql, params);
|
|
25387
25387
|
stmt.setReturnArrays(false);
|
|
25388
25388
|
const rows = stmt.all(...params).map((row) => ({ ...row }));
|
|
25389
25389
|
return this.useJitMappers ? (this.jitMapper = this.jitMapper ?? makeJitRqbMapper(this.rqbConfig))(rows) : customResultMapper(rows);
|
|
@@ -25429,9 +25429,9 @@ var init_session4 = __esm({
|
|
|
25429
25429
|
import { DatabaseSync } from "node:sqlite";
|
|
25430
25430
|
function construct(client, config2 = {}) {
|
|
25431
25431
|
const dialect = new SQLiteSyncDialect();
|
|
25432
|
-
let
|
|
25433
|
-
if (config2.logger === true)
|
|
25434
|
-
else if (config2.logger !== false)
|
|
25432
|
+
let logger6;
|
|
25433
|
+
if (config2.logger === true) logger6 = new DefaultLogger();
|
|
25434
|
+
else if (config2.logger !== false) logger6 = config2.logger;
|
|
25435
25435
|
let schema;
|
|
25436
25436
|
if (config2.schema) {
|
|
25437
25437
|
const tablesConfig = extractTablesRelationalConfig(config2.schema, createTableRelationsHelpers);
|
|
@@ -25443,7 +25443,7 @@ function construct(client, config2 = {}) {
|
|
|
25443
25443
|
}
|
|
25444
25444
|
const relations = config2.relations ?? {};
|
|
25445
25445
|
const db = new NodeSQLiteDatabase("sync", dialect, new NodeSQLiteSession(client, dialect, relations, schema, {
|
|
25446
|
-
logger:
|
|
25446
|
+
logger: logger6,
|
|
25447
25447
|
useJitMappers: jitCompatCheck(config2.jit)
|
|
25448
25448
|
}), relations, schema);
|
|
25449
25449
|
db.$client = client;
|
|
@@ -40041,8 +40041,6 @@ __export(config_exports, {
|
|
|
40041
40041
|
setConfigValue: () => setConfigValue
|
|
40042
40042
|
});
|
|
40043
40043
|
import { existsSync as existsSync16 } from "node:fs";
|
|
40044
|
-
import { mkdir as mkdir3, writeFile } from "node:fs/promises";
|
|
40045
|
-
import { dirname as dirname8 } from "node:path";
|
|
40046
40044
|
function getNestedValue(obj, path) {
|
|
40047
40045
|
const parts = path.split(".");
|
|
40048
40046
|
let current = obj;
|
|
@@ -40165,9 +40163,7 @@ function parseConfigValue(value) {
|
|
|
40165
40163
|
async function setConfigValue(key, value, cwd, opts) {
|
|
40166
40164
|
const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
|
|
40167
40165
|
if (!existsSync16(configPath)) {
|
|
40168
|
-
|
|
40169
|
-
await mkdir3(dir, { recursive: true });
|
|
40170
|
-
await writeFile(configPath, "{}", "utf-8");
|
|
40166
|
+
await atomicWriteJson(configPath, {});
|
|
40171
40167
|
}
|
|
40172
40168
|
const config2 = await readJson(configPath) ?? {};
|
|
40173
40169
|
const parsedValue = parseConfigValue(value);
|
|
@@ -40179,9 +40175,7 @@ async function applyStrictnessPreset(preset, cwd, opts) {
|
|
|
40179
40175
|
const definition = STRICTNESS_PRESETS[preset];
|
|
40180
40176
|
const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
|
|
40181
40177
|
if (!existsSync16(configPath)) {
|
|
40182
|
-
|
|
40183
|
-
await mkdir3(dir, { recursive: true });
|
|
40184
|
-
await writeFile(configPath, "{}", "utf-8");
|
|
40178
|
+
await atomicWriteJson(configPath, {});
|
|
40185
40179
|
}
|
|
40186
40180
|
const config2 = await readJson(configPath) ?? {};
|
|
40187
40181
|
for (const [key, value] of Object.entries(definition.values)) {
|
|
@@ -40210,6 +40204,7 @@ var init_config = __esm({
|
|
|
40210
40204
|
"use strict";
|
|
40211
40205
|
init_fallback_model();
|
|
40212
40206
|
init_paths();
|
|
40207
|
+
init_atomic();
|
|
40213
40208
|
init_json2();
|
|
40214
40209
|
DEFAULTS = {
|
|
40215
40210
|
version: "2.10.0",
|
|
@@ -40320,6 +40315,12 @@ var init_config = __esm({
|
|
|
40320
40315
|
// (T10383). The active runtime itself ships in T10512.
|
|
40321
40316
|
leadRollup: {
|
|
40322
40317
|
mode: "passive"
|
|
40318
|
+
},
|
|
40319
|
+
// T11984: daemon lifecycle — postinstall respects operator state by default.
|
|
40320
|
+
// Set daemon.autoStart = false (via global config.json) for a persistent
|
|
40321
|
+
// opt-out that survives npm upgrades.
|
|
40322
|
+
daemon: {
|
|
40323
|
+
autoStart: true
|
|
40323
40324
|
}
|
|
40324
40325
|
};
|
|
40325
40326
|
ENV_MAP = {
|
|
@@ -41544,15 +41545,27 @@ var init_credentials2 = __esm({
|
|
|
41544
41545
|
});
|
|
41545
41546
|
|
|
41546
41547
|
// packages/core/src/llm/credentials-store.ts
|
|
41548
|
+
var credentials_store_exports = {};
|
|
41549
|
+
__export(credentials_store_exports, {
|
|
41550
|
+
_resetPermsWarningForTests: () => _resetPermsWarningForTests,
|
|
41551
|
+
_resetRoundRobinForTests: () => _resetRoundRobinForTests,
|
|
41552
|
+
addCredential: () => addCredential,
|
|
41553
|
+
credentialsStorePath: () => credentialsStorePath,
|
|
41554
|
+
getCredentialByLabel: () => getCredentialByLabel,
|
|
41555
|
+
listCredentials: () => listCredentials,
|
|
41556
|
+
pickCredentialForProvider: () => pickCredentialForProvider,
|
|
41557
|
+
pickCredentialForProviderSync: () => pickCredentialForProviderSync,
|
|
41558
|
+
removeCredential: () => removeCredential
|
|
41559
|
+
});
|
|
41547
41560
|
import { chmodSync, existsSync as existsSync22, mkdirSync as mkdirSync7, readFileSync as readFileSync13, statSync as statSync6, writeFileSync as writeFileSync7 } from "node:fs";
|
|
41548
|
-
import { dirname as
|
|
41561
|
+
import { dirname as dirname8, join as join23 } from "node:path";
|
|
41549
41562
|
import { getCleoHome as getCleoHome7 } from "@cleocode/paths";
|
|
41550
41563
|
function credentialsStorePath() {
|
|
41551
41564
|
return join23(getCleoHome7(), "llm-credentials.json");
|
|
41552
41565
|
}
|
|
41553
41566
|
function ensureFileInitialized(path) {
|
|
41554
41567
|
if (existsSync22(path)) return;
|
|
41555
|
-
const dir =
|
|
41568
|
+
const dir = dirname8(path);
|
|
41556
41569
|
if (!existsSync22(dir)) {
|
|
41557
41570
|
mkdirSync7(dir, { recursive: true, mode: 448 });
|
|
41558
41571
|
} else {
|
|
@@ -41587,6 +41600,9 @@ function checkPermsOnRead(path) {
|
|
|
41587
41600
|
} catch {
|
|
41588
41601
|
}
|
|
41589
41602
|
}
|
|
41603
|
+
function _resetPermsWarningForTests() {
|
|
41604
|
+
_warnedLoosePerms = false;
|
|
41605
|
+
}
|
|
41590
41606
|
function emptyStore() {
|
|
41591
41607
|
return { version: 1, defaultStrategy: "priorityWithFallback", credentials: [] };
|
|
41592
41608
|
}
|
|
@@ -41629,6 +41645,9 @@ function isStoredCredential(value) {
|
|
|
41629
41645
|
if (typeof accessToken !== "string") return false;
|
|
41630
41646
|
return true;
|
|
41631
41647
|
}
|
|
41648
|
+
function _resetRoundRobinForTests() {
|
|
41649
|
+
_rrIndex.clear();
|
|
41650
|
+
}
|
|
41632
41651
|
function eligibleForProvider(data, provider, preferLabel) {
|
|
41633
41652
|
const now = Date.now();
|
|
41634
41653
|
const all = data.credentials.filter((c) => {
|
|
@@ -41732,6 +41751,35 @@ async function addCredential(input) {
|
|
|
41732
41751
|
clearAnthropicKeyCache();
|
|
41733
41752
|
return inserted;
|
|
41734
41753
|
}
|
|
41754
|
+
async function removeCredential(provider, label) {
|
|
41755
|
+
const path = credentialsStorePath();
|
|
41756
|
+
const snapshot = readStoreSync();
|
|
41757
|
+
if (!snapshot.credentials.some((c) => c.provider === provider && c.label === label)) {
|
|
41758
|
+
return false;
|
|
41759
|
+
}
|
|
41760
|
+
ensureFileInitialized(path);
|
|
41761
|
+
let removed = false;
|
|
41762
|
+
await withLock2(
|
|
41763
|
+
path,
|
|
41764
|
+
(current) => {
|
|
41765
|
+
const data = current ?? emptyStore();
|
|
41766
|
+
if (data.version !== 1 || !Array.isArray(data.credentials)) {
|
|
41767
|
+
return emptyStore();
|
|
41768
|
+
}
|
|
41769
|
+
const before = data.credentials.length;
|
|
41770
|
+
data.credentials = data.credentials.filter(
|
|
41771
|
+
(c) => !(c.provider === provider && c.label === label)
|
|
41772
|
+
);
|
|
41773
|
+
removed = data.credentials.length < before;
|
|
41774
|
+
data.defaultStrategy ??= "priorityWithFallback";
|
|
41775
|
+
return data;
|
|
41776
|
+
},
|
|
41777
|
+
// SECURITY (S-01/S-02): see addCredential for rationale.
|
|
41778
|
+
{ mode: 384 }
|
|
41779
|
+
);
|
|
41780
|
+
if (removed) clearAnthropicKeyCache();
|
|
41781
|
+
return removed;
|
|
41782
|
+
}
|
|
41735
41783
|
async function pickCredentialForProvider(provider, opts = {}) {
|
|
41736
41784
|
return pickCredentialForProviderSync(provider, opts);
|
|
41737
41785
|
}
|
|
@@ -41871,7 +41919,7 @@ var init_gemini = __esm({
|
|
|
41871
41919
|
// packages/core/src/llm/stable-device-id.ts
|
|
41872
41920
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
41873
41921
|
import { existsSync as existsSync23, mkdirSync as mkdirSync8, readFileSync as readFileSync14, renameSync as renameSync6, writeFileSync as writeFileSync8 } from "node:fs";
|
|
41874
|
-
import { dirname as
|
|
41922
|
+
import { dirname as dirname9, join as join24 } from "node:path";
|
|
41875
41923
|
import { getCleoHome as getCleoHome8 } from "@cleocode/paths";
|
|
41876
41924
|
function getStableDeviceId() {
|
|
41877
41925
|
if (_cachedDeviceId !== null) return _cachedDeviceId;
|
|
@@ -41888,7 +41936,7 @@ function getStableDeviceId() {
|
|
|
41888
41936
|
}
|
|
41889
41937
|
const fresh = randomUUID2();
|
|
41890
41938
|
try {
|
|
41891
|
-
const dir =
|
|
41939
|
+
const dir = dirname9(path);
|
|
41892
41940
|
if (!existsSync23(dir)) {
|
|
41893
41941
|
mkdirSync8(dir, { recursive: true });
|
|
41894
41942
|
}
|
|
@@ -42034,11 +42082,11 @@ var init_ollama = __esm({
|
|
|
42034
42082
|
displayName: "Ollama (local)",
|
|
42035
42083
|
authTypes: ["api_key"],
|
|
42036
42084
|
baseUrl: "http://localhost:11434",
|
|
42037
|
-
defaultModel: "
|
|
42085
|
+
defaultModel: "gemma4:e4b",
|
|
42038
42086
|
aliases: ["ollama-local"],
|
|
42039
42087
|
// Hermes-parity routing/catalog fields (T11756). Local on-device tier.
|
|
42040
42088
|
tier: "local",
|
|
42041
|
-
defaultAuxModel: "
|
|
42089
|
+
defaultAuxModel: "gemma4:e2b",
|
|
42042
42090
|
defaultMaxTokens: 2048,
|
|
42043
42091
|
envVars: ["OLLAMA_API_KEY", "OLLAMA_BASE_URL"],
|
|
42044
42092
|
supportsThinkingBudget: false
|
|
@@ -42272,6 +42320,15 @@ var init_loader = __esm({
|
|
|
42272
42320
|
});
|
|
42273
42321
|
|
|
42274
42322
|
// packages/core/src/llm/provider-registry/index.ts
|
|
42323
|
+
var provider_registry_exports = {};
|
|
42324
|
+
__export(provider_registry_exports, {
|
|
42325
|
+
_resetRegistryForTesting: () => _resetRegistryForTesting,
|
|
42326
|
+
discoverPlugins: () => discoverPlugins,
|
|
42327
|
+
ensureDiscovered: () => ensureDiscovered,
|
|
42328
|
+
getProviderProfile: () => getProviderProfile,
|
|
42329
|
+
listProviders: () => listProviders,
|
|
42330
|
+
registerProvider: () => registerProvider
|
|
42331
|
+
});
|
|
42275
42332
|
function registerProvider(profile) {
|
|
42276
42333
|
const key = profile.name.toLowerCase();
|
|
42277
42334
|
_registry.set(key, profile);
|
|
@@ -42294,12 +42351,25 @@ async function ensureDiscovered() {
|
|
|
42294
42351
|
}
|
|
42295
42352
|
return _discoveryPromise;
|
|
42296
42353
|
}
|
|
42354
|
+
async function discoverPlugins() {
|
|
42355
|
+
return ensureDiscovered();
|
|
42356
|
+
}
|
|
42297
42357
|
async function getProviderProfile(name15) {
|
|
42298
42358
|
await ensureDiscovered();
|
|
42299
42359
|
const key = name15.toLowerCase();
|
|
42300
42360
|
const canonical = _aliases.get(key) ?? key;
|
|
42301
42361
|
return _registry.get(canonical);
|
|
42302
42362
|
}
|
|
42363
|
+
async function listProviders() {
|
|
42364
|
+
await ensureDiscovered();
|
|
42365
|
+
const profiles = [..._registry.values()];
|
|
42366
|
+
return profiles.sort((a, b) => a.name.localeCompare(b.name));
|
|
42367
|
+
}
|
|
42368
|
+
function _resetRegistryForTesting() {
|
|
42369
|
+
_registry.clear();
|
|
42370
|
+
_aliases.clear();
|
|
42371
|
+
_discoveryPromise = null;
|
|
42372
|
+
}
|
|
42303
42373
|
var _registry, _aliases, _discoveryPromise, BUILTIN_PROFILES;
|
|
42304
42374
|
var init_provider_registry = __esm({
|
|
42305
42375
|
"packages/core/src/llm/provider-registry/index.ts"() {
|
|
@@ -43232,6 +43302,38 @@ var init_error_classifier = __esm({
|
|
|
43232
43302
|
});
|
|
43233
43303
|
|
|
43234
43304
|
// packages/core/src/llm/catalog-cache.ts
|
|
43305
|
+
import {
|
|
43306
|
+
existsSync as existsSync25,
|
|
43307
|
+
mkdirSync as mkdirSync10,
|
|
43308
|
+
readdirSync as readdirSync6,
|
|
43309
|
+
readFileSync as readFileSync15,
|
|
43310
|
+
statSync as statSync8,
|
|
43311
|
+
symlinkSync,
|
|
43312
|
+
unlinkSync as unlinkSync7,
|
|
43313
|
+
writeFileSync as writeFileSync9
|
|
43314
|
+
} from "node:fs";
|
|
43315
|
+
import { homedir as homedir4 } from "node:os";
|
|
43316
|
+
import { join as join27 } from "node:path";
|
|
43317
|
+
function getCatalogDir() {
|
|
43318
|
+
if (process.env["CLEO_DATA_DIR"]) {
|
|
43319
|
+
return join27(process.env["CLEO_DATA_DIR"], "llm-catalog");
|
|
43320
|
+
}
|
|
43321
|
+
const xdg = process.env["XDG_DATA_HOME"] ?? join27(homedir4(), ".local", "share");
|
|
43322
|
+
return join27(xdg, "cleo", "llm-catalog");
|
|
43323
|
+
}
|
|
43324
|
+
function findLatestCacheFile(dir) {
|
|
43325
|
+
if (!existsSync25(dir)) return null;
|
|
43326
|
+
const files = readdirSync6(dir).filter((f) => f.endsWith("-models.json")).map((f) => ({ name: f, mtime: statSync8(join27(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
43327
|
+
return files.length > 0 ? join27(dir, files[0].name) : null;
|
|
43328
|
+
}
|
|
43329
|
+
function readCacheFile(filePath) {
|
|
43330
|
+
try {
|
|
43331
|
+
const raw = readFileSync15(filePath, "utf-8");
|
|
43332
|
+
return JSON.parse(raw);
|
|
43333
|
+
} catch {
|
|
43334
|
+
return null;
|
|
43335
|
+
}
|
|
43336
|
+
}
|
|
43235
43337
|
var init_catalog_cache = __esm({
|
|
43236
43338
|
"packages/core/src/llm/catalog-cache.ts"() {
|
|
43237
43339
|
"use strict";
|
|
@@ -43239,16 +43341,16 @@ var init_catalog_cache = __esm({
|
|
|
43239
43341
|
});
|
|
43240
43342
|
|
|
43241
43343
|
// packages/core/src/llm/model-metadata.ts
|
|
43242
|
-
import { readFileSync as
|
|
43243
|
-
import { dirname as
|
|
43344
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
43345
|
+
import { dirname as dirname10, join as join28 } from "node:path";
|
|
43244
43346
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
43245
43347
|
function getCuratedTable() {
|
|
43246
43348
|
if (_curated !== void 0) {
|
|
43247
43349
|
return _curated;
|
|
43248
43350
|
}
|
|
43249
|
-
const thisDir =
|
|
43250
|
-
const jsonPath =
|
|
43251
|
-
const raw = JSON.parse(
|
|
43351
|
+
const thisDir = dirname10(fileURLToPath3(import.meta.url));
|
|
43352
|
+
const jsonPath = join28(thisDir, "curated-models.json");
|
|
43353
|
+
const raw = JSON.parse(readFileSync16(jsonPath, "utf-8"));
|
|
43252
43354
|
_curated = raw.models;
|
|
43253
43355
|
return _curated;
|
|
43254
43356
|
}
|
|
@@ -46088,7 +46190,69 @@ var init_chat_completions = __esm({
|
|
|
46088
46190
|
});
|
|
46089
46191
|
|
|
46090
46192
|
// packages/core/src/llm/transports/codex-responses.ts
|
|
46091
|
-
|
|
46193
|
+
function resolveCodexUrl(baseUrl) {
|
|
46194
|
+
const DEFAULT_BASE = "https://chatgpt.com/backend-api";
|
|
46195
|
+
const raw = baseUrl?.trim() ? baseUrl.trim() : DEFAULT_BASE;
|
|
46196
|
+
const normalized = raw.replace(/\/+$/, "");
|
|
46197
|
+
if (normalized.endsWith("/codex/responses")) return normalized;
|
|
46198
|
+
if (normalized.endsWith("/codex")) return `${normalized}/responses`;
|
|
46199
|
+
return `${normalized}/codex/responses`;
|
|
46200
|
+
}
|
|
46201
|
+
async function buildHttpError(res) {
|
|
46202
|
+
let bodyDetail = "";
|
|
46203
|
+
try {
|
|
46204
|
+
const text3 = await res.text();
|
|
46205
|
+
if (text3) {
|
|
46206
|
+
try {
|
|
46207
|
+
const parsed = JSON.parse(text3);
|
|
46208
|
+
const err = parsed["error"];
|
|
46209
|
+
bodyDetail = err?.["message"] ?? text3;
|
|
46210
|
+
} catch {
|
|
46211
|
+
bodyDetail = text3;
|
|
46212
|
+
}
|
|
46213
|
+
}
|
|
46214
|
+
} catch {
|
|
46215
|
+
}
|
|
46216
|
+
return bodyDetail ? `${res.status} ${bodyDetail}` : `${res.status} status code (no body)`;
|
|
46217
|
+
}
|
|
46218
|
+
function buildInputItems(request) {
|
|
46219
|
+
const items = [];
|
|
46220
|
+
for (const msg of request.messages) {
|
|
46221
|
+
if (msg.role === "tool") {
|
|
46222
|
+
items.push({
|
|
46223
|
+
type: "function_call_output",
|
|
46224
|
+
call_id: msg.toolUseId ?? `call_${Date.now().toString(36)}`,
|
|
46225
|
+
output: extractTextContent3(msg)
|
|
46226
|
+
});
|
|
46227
|
+
continue;
|
|
46228
|
+
}
|
|
46229
|
+
const contentItems = buildContentList(msg);
|
|
46230
|
+
if (contentItems.length === 1 && contentItems[0]?.["type"] === "input_text") {
|
|
46231
|
+
items.push({
|
|
46232
|
+
type: "message",
|
|
46233
|
+
role: msg.role === "assistant" ? "assistant" : "user",
|
|
46234
|
+
content: contentItems[0]["text"]
|
|
46235
|
+
});
|
|
46236
|
+
} else {
|
|
46237
|
+
items.push({
|
|
46238
|
+
type: "message",
|
|
46239
|
+
role: msg.role === "assistant" ? "assistant" : "user",
|
|
46240
|
+
content: contentItems
|
|
46241
|
+
});
|
|
46242
|
+
}
|
|
46243
|
+
}
|
|
46244
|
+
return items;
|
|
46245
|
+
}
|
|
46246
|
+
function buildTools(tools) {
|
|
46247
|
+
if (!tools || tools.length === 0) return [];
|
|
46248
|
+
return tools.map((t) => ({
|
|
46249
|
+
type: "function",
|
|
46250
|
+
name: t.name,
|
|
46251
|
+
description: t.description,
|
|
46252
|
+
parameters: t.inputSchema,
|
|
46253
|
+
strict: false
|
|
46254
|
+
}));
|
|
46255
|
+
}
|
|
46092
46256
|
function extractTextContent3(message) {
|
|
46093
46257
|
if (typeof message.content === "string") return message.content;
|
|
46094
46258
|
return message.content.filter(
|
|
@@ -46108,38 +46272,77 @@ function buildContentList(message) {
|
|
|
46108
46272
|
return { type: "input_image", image_url: imageUrl, detail: "auto" };
|
|
46109
46273
|
});
|
|
46110
46274
|
}
|
|
46111
|
-
function extractTextFromOutput(output) {
|
|
46112
|
-
const parts = [];
|
|
46113
|
-
for (const item of output) {
|
|
46114
|
-
const it = item;
|
|
46115
|
-
if (it["type"] !== "message") continue;
|
|
46116
|
-
const content = it["content"];
|
|
46117
|
-
if (!Array.isArray(content)) continue;
|
|
46118
|
-
for (const part of content) {
|
|
46119
|
-
if (part["type"] === "output_text" && typeof part["text"] === "string") {
|
|
46120
|
-
parts.push(part["text"]);
|
|
46121
|
-
}
|
|
46122
|
-
}
|
|
46123
|
-
}
|
|
46124
|
-
return parts.join("");
|
|
46125
|
-
}
|
|
46126
46275
|
function extractToolCallsFromOutput(output) {
|
|
46127
46276
|
const calls = [];
|
|
46128
46277
|
for (const item of output) {
|
|
46129
|
-
|
|
46130
|
-
if (it["type"] !== "function_call") continue;
|
|
46278
|
+
if (item["type"] !== "function_call") continue;
|
|
46131
46279
|
calls.push({
|
|
46132
|
-
id: typeof
|
|
46133
|
-
name: typeof
|
|
46134
|
-
arguments: typeof
|
|
46280
|
+
id: typeof item["call_id"] === "string" ? item["call_id"] : null,
|
|
46281
|
+
name: typeof item["name"] === "string" ? item["name"] : "unknown",
|
|
46282
|
+
arguments: typeof item["arguments"] === "string" ? item["arguments"] : "{}",
|
|
46135
46283
|
providerData: {
|
|
46136
|
-
call_id:
|
|
46137
|
-
response_item_id:
|
|
46284
|
+
call_id: item["call_id"],
|
|
46285
|
+
response_item_id: item["id"]
|
|
46138
46286
|
}
|
|
46139
46287
|
});
|
|
46140
46288
|
}
|
|
46141
46289
|
return calls;
|
|
46142
46290
|
}
|
|
46291
|
+
function normalizeUsage(usage) {
|
|
46292
|
+
const inputTokens = usage["input_tokens"] ?? 0;
|
|
46293
|
+
const outputTokens = usage["output_tokens"] ?? 0;
|
|
46294
|
+
const normalized = { inputTokens, outputTokens };
|
|
46295
|
+
const details = usage["input_tokens_details"];
|
|
46296
|
+
const cached2 = details?.["cached_tokens"];
|
|
46297
|
+
if (typeof cached2 === "number" && cached2 > 0) {
|
|
46298
|
+
normalized.cachedTokens = cached2;
|
|
46299
|
+
}
|
|
46300
|
+
return normalized;
|
|
46301
|
+
}
|
|
46302
|
+
async function* parseSSE(body, signal) {
|
|
46303
|
+
const reader = body.getReader();
|
|
46304
|
+
const decoder = new TextDecoder();
|
|
46305
|
+
let buffer = "";
|
|
46306
|
+
const onAbort = () => {
|
|
46307
|
+
void reader.cancel().catch(() => void 0);
|
|
46308
|
+
};
|
|
46309
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
46310
|
+
try {
|
|
46311
|
+
while (true) {
|
|
46312
|
+
if (signal?.aborted) throw new Error("Request was aborted");
|
|
46313
|
+
const { done, value } = await reader.read();
|
|
46314
|
+
if (signal?.aborted) throw new Error("Request was aborted");
|
|
46315
|
+
if (done) break;
|
|
46316
|
+
buffer += decoder.decode(value, { stream: true });
|
|
46317
|
+
let idx = buffer.indexOf("\n\n");
|
|
46318
|
+
while (idx !== -1) {
|
|
46319
|
+
const chunk = buffer.slice(0, idx);
|
|
46320
|
+
buffer = buffer.slice(idx + 2);
|
|
46321
|
+
const dataLines = chunk.split("\n").filter((l) => l.startsWith("data:")).map((l) => l.slice(5).trim());
|
|
46322
|
+
if (dataLines.length > 0) {
|
|
46323
|
+
const data = dataLines.join("\n").trim();
|
|
46324
|
+
if (data && data !== "[DONE]") {
|
|
46325
|
+
try {
|
|
46326
|
+
yield JSON.parse(data);
|
|
46327
|
+
} catch {
|
|
46328
|
+
}
|
|
46329
|
+
}
|
|
46330
|
+
}
|
|
46331
|
+
idx = buffer.indexOf("\n\n");
|
|
46332
|
+
}
|
|
46333
|
+
}
|
|
46334
|
+
} finally {
|
|
46335
|
+
signal?.removeEventListener("abort", onAbort);
|
|
46336
|
+
try {
|
|
46337
|
+
await reader.cancel();
|
|
46338
|
+
} catch {
|
|
46339
|
+
}
|
|
46340
|
+
try {
|
|
46341
|
+
reader.releaseLock();
|
|
46342
|
+
} catch {
|
|
46343
|
+
}
|
|
46344
|
+
}
|
|
46345
|
+
}
|
|
46143
46346
|
var CodexResponsesTransport;
|
|
46144
46347
|
var init_codex_responses = __esm({
|
|
46145
46348
|
"packages/core/src/llm/transports/codex-responses.ts"() {
|
|
@@ -46156,111 +46359,207 @@ var init_codex_responses = __esm({
|
|
|
46156
46359
|
* @see ADR-072 §Type lock-in
|
|
46157
46360
|
*/
|
|
46158
46361
|
apiMode = "codex_responses";
|
|
46159
|
-
/**
|
|
46160
|
-
|
|
46362
|
+
/** API key / OAuth bearer token. */
|
|
46363
|
+
_apiKey;
|
|
46364
|
+
/**
|
|
46365
|
+
* Resolved endpoint URL (the full `/codex/responses` path).
|
|
46366
|
+
* Derived once at construction so the URL normalisation runs once.
|
|
46367
|
+
*/
|
|
46368
|
+
_endpointUrl;
|
|
46369
|
+
/** Extra headers merged into every request (auth, originator, etc.). */
|
|
46370
|
+
_defaultHeaders;
|
|
46161
46371
|
/**
|
|
46162
46372
|
* Construct a CodexResponsesTransport.
|
|
46163
46373
|
*
|
|
46164
|
-
* @param opts - Construction options
|
|
46165
|
-
*
|
|
46374
|
+
* @param opts - Construction options: provider, API key, optional base URL
|
|
46375
|
+
* and default headers (auth + Cloudflare-bypass headers for OAuth callers).
|
|
46166
46376
|
*/
|
|
46167
46377
|
constructor(opts) {
|
|
46168
46378
|
this.provider = opts.provider;
|
|
46169
|
-
this.
|
|
46170
|
-
|
|
46171
|
-
|
|
46172
|
-
defaultHeaders: opts.defaultHeaders
|
|
46173
|
-
});
|
|
46379
|
+
this._apiKey = opts.apiKey;
|
|
46380
|
+
this._endpointUrl = resolveCodexUrl(opts.baseUrl);
|
|
46381
|
+
this._defaultHeaders = opts.defaultHeaders ?? {};
|
|
46174
46382
|
}
|
|
46383
|
+
// ---------------------------------------------------------------------------
|
|
46384
|
+
// LlmTransport — complete()
|
|
46385
|
+
// ---------------------------------------------------------------------------
|
|
46175
46386
|
/**
|
|
46176
|
-
* Execute a single completion using the
|
|
46387
|
+
* Execute a single (non-streaming) completion using the Responses API.
|
|
46177
46388
|
*
|
|
46178
|
-
*
|
|
46179
|
-
* `
|
|
46180
|
-
*
|
|
46389
|
+
* The Codex ChatGPT backend mandates `stream: true` on every request and
|
|
46390
|
+
* returns `400 {"detail":"Stream must be set to true"}` for `stream: false`.
|
|
46391
|
+
* This method therefore always sends `stream: true` with
|
|
46392
|
+
* `Accept: text/event-stream`, internally consumes the SSE stream, and
|
|
46393
|
+
* aggregates text deltas + tool calls + usage into a {@link NormalizedResponse}
|
|
46394
|
+
* — identical to calling `stream()` and collecting all chunks.
|
|
46181
46395
|
*
|
|
46182
46396
|
* @param request - Provider-neutral request parameters.
|
|
46183
46397
|
* @param _ctx - Transport context (unused; `request.signal` handles abort).
|
|
46184
46398
|
* @returns Normalized response envelope.
|
|
46185
46399
|
*/
|
|
46186
46400
|
async complete(request, _ctx) {
|
|
46187
|
-
const
|
|
46188
|
-
const
|
|
46189
|
-
const
|
|
46190
|
-
|
|
46191
|
-
|
|
46192
|
-
|
|
46193
|
-
|
|
46401
|
+
const body = this._buildBody(request, true);
|
|
46402
|
+
const headers = this._buildHeaders(true);
|
|
46403
|
+
const res = await fetch(this._endpointUrl, {
|
|
46404
|
+
method: "POST",
|
|
46405
|
+
headers,
|
|
46406
|
+
body: JSON.stringify(body),
|
|
46407
|
+
signal: request.signal
|
|
46408
|
+
});
|
|
46409
|
+
if (!res.ok) {
|
|
46410
|
+
throw new Error(await buildHttpError(res));
|
|
46411
|
+
}
|
|
46412
|
+
if (!res.body) {
|
|
46413
|
+
throw new Error("codex_responses: response body is null (no SSE stream)");
|
|
46414
|
+
}
|
|
46415
|
+
const textParts = [];
|
|
46416
|
+
const toolCalls = [];
|
|
46417
|
+
let finalUsage = null;
|
|
46418
|
+
let finishReason = null;
|
|
46419
|
+
let responseId = null;
|
|
46420
|
+
let responseModel = null;
|
|
46421
|
+
for await (const event of parseSSE(res.body, request.signal)) {
|
|
46422
|
+
const evType = event["type"];
|
|
46423
|
+
if (evType === "response.output_text.delta") {
|
|
46424
|
+
const delta = event["delta"];
|
|
46425
|
+
if (delta) textParts.push(delta);
|
|
46426
|
+
continue;
|
|
46427
|
+
}
|
|
46428
|
+
if (evType === "response.output_item.done") {
|
|
46429
|
+
const item = event["item"];
|
|
46430
|
+
if (item?.["type"] === "function_call") {
|
|
46431
|
+
toolCalls.push({
|
|
46432
|
+
id: typeof item["call_id"] === "string" ? item["call_id"] : null,
|
|
46433
|
+
name: typeof item["name"] === "string" ? item["name"] : "unknown",
|
|
46434
|
+
arguments: typeof item["arguments"] === "string" ? item["arguments"] : "{}",
|
|
46435
|
+
providerData: {
|
|
46436
|
+
call_id: item["call_id"],
|
|
46437
|
+
response_item_id: item["id"]
|
|
46438
|
+
}
|
|
46439
|
+
});
|
|
46440
|
+
}
|
|
46441
|
+
continue;
|
|
46442
|
+
}
|
|
46443
|
+
if (evType === "response.completed") {
|
|
46444
|
+
const completedResponse = event["response"];
|
|
46445
|
+
if (completedResponse) {
|
|
46446
|
+
finishReason = completedResponse["status"] ?? "completed";
|
|
46447
|
+
responseId = completedResponse["id"] ?? null;
|
|
46448
|
+
responseModel = completedResponse["model"] ?? null;
|
|
46449
|
+
const usage = completedResponse["usage"];
|
|
46450
|
+
if (usage) finalUsage = normalizeUsage(usage);
|
|
46451
|
+
const output = completedResponse["output"] ?? [];
|
|
46452
|
+
const embeddedCalls = extractToolCallsFromOutput(
|
|
46453
|
+
output
|
|
46454
|
+
);
|
|
46455
|
+
if (embeddedCalls.length > 0 && toolCalls.length === 0) {
|
|
46456
|
+
toolCalls.push(...embeddedCalls);
|
|
46457
|
+
}
|
|
46458
|
+
}
|
|
46459
|
+
break;
|
|
46460
|
+
}
|
|
46461
|
+
if (evType === "response.failed" || evType === "response.incomplete") {
|
|
46462
|
+
const failedResponse = event["response"];
|
|
46463
|
+
if (failedResponse) {
|
|
46464
|
+
finishReason = failedResponse["status"] ?? evType;
|
|
46465
|
+
const usage = failedResponse["usage"];
|
|
46466
|
+
if (usage) finalUsage = normalizeUsage(usage);
|
|
46467
|
+
}
|
|
46468
|
+
break;
|
|
46469
|
+
}
|
|
46470
|
+
if (evType === "error") {
|
|
46471
|
+
const code = event["code"];
|
|
46472
|
+
const message = event["message"];
|
|
46473
|
+
throw new Error(`Codex error: ${message ?? code ?? JSON.stringify(event)}`);
|
|
46474
|
+
}
|
|
46475
|
+
}
|
|
46476
|
+
const content = textParts.join("") || null;
|
|
46477
|
+
return {
|
|
46478
|
+
id: responseId ?? `resp-${Date.now().toString(36)}`,
|
|
46479
|
+
model: responseModel ?? request.model,
|
|
46480
|
+
content,
|
|
46481
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : null,
|
|
46482
|
+
stopReason: finishReason ?? "completed",
|
|
46483
|
+
usage: finalUsage ?? { inputTokens: 0, outputTokens: 0 },
|
|
46484
|
+
providerData: {
|
|
46485
|
+
codex_response_id: responseId
|
|
46486
|
+
},
|
|
46487
|
+
raw: {}
|
|
46194
46488
|
};
|
|
46195
|
-
if (request.system) params["instructions"] = request.system;
|
|
46196
|
-
if (tools.length > 0) params["tools"] = tools;
|
|
46197
|
-
const response = await this._client.responses.create(
|
|
46198
|
-
params,
|
|
46199
|
-
{ signal: request.signal }
|
|
46200
|
-
);
|
|
46201
|
-
return this._normalize(response, request.model);
|
|
46202
46489
|
}
|
|
46490
|
+
// ---------------------------------------------------------------------------
|
|
46491
|
+
// LlmTransport — stream()
|
|
46492
|
+
// ---------------------------------------------------------------------------
|
|
46203
46493
|
/**
|
|
46204
|
-
* Stream a completion using the
|
|
46494
|
+
* Stream a completion using the Responses API SSE stream.
|
|
46205
46495
|
*
|
|
46206
46496
|
* Yields {@link NormalizedDelta} chunks from `response.output_text.delta`
|
|
46207
|
-
* events
|
|
46208
|
-
*
|
|
46497
|
+
* events parsed from the raw SSE stream. The final delta carries
|
|
46498
|
+
* `stopReason` and `usage` from `response.completed`.
|
|
46499
|
+
*
|
|
46500
|
+
* Wire shape:
|
|
46501
|
+
* - `store: false` (required — codex backend rejects absent or true)
|
|
46502
|
+
* - `stream: true`
|
|
46503
|
+
* - `Accept: text/event-stream`
|
|
46504
|
+
* - `OpenAI-Beta: responses=experimental`
|
|
46209
46505
|
*
|
|
46210
46506
|
* @param request - Provider-neutral request parameters.
|
|
46211
46507
|
* @param _ctx - Transport context (unused; `request.signal` handles abort).
|
|
46212
46508
|
* @returns Async iterable of normalized delta chunks.
|
|
46213
46509
|
*/
|
|
46214
46510
|
async *stream(request, _ctx) {
|
|
46215
|
-
const
|
|
46216
|
-
const
|
|
46217
|
-
const
|
|
46218
|
-
|
|
46219
|
-
|
|
46220
|
-
|
|
46221
|
-
|
|
46222
|
-
|
|
46223
|
-
|
|
46224
|
-
|
|
46225
|
-
|
|
46226
|
-
|
|
46227
|
-
|
|
46228
|
-
|
|
46229
|
-
);
|
|
46511
|
+
const body = this._buildBody(request, true);
|
|
46512
|
+
const headers = this._buildHeaders(true);
|
|
46513
|
+
const res = await fetch(this._endpointUrl, {
|
|
46514
|
+
method: "POST",
|
|
46515
|
+
headers,
|
|
46516
|
+
body: JSON.stringify(body),
|
|
46517
|
+
signal: request.signal
|
|
46518
|
+
});
|
|
46519
|
+
if (!res.ok) {
|
|
46520
|
+
throw new Error(await buildHttpError(res));
|
|
46521
|
+
}
|
|
46522
|
+
if (!res.body) {
|
|
46523
|
+
throw new Error("codex_responses: response body is null (no SSE stream)");
|
|
46524
|
+
}
|
|
46230
46525
|
let finishReason = null;
|
|
46231
46526
|
let finalUsage = null;
|
|
46232
|
-
for await (const event of
|
|
46233
|
-
const
|
|
46234
|
-
const evType = ev["type"];
|
|
46527
|
+
for await (const event of parseSSE(res.body, request.signal)) {
|
|
46528
|
+
const evType = event["type"];
|
|
46235
46529
|
if (evType === "response.output_text.delta") {
|
|
46236
|
-
const delta =
|
|
46530
|
+
const delta = event["delta"];
|
|
46237
46531
|
if (delta) {
|
|
46238
46532
|
yield { text: delta, reasoning: "", stopReason: null, usage: null };
|
|
46239
46533
|
}
|
|
46240
46534
|
continue;
|
|
46241
46535
|
}
|
|
46242
46536
|
if (evType === "response.completed") {
|
|
46243
|
-
const completedResponse =
|
|
46537
|
+
const completedResponse = event["response"];
|
|
46244
46538
|
if (completedResponse) {
|
|
46245
|
-
finishReason = completedResponse
|
|
46246
|
-
const usage = completedResponse
|
|
46539
|
+
finishReason = completedResponse["status"] ?? "completed";
|
|
46540
|
+
const usage = completedResponse["usage"];
|
|
46247
46541
|
if (usage) {
|
|
46248
|
-
finalUsage =
|
|
46542
|
+
finalUsage = normalizeUsage(usage);
|
|
46249
46543
|
}
|
|
46250
46544
|
}
|
|
46251
46545
|
break;
|
|
46252
46546
|
}
|
|
46253
46547
|
if (evType === "response.failed" || evType === "response.incomplete") {
|
|
46254
|
-
const failedResponse =
|
|
46548
|
+
const failedResponse = event["response"];
|
|
46255
46549
|
if (failedResponse) {
|
|
46256
|
-
finishReason = failedResponse
|
|
46257
|
-
const usage = failedResponse
|
|
46550
|
+
finishReason = failedResponse["status"] ?? evType;
|
|
46551
|
+
const usage = failedResponse["usage"];
|
|
46258
46552
|
if (usage) {
|
|
46259
|
-
finalUsage =
|
|
46553
|
+
finalUsage = normalizeUsage(usage);
|
|
46260
46554
|
}
|
|
46261
46555
|
}
|
|
46262
46556
|
break;
|
|
46263
46557
|
}
|
|
46558
|
+
if (evType === "error") {
|
|
46559
|
+
const code = event["code"];
|
|
46560
|
+
const message = event["message"];
|
|
46561
|
+
throw new Error(`Codex error: ${message ?? code ?? JSON.stringify(event)}`);
|
|
46562
|
+
}
|
|
46264
46563
|
}
|
|
46265
46564
|
yield {
|
|
46266
46565
|
text: "",
|
|
@@ -46270,128 +46569,60 @@ var init_codex_responses = __esm({
|
|
|
46270
46569
|
};
|
|
46271
46570
|
}
|
|
46272
46571
|
// ---------------------------------------------------------------------------
|
|
46273
|
-
//
|
|
46572
|
+
// Private helpers
|
|
46274
46573
|
// ---------------------------------------------------------------------------
|
|
46275
46574
|
/**
|
|
46276
|
-
*
|
|
46575
|
+
* Build the HTTP headers for a Codex request.
|
|
46277
46576
|
*
|
|
46278
|
-
*
|
|
46279
|
-
* -
|
|
46280
|
-
* - `
|
|
46281
|
-
*
|
|
46282
|
-
* - `
|
|
46283
|
-
* `toolUseId` as `call_id`.
|
|
46577
|
+
* Merges the auth/cloudflare headers from `_defaultHeaders` with the
|
|
46578
|
+
* mandatory Codex-specific headers:
|
|
46579
|
+
* - `OpenAI-Beta: responses=experimental`
|
|
46580
|
+
* - `content-type: application/json`
|
|
46581
|
+
* - `accept: text/event-stream` (always — both complete() and stream() use SSE)
|
|
46284
46582
|
*
|
|
46285
|
-
*
|
|
46286
|
-
* `
|
|
46287
|
-
* call round-trip), the item is converted to a `function_call` input item
|
|
46288
|
-
* so the Responses API can continue the conversation.
|
|
46583
|
+
* The Authorization header is injected only if not already present in
|
|
46584
|
+
* `_defaultHeaders` (OAuth callers pre-set it via buildCodexOAuthHeaders).
|
|
46289
46585
|
*
|
|
46290
|
-
* @param
|
|
46291
|
-
* @returns
|
|
46586
|
+
* @param streaming - Whether this is a streaming (SSE) or completion call.
|
|
46587
|
+
* @returns Plain string record of all request headers.
|
|
46292
46588
|
*/
|
|
46293
|
-
|
|
46294
|
-
const
|
|
46295
|
-
|
|
46296
|
-
|
|
46297
|
-
|
|
46298
|
-
|
|
46299
|
-
|
|
46300
|
-
|
|
46301
|
-
|
|
46302
|
-
|
|
46303
|
-
}
|
|
46304
|
-
const contentItems = buildContentList(msg);
|
|
46305
|
-
if (contentItems.length === 1 && contentItems[0]?.["type"] === "input_text") {
|
|
46306
|
-
items.push({
|
|
46307
|
-
type: "message",
|
|
46308
|
-
role: msg.role === "assistant" ? "assistant" : "user",
|
|
46309
|
-
content: contentItems[0]["text"]
|
|
46310
|
-
});
|
|
46311
|
-
} else {
|
|
46312
|
-
items.push({
|
|
46313
|
-
type: "message",
|
|
46314
|
-
role: msg.role === "assistant" ? "assistant" : "user",
|
|
46315
|
-
content: contentItems
|
|
46316
|
-
});
|
|
46317
|
-
}
|
|
46589
|
+
_buildHeaders(streaming) {
|
|
46590
|
+
const headers = {
|
|
46591
|
+
...this._defaultHeaders,
|
|
46592
|
+
"OpenAI-Beta": "responses=experimental",
|
|
46593
|
+
"content-type": "application/json",
|
|
46594
|
+
accept: streaming ? "text/event-stream" : "application/json"
|
|
46595
|
+
};
|
|
46596
|
+
const hasAuth = Object.keys(headers).some((k) => k.toLowerCase() === "authorization");
|
|
46597
|
+
if (!hasAuth) {
|
|
46598
|
+
headers["Authorization"] = `Bearer ${this._apiKey}`;
|
|
46318
46599
|
}
|
|
46319
|
-
return
|
|
46600
|
+
return headers;
|
|
46320
46601
|
}
|
|
46321
|
-
// ---------------------------------------------------------------------------
|
|
46322
|
-
// Tool conversion
|
|
46323
|
-
// ---------------------------------------------------------------------------
|
|
46324
|
-
/**
|
|
46325
|
-
* Convert provider-neutral tool definitions to the Responses API
|
|
46326
|
-
* `{type: 'function', name, description, parameters, strict}` shape.
|
|
46327
|
-
*
|
|
46328
|
-
* @param tools - Provider-neutral tool definitions (may be undefined).
|
|
46329
|
-
* @returns Responses API tool objects, or empty array.
|
|
46330
|
-
*/
|
|
46331
|
-
_buildTools(tools) {
|
|
46332
|
-
if (!tools || tools.length === 0) return [];
|
|
46333
|
-
return tools.map((t) => ({
|
|
46334
|
-
type: "function",
|
|
46335
|
-
name: t.name,
|
|
46336
|
-
description: t.description,
|
|
46337
|
-
parameters: t.inputSchema,
|
|
46338
|
-
strict: false
|
|
46339
|
-
}));
|
|
46340
|
-
}
|
|
46341
|
-
// ---------------------------------------------------------------------------
|
|
46342
|
-
// Response normalization
|
|
46343
|
-
// ---------------------------------------------------------------------------
|
|
46344
46602
|
/**
|
|
46345
|
-
*
|
|
46346
|
-
* {@link NormalizedResponse}.
|
|
46603
|
+
* Build the JSON request body for a Codex Responses API call.
|
|
46347
46604
|
*
|
|
46348
|
-
*
|
|
46349
|
-
* - `
|
|
46350
|
-
*
|
|
46351
|
-
* - `
|
|
46352
|
-
* - `stopReason` — from `response.status` (completed / failed / incomplete).
|
|
46353
|
-
* - `usage` — `input_tokens` → `inputTokens`, `output_tokens` → `outputTokens`.
|
|
46354
|
-
* - `cachedTokens` — from `usage.input_tokens_details.cached_tokens`.
|
|
46355
|
-
* - `raw` — unmodified SDK response.
|
|
46605
|
+
* Mandatory fields per the Codex backend:
|
|
46606
|
+
* - `store: false` — backend rejects absent or `true`.
|
|
46607
|
+
* - `instructions` — system prompt (defaulting to empty string when absent).
|
|
46608
|
+
* - `input` — array of Responses API input items.
|
|
46356
46609
|
*
|
|
46357
|
-
* @param
|
|
46358
|
-
* @param
|
|
46359
|
-
* @returns
|
|
46360
|
-
*/
|
|
46361
|
-
_normalize(response, requestedModel) {
|
|
46362
|
-
const content = response.output_text && response.output_text.length > 0 ? response.output_text : extractTextFromOutput(response.output);
|
|
46363
|
-
const toolCalls = extractToolCallsFromOutput(response.output);
|
|
46364
|
-
const usage = this._normalizeUsage(response.usage ?? null);
|
|
46365
|
-
return {
|
|
46366
|
-
id: response.id ?? `resp-${Date.now().toString(36)}`,
|
|
46367
|
-
model: String(response.model ?? requestedModel),
|
|
46368
|
-
content: content || null,
|
|
46369
|
-
toolCalls: toolCalls.length > 0 ? toolCalls : null,
|
|
46370
|
-
stopReason: response.status ?? "completed",
|
|
46371
|
-
usage,
|
|
46372
|
-
providerData: {
|
|
46373
|
-
codex_response_id: response.id
|
|
46374
|
-
},
|
|
46375
|
-
raw: response
|
|
46376
|
-
};
|
|
46377
|
-
}
|
|
46378
|
-
/**
|
|
46379
|
-
* Normalize OpenAI Responses API usage into {@link NormalizedUsage}.
|
|
46380
|
-
*
|
|
46381
|
-
* @param usage - Raw usage object (may be null when the API omits it).
|
|
46382
|
-
* @returns Normalized usage with optional `cachedTokens`.
|
|
46610
|
+
* @param request - Provider-neutral request.
|
|
46611
|
+
* @param streaming - Whether to enable SSE streaming.
|
|
46612
|
+
* @returns Serialisable request body.
|
|
46383
46613
|
*/
|
|
46384
|
-
|
|
46385
|
-
|
|
46386
|
-
|
|
46387
|
-
|
|
46388
|
-
|
|
46614
|
+
_buildBody(request, streaming) {
|
|
46615
|
+
const body = {
|
|
46616
|
+
model: request.model,
|
|
46617
|
+
input: buildInputItems(request),
|
|
46618
|
+
instructions: request.system ?? "",
|
|
46619
|
+
store: false,
|
|
46620
|
+
stream: streaming
|
|
46389
46621
|
};
|
|
46390
|
-
|
|
46391
|
-
|
|
46392
|
-
|
|
46393
|
-
|
|
46394
|
-
return normalized;
|
|
46622
|
+
if (request.temperature != null) body.temperature = request.temperature;
|
|
46623
|
+
const tools = buildTools(request.tools);
|
|
46624
|
+
if (tools.length > 0) body.tools = tools;
|
|
46625
|
+
return body;
|
|
46395
46626
|
}
|
|
46396
46627
|
};
|
|
46397
46628
|
}
|
|
@@ -75237,6 +75468,295 @@ var init_model_runner = __esm({
|
|
|
75237
75468
|
}
|
|
75238
75469
|
});
|
|
75239
75470
|
|
|
75471
|
+
// packages/core/src/llm/catalog-model-resolver.ts
|
|
75472
|
+
var catalog_model_resolver_exports = {};
|
|
75473
|
+
__export(catalog_model_resolver_exports, {
|
|
75474
|
+
_resetCatalogModelResolverCache: () => _resetCatalogModelResolverCache,
|
|
75475
|
+
catalogKeyForProvider: () => catalogKeyForProvider,
|
|
75476
|
+
listProviderModels: () => listProviderModels,
|
|
75477
|
+
resolveProviderDefaultModel: () => resolveProviderDefaultModel,
|
|
75478
|
+
validateModelForProvider: () => validateModelForProvider
|
|
75479
|
+
});
|
|
75480
|
+
function getDiskCatalog() {
|
|
75481
|
+
if (_catalog !== void 0) return _catalog;
|
|
75482
|
+
const dir = getCatalogDir();
|
|
75483
|
+
const latest = findLatestCacheFile(dir);
|
|
75484
|
+
if (!latest) {
|
|
75485
|
+
_catalog = null;
|
|
75486
|
+
return null;
|
|
75487
|
+
}
|
|
75488
|
+
_catalog = readCacheFile(latest);
|
|
75489
|
+
return _catalog;
|
|
75490
|
+
}
|
|
75491
|
+
function resolveProviderDefaultModel(providerCatalogKey, catalogOverride) {
|
|
75492
|
+
const catalog = catalogOverride ?? getDiskCatalog();
|
|
75493
|
+
if (!catalog) return null;
|
|
75494
|
+
const provider = catalog[providerCatalogKey];
|
|
75495
|
+
if (!provider?.models) return null;
|
|
75496
|
+
let latestId = null;
|
|
75497
|
+
let latestDate = "";
|
|
75498
|
+
for (const [id, entry] of Object.entries(provider.models)) {
|
|
75499
|
+
const rd = entry.release_date;
|
|
75500
|
+
if (!rd) continue;
|
|
75501
|
+
if (rd > latestDate) {
|
|
75502
|
+
latestDate = rd;
|
|
75503
|
+
latestId = id;
|
|
75504
|
+
}
|
|
75505
|
+
}
|
|
75506
|
+
return latestId;
|
|
75507
|
+
}
|
|
75508
|
+
function validateModelForProvider(model, providerCatalogKey, catalogOverride) {
|
|
75509
|
+
const catalog = catalogOverride ?? getDiskCatalog();
|
|
75510
|
+
if (!catalog) {
|
|
75511
|
+
return { valid: true, reason: "catalog-unavailable" };
|
|
75512
|
+
}
|
|
75513
|
+
const provider = catalog[providerCatalogKey];
|
|
75514
|
+
if (!provider?.models) {
|
|
75515
|
+
return { valid: true, reason: "provider-not-in-catalog" };
|
|
75516
|
+
}
|
|
75517
|
+
const found = Object.hasOwn(provider.models, model);
|
|
75518
|
+
return { valid: found, reason: found ? "found" : "not-found" };
|
|
75519
|
+
}
|
|
75520
|
+
function listProviderModels(providerCatalogKey, limit = 12, catalogOverride) {
|
|
75521
|
+
const catalog = catalogOverride ?? getDiskCatalog();
|
|
75522
|
+
if (!catalog) return [];
|
|
75523
|
+
const provider = catalog[providerCatalogKey];
|
|
75524
|
+
if (!provider?.models) return [];
|
|
75525
|
+
const entries = Object.entries(provider.models);
|
|
75526
|
+
const sorted = [...entries].sort(([, a], [, b]) => {
|
|
75527
|
+
const da = a.release_date ?? "";
|
|
75528
|
+
const db = b.release_date ?? "";
|
|
75529
|
+
if (da === db) return 0;
|
|
75530
|
+
return db.localeCompare(da);
|
|
75531
|
+
});
|
|
75532
|
+
return sorted.slice(0, Math.max(0, limit)).map(([id]) => id);
|
|
75533
|
+
}
|
|
75534
|
+
function catalogKeyForProvider(providerName) {
|
|
75535
|
+
const PROVIDER_KEY_MAP = {
|
|
75536
|
+
gemini: "google"
|
|
75537
|
+
// CLEO name → models.dev key overrides only (identical mappings are omitted)
|
|
75538
|
+
};
|
|
75539
|
+
return PROVIDER_KEY_MAP[providerName.toLowerCase()] ?? providerName.toLowerCase();
|
|
75540
|
+
}
|
|
75541
|
+
function _resetCatalogModelResolverCache() {
|
|
75542
|
+
_catalog = void 0;
|
|
75543
|
+
}
|
|
75544
|
+
var _catalog;
|
|
75545
|
+
var init_catalog_model_resolver = __esm({
|
|
75546
|
+
"packages/core/src/llm/catalog-model-resolver.ts"() {
|
|
75547
|
+
"use strict";
|
|
75548
|
+
init_catalog_cache();
|
|
75549
|
+
}
|
|
75550
|
+
});
|
|
75551
|
+
|
|
75552
|
+
// packages/core/src/llm/cross-provider-selector.ts
|
|
75553
|
+
import { totalmem } from "node:os";
|
|
75554
|
+
async function probeOllamaAlive(baseUrl) {
|
|
75555
|
+
const cached2 = _ollamaProbeCache.get(baseUrl);
|
|
75556
|
+
if (cached2 && Date.now() - cached2.checkedAt < OLLAMA_PROBE_TTL_MS) {
|
|
75557
|
+
return cached2.alive;
|
|
75558
|
+
}
|
|
75559
|
+
let alive = false;
|
|
75560
|
+
try {
|
|
75561
|
+
const controller = new AbortController();
|
|
75562
|
+
const timeoutId = setTimeout(() => controller.abort(), OLLAMA_PROBE_TIMEOUT_MS);
|
|
75563
|
+
try {
|
|
75564
|
+
const res = await fetch(baseUrl, { signal: controller.signal });
|
|
75565
|
+
alive = res.ok || res.status < 500;
|
|
75566
|
+
} finally {
|
|
75567
|
+
clearTimeout(timeoutId);
|
|
75568
|
+
}
|
|
75569
|
+
} catch {
|
|
75570
|
+
alive = false;
|
|
75571
|
+
}
|
|
75572
|
+
_ollamaProbeCache.set(baseUrl, { alive, checkedAt: Date.now() });
|
|
75573
|
+
return alive;
|
|
75574
|
+
}
|
|
75575
|
+
function ollamaDefaultModelForTier(tier, ramBytesOverride) {
|
|
75576
|
+
const ramBytes = ramBytesOverride ?? totalmem();
|
|
75577
|
+
const gb = ramBytes / 1024 ** 3;
|
|
75578
|
+
if (gb >= 8) {
|
|
75579
|
+
return tier === "fast" || tier === "local" ? "gemma4:e2b" : "gemma4:e4b";
|
|
75580
|
+
}
|
|
75581
|
+
if (gb >= 4) {
|
|
75582
|
+
return "gemma4:e2b";
|
|
75583
|
+
}
|
|
75584
|
+
logger4.warn(
|
|
75585
|
+
{ ramGb: gb.toFixed(1), tier },
|
|
75586
|
+
"cross-provider-selector: RAM < 4 GB; selecting qwen2:0.5b (proof-of-life only \u2014 not suitable for production)"
|
|
75587
|
+
);
|
|
75588
|
+
return "qwen2:0.5b";
|
|
75589
|
+
}
|
|
75590
|
+
function isProvisioned(provider) {
|
|
75591
|
+
if (provider === "ollama") {
|
|
75592
|
+
if (process.env["OLLAMA_HOST"]?.trim()) return true;
|
|
75593
|
+
const stored = pickCredentialForProviderSync(provider, { strategy: "priorityOnly" });
|
|
75594
|
+
return stored !== null;
|
|
75595
|
+
}
|
|
75596
|
+
const cred = resolveCredentials(provider);
|
|
75597
|
+
return (cred.apiKey?.trim().length ?? 0) > 0;
|
|
75598
|
+
}
|
|
75599
|
+
function scoreProvider(provider, providerTier, taskTier, ollamaAlive, costInputPerMillion) {
|
|
75600
|
+
let score = TIER_BASE[providerTier];
|
|
75601
|
+
if (taskTier === "frontier" && providerTier === "frontier") {
|
|
75602
|
+
score += TASK_MATCH_BONUS_FRONTIER;
|
|
75603
|
+
} else if ((taskTier === "fast" || taskTier === "local") && (providerTier === "fast" || providerTier === "local")) {
|
|
75604
|
+
score += TASK_MATCH_BONUS_FAST;
|
|
75605
|
+
}
|
|
75606
|
+
if (providerTier === "local" && ollamaAlive) {
|
|
75607
|
+
score += LOCALITY_BONUS;
|
|
75608
|
+
}
|
|
75609
|
+
if ((providerTier === "frontier" || providerTier === "standard") && provider !== "ollama") {
|
|
75610
|
+
score += PROVISIONED_CLOUD_BIAS;
|
|
75611
|
+
}
|
|
75612
|
+
const penalty = Math.min(Math.floor(costInputPerMillion / 10), MAX_COST_PENALTY);
|
|
75613
|
+
score -= penalty;
|
|
75614
|
+
return score;
|
|
75615
|
+
}
|
|
75616
|
+
function roleTierFor(role) {
|
|
75617
|
+
switch (role) {
|
|
75618
|
+
case "consolidation":
|
|
75619
|
+
case "judgement":
|
|
75620
|
+
case "hygiene":
|
|
75621
|
+
return "frontier";
|
|
75622
|
+
case "extraction":
|
|
75623
|
+
case "derivation":
|
|
75624
|
+
return "standard";
|
|
75625
|
+
default:
|
|
75626
|
+
return "fast";
|
|
75627
|
+
}
|
|
75628
|
+
}
|
|
75629
|
+
async function selectBestProvisioned(role, opts) {
|
|
75630
|
+
const taskTier = roleTierFor(role);
|
|
75631
|
+
const provisionedIds = [];
|
|
75632
|
+
for (const id of BUILTIN_PROVIDER_IDS) {
|
|
75633
|
+
if (isProvisioned(id)) {
|
|
75634
|
+
provisionedIds.push(id);
|
|
75635
|
+
}
|
|
75636
|
+
}
|
|
75637
|
+
if (provisionedIds.length === 0) {
|
|
75638
|
+
logger4.warn(
|
|
75639
|
+
{
|
|
75640
|
+
providers_checked: BUILTIN_PROVIDER_IDS.slice(),
|
|
75641
|
+
reason: "no-provisioned-provider",
|
|
75642
|
+
role,
|
|
75643
|
+
projectRoot: opts.projectRoot
|
|
75644
|
+
},
|
|
75645
|
+
"resolveLLMForSystem: no provider has a usable credential; returning null-credential envelope"
|
|
75646
|
+
);
|
|
75647
|
+
return null;
|
|
75648
|
+
}
|
|
75649
|
+
const { getProviderProfile: getProviderProfile2 } = await Promise.resolve().then(() => (init_provider_registry(), provider_registry_exports));
|
|
75650
|
+
const { resolveProviderDefaultModel: resolveProviderDefaultModel2, catalogKeyForProvider: catalogKeyForProvider2 } = await Promise.resolve().then(() => (init_catalog_model_resolver(), catalog_model_resolver_exports));
|
|
75651
|
+
const { pickCredentialForProvider: pickCredentialForProvider2 } = await Promise.resolve().then(() => (init_credentials_store(), credentials_store_exports));
|
|
75652
|
+
const ollamaProvisioned = provisionedIds.includes("ollama");
|
|
75653
|
+
let ollamaAlive = false;
|
|
75654
|
+
if (ollamaProvisioned) {
|
|
75655
|
+
const profile = await getProviderProfile2("ollama");
|
|
75656
|
+
const ollamaBase = profile?.baseUrl ?? "http://localhost:11434";
|
|
75657
|
+
ollamaAlive = await probeOllamaAlive(ollamaBase);
|
|
75658
|
+
}
|
|
75659
|
+
const scored = [];
|
|
75660
|
+
for (const id of provisionedIds) {
|
|
75661
|
+
const profile = await getProviderProfile2(id);
|
|
75662
|
+
const tier = profile?.tier ?? "standard";
|
|
75663
|
+
const costInput = 0;
|
|
75664
|
+
const score = scoreProvider(id, tier, taskTier, ollamaAlive, costInput);
|
|
75665
|
+
const storedCred = await pickCredentialForProvider2(id, { strategy: "priorityOnly" });
|
|
75666
|
+
const credentialPriority = storedCred?.priority ?? Number.MAX_SAFE_INTEGER;
|
|
75667
|
+
scored.push({ id, tier, score, credentialPriority });
|
|
75668
|
+
}
|
|
75669
|
+
scored.sort((a, b) => {
|
|
75670
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
75671
|
+
return a.credentialPriority - b.credentialPriority;
|
|
75672
|
+
});
|
|
75673
|
+
const winner = scored[0];
|
|
75674
|
+
if (!winner) return null;
|
|
75675
|
+
let model;
|
|
75676
|
+
if (winner.id === "ollama") {
|
|
75677
|
+
const ollamaProfile2 = await getProviderProfile2("ollama");
|
|
75678
|
+
const ramBytes = totalmem();
|
|
75679
|
+
const gb = ramBytes / 1024 ** 3;
|
|
75680
|
+
if (gb >= 8) {
|
|
75681
|
+
model = (winner.tier === "fast" || taskTier === "fast" ? ollamaProfile2?.defaultAuxModel : ollamaProfile2?.defaultModel) ?? ollamaDefaultModelForTier(winner.tier);
|
|
75682
|
+
} else if (gb >= 4) {
|
|
75683
|
+
model = ollamaProfile2?.defaultAuxModel ?? "gemma4:e2b";
|
|
75684
|
+
} else {
|
|
75685
|
+
model = ollamaDefaultModelForTier(winner.tier, ramBytes);
|
|
75686
|
+
}
|
|
75687
|
+
const catalogKey = catalogKeyForProvider2(winner.id);
|
|
75688
|
+
const catalogModel = resolveProviderDefaultModel2(catalogKey);
|
|
75689
|
+
if (!catalogModel?.startsWith("gemma4")) {
|
|
75690
|
+
logger4.info(
|
|
75691
|
+
{ provider: "ollama", selectedModel: model },
|
|
75692
|
+
"cross-provider-selector: gemma4 family not in catalog snapshot \u2014 run `cleo llm refresh-catalog` to pull latest"
|
|
75693
|
+
);
|
|
75694
|
+
}
|
|
75695
|
+
} else {
|
|
75696
|
+
try {
|
|
75697
|
+
const catalogKey = catalogKeyForProvider2(winner.id);
|
|
75698
|
+
const catalogModel = resolveProviderDefaultModel2(catalogKey);
|
|
75699
|
+
const profileModel = (await getProviderProfile2(winner.id))?.defaultModel;
|
|
75700
|
+
model = catalogModel ?? profileModel ?? "unknown";
|
|
75701
|
+
} catch {
|
|
75702
|
+
model = (await getProviderProfile2(winner.id))?.defaultModel ?? "unknown";
|
|
75703
|
+
}
|
|
75704
|
+
}
|
|
75705
|
+
logger4.debug(
|
|
75706
|
+
{
|
|
75707
|
+
winner: winner.id,
|
|
75708
|
+
score: winner.score,
|
|
75709
|
+
taskTier,
|
|
75710
|
+
model,
|
|
75711
|
+
provisionedCount: provisionedIds.length
|
|
75712
|
+
},
|
|
75713
|
+
"cross-provider-selector: selected best provisioned provider"
|
|
75714
|
+
);
|
|
75715
|
+
return {
|
|
75716
|
+
provider: winner.id,
|
|
75717
|
+
model,
|
|
75718
|
+
credentialLabel: void 0,
|
|
75719
|
+
source: "cross-provider"
|
|
75720
|
+
};
|
|
75721
|
+
}
|
|
75722
|
+
var logger4, BUILTIN_PROVIDER_IDS, TIER_BASE, PROVISIONED_CLOUD_BIAS, LOCALITY_BONUS, TASK_MATCH_BONUS_FRONTIER, TASK_MATCH_BONUS_FAST, MAX_COST_PENALTY, OLLAMA_PROBE_TIMEOUT_MS, OLLAMA_PROBE_TTL_MS, _ollamaProbeCache;
|
|
75723
|
+
var init_cross_provider_selector = __esm({
|
|
75724
|
+
"packages/core/src/llm/cross-provider-selector.ts"() {
|
|
75725
|
+
"use strict";
|
|
75726
|
+
init_logger2();
|
|
75727
|
+
init_credentials2();
|
|
75728
|
+
init_credentials_store();
|
|
75729
|
+
logger4 = getLogger("llm-cross-provider-selector");
|
|
75730
|
+
BUILTIN_PROVIDER_IDS = [
|
|
75731
|
+
"anthropic",
|
|
75732
|
+
"openai",
|
|
75733
|
+
"gemini",
|
|
75734
|
+
"moonshot",
|
|
75735
|
+
"openrouter",
|
|
75736
|
+
"bedrock",
|
|
75737
|
+
"deepseek",
|
|
75738
|
+
"xai",
|
|
75739
|
+
"groq",
|
|
75740
|
+
"kimi-code",
|
|
75741
|
+
"ollama"
|
|
75742
|
+
];
|
|
75743
|
+
TIER_BASE = {
|
|
75744
|
+
frontier: 100,
|
|
75745
|
+
standard: 70,
|
|
75746
|
+
fast: 50,
|
|
75747
|
+
local: 120
|
|
75748
|
+
};
|
|
75749
|
+
PROVISIONED_CLOUD_BIAS = 60;
|
|
75750
|
+
LOCALITY_BONUS = 30;
|
|
75751
|
+
TASK_MATCH_BONUS_FRONTIER = 20;
|
|
75752
|
+
TASK_MATCH_BONUS_FAST = 15;
|
|
75753
|
+
MAX_COST_PENALTY = 10;
|
|
75754
|
+
OLLAMA_PROBE_TIMEOUT_MS = 200;
|
|
75755
|
+
OLLAMA_PROBE_TTL_MS = 3e4;
|
|
75756
|
+
_ollamaProbeCache = /* @__PURE__ */ new Map();
|
|
75757
|
+
}
|
|
75758
|
+
});
|
|
75759
|
+
|
|
75240
75760
|
// packages/core/src/llm/sealed-credential.ts
|
|
75241
75761
|
function tokenPreview(token, authType) {
|
|
75242
75762
|
const prefix = authType === "oauth" ? "oat-\u2026" : "\u2026";
|
|
@@ -75285,14 +75805,14 @@ function getRegisteredSystemDefault(key) {
|
|
|
75285
75805
|
if (!isResolvableSystemDefault(record2.defaults)) return void 0;
|
|
75286
75806
|
return record2.defaults;
|
|
75287
75807
|
}
|
|
75288
|
-
var
|
|
75808
|
+
var logger5, REGISTRY;
|
|
75289
75809
|
var init_system_of_use_registry = __esm({
|
|
75290
75810
|
"packages/core/src/llm/system-of-use-registry.ts"() {
|
|
75291
75811
|
"use strict";
|
|
75292
75812
|
init_src();
|
|
75293
75813
|
init_logger2();
|
|
75294
75814
|
init_system_key();
|
|
75295
|
-
|
|
75815
|
+
logger5 = getLogger("llm-system-of-use-registry");
|
|
75296
75816
|
REGISTRY = /* @__PURE__ */ new Map();
|
|
75297
75817
|
}
|
|
75298
75818
|
});
|
|
@@ -75380,7 +75900,7 @@ function resolveRegisteredSystemDefault(llm, systemKey) {
|
|
|
75380
75900
|
}
|
|
75381
75901
|
return void 0;
|
|
75382
75902
|
}
|
|
75383
|
-
function selectProviderModel(llm, role, systemKey, profileOverride) {
|
|
75903
|
+
async function selectProviderModel(llm, role, systemKey, profileOverride, projectRoot) {
|
|
75384
75904
|
const roleEntry = llm?.roles?.[role];
|
|
75385
75905
|
const pinnedProfile = resolveNamedProfile(llm, profileOverride, "profile");
|
|
75386
75906
|
if (pinnedProfile) return pinnedProfile;
|
|
@@ -75409,6 +75929,15 @@ function selectProviderModel(llm, role, systemKey, profileOverride) {
|
|
|
75409
75929
|
if (defaultProfile) return defaultProfile;
|
|
75410
75930
|
const registeredDefault = resolveRegisteredSystemDefault(llm, systemKey);
|
|
75411
75931
|
if (registeredDefault) return registeredDefault;
|
|
75932
|
+
try {
|
|
75933
|
+
const crossProviderResult = await selectBestProvisioned(role, {
|
|
75934
|
+
projectRoot: projectRoot ?? ""
|
|
75935
|
+
});
|
|
75936
|
+
if (crossProviderResult !== null) {
|
|
75937
|
+
return crossProviderResult;
|
|
75938
|
+
}
|
|
75939
|
+
} catch {
|
|
75940
|
+
}
|
|
75412
75941
|
return {
|
|
75413
75942
|
provider: IMPLICIT_FALLBACK_PROVIDER,
|
|
75414
75943
|
model: IMPLICIT_FALLBACK_MODEL,
|
|
@@ -75468,11 +75997,12 @@ async function resolveLLMForRole(role, opts) {
|
|
|
75468
75997
|
config2 = void 0;
|
|
75469
75998
|
}
|
|
75470
75999
|
const llmBlock = readLlmBlock(config2);
|
|
75471
|
-
const { provider, model, credentialLabel, source } = selectProviderModel(
|
|
76000
|
+
const { provider, model, credentialLabel, source } = await selectProviderModel(
|
|
75472
76001
|
llmBlock,
|
|
75473
76002
|
role,
|
|
75474
76003
|
opts?.systemKey,
|
|
75475
|
-
opts?.profileOverride
|
|
76004
|
+
opts?.profileOverride,
|
|
76005
|
+
projectRoot
|
|
75476
76006
|
);
|
|
75477
76007
|
const { credential, usedLabel } = await resolveCredentialForRole(
|
|
75478
76008
|
provider,
|
|
@@ -75550,6 +76080,7 @@ var init_role_resolver = __esm({
|
|
|
75550
76080
|
init_credential_pool();
|
|
75551
76081
|
init_credentials2();
|
|
75552
76082
|
init_credentials_store();
|
|
76083
|
+
init_cross_provider_selector();
|
|
75553
76084
|
init_fallback_model();
|
|
75554
76085
|
init_sealed_credential();
|
|
75555
76086
|
init_system_of_use_registry();
|