jev-agent-tools 0.2.0 → 0.3.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/CHANGELOG.md +37 -1
- package/CONTRIBUTING.md +3 -0
- package/README.md +22 -14
- package/SECURITY.md +17 -1
- package/dist/adapters/ask-files.js +11 -2
- package/dist/adapters/ask-proof.js +63 -7
- package/dist/adapters/command.js +82 -29
- package/dist/adapters/docs.js +30 -10
- package/dist/adapters/evidence-context.js +119 -0
- package/dist/adapters/files.js +141 -16
- package/dist/adapters/find.js +34 -6
- package/dist/adapters/git-base.js +7 -1
- package/dist/adapters/git.js +51 -7
- package/dist/adapters/locate-file.js +47 -9
- package/dist/adapters/private-storage.js +14 -6
- package/dist/adapters/risk-callers.js +3 -0
- package/dist/adapters/shell.js +23 -7
- package/dist/adapters/test-inventory.js +10 -2
- package/dist/configuration.js +17 -7
- package/dist/constants.js +26 -5
- package/dist/core/ask-references.js +193 -109
- package/dist/core/asks.js +78 -7
- package/dist/core/locate.js +8 -8
- package/dist/core/output.js +17 -0
- package/dist/core/result-report.js +302 -0
- package/dist/core/secret-path.js +34 -0
- package/dist/core/state.js +8 -1
- package/dist/core/units.js +1 -1
- package/dist/jev/client.js +34 -12
- package/dist/mcp/protocol.js +50 -27
- package/dist/mcp/tools.js +20 -7
- package/dist/render.js +72 -0
- package/dist/report-schema.js +1356 -0
- package/dist/result-types.js +1 -0
- package/dist/texts/ask-files.js +3 -1
- package/dist/texts/ask.js +3 -1
- package/dist/texts/check-diff.js +7 -4
- package/dist/texts/find.js +7 -2
- package/dist/texts/guide.js +3 -16
- package/dist/texts/instructions.js +72 -0
- package/dist/texts/locate.js +7 -2
- package/dist/texts/select-tests.js +3 -1
- package/dist/tools/ask-files.js +248 -15
- package/dist/tools/ask.js +523 -62
- package/dist/tools/check-diff.js +222 -30
- package/dist/tools/docs-check.js +122 -13
- package/dist/tools/find.js +320 -27
- package/dist/tools/locate.js +317 -18
- package/dist/tools/review-report.js +230 -0
- package/dist/tools/select-tests.js +273 -19
- package/dist/tools/spec-check.js +119 -22
- package/docs/adr/0001-strict-typescript-pure-core-offline-tests.md +3 -3
- package/docs/agent-instructions.md +59 -30
- package/docs/design.md +13 -1
- package/docs/mcp.md +8 -6
- package/docs/tools/jev_ask.md +8 -5
- package/docs/tools/jev_ask_files.md +2 -1
- package/docs/tools/jev_check_diff.md +4 -1
- package/docs/tools/jev_find_files.md +2 -1
- package/docs/tools/jev_locate_in_file.md +5 -0
- package/docs/tools/jev_select_tests.md +4 -1
- package/package.json +1 -1
- package/rules/jev-ask.md +22 -1
- package/server.json +2 -2
- package/src/adapters/ask-files.ts +11 -3
- package/src/adapters/ask-proof.ts +69 -11
- package/src/adapters/command.ts +96 -33
- package/src/adapters/docs.ts +33 -14
- package/src/adapters/evidence-context.ts +169 -0
- package/src/adapters/files.ts +146 -16
- package/src/adapters/find.ts +37 -7
- package/src/adapters/git-base.ts +7 -1
- package/src/adapters/git.ts +61 -8
- package/src/adapters/locate-file.ts +51 -9
- package/src/adapters/private-storage.ts +17 -5
- package/src/adapters/risk-callers.ts +3 -0
- package/src/adapters/shell.ts +23 -7
- package/src/adapters/test-inventory.ts +12 -4
- package/src/configuration.ts +16 -2
- package/src/constants.ts +26 -5
- package/src/core/ask-references.ts +262 -146
- package/src/core/asks.ts +79 -7
- package/src/core/import-boundaries.ts +8 -3
- package/src/core/locate.ts +8 -5
- package/src/core/output.ts +34 -0
- package/src/core/result-report.ts +410 -0
- package/src/core/secret-path.ts +37 -0
- package/src/core/state.ts +8 -1
- package/src/core/units.ts +3 -2
- package/src/index.ts +3 -0
- package/src/jev/client.ts +54 -16
- package/src/jev/types.ts +18 -3
- package/src/mcp/protocol.ts +91 -41
- package/src/mcp/tools.ts +26 -13
- package/src/render.ts +109 -0
- package/src/report-schema.ts +1380 -0
- package/src/result-types.ts +234 -0
- package/src/result.ts +4 -1
- package/src/runtime.ts +6 -0
- package/src/texts/ask-files.ts +4 -1
- package/src/texts/ask.ts +8 -1
- package/src/texts/check-diff.ts +7 -4
- package/src/texts/find.ts +8 -2
- package/src/texts/guide.ts +8 -16
- package/src/texts/instructions.ts +98 -0
- package/src/texts/locate.ts +8 -2
- package/src/texts/run-end.ts +2 -2
- package/src/texts/select-tests.ts +4 -1
- package/src/tools/ask-files.ts +309 -14
- package/src/tools/ask.ts +700 -77
- package/src/tools/check-diff.ts +331 -28
- package/src/tools/docs-check.ts +241 -39
- package/src/tools/find.ts +386 -29
- package/src/tools/locate.ts +384 -19
- package/src/tools/review-report.ts +308 -0
- package/src/tools/select-tests.ts +479 -21
- package/src/tools/spec-check.ts +193 -19
package/src/tools/docs-check.ts
CHANGED
|
@@ -3,6 +3,11 @@ import {
|
|
|
3
3
|
collectDocsInventory,
|
|
4
4
|
docsDeclarationSearch,
|
|
5
5
|
} from "../adapters/docs.ts";
|
|
6
|
+
import {
|
|
7
|
+
type EvidenceContext,
|
|
8
|
+
resolveEvidenceContext,
|
|
9
|
+
withEvidenceContext,
|
|
10
|
+
} from "../adapters/evidence-context.ts";
|
|
6
11
|
import { collectUnits } from "../adapters/git.ts";
|
|
7
12
|
import { resolveBase } from "../adapters/git-base.ts";
|
|
8
13
|
import { shareGitInventory } from "../adapters/git-inventory.ts";
|
|
@@ -12,6 +17,7 @@ import {
|
|
|
12
17
|
DOCS_DISPLAY_MAX_SECTIONS,
|
|
13
18
|
DOCS_MAX_SECTIONS,
|
|
14
19
|
STATE_MAX_CHARS,
|
|
20
|
+
TIMEOUT_MS,
|
|
15
21
|
} from "../constants.ts";
|
|
16
22
|
import { collectDocsCandidates } from "../core/docs.ts";
|
|
17
23
|
import {
|
|
@@ -21,6 +27,11 @@ import {
|
|
|
21
27
|
type Envelope,
|
|
22
28
|
type Limitation,
|
|
23
29
|
} from "../core/output.ts";
|
|
30
|
+
import {
|
|
31
|
+
type Cause,
|
|
32
|
+
known,
|
|
33
|
+
type ResultReportV1,
|
|
34
|
+
} from "../core/result-report.ts";
|
|
24
35
|
import type { Judgment } from "../jev/types.ts";
|
|
25
36
|
import {
|
|
26
37
|
type DocsFinding,
|
|
@@ -29,6 +40,7 @@ import {
|
|
|
29
40
|
} from "../presets/docs.ts";
|
|
30
41
|
import type { ToolDependencies } from "../runtime.ts";
|
|
31
42
|
import { NOT_CONFIGURED } from "../texts/configuration.ts";
|
|
43
|
+
import { ReviewReport, reportMetrics } from "./review-report.ts";
|
|
32
44
|
|
|
33
45
|
export interface DocsCheckInput {
|
|
34
46
|
cwd: string;
|
|
@@ -36,6 +48,7 @@ export interface DocsCheckInput {
|
|
|
36
48
|
signal?: AbortSignal;
|
|
37
49
|
budgetMs?: number;
|
|
38
50
|
maxCalls?: number;
|
|
51
|
+
evidenceContext?: EvidenceContext;
|
|
39
52
|
}
|
|
40
53
|
export interface DocsCheckResult {
|
|
41
54
|
ok: boolean;
|
|
@@ -47,6 +60,7 @@ export interface DocsCheckResult {
|
|
|
47
60
|
envelope: Envelope;
|
|
48
61
|
judgments: Judgment[];
|
|
49
62
|
findings: DocsFinding[];
|
|
63
|
+
result: ResultReportV1;
|
|
50
64
|
unjudged?: { count: number; sections: readonly string[]; truncated: boolean };
|
|
51
65
|
collection?: {
|
|
52
66
|
kind: "collection_budget";
|
|
@@ -61,6 +75,17 @@ export async function runDocsCheck(
|
|
|
61
75
|
input: DocsCheckInput,
|
|
62
76
|
): Promise<DocsCheckResult> {
|
|
63
77
|
const started = performance.now();
|
|
78
|
+
const report = new ReviewReport();
|
|
79
|
+
const admission = input.evidenceContext
|
|
80
|
+
? undefined
|
|
81
|
+
: await resolveEvidenceContext(input.cwd, undefined, {
|
|
82
|
+
exec: deps.exec,
|
|
83
|
+
signal: input.signal,
|
|
84
|
+
origin: deps.evidenceOrigin,
|
|
85
|
+
});
|
|
86
|
+
const evidenceContext = input.evidenceContext ?? admission?.context;
|
|
87
|
+
if (!evidenceContext) throw new Error("Evidence context was not established");
|
|
88
|
+
evidenceContext.requestedBase = input.base ?? "HEAD";
|
|
64
89
|
deps = { ...deps, exec: shareGitInventory(deps.exec) };
|
|
65
90
|
const timeout =
|
|
66
91
|
input.budgetMs === undefined
|
|
@@ -84,7 +109,10 @@ export async function runDocsCheck(
|
|
|
84
109
|
let budget: BudgetRefusal | undefined;
|
|
85
110
|
let sent = 0;
|
|
86
111
|
let emptyBase: string | undefined;
|
|
87
|
-
const finish = (
|
|
112
|
+
const finish = (
|
|
113
|
+
refusal?: string,
|
|
114
|
+
cause: Cause = "internal_error",
|
|
115
|
+
): DocsCheckResult => {
|
|
88
116
|
if (unchecked.length > 5) {
|
|
89
117
|
unjudged = {
|
|
90
118
|
count: unchecked.length,
|
|
@@ -157,7 +185,9 @@ export async function runDocsCheck(
|
|
|
157
185
|
!collection &&
|
|
158
186
|
!unchecked.length &&
|
|
159
187
|
!findings.length &&
|
|
160
|
-
emptyBase === undefined
|
|
188
|
+
emptyBase === undefined &&
|
|
189
|
+
report.items.size > 0 &&
|
|
190
|
+
[...report.items.values()].every((item) => item.treatment === "judged")
|
|
161
191
|
? {
|
|
162
192
|
lines: [
|
|
163
193
|
{
|
|
@@ -171,7 +201,10 @@ export async function runDocsCheck(
|
|
|
171
201
|
yield: {
|
|
172
202
|
calls: judgments.reduce((n, j) => n + (j.calls ?? 0), 0),
|
|
173
203
|
questions: judgments.reduce((n, j) => n + (j.questions ?? 0), 0),
|
|
174
|
-
costUsd:
|
|
204
|
+
costUsd:
|
|
205
|
+
judgments.length && judgments.every((j) => j.usage !== undefined)
|
|
206
|
+
? judgments.reduce((n, j) => n + (j.usage?.costUsd ?? 0), 0)
|
|
207
|
+
: undefined,
|
|
175
208
|
cacheHits: judgments.reduce((n, j) => n + (j.cacheHits ?? 0), 0),
|
|
176
209
|
cacheRequests: judgments.reduce(
|
|
177
210
|
(n, j) => n + (j.cacheRequests ?? 0),
|
|
@@ -180,6 +213,41 @@ export async function runDocsCheck(
|
|
|
180
213
|
elapsedMs: performance.now() - started,
|
|
181
214
|
},
|
|
182
215
|
});
|
|
216
|
+
report.diagnose(
|
|
217
|
+
"collection_omitted",
|
|
218
|
+
"Existing documentation sentences only; missing documentation is not exhaustively detected (measured 2/45 obligations across 180 partial commits).",
|
|
219
|
+
undefined,
|
|
220
|
+
[],
|
|
221
|
+
false,
|
|
222
|
+
);
|
|
223
|
+
if (emptyBase !== undefined)
|
|
224
|
+
report.diagnose(
|
|
225
|
+
"no_changed_units",
|
|
226
|
+
`No changed units against ${emptyBase}`,
|
|
227
|
+
emptyBase,
|
|
228
|
+
[],
|
|
229
|
+
false,
|
|
230
|
+
);
|
|
231
|
+
if (!refusal && emptyBase === undefined && !report.items.size)
|
|
232
|
+
report.diagnose(
|
|
233
|
+
"collection_empty",
|
|
234
|
+
"No matching documentation sections were collected; this does not establish documentation completeness.",
|
|
235
|
+
undefined,
|
|
236
|
+
[],
|
|
237
|
+
false,
|
|
238
|
+
);
|
|
239
|
+
if (refusal) {
|
|
240
|
+
report.refusal =
|
|
241
|
+
cause === "invalid_base" ||
|
|
242
|
+
cause === "invalid_root" ||
|
|
243
|
+
cause === "git_failure";
|
|
244
|
+
report.diagnose(cause, refusal);
|
|
245
|
+
}
|
|
246
|
+
const result = report.build(
|
|
247
|
+
"jev_check_diff",
|
|
248
|
+
evidenceContext,
|
|
249
|
+
reportMetrics(envelope),
|
|
250
|
+
);
|
|
183
251
|
return {
|
|
184
252
|
ok: !refusal,
|
|
185
253
|
status: timeout?.aborted
|
|
@@ -192,14 +260,15 @@ export async function runDocsCheck(
|
|
|
192
260
|
envelope,
|
|
193
261
|
judgments,
|
|
194
262
|
findings,
|
|
263
|
+
result,
|
|
195
264
|
...(collection ? { collection } : {}),
|
|
196
265
|
...(unjudged ? { unjudged } : {}),
|
|
197
266
|
};
|
|
198
267
|
};
|
|
199
268
|
const client = deps.client;
|
|
200
|
-
if (!client) return finish(NOT_CONFIGURED);
|
|
269
|
+
if (!client) return finish(NOT_CONFIGURED, "not_configured");
|
|
201
270
|
const sessionRefusal = deps.runtime.session.refusal();
|
|
202
|
-
if (sessionRefusal) return finish(sessionRefusal);
|
|
271
|
+
if (sessionRefusal) return finish(sessionRefusal, "session_budget");
|
|
203
272
|
try {
|
|
204
273
|
const comparison = await resolveBase(
|
|
205
274
|
deps.exec,
|
|
@@ -207,8 +276,10 @@ export async function runDocsCheck(
|
|
|
207
276
|
input.base,
|
|
208
277
|
signal,
|
|
209
278
|
);
|
|
210
|
-
if (!comparison.ok)
|
|
279
|
+
if (!comparison.ok)
|
|
280
|
+
return finish(comparison.error, comparison.cause ?? "invalid_base");
|
|
211
281
|
const base = comparison.base;
|
|
282
|
+
evidenceContext.resolvedBase = base;
|
|
212
283
|
const analysis = await createAnalysisContext();
|
|
213
284
|
const [collected, inventory] = await Promise.all([
|
|
214
285
|
collectUnits(
|
|
@@ -218,15 +289,46 @@ export async function runDocsCheck(
|
|
|
218
289
|
),
|
|
219
290
|
collectDocsInventory(deps.exec, input.cwd, signal),
|
|
220
291
|
]);
|
|
221
|
-
if (!collected.ok)
|
|
222
|
-
|
|
223
|
-
|
|
292
|
+
if (!collected.ok)
|
|
293
|
+
return finish(collected.error, collected.cause ?? "git_failure");
|
|
294
|
+
if (!inventory.ok)
|
|
295
|
+
return finish(inventory.error, inventory.cause ?? "file_unavailable");
|
|
296
|
+
const repositoryRoot = await deps.exec(
|
|
297
|
+
"git",
|
|
298
|
+
["rev-parse", "--show-toplevel"],
|
|
299
|
+
{ cwd: input.cwd, timeout: TIMEOUT_MS, signal },
|
|
300
|
+
);
|
|
301
|
+
if (
|
|
302
|
+
!repositoryRoot.code &&
|
|
303
|
+
!repositoryRoot.killed &&
|
|
304
|
+
evidenceContext.effectiveRoot
|
|
305
|
+
)
|
|
306
|
+
evidenceContext.effectiveRoot.path = repositoryRoot.stdout.trim();
|
|
307
|
+
for (const limit of collected.limits) {
|
|
308
|
+
report.diagnose(
|
|
309
|
+
limit.kind === "secret_pattern"
|
|
310
|
+
? "secret_pattern"
|
|
311
|
+
: "collection_omitted",
|
|
312
|
+
limit.kind,
|
|
313
|
+
limit.file,
|
|
314
|
+
);
|
|
224
315
|
limitations.push({
|
|
225
316
|
fact: `${limit.file} : ${limit.kind}`,
|
|
226
317
|
next: "Read the complete change before concluding.",
|
|
227
318
|
});
|
|
319
|
+
}
|
|
228
320
|
if (!collected.units.length) {
|
|
229
321
|
emptyBase = base;
|
|
322
|
+
report.inventories.push({
|
|
323
|
+
id: "changed-units",
|
|
324
|
+
kind: "units",
|
|
325
|
+
rules: ["Changed source units against resolved base"],
|
|
326
|
+
restrictions: [],
|
|
327
|
+
discovered: known(0),
|
|
328
|
+
considered: known(0),
|
|
329
|
+
scopeRestricted: false,
|
|
330
|
+
criteria: [],
|
|
331
|
+
});
|
|
230
332
|
return finish();
|
|
231
333
|
}
|
|
232
334
|
const collectDeadline = performance.now() + DOCS_COLLECT_BUDGET_MS;
|
|
@@ -243,6 +345,65 @@ export async function runDocsCheck(
|
|
|
243
345
|
performance.now() >= collectDeadline || !!signal?.aborted,
|
|
244
346
|
},
|
|
245
347
|
);
|
|
348
|
+
report.inventories.push({
|
|
349
|
+
id: "docs-sections",
|
|
350
|
+
kind: "sections",
|
|
351
|
+
rules: [
|
|
352
|
+
"Tracked Markdown sections referring to changed declarations or static import closure",
|
|
353
|
+
`At most ${DOCS_MAX_SECTIONS} admitted sections`,
|
|
354
|
+
],
|
|
355
|
+
restrictions: [],
|
|
356
|
+
discovered: known(
|
|
357
|
+
candidates.candidates.length + candidates.omitted.length,
|
|
358
|
+
),
|
|
359
|
+
considered: known(candidates.candidates.length),
|
|
360
|
+
scopeRestricted: false,
|
|
361
|
+
criteria: [],
|
|
362
|
+
});
|
|
363
|
+
for (const candidate of candidates.candidates)
|
|
364
|
+
report.expect(
|
|
365
|
+
`docs:${candidate.path}:${candidate.start}`,
|
|
366
|
+
`${candidate.path} § ${candidate.heading}`,
|
|
367
|
+
"section",
|
|
368
|
+
);
|
|
369
|
+
for (const candidate of candidates.omitted) {
|
|
370
|
+
const id = `docs:${candidate.path}:${candidate.start}`;
|
|
371
|
+
report.expect(id, `${candidate.path} § ${candidate.heading}`, "section");
|
|
372
|
+
report.diagnose(
|
|
373
|
+
"collection_omitted",
|
|
374
|
+
"Section exceeds DOCS_MAX_SECTIONS",
|
|
375
|
+
candidate.path,
|
|
376
|
+
[id],
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
for (const limit of candidates.limits) {
|
|
380
|
+
if (limit.kind === "collection_budget") {
|
|
381
|
+
report.missingWork = true;
|
|
382
|
+
report.diagnose(
|
|
383
|
+
"collection_omitted",
|
|
384
|
+
limit.reason,
|
|
385
|
+
limit.path,
|
|
386
|
+
[],
|
|
387
|
+
true,
|
|
388
|
+
[...(limit.sections ?? [])],
|
|
389
|
+
);
|
|
390
|
+
} else
|
|
391
|
+
report.diagnose(
|
|
392
|
+
"dynamic_dependency",
|
|
393
|
+
limit.reason,
|
|
394
|
+
limit.path,
|
|
395
|
+
[],
|
|
396
|
+
false,
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
for (const limit of inventory.limits)
|
|
400
|
+
report.diagnose(
|
|
401
|
+
limit.cause === "secret_pattern"
|
|
402
|
+
? "secret_pattern"
|
|
403
|
+
: "collection_omitted",
|
|
404
|
+
limit.reason,
|
|
405
|
+
limit.path,
|
|
406
|
+
);
|
|
246
407
|
for (const limit of inventory.limits)
|
|
247
408
|
limitations.push({
|
|
248
409
|
fact: `${limit.path} : ${limit.reason}`,
|
|
@@ -290,61 +451,101 @@ export async function runDocsCheck(
|
|
|
290
451
|
await Promise.all(
|
|
291
452
|
candidates.candidates.map(async (candidate) => {
|
|
292
453
|
const label = `${candidate.path} § ${candidate.heading}`;
|
|
454
|
+
const reportId = `docs:${candidate.path}:${candidate.start}`;
|
|
293
455
|
if (
|
|
294
456
|
candidate.units.some(
|
|
295
457
|
(unit) => unit.before === null && unit.after === null,
|
|
296
458
|
)
|
|
297
459
|
) {
|
|
298
460
|
unchecked.push(`${label} (changed source unavailable)`);
|
|
461
|
+
report.diagnose(
|
|
462
|
+
"binary_or_non_utf8",
|
|
463
|
+
"Changed source unavailable",
|
|
464
|
+
label,
|
|
465
|
+
[reportId],
|
|
466
|
+
);
|
|
299
467
|
return;
|
|
300
468
|
}
|
|
301
469
|
if (budget?.kind === "session") {
|
|
302
470
|
unchecked.push(`${label} (${budget.message})`);
|
|
471
|
+
report.diagnose("session_budget", budget.message, label, [reportId]);
|
|
303
472
|
return;
|
|
304
473
|
}
|
|
305
474
|
const prepared = prepareDocsCheck(candidate);
|
|
475
|
+
const state = withEvidenceContext(prepared.state, evidenceContext);
|
|
306
476
|
if (
|
|
307
|
-
JSON.stringify(
|
|
477
|
+
JSON.stringify(state).length > STATE_MAX_CHARS ||
|
|
308
478
|
candidate.sentences.length + 1 > CHOICE_MAX_OPTIONS
|
|
309
479
|
) {
|
|
310
480
|
unchecked.push(`${label} (state or pointer too large)`);
|
|
481
|
+
report.diagnose(
|
|
482
|
+
"evidence_too_large",
|
|
483
|
+
"Section state or sentence pointer exceeds limits",
|
|
484
|
+
label,
|
|
485
|
+
[reportId],
|
|
486
|
+
);
|
|
311
487
|
return;
|
|
312
488
|
}
|
|
313
489
|
if (signal?.aborted) {
|
|
314
490
|
unchecked.push(`${label} (budget exceeded or canceled)`);
|
|
491
|
+
report.diagnose(
|
|
492
|
+
"cancelled",
|
|
493
|
+
"Collection budget exceeded or check canceled",
|
|
494
|
+
label,
|
|
495
|
+
[reportId],
|
|
496
|
+
);
|
|
315
497
|
return;
|
|
316
498
|
}
|
|
317
|
-
const judgment = await client.judge(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
},
|
|
344
|
-
onUsage: (usage) => deps.runtime.session.recordUsage(usage),
|
|
499
|
+
const judgment = await client.judge(state, prepared.questions, {
|
|
500
|
+
signal,
|
|
501
|
+
groups: [["status", "sentence"]],
|
|
502
|
+
...deps.runtime.session.requestGate(),
|
|
503
|
+
admissionCause: () =>
|
|
504
|
+
budget?.kind === "session" ? "session_budget" : "call_budget",
|
|
505
|
+
beforeRequest(questionCount) {
|
|
506
|
+
if (budget?.kind === "session")
|
|
507
|
+
return { ok: false, error: budget.message };
|
|
508
|
+
if (signal?.aborted)
|
|
509
|
+
return {
|
|
510
|
+
ok: false,
|
|
511
|
+
error: "Budget exceeded or call canceled.",
|
|
512
|
+
};
|
|
513
|
+
if (input.maxCalls !== undefined && sent >= input.maxCalls) {
|
|
514
|
+
budget = {
|
|
515
|
+
kind: "max_calls",
|
|
516
|
+
message: `max_calls=${input.maxCalls} reached`,
|
|
517
|
+
};
|
|
518
|
+
return { ok: false, error: budget.message };
|
|
519
|
+
}
|
|
520
|
+
const admitted = deps.runtime.session.admit(questionCount);
|
|
521
|
+
if (!admitted.ok)
|
|
522
|
+
budget = { kind: "session", message: admitted.error };
|
|
523
|
+
else sent++;
|
|
524
|
+
return admitted;
|
|
345
525
|
},
|
|
346
|
-
|
|
526
|
+
onUsage: (usage) => deps.runtime.session.recordUsage(usage),
|
|
527
|
+
});
|
|
347
528
|
judgments.push(judgment);
|
|
529
|
+
if (!judgment.ok) report.failure(judgment, [reportId]);
|
|
530
|
+
else {
|
|
531
|
+
const status = judgment.answers.status;
|
|
532
|
+
const pointer = judgment.answers.sentence;
|
|
533
|
+
const finding = readDocsJudgment(candidate, judgment.answers);
|
|
534
|
+
const item = report.items.get(reportId);
|
|
535
|
+
if (finding && item)
|
|
536
|
+
item.label = `${label} — ${finding.sentence ? JSON.stringify(finding.sentence.text) : "sentence not identified"} — after ${finding.units.map((unit) => `${unit.name} (${unit.file})`).join(", ")}`;
|
|
537
|
+
report.answer(
|
|
538
|
+
reportId,
|
|
539
|
+
status,
|
|
540
|
+
{ band: finding?.band ?? "verdict", reason: finding?.reason },
|
|
541
|
+
[
|
|
542
|
+
pointer ?? {
|
|
543
|
+
type: "unjudged",
|
|
544
|
+
reason: "Required sentence pointer missing",
|
|
545
|
+
},
|
|
546
|
+
],
|
|
547
|
+
);
|
|
548
|
+
}
|
|
348
549
|
if (!judgment.ok) {
|
|
349
550
|
unchecked.push(`${label} (${judgment.error})`);
|
|
350
551
|
return;
|
|
@@ -394,6 +595,7 @@ export async function runDocsCheck(
|
|
|
394
595
|
if (signal?.aborted)
|
|
395
596
|
return finish(
|
|
396
597
|
timeout?.aborted ? "Docs budget exceeded." : "Docs check canceled.",
|
|
598
|
+
"cancelled",
|
|
397
599
|
);
|
|
398
600
|
throw error;
|
|
399
601
|
}
|