opencode-reviewer 0.6.0 → 0.7.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 +13 -5
- package/dist/tui.js +128 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -116,11 +116,19 @@ costs use reported charges; other endpoints use available catalog estimates.
|
|
|
116
116
|
Received usage counts even if a review fails or is interrupted. Unreported charges
|
|
117
117
|
are missing from the totals.
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
review,
|
|
123
|
-
|
|
119
|
+
The lifetime dialog shows completed reviews, retries, tokens, cost, Safe/Unsafe
|
|
120
|
+
percentages, confirmed auto-approvals, and average time to a rating and full report.
|
|
121
|
+
Percentages use recorded completed reviews as their denominator. Each validated
|
|
122
|
+
review counts once, even without usage data; a fresh review after re-enabling counts
|
|
123
|
+
again. Retries count extra API attempts actually dispatched, including format
|
|
124
|
+
corrections and transport recovery. Manual approvals are not auto-approvals.
|
|
125
|
+
Timings run from evaluation start, including evidence and retries, to the accepted
|
|
126
|
+
attempt's first rating and final validated response, excluding rendering/countdown
|
|
127
|
+
time. Non-streaming reviews use the final response time for both measurements.
|
|
128
|
+
Only running averages and sample counts are stored, not individual timings.
|
|
129
|
+
Totals persist across restarts. New metrics show partial history when older records
|
|
130
|
+
lack them; averages include measured reviews only. Earlier unrecorded values cannot
|
|
131
|
+
be reconstructed.
|
|
124
132
|
|
|
125
133
|
Reviews send the pending request, latest user prompt, project context, and relevant
|
|
126
134
|
file snapshots, diffs, or tool arguments to your endpoint before approval. Shell
|
package/dist/tui.js
CHANGED
|
@@ -1181,7 +1181,17 @@ var uiText = {
|
|
|
1181
1181
|
tokenCoverage: (available, total) => `Token counts available: ${available}/${total} requests`,
|
|
1182
1182
|
pricingCoverage: (available, total) => `Pricing available: ${available}/${total} requests`,
|
|
1183
1183
|
since: (date) => `Recorded since: ${date}`,
|
|
1184
|
-
ratings: (safe, unsafe) =>
|
|
1184
|
+
ratings: (safe, unsafe) => `${safe} \u2713 ${unsafe} \u2717`,
|
|
1185
|
+
dialogReviews: (count3) => `Reviews: ${count3}`,
|
|
1186
|
+
dialogRetries: (count3, partial) => `Retries: ${count3}${partial ? " (partial history)" : ""}`,
|
|
1187
|
+
dialogTokens: (input, output, partial) => `Tokens: ${input} in ${output} out${partial ? " (partial coverage)" : ""}`,
|
|
1188
|
+
dialogTokensUnavailable: "Tokens: unavailable",
|
|
1189
|
+
dialogCost: (amount2, partial) => amount2 === void 0 ? "Cost: unavailable" : `Cost: $${amount2}${partial ? " (partial pricing)" : ""}`,
|
|
1190
|
+
dialogSafe: (count3, percentage) => `Safe: ${count3} (${percentage === void 0 ? "n/a" : `${percentage}%`})`,
|
|
1191
|
+
dialogUnsafe: (count3, percentage) => `Unsafe: ${count3} (${percentage === void 0 ? "n/a" : `${percentage}%`})`,
|
|
1192
|
+
dialogAutoApproved: (count3, percentage, partial) => `Auto-approved: ${count3} (${percentage === void 0 ? "n/a" : `${percentage}%`})${partial ? " (partial history)" : ""}`,
|
|
1193
|
+
averageFullReport: (seconds) => `Average time to full report: ${seconds === void 0 ? "unavailable" : `${seconds}s`}`,
|
|
1194
|
+
averageRating: (seconds) => `Average time to rating: ${seconds === void 0 ? "unavailable" : `${seconds}s`}`,
|
|
1185
1195
|
ratingsSince: (date) => `Ratings recorded since: ${date}`,
|
|
1186
1196
|
ratingsExplanation: "Ratings count completed, validated reviews, including those without usage data. Previews, retries and failed or interrupted analyses do not count. A fresh review after re-enabling counts again. Earlier ratings were not recorded and cannot be recovered.",
|
|
1187
1197
|
explanation: "Received usage only, including interrupted or unsuccessful reviews. Unreported charges remain unknown. Costs combine endpoint-reported amounts and catalog estimates; legacy history retains its original estimates. Earlier unrecorded usage cannot be recovered."
|
|
@@ -1817,11 +1827,11 @@ async function streamedAssessment(response, signal, accounting, progress, firstC
|
|
|
1817
1827
|
if (!done || !stopped) throw new Error("Reviewer stream ended without stop and DONE");
|
|
1818
1828
|
return assessment;
|
|
1819
1829
|
}
|
|
1820
|
-
async function review(evidence, config, signal, fetcher = fetch, environment = process.env, prompts = BUILTIN_PROMPTS, pricing, onUsage, onProgress, onDiagnostics) {
|
|
1830
|
+
async function review(evidence, config, signal, fetcher = fetch, environment = process.env, prompts = BUILTIN_PROMPTS, pricing, onUsage, onProgress, onDiagnostics, onRetry) {
|
|
1821
1831
|
if (remainingTime(signal) === Infinity) {
|
|
1822
1832
|
let worker;
|
|
1823
1833
|
try {
|
|
1824
|
-
return await withDeadline(signal, config.timeoutMs, (bounded) => worker = review(evidence, config, bounded, fetcher, environment, prompts, pricing, onUsage, onProgress, onDiagnostics));
|
|
1834
|
+
return await withDeadline(signal, config.timeoutMs, (bounded) => worker = review(evidence, config, bounded, fetcher, environment, prompts, pricing, onUsage, onProgress, onDiagnostics, onRetry));
|
|
1825
1835
|
} finally {
|
|
1826
1836
|
await worker?.catch(() => {
|
|
1827
1837
|
});
|
|
@@ -1861,18 +1871,32 @@ async function review(evidence, config, signal, fetcher = fetch, environment = p
|
|
|
1861
1871
|
const body = JSON.stringify({
|
|
1862
1872
|
model: config.model,
|
|
1863
1873
|
messages,
|
|
1874
|
+
max_tokens: 2e3,
|
|
1864
1875
|
stream: config.stream,
|
|
1865
1876
|
...config.stream ? { stream_options: { include_usage: true } } : {}
|
|
1866
1877
|
});
|
|
1867
1878
|
reviewStage(signal, "Reviewer response");
|
|
1868
1879
|
diagnose = onDiagnostics ? diagnosticAttempt(onDiagnostics, attempt) : void 0;
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1880
|
+
signal.throwIfAborted();
|
|
1881
|
+
let pending;
|
|
1882
|
+
try {
|
|
1883
|
+
pending = fetcher(`${config.baseURL}/chat/completions`, {
|
|
1884
|
+
method: "POST",
|
|
1885
|
+
redirect: "error",
|
|
1886
|
+
signal: AbortSignal.any([signal, requestAbort.signal]),
|
|
1887
|
+
headers: { "Content-Type": "application/json", ...key ? { Authorization: `Bearer ${key}` } : {} },
|
|
1888
|
+
body
|
|
1889
|
+
});
|
|
1890
|
+
} finally {
|
|
1891
|
+
if (attempt > 0) {
|
|
1892
|
+
try {
|
|
1893
|
+
void Promise.resolve(onRetry?.()).catch(() => {
|
|
1894
|
+
});
|
|
1895
|
+
} catch {
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
response = await abortable(pending, signal, cancelBody);
|
|
1876
1900
|
diagnose?.("headers");
|
|
1877
1901
|
} catch (error) {
|
|
1878
1902
|
signal.throwIfAborted();
|
|
@@ -2184,6 +2208,7 @@ var Controller = class {
|
|
|
2184
2208
|
if (value.attempt !== entry.attempt + 1 || value.phase !== (value.attempt ? "retrying" : "evaluating")) return;
|
|
2185
2209
|
this.clearProgress(entry);
|
|
2186
2210
|
entry.attempt = value.attempt;
|
|
2211
|
+
entry.ratingAt = void 0;
|
|
2187
2212
|
entry.view = { ...entry.view, progress: { attempt: value.attempt, phase: value.phase } };
|
|
2188
2213
|
this.publish();
|
|
2189
2214
|
return;
|
|
@@ -2199,6 +2224,7 @@ var Controller = class {
|
|
|
2199
2224
|
...typeof value.preview.safe === "boolean" ? { safe: value.preview.safe } : {},
|
|
2200
2225
|
...typeof value.preview.desc === "string" ? { desc: value.preview.desc } : {}
|
|
2201
2226
|
};
|
|
2227
|
+
if (typeof preview.safe === "boolean" && entry.ratingAt === void 0) entry.ratingAt = this.time.now();
|
|
2202
2228
|
entry.pendingProgress = { attempt: value.attempt, phase: "streaming", preview };
|
|
2203
2229
|
if (preview.safe !== entry.view.progress?.preview?.safe) {
|
|
2204
2230
|
const desc = entry.view.progress?.preview?.desc;
|
|
@@ -2378,6 +2404,7 @@ var Controller = class {
|
|
|
2378
2404
|
return null;
|
|
2379
2405
|
}
|
|
2380
2406
|
}
|
|
2407
|
+
entry.startedAt = this.time.now();
|
|
2381
2408
|
return this.evaluate(request, entry.abort.signal, () => {
|
|
2382
2409
|
if (active() && (entry.view.status === "identifying" || entry.view.status === "analyzing")) {
|
|
2383
2410
|
entry.view = { ...entry.view, status: "analyzing" };
|
|
@@ -2390,7 +2417,9 @@ var Controller = class {
|
|
|
2390
2417
|
entry.view = assessment ? { ...entry.view, status: "complete", assessment, progress: void 0 } : { ...entry.view, status: "unrelated", progress: void 0 };
|
|
2391
2418
|
if (assessment) {
|
|
2392
2419
|
try {
|
|
2393
|
-
|
|
2420
|
+
const fullReportMs = Math.max(0, this.time.now() - entry.startedAt);
|
|
2421
|
+
const ratingMs = entry.ratingAt === void 0 ? fullReportMs : Math.max(0, entry.ratingAt - entry.startedAt);
|
|
2422
|
+
void Promise.resolve(this.ratingObserver?.(assessment.safe, { fullReportMs, ratingMs })).catch(() => {
|
|
2394
2423
|
});
|
|
2395
2424
|
} catch {
|
|
2396
2425
|
}
|
|
@@ -3645,6 +3674,16 @@ import { constants as constants3 } from "node:fs";
|
|
|
3645
3674
|
import { mkdir, open as open3, readdir as readdir2, rename, unlink } from "node:fs/promises";
|
|
3646
3675
|
import { randomUUID } from "node:crypto";
|
|
3647
3676
|
import path8 from "node:path";
|
|
3677
|
+
var emptyActivity = () => ({
|
|
3678
|
+
reviews: 0,
|
|
3679
|
+
usageRequests: 0,
|
|
3680
|
+
retries: 0,
|
|
3681
|
+
autoApproved: 0,
|
|
3682
|
+
timedReviews: 0,
|
|
3683
|
+
meanFullReportMs: 0,
|
|
3684
|
+
meanRatingMs: 0,
|
|
3685
|
+
since: null
|
|
3686
|
+
});
|
|
3648
3687
|
var empty = () => ({
|
|
3649
3688
|
requests: 0,
|
|
3650
3689
|
tokenRequests: 0,
|
|
@@ -3655,7 +3694,8 @@ var empty = () => ({
|
|
|
3655
3694
|
since: null,
|
|
3656
3695
|
safe: 0,
|
|
3657
3696
|
unsafe: 0,
|
|
3658
|
-
ratingsSince: null
|
|
3697
|
+
ratingsSince: null,
|
|
3698
|
+
activity: emptyActivity()
|
|
3659
3699
|
});
|
|
3660
3700
|
var count2 = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
3661
3701
|
var amount = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
@@ -3664,8 +3704,15 @@ function validate(value) {
|
|
|
3664
3704
|
if (!value || ![value.requests, value.tokenRequests, value.input, value.output, value.priced, value.safe, value.unsafe, value.safe + value.unsafe].every(count2) || !amount(value.cost) || value.priced > value.requests || value.tokenRequests > value.requests || value.requests > value.tokenRequests + value.priced || !value.tokenRequests && (value.input !== 0 || value.output !== 0) || (value.requests > 0 ? !count2(value.since) || value.since > 864e13 : value.since !== null || value.input !== 0 || value.output !== 0) || !value.priced && value.cost !== 0 || (value.safe + value.unsafe > 0 ? !count2(value.ratingsSince) || value.ratingsSince > 864e13 : value.ratingsSince !== null)) {
|
|
3665
3705
|
throw new Error("Invalid lifetime usage totals");
|
|
3666
3706
|
}
|
|
3707
|
+
const activity = value.activity;
|
|
3708
|
+
if (!activity || ![activity.reviews, activity.usageRequests, activity.retries, activity.autoApproved, activity.timedReviews].every(count2) || activity.reviews > value.safe + value.unsafe || activity.usageRequests > value.requests || activity.timedReviews > activity.reviews || ![activity.meanFullReportMs, activity.meanRatingMs].every(amount) || activity.meanRatingMs > activity.meanFullReportMs || !activity.timedReviews && (activity.meanFullReportMs !== 0 || activity.meanRatingMs !== 0) || (activity.reviews || activity.usageRequests || activity.retries || activity.autoApproved ? !count2(activity.since) || activity.since > 864e13 : activity.since !== null)) throw new Error("Invalid lifetime activity totals");
|
|
3667
3709
|
return value;
|
|
3668
3710
|
}
|
|
3711
|
+
function mean(left, leftCount, right, rightCount) {
|
|
3712
|
+
if (!leftCount) return right;
|
|
3713
|
+
if (!rightCount) return left;
|
|
3714
|
+
return left + (right - left) * (rightCount / (leftCount + rightCount));
|
|
3715
|
+
}
|
|
3669
3716
|
function add(left, right) {
|
|
3670
3717
|
return validate({
|
|
3671
3718
|
requests: left.requests + right.requests,
|
|
@@ -3677,7 +3724,17 @@ function add(left, right) {
|
|
|
3677
3724
|
since: left.since === null ? right.since : right.since === null ? left.since : Math.min(left.since, right.since),
|
|
3678
3725
|
safe: left.safe + right.safe,
|
|
3679
3726
|
unsafe: left.unsafe + right.unsafe,
|
|
3680
|
-
ratingsSince: left.ratingsSince === null ? right.ratingsSince : right.ratingsSince === null ? left.ratingsSince : Math.min(left.ratingsSince, right.ratingsSince)
|
|
3727
|
+
ratingsSince: left.ratingsSince === null ? right.ratingsSince : right.ratingsSince === null ? left.ratingsSince : Math.min(left.ratingsSince, right.ratingsSince),
|
|
3728
|
+
activity: {
|
|
3729
|
+
reviews: left.activity.reviews + right.activity.reviews,
|
|
3730
|
+
usageRequests: left.activity.usageRequests + right.activity.usageRequests,
|
|
3731
|
+
retries: left.activity.retries + right.activity.retries,
|
|
3732
|
+
autoApproved: left.activity.autoApproved + right.activity.autoApproved,
|
|
3733
|
+
timedReviews: left.activity.timedReviews + right.activity.timedReviews,
|
|
3734
|
+
meanFullReportMs: mean(left.activity.meanFullReportMs, left.activity.timedReviews, right.activity.meanFullReportMs, right.activity.timedReviews),
|
|
3735
|
+
meanRatingMs: mean(left.activity.meanRatingMs, left.activity.timedReviews, right.activity.meanRatingMs, right.activity.timedReviews),
|
|
3736
|
+
since: left.activity.since === null ? right.activity.since : right.activity.since === null ? left.activity.since : Math.min(left.activity.since, right.activity.since)
|
|
3737
|
+
}
|
|
3681
3738
|
});
|
|
3682
3739
|
}
|
|
3683
3740
|
var LifetimeUsage = class {
|
|
@@ -3706,13 +3763,36 @@ var LifetimeUsage = class {
|
|
|
3706
3763
|
output: usage.output ?? 0,
|
|
3707
3764
|
priced: usage.cost === void 0 ? 0 : 1,
|
|
3708
3765
|
cost: usage.cost ?? 0,
|
|
3709
|
-
since: Date.now()
|
|
3766
|
+
since: Date.now(),
|
|
3767
|
+
activity: { ...emptyActivity(), usageRequests: 1, since: Date.now() }
|
|
3710
3768
|
});
|
|
3711
3769
|
}
|
|
3712
3770
|
/** One accepted final review, independent of POST count or received usage. */
|
|
3713
|
-
recordRating(safe) {
|
|
3771
|
+
recordRating(safe, timing) {
|
|
3714
3772
|
if (typeof safe !== "boolean") return Promise.reject(new Error("Invalid review rating"));
|
|
3715
|
-
|
|
3773
|
+
if (timing && (![timing.fullReportMs, timing.ratingMs].every(amount) || timing.ratingMs > timing.fullReportMs)) {
|
|
3774
|
+
return Promise.reject(new Error("Invalid review timing"));
|
|
3775
|
+
}
|
|
3776
|
+
return this.increment({
|
|
3777
|
+
...empty(),
|
|
3778
|
+
safe: safe ? 1 : 0,
|
|
3779
|
+
unsafe: safe ? 0 : 1,
|
|
3780
|
+
ratingsSince: Date.now(),
|
|
3781
|
+
activity: {
|
|
3782
|
+
...emptyActivity(),
|
|
3783
|
+
reviews: 1,
|
|
3784
|
+
since: Date.now(),
|
|
3785
|
+
timedReviews: timing ? 1 : 0,
|
|
3786
|
+
meanFullReportMs: timing?.fullReportMs ?? 0,
|
|
3787
|
+
meanRatingMs: timing?.ratingMs ?? 0
|
|
3788
|
+
}
|
|
3789
|
+
});
|
|
3790
|
+
}
|
|
3791
|
+
recordRetry() {
|
|
3792
|
+
return this.increment({ ...empty(), activity: { ...emptyActivity(), retries: 1, since: Date.now() } });
|
|
3793
|
+
}
|
|
3794
|
+
recordAutoApproval() {
|
|
3795
|
+
return this.increment({ ...empty(), activity: { ...emptyActivity(), autoApproved: 1, since: Date.now() } });
|
|
3716
3796
|
}
|
|
3717
3797
|
increment(increment) {
|
|
3718
3798
|
this.pending = this.pending.catch(() => {
|
|
@@ -3723,7 +3803,7 @@ var LifetimeUsage = class {
|
|
|
3723
3803
|
try {
|
|
3724
3804
|
const file = await open3(temporary, "wx", 384);
|
|
3725
3805
|
try {
|
|
3726
|
-
await file.writeFile(JSON.stringify({ version:
|
|
3806
|
+
await file.writeFile(JSON.stringify({ version: 4, ...this.local }));
|
|
3727
3807
|
await file.sync();
|
|
3728
3808
|
} finally {
|
|
3729
3809
|
await file.close();
|
|
@@ -3783,7 +3863,7 @@ var LifetimeUsage = class {
|
|
|
3783
3863
|
}
|
|
3784
3864
|
if (size > 1024) throw new Error("Invalid lifetime usage snapshot");
|
|
3785
3865
|
const value = JSON.parse(bytes.subarray(0, size).toString("utf8"));
|
|
3786
|
-
if (
|
|
3866
|
+
if (![1, 2, 3, 4].includes(value?.version)) throw new Error("Unsupported lifetime usage snapshot");
|
|
3787
3867
|
total = add(total, validate({
|
|
3788
3868
|
requests: value.requests,
|
|
3789
3869
|
input: value.input,
|
|
@@ -3792,9 +3872,10 @@ var LifetimeUsage = class {
|
|
|
3792
3872
|
priced: value.priced,
|
|
3793
3873
|
cost: value.cost,
|
|
3794
3874
|
since: value.since,
|
|
3795
|
-
safe: value.version
|
|
3796
|
-
unsafe: value.version
|
|
3797
|
-
ratingsSince: value.version
|
|
3875
|
+
safe: value.version >= 3 ? value.safe : 0,
|
|
3876
|
+
unsafe: value.version >= 3 ? value.unsafe : 0,
|
|
3877
|
+
ratingsSince: value.version >= 3 ? value.ratingsSince : null,
|
|
3878
|
+
activity: value.version === 4 ? value.activity : emptyActivity()
|
|
3798
3879
|
}));
|
|
3799
3880
|
} finally {
|
|
3800
3881
|
await file.close();
|
|
@@ -3811,19 +3892,21 @@ function lifetimeCost(totals) {
|
|
|
3811
3892
|
return uiText.lifetime.cost(totals.cost.toFixed(4), totals.priced < totals.requests);
|
|
3812
3893
|
}
|
|
3813
3894
|
function lifetimeReport(totals) {
|
|
3895
|
+
const reviews = totals.safe + totals.unsafe, activity = totals.activity;
|
|
3896
|
+
const percentage = (count3) => reviews ? (count3 / reviews * 100).toFixed(1) : void 0;
|
|
3897
|
+
const partial = activity.reviews < reviews || activity.usageRequests < totals.requests;
|
|
3814
3898
|
return [
|
|
3815
|
-
|
|
3816
|
-
uiText.lifetime.
|
|
3817
|
-
uiText.lifetime.
|
|
3818
|
-
|
|
3819
|
-
uiText.lifetime.tokenCoverage(totals.tokenRequests, totals.requests),
|
|
3820
|
-
uiText.lifetime.pricingCoverage(totals.priced, totals.requests),
|
|
3821
|
-
...totals.since === null ? [] : [uiText.lifetime.since(new Date(totals.since).toISOString().slice(0, 10))],
|
|
3822
|
-
...totals.ratingsSince === null ? [] : [uiText.lifetime.ratingsSince(new Date(totals.ratingsSince).toISOString().slice(0, 10))],
|
|
3899
|
+
uiText.lifetime.dialogReviews(reviews),
|
|
3900
|
+
uiText.lifetime.dialogRetries(activity.retries, partial),
|
|
3901
|
+
totals.tokenRequests ? uiText.lifetime.dialogTokens(totals.input, totals.output, totals.tokenRequests < totals.requests) : uiText.lifetime.dialogTokensUnavailable,
|
|
3902
|
+
uiText.lifetime.dialogCost(totals.priced ? totals.cost.toFixed(4) : void 0, totals.priced < totals.requests),
|
|
3823
3903
|
"",
|
|
3824
|
-
uiText.lifetime.
|
|
3904
|
+
uiText.lifetime.dialogSafe(totals.safe, percentage(totals.safe)),
|
|
3905
|
+
uiText.lifetime.dialogUnsafe(totals.unsafe, percentage(totals.unsafe)),
|
|
3906
|
+
uiText.lifetime.dialogAutoApproved(activity.autoApproved, percentage(activity.autoApproved), partial),
|
|
3825
3907
|
"",
|
|
3826
|
-
uiText.lifetime.
|
|
3908
|
+
uiText.lifetime.averageFullReport(activity.timedReviews ? (activity.meanFullReportMs / 1e3).toFixed(2) : void 0),
|
|
3909
|
+
uiText.lifetime.averageRating(activity.timedReviews ? (activity.meanRatingMs / 1e3).toFixed(2) : void 0)
|
|
3827
3910
|
].join("\n");
|
|
3828
3911
|
}
|
|
3829
3912
|
|
|
@@ -3909,7 +3992,7 @@ var LifetimeRefresh = class {
|
|
|
3909
3992
|
// src/lifetime-view.tsx
|
|
3910
3993
|
function lifetimeTracker(api) {
|
|
3911
3994
|
const directory = path9.join(api.state.path.state, "opencode-reviewer");
|
|
3912
|
-
const store = new LifetimeUsage(path9.join(directory, "usage-v3"), path9.join(directory, "usage-v2"), path9.join(directory, "usage-v1"));
|
|
3995
|
+
const store = new LifetimeUsage(path9.join(directory, "usage-v4"), path9.join(directory, "usage-v3"), path9.join(directory, "usage-v2"), path9.join(directory, "usage-v1"));
|
|
3913
3996
|
const [totals, setTotals] = createSignal();
|
|
3914
3997
|
const [unavailable, setUnavailable] = createSignal(false);
|
|
3915
3998
|
const refresh = new LifetimeRefresh((signal) => store.totals(signal), (value) => {
|
|
@@ -3950,8 +4033,14 @@ function lifetimeTracker(api) {
|
|
|
3950
4033
|
record: (usage) => {
|
|
3951
4034
|
void store.record(usage).then(() => refresh.refresh(), () => refresh.failed());
|
|
3952
4035
|
},
|
|
3953
|
-
recordRating: (safe) => {
|
|
3954
|
-
void store.recordRating(safe).then(() => refresh.refresh(), () => refresh.failed());
|
|
4036
|
+
recordRating: (safe, timing) => {
|
|
4037
|
+
void store.recordRating(safe, timing).then(() => refresh.refresh(), () => refresh.failed());
|
|
4038
|
+
},
|
|
4039
|
+
recordRetry: () => {
|
|
4040
|
+
void store.recordRetry().then(() => refresh.refresh(), () => refresh.failed());
|
|
4041
|
+
},
|
|
4042
|
+
recordAutoApproval: () => {
|
|
4043
|
+
void store.recordAutoApproval().then(() => refresh.refresh(), () => refresh.failed());
|
|
3955
4044
|
}
|
|
3956
4045
|
};
|
|
3957
4046
|
}
|
|
@@ -6347,7 +6436,7 @@ async function reviewTui(api, options, fileIO, observer, notificationBackend) {
|
|
|
6347
6436
|
}, config, configError, signal, onIdentified, files);
|
|
6348
6437
|
if (!evidence) return null;
|
|
6349
6438
|
signal.throwIfAborted();
|
|
6350
|
-
const result = review(evidence, config, signal, void 0, void 0, prompts, (model) => modelPricing(api.state.provider, config.baseURL, model), lifetime.record, onProgress, trace?.forward);
|
|
6439
|
+
const result = review(evidence, config, signal, void 0, void 0, prompts, (model) => modelPricing(api.state.provider, config.baseURL, model), lifetime.record, onProgress, trace?.forward, lifetime.recordRetry);
|
|
6351
6440
|
worker = result;
|
|
6352
6441
|
return result;
|
|
6353
6442
|
});
|
|
@@ -6368,7 +6457,10 @@ async function reviewTui(api, options, fileIO, observer, notificationBackend) {
|
|
|
6368
6457
|
once: (request, signal) => measured(traces?.get(request), "approval-reply", () => approval.once(request, signal))
|
|
6369
6458
|
} : approval,
|
|
6370
6459
|
visibleID: () => visibleApproval()
|
|
6371
|
-
}, void 0, modes, (fact) =>
|
|
6460
|
+
}, void 0, modes, (fact) => {
|
|
6461
|
+
if (fact.type === "confirmed" && fact.automatic) lifetime.recordAutoApproval();
|
|
6462
|
+
notifications?.fact(fact);
|
|
6463
|
+
}, lifetime.recordRating);
|
|
6372
6464
|
api.event.on("permission.asked", (event) => controller.asked(event.properties));
|
|
6373
6465
|
api.event.on("permission.replied", (event) => controller.replied(event.properties.requestID));
|
|
6374
6466
|
api.event.on("session.deleted", (event) => {
|