llm-cli-gateway 2.15.0 → 2.17.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/.agents/skills/least-cost-routing/SKILL.md +123 -0
- package/CHANGELOG.md +78 -1
- package/dist/acp/client.js +5 -0
- package/dist/acp/flight-redaction.d.ts +2 -0
- package/dist/acp/flight-redaction.js +2 -0
- package/dist/acp/process-manager.js +2 -1
- package/dist/acp/provider-registry.js +8 -8
- package/dist/acp/runtime.d.ts +1 -0
- package/dist/acp/runtime.js +20 -0
- package/dist/acp/types.d.ts +52 -0
- package/dist/acp/types.js +8 -0
- package/dist/api-provider.d.ts +1 -0
- package/dist/api-provider.js +1 -0
- package/dist/async-job-manager.d.ts +20 -1
- package/dist/async-job-manager.js +85 -28
- package/dist/claude-mcp-config.js +1 -1
- package/dist/compressor/estimate.d.ts +5 -0
- package/dist/compressor/estimate.js +21 -0
- package/dist/compressor/index.d.ts +23 -0
- package/dist/compressor/index.js +77 -0
- package/dist/compressor/router.d.ts +2 -0
- package/dist/compressor/router.js +57 -0
- package/dist/compressor/transforms/ansi.d.ts +3 -0
- package/dist/compressor/transforms/ansi.js +99 -0
- package/dist/compressor/transforms/json.d.ts +1 -0
- package/dist/compressor/transforms/json.js +156 -0
- package/dist/compressor/transforms/log.d.ts +12 -0
- package/dist/compressor/transforms/log.js +55 -0
- package/dist/compressor/transforms/whitespace.d.ts +8 -0
- package/dist/compressor/transforms/whitespace.js +79 -0
- package/dist/config.d.ts +39 -0
- package/dist/config.js +166 -6
- package/dist/db.js +4 -4
- package/dist/doctor.d.ts +34 -1
- package/dist/doctor.js +85 -3
- package/dist/executor.d.ts +6 -0
- package/dist/executor.js +16 -3
- package/dist/flight-recorder.d.ts +19 -0
- package/dist/flight-recorder.js +110 -2
- package/dist/http-transport.js +19 -21
- package/dist/index.d.ts +58 -2
- package/dist/index.js +929 -94
- package/dist/job-store.d.ts +14 -2
- package/dist/job-store.js +170 -43
- package/dist/lcr-priors.d.ts +60 -0
- package/dist/lcr-priors.js +190 -0
- package/dist/lcr-router-env.d.ts +20 -0
- package/dist/lcr-router-env.js +133 -0
- package/dist/lcr-telemetry.d.ts +2 -0
- package/dist/lcr-telemetry.js +17 -0
- package/dist/least-cost-router.d.ts +86 -0
- package/dist/least-cost-router.js +296 -0
- package/dist/least-cost-types.d.ts +34 -0
- package/dist/least-cost-types.js +1 -0
- package/dist/migrate-sessions.js +1 -1
- package/dist/migrate.js +1 -1
- package/dist/model-registry.js +1 -1
- package/dist/postgres-job-store-worker.js +56 -13
- package/dist/pricing.d.ts +17 -0
- package/dist/pricing.js +167 -0
- package/dist/provider-definitions.d.ts +5 -0
- package/dist/provider-definitions.js +56 -10
- package/dist/provider-tool-capabilities.js +3 -3
- package/dist/request-helpers.d.ts +2 -2
- package/dist/request-helpers.js +1 -1
- package/dist/resources.d.ts +37 -2
- package/dist/resources.js +96 -1
- package/dist/retry.d.ts +1 -0
- package/dist/retry.js +1 -1
- package/dist/spawn-env-isolation.d.ts +10 -0
- package/dist/spawn-env-isolation.js +55 -0
- package/dist/token-estimator.d.ts +6 -0
- package/dist/token-estimator.js +59 -0
- package/dist/upstream-contracts.js +48 -28
- package/dist/validation-receipt.js +1 -1
- package/dist/validation-tools.d.ts +6 -0
- package/dist/validation-tools.js +174 -54
- package/npm-shrinkwrap.json +2 -2
- package/package.json +15 -6
- package/setup/status.schema.json +68 -0
|
@@ -1,7 +1,21 @@
|
|
|
1
|
-
import { writeFileSync } from "node:fs";
|
|
2
1
|
import { parentPort, workerData } from "node:worker_threads";
|
|
3
2
|
let pool = null;
|
|
4
3
|
const PG_NOW_MS = "(EXTRACT(EPOCH FROM now()) * 1000)::bigint";
|
|
4
|
+
const PG_BOOTSTRAP_LOCK_KEY = 13_920_260_713;
|
|
5
|
+
const PG_POOL_MAX = 1;
|
|
6
|
+
const PG_STATEMENT_TIMEOUT_MS = 25_000;
|
|
7
|
+
const PG_LOCK_TIMEOUT_MS = 5_000;
|
|
8
|
+
const PG_QUERY_TIMEOUT_MS = 27_000;
|
|
9
|
+
function reportDiagnostic(kind, error) {
|
|
10
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11
|
+
const stack = error instanceof Error ? error.stack : undefined;
|
|
12
|
+
parentPort?.postMessage({
|
|
13
|
+
type: "postgres-job-store-diagnostic",
|
|
14
|
+
kind,
|
|
15
|
+
message,
|
|
16
|
+
stack,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
5
19
|
function signal(shared, status) {
|
|
6
20
|
const view = new Int32Array(shared);
|
|
7
21
|
Atomics.store(view, 0, status);
|
|
@@ -48,9 +62,22 @@ async function init() {
|
|
|
48
62
|
pool = new pg.Pool({
|
|
49
63
|
connectionString: workerData.dsn,
|
|
50
64
|
connectionTimeoutMillis: workerData.connectionTimeoutMillis,
|
|
65
|
+
max: PG_POOL_MAX,
|
|
66
|
+
idleTimeoutMillis: 30_000,
|
|
67
|
+
statement_timeout: PG_STATEMENT_TIMEOUT_MS,
|
|
68
|
+
lock_timeout: PG_LOCK_TIMEOUT_MS,
|
|
69
|
+
query_timeout: PG_QUERY_TIMEOUT_MS,
|
|
70
|
+
application_name: "llm-cli-gateway-job-store",
|
|
51
71
|
});
|
|
72
|
+
getPool().on("error", error => reportDiagnostic("pool_error", error));
|
|
52
73
|
await getPool().query("SELECT 1");
|
|
53
|
-
await
|
|
74
|
+
await withClient(async (client) => {
|
|
75
|
+
await client.query("BEGIN");
|
|
76
|
+
try {
|
|
77
|
+
await client.query("SET LOCAL lock_timeout = 0");
|
|
78
|
+
await client.query("SELECT pg_advisory_xact_lock($1::bigint)", [PG_BOOTSTRAP_LOCK_KEY]);
|
|
79
|
+
await client.query(`SET LOCAL lock_timeout = '${PG_LOCK_TIMEOUT_MS}ms'`);
|
|
80
|
+
await client.query(`
|
|
54
81
|
CREATE TABLE IF NOT EXISTS jobs (
|
|
55
82
|
id TEXT PRIMARY KEY,
|
|
56
83
|
correlation_id TEXT NOT NULL,
|
|
@@ -125,14 +152,26 @@ async function init() {
|
|
|
125
152
|
confidence TEXT NOT NULL
|
|
126
153
|
);
|
|
127
154
|
CREATE INDEX IF NOT EXISTS idx_validation_receipts_owner ON validation_receipts(owner_principal);
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
155
|
+
`);
|
|
156
|
+
await client.query("ALTER TABLE jobs ADD COLUMN IF NOT EXISTS owner_principal TEXT");
|
|
157
|
+
await client.query("ALTER TABLE jobs ADD COLUMN IF NOT EXISTS transport TEXT NOT NULL DEFAULT 'process'");
|
|
158
|
+
await client.query("ALTER TABLE jobs ADD COLUMN IF NOT EXISTS http_status INTEGER");
|
|
159
|
+
await client.query("ALTER TABLE jobs ADD COLUMN IF NOT EXISTS payload_json TEXT");
|
|
160
|
+
await client.query("ALTER TABLE jobs ADD COLUMN IF NOT EXISTS owner_instance TEXT");
|
|
161
|
+
await client.query("ALTER TABLE jobs ADD COLUMN IF NOT EXISTS lease_deadline BIGINT");
|
|
162
|
+
await client.query("CREATE INDEX IF NOT EXISTS idx_jobs_owner_status ON jobs(owner_instance, status)");
|
|
163
|
+
await client.query("COMMIT");
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
try {
|
|
167
|
+
await client.query("ROLLBACK");
|
|
168
|
+
}
|
|
169
|
+
catch (rollbackError) {
|
|
170
|
+
reportDiagnostic("bootstrap_rollback_error", rollbackError);
|
|
171
|
+
}
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
});
|
|
136
175
|
}
|
|
137
176
|
async function op(method, args) {
|
|
138
177
|
switch (method) {
|
|
@@ -426,7 +465,7 @@ async function op(method, args) {
|
|
|
426
465
|
}
|
|
427
466
|
}
|
|
428
467
|
parentPort?.on("message", async (message) => {
|
|
429
|
-
const { method, args,
|
|
468
|
+
const { method, args, shared, responsePort } = message;
|
|
430
469
|
let payload;
|
|
431
470
|
try {
|
|
432
471
|
payload = ok(await op(method, args));
|
|
@@ -435,10 +474,14 @@ parentPort?.on("message", async (message) => {
|
|
|
435
474
|
payload = fail(error);
|
|
436
475
|
}
|
|
437
476
|
try {
|
|
438
|
-
|
|
477
|
+
responsePort.postMessage(payload);
|
|
439
478
|
signal(shared, 1);
|
|
440
479
|
}
|
|
441
|
-
catch {
|
|
480
|
+
catch (error) {
|
|
481
|
+
reportDiagnostic("response_transport_error", error);
|
|
442
482
|
signal(shared, 2);
|
|
443
483
|
}
|
|
484
|
+
finally {
|
|
485
|
+
responsePort.close();
|
|
486
|
+
}
|
|
444
487
|
});
|
package/dist/pricing.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CliType } from "./provider-types.js";
|
|
2
|
+
import type { ModelCost, TokenCounts, TokenEstimate, CostResult, AccountingMode } from "./least-cost-types.js";
|
|
2
3
|
export interface PricePerMillion {
|
|
3
4
|
inputUsd: number;
|
|
4
5
|
outputUsd: number;
|
|
@@ -7,3 +8,19 @@ export interface PricePerMillion {
|
|
|
7
8
|
export declare const PRICING_AS_OF = "2026-06-13";
|
|
8
9
|
export declare function getPricing(cli: CliType, model: string): PricePerMillion;
|
|
9
10
|
export declare function estimateCacheSavingsUsd(cli: CliType, model: string, cacheReadTokens: number): number;
|
|
11
|
+
export declare function modelIdToFamily(model: string): string;
|
|
12
|
+
export declare const API_CATALOG_AS_OF = "2026-07-11";
|
|
13
|
+
export interface ApiCatalogEntry {
|
|
14
|
+
inputUsdPerMTok: number;
|
|
15
|
+
outputUsdPerMTok: number;
|
|
16
|
+
cacheReadMultiplier: number;
|
|
17
|
+
accountingMode?: AccountingMode;
|
|
18
|
+
family?: string;
|
|
19
|
+
}
|
|
20
|
+
export type ApiCatalog = ReadonlyMap<string, ApiCatalogEntry>;
|
|
21
|
+
export declare const API_CATALOG: ApiCatalog;
|
|
22
|
+
export declare function getModelCost(provider: string, model: string, opts?: {
|
|
23
|
+
catalog?: ApiCatalog;
|
|
24
|
+
preferCatalog?: boolean;
|
|
25
|
+
}): ModelCost;
|
|
26
|
+
export declare function composeCost(counts: TokenCounts | null, estimate: TokenEstimate, modelCost: ModelCost): CostResult;
|
package/dist/pricing.js
CHANGED
|
@@ -116,3 +116,170 @@ export function estimateCacheSavingsUsd(cli, model, cacheReadTokens) {
|
|
|
116
116
|
const savedPerToken = (p.inputUsd * (1 - p.cacheReadMultiplier)) / 1_000_000;
|
|
117
117
|
return cacheReadTokens * savedPerToken;
|
|
118
118
|
}
|
|
119
|
+
export function modelIdToFamily(model) {
|
|
120
|
+
const lower = model.toLowerCase();
|
|
121
|
+
if (lower.includes("sonnet"))
|
|
122
|
+
return "claude-sonnet";
|
|
123
|
+
if (lower.includes("opus"))
|
|
124
|
+
return "claude-opus";
|
|
125
|
+
if (lower.includes("haiku"))
|
|
126
|
+
return "claude-haiku";
|
|
127
|
+
if (lower.includes("gpt-5") || lower.includes("o3"))
|
|
128
|
+
return "openai-gpt5";
|
|
129
|
+
const geminiSpecialty = lower.includes("lite") ||
|
|
130
|
+
lower.includes("image") ||
|
|
131
|
+
lower.includes("audio") ||
|
|
132
|
+
lower.includes("tts");
|
|
133
|
+
if (!geminiSpecialty) {
|
|
134
|
+
if (lower.includes("2.5-flash"))
|
|
135
|
+
return "gemini-2.5-flash";
|
|
136
|
+
if (lower.includes("2.5-pro"))
|
|
137
|
+
return "gemini-2.5-pro";
|
|
138
|
+
if (lower.includes("gemini-3") && lower.includes("pro"))
|
|
139
|
+
return "gemini-3-pro";
|
|
140
|
+
}
|
|
141
|
+
if (lower.includes("grok-build") || lower.includes("grok-code"))
|
|
142
|
+
return "grok-build";
|
|
143
|
+
if (lower.includes("grok-4") || lower.includes("grok-3") || lower.includes("grok-latest")) {
|
|
144
|
+
return "grok-4";
|
|
145
|
+
}
|
|
146
|
+
if (lower.includes("devstral-small"))
|
|
147
|
+
return "mistral-devstral";
|
|
148
|
+
if (lower.includes("mistral-medium-3.5"))
|
|
149
|
+
return "mistral-medium";
|
|
150
|
+
return "unknown";
|
|
151
|
+
}
|
|
152
|
+
const FAMILY_PRICING = new Map([
|
|
153
|
+
["claude-sonnet", ANTHROPIC_SONNET],
|
|
154
|
+
["claude-opus", ANTHROPIC_OPUS],
|
|
155
|
+
["claude-haiku", ANTHROPIC_HAIKU],
|
|
156
|
+
["openai-gpt5", OPENAI_GPT5],
|
|
157
|
+
["gemini-2.5-pro", GEMINI_25_PRO],
|
|
158
|
+
["gemini-2.5-flash", GEMINI_FLASH],
|
|
159
|
+
["gemini-3-pro", GEMINI_3_PRO],
|
|
160
|
+
["grok-4", GROK_4],
|
|
161
|
+
["grok-build", GROK_BUILD],
|
|
162
|
+
["mistral-medium", MISTRAL_MEDIUM],
|
|
163
|
+
["mistral-devstral", MISTRAL_DEVSTRAL],
|
|
164
|
+
]);
|
|
165
|
+
export const API_CATALOG_AS_OF = "2026-07-11";
|
|
166
|
+
export const API_CATALOG = new Map([
|
|
167
|
+
[
|
|
168
|
+
"openai/gpt-5.5",
|
|
169
|
+
{
|
|
170
|
+
inputUsdPerMTok: 1.25,
|
|
171
|
+
outputUsdPerMTok: 10,
|
|
172
|
+
cacheReadMultiplier: 0.5,
|
|
173
|
+
family: "openai-gpt5",
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
[
|
|
177
|
+
"anthropic/claude-sonnet-4.5",
|
|
178
|
+
{
|
|
179
|
+
inputUsdPerMTok: 3,
|
|
180
|
+
outputUsdPerMTok: 15,
|
|
181
|
+
cacheReadMultiplier: 0.1,
|
|
182
|
+
accountingMode: "disjoint",
|
|
183
|
+
family: "claude-sonnet",
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
[
|
|
187
|
+
"google/gemini-2.5-flash",
|
|
188
|
+
{
|
|
189
|
+
inputUsdPerMTok: 0.3,
|
|
190
|
+
outputUsdPerMTok: 2.5,
|
|
191
|
+
cacheReadMultiplier: 0.1,
|
|
192
|
+
family: "gemini-2.5-flash",
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
[
|
|
196
|
+
"grok-build-0.1",
|
|
197
|
+
{ inputUsdPerMTok: 1, outputUsdPerMTok: 2, cacheReadMultiplier: 0.2, family: "grok-build" },
|
|
198
|
+
],
|
|
199
|
+
[
|
|
200
|
+
"grok-4",
|
|
201
|
+
{ inputUsdPerMTok: 1.25, outputUsdPerMTok: 2.5, cacheReadMultiplier: 0.16, family: "grok-4" },
|
|
202
|
+
],
|
|
203
|
+
]);
|
|
204
|
+
function tableModelCost(family, rate) {
|
|
205
|
+
const accountingMode = family.startsWith("claude-") ? "disjoint" : "inclusive";
|
|
206
|
+
return {
|
|
207
|
+
inputUsdPerMTok: rate.inputUsd,
|
|
208
|
+
outputUsdPerMTok: rate.outputUsd,
|
|
209
|
+
cacheReadMultiplier: rate.cacheReadMultiplier,
|
|
210
|
+
cacheWriteUsdPerMTok: rate.inputUsd,
|
|
211
|
+
accountingMode,
|
|
212
|
+
family,
|
|
213
|
+
source: "table",
|
|
214
|
+
asOf: PRICING_AS_OF,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function catalogModelCost(model, entry) {
|
|
218
|
+
const family = entry.family ?? modelIdToFamily(model);
|
|
219
|
+
return {
|
|
220
|
+
inputUsdPerMTok: entry.inputUsdPerMTok,
|
|
221
|
+
outputUsdPerMTok: entry.outputUsdPerMTok,
|
|
222
|
+
cacheReadMultiplier: entry.cacheReadMultiplier,
|
|
223
|
+
cacheWriteUsdPerMTok: entry.inputUsdPerMTok,
|
|
224
|
+
accountingMode: entry.accountingMode ?? "inclusive",
|
|
225
|
+
family: family === "unknown" ? model.toLowerCase() : family,
|
|
226
|
+
source: "api-catalog",
|
|
227
|
+
asOf: API_CATALOG_AS_OF,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
const UNKNOWN_MODEL_COST = {
|
|
231
|
+
inputUsdPerMTok: 0,
|
|
232
|
+
outputUsdPerMTok: 0,
|
|
233
|
+
cacheReadMultiplier: 0,
|
|
234
|
+
cacheWriteUsdPerMTok: 0,
|
|
235
|
+
accountingMode: "inclusive",
|
|
236
|
+
family: "unknown",
|
|
237
|
+
source: "unknown",
|
|
238
|
+
asOf: PRICING_AS_OF,
|
|
239
|
+
};
|
|
240
|
+
export function getModelCost(provider, model, opts) {
|
|
241
|
+
const catalog = opts?.catalog ?? API_CATALOG;
|
|
242
|
+
const preferCatalog = opts?.preferCatalog ?? true;
|
|
243
|
+
const catalogEntry = catalog.get(model.toLowerCase());
|
|
244
|
+
const family = modelIdToFamily(model);
|
|
245
|
+
const familyRate = FAMILY_PRICING.get(family);
|
|
246
|
+
if (catalogEntry !== undefined && (preferCatalog || familyRate === undefined)) {
|
|
247
|
+
return catalogModelCost(model, catalogEntry);
|
|
248
|
+
}
|
|
249
|
+
if (familyRate !== undefined) {
|
|
250
|
+
return tableModelCost(family, familyRate);
|
|
251
|
+
}
|
|
252
|
+
return { ...UNKNOWN_MODEL_COST };
|
|
253
|
+
}
|
|
254
|
+
function composeTotalUsd(inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens, reasoningTokens, modelCost, inputIsWholePrompt) {
|
|
255
|
+
const M = 1_000_000;
|
|
256
|
+
const { inputUsdPerMTok, outputUsdPerMTok, cacheWriteUsdPerMTok, cacheReadMultiplier } = modelCost;
|
|
257
|
+
const outputCost = ((outputTokens + reasoningTokens) * outputUsdPerMTok) / M;
|
|
258
|
+
const cacheWriteCost = (cacheWriteTokens * cacheWriteUsdPerMTok) / M;
|
|
259
|
+
if (modelCost.accountingMode === "disjoint") {
|
|
260
|
+
const freshTokens = inputIsWholePrompt
|
|
261
|
+
? inputTokens - cacheReadTokens - cacheWriteTokens
|
|
262
|
+
: inputTokens;
|
|
263
|
+
const freshCost = (freshTokens * inputUsdPerMTok) / M;
|
|
264
|
+
const cacheReadCost = (cacheReadTokens * inputUsdPerMTok * cacheReadMultiplier) / M;
|
|
265
|
+
return freshCost + cacheWriteCost + cacheReadCost + outputCost;
|
|
266
|
+
}
|
|
267
|
+
const baseCost = (inputTokens * inputUsdPerMTok) / M;
|
|
268
|
+
const cacheReadDiscount = (cacheReadTokens * inputUsdPerMTok * (1 - cacheReadMultiplier)) / M;
|
|
269
|
+
return baseCost + cacheWriteCost + outputCost - cacheReadDiscount;
|
|
270
|
+
}
|
|
271
|
+
export function composeCost(counts, estimate, modelCost) {
|
|
272
|
+
if (counts?.reportedCostUsd != null) {
|
|
273
|
+
return {
|
|
274
|
+
costUsd: counts.reportedCostUsd,
|
|
275
|
+
cost_basis: "provider-reported",
|
|
276
|
+
confidence: "high",
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
if (counts != null && modelCost.source !== "unknown") {
|
|
280
|
+
const costUsd = composeTotalUsd(counts.inputTokens, counts.outputTokens, counts.cacheReadTokens ?? 0, counts.cacheCreationTokens ?? 0, counts.reasoningTokens ?? 0, modelCost, false);
|
|
281
|
+
return { costUsd, cost_basis: "derived-from-tokens", confidence: "high" };
|
|
282
|
+
}
|
|
283
|
+
const costUsd = composeTotalUsd(estimate.estInputTokens, estimate.estOutputTokens, estimate.estCacheReadTokens ?? 0, estimate.estCacheWriteTokens ?? 0, 0, modelCost, true);
|
|
284
|
+
return { costUsd, cost_basis: "pre-flight-estimate", confidence: "low" };
|
|
285
|
+
}
|
|
@@ -97,6 +97,10 @@ export interface ProviderRequestSurface {
|
|
|
97
97
|
readonly acpCapable: boolean;
|
|
98
98
|
readonly syncToolName: string;
|
|
99
99
|
readonly asyncToolName: string;
|
|
100
|
+
readonly acceptsImages: boolean;
|
|
101
|
+
readonly acceptsAttachments: boolean;
|
|
102
|
+
readonly toolCalling: boolean;
|
|
103
|
+
readonly jsonSchema: boolean;
|
|
100
104
|
}
|
|
101
105
|
export interface ProviderDefinition {
|
|
102
106
|
readonly id: ProviderId;
|
|
@@ -119,6 +123,7 @@ export interface ProviderDefinition {
|
|
|
119
123
|
readonly upstreamContract: ProviderUpstreamLinkage;
|
|
120
124
|
readonly capabilityScope: CapabilityScope;
|
|
121
125
|
}
|
|
126
|
+
export declare const PROVIDER_TARGET_VERSIONS: Record<CliType, string>;
|
|
122
127
|
export declare const PROVIDER_DEFINITIONS_BY_ID: Readonly<Record<CliType, ProviderDefinition>>;
|
|
123
128
|
export declare function getAllProviderDefinitions(): readonly ProviderDefinition[];
|
|
124
129
|
export declare function getProviderDefinition(id: CliType): ProviderDefinition;
|
|
@@ -4,6 +4,15 @@ export function adminSurfaceKind(family) {
|
|
|
4
4
|
return family.kind ?? "cli-subcommand";
|
|
5
5
|
}
|
|
6
6
|
export const DEVIN_ACP_AGENT_TYPES = ["summarizer", "review"];
|
|
7
|
+
export const PROVIDER_TARGET_VERSIONS = {
|
|
8
|
+
claude: "claude 2.1.206",
|
|
9
|
+
codex: "codex-cli 0.144.1",
|
|
10
|
+
gemini: "agy 1.1.0",
|
|
11
|
+
grok: "grok 0.2.93 (f00f96316d)",
|
|
12
|
+
mistral: "vibe 2.19.1",
|
|
13
|
+
devin: "devin 3000.1.27 (0d4bf12e)",
|
|
14
|
+
cursor: "cursor-agent 2026.07.09-c59fd9a",
|
|
15
|
+
};
|
|
7
16
|
const PROVIDER_DEFINITIONS = {
|
|
8
17
|
claude: {
|
|
9
18
|
id: "claude",
|
|
@@ -19,6 +28,10 @@ const PROVIDER_DEFINITIONS = {
|
|
|
19
28
|
acpCapable: false,
|
|
20
29
|
syncToolName: "claude_request",
|
|
21
30
|
asyncToolName: "claude_request_async",
|
|
31
|
+
acceptsImages: false,
|
|
32
|
+
acceptsAttachments: false,
|
|
33
|
+
toolCalling: true,
|
|
34
|
+
jsonSchema: true,
|
|
22
35
|
},
|
|
23
36
|
docs: { primary: ["https://code.claude.com/docs/en/cli-reference"] },
|
|
24
37
|
discovery: {
|
|
@@ -86,7 +99,7 @@ const PROVIDER_DEFINITIONS = {
|
|
|
86
99
|
nativeEntrypoint: null,
|
|
87
100
|
entrypoint: null,
|
|
88
101
|
probeArgv: [],
|
|
89
|
-
evidence:
|
|
102
|
+
evidence: `No native Claude Code ACP subcommand or flag in installed help (${PROVIDER_TARGET_VERSIONS.claude}) or the official CLI reference. Coverage is CLI-first; ACP reporting says no native entrypoint is advertised.`,
|
|
90
103
|
},
|
|
91
104
|
safetyModes: {
|
|
92
105
|
sandbox: false,
|
|
@@ -98,7 +111,10 @@ const PROVIDER_DEFINITIONS = {
|
|
|
98
111
|
outputFormats: ["text", "json", "stream-json"],
|
|
99
112
|
streamingFormats: ["stream-json"],
|
|
100
113
|
resourcePolicy: { exposesModelsResource: true, exposesSessionsResource: true },
|
|
101
|
-
upstreamContract: {
|
|
114
|
+
upstreamContract: {
|
|
115
|
+
targetVersion: PROVIDER_TARGET_VERSIONS.claude,
|
|
116
|
+
helpChecksumRef: "claude--help.txt",
|
|
117
|
+
},
|
|
102
118
|
capabilityScope: "full",
|
|
103
119
|
},
|
|
104
120
|
codex: {
|
|
@@ -115,6 +131,10 @@ const PROVIDER_DEFINITIONS = {
|
|
|
115
131
|
acpCapable: false,
|
|
116
132
|
syncToolName: "codex_request",
|
|
117
133
|
asyncToolName: "codex_request_async",
|
|
134
|
+
acceptsImages: true,
|
|
135
|
+
acceptsAttachments: true,
|
|
136
|
+
toolCalling: true,
|
|
137
|
+
jsonSchema: true,
|
|
118
138
|
},
|
|
119
139
|
docs: {
|
|
120
140
|
primary: [
|
|
@@ -215,7 +235,7 @@ const PROVIDER_DEFINITIONS = {
|
|
|
215
235
|
nativeEntrypoint: null,
|
|
216
236
|
entrypoint: null,
|
|
217
237
|
probeArgv: [],
|
|
218
|
-
evidence:
|
|
238
|
+
evidence: `${PROVIDER_TARGET_VERSIONS.codex} advertises mcp-server and app-server transports, not a native ACP agent entrypoint. Third-party adapters exist but are documentation only and are never treated as native gateway ACP.`,
|
|
219
239
|
},
|
|
220
240
|
safetyModes: {
|
|
221
241
|
sandbox: true,
|
|
@@ -233,7 +253,7 @@ const PROVIDER_DEFINITIONS = {
|
|
|
233
253
|
streamingFormats: ["jsonl"],
|
|
234
254
|
resourcePolicy: { exposesModelsResource: true, exposesSessionsResource: true },
|
|
235
255
|
upstreamContract: {
|
|
236
|
-
targetVersion:
|
|
256
|
+
targetVersion: PROVIDER_TARGET_VERSIONS.codex,
|
|
237
257
|
helpChecksumRef: "codex-exec--help.txt",
|
|
238
258
|
},
|
|
239
259
|
capabilityScope: "full",
|
|
@@ -252,6 +272,10 @@ const PROVIDER_DEFINITIONS = {
|
|
|
252
272
|
acpCapable: false,
|
|
253
273
|
syncToolName: "gemini_request",
|
|
254
274
|
asyncToolName: "gemini_request_async",
|
|
275
|
+
acceptsImages: false,
|
|
276
|
+
acceptsAttachments: false,
|
|
277
|
+
toolCalling: true,
|
|
278
|
+
jsonSchema: false,
|
|
255
279
|
},
|
|
256
280
|
docs: {
|
|
257
281
|
primary: [
|
|
@@ -319,7 +343,7 @@ const PROVIDER_DEFINITIONS = {
|
|
|
319
343
|
nativeEntrypoint: null,
|
|
320
344
|
entrypoint: null,
|
|
321
345
|
probeArgv: [],
|
|
322
|
-
evidence:
|
|
346
|
+
evidence: `${PROVIDER_TARGET_VERSIONS.gemini} has no ACP flag or subcommand in installed help or the Antigravity CLI docs. Legacy Gemini CLI ACP evidence does not transfer. No native entrypoint advertised.`,
|
|
323
347
|
},
|
|
324
348
|
safetyModes: {
|
|
325
349
|
sandbox: true,
|
|
@@ -331,7 +355,10 @@ const PROVIDER_DEFINITIONS = {
|
|
|
331
355
|
outputFormats: ["text"],
|
|
332
356
|
streamingFormats: [],
|
|
333
357
|
resourcePolicy: { exposesModelsResource: true, exposesSessionsResource: true },
|
|
334
|
-
upstreamContract: {
|
|
358
|
+
upstreamContract: {
|
|
359
|
+
targetVersion: PROVIDER_TARGET_VERSIONS.gemini,
|
|
360
|
+
helpChecksumRef: "agy--help.txt",
|
|
361
|
+
},
|
|
335
362
|
capabilityScope: "full",
|
|
336
363
|
},
|
|
337
364
|
grok: {
|
|
@@ -348,6 +375,10 @@ const PROVIDER_DEFINITIONS = {
|
|
|
348
375
|
acpCapable: true,
|
|
349
376
|
syncToolName: "grok_request",
|
|
350
377
|
asyncToolName: "grok_request_async",
|
|
378
|
+
acceptsImages: false,
|
|
379
|
+
acceptsAttachments: false,
|
|
380
|
+
toolCalling: true,
|
|
381
|
+
jsonSchema: true,
|
|
351
382
|
},
|
|
352
383
|
docs: {
|
|
353
384
|
primary: [
|
|
@@ -436,7 +467,7 @@ const PROVIDER_DEFINITIONS = {
|
|
|
436
467
|
streamingFormats: ["json"],
|
|
437
468
|
resourcePolicy: { exposesModelsResource: true, exposesSessionsResource: true },
|
|
438
469
|
upstreamContract: {
|
|
439
|
-
targetVersion:
|
|
470
|
+
targetVersion: PROVIDER_TARGET_VERSIONS.grok,
|
|
440
471
|
helpChecksumRef: "grok--help.txt",
|
|
441
472
|
},
|
|
442
473
|
capabilityScope: "full",
|
|
@@ -455,6 +486,10 @@ const PROVIDER_DEFINITIONS = {
|
|
|
455
486
|
acpCapable: true,
|
|
456
487
|
syncToolName: "mistral_request",
|
|
457
488
|
asyncToolName: "mistral_request_async",
|
|
489
|
+
acceptsImages: false,
|
|
490
|
+
acceptsAttachments: false,
|
|
491
|
+
toolCalling: true,
|
|
492
|
+
jsonSchema: false,
|
|
458
493
|
},
|
|
459
494
|
docs: { primary: ["https://github.com/mistralai/mistral-vibe"] },
|
|
460
495
|
discovery: {
|
|
@@ -551,7 +586,10 @@ const PROVIDER_DEFINITIONS = {
|
|
|
551
586
|
outputFormats: ["text", "json"],
|
|
552
587
|
streamingFormats: [],
|
|
553
588
|
resourcePolicy: { exposesModelsResource: true, exposesSessionsResource: true },
|
|
554
|
-
upstreamContract: {
|
|
589
|
+
upstreamContract: {
|
|
590
|
+
targetVersion: PROVIDER_TARGET_VERSIONS.mistral,
|
|
591
|
+
helpChecksumRef: "vibe--help.txt",
|
|
592
|
+
},
|
|
555
593
|
capabilityScope: "full",
|
|
556
594
|
},
|
|
557
595
|
devin: {
|
|
@@ -568,6 +606,10 @@ const PROVIDER_DEFINITIONS = {
|
|
|
568
606
|
acpCapable: true,
|
|
569
607
|
syncToolName: "devin_request",
|
|
570
608
|
asyncToolName: "devin_request_async",
|
|
609
|
+
acceptsImages: false,
|
|
610
|
+
acceptsAttachments: false,
|
|
611
|
+
toolCalling: true,
|
|
612
|
+
jsonSchema: false,
|
|
571
613
|
},
|
|
572
614
|
docs: { primary: ["https://docs.devin.ai/cli/reference/commands"] },
|
|
573
615
|
discovery: {
|
|
@@ -660,7 +702,7 @@ const PROVIDER_DEFINITIONS = {
|
|
|
660
702
|
streamingFormats: [],
|
|
661
703
|
resourcePolicy: { exposesModelsResource: true, exposesSessionsResource: true },
|
|
662
704
|
upstreamContract: {
|
|
663
|
-
targetVersion:
|
|
705
|
+
targetVersion: PROVIDER_TARGET_VERSIONS.devin,
|
|
664
706
|
helpChecksumRef: "devin--help.txt",
|
|
665
707
|
},
|
|
666
708
|
capabilityScope: "full",
|
|
@@ -679,6 +721,10 @@ const PROVIDER_DEFINITIONS = {
|
|
|
679
721
|
acpCapable: true,
|
|
680
722
|
syncToolName: "cursor_request",
|
|
681
723
|
asyncToolName: "cursor_request_async",
|
|
724
|
+
acceptsImages: false,
|
|
725
|
+
acceptsAttachments: false,
|
|
726
|
+
toolCalling: true,
|
|
727
|
+
jsonSchema: false,
|
|
682
728
|
},
|
|
683
729
|
docs: { primary: ["https://docs.cursor.com/en/cli/overview"] },
|
|
684
730
|
discovery: {
|
|
@@ -734,7 +780,7 @@ const PROVIDER_DEFINITIONS = {
|
|
|
734
780
|
streamingFormats: ["stream-json"],
|
|
735
781
|
resourcePolicy: { exposesModelsResource: true, exposesSessionsResource: true },
|
|
736
782
|
upstreamContract: {
|
|
737
|
-
targetVersion:
|
|
783
|
+
targetVersion: PROVIDER_TARGET_VERSIONS.cursor,
|
|
738
784
|
helpChecksumRef: "cursor-agent--help.txt",
|
|
739
785
|
},
|
|
740
786
|
capabilityScope: "maintain-only",
|
|
@@ -4,7 +4,7 @@ import path from "path";
|
|
|
4
4
|
import { parse as parseToml } from "smol-toml";
|
|
5
5
|
import { CLAUDE_MCP_SERVER_NAMES } from "./claude-mcp-config.js";
|
|
6
6
|
import { getAvailableCliInfo } from "./model-registry.js";
|
|
7
|
-
import { CLI_TYPES, getProviderDefinition } from "./provider-definitions.js";
|
|
7
|
+
import { CLI_TYPES, getProviderDefinition, PROVIDER_TARGET_VERSIONS, } from "./provider-definitions.js";
|
|
8
8
|
import { enabledApiProviders, isXaiProviderEnabled, loadProvidersConfig, } from "./config.js";
|
|
9
9
|
import { apiContinuityForKind } from "./api-provider.js";
|
|
10
10
|
const MAX_SKILLS_PER_DIR = 100;
|
|
@@ -50,7 +50,7 @@ export const ACP_CONTRACT = {
|
|
|
50
50
|
},
|
|
51
51
|
gemini: {
|
|
52
52
|
classification: "absent_watchlist",
|
|
53
|
-
summary:
|
|
53
|
+
summary: `Google Antigravity ${PROVIDER_TARGET_VERSIONS.gemini} has no ACP surface; watchlist item only.`,
|
|
54
54
|
},
|
|
55
55
|
grok_api: {
|
|
56
56
|
classification: "absent_watchlist",
|
|
@@ -110,7 +110,7 @@ const ACP_RESIDUAL = {
|
|
|
110
110
|
smokeSupported: false,
|
|
111
111
|
smokeStatus: "unsupported",
|
|
112
112
|
caveats: [
|
|
113
|
-
|
|
113
|
+
`Antigravity ${PROVIDER_TARGET_VERSIONS.gemini} has no ACP flag or subcommand.`,
|
|
114
114
|
"Legacy Gemini CLI ACP evidence does not transfer to agy; kept on the upstream drift watchlist.",
|
|
115
115
|
],
|
|
116
116
|
},
|
|
@@ -229,8 +229,8 @@ export declare const CODEX_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodObject<{
|
|
|
229
229
|
disable: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
230
230
|
}, "strip", z.ZodTypeAny, {
|
|
231
231
|
search?: boolean | undefined;
|
|
232
|
-
outputSchema?: string | Record<string, unknown> | undefined;
|
|
233
232
|
profile?: string | undefined;
|
|
233
|
+
outputSchema?: string | Record<string, unknown> | undefined;
|
|
234
234
|
configOverrides?: Record<string, string> | undefined;
|
|
235
235
|
ephemeral?: boolean | undefined;
|
|
236
236
|
images?: string[] | undefined;
|
|
@@ -240,8 +240,8 @@ export declare const CODEX_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodObject<{
|
|
|
240
240
|
disable?: string[] | undefined;
|
|
241
241
|
}, {
|
|
242
242
|
search?: boolean | undefined;
|
|
243
|
-
outputSchema?: string | Record<string, unknown> | undefined;
|
|
244
243
|
profile?: string | undefined;
|
|
244
|
+
outputSchema?: string | Record<string, unknown> | undefined;
|
|
245
245
|
configOverrides?: Record<string, string> | undefined;
|
|
246
246
|
ephemeral?: boolean | undefined;
|
|
247
247
|
images?: string[] | undefined;
|
package/dist/request-helpers.js
CHANGED
|
@@ -99,7 +99,7 @@ export const MISTRAL_BUILTIN_AGENT_MODES = [
|
|
|
99
99
|
"accept-edits",
|
|
100
100
|
"auto-approve",
|
|
101
101
|
];
|
|
102
|
-
export const MISTRAL_DEFAULT_AGENT_MODE = "
|
|
102
|
+
export const MISTRAL_DEFAULT_AGENT_MODE = "accept-edits";
|
|
103
103
|
export function prepareMistralRequest(input) {
|
|
104
104
|
const args = ["-p", input.prompt];
|
|
105
105
|
const env = {};
|
package/dist/resources.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type CliType } from "./session-manager.js";
|
|
|
3
3
|
import { PerformanceMetrics } from "./metrics.js";
|
|
4
4
|
import { FlightRecorderQuery } from "./flight-recorder.js";
|
|
5
5
|
import { type GlobalCacheStats, type PrefixCacheStats, type SessionCacheStats } from "./cache-stats.js";
|
|
6
|
-
import { type CacheAwarenessConfig, type ProvidersConfig } from "./config.js";
|
|
6
|
+
import { type CacheAwarenessConfig, type LeastCostConfig, type ProvidersConfig } from "./config.js";
|
|
7
7
|
import type { AcpConfig } from "./config.js";
|
|
8
8
|
import { type ResolvedProviderCapability } from "./provider-capability-resolver.js";
|
|
9
9
|
export interface ResourceDefinition {
|
|
@@ -31,7 +31,9 @@ export declare class ResourceProvider {
|
|
|
31
31
|
private providers;
|
|
32
32
|
private capabilityPeek;
|
|
33
33
|
private acpConfig;
|
|
34
|
-
|
|
34
|
+
private leastCost;
|
|
35
|
+
constructor(sessionManager: ISessionManager, performanceMetrics: PerformanceMetrics, flightRecorder?: FlightRecorderQuery, cacheAwareness?: CacheAwarenessConfig | null, providers?: ProvidersConfig | null, capabilityPeek?: (id: CliType) => ResolvedProviderCapability | null, acpConfig?: AcpConfig | null, leastCost?: LeastCostConfig | undefined);
|
|
36
|
+
private routingResourcesEnabled;
|
|
35
37
|
getFlightRecorderQuery(): FlightRecorderQuery;
|
|
36
38
|
private apiRuntimes;
|
|
37
39
|
private continuityTrackedApiRuntimes;
|
|
@@ -42,7 +44,40 @@ export declare class ResourceProvider {
|
|
|
42
44
|
readCacheStateSession(sessionId: string): SessionCacheStats;
|
|
43
45
|
readCacheStateForPrefix(stablePrefixHash: string): PrefixCacheStats;
|
|
44
46
|
listResources(): ResourceDefinition[];
|
|
47
|
+
private readRoutingDecisions;
|
|
48
|
+
private readRoutingPriors;
|
|
45
49
|
private ownedSessions;
|
|
46
50
|
private ownedActiveId;
|
|
47
51
|
readResource(uri: string): Promise<ResourceContents | null>;
|
|
48
52
|
}
|
|
53
|
+
export interface RoutingDecision {
|
|
54
|
+
provider: string;
|
|
55
|
+
model: string;
|
|
56
|
+
tier: string;
|
|
57
|
+
estCostUsd: number | null;
|
|
58
|
+
costBasis: string | null;
|
|
59
|
+
confidence: string | null;
|
|
60
|
+
reason: string | null;
|
|
61
|
+
considered: number | null;
|
|
62
|
+
reroutes: number | null;
|
|
63
|
+
at: string;
|
|
64
|
+
}
|
|
65
|
+
export interface RoutingPriorsPayload {
|
|
66
|
+
priorsScope: string;
|
|
67
|
+
priceAsOf: {
|
|
68
|
+
table: string;
|
|
69
|
+
apiCatalog: string;
|
|
70
|
+
};
|
|
71
|
+
outputPriors: Array<{
|
|
72
|
+
candidate: string;
|
|
73
|
+
median: number;
|
|
74
|
+
p90: number;
|
|
75
|
+
samples: number;
|
|
76
|
+
}>;
|
|
77
|
+
calibration: Array<{
|
|
78
|
+
bucket: string;
|
|
79
|
+
k: number;
|
|
80
|
+
samples: number;
|
|
81
|
+
confidence: string;
|
|
82
|
+
}>;
|
|
83
|
+
}
|