@cleocode/core 2026.6.14 → 2026.6.17
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 +58 -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/gc/janitor.d.ts +149 -0
- package/dist/gc/janitor.d.ts.map +1 -0
- package/dist/gc/janitor.js +760 -0
- package/dist/gc/janitor.js.map +1 -0
- package/dist/internal.d.ts +1 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +3 -0
- package/dist/internal.js.map +1 -1
- package/dist/llm/cli-ops.d.ts +31 -4
- package/dist/llm/cli-ops.d.ts.map +1 -1
- package/dist/llm/cli-ops.js +110 -26
- package/dist/llm/cli-ops.js.map +1 -1
- package/dist/llm/credential-pool.d.ts +62 -0
- package/dist/llm/credential-pool.d.ts.map +1 -1
- package/dist/llm/credential-pool.js +161 -0
- package/dist/llm/credential-pool.js.map +1 -1
- package/dist/llm/cross-provider-selector.d.ts +254 -0
- package/dist/llm/cross-provider-selector.d.ts.map +1 -0
- package/dist/llm/cross-provider-selector.js +635 -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 +883 -231
- 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-context.d.ts +172 -0
- package/dist/selfimprove/fix-gen-context.d.ts.map +1 -0
- package/dist/selfimprove/fix-gen-context.js +218 -0
- package/dist/selfimprove/fix-gen-context.js.map +1 -0
- package/dist/selfimprove/fix-gen.d.ts +285 -0
- package/dist/selfimprove/fix-gen.d.ts.map +1 -0
- package/dist/selfimprove/fix-gen.js +346 -0
- package/dist/selfimprove/fix-gen.js.map +1 -0
- package/dist/selfimprove/op-source-map.d.ts +92 -0
- package/dist/selfimprove/op-source-map.d.ts.map +1 -0
- package/dist/selfimprove/op-source-map.js +187 -0
- package/dist/selfimprove/op-source-map.js.map +1 -0
- package/dist/selfimprove/probe-helper.d.ts +61 -0
- package/dist/selfimprove/probe-helper.d.ts.map +1 -0
- package/dist/selfimprove/probe-helper.js +64 -0
- package/dist/selfimprove/probe-helper.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/selfimprove/scenarios/seeded-code-regression/golden.json +18 -0
- package/dist/selfimprove/scenarios/seeded-code-regression/scenario.json +12 -0
- 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/setup/index.d.ts +1 -0
- package/dist/setup/index.d.ts.map +1 -1
- package/dist/setup/index.js +1 -0
- package/dist/setup/index.js.map +1 -1
- package/dist/setup/sections/models-roles.d.ts +32 -1
- package/dist/setup/sections/models-roles.d.ts.map +1 -1
- package/dist/setup/sections/models-roles.js +118 -19
- package/dist/setup/sections/models-roles.js.map +1 -1
- package/dist/setup/whoami-summary.d.ts +34 -0
- package/dist/setup/whoami-summary.d.ts.map +1 -0
- package/dist/setup/whoami-summary.js +106 -0
- package/dist/setup/whoami-summary.js.map +1 -0
- 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
|
@@ -10804,6 +10804,22 @@ var init_operations_registry = __esm({
|
|
|
10804
10804
|
}
|
|
10805
10805
|
]
|
|
10806
10806
|
},
|
|
10807
|
+
// ── selfimprove query: probe (T11988 — seeded-code-regression scenario) ────────
|
|
10808
|
+
// Pure read-only op that returns `{ probe: 'ok', version: probeVersion() }`.
|
|
10809
|
+
// The `probe-helper.ts` intentionally ships with `probeVersion()` returning `2`
|
|
10810
|
+
// (should be `1`) so the seeded-code-regression scenario replay diverges from its
|
|
10811
|
+
// golden (`version: 1`) and gives the fix-gen LLM stage a real, patchable bug.
|
|
10812
|
+
{
|
|
10813
|
+
gateway: "query",
|
|
10814
|
+
domain: "selfimprove",
|
|
10815
|
+
operation: "probe",
|
|
10816
|
+
description: 'selfimprove.probe (query) \u2014 returns { probe: "ok", version: 1 } (health/version probe). Used by the seeded-code-regression scenario to validate the fix-gen pipeline (T11988).',
|
|
10817
|
+
tier: 2,
|
|
10818
|
+
idempotent: true,
|
|
10819
|
+
sessionRequired: false,
|
|
10820
|
+
requiredParams: [],
|
|
10821
|
+
params: []
|
|
10822
|
+
},
|
|
10807
10823
|
// ── selfimprove mutate: run (T11889 / T11889-D — the self-dogfooding loop) ──
|
|
10808
10824
|
// Boots ONE sandbox → replays the named canned scenario → diffs result
|
|
10809
10825
|
// envelopes vs the golden → on a regression emits ONE leased `selfimprove_dhq`
|
|
@@ -11417,6 +11433,31 @@ var init_operations_registry = __esm({
|
|
|
11417
11433
|
cli: { positional: true }
|
|
11418
11434
|
}
|
|
11419
11435
|
]
|
|
11436
|
+
},
|
|
11437
|
+
// T11995 — Janitor MVP: orphan process reaper + stale scope/lock/debris sweep
|
|
11438
|
+
{
|
|
11439
|
+
gateway: "mutate",
|
|
11440
|
+
domain: "admin",
|
|
11441
|
+
operation: "janitor.run",
|
|
11442
|
+
description: "admin.janitor.run (mutate) \u2014 run the janitor sweep: reap orphan processes, stop dead cleo-owned scopes, reclaim stale locks, prune tmp debris",
|
|
11443
|
+
tier: 1,
|
|
11444
|
+
idempotent: true,
|
|
11445
|
+
sessionRequired: false,
|
|
11446
|
+
requiredParams: [],
|
|
11447
|
+
params: [
|
|
11448
|
+
{
|
|
11449
|
+
name: "dryRun",
|
|
11450
|
+
type: "boolean",
|
|
11451
|
+
required: false,
|
|
11452
|
+
description: "Report planned actions without mutating anything."
|
|
11453
|
+
},
|
|
11454
|
+
{
|
|
11455
|
+
name: "gracePeriodMs",
|
|
11456
|
+
type: "number",
|
|
11457
|
+
required: false,
|
|
11458
|
+
description: "Minimum age (ms) of an unregistered process before reap eligibility (default: 600000)."
|
|
11459
|
+
}
|
|
11460
|
+
]
|
|
11420
11461
|
}
|
|
11421
11462
|
];
|
|
11422
11463
|
}
|
|
@@ -17608,7 +17649,7 @@ var init_sql = __esm({
|
|
|
17608
17649
|
return new SQL([new StringChunk(str)]);
|
|
17609
17650
|
}
|
|
17610
17651
|
_sql.raw = raw;
|
|
17611
|
-
function
|
|
17652
|
+
function join29(chunks, separator) {
|
|
17612
17653
|
const result = [];
|
|
17613
17654
|
for (const [i, chunk] of chunks.entries()) {
|
|
17614
17655
|
if (i > 0 && separator !== void 0) result.push(separator);
|
|
@@ -17616,7 +17657,7 @@ var init_sql = __esm({
|
|
|
17616
17657
|
}
|
|
17617
17658
|
return new SQL(result);
|
|
17618
17659
|
}
|
|
17619
|
-
_sql.join =
|
|
17660
|
+
_sql.join = join29;
|
|
17620
17661
|
function identifier(value) {
|
|
17621
17662
|
return new Name(value);
|
|
17622
17663
|
}
|
|
@@ -20003,7 +20044,7 @@ var init_select2 = __esm({
|
|
|
20003
20044
|
const baseTableName = this.tableName;
|
|
20004
20045
|
const tableName = getTableLikeName(table);
|
|
20005
20046
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
20006
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
20047
|
+
if (typeof tableName === "string" && this.config.joins?.some((join29) => join29.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
20007
20048
|
if (!this.isPartialSelect) {
|
|
20008
20049
|
if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === "string") this.config.fields = { [baseTableName]: this.config.fields };
|
|
20009
20050
|
if (typeof tableName === "string" && !is(table, SQL)) {
|
|
@@ -23813,7 +23854,7 @@ var init_dialect = __esm({
|
|
|
23813
23854
|
if (!joins2) return;
|
|
23814
23855
|
const withEntries = Object.entries(joins2).filter(([_, v]) => v);
|
|
23815
23856
|
if (!withEntries.length) return;
|
|
23816
|
-
return sql.join(withEntries.map(([k,
|
|
23857
|
+
return sql.join(withEntries.map(([k, join29]) => {
|
|
23817
23858
|
const relation = tableConfig.relations[k];
|
|
23818
23859
|
const isSingle2 = is(relation, One);
|
|
23819
23860
|
const targetTable = aliasedTable(relation.targetTable, `d${currentDepth + 1}`);
|
|
@@ -23824,7 +23865,7 @@ var init_dialect = __esm({
|
|
|
23824
23865
|
table: targetTable,
|
|
23825
23866
|
mode: isSingle2 ? "first" : "many",
|
|
23826
23867
|
schema,
|
|
23827
|
-
queryConfig:
|
|
23868
|
+
queryConfig: join29,
|
|
23828
23869
|
tableConfig: schema[relation.targetTableName],
|
|
23829
23870
|
relationWhere: filter2,
|
|
23830
23871
|
isNested: true,
|
|
@@ -23838,7 +23879,7 @@ var init_dialect = __esm({
|
|
|
23838
23879
|
key: k,
|
|
23839
23880
|
selection: innerQuery.selection,
|
|
23840
23881
|
isArray: !isSingle2,
|
|
23841
|
-
isOptional: (relation.optional ?? false) ||
|
|
23882
|
+
isOptional: (relation.optional ?? false) || join29 !== true && !!join29.where
|
|
23842
23883
|
});
|
|
23843
23884
|
const jsonColumns = sql.join(innerQuery.selection.map((s) => {
|
|
23844
23885
|
return sql`${sql.raw(this.escapeString(s.key))}, ${s.selection ? sql`${jsonb3}(${sql.identifier(s.key)})` : sql.identifier(s.key)}`;
|
|
@@ -24659,7 +24700,7 @@ var init_update = __esm({
|
|
|
24659
24700
|
createJoin(joinType) {
|
|
24660
24701
|
return ((table, on) => {
|
|
24661
24702
|
const tableName = getTableLikeName(table);
|
|
24662
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
24703
|
+
if (typeof tableName === "string" && this.config.joins.some((join29) => join29.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
24663
24704
|
if (typeof on === "function") {
|
|
24664
24705
|
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
24706
|
on = on(new Proxy(this.config.table[Table.Symbol.Columns], new SelectionProxyHandler({
|
|
@@ -25348,10 +25389,10 @@ var init_session4 = __esm({
|
|
|
25348
25389
|
NodeSQLitePreparedQuery = class extends SQLitePreparedQuery {
|
|
25349
25390
|
static [entityKind] = "SQLJsPreparedQuery";
|
|
25350
25391
|
jitMapper;
|
|
25351
|
-
constructor(stmt, query,
|
|
25392
|
+
constructor(stmt, query, logger6, fields, executeMethod, useJitMappers, customResultMapper, isRqbV2Query, rqbConfig) {
|
|
25352
25393
|
super("sync", executeMethod, query);
|
|
25353
25394
|
this.stmt = stmt;
|
|
25354
|
-
this.logger =
|
|
25395
|
+
this.logger = logger6;
|
|
25355
25396
|
this.fields = fields;
|
|
25356
25397
|
this.useJitMappers = useJitMappers;
|
|
25357
25398
|
this.customResultMapper = customResultMapper;
|
|
@@ -25367,10 +25408,10 @@ var init_session4 = __esm({
|
|
|
25367
25408
|
all(placeholderValues = {}) {
|
|
25368
25409
|
if (this.isRqbV2Query) return this.allRqbV2(placeholderValues);
|
|
25369
25410
|
const { stmt } = this;
|
|
25370
|
-
const { fields, joinsNotNullableMap, logger:
|
|
25411
|
+
const { fields, joinsNotNullableMap, logger: logger6, query, customResultMapper } = this;
|
|
25371
25412
|
if (!fields && !customResultMapper) {
|
|
25372
25413
|
const params = fillPlaceholders(query.params, placeholderValues);
|
|
25373
|
-
|
|
25414
|
+
logger6.logQuery(query.sql, params);
|
|
25374
25415
|
stmt.setReturnArrays(false);
|
|
25375
25416
|
return stmt.all(...params);
|
|
25376
25417
|
}
|
|
@@ -25381,9 +25422,9 @@ var init_session4 = __esm({
|
|
|
25381
25422
|
}
|
|
25382
25423
|
allRqbV2(placeholderValues = {}) {
|
|
25383
25424
|
const { stmt } = this;
|
|
25384
|
-
const { logger:
|
|
25425
|
+
const { logger: logger6, query, customResultMapper } = this;
|
|
25385
25426
|
const params = fillPlaceholders(query.params, placeholderValues);
|
|
25386
|
-
|
|
25427
|
+
logger6.logQuery(query.sql, params);
|
|
25387
25428
|
stmt.setReturnArrays(false);
|
|
25388
25429
|
const rows = stmt.all(...params).map((row) => ({ ...row }));
|
|
25389
25430
|
return this.useJitMappers ? (this.jitMapper = this.jitMapper ?? makeJitRqbMapper(this.rqbConfig))(rows) : customResultMapper(rows);
|
|
@@ -25429,9 +25470,9 @@ var init_session4 = __esm({
|
|
|
25429
25470
|
import { DatabaseSync } from "node:sqlite";
|
|
25430
25471
|
function construct(client, config2 = {}) {
|
|
25431
25472
|
const dialect = new SQLiteSyncDialect();
|
|
25432
|
-
let
|
|
25433
|
-
if (config2.logger === true)
|
|
25434
|
-
else if (config2.logger !== false)
|
|
25473
|
+
let logger6;
|
|
25474
|
+
if (config2.logger === true) logger6 = new DefaultLogger();
|
|
25475
|
+
else if (config2.logger !== false) logger6 = config2.logger;
|
|
25435
25476
|
let schema;
|
|
25436
25477
|
if (config2.schema) {
|
|
25437
25478
|
const tablesConfig = extractTablesRelationalConfig(config2.schema, createTableRelationsHelpers);
|
|
@@ -25443,7 +25484,7 @@ function construct(client, config2 = {}) {
|
|
|
25443
25484
|
}
|
|
25444
25485
|
const relations = config2.relations ?? {};
|
|
25445
25486
|
const db = new NodeSQLiteDatabase("sync", dialect, new NodeSQLiteSession(client, dialect, relations, schema, {
|
|
25446
|
-
logger:
|
|
25487
|
+
logger: logger6,
|
|
25447
25488
|
useJitMappers: jitCompatCheck(config2.jit)
|
|
25448
25489
|
}), relations, schema);
|
|
25449
25490
|
db.$client = client;
|
|
@@ -40041,8 +40082,6 @@ __export(config_exports, {
|
|
|
40041
40082
|
setConfigValue: () => setConfigValue
|
|
40042
40083
|
});
|
|
40043
40084
|
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
40085
|
function getNestedValue(obj, path) {
|
|
40047
40086
|
const parts = path.split(".");
|
|
40048
40087
|
let current = obj;
|
|
@@ -40165,9 +40204,7 @@ function parseConfigValue(value) {
|
|
|
40165
40204
|
async function setConfigValue(key, value, cwd, opts) {
|
|
40166
40205
|
const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
|
|
40167
40206
|
if (!existsSync16(configPath)) {
|
|
40168
|
-
|
|
40169
|
-
await mkdir3(dir, { recursive: true });
|
|
40170
|
-
await writeFile(configPath, "{}", "utf-8");
|
|
40207
|
+
await atomicWriteJson(configPath, {});
|
|
40171
40208
|
}
|
|
40172
40209
|
const config2 = await readJson(configPath) ?? {};
|
|
40173
40210
|
const parsedValue = parseConfigValue(value);
|
|
@@ -40179,9 +40216,7 @@ async function applyStrictnessPreset(preset, cwd, opts) {
|
|
|
40179
40216
|
const definition = STRICTNESS_PRESETS[preset];
|
|
40180
40217
|
const configPath = opts?.global ? getGlobalConfigPath() : getConfigPath(cwd);
|
|
40181
40218
|
if (!existsSync16(configPath)) {
|
|
40182
|
-
|
|
40183
|
-
await mkdir3(dir, { recursive: true });
|
|
40184
|
-
await writeFile(configPath, "{}", "utf-8");
|
|
40219
|
+
await atomicWriteJson(configPath, {});
|
|
40185
40220
|
}
|
|
40186
40221
|
const config2 = await readJson(configPath) ?? {};
|
|
40187
40222
|
for (const [key, value] of Object.entries(definition.values)) {
|
|
@@ -40210,6 +40245,7 @@ var init_config = __esm({
|
|
|
40210
40245
|
"use strict";
|
|
40211
40246
|
init_fallback_model();
|
|
40212
40247
|
init_paths();
|
|
40248
|
+
init_atomic();
|
|
40213
40249
|
init_json2();
|
|
40214
40250
|
DEFAULTS = {
|
|
40215
40251
|
version: "2.10.0",
|
|
@@ -40320,6 +40356,12 @@ var init_config = __esm({
|
|
|
40320
40356
|
// (T10383). The active runtime itself ships in T10512.
|
|
40321
40357
|
leadRollup: {
|
|
40322
40358
|
mode: "passive"
|
|
40359
|
+
},
|
|
40360
|
+
// T11984: daemon lifecycle — postinstall respects operator state by default.
|
|
40361
|
+
// Set daemon.autoStart = false (via global config.json) for a persistent
|
|
40362
|
+
// opt-out that survives npm upgrades.
|
|
40363
|
+
daemon: {
|
|
40364
|
+
autoStart: true
|
|
40323
40365
|
}
|
|
40324
40366
|
};
|
|
40325
40367
|
ENV_MAP = {
|
|
@@ -41544,15 +41586,27 @@ var init_credentials2 = __esm({
|
|
|
41544
41586
|
});
|
|
41545
41587
|
|
|
41546
41588
|
// packages/core/src/llm/credentials-store.ts
|
|
41589
|
+
var credentials_store_exports = {};
|
|
41590
|
+
__export(credentials_store_exports, {
|
|
41591
|
+
_resetPermsWarningForTests: () => _resetPermsWarningForTests,
|
|
41592
|
+
_resetRoundRobinForTests: () => _resetRoundRobinForTests,
|
|
41593
|
+
addCredential: () => addCredential,
|
|
41594
|
+
credentialsStorePath: () => credentialsStorePath,
|
|
41595
|
+
getCredentialByLabel: () => getCredentialByLabel,
|
|
41596
|
+
listCredentials: () => listCredentials,
|
|
41597
|
+
pickCredentialForProvider: () => pickCredentialForProvider,
|
|
41598
|
+
pickCredentialForProviderSync: () => pickCredentialForProviderSync,
|
|
41599
|
+
removeCredential: () => removeCredential
|
|
41600
|
+
});
|
|
41547
41601
|
import { chmodSync, existsSync as existsSync22, mkdirSync as mkdirSync7, readFileSync as readFileSync13, statSync as statSync6, writeFileSync as writeFileSync7 } from "node:fs";
|
|
41548
|
-
import { dirname as
|
|
41602
|
+
import { dirname as dirname8, join as join23 } from "node:path";
|
|
41549
41603
|
import { getCleoHome as getCleoHome7 } from "@cleocode/paths";
|
|
41550
41604
|
function credentialsStorePath() {
|
|
41551
41605
|
return join23(getCleoHome7(), "llm-credentials.json");
|
|
41552
41606
|
}
|
|
41553
41607
|
function ensureFileInitialized(path) {
|
|
41554
41608
|
if (existsSync22(path)) return;
|
|
41555
|
-
const dir =
|
|
41609
|
+
const dir = dirname8(path);
|
|
41556
41610
|
if (!existsSync22(dir)) {
|
|
41557
41611
|
mkdirSync7(dir, { recursive: true, mode: 448 });
|
|
41558
41612
|
} else {
|
|
@@ -41587,6 +41641,9 @@ function checkPermsOnRead(path) {
|
|
|
41587
41641
|
} catch {
|
|
41588
41642
|
}
|
|
41589
41643
|
}
|
|
41644
|
+
function _resetPermsWarningForTests() {
|
|
41645
|
+
_warnedLoosePerms = false;
|
|
41646
|
+
}
|
|
41590
41647
|
function emptyStore() {
|
|
41591
41648
|
return { version: 1, defaultStrategy: "priorityWithFallback", credentials: [] };
|
|
41592
41649
|
}
|
|
@@ -41629,6 +41686,9 @@ function isStoredCredential(value) {
|
|
|
41629
41686
|
if (typeof accessToken !== "string") return false;
|
|
41630
41687
|
return true;
|
|
41631
41688
|
}
|
|
41689
|
+
function _resetRoundRobinForTests() {
|
|
41690
|
+
_rrIndex.clear();
|
|
41691
|
+
}
|
|
41632
41692
|
function eligibleForProvider(data, provider, preferLabel) {
|
|
41633
41693
|
const now = Date.now();
|
|
41634
41694
|
const all = data.credentials.filter((c) => {
|
|
@@ -41732,6 +41792,35 @@ async function addCredential(input) {
|
|
|
41732
41792
|
clearAnthropicKeyCache();
|
|
41733
41793
|
return inserted;
|
|
41734
41794
|
}
|
|
41795
|
+
async function removeCredential(provider, label) {
|
|
41796
|
+
const path = credentialsStorePath();
|
|
41797
|
+
const snapshot = readStoreSync();
|
|
41798
|
+
if (!snapshot.credentials.some((c) => c.provider === provider && c.label === label)) {
|
|
41799
|
+
return false;
|
|
41800
|
+
}
|
|
41801
|
+
ensureFileInitialized(path);
|
|
41802
|
+
let removed = false;
|
|
41803
|
+
await withLock2(
|
|
41804
|
+
path,
|
|
41805
|
+
(current) => {
|
|
41806
|
+
const data = current ?? emptyStore();
|
|
41807
|
+
if (data.version !== 1 || !Array.isArray(data.credentials)) {
|
|
41808
|
+
return emptyStore();
|
|
41809
|
+
}
|
|
41810
|
+
const before = data.credentials.length;
|
|
41811
|
+
data.credentials = data.credentials.filter(
|
|
41812
|
+
(c) => !(c.provider === provider && c.label === label)
|
|
41813
|
+
);
|
|
41814
|
+
removed = data.credentials.length < before;
|
|
41815
|
+
data.defaultStrategy ??= "priorityWithFallback";
|
|
41816
|
+
return data;
|
|
41817
|
+
},
|
|
41818
|
+
// SECURITY (S-01/S-02): see addCredential for rationale.
|
|
41819
|
+
{ mode: 384 }
|
|
41820
|
+
);
|
|
41821
|
+
if (removed) clearAnthropicKeyCache();
|
|
41822
|
+
return removed;
|
|
41823
|
+
}
|
|
41735
41824
|
async function pickCredentialForProvider(provider, opts = {}) {
|
|
41736
41825
|
return pickCredentialForProviderSync(provider, opts);
|
|
41737
41826
|
}
|
|
@@ -41871,7 +41960,7 @@ var init_gemini = __esm({
|
|
|
41871
41960
|
// packages/core/src/llm/stable-device-id.ts
|
|
41872
41961
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
41873
41962
|
import { existsSync as existsSync23, mkdirSync as mkdirSync8, readFileSync as readFileSync14, renameSync as renameSync6, writeFileSync as writeFileSync8 } from "node:fs";
|
|
41874
|
-
import { dirname as
|
|
41963
|
+
import { dirname as dirname9, join as join24 } from "node:path";
|
|
41875
41964
|
import { getCleoHome as getCleoHome8 } from "@cleocode/paths";
|
|
41876
41965
|
function getStableDeviceId() {
|
|
41877
41966
|
if (_cachedDeviceId !== null) return _cachedDeviceId;
|
|
@@ -41888,7 +41977,7 @@ function getStableDeviceId() {
|
|
|
41888
41977
|
}
|
|
41889
41978
|
const fresh = randomUUID2();
|
|
41890
41979
|
try {
|
|
41891
|
-
const dir =
|
|
41980
|
+
const dir = dirname9(path);
|
|
41892
41981
|
if (!existsSync23(dir)) {
|
|
41893
41982
|
mkdirSync8(dir, { recursive: true });
|
|
41894
41983
|
}
|
|
@@ -42034,11 +42123,11 @@ var init_ollama = __esm({
|
|
|
42034
42123
|
displayName: "Ollama (local)",
|
|
42035
42124
|
authTypes: ["api_key"],
|
|
42036
42125
|
baseUrl: "http://localhost:11434",
|
|
42037
|
-
defaultModel: "
|
|
42126
|
+
defaultModel: "gemma4:e4b",
|
|
42038
42127
|
aliases: ["ollama-local"],
|
|
42039
42128
|
// Hermes-parity routing/catalog fields (T11756). Local on-device tier.
|
|
42040
42129
|
tier: "local",
|
|
42041
|
-
defaultAuxModel: "
|
|
42130
|
+
defaultAuxModel: "gemma4:e2b",
|
|
42042
42131
|
defaultMaxTokens: 2048,
|
|
42043
42132
|
envVars: ["OLLAMA_API_KEY", "OLLAMA_BASE_URL"],
|
|
42044
42133
|
supportsThinkingBudget: false
|
|
@@ -42272,6 +42361,15 @@ var init_loader = __esm({
|
|
|
42272
42361
|
});
|
|
42273
42362
|
|
|
42274
42363
|
// packages/core/src/llm/provider-registry/index.ts
|
|
42364
|
+
var provider_registry_exports = {};
|
|
42365
|
+
__export(provider_registry_exports, {
|
|
42366
|
+
_resetRegistryForTesting: () => _resetRegistryForTesting,
|
|
42367
|
+
discoverPlugins: () => discoverPlugins,
|
|
42368
|
+
ensureDiscovered: () => ensureDiscovered,
|
|
42369
|
+
getProviderProfile: () => getProviderProfile,
|
|
42370
|
+
listProviders: () => listProviders,
|
|
42371
|
+
registerProvider: () => registerProvider
|
|
42372
|
+
});
|
|
42275
42373
|
function registerProvider(profile) {
|
|
42276
42374
|
const key = profile.name.toLowerCase();
|
|
42277
42375
|
_registry.set(key, profile);
|
|
@@ -42294,12 +42392,25 @@ async function ensureDiscovered() {
|
|
|
42294
42392
|
}
|
|
42295
42393
|
return _discoveryPromise;
|
|
42296
42394
|
}
|
|
42395
|
+
async function discoverPlugins() {
|
|
42396
|
+
return ensureDiscovered();
|
|
42397
|
+
}
|
|
42297
42398
|
async function getProviderProfile(name15) {
|
|
42298
42399
|
await ensureDiscovered();
|
|
42299
42400
|
const key = name15.toLowerCase();
|
|
42300
42401
|
const canonical = _aliases.get(key) ?? key;
|
|
42301
42402
|
return _registry.get(canonical);
|
|
42302
42403
|
}
|
|
42404
|
+
async function listProviders() {
|
|
42405
|
+
await ensureDiscovered();
|
|
42406
|
+
const profiles = [..._registry.values()];
|
|
42407
|
+
return profiles.sort((a, b) => a.name.localeCompare(b.name));
|
|
42408
|
+
}
|
|
42409
|
+
function _resetRegistryForTesting() {
|
|
42410
|
+
_registry.clear();
|
|
42411
|
+
_aliases.clear();
|
|
42412
|
+
_discoveryPromise = null;
|
|
42413
|
+
}
|
|
42303
42414
|
var _registry, _aliases, _discoveryPromise, BUILTIN_PROFILES;
|
|
42304
42415
|
var init_provider_registry = __esm({
|
|
42305
42416
|
"packages/core/src/llm/provider-registry/index.ts"() {
|
|
@@ -42424,6 +42535,60 @@ function isInCooldown(credential) {
|
|
|
42424
42535
|
function sortByPriorityDesc(entries) {
|
|
42425
42536
|
return [...entries].sort((a, b) => b.priority - a.priority);
|
|
42426
42537
|
}
|
|
42538
|
+
async function refreshExpiredOAuthForProvider(provider) {
|
|
42539
|
+
const entries = await listCredentials(provider);
|
|
42540
|
+
const now = Date.now();
|
|
42541
|
+
let attempted = 0;
|
|
42542
|
+
let refreshed = 0;
|
|
42543
|
+
let lastError = null;
|
|
42544
|
+
for (const entry of entries) {
|
|
42545
|
+
if (entry.authType !== "oauth") continue;
|
|
42546
|
+
if (!entry.refreshToken) continue;
|
|
42547
|
+
if (entry.disabled === true) continue;
|
|
42548
|
+
const isExpiredOrNearExpiry = typeof entry.expiresAt === "number" && entry.expiresAt > 0 && entry.expiresAt <= now + PROACTIVE_REFRESH_FLOOR_MS;
|
|
42549
|
+
if (!isExpiredOrNearExpiry) continue;
|
|
42550
|
+
const key = `${provider}::${entry.label}`;
|
|
42551
|
+
const negExpiry = _refreshNegativeCache.get(key);
|
|
42552
|
+
if (typeof negExpiry === "number" && now < negExpiry) {
|
|
42553
|
+
attempted += 1;
|
|
42554
|
+
lastError = lastError ?? new Error(
|
|
42555
|
+
`OAuth refresh suppressed for ${provider}::${entry.label} (negative cache active)`
|
|
42556
|
+
);
|
|
42557
|
+
continue;
|
|
42558
|
+
}
|
|
42559
|
+
attempted += 1;
|
|
42560
|
+
let inFlight = _refreshInFlight.get(key);
|
|
42561
|
+
if (!inFlight) {
|
|
42562
|
+
const pool = new CredentialPool(provider);
|
|
42563
|
+
const expiresAtBefore = entry.expiresAt;
|
|
42564
|
+
inFlight = pool.proactiveRefresh(entry.label).then(async (wasAttempted) => {
|
|
42565
|
+
if (!wasAttempted) {
|
|
42566
|
+
return true;
|
|
42567
|
+
}
|
|
42568
|
+
const after = await getCredentialByLabel(provider, entry.label);
|
|
42569
|
+
const didAdvance = after !== null && typeof after.expiresAt === "number" && after.expiresAt > (expiresAtBefore ?? 0);
|
|
42570
|
+
if (!didAdvance) {
|
|
42571
|
+
throw new Error(
|
|
42572
|
+
`OAuth refresh token exchange failed for ${provider}::${entry.label} \u2014 the stored token may be revoked. Run \`cleo login ${provider}\` to re-authenticate.`
|
|
42573
|
+
);
|
|
42574
|
+
}
|
|
42575
|
+
return true;
|
|
42576
|
+
}).finally(() => {
|
|
42577
|
+
_refreshInFlight.delete(key);
|
|
42578
|
+
});
|
|
42579
|
+
_refreshInFlight.set(key, inFlight);
|
|
42580
|
+
}
|
|
42581
|
+
try {
|
|
42582
|
+
await inFlight;
|
|
42583
|
+
refreshed += 1;
|
|
42584
|
+
} catch (err) {
|
|
42585
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
42586
|
+
_refreshNegativeCache.set(key, Date.now() + REFRESH_NEGATIVE_CACHE_TTL_MS);
|
|
42587
|
+
}
|
|
42588
|
+
}
|
|
42589
|
+
const actionableHint = attempted > 0 && refreshed === 0 && lastError !== null ? `OAuth refresh failed for provider '${provider}'. Run \`cleo login ${provider}\` to re-authenticate.` : null;
|
|
42590
|
+
return { attempted, refreshed, lastError, actionableHint };
|
|
42591
|
+
}
|
|
42427
42592
|
function debugLog(msg, ...rest) {
|
|
42428
42593
|
if (process.env["CLEO_DEBUG"]) {
|
|
42429
42594
|
console.debug(`[cleo:credential-pool] ${msg}`, ...rest);
|
|
@@ -42435,7 +42600,7 @@ function getCredentialPool() {
|
|
|
42435
42600
|
}
|
|
42436
42601
|
return _singleton;
|
|
42437
42602
|
}
|
|
42438
|
-
var COOLDOWN_AUTH_MS, COOLDOWN_RATE_LIMIT_MS, COOLDOWN_DEFAULT_MS, PROACTIVE_REFRESH_FLOOR_MS, PoolExhaustedError, CredentialPool, POOL_SEED_CACHE_TTL_MS, UnifiedCredentialPool, _singleton;
|
|
42603
|
+
var COOLDOWN_AUTH_MS, COOLDOWN_RATE_LIMIT_MS, COOLDOWN_DEFAULT_MS, PROACTIVE_REFRESH_FLOOR_MS, PoolExhaustedError, _refreshInFlight, REFRESH_NEGATIVE_CACHE_TTL_MS, _refreshNegativeCache, CredentialPool, POOL_SEED_CACHE_TTL_MS, UnifiedCredentialPool, _singleton;
|
|
42439
42604
|
var init_credential_pool = __esm({
|
|
42440
42605
|
"packages/core/src/llm/credential-pool.ts"() {
|
|
42441
42606
|
"use strict";
|
|
@@ -42472,6 +42637,9 @@ var init_credential_pool = __esm({
|
|
|
42472
42637
|
/** Stable LAFS error code. */
|
|
42473
42638
|
code = "E_LLM_POOL_EXHAUSTED";
|
|
42474
42639
|
};
|
|
42640
|
+
_refreshInFlight = /* @__PURE__ */ new Map();
|
|
42641
|
+
REFRESH_NEGATIVE_CACHE_TTL_MS = 3e4;
|
|
42642
|
+
_refreshNegativeCache = /* @__PURE__ */ new Map();
|
|
42475
42643
|
CredentialPool = class {
|
|
42476
42644
|
/**
|
|
42477
42645
|
* @param provider - The LLM transport this pool manages.
|
|
@@ -43232,6 +43400,38 @@ var init_error_classifier = __esm({
|
|
|
43232
43400
|
});
|
|
43233
43401
|
|
|
43234
43402
|
// packages/core/src/llm/catalog-cache.ts
|
|
43403
|
+
import {
|
|
43404
|
+
existsSync as existsSync25,
|
|
43405
|
+
mkdirSync as mkdirSync10,
|
|
43406
|
+
readdirSync as readdirSync6,
|
|
43407
|
+
readFileSync as readFileSync15,
|
|
43408
|
+
statSync as statSync8,
|
|
43409
|
+
symlinkSync,
|
|
43410
|
+
unlinkSync as unlinkSync7,
|
|
43411
|
+
writeFileSync as writeFileSync9
|
|
43412
|
+
} from "node:fs";
|
|
43413
|
+
import { homedir as homedir4 } from "node:os";
|
|
43414
|
+
import { join as join27 } from "node:path";
|
|
43415
|
+
function getCatalogDir() {
|
|
43416
|
+
if (process.env["CLEO_DATA_DIR"]) {
|
|
43417
|
+
return join27(process.env["CLEO_DATA_DIR"], "llm-catalog");
|
|
43418
|
+
}
|
|
43419
|
+
const xdg = process.env["XDG_DATA_HOME"] ?? join27(homedir4(), ".local", "share");
|
|
43420
|
+
return join27(xdg, "cleo", "llm-catalog");
|
|
43421
|
+
}
|
|
43422
|
+
function findLatestCacheFile(dir) {
|
|
43423
|
+
if (!existsSync25(dir)) return null;
|
|
43424
|
+
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);
|
|
43425
|
+
return files.length > 0 ? join27(dir, files[0].name) : null;
|
|
43426
|
+
}
|
|
43427
|
+
function readCacheFile(filePath) {
|
|
43428
|
+
try {
|
|
43429
|
+
const raw = readFileSync15(filePath, "utf-8");
|
|
43430
|
+
return JSON.parse(raw);
|
|
43431
|
+
} catch {
|
|
43432
|
+
return null;
|
|
43433
|
+
}
|
|
43434
|
+
}
|
|
43235
43435
|
var init_catalog_cache = __esm({
|
|
43236
43436
|
"packages/core/src/llm/catalog-cache.ts"() {
|
|
43237
43437
|
"use strict";
|
|
@@ -43239,16 +43439,16 @@ var init_catalog_cache = __esm({
|
|
|
43239
43439
|
});
|
|
43240
43440
|
|
|
43241
43441
|
// packages/core/src/llm/model-metadata.ts
|
|
43242
|
-
import { readFileSync as
|
|
43243
|
-
import { dirname as
|
|
43442
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
43443
|
+
import { dirname as dirname10, join as join28 } from "node:path";
|
|
43244
43444
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
43245
43445
|
function getCuratedTable() {
|
|
43246
43446
|
if (_curated !== void 0) {
|
|
43247
43447
|
return _curated;
|
|
43248
43448
|
}
|
|
43249
|
-
const thisDir =
|
|
43250
|
-
const jsonPath =
|
|
43251
|
-
const raw = JSON.parse(
|
|
43449
|
+
const thisDir = dirname10(fileURLToPath3(import.meta.url));
|
|
43450
|
+
const jsonPath = join28(thisDir, "curated-models.json");
|
|
43451
|
+
const raw = JSON.parse(readFileSync16(jsonPath, "utf-8"));
|
|
43252
43452
|
_curated = raw.models;
|
|
43253
43453
|
return _curated;
|
|
43254
43454
|
}
|
|
@@ -46088,7 +46288,69 @@ var init_chat_completions = __esm({
|
|
|
46088
46288
|
});
|
|
46089
46289
|
|
|
46090
46290
|
// packages/core/src/llm/transports/codex-responses.ts
|
|
46091
|
-
|
|
46291
|
+
function resolveCodexUrl(baseUrl) {
|
|
46292
|
+
const DEFAULT_BASE = "https://chatgpt.com/backend-api";
|
|
46293
|
+
const raw = baseUrl?.trim() ? baseUrl.trim() : DEFAULT_BASE;
|
|
46294
|
+
const normalized = raw.replace(/\/+$/, "");
|
|
46295
|
+
if (normalized.endsWith("/codex/responses")) return normalized;
|
|
46296
|
+
if (normalized.endsWith("/codex")) return `${normalized}/responses`;
|
|
46297
|
+
return `${normalized}/codex/responses`;
|
|
46298
|
+
}
|
|
46299
|
+
async function buildHttpError(res) {
|
|
46300
|
+
let bodyDetail = "";
|
|
46301
|
+
try {
|
|
46302
|
+
const text3 = await res.text();
|
|
46303
|
+
if (text3) {
|
|
46304
|
+
try {
|
|
46305
|
+
const parsed = JSON.parse(text3);
|
|
46306
|
+
const err = parsed["error"];
|
|
46307
|
+
bodyDetail = err?.["message"] ?? text3;
|
|
46308
|
+
} catch {
|
|
46309
|
+
bodyDetail = text3;
|
|
46310
|
+
}
|
|
46311
|
+
}
|
|
46312
|
+
} catch {
|
|
46313
|
+
}
|
|
46314
|
+
return bodyDetail ? `${res.status} ${bodyDetail}` : `${res.status} status code (no body)`;
|
|
46315
|
+
}
|
|
46316
|
+
function buildInputItems(request) {
|
|
46317
|
+
const items = [];
|
|
46318
|
+
for (const msg of request.messages) {
|
|
46319
|
+
if (msg.role === "tool") {
|
|
46320
|
+
items.push({
|
|
46321
|
+
type: "function_call_output",
|
|
46322
|
+
call_id: msg.toolUseId ?? `call_${Date.now().toString(36)}`,
|
|
46323
|
+
output: extractTextContent3(msg)
|
|
46324
|
+
});
|
|
46325
|
+
continue;
|
|
46326
|
+
}
|
|
46327
|
+
const contentItems = buildContentList(msg);
|
|
46328
|
+
if (contentItems.length === 1 && contentItems[0]?.["type"] === "input_text") {
|
|
46329
|
+
items.push({
|
|
46330
|
+
type: "message",
|
|
46331
|
+
role: msg.role === "assistant" ? "assistant" : "user",
|
|
46332
|
+
content: contentItems[0]["text"]
|
|
46333
|
+
});
|
|
46334
|
+
} else {
|
|
46335
|
+
items.push({
|
|
46336
|
+
type: "message",
|
|
46337
|
+
role: msg.role === "assistant" ? "assistant" : "user",
|
|
46338
|
+
content: contentItems
|
|
46339
|
+
});
|
|
46340
|
+
}
|
|
46341
|
+
}
|
|
46342
|
+
return items;
|
|
46343
|
+
}
|
|
46344
|
+
function buildTools(tools) {
|
|
46345
|
+
if (!tools || tools.length === 0) return [];
|
|
46346
|
+
return tools.map((t) => ({
|
|
46347
|
+
type: "function",
|
|
46348
|
+
name: t.name,
|
|
46349
|
+
description: t.description,
|
|
46350
|
+
parameters: t.inputSchema,
|
|
46351
|
+
strict: false
|
|
46352
|
+
}));
|
|
46353
|
+
}
|
|
46092
46354
|
function extractTextContent3(message) {
|
|
46093
46355
|
if (typeof message.content === "string") return message.content;
|
|
46094
46356
|
return message.content.filter(
|
|
@@ -46108,38 +46370,77 @@ function buildContentList(message) {
|
|
|
46108
46370
|
return { type: "input_image", image_url: imageUrl, detail: "auto" };
|
|
46109
46371
|
});
|
|
46110
46372
|
}
|
|
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
46373
|
function extractToolCallsFromOutput(output) {
|
|
46127
46374
|
const calls = [];
|
|
46128
46375
|
for (const item of output) {
|
|
46129
|
-
|
|
46130
|
-
if (it["type"] !== "function_call") continue;
|
|
46376
|
+
if (item["type"] !== "function_call") continue;
|
|
46131
46377
|
calls.push({
|
|
46132
|
-
id: typeof
|
|
46133
|
-
name: typeof
|
|
46134
|
-
arguments: typeof
|
|
46378
|
+
id: typeof item["call_id"] === "string" ? item["call_id"] : null,
|
|
46379
|
+
name: typeof item["name"] === "string" ? item["name"] : "unknown",
|
|
46380
|
+
arguments: typeof item["arguments"] === "string" ? item["arguments"] : "{}",
|
|
46135
46381
|
providerData: {
|
|
46136
|
-
call_id:
|
|
46137
|
-
response_item_id:
|
|
46382
|
+
call_id: item["call_id"],
|
|
46383
|
+
response_item_id: item["id"]
|
|
46138
46384
|
}
|
|
46139
46385
|
});
|
|
46140
46386
|
}
|
|
46141
46387
|
return calls;
|
|
46142
46388
|
}
|
|
46389
|
+
function normalizeUsage(usage) {
|
|
46390
|
+
const inputTokens = usage["input_tokens"] ?? 0;
|
|
46391
|
+
const outputTokens = usage["output_tokens"] ?? 0;
|
|
46392
|
+
const normalized = { inputTokens, outputTokens };
|
|
46393
|
+
const details = usage["input_tokens_details"];
|
|
46394
|
+
const cached2 = details?.["cached_tokens"];
|
|
46395
|
+
if (typeof cached2 === "number" && cached2 > 0) {
|
|
46396
|
+
normalized.cachedTokens = cached2;
|
|
46397
|
+
}
|
|
46398
|
+
return normalized;
|
|
46399
|
+
}
|
|
46400
|
+
async function* parseSSE(body, signal) {
|
|
46401
|
+
const reader = body.getReader();
|
|
46402
|
+
const decoder = new TextDecoder();
|
|
46403
|
+
let buffer = "";
|
|
46404
|
+
const onAbort = () => {
|
|
46405
|
+
void reader.cancel().catch(() => void 0);
|
|
46406
|
+
};
|
|
46407
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
46408
|
+
try {
|
|
46409
|
+
while (true) {
|
|
46410
|
+
if (signal?.aborted) throw new Error("Request was aborted");
|
|
46411
|
+
const { done, value } = await reader.read();
|
|
46412
|
+
if (signal?.aborted) throw new Error("Request was aborted");
|
|
46413
|
+
if (done) break;
|
|
46414
|
+
buffer += decoder.decode(value, { stream: true });
|
|
46415
|
+
let idx = buffer.indexOf("\n\n");
|
|
46416
|
+
while (idx !== -1) {
|
|
46417
|
+
const chunk = buffer.slice(0, idx);
|
|
46418
|
+
buffer = buffer.slice(idx + 2);
|
|
46419
|
+
const dataLines = chunk.split("\n").filter((l) => l.startsWith("data:")).map((l) => l.slice(5).trim());
|
|
46420
|
+
if (dataLines.length > 0) {
|
|
46421
|
+
const data = dataLines.join("\n").trim();
|
|
46422
|
+
if (data && data !== "[DONE]") {
|
|
46423
|
+
try {
|
|
46424
|
+
yield JSON.parse(data);
|
|
46425
|
+
} catch {
|
|
46426
|
+
}
|
|
46427
|
+
}
|
|
46428
|
+
}
|
|
46429
|
+
idx = buffer.indexOf("\n\n");
|
|
46430
|
+
}
|
|
46431
|
+
}
|
|
46432
|
+
} finally {
|
|
46433
|
+
signal?.removeEventListener("abort", onAbort);
|
|
46434
|
+
try {
|
|
46435
|
+
await reader.cancel();
|
|
46436
|
+
} catch {
|
|
46437
|
+
}
|
|
46438
|
+
try {
|
|
46439
|
+
reader.releaseLock();
|
|
46440
|
+
} catch {
|
|
46441
|
+
}
|
|
46442
|
+
}
|
|
46443
|
+
}
|
|
46143
46444
|
var CodexResponsesTransport;
|
|
46144
46445
|
var init_codex_responses = __esm({
|
|
46145
46446
|
"packages/core/src/llm/transports/codex-responses.ts"() {
|
|
@@ -46156,111 +46457,207 @@ var init_codex_responses = __esm({
|
|
|
46156
46457
|
* @see ADR-072 §Type lock-in
|
|
46157
46458
|
*/
|
|
46158
46459
|
apiMode = "codex_responses";
|
|
46159
|
-
/**
|
|
46160
|
-
|
|
46460
|
+
/** API key / OAuth bearer token. */
|
|
46461
|
+
_apiKey;
|
|
46462
|
+
/**
|
|
46463
|
+
* Resolved endpoint URL (the full `/codex/responses` path).
|
|
46464
|
+
* Derived once at construction so the URL normalisation runs once.
|
|
46465
|
+
*/
|
|
46466
|
+
_endpointUrl;
|
|
46467
|
+
/** Extra headers merged into every request (auth, originator, etc.). */
|
|
46468
|
+
_defaultHeaders;
|
|
46161
46469
|
/**
|
|
46162
46470
|
* Construct a CodexResponsesTransport.
|
|
46163
46471
|
*
|
|
46164
|
-
* @param opts - Construction options
|
|
46165
|
-
*
|
|
46472
|
+
* @param opts - Construction options: provider, API key, optional base URL
|
|
46473
|
+
* and default headers (auth + Cloudflare-bypass headers for OAuth callers).
|
|
46166
46474
|
*/
|
|
46167
46475
|
constructor(opts) {
|
|
46168
46476
|
this.provider = opts.provider;
|
|
46169
|
-
this.
|
|
46170
|
-
|
|
46171
|
-
|
|
46172
|
-
defaultHeaders: opts.defaultHeaders
|
|
46173
|
-
});
|
|
46477
|
+
this._apiKey = opts.apiKey;
|
|
46478
|
+
this._endpointUrl = resolveCodexUrl(opts.baseUrl);
|
|
46479
|
+
this._defaultHeaders = opts.defaultHeaders ?? {};
|
|
46174
46480
|
}
|
|
46481
|
+
// ---------------------------------------------------------------------------
|
|
46482
|
+
// LlmTransport — complete()
|
|
46483
|
+
// ---------------------------------------------------------------------------
|
|
46175
46484
|
/**
|
|
46176
|
-
* Execute a single completion using the
|
|
46485
|
+
* Execute a single (non-streaming) completion using the Responses API.
|
|
46177
46486
|
*
|
|
46178
|
-
*
|
|
46179
|
-
* `
|
|
46180
|
-
*
|
|
46487
|
+
* The Codex ChatGPT backend mandates `stream: true` on every request and
|
|
46488
|
+
* returns `400 {"detail":"Stream must be set to true"}` for `stream: false`.
|
|
46489
|
+
* This method therefore always sends `stream: true` with
|
|
46490
|
+
* `Accept: text/event-stream`, internally consumes the SSE stream, and
|
|
46491
|
+
* aggregates text deltas + tool calls + usage into a {@link NormalizedResponse}
|
|
46492
|
+
* — identical to calling `stream()` and collecting all chunks.
|
|
46181
46493
|
*
|
|
46182
46494
|
* @param request - Provider-neutral request parameters.
|
|
46183
46495
|
* @param _ctx - Transport context (unused; `request.signal` handles abort).
|
|
46184
46496
|
* @returns Normalized response envelope.
|
|
46185
46497
|
*/
|
|
46186
46498
|
async complete(request, _ctx) {
|
|
46187
|
-
const
|
|
46188
|
-
const
|
|
46189
|
-
const
|
|
46190
|
-
|
|
46191
|
-
|
|
46192
|
-
|
|
46193
|
-
|
|
46499
|
+
const body = this._buildBody(request, true);
|
|
46500
|
+
const headers = this._buildHeaders(true);
|
|
46501
|
+
const res = await fetch(this._endpointUrl, {
|
|
46502
|
+
method: "POST",
|
|
46503
|
+
headers,
|
|
46504
|
+
body: JSON.stringify(body),
|
|
46505
|
+
signal: request.signal
|
|
46506
|
+
});
|
|
46507
|
+
if (!res.ok) {
|
|
46508
|
+
throw new Error(await buildHttpError(res));
|
|
46509
|
+
}
|
|
46510
|
+
if (!res.body) {
|
|
46511
|
+
throw new Error("codex_responses: response body is null (no SSE stream)");
|
|
46512
|
+
}
|
|
46513
|
+
const textParts = [];
|
|
46514
|
+
const toolCalls = [];
|
|
46515
|
+
let finalUsage = null;
|
|
46516
|
+
let finishReason = null;
|
|
46517
|
+
let responseId = null;
|
|
46518
|
+
let responseModel = null;
|
|
46519
|
+
for await (const event of parseSSE(res.body, request.signal)) {
|
|
46520
|
+
const evType = event["type"];
|
|
46521
|
+
if (evType === "response.output_text.delta") {
|
|
46522
|
+
const delta = event["delta"];
|
|
46523
|
+
if (delta) textParts.push(delta);
|
|
46524
|
+
continue;
|
|
46525
|
+
}
|
|
46526
|
+
if (evType === "response.output_item.done") {
|
|
46527
|
+
const item = event["item"];
|
|
46528
|
+
if (item?.["type"] === "function_call") {
|
|
46529
|
+
toolCalls.push({
|
|
46530
|
+
id: typeof item["call_id"] === "string" ? item["call_id"] : null,
|
|
46531
|
+
name: typeof item["name"] === "string" ? item["name"] : "unknown",
|
|
46532
|
+
arguments: typeof item["arguments"] === "string" ? item["arguments"] : "{}",
|
|
46533
|
+
providerData: {
|
|
46534
|
+
call_id: item["call_id"],
|
|
46535
|
+
response_item_id: item["id"]
|
|
46536
|
+
}
|
|
46537
|
+
});
|
|
46538
|
+
}
|
|
46539
|
+
continue;
|
|
46540
|
+
}
|
|
46541
|
+
if (evType === "response.completed") {
|
|
46542
|
+
const completedResponse = event["response"];
|
|
46543
|
+
if (completedResponse) {
|
|
46544
|
+
finishReason = completedResponse["status"] ?? "completed";
|
|
46545
|
+
responseId = completedResponse["id"] ?? null;
|
|
46546
|
+
responseModel = completedResponse["model"] ?? null;
|
|
46547
|
+
const usage = completedResponse["usage"];
|
|
46548
|
+
if (usage) finalUsage = normalizeUsage(usage);
|
|
46549
|
+
const output = completedResponse["output"] ?? [];
|
|
46550
|
+
const embeddedCalls = extractToolCallsFromOutput(
|
|
46551
|
+
output
|
|
46552
|
+
);
|
|
46553
|
+
if (embeddedCalls.length > 0 && toolCalls.length === 0) {
|
|
46554
|
+
toolCalls.push(...embeddedCalls);
|
|
46555
|
+
}
|
|
46556
|
+
}
|
|
46557
|
+
break;
|
|
46558
|
+
}
|
|
46559
|
+
if (evType === "response.failed" || evType === "response.incomplete") {
|
|
46560
|
+
const failedResponse = event["response"];
|
|
46561
|
+
if (failedResponse) {
|
|
46562
|
+
finishReason = failedResponse["status"] ?? evType;
|
|
46563
|
+
const usage = failedResponse["usage"];
|
|
46564
|
+
if (usage) finalUsage = normalizeUsage(usage);
|
|
46565
|
+
}
|
|
46566
|
+
break;
|
|
46567
|
+
}
|
|
46568
|
+
if (evType === "error") {
|
|
46569
|
+
const code = event["code"];
|
|
46570
|
+
const message = event["message"];
|
|
46571
|
+
throw new Error(`Codex error: ${message ?? code ?? JSON.stringify(event)}`);
|
|
46572
|
+
}
|
|
46573
|
+
}
|
|
46574
|
+
const content = textParts.join("") || null;
|
|
46575
|
+
return {
|
|
46576
|
+
id: responseId ?? `resp-${Date.now().toString(36)}`,
|
|
46577
|
+
model: responseModel ?? request.model,
|
|
46578
|
+
content,
|
|
46579
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : null,
|
|
46580
|
+
stopReason: finishReason ?? "completed",
|
|
46581
|
+
usage: finalUsage ?? { inputTokens: 0, outputTokens: 0 },
|
|
46582
|
+
providerData: {
|
|
46583
|
+
codex_response_id: responseId
|
|
46584
|
+
},
|
|
46585
|
+
raw: {}
|
|
46194
46586
|
};
|
|
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
46587
|
}
|
|
46588
|
+
// ---------------------------------------------------------------------------
|
|
46589
|
+
// LlmTransport — stream()
|
|
46590
|
+
// ---------------------------------------------------------------------------
|
|
46203
46591
|
/**
|
|
46204
|
-
* Stream a completion using the
|
|
46592
|
+
* Stream a completion using the Responses API SSE stream.
|
|
46205
46593
|
*
|
|
46206
46594
|
* Yields {@link NormalizedDelta} chunks from `response.output_text.delta`
|
|
46207
|
-
* events
|
|
46208
|
-
*
|
|
46595
|
+
* events parsed from the raw SSE stream. The final delta carries
|
|
46596
|
+
* `stopReason` and `usage` from `response.completed`.
|
|
46597
|
+
*
|
|
46598
|
+
* Wire shape:
|
|
46599
|
+
* - `store: false` (required — codex backend rejects absent or true)
|
|
46600
|
+
* - `stream: true`
|
|
46601
|
+
* - `Accept: text/event-stream`
|
|
46602
|
+
* - `OpenAI-Beta: responses=experimental`
|
|
46209
46603
|
*
|
|
46210
46604
|
* @param request - Provider-neutral request parameters.
|
|
46211
46605
|
* @param _ctx - Transport context (unused; `request.signal` handles abort).
|
|
46212
46606
|
* @returns Async iterable of normalized delta chunks.
|
|
46213
46607
|
*/
|
|
46214
46608
|
async *stream(request, _ctx) {
|
|
46215
|
-
const
|
|
46216
|
-
const
|
|
46217
|
-
const
|
|
46218
|
-
|
|
46219
|
-
|
|
46220
|
-
|
|
46221
|
-
|
|
46222
|
-
|
|
46223
|
-
|
|
46224
|
-
|
|
46225
|
-
|
|
46226
|
-
|
|
46227
|
-
|
|
46228
|
-
|
|
46229
|
-
);
|
|
46609
|
+
const body = this._buildBody(request, true);
|
|
46610
|
+
const headers = this._buildHeaders(true);
|
|
46611
|
+
const res = await fetch(this._endpointUrl, {
|
|
46612
|
+
method: "POST",
|
|
46613
|
+
headers,
|
|
46614
|
+
body: JSON.stringify(body),
|
|
46615
|
+
signal: request.signal
|
|
46616
|
+
});
|
|
46617
|
+
if (!res.ok) {
|
|
46618
|
+
throw new Error(await buildHttpError(res));
|
|
46619
|
+
}
|
|
46620
|
+
if (!res.body) {
|
|
46621
|
+
throw new Error("codex_responses: response body is null (no SSE stream)");
|
|
46622
|
+
}
|
|
46230
46623
|
let finishReason = null;
|
|
46231
46624
|
let finalUsage = null;
|
|
46232
|
-
for await (const event of
|
|
46233
|
-
const
|
|
46234
|
-
const evType = ev["type"];
|
|
46625
|
+
for await (const event of parseSSE(res.body, request.signal)) {
|
|
46626
|
+
const evType = event["type"];
|
|
46235
46627
|
if (evType === "response.output_text.delta") {
|
|
46236
|
-
const delta =
|
|
46628
|
+
const delta = event["delta"];
|
|
46237
46629
|
if (delta) {
|
|
46238
46630
|
yield { text: delta, reasoning: "", stopReason: null, usage: null };
|
|
46239
46631
|
}
|
|
46240
46632
|
continue;
|
|
46241
46633
|
}
|
|
46242
46634
|
if (evType === "response.completed") {
|
|
46243
|
-
const completedResponse =
|
|
46635
|
+
const completedResponse = event["response"];
|
|
46244
46636
|
if (completedResponse) {
|
|
46245
|
-
finishReason = completedResponse
|
|
46246
|
-
const usage = completedResponse
|
|
46637
|
+
finishReason = completedResponse["status"] ?? "completed";
|
|
46638
|
+
const usage = completedResponse["usage"];
|
|
46247
46639
|
if (usage) {
|
|
46248
|
-
finalUsage =
|
|
46640
|
+
finalUsage = normalizeUsage(usage);
|
|
46249
46641
|
}
|
|
46250
46642
|
}
|
|
46251
46643
|
break;
|
|
46252
46644
|
}
|
|
46253
46645
|
if (evType === "response.failed" || evType === "response.incomplete") {
|
|
46254
|
-
const failedResponse =
|
|
46646
|
+
const failedResponse = event["response"];
|
|
46255
46647
|
if (failedResponse) {
|
|
46256
|
-
finishReason = failedResponse
|
|
46257
|
-
const usage = failedResponse
|
|
46648
|
+
finishReason = failedResponse["status"] ?? evType;
|
|
46649
|
+
const usage = failedResponse["usage"];
|
|
46258
46650
|
if (usage) {
|
|
46259
|
-
finalUsage =
|
|
46651
|
+
finalUsage = normalizeUsage(usage);
|
|
46260
46652
|
}
|
|
46261
46653
|
}
|
|
46262
46654
|
break;
|
|
46263
46655
|
}
|
|
46656
|
+
if (evType === "error") {
|
|
46657
|
+
const code = event["code"];
|
|
46658
|
+
const message = event["message"];
|
|
46659
|
+
throw new Error(`Codex error: ${message ?? code ?? JSON.stringify(event)}`);
|
|
46660
|
+
}
|
|
46264
46661
|
}
|
|
46265
46662
|
yield {
|
|
46266
46663
|
text: "",
|
|
@@ -46270,128 +46667,60 @@ var init_codex_responses = __esm({
|
|
|
46270
46667
|
};
|
|
46271
46668
|
}
|
|
46272
46669
|
// ---------------------------------------------------------------------------
|
|
46273
|
-
//
|
|
46670
|
+
// Private helpers
|
|
46274
46671
|
// ---------------------------------------------------------------------------
|
|
46275
46672
|
/**
|
|
46276
|
-
*
|
|
46673
|
+
* Build the HTTP headers for a Codex request.
|
|
46277
46674
|
*
|
|
46278
|
-
*
|
|
46279
|
-
* -
|
|
46280
|
-
* - `
|
|
46281
|
-
*
|
|
46282
|
-
* - `
|
|
46283
|
-
* `toolUseId` as `call_id`.
|
|
46675
|
+
* Merges the auth/cloudflare headers from `_defaultHeaders` with the
|
|
46676
|
+
* mandatory Codex-specific headers:
|
|
46677
|
+
* - `OpenAI-Beta: responses=experimental`
|
|
46678
|
+
* - `content-type: application/json`
|
|
46679
|
+
* - `accept: text/event-stream` (always — both complete() and stream() use SSE)
|
|
46284
46680
|
*
|
|
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.
|
|
46681
|
+
* The Authorization header is injected only if not already present in
|
|
46682
|
+
* `_defaultHeaders` (OAuth callers pre-set it via buildCodexOAuthHeaders).
|
|
46289
46683
|
*
|
|
46290
|
-
* @param
|
|
46291
|
-
* @returns
|
|
46684
|
+
* @param streaming - Whether this is a streaming (SSE) or completion call.
|
|
46685
|
+
* @returns Plain string record of all request headers.
|
|
46292
46686
|
*/
|
|
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
|
-
}
|
|
46687
|
+
_buildHeaders(streaming) {
|
|
46688
|
+
const headers = {
|
|
46689
|
+
...this._defaultHeaders,
|
|
46690
|
+
"OpenAI-Beta": "responses=experimental",
|
|
46691
|
+
"content-type": "application/json",
|
|
46692
|
+
accept: streaming ? "text/event-stream" : "application/json"
|
|
46693
|
+
};
|
|
46694
|
+
const hasAuth = Object.keys(headers).some((k) => k.toLowerCase() === "authorization");
|
|
46695
|
+
if (!hasAuth) {
|
|
46696
|
+
headers["Authorization"] = `Bearer ${this._apiKey}`;
|
|
46318
46697
|
}
|
|
46319
|
-
return
|
|
46320
|
-
}
|
|
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
|
-
}));
|
|
46698
|
+
return headers;
|
|
46340
46699
|
}
|
|
46341
|
-
// ---------------------------------------------------------------------------
|
|
46342
|
-
// Response normalization
|
|
46343
|
-
// ---------------------------------------------------------------------------
|
|
46344
46700
|
/**
|
|
46345
|
-
*
|
|
46346
|
-
* {@link NormalizedResponse}.
|
|
46701
|
+
* Build the JSON request body for a Codex Responses API call.
|
|
46347
46702
|
*
|
|
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.
|
|
46703
|
+
* Mandatory fields per the Codex backend:
|
|
46704
|
+
* - `store: false` — backend rejects absent or `true`.
|
|
46705
|
+
* - `instructions` — system prompt (defaulting to empty string when absent).
|
|
46706
|
+
* - `input` — array of Responses API input items.
|
|
46356
46707
|
*
|
|
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`.
|
|
46708
|
+
* @param request - Provider-neutral request.
|
|
46709
|
+
* @param streaming - Whether to enable SSE streaming.
|
|
46710
|
+
* @returns Serialisable request body.
|
|
46383
46711
|
*/
|
|
46384
|
-
|
|
46385
|
-
|
|
46386
|
-
|
|
46387
|
-
|
|
46388
|
-
|
|
46712
|
+
_buildBody(request, streaming) {
|
|
46713
|
+
const body = {
|
|
46714
|
+
model: request.model,
|
|
46715
|
+
input: buildInputItems(request),
|
|
46716
|
+
instructions: request.system ?? "",
|
|
46717
|
+
store: false,
|
|
46718
|
+
stream: streaming
|
|
46389
46719
|
};
|
|
46390
|
-
|
|
46391
|
-
|
|
46392
|
-
|
|
46393
|
-
|
|
46394
|
-
return normalized;
|
|
46720
|
+
if (request.temperature != null) body.temperature = request.temperature;
|
|
46721
|
+
const tools = buildTools(request.tools);
|
|
46722
|
+
if (tools.length > 0) body.tools = tools;
|
|
46723
|
+
return body;
|
|
46395
46724
|
}
|
|
46396
46725
|
};
|
|
46397
46726
|
}
|
|
@@ -75237,6 +75566,318 @@ var init_model_runner = __esm({
|
|
|
75237
75566
|
}
|
|
75238
75567
|
});
|
|
75239
75568
|
|
|
75569
|
+
// packages/core/src/llm/catalog-model-resolver.ts
|
|
75570
|
+
var catalog_model_resolver_exports = {};
|
|
75571
|
+
__export(catalog_model_resolver_exports, {
|
|
75572
|
+
_resetCatalogModelResolverCache: () => _resetCatalogModelResolverCache,
|
|
75573
|
+
catalogKeyForProvider: () => catalogKeyForProvider,
|
|
75574
|
+
listProviderModels: () => listProviderModels,
|
|
75575
|
+
resolveProviderDefaultModel: () => resolveProviderDefaultModel,
|
|
75576
|
+
validateModelForProvider: () => validateModelForProvider
|
|
75577
|
+
});
|
|
75578
|
+
function getDiskCatalog() {
|
|
75579
|
+
if (_catalog !== void 0) return _catalog;
|
|
75580
|
+
const dir = getCatalogDir();
|
|
75581
|
+
const latest = findLatestCacheFile(dir);
|
|
75582
|
+
if (!latest) {
|
|
75583
|
+
_catalog = null;
|
|
75584
|
+
return null;
|
|
75585
|
+
}
|
|
75586
|
+
_catalog = readCacheFile(latest);
|
|
75587
|
+
return _catalog;
|
|
75588
|
+
}
|
|
75589
|
+
function resolveProviderDefaultModel(providerCatalogKey, catalogOverride) {
|
|
75590
|
+
const catalog = catalogOverride ?? getDiskCatalog();
|
|
75591
|
+
if (!catalog) return null;
|
|
75592
|
+
const provider = catalog[providerCatalogKey];
|
|
75593
|
+
if (!provider?.models) return null;
|
|
75594
|
+
let latestId = null;
|
|
75595
|
+
let latestDate = "";
|
|
75596
|
+
for (const [id, entry] of Object.entries(provider.models)) {
|
|
75597
|
+
const rd = entry.release_date;
|
|
75598
|
+
if (!rd) continue;
|
|
75599
|
+
if (rd > latestDate) {
|
|
75600
|
+
latestDate = rd;
|
|
75601
|
+
latestId = id;
|
|
75602
|
+
}
|
|
75603
|
+
}
|
|
75604
|
+
return latestId;
|
|
75605
|
+
}
|
|
75606
|
+
function validateModelForProvider(model, providerCatalogKey, catalogOverride) {
|
|
75607
|
+
const catalog = catalogOverride ?? getDiskCatalog();
|
|
75608
|
+
if (!catalog) {
|
|
75609
|
+
return { valid: true, reason: "catalog-unavailable" };
|
|
75610
|
+
}
|
|
75611
|
+
const provider = catalog[providerCatalogKey];
|
|
75612
|
+
if (!provider?.models) {
|
|
75613
|
+
return { valid: true, reason: "provider-not-in-catalog" };
|
|
75614
|
+
}
|
|
75615
|
+
const found = Object.hasOwn(provider.models, model);
|
|
75616
|
+
return { valid: found, reason: found ? "found" : "not-found" };
|
|
75617
|
+
}
|
|
75618
|
+
function listProviderModels(providerCatalogKey, limit = 12, catalogOverride) {
|
|
75619
|
+
const catalog = catalogOverride ?? getDiskCatalog();
|
|
75620
|
+
if (!catalog) return [];
|
|
75621
|
+
const provider = catalog[providerCatalogKey];
|
|
75622
|
+
if (!provider?.models) return [];
|
|
75623
|
+
const entries = Object.entries(provider.models);
|
|
75624
|
+
const sorted = [...entries].sort(([, a], [, b]) => {
|
|
75625
|
+
const da = a.release_date ?? "";
|
|
75626
|
+
const db = b.release_date ?? "";
|
|
75627
|
+
if (da === db) return 0;
|
|
75628
|
+
return db.localeCompare(da);
|
|
75629
|
+
});
|
|
75630
|
+
return sorted.slice(0, Math.max(0, limit)).map(([id]) => id);
|
|
75631
|
+
}
|
|
75632
|
+
function catalogKeyForProvider(providerName) {
|
|
75633
|
+
const PROVIDER_KEY_MAP = {
|
|
75634
|
+
gemini: "google"
|
|
75635
|
+
// CLEO name → models.dev key overrides only (identical mappings are omitted)
|
|
75636
|
+
};
|
|
75637
|
+
return PROVIDER_KEY_MAP[providerName.toLowerCase()] ?? providerName.toLowerCase();
|
|
75638
|
+
}
|
|
75639
|
+
function _resetCatalogModelResolverCache() {
|
|
75640
|
+
_catalog = void 0;
|
|
75641
|
+
}
|
|
75642
|
+
var _catalog;
|
|
75643
|
+
var init_catalog_model_resolver = __esm({
|
|
75644
|
+
"packages/core/src/llm/catalog-model-resolver.ts"() {
|
|
75645
|
+
"use strict";
|
|
75646
|
+
init_catalog_cache();
|
|
75647
|
+
}
|
|
75648
|
+
});
|
|
75649
|
+
|
|
75650
|
+
// packages/core/src/llm/cross-provider-selector.ts
|
|
75651
|
+
import { totalmem } from "node:os";
|
|
75652
|
+
async function probeOllamaAlive(baseUrl) {
|
|
75653
|
+
const cached2 = _ollamaProbeCache.get(baseUrl);
|
|
75654
|
+
if (cached2 && Date.now() - cached2.checkedAt < OLLAMA_PROBE_TTL_MS) {
|
|
75655
|
+
return cached2.alive;
|
|
75656
|
+
}
|
|
75657
|
+
let alive = false;
|
|
75658
|
+
try {
|
|
75659
|
+
const controller = new AbortController();
|
|
75660
|
+
const timeoutId = setTimeout(() => controller.abort(), OLLAMA_PROBE_TIMEOUT_MS);
|
|
75661
|
+
try {
|
|
75662
|
+
const res = await fetch(baseUrl, { signal: controller.signal });
|
|
75663
|
+
alive = res.ok || res.status < 500;
|
|
75664
|
+
} finally {
|
|
75665
|
+
clearTimeout(timeoutId);
|
|
75666
|
+
}
|
|
75667
|
+
} catch {
|
|
75668
|
+
alive = false;
|
|
75669
|
+
}
|
|
75670
|
+
_ollamaProbeCache.set(baseUrl, { alive, checkedAt: Date.now() });
|
|
75671
|
+
return alive;
|
|
75672
|
+
}
|
|
75673
|
+
function ollamaDefaultModelForTier(tier, ramBytesOverride) {
|
|
75674
|
+
const ramBytes = ramBytesOverride ?? totalmem();
|
|
75675
|
+
const gb = ramBytes / 1024 ** 3;
|
|
75676
|
+
if (gb >= 8) {
|
|
75677
|
+
return tier === "fast" || tier === "local" ? "gemma4:e2b" : "gemma4:e4b";
|
|
75678
|
+
}
|
|
75679
|
+
if (gb >= 4) {
|
|
75680
|
+
return "gemma4:e2b";
|
|
75681
|
+
}
|
|
75682
|
+
logger4.warn(
|
|
75683
|
+
{ ramGb: gb.toFixed(1), tier },
|
|
75684
|
+
"cross-provider-selector: RAM < 4 GB; selecting qwen2:0.5b (proof-of-life only \u2014 not suitable for production)"
|
|
75685
|
+
);
|
|
75686
|
+
return "qwen2:0.5b";
|
|
75687
|
+
}
|
|
75688
|
+
function isProvisioned(provider) {
|
|
75689
|
+
if (provider === "ollama") {
|
|
75690
|
+
if (process.env["OLLAMA_HOST"]?.trim()) return true;
|
|
75691
|
+
const stored = pickCredentialForProviderSync(provider, { strategy: "priorityOnly" });
|
|
75692
|
+
return stored !== null;
|
|
75693
|
+
}
|
|
75694
|
+
const cred = resolveCredentials(provider);
|
|
75695
|
+
return (cred.apiKey?.trim().length ?? 0) > 0;
|
|
75696
|
+
}
|
|
75697
|
+
function scoreProvider(provider, providerTier, taskTier, ollamaAlive, costInputPerMillion) {
|
|
75698
|
+
let score = TIER_BASE[providerTier];
|
|
75699
|
+
if (taskTier === "frontier" && providerTier === "frontier") {
|
|
75700
|
+
score += TASK_MATCH_BONUS_FRONTIER;
|
|
75701
|
+
} else if ((taskTier === "fast" || taskTier === "local") && (providerTier === "fast" || providerTier === "local")) {
|
|
75702
|
+
score += TASK_MATCH_BONUS_FAST;
|
|
75703
|
+
}
|
|
75704
|
+
if (providerTier === "local" && ollamaAlive) {
|
|
75705
|
+
score += LOCALITY_BONUS;
|
|
75706
|
+
}
|
|
75707
|
+
if ((providerTier === "frontier" || providerTier === "standard") && provider !== "ollama") {
|
|
75708
|
+
score += PROVISIONED_CLOUD_BIAS;
|
|
75709
|
+
}
|
|
75710
|
+
const penalty = Math.min(Math.floor(costInputPerMillion / 10), MAX_COST_PENALTY);
|
|
75711
|
+
score -= penalty;
|
|
75712
|
+
return score;
|
|
75713
|
+
}
|
|
75714
|
+
function roleTierFor(role) {
|
|
75715
|
+
switch (role) {
|
|
75716
|
+
case "consolidation":
|
|
75717
|
+
case "judgement":
|
|
75718
|
+
case "hygiene":
|
|
75719
|
+
return "frontier";
|
|
75720
|
+
case "extraction":
|
|
75721
|
+
case "derivation":
|
|
75722
|
+
return "standard";
|
|
75723
|
+
default:
|
|
75724
|
+
return "fast";
|
|
75725
|
+
}
|
|
75726
|
+
}
|
|
75727
|
+
async function selectBestProvisioned(role, opts) {
|
|
75728
|
+
const taskTier = roleTierFor(role);
|
|
75729
|
+
for (const id of BUILTIN_PROVIDER_IDS) {
|
|
75730
|
+
const creds = await listCredentials(id);
|
|
75731
|
+
const hasExpiredOAuth = creds.some(
|
|
75732
|
+
(c) => c.authType === "oauth" && c.refreshToken && typeof c.expiresAt === "number" && c.expiresAt > 0 && c.expiresAt <= Date.now()
|
|
75733
|
+
);
|
|
75734
|
+
if (!hasExpiredOAuth) continue;
|
|
75735
|
+
try {
|
|
75736
|
+
const result = await refreshExpiredOAuthForProvider(id);
|
|
75737
|
+
if (result.actionableHint) {
|
|
75738
|
+
logger4.warn(
|
|
75739
|
+
{ provider: id, hint: result.actionableHint },
|
|
75740
|
+
"cross-provider-selector: OAuth refresh-on-use failed \u2014 credential will be excluded from resolution"
|
|
75741
|
+
);
|
|
75742
|
+
} else if (result.refreshed > 0) {
|
|
75743
|
+
logger4.debug(
|
|
75744
|
+
{ provider: id, refreshed: result.refreshed },
|
|
75745
|
+
"cross-provider-selector: renewed expired OAuth credential via refresh-on-use"
|
|
75746
|
+
);
|
|
75747
|
+
}
|
|
75748
|
+
} catch {
|
|
75749
|
+
}
|
|
75750
|
+
}
|
|
75751
|
+
const provisionedIds = [];
|
|
75752
|
+
for (const id of BUILTIN_PROVIDER_IDS) {
|
|
75753
|
+
if (isProvisioned(id)) {
|
|
75754
|
+
provisionedIds.push(id);
|
|
75755
|
+
}
|
|
75756
|
+
}
|
|
75757
|
+
if (provisionedIds.length === 0) {
|
|
75758
|
+
logger4.warn(
|
|
75759
|
+
{
|
|
75760
|
+
providers_checked: BUILTIN_PROVIDER_IDS.slice(),
|
|
75761
|
+
reason: "no-provisioned-provider",
|
|
75762
|
+
role,
|
|
75763
|
+
projectRoot: opts.projectRoot
|
|
75764
|
+
},
|
|
75765
|
+
"resolveLLMForSystem: no provider has a usable credential; returning null-credential envelope"
|
|
75766
|
+
);
|
|
75767
|
+
return null;
|
|
75768
|
+
}
|
|
75769
|
+
const { getProviderProfile: getProviderProfile2 } = await Promise.resolve().then(() => (init_provider_registry(), provider_registry_exports));
|
|
75770
|
+
const { resolveProviderDefaultModel: resolveProviderDefaultModel2, catalogKeyForProvider: catalogKeyForProvider2 } = await Promise.resolve().then(() => (init_catalog_model_resolver(), catalog_model_resolver_exports));
|
|
75771
|
+
const { pickCredentialForProvider: pickCredentialForProvider2 } = await Promise.resolve().then(() => (init_credentials_store(), credentials_store_exports));
|
|
75772
|
+
const ollamaProvisioned = provisionedIds.includes("ollama");
|
|
75773
|
+
let ollamaAlive = false;
|
|
75774
|
+
if (ollamaProvisioned) {
|
|
75775
|
+
const profile = await getProviderProfile2("ollama");
|
|
75776
|
+
const ollamaBase = profile?.baseUrl ?? "http://localhost:11434";
|
|
75777
|
+
ollamaAlive = await probeOllamaAlive(ollamaBase);
|
|
75778
|
+
}
|
|
75779
|
+
const scored = [];
|
|
75780
|
+
for (const id of provisionedIds) {
|
|
75781
|
+
const profile = await getProviderProfile2(id);
|
|
75782
|
+
const tier = profile?.tier ?? "standard";
|
|
75783
|
+
const costInput = 0;
|
|
75784
|
+
const score = scoreProvider(id, tier, taskTier, ollamaAlive, costInput);
|
|
75785
|
+
const storedCred = await pickCredentialForProvider2(id, { strategy: "priorityOnly" });
|
|
75786
|
+
const credentialPriority = storedCred?.priority ?? Number.MAX_SAFE_INTEGER;
|
|
75787
|
+
scored.push({ id, tier, score, credentialPriority });
|
|
75788
|
+
}
|
|
75789
|
+
scored.sort((a, b) => {
|
|
75790
|
+
if (b.score !== a.score) return b.score - a.score;
|
|
75791
|
+
return a.credentialPriority - b.credentialPriority;
|
|
75792
|
+
});
|
|
75793
|
+
const winner = scored[0];
|
|
75794
|
+
if (!winner) return null;
|
|
75795
|
+
let model;
|
|
75796
|
+
if (winner.id === "ollama") {
|
|
75797
|
+
const ollamaProfile2 = await getProviderProfile2("ollama");
|
|
75798
|
+
const ramBytes = totalmem();
|
|
75799
|
+
const gb = ramBytes / 1024 ** 3;
|
|
75800
|
+
if (gb >= 8) {
|
|
75801
|
+
model = (winner.tier === "fast" || taskTier === "fast" ? ollamaProfile2?.defaultAuxModel : ollamaProfile2?.defaultModel) ?? ollamaDefaultModelForTier(winner.tier);
|
|
75802
|
+
} else if (gb >= 4) {
|
|
75803
|
+
model = ollamaProfile2?.defaultAuxModel ?? "gemma4:e2b";
|
|
75804
|
+
} else {
|
|
75805
|
+
model = ollamaDefaultModelForTier(winner.tier, ramBytes);
|
|
75806
|
+
}
|
|
75807
|
+
const catalogKey = catalogKeyForProvider2(winner.id);
|
|
75808
|
+
const catalogModel = resolveProviderDefaultModel2(catalogKey);
|
|
75809
|
+
if (!catalogModel?.startsWith("gemma4")) {
|
|
75810
|
+
logger4.info(
|
|
75811
|
+
{ provider: "ollama", selectedModel: model },
|
|
75812
|
+
"cross-provider-selector: gemma4 family not in catalog snapshot \u2014 run `cleo llm refresh-catalog` to pull latest"
|
|
75813
|
+
);
|
|
75814
|
+
}
|
|
75815
|
+
} else {
|
|
75816
|
+
try {
|
|
75817
|
+
const catalogKey = catalogKeyForProvider2(winner.id);
|
|
75818
|
+
const catalogModel = resolveProviderDefaultModel2(catalogKey);
|
|
75819
|
+
const profileModel = (await getProviderProfile2(winner.id))?.defaultModel;
|
|
75820
|
+
model = catalogModel ?? profileModel ?? "unknown";
|
|
75821
|
+
} catch {
|
|
75822
|
+
model = (await getProviderProfile2(winner.id))?.defaultModel ?? "unknown";
|
|
75823
|
+
}
|
|
75824
|
+
}
|
|
75825
|
+
logger4.debug(
|
|
75826
|
+
{
|
|
75827
|
+
winner: winner.id,
|
|
75828
|
+
score: winner.score,
|
|
75829
|
+
taskTier,
|
|
75830
|
+
model,
|
|
75831
|
+
provisionedCount: provisionedIds.length
|
|
75832
|
+
},
|
|
75833
|
+
"cross-provider-selector: selected best provisioned provider"
|
|
75834
|
+
);
|
|
75835
|
+
return {
|
|
75836
|
+
provider: winner.id,
|
|
75837
|
+
model,
|
|
75838
|
+
credentialLabel: void 0,
|
|
75839
|
+
source: "cross-provider"
|
|
75840
|
+
};
|
|
75841
|
+
}
|
|
75842
|
+
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;
|
|
75843
|
+
var init_cross_provider_selector = __esm({
|
|
75844
|
+
"packages/core/src/llm/cross-provider-selector.ts"() {
|
|
75845
|
+
"use strict";
|
|
75846
|
+
init_logger2();
|
|
75847
|
+
init_credential_pool();
|
|
75848
|
+
init_credentials2();
|
|
75849
|
+
init_credentials_store();
|
|
75850
|
+
logger4 = getLogger("llm-cross-provider-selector");
|
|
75851
|
+
BUILTIN_PROVIDER_IDS = [
|
|
75852
|
+
"anthropic",
|
|
75853
|
+
"openai",
|
|
75854
|
+
"gemini",
|
|
75855
|
+
"moonshot",
|
|
75856
|
+
"openrouter",
|
|
75857
|
+
"bedrock",
|
|
75858
|
+
"deepseek",
|
|
75859
|
+
"xai",
|
|
75860
|
+
"groq",
|
|
75861
|
+
"kimi-code",
|
|
75862
|
+
"ollama"
|
|
75863
|
+
];
|
|
75864
|
+
TIER_BASE = {
|
|
75865
|
+
frontier: 100,
|
|
75866
|
+
standard: 70,
|
|
75867
|
+
fast: 50,
|
|
75868
|
+
local: 120
|
|
75869
|
+
};
|
|
75870
|
+
PROVISIONED_CLOUD_BIAS = 60;
|
|
75871
|
+
LOCALITY_BONUS = 30;
|
|
75872
|
+
TASK_MATCH_BONUS_FRONTIER = 20;
|
|
75873
|
+
TASK_MATCH_BONUS_FAST = 15;
|
|
75874
|
+
MAX_COST_PENALTY = 10;
|
|
75875
|
+
OLLAMA_PROBE_TIMEOUT_MS = 200;
|
|
75876
|
+
OLLAMA_PROBE_TTL_MS = 3e4;
|
|
75877
|
+
_ollamaProbeCache = /* @__PURE__ */ new Map();
|
|
75878
|
+
}
|
|
75879
|
+
});
|
|
75880
|
+
|
|
75240
75881
|
// packages/core/src/llm/sealed-credential.ts
|
|
75241
75882
|
function tokenPreview(token, authType) {
|
|
75242
75883
|
const prefix = authType === "oauth" ? "oat-\u2026" : "\u2026";
|
|
@@ -75285,14 +75926,14 @@ function getRegisteredSystemDefault(key) {
|
|
|
75285
75926
|
if (!isResolvableSystemDefault(record2.defaults)) return void 0;
|
|
75286
75927
|
return record2.defaults;
|
|
75287
75928
|
}
|
|
75288
|
-
var
|
|
75929
|
+
var logger5, REGISTRY;
|
|
75289
75930
|
var init_system_of_use_registry = __esm({
|
|
75290
75931
|
"packages/core/src/llm/system-of-use-registry.ts"() {
|
|
75291
75932
|
"use strict";
|
|
75292
75933
|
init_src();
|
|
75293
75934
|
init_logger2();
|
|
75294
75935
|
init_system_key();
|
|
75295
|
-
|
|
75936
|
+
logger5 = getLogger("llm-system-of-use-registry");
|
|
75296
75937
|
REGISTRY = /* @__PURE__ */ new Map();
|
|
75297
75938
|
}
|
|
75298
75939
|
});
|
|
@@ -75380,7 +76021,7 @@ function resolveRegisteredSystemDefault(llm, systemKey) {
|
|
|
75380
76021
|
}
|
|
75381
76022
|
return void 0;
|
|
75382
76023
|
}
|
|
75383
|
-
function selectProviderModel(llm, role, systemKey, profileOverride) {
|
|
76024
|
+
async function selectProviderModel(llm, role, systemKey, profileOverride, projectRoot) {
|
|
75384
76025
|
const roleEntry = llm?.roles?.[role];
|
|
75385
76026
|
const pinnedProfile = resolveNamedProfile(llm, profileOverride, "profile");
|
|
75386
76027
|
if (pinnedProfile) return pinnedProfile;
|
|
@@ -75409,6 +76050,15 @@ function selectProviderModel(llm, role, systemKey, profileOverride) {
|
|
|
75409
76050
|
if (defaultProfile) return defaultProfile;
|
|
75410
76051
|
const registeredDefault = resolveRegisteredSystemDefault(llm, systemKey);
|
|
75411
76052
|
if (registeredDefault) return registeredDefault;
|
|
76053
|
+
try {
|
|
76054
|
+
const crossProviderResult = await selectBestProvisioned(role, {
|
|
76055
|
+
projectRoot: projectRoot ?? ""
|
|
76056
|
+
});
|
|
76057
|
+
if (crossProviderResult !== null) {
|
|
76058
|
+
return crossProviderResult;
|
|
76059
|
+
}
|
|
76060
|
+
} catch {
|
|
76061
|
+
}
|
|
75412
76062
|
return {
|
|
75413
76063
|
provider: IMPLICIT_FALLBACK_PROVIDER,
|
|
75414
76064
|
model: IMPLICIT_FALLBACK_MODEL,
|
|
@@ -75468,11 +76118,12 @@ async function resolveLLMForRole(role, opts) {
|
|
|
75468
76118
|
config2 = void 0;
|
|
75469
76119
|
}
|
|
75470
76120
|
const llmBlock = readLlmBlock(config2);
|
|
75471
|
-
const { provider, model, credentialLabel, source } = selectProviderModel(
|
|
76121
|
+
const { provider, model, credentialLabel, source } = await selectProviderModel(
|
|
75472
76122
|
llmBlock,
|
|
75473
76123
|
role,
|
|
75474
76124
|
opts?.systemKey,
|
|
75475
|
-
opts?.profileOverride
|
|
76125
|
+
opts?.profileOverride,
|
|
76126
|
+
projectRoot
|
|
75476
76127
|
);
|
|
75477
76128
|
const { credential, usedLabel } = await resolveCredentialForRole(
|
|
75478
76129
|
provider,
|
|
@@ -75550,6 +76201,7 @@ var init_role_resolver = __esm({
|
|
|
75550
76201
|
init_credential_pool();
|
|
75551
76202
|
init_credentials2();
|
|
75552
76203
|
init_credentials_store();
|
|
76204
|
+
init_cross_provider_selector();
|
|
75553
76205
|
init_fallback_model();
|
|
75554
76206
|
init_sealed_credential();
|
|
75555
76207
|
init_system_of_use_registry();
|