anpord 0.1.23 → 0.1.24
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/bin.cjs +93 -4
- package/dist/bin.mjs +93 -4
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -19,7 +19,7 @@ let yaml = require("yaml");
|
|
|
19
19
|
let node_crypto = require("node:crypto");
|
|
20
20
|
let node_child_process = require("node:child_process");
|
|
21
21
|
//#region package.json
|
|
22
|
-
var version$1 = "0.1.
|
|
22
|
+
var version$1 = "0.1.24";
|
|
23
23
|
//#endregion
|
|
24
24
|
//#region ../template/src/extract.ts
|
|
25
25
|
/** Reads escapes too, so text the renderer leaves literal is never reported as
|
|
@@ -220,6 +220,86 @@ var NoEvalFiles = class extends effect.Data.TaggedError("NoEvalFiles") {
|
|
|
220
220
|
}
|
|
221
221
|
};
|
|
222
222
|
//#endregion
|
|
223
|
+
//#region ../schema/src/domain/usage-health.ts
|
|
224
|
+
const CACHE_FLOOR = 5e4;
|
|
225
|
+
const PER_TURN_CEILING = 12e3;
|
|
226
|
+
const perTurnInput = ({ turns, usage }) => turns <= 0 ? usage.inputTokens : Math.round(usage.inputTokens / turns);
|
|
227
|
+
const usageConcerns = (reading) => {
|
|
228
|
+
const { usage } = reading;
|
|
229
|
+
const served = usage.inputTokens + usage.cacheReadTokens;
|
|
230
|
+
const concerns = [];
|
|
231
|
+
if (perTurnInput(reading) >= PER_TURN_CEILING) concerns.push("context-grew-fast");
|
|
232
|
+
if (served >= CACHE_FLOOR && usage.cacheReadTokens === 0) concerns.push("nothing-cached");
|
|
233
|
+
return concerns;
|
|
234
|
+
};
|
|
235
|
+
const CONCERN_REASONS = {
|
|
236
|
+
"context-grew-fast": "Each turn carried a large context, which is what happens when an agent reads a dependency or a long file into the conversation and then re-sends it every turn after.",
|
|
237
|
+
"nothing-cached": "Nothing was served from cache, so every turn paid full price for the turns before it."
|
|
238
|
+
};
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/cli/eval-usage.ts
|
|
241
|
+
const THOUSAND = 1e3;
|
|
242
|
+
const MILLION = 1e6;
|
|
243
|
+
const CENT = .01;
|
|
244
|
+
const trialsOf = (run) => run.cells.flatMap((cell) => cell.trials);
|
|
245
|
+
const runUsage = (run) => {
|
|
246
|
+
const concerns = /* @__PURE__ */ new Set();
|
|
247
|
+
let inputTokens = 0;
|
|
248
|
+
let outputTokens = 0;
|
|
249
|
+
let totalTokens = 0;
|
|
250
|
+
for (const trial of trialsOf(run)) {
|
|
251
|
+
if (!trial.usage) continue;
|
|
252
|
+
inputTokens += trial.usage.inputTokens;
|
|
253
|
+
outputTokens += trial.usage.outputTokens;
|
|
254
|
+
totalTokens += trial.usage.totalTokens;
|
|
255
|
+
for (const concern of usageConcerns({
|
|
256
|
+
turns: trial.commands,
|
|
257
|
+
usage: trial.usage
|
|
258
|
+
})) concerns.add(concern);
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
concerns: [...concerns],
|
|
262
|
+
inputTokens,
|
|
263
|
+
outputTokens,
|
|
264
|
+
totalTokens,
|
|
265
|
+
usd: run.costs?.estimatedEquivalentUsd ?? null
|
|
266
|
+
};
|
|
267
|
+
};
|
|
268
|
+
const formatTokens = (value) => {
|
|
269
|
+
if (value >= MILLION) return `${(value / MILLION).toFixed(1)}M`;
|
|
270
|
+
return value >= THOUSAND ? `${Math.round(value / THOUSAND)}k` : String(value);
|
|
271
|
+
};
|
|
272
|
+
const formatUsd = (value) => value < CENT ? "<$0.01" : `$${value.toFixed(2)}`;
|
|
273
|
+
const usageLines = (usage) => {
|
|
274
|
+
if (usage.totalTokens === 0) return [];
|
|
275
|
+
const spend = usage.usd === null ? "" : `, ${formatUsd(usage.usd)} est.`;
|
|
276
|
+
return [`${formatTokens(usage.totalTokens)} tokens (${formatTokens(usage.inputTokens)} in, ${formatTokens(usage.outputTokens)} out)${spend}`, ...usage.concerns.map((concern) => CONCERN_REASONS[concern])];
|
|
277
|
+
};
|
|
278
|
+
const localUsage = (cases) => {
|
|
279
|
+
const concerns = /* @__PURE__ */ new Set();
|
|
280
|
+
let inputTokens = 0;
|
|
281
|
+
let outputTokens = 0;
|
|
282
|
+
let totalTokens = 0;
|
|
283
|
+
for (const one of cases) {
|
|
284
|
+
if (!one.usage) continue;
|
|
285
|
+
inputTokens += one.usage.inputTokens;
|
|
286
|
+
outputTokens += one.usage.outputTokens;
|
|
287
|
+
totalTokens += one.usage.inputTokens + one.usage.outputTokens;
|
|
288
|
+
for (const concern of usageConcerns({
|
|
289
|
+
turns: one.turns,
|
|
290
|
+
usage: one.usage
|
|
291
|
+
})) concerns.add(concern);
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
concerns: [...concerns],
|
|
295
|
+
inputTokens,
|
|
296
|
+
outputTokens,
|
|
297
|
+
totalTokens,
|
|
298
|
+
usd: null
|
|
299
|
+
};
|
|
300
|
+
};
|
|
301
|
+
const localUsageLines = (cases) => usageLines(localUsage(cases)).map((line) => ` ${line}`);
|
|
302
|
+
//#endregion
|
|
223
303
|
//#region src/cli/eval-grid.ts
|
|
224
304
|
const DIM = "\x1B[2m";
|
|
225
305
|
const BOLD = "\x1B[1m";
|
|
@@ -289,7 +369,10 @@ const formatGrid = (run, trials, elapsedMs) => {
|
|
|
289
369
|
}
|
|
290
370
|
lines.push("");
|
|
291
371
|
}
|
|
292
|
-
|
|
372
|
+
const usage = runUsage(run);
|
|
373
|
+
const [spend, ...concerns] = usageLines(usage);
|
|
374
|
+
lines.push(paint(DIM, spend === void 0 ? ` ${formatElapsed(elapsedMs)} elapsed` : ` ${formatElapsed(elapsedMs)} elapsed · ${spend}`));
|
|
375
|
+
for (const concern of concerns) lines.push(paint(YELLOW, ` ${concern}`));
|
|
293
376
|
return lines;
|
|
294
377
|
};
|
|
295
378
|
const up = (rows) => `[${rows}A[0J`;
|
|
@@ -4543,11 +4626,17 @@ const runLocally = (request, options = {}) => effect.Effect.gen(function* () {
|
|
|
4543
4626
|
}) ?? effect.Effect.void), effect.Effect.map((outcome) => ({
|
|
4544
4627
|
durationMs: outcome.durationMs,
|
|
4545
4628
|
name: subject.name,
|
|
4546
|
-
status: outcome.outcome.status
|
|
4629
|
+
status: outcome.outcome.status,
|
|
4630
|
+
turns: outcome.outcome.commandCount,
|
|
4631
|
+
usage: effect.Option.getOrNull(outcome.result.usage)
|
|
4547
4632
|
}))), { concurrency: 1 });
|
|
4548
4633
|
}).pipe(effect.Effect.provide(options.credentials === void 0 ? EvalLocalLive : evalLocalWith(credentialResolverFrom(options.credentials))), effect.Effect.scoped, effect.Effect.withConfigProvider(effect.ConfigProvider.fromEnv().pipe(effect.ConfigProvider.orElse(() => effect.ConfigProvider.fromMap(/* @__PURE__ */ new Map([["ANPORD_LOCAL_SANDBOX", "true"]]))))));
|
|
4549
4634
|
const seconds = (ms) => `${(ms / 1e3).toFixed(1)}s`;
|
|
4550
|
-
const reportLocal = (file, cases) => effect.Effect.forEach([
|
|
4635
|
+
const reportLocal = (file, cases) => effect.Effect.forEach([
|
|
4636
|
+
`${file}: ${cases.length} case(s) on this machine`,
|
|
4637
|
+
...cases.map((one) => ` ${one.status} ${one.name} ${seconds(one.durationMs)}`),
|
|
4638
|
+
...localUsageLines(cases)
|
|
4639
|
+
], note);
|
|
4551
4640
|
const localProblems = (cases) => cases.flatMap((one) => one.status === "passed" ? [] : [`${one.name} ${one.status}`]);
|
|
4552
4641
|
//#endregion
|
|
4553
4642
|
//#region src/cli/eval-outcome.ts
|
package/dist/bin.mjs
CHANGED
|
@@ -19,7 +19,7 @@ import { parseDocument } from "yaml";
|
|
|
19
19
|
import { createHash } from "node:crypto";
|
|
20
20
|
import { spawn } from "node:child_process";
|
|
21
21
|
//#region package.json
|
|
22
|
-
var version$1 = "0.1.
|
|
22
|
+
var version$1 = "0.1.24";
|
|
23
23
|
//#endregion
|
|
24
24
|
//#region ../template/src/extract.ts
|
|
25
25
|
/** Reads escapes too, so text the renderer leaves literal is never reported as
|
|
@@ -220,6 +220,86 @@ var NoEvalFiles = class extends Data.TaggedError("NoEvalFiles") {
|
|
|
220
220
|
}
|
|
221
221
|
};
|
|
222
222
|
//#endregion
|
|
223
|
+
//#region ../schema/src/domain/usage-health.ts
|
|
224
|
+
const CACHE_FLOOR = 5e4;
|
|
225
|
+
const PER_TURN_CEILING = 12e3;
|
|
226
|
+
const perTurnInput = ({ turns, usage }) => turns <= 0 ? usage.inputTokens : Math.round(usage.inputTokens / turns);
|
|
227
|
+
const usageConcerns = (reading) => {
|
|
228
|
+
const { usage } = reading;
|
|
229
|
+
const served = usage.inputTokens + usage.cacheReadTokens;
|
|
230
|
+
const concerns = [];
|
|
231
|
+
if (perTurnInput(reading) >= PER_TURN_CEILING) concerns.push("context-grew-fast");
|
|
232
|
+
if (served >= CACHE_FLOOR && usage.cacheReadTokens === 0) concerns.push("nothing-cached");
|
|
233
|
+
return concerns;
|
|
234
|
+
};
|
|
235
|
+
const CONCERN_REASONS = {
|
|
236
|
+
"context-grew-fast": "Each turn carried a large context, which is what happens when an agent reads a dependency or a long file into the conversation and then re-sends it every turn after.",
|
|
237
|
+
"nothing-cached": "Nothing was served from cache, so every turn paid full price for the turns before it."
|
|
238
|
+
};
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/cli/eval-usage.ts
|
|
241
|
+
const THOUSAND = 1e3;
|
|
242
|
+
const MILLION = 1e6;
|
|
243
|
+
const CENT = .01;
|
|
244
|
+
const trialsOf = (run) => run.cells.flatMap((cell) => cell.trials);
|
|
245
|
+
const runUsage = (run) => {
|
|
246
|
+
const concerns = /* @__PURE__ */ new Set();
|
|
247
|
+
let inputTokens = 0;
|
|
248
|
+
let outputTokens = 0;
|
|
249
|
+
let totalTokens = 0;
|
|
250
|
+
for (const trial of trialsOf(run)) {
|
|
251
|
+
if (!trial.usage) continue;
|
|
252
|
+
inputTokens += trial.usage.inputTokens;
|
|
253
|
+
outputTokens += trial.usage.outputTokens;
|
|
254
|
+
totalTokens += trial.usage.totalTokens;
|
|
255
|
+
for (const concern of usageConcerns({
|
|
256
|
+
turns: trial.commands,
|
|
257
|
+
usage: trial.usage
|
|
258
|
+
})) concerns.add(concern);
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
concerns: [...concerns],
|
|
262
|
+
inputTokens,
|
|
263
|
+
outputTokens,
|
|
264
|
+
totalTokens,
|
|
265
|
+
usd: run.costs?.estimatedEquivalentUsd ?? null
|
|
266
|
+
};
|
|
267
|
+
};
|
|
268
|
+
const formatTokens = (value) => {
|
|
269
|
+
if (value >= MILLION) return `${(value / MILLION).toFixed(1)}M`;
|
|
270
|
+
return value >= THOUSAND ? `${Math.round(value / THOUSAND)}k` : String(value);
|
|
271
|
+
};
|
|
272
|
+
const formatUsd = (value) => value < CENT ? "<$0.01" : `$${value.toFixed(2)}`;
|
|
273
|
+
const usageLines = (usage) => {
|
|
274
|
+
if (usage.totalTokens === 0) return [];
|
|
275
|
+
const spend = usage.usd === null ? "" : `, ${formatUsd(usage.usd)} est.`;
|
|
276
|
+
return [`${formatTokens(usage.totalTokens)} tokens (${formatTokens(usage.inputTokens)} in, ${formatTokens(usage.outputTokens)} out)${spend}`, ...usage.concerns.map((concern) => CONCERN_REASONS[concern])];
|
|
277
|
+
};
|
|
278
|
+
const localUsage = (cases) => {
|
|
279
|
+
const concerns = /* @__PURE__ */ new Set();
|
|
280
|
+
let inputTokens = 0;
|
|
281
|
+
let outputTokens = 0;
|
|
282
|
+
let totalTokens = 0;
|
|
283
|
+
for (const one of cases) {
|
|
284
|
+
if (!one.usage) continue;
|
|
285
|
+
inputTokens += one.usage.inputTokens;
|
|
286
|
+
outputTokens += one.usage.outputTokens;
|
|
287
|
+
totalTokens += one.usage.inputTokens + one.usage.outputTokens;
|
|
288
|
+
for (const concern of usageConcerns({
|
|
289
|
+
turns: one.turns,
|
|
290
|
+
usage: one.usage
|
|
291
|
+
})) concerns.add(concern);
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
concerns: [...concerns],
|
|
295
|
+
inputTokens,
|
|
296
|
+
outputTokens,
|
|
297
|
+
totalTokens,
|
|
298
|
+
usd: null
|
|
299
|
+
};
|
|
300
|
+
};
|
|
301
|
+
const localUsageLines = (cases) => usageLines(localUsage(cases)).map((line) => ` ${line}`);
|
|
302
|
+
//#endregion
|
|
223
303
|
//#region src/cli/eval-grid.ts
|
|
224
304
|
const DIM = "\x1B[2m";
|
|
225
305
|
const BOLD = "\x1B[1m";
|
|
@@ -289,7 +369,10 @@ const formatGrid = (run, trials, elapsedMs) => {
|
|
|
289
369
|
}
|
|
290
370
|
lines.push("");
|
|
291
371
|
}
|
|
292
|
-
|
|
372
|
+
const usage = runUsage(run);
|
|
373
|
+
const [spend, ...concerns] = usageLines(usage);
|
|
374
|
+
lines.push(paint(DIM, spend === void 0 ? ` ${formatElapsed(elapsedMs)} elapsed` : ` ${formatElapsed(elapsedMs)} elapsed · ${spend}`));
|
|
375
|
+
for (const concern of concerns) lines.push(paint(YELLOW, ` ${concern}`));
|
|
293
376
|
return lines;
|
|
294
377
|
};
|
|
295
378
|
const up = (rows) => `[${rows}A[0J`;
|
|
@@ -4543,11 +4626,17 @@ const runLocally = (request, options = {}) => Effect.gen(function* () {
|
|
|
4543
4626
|
}) ?? Effect.void), Effect.map((outcome) => ({
|
|
4544
4627
|
durationMs: outcome.durationMs,
|
|
4545
4628
|
name: subject.name,
|
|
4546
|
-
status: outcome.outcome.status
|
|
4629
|
+
status: outcome.outcome.status,
|
|
4630
|
+
turns: outcome.outcome.commandCount,
|
|
4631
|
+
usage: Option.getOrNull(outcome.result.usage)
|
|
4547
4632
|
}))), { concurrency: 1 });
|
|
4548
4633
|
}).pipe(Effect.provide(options.credentials === void 0 ? EvalLocalLive : evalLocalWith(credentialResolverFrom(options.credentials))), Effect.scoped, Effect.withConfigProvider(ConfigProvider.fromEnv().pipe(ConfigProvider.orElse(() => ConfigProvider.fromMap(/* @__PURE__ */ new Map([["ANPORD_LOCAL_SANDBOX", "true"]]))))));
|
|
4549
4634
|
const seconds = (ms) => `${(ms / 1e3).toFixed(1)}s`;
|
|
4550
|
-
const reportLocal = (file, cases) => Effect.forEach([
|
|
4635
|
+
const reportLocal = (file, cases) => Effect.forEach([
|
|
4636
|
+
`${file}: ${cases.length} case(s) on this machine`,
|
|
4637
|
+
...cases.map((one) => ` ${one.status} ${one.name} ${seconds(one.durationMs)}`),
|
|
4638
|
+
...localUsageLines(cases)
|
|
4639
|
+
], note);
|
|
4551
4640
|
const localProblems = (cases) => cases.flatMap((one) => one.status === "passed" ? [] : [`${one.name} ${one.status}`]);
|
|
4552
4641
|
//#endregion
|
|
4553
4642
|
//#region src/cli/eval-outcome.ts
|