@plune-ai/cli 0.32.2 → 0.33.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 +53 -1
- package/dist/cli.cjs +384 -100
- package/dist/index.cjs +34 -16
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +34 -16
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -457,24 +457,24 @@ function priceFrom(price, usage) {
|
|
|
457
457
|
var defaultWarn = (message) => {
|
|
458
458
|
process.stderr.write(message + "\n");
|
|
459
459
|
};
|
|
460
|
-
function
|
|
460
|
+
function resolveCostEntry(usage, model, reportedCostUsd, overrides, deps = {}) {
|
|
461
461
|
const table = deps.table ?? PRICE_TABLE;
|
|
462
462
|
const warn = deps.warn ?? defaultWarn;
|
|
463
463
|
const override = overrides?.[model];
|
|
464
464
|
if (override !== void 0) {
|
|
465
|
-
return priceFrom(override, usage);
|
|
465
|
+
return { cost_usd: priceFrom(override, usage), priced: true };
|
|
466
466
|
}
|
|
467
467
|
if (reportedCostUsd !== void 0) {
|
|
468
|
-
return reportedCostUsd;
|
|
468
|
+
return { cost_usd: reportedCostUsd, priced: true };
|
|
469
469
|
}
|
|
470
470
|
const tablePrice = table[model];
|
|
471
471
|
if (tablePrice !== void 0) {
|
|
472
|
-
return priceFrom(tablePrice, usage);
|
|
472
|
+
return { cost_usd: priceFrom(tablePrice, usage), priced: true };
|
|
473
473
|
}
|
|
474
474
|
warn(
|
|
475
475
|
`plune: no price for model "${model}" \u2014 reporting cost_usd=0. Set pricing["${model}"] in plune.yaml to track its cost.`
|
|
476
476
|
);
|
|
477
|
-
return 0;
|
|
477
|
+
return { cost_usd: 0, priced: false };
|
|
478
478
|
}
|
|
479
479
|
|
|
480
480
|
// src/providers/anthropic.ts
|
|
@@ -520,7 +520,7 @@ function makeAnthropicProvider(config, env, pricing) {
|
|
|
520
520
|
}
|
|
521
521
|
},
|
|
522
522
|
estimateCost(usage, reportedCostUsd) {
|
|
523
|
-
return
|
|
523
|
+
return resolveCostEntry(usage, config.model, reportedCostUsd, pricing);
|
|
524
524
|
}
|
|
525
525
|
};
|
|
526
526
|
}
|
|
@@ -576,7 +576,7 @@ function makeOpenAiCompatibleProvider(opts) {
|
|
|
576
576
|
}
|
|
577
577
|
},
|
|
578
578
|
estimateCost(usage, reportedCostUsd) {
|
|
579
|
-
return
|
|
579
|
+
return resolveCostEntry(usage, config.model, reportedCostUsd, pricing);
|
|
580
580
|
}
|
|
581
581
|
};
|
|
582
582
|
}
|
|
@@ -638,9 +638,7 @@ function makeEstimateProvider(config, pricing) {
|
|
|
638
638
|
complete: () => Promise.reject(
|
|
639
639
|
new Error("The --dry-run provider only estimates cost; it never calls a model.")
|
|
640
640
|
),
|
|
641
|
-
estimateCost: (usage, reportedCostUsd) => (
|
|
642
|
-
cost_usd: resolveCost(usage, config.model, reportedCostUsd, pricing)
|
|
643
|
-
})
|
|
641
|
+
estimateCost: (usage, reportedCostUsd) => resolveCostEntry(usage, config.model, reportedCostUsd, pricing)
|
|
644
642
|
};
|
|
645
643
|
}
|
|
646
644
|
|
|
@@ -1426,6 +1424,12 @@ function toRunError(err) {
|
|
|
1426
1424
|
function estimateUsage(prompt5, maxTokens) {
|
|
1427
1425
|
return { input_tokens: Math.ceil(prompt5.length / 4), output_tokens: maxTokens };
|
|
1428
1426
|
}
|
|
1427
|
+
function pricedField(priced) {
|
|
1428
|
+
return priced === void 0 ? {} : { priced };
|
|
1429
|
+
}
|
|
1430
|
+
function costFields(c) {
|
|
1431
|
+
return { cost_usd: c.cost_usd, ...pricedField(c.priced) };
|
|
1432
|
+
}
|
|
1429
1433
|
async function runRow(p) {
|
|
1430
1434
|
const t0 = p.now();
|
|
1431
1435
|
const prompt5 = resolvePrompt(p.template, p.row.vars);
|
|
@@ -1433,7 +1437,8 @@ async function runRow(p) {
|
|
|
1433
1437
|
const maxTokens = p.providerConfig.max_tokens ?? DEFAULT_MAX_TOKENS2;
|
|
1434
1438
|
if (p.dryRun) {
|
|
1435
1439
|
const est = estimateUsage(prompt5, maxTokens);
|
|
1436
|
-
const
|
|
1440
|
+
const cost = p.provider.estimateCost(est);
|
|
1441
|
+
const usage2 = { ...est, ...costFields(cost) };
|
|
1437
1442
|
return { vars: p.row.vars, output: null, cached: false, usage: usage2, assertions: [] };
|
|
1438
1443
|
}
|
|
1439
1444
|
const key = cacheKey(
|
|
@@ -1471,7 +1476,9 @@ async function runRow(p) {
|
|
|
1471
1476
|
usage = {
|
|
1472
1477
|
input_tokens: hit.usage.input_tokens,
|
|
1473
1478
|
output_tokens: hit.usage.output_tokens,
|
|
1474
|
-
cost_usd: 0
|
|
1479
|
+
cost_usd: 0,
|
|
1480
|
+
// A hit costs nothing, but whether that 0 is a known price depends on the model.
|
|
1481
|
+
...pricedField(p.provider.estimateCost(hit.usage).priced)
|
|
1475
1482
|
};
|
|
1476
1483
|
cacheSaved = {
|
|
1477
1484
|
input_tokens: hit.usage.input_tokens,
|
|
@@ -1488,12 +1495,13 @@ async function runRow(p) {
|
|
|
1488
1495
|
prompt_resolved: prompt5
|
|
1489
1496
|
});
|
|
1490
1497
|
output = res.output;
|
|
1498
|
+
const cost = p.provider.estimateCost(res.usage, res.cost_usd);
|
|
1491
1499
|
usage = {
|
|
1492
1500
|
input_tokens: res.usage.input_tokens,
|
|
1493
1501
|
output_tokens: res.usage.output_tokens,
|
|
1494
1502
|
// Prefer the provider-reported actual cost (res.cost_usd) when present; resolveCost still
|
|
1495
1503
|
// lets a config pricing override win, else falls back to the table estimate (ADR-PRC01).
|
|
1496
|
-
|
|
1504
|
+
...costFields(cost)
|
|
1497
1505
|
};
|
|
1498
1506
|
if (!p.noCache && isCacheable(res) && answerParses(res.output, p.assertions)) {
|
|
1499
1507
|
p.cache.set(key, res);
|
|
@@ -1510,8 +1518,11 @@ async function runRow(p) {
|
|
|
1510
1518
|
}
|
|
1511
1519
|
}
|
|
1512
1520
|
let judgeCost = 0;
|
|
1521
|
+
let judgeUnpriced = false;
|
|
1513
1522
|
const judge = buildJudge(p.provider, p.providerConfig, (u) => {
|
|
1514
|
-
|
|
1523
|
+
const c = p.provider.estimateCost(u);
|
|
1524
|
+
judgeCost += c.cost_usd;
|
|
1525
|
+
if (c.priced === false) judgeUnpriced = true;
|
|
1515
1526
|
});
|
|
1516
1527
|
const records = [];
|
|
1517
1528
|
let assertionError;
|
|
@@ -1536,7 +1547,12 @@ async function runRow(p) {
|
|
|
1536
1547
|
break;
|
|
1537
1548
|
}
|
|
1538
1549
|
}
|
|
1539
|
-
const finalUsage = {
|
|
1550
|
+
const finalUsage = {
|
|
1551
|
+
...usage,
|
|
1552
|
+
cost_usd: usage.cost_usd + judgeCost,
|
|
1553
|
+
// A row is priced only when every call in it was; the field stays absent if the provider never said.
|
|
1554
|
+
...judgeUnpriced ? { priced: false } : {}
|
|
1555
|
+
};
|
|
1540
1556
|
return {
|
|
1541
1557
|
vars: p.row.vars,
|
|
1542
1558
|
output,
|
|
@@ -1758,7 +1774,9 @@ var assertionResultRecordSchema2 = import_zod3.z.object({
|
|
|
1758
1774
|
var usageSchema = import_zod3.z.object({
|
|
1759
1775
|
input_tokens: import_zod3.z.number(),
|
|
1760
1776
|
output_tokens: import_zod3.z.number(),
|
|
1761
|
-
cost_usd: import_zod3.z.number()
|
|
1777
|
+
cost_usd: import_zod3.z.number(),
|
|
1778
|
+
/** cli#151. Optional and additive — a RunResult written before it validates unchanged. */
|
|
1779
|
+
priced: import_zod3.z.boolean().optional()
|
|
1762
1780
|
});
|
|
1763
1781
|
var runErrorSchema = import_zod3.z.object({
|
|
1764
1782
|
code: import_zod3.z.string(),
|
package/dist/index.d.cts
CHANGED
|
@@ -44,6 +44,12 @@ interface Usage {
|
|
|
44
44
|
input_tokens: number;
|
|
45
45
|
output_tokens: number;
|
|
46
46
|
cost_usd: number;
|
|
47
|
+
/**
|
|
48
|
+
* plune-ai/cli#151. `true` when the price of the model is known, a zero price included (a `:free`
|
|
49
|
+
* model, `pricing: 0`); `false` when nobody has a price and `cost_usd` is a placeholder 0. Optional
|
|
50
|
+
* and additive: a report without it reads as before, and `schemaVersion` stays 1.
|
|
51
|
+
*/
|
|
52
|
+
priced?: boolean;
|
|
47
53
|
}
|
|
48
54
|
interface RunError {
|
|
49
55
|
code: string;
|
|
@@ -263,6 +269,8 @@ interface CompletionResponse {
|
|
|
263
269
|
}
|
|
264
270
|
interface CostEstimate {
|
|
265
271
|
cost_usd: number;
|
|
272
|
+
/** Whether `cost_usd` is a known price (zero included) rather than the 0 of an unpriced model. Optional and additive. */
|
|
273
|
+
priced?: boolean;
|
|
266
274
|
}
|
|
267
275
|
interface Provider<_TConfig extends ProviderConfig = ProviderConfig> {
|
|
268
276
|
complete(req: CompletionRequest): Promise<CompletionResponse>;
|
|
@@ -510,6 +518,7 @@ declare const runResultSchema: z.ZodObject<{
|
|
|
510
518
|
input_tokens: z.ZodNumber;
|
|
511
519
|
output_tokens: z.ZodNumber;
|
|
512
520
|
cost_usd: z.ZodNumber;
|
|
521
|
+
priced: z.ZodOptional<z.ZodBoolean>;
|
|
513
522
|
}, z.core.$strip>>;
|
|
514
523
|
latency_ms: z.ZodOptional<z.ZodNumber>;
|
|
515
524
|
error: z.ZodOptional<z.ZodObject<{
|
package/dist/index.d.ts
CHANGED
|
@@ -44,6 +44,12 @@ interface Usage {
|
|
|
44
44
|
input_tokens: number;
|
|
45
45
|
output_tokens: number;
|
|
46
46
|
cost_usd: number;
|
|
47
|
+
/**
|
|
48
|
+
* plune-ai/cli#151. `true` when the price of the model is known, a zero price included (a `:free`
|
|
49
|
+
* model, `pricing: 0`); `false` when nobody has a price and `cost_usd` is a placeholder 0. Optional
|
|
50
|
+
* and additive: a report without it reads as before, and `schemaVersion` stays 1.
|
|
51
|
+
*/
|
|
52
|
+
priced?: boolean;
|
|
47
53
|
}
|
|
48
54
|
interface RunError {
|
|
49
55
|
code: string;
|
|
@@ -263,6 +269,8 @@ interface CompletionResponse {
|
|
|
263
269
|
}
|
|
264
270
|
interface CostEstimate {
|
|
265
271
|
cost_usd: number;
|
|
272
|
+
/** Whether `cost_usd` is a known price (zero included) rather than the 0 of an unpriced model. Optional and additive. */
|
|
273
|
+
priced?: boolean;
|
|
266
274
|
}
|
|
267
275
|
interface Provider<_TConfig extends ProviderConfig = ProviderConfig> {
|
|
268
276
|
complete(req: CompletionRequest): Promise<CompletionResponse>;
|
|
@@ -510,6 +518,7 @@ declare const runResultSchema: z.ZodObject<{
|
|
|
510
518
|
input_tokens: z.ZodNumber;
|
|
511
519
|
output_tokens: z.ZodNumber;
|
|
512
520
|
cost_usd: z.ZodNumber;
|
|
521
|
+
priced: z.ZodOptional<z.ZodBoolean>;
|
|
513
522
|
}, z.core.$strip>>;
|
|
514
523
|
latency_ms: z.ZodOptional<z.ZodNumber>;
|
|
515
524
|
error: z.ZodOptional<z.ZodObject<{
|
package/dist/index.js
CHANGED
|
@@ -397,24 +397,24 @@ function priceFrom(price, usage) {
|
|
|
397
397
|
var defaultWarn = (message) => {
|
|
398
398
|
process.stderr.write(message + "\n");
|
|
399
399
|
};
|
|
400
|
-
function
|
|
400
|
+
function resolveCostEntry(usage, model, reportedCostUsd, overrides, deps = {}) {
|
|
401
401
|
const table = deps.table ?? PRICE_TABLE;
|
|
402
402
|
const warn = deps.warn ?? defaultWarn;
|
|
403
403
|
const override = overrides?.[model];
|
|
404
404
|
if (override !== void 0) {
|
|
405
|
-
return priceFrom(override, usage);
|
|
405
|
+
return { cost_usd: priceFrom(override, usage), priced: true };
|
|
406
406
|
}
|
|
407
407
|
if (reportedCostUsd !== void 0) {
|
|
408
|
-
return reportedCostUsd;
|
|
408
|
+
return { cost_usd: reportedCostUsd, priced: true };
|
|
409
409
|
}
|
|
410
410
|
const tablePrice = table[model];
|
|
411
411
|
if (tablePrice !== void 0) {
|
|
412
|
-
return priceFrom(tablePrice, usage);
|
|
412
|
+
return { cost_usd: priceFrom(tablePrice, usage), priced: true };
|
|
413
413
|
}
|
|
414
414
|
warn(
|
|
415
415
|
`plune: no price for model "${model}" \u2014 reporting cost_usd=0. Set pricing["${model}"] in plune.yaml to track its cost.`
|
|
416
416
|
);
|
|
417
|
-
return 0;
|
|
417
|
+
return { cost_usd: 0, priced: false };
|
|
418
418
|
}
|
|
419
419
|
|
|
420
420
|
// src/providers/anthropic.ts
|
|
@@ -460,7 +460,7 @@ function makeAnthropicProvider(config, env, pricing) {
|
|
|
460
460
|
}
|
|
461
461
|
},
|
|
462
462
|
estimateCost(usage, reportedCostUsd) {
|
|
463
|
-
return
|
|
463
|
+
return resolveCostEntry(usage, config.model, reportedCostUsd, pricing);
|
|
464
464
|
}
|
|
465
465
|
};
|
|
466
466
|
}
|
|
@@ -516,7 +516,7 @@ function makeOpenAiCompatibleProvider(opts) {
|
|
|
516
516
|
}
|
|
517
517
|
},
|
|
518
518
|
estimateCost(usage, reportedCostUsd) {
|
|
519
|
-
return
|
|
519
|
+
return resolveCostEntry(usage, config.model, reportedCostUsd, pricing);
|
|
520
520
|
}
|
|
521
521
|
};
|
|
522
522
|
}
|
|
@@ -578,9 +578,7 @@ function makeEstimateProvider(config, pricing) {
|
|
|
578
578
|
complete: () => Promise.reject(
|
|
579
579
|
new Error("The --dry-run provider only estimates cost; it never calls a model.")
|
|
580
580
|
),
|
|
581
|
-
estimateCost: (usage, reportedCostUsd) => (
|
|
582
|
-
cost_usd: resolveCost(usage, config.model, reportedCostUsd, pricing)
|
|
583
|
-
})
|
|
581
|
+
estimateCost: (usage, reportedCostUsd) => resolveCostEntry(usage, config.model, reportedCostUsd, pricing)
|
|
584
582
|
};
|
|
585
583
|
}
|
|
586
584
|
|
|
@@ -1366,6 +1364,12 @@ function toRunError(err) {
|
|
|
1366
1364
|
function estimateUsage(prompt5, maxTokens) {
|
|
1367
1365
|
return { input_tokens: Math.ceil(prompt5.length / 4), output_tokens: maxTokens };
|
|
1368
1366
|
}
|
|
1367
|
+
function pricedField(priced) {
|
|
1368
|
+
return priced === void 0 ? {} : { priced };
|
|
1369
|
+
}
|
|
1370
|
+
function costFields(c) {
|
|
1371
|
+
return { cost_usd: c.cost_usd, ...pricedField(c.priced) };
|
|
1372
|
+
}
|
|
1369
1373
|
async function runRow(p) {
|
|
1370
1374
|
const t0 = p.now();
|
|
1371
1375
|
const prompt5 = resolvePrompt(p.template, p.row.vars);
|
|
@@ -1373,7 +1377,8 @@ async function runRow(p) {
|
|
|
1373
1377
|
const maxTokens = p.providerConfig.max_tokens ?? DEFAULT_MAX_TOKENS2;
|
|
1374
1378
|
if (p.dryRun) {
|
|
1375
1379
|
const est = estimateUsage(prompt5, maxTokens);
|
|
1376
|
-
const
|
|
1380
|
+
const cost = p.provider.estimateCost(est);
|
|
1381
|
+
const usage2 = { ...est, ...costFields(cost) };
|
|
1377
1382
|
return { vars: p.row.vars, output: null, cached: false, usage: usage2, assertions: [] };
|
|
1378
1383
|
}
|
|
1379
1384
|
const key = cacheKey(
|
|
@@ -1411,7 +1416,9 @@ async function runRow(p) {
|
|
|
1411
1416
|
usage = {
|
|
1412
1417
|
input_tokens: hit.usage.input_tokens,
|
|
1413
1418
|
output_tokens: hit.usage.output_tokens,
|
|
1414
|
-
cost_usd: 0
|
|
1419
|
+
cost_usd: 0,
|
|
1420
|
+
// A hit costs nothing, but whether that 0 is a known price depends on the model.
|
|
1421
|
+
...pricedField(p.provider.estimateCost(hit.usage).priced)
|
|
1415
1422
|
};
|
|
1416
1423
|
cacheSaved = {
|
|
1417
1424
|
input_tokens: hit.usage.input_tokens,
|
|
@@ -1428,12 +1435,13 @@ async function runRow(p) {
|
|
|
1428
1435
|
prompt_resolved: prompt5
|
|
1429
1436
|
});
|
|
1430
1437
|
output = res.output;
|
|
1438
|
+
const cost = p.provider.estimateCost(res.usage, res.cost_usd);
|
|
1431
1439
|
usage = {
|
|
1432
1440
|
input_tokens: res.usage.input_tokens,
|
|
1433
1441
|
output_tokens: res.usage.output_tokens,
|
|
1434
1442
|
// Prefer the provider-reported actual cost (res.cost_usd) when present; resolveCost still
|
|
1435
1443
|
// lets a config pricing override win, else falls back to the table estimate (ADR-PRC01).
|
|
1436
|
-
|
|
1444
|
+
...costFields(cost)
|
|
1437
1445
|
};
|
|
1438
1446
|
if (!p.noCache && isCacheable(res) && answerParses(res.output, p.assertions)) {
|
|
1439
1447
|
p.cache.set(key, res);
|
|
@@ -1450,8 +1458,11 @@ async function runRow(p) {
|
|
|
1450
1458
|
}
|
|
1451
1459
|
}
|
|
1452
1460
|
let judgeCost = 0;
|
|
1461
|
+
let judgeUnpriced = false;
|
|
1453
1462
|
const judge = buildJudge(p.provider, p.providerConfig, (u) => {
|
|
1454
|
-
|
|
1463
|
+
const c = p.provider.estimateCost(u);
|
|
1464
|
+
judgeCost += c.cost_usd;
|
|
1465
|
+
if (c.priced === false) judgeUnpriced = true;
|
|
1455
1466
|
});
|
|
1456
1467
|
const records = [];
|
|
1457
1468
|
let assertionError;
|
|
@@ -1476,7 +1487,12 @@ async function runRow(p) {
|
|
|
1476
1487
|
break;
|
|
1477
1488
|
}
|
|
1478
1489
|
}
|
|
1479
|
-
const finalUsage = {
|
|
1490
|
+
const finalUsage = {
|
|
1491
|
+
...usage,
|
|
1492
|
+
cost_usd: usage.cost_usd + judgeCost,
|
|
1493
|
+
// A row is priced only when every call in it was; the field stays absent if the provider never said.
|
|
1494
|
+
...judgeUnpriced ? { priced: false } : {}
|
|
1495
|
+
};
|
|
1480
1496
|
return {
|
|
1481
1497
|
vars: p.row.vars,
|
|
1482
1498
|
output,
|
|
@@ -1698,7 +1714,9 @@ var assertionResultRecordSchema2 = z3.object({
|
|
|
1698
1714
|
var usageSchema = z3.object({
|
|
1699
1715
|
input_tokens: z3.number(),
|
|
1700
1716
|
output_tokens: z3.number(),
|
|
1701
|
-
cost_usd: z3.number()
|
|
1717
|
+
cost_usd: z3.number(),
|
|
1718
|
+
/** cli#151. Optional and additive — a RunResult written before it validates unchanged. */
|
|
1719
|
+
priced: z3.boolean().optional()
|
|
1702
1720
|
});
|
|
1703
1721
|
var runErrorSchema = z3.object({
|
|
1704
1722
|
code: z3.string(),
|
package/package.json
CHANGED