@vizuh/sabi 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/mod/sabi.mjs +155 -11
- package/package.json +4 -2
- package/sabi.config.json +16 -15
package/README.md
CHANGED
|
@@ -18,7 +18,9 @@ The two paths are independent:
|
|
|
18
18
|
- The Command Code mod needs no Sabi provider key or proxy. It routes the subscription already
|
|
19
19
|
available to Command Code.
|
|
20
20
|
- The local proxy works with OpenCode, Hermes, Kilo, and other OpenAI-compatible clients. It uses
|
|
21
|
-
OpenRouter, Ollama, or another configured upstream.
|
|
21
|
+
OpenRouter, Ollama, or another configured upstream. In the shipped default the OpenRouter
|
|
22
|
+
upstream is **free-models-only** (`paidModelsAllowed: false`): a priced model id is refused
|
|
23
|
+
before the request leaves the process, so the proxy cannot spend on its own.
|
|
22
24
|
|
|
23
25
|
For the proxy, Sabi loads only the credential names referenced by `sabi.config.json`. Existing
|
|
24
26
|
environment variables win, followed by `SABI_SECRETS_FILE`, the nearest workspace `secrets/.env`,
|
package/mod/sabi.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @vizuh/sabi 0.
|
|
1
|
+
// @vizuh/sabi 0.2.0 — generated by pack.mjs from packages/adapters/command-code/mod/sabi.ts.
|
|
2
2
|
// Source and docs: https://github.com/vizuh/sabi
|
|
3
3
|
|
|
4
4
|
// packages/core/src/telemetry.ts
|
|
@@ -163,8 +163,8 @@ function normalizeTrajectoryEvidence(value, fallbackGeneration = 0) {
|
|
|
163
163
|
};
|
|
164
164
|
}
|
|
165
165
|
function boundTrajectoryEvidence(values, maxItems = MAX_EVIDENCE_ITEMS) {
|
|
166
|
-
const
|
|
167
|
-
if (maxItems <= 0) return
|
|
166
|
+
const result2 = [];
|
|
167
|
+
if (maxItems <= 0) return result2;
|
|
168
168
|
const seen = /* @__PURE__ */ new Set();
|
|
169
169
|
for (const value of values ?? []) {
|
|
170
170
|
const item = normalizeTrajectoryEvidence(value);
|
|
@@ -172,10 +172,10 @@ function boundTrajectoryEvidence(values, maxItems = MAX_EVIDENCE_ITEMS) {
|
|
|
172
172
|
const key = JSON.stringify(item);
|
|
173
173
|
if (seen.has(key)) continue;
|
|
174
174
|
seen.add(key);
|
|
175
|
-
|
|
176
|
-
if (
|
|
175
|
+
result2.push(item);
|
|
176
|
+
if (result2.length >= Math.max(0, Math.min(maxItems, MAX_EVIDENCE_ITEMS))) break;
|
|
177
177
|
}
|
|
178
|
-
return
|
|
178
|
+
return result2;
|
|
179
179
|
}
|
|
180
180
|
function countScope(value) {
|
|
181
181
|
if (typeof value === "number") return Number.isSafeInteger(value) && value >= 0 ? { count: value } : {};
|
|
@@ -591,6 +591,96 @@ function firstServingTier(tiers, required, declared) {
|
|
|
591
591
|
return void 0;
|
|
592
592
|
}
|
|
593
593
|
|
|
594
|
+
// packages/core/src/cache-routing.ts
|
|
595
|
+
var SWITCH_ACTIONS = /* @__PURE__ */ new Set([
|
|
596
|
+
"escalate-model",
|
|
597
|
+
"fresh-context",
|
|
598
|
+
"rollback-with-reflection",
|
|
599
|
+
"retry-with-feedback"
|
|
600
|
+
]);
|
|
601
|
+
function finiteNonNegative(value) {
|
|
602
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
603
|
+
}
|
|
604
|
+
function boundedTokens(value) {
|
|
605
|
+
return Number.isSafeInteger(value) && finiteNonNegative(value) ? value : void 0;
|
|
606
|
+
}
|
|
607
|
+
function cacheObservationFromUsage(usage) {
|
|
608
|
+
if (!usage || !Number.isSafeInteger(usage.promptTokens) || usage.promptTokens < 0 || !Number.isSafeInteger(usage.cachedTokens) || usage.cachedTokens < 0) {
|
|
609
|
+
return { status: "unknown" };
|
|
610
|
+
}
|
|
611
|
+
const cachedTokens = Math.min(usage.promptTokens, usage.cachedTokens);
|
|
612
|
+
return {
|
|
613
|
+
status: cachedTokens > 0 ? "hit" : "miss",
|
|
614
|
+
promptTokens: usage.promptTokens,
|
|
615
|
+
cachedTokens
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function phaseOf(input, sameToolCycle) {
|
|
619
|
+
if (input.state.failure === "hard") return "failure";
|
|
620
|
+
if (input.recoveryAction && SWITCH_ACTIONS.has(input.recoveryAction)) return "escalation";
|
|
621
|
+
if (sameToolCycle) return "same-tool-cycle";
|
|
622
|
+
if (input.previousTier !== void 0) return "new-phase";
|
|
623
|
+
return "unknown";
|
|
624
|
+
}
|
|
625
|
+
function routeCost(rate, tokens) {
|
|
626
|
+
return finiteNonNegative(rate) && boundedTokens(tokens) !== void 0 ? rate * tokens / 1e6 : void 0;
|
|
627
|
+
}
|
|
628
|
+
function switchEconomics(input, cachedTokens, contextTokens) {
|
|
629
|
+
const expectedGain = input.previousCost && input.plannedCost && contextTokens !== void 0 ? routeCost(Math.max(0, input.previousCost.input - input.plannedCost.input), contextTokens) : void 0;
|
|
630
|
+
const cachePenalty = input.previousCost && input.plannedCost && cachedTokens !== void 0 ? routeCost(Math.max(0, input.plannedCost.input - (input.previousCost.cacheRead ?? input.previousCost.input)), cachedTokens) : void 0;
|
|
631
|
+
return {
|
|
632
|
+
...expectedGain !== void 0 ? { expectedGain } : {},
|
|
633
|
+
...cachePenalty !== void 0 ? { cachePenalty } : {}
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
function result(input, action, phase, selectedTier, reason, extra = {}) {
|
|
637
|
+
const cache = input.previousCache;
|
|
638
|
+
const contextTokens = boundedTokens(input.state.contextTokens) ?? boundedTokens(input.state.estimatedTokens);
|
|
639
|
+
const cachedTokens = boundedTokens(cache?.cachedTokens);
|
|
640
|
+
const reprocessTokens = cache?.status === "hit" && cachedTokens !== void 0 ? cachedTokens : void 0;
|
|
641
|
+
return {
|
|
642
|
+
action,
|
|
643
|
+
phase,
|
|
644
|
+
cacheStatus: cache?.status ?? "unknown",
|
|
645
|
+
plannedTier: input.plannedTier,
|
|
646
|
+
selectedTier,
|
|
647
|
+
...input.previousTier !== void 0 ? { previousTier: input.previousTier } : {},
|
|
648
|
+
...contextTokens !== void 0 ? { estimatedContextTokens: contextTokens } : {},
|
|
649
|
+
...cachedTokens !== void 0 ? { cachedTokens } : {},
|
|
650
|
+
...reprocessTokens !== void 0 ? { reprocessTokens } : {},
|
|
651
|
+
...extra,
|
|
652
|
+
reason
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
function cacheAwareRoute(input) {
|
|
656
|
+
const sameToolCycle = input.state.lastRole === "tool" && input.previousTier !== void 0 && (input.state.contextGeneration ?? 0) === (input.previousGeneration ?? 0);
|
|
657
|
+
const phase = phaseOf(input, sameToolCycle);
|
|
658
|
+
const canKeep = input.previousTier !== void 0 && input.canKeepPrevious !== false;
|
|
659
|
+
const cache = input.previousCache;
|
|
660
|
+
const cachedTokens = boundedTokens(cache?.cachedTokens);
|
|
661
|
+
const contextTokens = boundedTokens(input.state.contextTokens) ?? boundedTokens(input.state.estimatedTokens);
|
|
662
|
+
const economics = switchEconomics(input, cachedTokens, contextTokens);
|
|
663
|
+
if (!input.previousTier || !canKeep) {
|
|
664
|
+
return result(input, "evaluate", phase, input.plannedTier, "no usable previous route affinity; policy decision evaluated", economics);
|
|
665
|
+
}
|
|
666
|
+
if (input.plannedTier === input.previousTier) {
|
|
667
|
+
return result(input, "evaluate", phase, input.previousTier, "policy selected the current model; route unchanged", economics);
|
|
668
|
+
}
|
|
669
|
+
if (phase === "same-tool-cycle") {
|
|
670
|
+
return result(input, "keep", phase, input.previousTier, "same tool cycle; keep the current model", economics);
|
|
671
|
+
}
|
|
672
|
+
if (phase === "failure" || phase === "escalation") {
|
|
673
|
+
return result(input, "switch", phase, input.plannedTier, "failure or escalation requires evaluating a different model", economics);
|
|
674
|
+
}
|
|
675
|
+
if (cache?.status === "hit" && cachedTokens !== void 0 && economics.expectedGain !== void 0 && economics.cachePenalty !== void 0 && economics.expectedGain > economics.cachePenalty) {
|
|
676
|
+
return result(input, "switch", phase, input.plannedTier, "expected cost gain exceeds the measured cache penalty", economics);
|
|
677
|
+
}
|
|
678
|
+
if (cache?.status === "hit" && cachedTokens !== void 0) {
|
|
679
|
+
return result(input, "keep", phase, input.previousTier, "cache hit retained; unpriced policy gain does not exceed cache loss", economics);
|
|
680
|
+
}
|
|
681
|
+
return result(input, "switch", phase, input.plannedTier, "policy changed phase without a measured cache hit to preserve", economics);
|
|
682
|
+
}
|
|
683
|
+
|
|
594
684
|
// packages/core/src/config.ts
|
|
595
685
|
import { existsSync, readFileSync } from "node:fs";
|
|
596
686
|
import os from "node:os";
|
|
@@ -770,6 +860,9 @@ function validateConfig(value, source = "<inline>") {
|
|
|
770
860
|
if (upstream.enabled !== void 0 && typeof upstream.enabled !== "boolean") {
|
|
771
861
|
throw new Error(`Sabi config ${source}: upstream '${name}'.enabled must be a boolean`);
|
|
772
862
|
}
|
|
863
|
+
if (upstream.paidModelsAllowed !== void 0 && typeof upstream.paidModelsAllowed !== "boolean") {
|
|
864
|
+
throw new Error(`Sabi config ${source}: upstream '${name}'.paidModelsAllowed must be a boolean`);
|
|
865
|
+
}
|
|
773
866
|
}
|
|
774
867
|
if (!Object.keys(models).length) throw new Error(`Sabi config ${source}: no models declared`);
|
|
775
868
|
for (const [name, model] of Object.entries(models)) {
|
|
@@ -1115,6 +1208,7 @@ function sanitizeDecisionRecord(record, config) {
|
|
|
1115
1208
|
upstreamModel: record.upstreamModel,
|
|
1116
1209
|
stream: record.stream,
|
|
1117
1210
|
state,
|
|
1211
|
+
cache: record.cache,
|
|
1118
1212
|
judge: record.judge,
|
|
1119
1213
|
usage: record.usage,
|
|
1120
1214
|
cost: record.cost,
|
|
@@ -1211,6 +1305,20 @@ function planRound(state, policy, tiers, options = {}) {
|
|
|
1211
1305
|
rule = "capability";
|
|
1212
1306
|
tier = alternate;
|
|
1213
1307
|
}
|
|
1308
|
+
const cache = cacheAwareRoute({
|
|
1309
|
+
state: withWindow,
|
|
1310
|
+
plannedTier: tier,
|
|
1311
|
+
previousTier: options.previous?.tier,
|
|
1312
|
+
previousLastRole: options.previous?.lastRole,
|
|
1313
|
+
previousGeneration: options.previous?.generation,
|
|
1314
|
+
previousCache: options.previous?.cache,
|
|
1315
|
+
canKeepPrevious: Boolean(options.previous?.tier && tiers[options.previous.tier] && servesInputModalities(tiers[options.previous.tier]?.inputModalities, required))
|
|
1316
|
+
});
|
|
1317
|
+
if (cache.selectedTier !== tier) {
|
|
1318
|
+
tier = cache.selectedTier;
|
|
1319
|
+
rule = "cache-affinity";
|
|
1320
|
+
reason = cache.reason;
|
|
1321
|
+
}
|
|
1214
1322
|
const chosen = tiers[tier];
|
|
1215
1323
|
if (!chosen || !chosen.model) return void 0;
|
|
1216
1324
|
return {
|
|
@@ -1219,13 +1327,31 @@ function planRound(state, policy, tiers, options = {}) {
|
|
|
1219
1327
|
effort: chosen.effort,
|
|
1220
1328
|
rule,
|
|
1221
1329
|
reason,
|
|
1222
|
-
state: withWindow
|
|
1330
|
+
state: withWindow,
|
|
1331
|
+
cache
|
|
1223
1332
|
};
|
|
1224
1333
|
}
|
|
1225
1334
|
|
|
1226
1335
|
// packages/core/src/prompt.ts
|
|
1227
1336
|
import * as readline from "node:readline/promises";
|
|
1228
1337
|
|
|
1338
|
+
// packages/core/src/signals.ts
|
|
1339
|
+
var KNOWN_SIGNAL_KINDS = [
|
|
1340
|
+
"failure.real",
|
|
1341
|
+
"failure.transport",
|
|
1342
|
+
"progress.stalled",
|
|
1343
|
+
"verification.complete",
|
|
1344
|
+
"coverage",
|
|
1345
|
+
"context.pressure",
|
|
1346
|
+
"context.staleness",
|
|
1347
|
+
"task.ambiguity",
|
|
1348
|
+
"mutation.risk",
|
|
1349
|
+
"retry.value",
|
|
1350
|
+
"evidence.nextValue",
|
|
1351
|
+
"model.requiredStrength"
|
|
1352
|
+
];
|
|
1353
|
+
var KNOWN_KINDS = new Set(KNOWN_SIGNAL_KINDS);
|
|
1354
|
+
|
|
1229
1355
|
// packages/adapters/command-code/mod/sabi.ts
|
|
1230
1356
|
import path3 from "node:path";
|
|
1231
1357
|
var MOD_ID = "sabi";
|
|
@@ -1243,6 +1369,9 @@ function readLedger(state) {
|
|
|
1243
1369
|
hasTools: raw.hasTools === true,
|
|
1244
1370
|
lastModel: raw.lastModel,
|
|
1245
1371
|
lastUsage: raw.lastUsage,
|
|
1372
|
+
lastTier: raw.lastTier,
|
|
1373
|
+
lastLastRole: raw.lastLastRole,
|
|
1374
|
+
lastCache: raw.lastCache,
|
|
1246
1375
|
sessionId: typeof raw.sessionId === "string" ? raw.sessionId : void 0
|
|
1247
1376
|
};
|
|
1248
1377
|
}
|
|
@@ -1311,12 +1440,12 @@ function sabi(cmd) {
|
|
|
1311
1440
|
return writeLedger(state, { ...ledger, rounds: turnNumber });
|
|
1312
1441
|
},
|
|
1313
1442
|
// Sabi observes tool outcomes and never rewrites what the model sees.
|
|
1314
|
-
afterToolCall: ({ toolName, input, isError, result }) => {
|
|
1443
|
+
afterToolCall: ({ toolName, input, isError, result: result2 }) => {
|
|
1315
1444
|
calls.push({
|
|
1316
1445
|
name: toolName,
|
|
1317
1446
|
args: JSON.stringify(input ?? {}),
|
|
1318
1447
|
failed: isError === true,
|
|
1319
|
-
output: typeof
|
|
1448
|
+
output: typeof result2 === "string" ? result2 : void 0
|
|
1320
1449
|
});
|
|
1321
1450
|
return void 0;
|
|
1322
1451
|
},
|
|
@@ -1327,6 +1456,9 @@ function sabi(cmd) {
|
|
|
1327
1456
|
previousFailure = void 0;
|
|
1328
1457
|
ledger.generation = (ledger.generation ?? 0) + 1;
|
|
1329
1458
|
ledger.contextTokens = void 0;
|
|
1459
|
+
ledger.lastTier = void 0;
|
|
1460
|
+
ledger.lastLastRole = void 0;
|
|
1461
|
+
ledger.lastCache = { status: "unknown" };
|
|
1330
1462
|
}
|
|
1331
1463
|
const round = {
|
|
1332
1464
|
messageCount: stats.messageCount,
|
|
@@ -1341,7 +1473,15 @@ function sabi(cmd) {
|
|
|
1341
1473
|
...Object.keys(stats.media.counts).length ? { inputModalities: modalitiesOf(stats.media.counts), mediaCounts: stats.media.counts } : {}
|
|
1342
1474
|
};
|
|
1343
1475
|
const trajectory = trajectoryFromRound(round, previousFailure);
|
|
1344
|
-
const plan = planRound(trajectory, policy, tiers, {
|
|
1476
|
+
const plan = planRound(trajectory, policy, tiers, {
|
|
1477
|
+
contextWindow: config.harness?.contextWindow,
|
|
1478
|
+
previous: {
|
|
1479
|
+
tier: ledger.lastTier,
|
|
1480
|
+
lastRole: ledger.lastLastRole,
|
|
1481
|
+
generation: ledger.generation,
|
|
1482
|
+
cache: ledger.lastCache
|
|
1483
|
+
}
|
|
1484
|
+
});
|
|
1345
1485
|
if (!plan) return void 0;
|
|
1346
1486
|
nextPlan = plan;
|
|
1347
1487
|
return plan.effort ? { model: plan.model, effort: plan.effort } : { model: plan.model };
|
|
@@ -1367,7 +1507,10 @@ function sabi(cmd) {
|
|
|
1367
1507
|
// Only advance attribution when a fresh value actually arrived this turn. A missing
|
|
1368
1508
|
// usage or model event stays unknown rather than re-serializing an old round's value.
|
|
1369
1509
|
lastModel: servedBy,
|
|
1370
|
-
lastUsage: usedThisTurn ? usage : void 0
|
|
1510
|
+
lastUsage: usedThisTurn ? usage : void 0,
|
|
1511
|
+
lastTier: adopted?.tier ?? (compacted ? void 0 : ledger.lastTier),
|
|
1512
|
+
lastLastRole: adopted?.state.lastRole ?? (compacted ? void 0 : ledger.lastLastRole),
|
|
1513
|
+
lastCache: usedThisTurn ? cacheObservationFromUsage(toUsageTotals(usage)) : { status: "unknown" }
|
|
1371
1514
|
};
|
|
1372
1515
|
previousFailure = adopted ? { failure: adopted.state.failure, failureEvidence: adopted.state.failureEvidence } : void 0;
|
|
1373
1516
|
recordCustomEntry(ctx, {
|
|
@@ -1410,6 +1553,7 @@ function sabi(cmd) {
|
|
|
1410
1553
|
// This is the host adapter, not a provider entitlement claim.
|
|
1411
1554
|
upstream: CLIENT_ID,
|
|
1412
1555
|
upstreamModel: servingPlan.model,
|
|
1556
|
+
cache: servingPlan.cache,
|
|
1413
1557
|
stream: false,
|
|
1414
1558
|
state: {
|
|
1415
1559
|
...servingPlan.state,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizuh/sabi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Adaptive inference scheduling for Command Code: one bundled mod that routes each continuing round by model, effort and trajectory state.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
"command-code",
|
|
16
16
|
"mod",
|
|
17
17
|
"llm",
|
|
18
|
-
"routing"
|
|
18
|
+
"routing",
|
|
19
|
+
"ai-agents",
|
|
20
|
+
"inference-scheduling"
|
|
19
21
|
],
|
|
20
22
|
"publishConfig": {
|
|
21
23
|
"access": "public"
|
package/sabi.config.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"provenance": "
|
|
2
|
+
"provenance": "Operator rule (2026-09-22): OpenRouter may serve FREE models only. The openrouter upstream declares paidModelsAllowed:false, so any model whose price is unknown or non-zero is refused at dispatch (packages/core/src/compatibility.ts) — a config mistake cannot spend money. Every openrouter model id below carries the :free variant and cost 0. Ids, context windows, output ceilings, modalities and zero pricing verified live from https://openrouter.ai/api/v1/models and a real completion per id on 2026-09-22. Jev (TypeSafe judge) is a separate upstream and unaffected by this rule.",
|
|
3
3
|
"server": { "host": "127.0.0.1", "port": 8787 },
|
|
4
4
|
"upstreams": {
|
|
5
5
|
"openrouter": {
|
|
6
6
|
"baseURL": "https://openrouter.ai/api/v1",
|
|
7
7
|
"apiKey": "$OPENROUTER_API_KEY",
|
|
8
8
|
"streamUsage": true,
|
|
9
|
+
"paidModelsAllowed": false,
|
|
9
10
|
"headers": {
|
|
10
11
|
"HTTP-Referer": "https://github.com/vizuh/sabi",
|
|
11
12
|
"X-Title": "Sabi"
|
|
@@ -20,27 +21,27 @@
|
|
|
20
21
|
"models": {
|
|
21
22
|
"cheap": {
|
|
22
23
|
"upstream": "openrouter",
|
|
23
|
-
"model": "
|
|
24
|
-
"contextWindow":
|
|
25
|
-
"maxOutputTokens":
|
|
24
|
+
"model": "poolside/laguna-s-2.1:free",
|
|
25
|
+
"contextWindow": 262144,
|
|
26
|
+
"maxOutputTokens": 32768,
|
|
26
27
|
"capabilities": { "inputModalities": ["text"] },
|
|
27
|
-
"cost": { "input": 0
|
|
28
|
+
"cost": { "input": 0, "output": 0 }
|
|
28
29
|
},
|
|
29
30
|
"mid": {
|
|
30
31
|
"upstream": "openrouter",
|
|
31
|
-
"model": "
|
|
32
|
-
"contextWindow":
|
|
33
|
-
"maxOutputTokens":
|
|
34
|
-
"capabilities": { "inputModalities": ["text", "image"
|
|
35
|
-
"cost": { "input": 0
|
|
32
|
+
"model": "dots-studio/dots-3-note-preview:free",
|
|
33
|
+
"contextWindow": 512000,
|
|
34
|
+
"maxOutputTokens": 460800,
|
|
35
|
+
"capabilities": { "inputModalities": ["text", "image"] },
|
|
36
|
+
"cost": { "input": 0, "output": 0 }
|
|
36
37
|
},
|
|
37
38
|
"strong": {
|
|
38
39
|
"upstream": "openrouter",
|
|
39
|
-
"model": "
|
|
40
|
+
"model": "nvidia/nemotron-3-ultra-550b-a55b:free",
|
|
40
41
|
"contextWindow": 1000000,
|
|
41
|
-
"maxOutputTokens":
|
|
42
|
-
"capabilities": { "inputModalities": ["text"
|
|
43
|
-
"cost": { "input":
|
|
42
|
+
"maxOutputTokens": 65536,
|
|
43
|
+
"capabilities": { "inputModalities": ["text"] },
|
|
44
|
+
"cost": { "input": 0, "output": 0 }
|
|
44
45
|
},
|
|
45
46
|
"local": {
|
|
46
47
|
"upstream": "ollama",
|
|
@@ -96,7 +97,7 @@
|
|
|
96
97
|
"costPerMTokInput": 0.042
|
|
97
98
|
},
|
|
98
99
|
"harness": {
|
|
99
|
-
"provenance": "Command Code catalog ids, efforts and min plans verified 2026-09-18 against `cmd --list-models` and the bundled reference models.md. Used by the in-process mod adapter (harness keeps its own loop, no proxy, no key).
|
|
100
|
+
"provenance": "Command Code catalog ids, efforts and min plans verified 2026-09-18 against `cmd --list-models` and the bundled reference models.md. Used by the in-process mod adapter (harness keeps its own loop, no proxy, no key). This is the Command Code subscription catalog, not OpenRouter — the free-models-only rule above does not apply to it.",
|
|
100
101
|
"tiers": {
|
|
101
102
|
"cheap": {
|
|
102
103
|
"model": "deepseek/deepseek-v4-flash",
|