blun-king-cli 9.1.451 → 9.1.452
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.
|
@@ -25,7 +25,7 @@ const PROBLEM_FRAME_KEYS = new Set([
|
|
|
25
25
|
const NEXT_TRIGGER_KEYS = new Set(['kind', 'condition', 'dueAt']);
|
|
26
26
|
const EVIDENCE_INPUT_KEYS = new Set([
|
|
27
27
|
'turnId', 'toolCallId', 'toolName', 'decision', 'outcome', 'durationMs', 'toolArgs',
|
|
28
|
-
'resultEvidenceKinds',
|
|
28
|
+
'resultEvidenceKinds', 'resultEvidenceScopes',
|
|
29
29
|
]);
|
|
30
30
|
const REQUIRED_EVIDENCE_INPUT_KEYS = new Set([
|
|
31
31
|
'turnId', 'toolCallId', 'toolName', 'decision', 'outcome', 'durationMs',
|
|
@@ -51,6 +51,7 @@ const INTEGRITY_COMMAND = /(?:^|(?:&&|\|\||;|\s))(?:(?:git\s+(?:diff(?:\s+--chec
|
|
|
51
51
|
const SYNTAX_COMMAND = /(?:^|(?:&&|\|\||;|\s))(?:(?:node\s+--check\b)|(?:(?:npx\s+)?tsc\b)|(?:(?:npm|pnpm|yarn)\s+(?:(?:run\s+)?typecheck)\b))/iu;
|
|
52
52
|
const TEST_COMMAND = /(?:^|(?:&&|\|\||;|\s))(?:(?:node\s+--test\b)|(?:node\s+(?!--)[^\s;&|]*(?:check|test|verify|validate|lint|gate|probe)[^\s;&|]*\b)|(?:(?:npm|pnpm|yarn)\s+(?:test|(?:run\s+)?(?:test|lint|check|build))\b)|(?:python(?:3)?\s+-m\s+pytest\b)|(?:pytest\b)|(?:go\s+test\b)|(?:cargo\s+test\b)|(?:dotnet\s+test\b)|(?:(?:npx\s+)?(?:eslint|biome\s+check)\b))/iu;
|
|
53
53
|
const RUNTIME_EVIDENCE_COMMAND = /(?:^|(?:&&|\|\||;|\s))(?:node\s+(?!--check\b)(?:-e\b|[^\s;&|]+)|(?:python(?:3)?\s+(?!-m\s+pytest\b)[^\s;&|]+)|(?:npm|pnpm|yarn)\s+(?:test|run\b)|pytest\b|go\s+test\b|cargo\s+test\b|dotnet\s+test\b)/iu;
|
|
54
|
+
const EVIDENCE_SCOPE_MARKER = /(?:^|\s)BLUN_EVIDENCE_SCOPE=([A-Za-z0-9._:/\\-]{1,256})(?=\s|$)/gu;
|
|
54
55
|
const MAX_SUCCESSFUL_TOOL_DIGESTS = 32;
|
|
55
56
|
|
|
56
57
|
function bounded(value, field, max = 512) {
|
|
@@ -199,6 +200,22 @@ function successfulVerificationCallDigest(turnId, toolCallId, toolName, kind) {
|
|
|
199
200
|
.slice(0, 16);
|
|
200
201
|
}
|
|
201
202
|
|
|
203
|
+
function normalizedVerificationScope(value, field = 'verificationProof scope') {
|
|
204
|
+
return bounded(value, field, 256);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function successfulVerificationScopeDigest(turnId, toolCallId, toolName, kind, scope) {
|
|
208
|
+
const turn = normalizedTurnId(turnId);
|
|
209
|
+
const callId = bounded(toolCallId, 'verificationProof toolCallId', 256);
|
|
210
|
+
const name = bounded(toolName, 'verificationProof toolName', 128);
|
|
211
|
+
const normalizedKind = normalizedVerificationKind(kind);
|
|
212
|
+
const normalizedScope = normalizedVerificationScope(scope);
|
|
213
|
+
return crypto.createHash('sha256')
|
|
214
|
+
.update(`turn:${turn}\0call:${callId}\0tool:${name}\0kind:${normalizedKind}\0scope:${normalizedScope}`)
|
|
215
|
+
.digest('hex')
|
|
216
|
+
.slice(0, 16);
|
|
217
|
+
}
|
|
218
|
+
|
|
202
219
|
function isActionOnlyTool(toolName) {
|
|
203
220
|
return ACTION_ONLY_TOOL_NAMES.has(String(toolName ?? '').trim());
|
|
204
221
|
}
|
|
@@ -209,6 +226,43 @@ function verificationCommand(toolArgs) {
|
|
|
209
226
|
return typeof command === 'string' ? command.trim().replace(/\s+/gu, ' ') : '';
|
|
210
227
|
}
|
|
211
228
|
|
|
229
|
+
function toolArgumentScope(toolName, toolArgs) {
|
|
230
|
+
if (!toolArgs || typeof toolArgs !== 'object' || Array.isArray(toolArgs)) return '';
|
|
231
|
+
const name = String(toolName ?? '').trim().toLowerCase();
|
|
232
|
+
const first = (...keys) => {
|
|
233
|
+
for (const key of keys) {
|
|
234
|
+
if (typeof toolArgs[key] === 'string' && toolArgs[key].trim().length > 0) {
|
|
235
|
+
return normalizedVerificationScope(toolArgs[key], 'verification target scope');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return '';
|
|
239
|
+
};
|
|
240
|
+
if (['read', 'readmediafile', 'understandimage', 'understandvideo'].includes(name)) {
|
|
241
|
+
return first('file_path', 'path', 'image_path', 'video_path');
|
|
242
|
+
}
|
|
243
|
+
if (name === 'getmedia') return first('media_id', 'id', 'path');
|
|
244
|
+
if (name === 'taskoutput') return first('task_id', 'id');
|
|
245
|
+
if (name === 'fetchurl') return first('url', 'uri');
|
|
246
|
+
if (name === 'websearch') return first('query', 'q');
|
|
247
|
+
if (name === 'grep' || name === 'glob' || name === 'codebasesearch') {
|
|
248
|
+
return first('path', 'cwd', 'directory', 'root', 'query', 'pattern');
|
|
249
|
+
}
|
|
250
|
+
if (name === 'getgoal') return 'runtime:active-goal';
|
|
251
|
+
if (name === 'cronlist') return 'runtime:cron-jobs';
|
|
252
|
+
return '';
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function commandEvidenceScopes(toolName, toolArgs, providedScopes) {
|
|
256
|
+
const normalizedName = String(toolName ?? '').trim().toLowerCase();
|
|
257
|
+
if (!COMMAND_TOOL_NAMES.has(normalizedName)) return Object.freeze([]);
|
|
258
|
+
const command = verificationCommand(toolArgs);
|
|
259
|
+
if (command.length < 1 || MUTATING_COMMAND.test(command)) return Object.freeze([]);
|
|
260
|
+
const declared = new Set();
|
|
261
|
+
EVIDENCE_SCOPE_MARKER.lastIndex = 0;
|
|
262
|
+
for (const match of command.matchAll(EVIDENCE_SCOPE_MARKER)) declared.add(match[1]);
|
|
263
|
+
return Object.freeze(providedScopes.filter((scope) => declared.has(scope)));
|
|
264
|
+
}
|
|
265
|
+
|
|
212
266
|
function verificationKindsForToolCall(toolName, toolArgs) {
|
|
213
267
|
const normalizedName = String(toolName ?? '').trim().toLowerCase();
|
|
214
268
|
if (INSPECTION_TOOL_NAMES.has(normalizedName)) return Object.freeze(['inspection']);
|
|
@@ -250,6 +304,17 @@ function normalizedResultEvidenceKinds(value) {
|
|
|
250
304
|
return Object.freeze(kinds);
|
|
251
305
|
}
|
|
252
306
|
|
|
307
|
+
function normalizedResultEvidenceScopes(value) {
|
|
308
|
+
if (value === undefined) return Object.freeze([]);
|
|
309
|
+
const scopes = Array.isArray(value)
|
|
310
|
+
? value.map((item, index) => normalizedVerificationScope(item, `resultEvidenceScopes[${index}]`))
|
|
311
|
+
: [];
|
|
312
|
+
if (!Array.isArray(value) || value.length > 5 || new Set(scopes).size !== scopes.length) {
|
|
313
|
+
throw new TypeError('result evidence scopes are invalid');
|
|
314
|
+
}
|
|
315
|
+
return Object.freeze(scopes);
|
|
316
|
+
}
|
|
317
|
+
|
|
253
318
|
function normalizeSuccessfulToolDigests(value) {
|
|
254
319
|
if (value === undefined) return Object.freeze([]);
|
|
255
320
|
if (!Array.isArray(value) || value.length > MAX_SUCCESSFUL_TOOL_DIGESTS
|
|
@@ -262,13 +327,15 @@ function normalizeSuccessfulToolDigests(value) {
|
|
|
262
327
|
|
|
263
328
|
function normalizeExactVerificationCall(input, receipt, label, options = {}) {
|
|
264
329
|
const requireKind = options.requireKind === true;
|
|
265
|
-
const
|
|
330
|
+
const requireScope = options.requireScope === true;
|
|
331
|
+
const expectedKeys = 3 + (requireKind ? 1 : 0) + (requireScope ? 1 : 0);
|
|
266
332
|
if (!input || typeof input !== 'object' || Array.isArray(input)
|
|
267
333
|
|| Object.keys(input).length !== expectedKeys
|
|
268
334
|
|| !Object.hasOwn(input, 'toolCallId')
|
|
269
335
|
|| !Object.hasOwn(input, 'toolName')
|
|
270
336
|
|| !Object.hasOwn(input, 'claim')
|
|
271
|
-
|| requireKind !== Object.hasOwn(input, 'kind')
|
|
337
|
+
|| requireKind !== Object.hasOwn(input, 'kind')
|
|
338
|
+
|| requireScope !== Object.hasOwn(input, 'scope')) {
|
|
272
339
|
throw new TypeError(`${label} fields are invalid`);
|
|
273
340
|
}
|
|
274
341
|
const toolCallId = bounded(input.toolCallId, `${label} toolCallId`, 256);
|
|
@@ -288,6 +355,16 @@ function normalizeExactVerificationCall(input, receipt, label, options = {}) {
|
|
|
288
355
|
if (!receipt.successfulVerificationCallDigests.includes(typedDigest)) {
|
|
289
356
|
throw new TypeError(`${label} kind must match the successful current-turn verification call`);
|
|
290
357
|
}
|
|
358
|
+
if (requireScope) {
|
|
359
|
+
const scope = normalizedVerificationScope(input.scope, `${label} scope`);
|
|
360
|
+
const scopeDigest = successfulVerificationScopeDigest(
|
|
361
|
+
receipt.turnId, toolCallId, toolName, kind, scope,
|
|
362
|
+
);
|
|
363
|
+
if (!receipt.successfulVerificationScopeDigests.includes(scopeDigest)) {
|
|
364
|
+
throw new TypeError(`${label} scope must match the successful current-turn verification call target`);
|
|
365
|
+
}
|
|
366
|
+
return Object.freeze({ toolCallId, toolName, kind, scope, claim });
|
|
367
|
+
}
|
|
291
368
|
return Object.freeze({ toolCallId, toolName, kind, claim });
|
|
292
369
|
}
|
|
293
370
|
return Object.freeze({ toolCallId, toolName, claim });
|
|
@@ -320,20 +397,38 @@ function normalizeVerificationProof(input, evidenceReceipt, options = {}) {
|
|
|
320
397
|
&& Object.hasOwn(input, 'toolName')
|
|
321
398
|
&& Object.hasOwn(input, 'claim')
|
|
322
399
|
&& keys.every((key) => ['subject', 'toolCallId', 'toolName', 'claim', 'sharpnessProof'].includes(key));
|
|
323
|
-
const
|
|
400
|
+
const legacyTypedSubjectResult = options.allowLegacy === true
|
|
401
|
+
&& subject === 'result'
|
|
324
402
|
&& keys.length === 5
|
|
325
403
|
&& Object.hasOwn(input, 'toolCallId')
|
|
326
404
|
&& Object.hasOwn(input, 'toolName')
|
|
327
405
|
&& Object.hasOwn(input, 'kind')
|
|
328
406
|
&& Object.hasOwn(input, 'claim');
|
|
329
|
-
const
|
|
407
|
+
const legacyTypedSubjectVerifier = options.allowLegacy === true
|
|
408
|
+
&& subject === 'verifier'
|
|
330
409
|
&& (keys.length === 5 || keys.length === 6)
|
|
331
410
|
&& Object.hasOwn(input, 'toolCallId')
|
|
332
411
|
&& Object.hasOwn(input, 'toolName')
|
|
333
412
|
&& Object.hasOwn(input, 'kind')
|
|
334
413
|
&& Object.hasOwn(input, 'claim')
|
|
335
414
|
&& keys.every((key) => ['subject', 'toolCallId', 'toolName', 'kind', 'claim', 'sharpnessProof'].includes(key));
|
|
415
|
+
const currentResult = subject === 'result'
|
|
416
|
+
&& keys.length === 6
|
|
417
|
+
&& Object.hasOwn(input, 'toolCallId')
|
|
418
|
+
&& Object.hasOwn(input, 'toolName')
|
|
419
|
+
&& Object.hasOwn(input, 'kind')
|
|
420
|
+
&& Object.hasOwn(input, 'scope')
|
|
421
|
+
&& Object.hasOwn(input, 'claim');
|
|
422
|
+
const currentVerifier = subject === 'verifier'
|
|
423
|
+
&& (keys.length === 6 || keys.length === 7)
|
|
424
|
+
&& Object.hasOwn(input, 'toolCallId')
|
|
425
|
+
&& Object.hasOwn(input, 'toolName')
|
|
426
|
+
&& Object.hasOwn(input, 'kind')
|
|
427
|
+
&& Object.hasOwn(input, 'scope')
|
|
428
|
+
&& Object.hasOwn(input, 'claim')
|
|
429
|
+
&& keys.every((key) => ['subject', 'toolCallId', 'toolName', 'kind', 'scope', 'claim', 'sharpnessProof'].includes(key));
|
|
336
430
|
if (!legacyName && !legacyExact && !legacySubjectResult && !legacySubjectVerifier
|
|
431
|
+
&& !legacyTypedSubjectResult && !legacyTypedSubjectVerifier
|
|
337
432
|
&& !currentResult && !currentVerifier) {
|
|
338
433
|
throw new TypeError('verificationProof fields are invalid');
|
|
339
434
|
}
|
|
@@ -350,12 +445,17 @@ function normalizeVerificationProof(input, evidenceReceipt, options = {}) {
|
|
|
350
445
|
return Object.freeze({ toolName, claim });
|
|
351
446
|
}
|
|
352
447
|
const legacySubject = legacySubjectResult || legacySubjectVerifier;
|
|
448
|
+
const legacyTypedSubject = legacyTypedSubjectResult || legacyTypedSubjectVerifier;
|
|
353
449
|
const primary = normalizeExactVerificationCall(legacyExact ? input : {
|
|
354
450
|
toolCallId: input.toolCallId,
|
|
355
451
|
toolName: input.toolName,
|
|
356
452
|
...(legacySubject ? {} : { kind: input.kind }),
|
|
453
|
+
...(currentResult || currentVerifier ? { scope: input.scope } : {}),
|
|
357
454
|
claim: input.claim,
|
|
358
|
-
}, receipt, 'verificationProof', {
|
|
455
|
+
}, receipt, 'verificationProof', {
|
|
456
|
+
requireKind: !legacyExact && !legacySubject,
|
|
457
|
+
requireScope: currentResult || currentVerifier,
|
|
458
|
+
});
|
|
359
459
|
if (legacyExact) return primary;
|
|
360
460
|
if (!VERIFICATION_SUBJECTS.has(subject)) throw new TypeError('verificationProof subject is invalid');
|
|
361
461
|
if (subject === 'result') return Object.freeze({ subject, ...primary });
|
|
@@ -364,6 +464,7 @@ function normalizeVerificationProof(input, evidenceReceipt, options = {}) {
|
|
|
364
464
|
}
|
|
365
465
|
const sharpnessProof = normalizeExactVerificationCall(input.sharpnessProof, receipt, 'sharpnessProof', {
|
|
366
466
|
requireKind: !legacySubject,
|
|
467
|
+
requireScope: !legacySubject && !legacyTypedSubject,
|
|
367
468
|
});
|
|
368
469
|
if (sharpnessProof.toolCallId === primary.toolCallId
|
|
369
470
|
&& sharpnessProof.toolName === primary.toolName) {
|
|
@@ -382,6 +483,7 @@ function emptyActionEvidenceReceipt(turnId) {
|
|
|
382
483
|
successfulToolDigests: Object.freeze([]),
|
|
383
484
|
successfulToolCallDigests: Object.freeze([]),
|
|
384
485
|
successfulVerificationCallDigests: Object.freeze([]),
|
|
486
|
+
successfulVerificationScopeDigests: Object.freeze([]),
|
|
385
487
|
digest: crypto.createHash('sha256').update(`turn:${normalized}:empty`).digest('hex').slice(0, 16),
|
|
386
488
|
});
|
|
387
489
|
}
|
|
@@ -391,7 +493,7 @@ function normalizeActionEvidenceReceipt(input) {
|
|
|
391
493
|
const requiredKeys = new Set(['turnId', 'completedTools', 'successfulTools', 'failedTools', 'digest']);
|
|
392
494
|
const allowedKeys = new Set([
|
|
393
495
|
...requiredKeys, 'successfulToolDigests', 'successfulToolCallDigests',
|
|
394
|
-
'successfulVerificationCallDigests',
|
|
496
|
+
'successfulVerificationCallDigests', 'successfulVerificationScopeDigests',
|
|
395
497
|
]);
|
|
396
498
|
if (!Object.keys(input).every((key) => allowedKeys.has(key))
|
|
397
499
|
|| ![...requiredKeys].every((key) => Object.hasOwn(input, key))) {
|
|
@@ -407,6 +509,9 @@ function normalizeActionEvidenceReceipt(input) {
|
|
|
407
509
|
successfulVerificationCallDigests: normalizeSuccessfulToolDigests(
|
|
408
510
|
input.successfulVerificationCallDigests,
|
|
409
511
|
),
|
|
512
|
+
successfulVerificationScopeDigests: normalizeSuccessfulToolDigests(
|
|
513
|
+
input.successfulVerificationScopeDigests,
|
|
514
|
+
),
|
|
410
515
|
digest: String(input.digest ?? ''),
|
|
411
516
|
};
|
|
412
517
|
if (![receipt.completedTools, receipt.successfulTools, receipt.failedTools]
|
|
@@ -440,6 +545,7 @@ function advanceActionEvidenceReceipt(current, input) {
|
|
|
440
545
|
const successfulToolDigests = [...prior.successfulToolDigests];
|
|
441
546
|
const successfulToolCallDigests = [...prior.successfulToolCallDigests];
|
|
442
547
|
const successfulVerificationCallDigests = [...prior.successfulVerificationCallDigests];
|
|
548
|
+
const successfulVerificationScopeDigests = [...prior.successfulVerificationScopeDigests];
|
|
443
549
|
const toolDigest = successfulToolDigest(toolName);
|
|
444
550
|
if (successful && !successfulToolDigests.includes(toolDigest)) {
|
|
445
551
|
successfulToolDigests.push(toolDigest);
|
|
@@ -452,6 +558,15 @@ function advanceActionEvidenceReceipt(current, input) {
|
|
|
452
558
|
const verificationKinds = successful
|
|
453
559
|
? [...new Set([...verificationKindsForToolCall(toolName, input.toolArgs), ...explicitResultKinds])]
|
|
454
560
|
: [];
|
|
561
|
+
const argumentScope = successful ? toolArgumentScope(toolName, input.toolArgs) : '';
|
|
562
|
+
const providedResultScopes = normalizedResultEvidenceScopes(input.resultEvidenceScopes);
|
|
563
|
+
const explicitResultScopes = successful
|
|
564
|
+
? commandEvidenceScopes(toolName, input.toolArgs, providedResultScopes)
|
|
565
|
+
: [];
|
|
566
|
+
const verificationScopes = [...new Set([
|
|
567
|
+
...(argumentScope ? [argumentScope] : []),
|
|
568
|
+
...explicitResultScopes,
|
|
569
|
+
])];
|
|
455
570
|
const verificationCall = verificationKinds.length > 0;
|
|
456
571
|
if (verificationCall) {
|
|
457
572
|
const callDigest = successfulToolCallDigest(turnId, toolCallId, toolName);
|
|
@@ -465,11 +580,22 @@ function advanceActionEvidenceReceipt(current, input) {
|
|
|
465
580
|
if (successfulVerificationCallDigests.length > MAX_SUCCESSFUL_TOOL_DIGESTS) {
|
|
466
581
|
successfulVerificationCallDigests.shift();
|
|
467
582
|
}
|
|
583
|
+
for (const scope of verificationScopes) {
|
|
584
|
+
const scopeDigest = successfulVerificationScopeDigest(
|
|
585
|
+
turnId, toolCallId, toolName, kind, scope,
|
|
586
|
+
);
|
|
587
|
+
if (!successfulVerificationScopeDigests.includes(scopeDigest)) {
|
|
588
|
+
successfulVerificationScopeDigests.push(scopeDigest);
|
|
589
|
+
}
|
|
590
|
+
if (successfulVerificationScopeDigests.length > MAX_SUCCESSFUL_TOOL_DIGESTS) {
|
|
591
|
+
successfulVerificationScopeDigests.shift();
|
|
592
|
+
}
|
|
593
|
+
}
|
|
468
594
|
}
|
|
469
595
|
}
|
|
470
596
|
const digest = crypto.createHash('sha256').update([
|
|
471
597
|
prior.digest, String(turnId), toolCallId, toolName, decision, outcome, String(durationMs),
|
|
472
|
-
verificationKinds.join(','),
|
|
598
|
+
verificationKinds.join(','), verificationScopes.join(','),
|
|
473
599
|
].join('\0')).digest('hex').slice(0, 16);
|
|
474
600
|
return Object.freeze({
|
|
475
601
|
turnId,
|
|
@@ -479,6 +605,7 @@ function advanceActionEvidenceReceipt(current, input) {
|
|
|
479
605
|
successfulToolDigests: Object.freeze(successfulToolDigests),
|
|
480
606
|
successfulToolCallDigests: Object.freeze(successfulToolCallDigests),
|
|
481
607
|
successfulVerificationCallDigests: Object.freeze(successfulVerificationCallDigests),
|
|
608
|
+
successfulVerificationScopeDigests: Object.freeze(successfulVerificationScopeDigests),
|
|
482
609
|
digest,
|
|
483
610
|
});
|
|
484
611
|
}
|
|
@@ -598,11 +725,15 @@ function projectActionCheckpoint(checkpoint) {
|
|
|
598
725
|
const kind = value.verificationProof.kind === undefined
|
|
599
726
|
? ''
|
|
600
727
|
: ` [${value.verificationProof.kind}]`;
|
|
601
|
-
|
|
728
|
+
const scope = value.verificationProof.scope === undefined
|
|
729
|
+
? ''
|
|
730
|
+
: ` [scope: ${value.verificationProof.scope}]`;
|
|
731
|
+
lines.push(`Verification proof${subject}${kind}${scope}: ${call} - ${value.verificationProof.claim}`);
|
|
602
732
|
if (value.verificationProof.sharpnessProof !== undefined) {
|
|
603
733
|
const sharpness = value.verificationProof.sharpnessProof;
|
|
604
734
|
const sharpnessKind = sharpness.kind === undefined ? '' : ` [${sharpness.kind}]`;
|
|
605
|
-
|
|
735
|
+
const sharpnessScope = sharpness.scope === undefined ? '' : ` [scope: ${sharpness.scope}]`;
|
|
736
|
+
lines.push(`Sharpness proof${sharpnessKind}${sharpnessScope}: ${sharpness.toolName} call ${sharpness.toolCallId} - ${sharpness.claim}`);
|
|
606
737
|
}
|
|
607
738
|
}
|
|
608
739
|
if (value.nextTrigger !== undefined) {
|
|
@@ -34,6 +34,10 @@ function verificationProofGaps(checkpoint) {
|
|
|
34
34
|
.test(String(error?.message ?? ''))) {
|
|
35
35
|
return ['The completion proof kind exceeds what its exact verification call measured.'];
|
|
36
36
|
}
|
|
37
|
+
if (/(?:verificationProof|sharpnessProof) scope must match the successful current-turn verification call target/u
|
|
38
|
+
.test(String(error?.message ?? ''))) {
|
|
39
|
+
return ['Bind the completion proof scope to the exact target measured by its successful current-turn verification call.'];
|
|
40
|
+
}
|
|
37
41
|
if (/action-only tool/u.test(String(error?.message ?? ''))) {
|
|
38
42
|
return ['The completion proof names an action-only tool, not a verification tool.'];
|
|
39
43
|
}
|
package/blun.mjs
CHANGED
|
@@ -260353,11 +260353,13 @@ function createActionCheckpointInputSchema(problemFrameSchema, requireProblemFra
|
|
|
260353
260353
|
toolCallId: string().min(1).max(256),
|
|
260354
260354
|
toolName: string().min(1).max(128),
|
|
260355
260355
|
kind: _enum(["inspection", "integrity", "syntax", "test", "reachability"]),
|
|
260356
|
+
scope: string().min(1).max(256),
|
|
260356
260357
|
claim: string().min(1).max(512),
|
|
260357
260358
|
sharpnessProof: object({
|
|
260358
260359
|
toolCallId: string().min(1).max(256),
|
|
260359
260360
|
toolName: string().min(1).max(128),
|
|
260360
260361
|
kind: _enum(["inspection", "integrity", "syntax", "test", "reachability"]),
|
|
260362
|
+
scope: string().min(1).max(256),
|
|
260361
260363
|
claim: string().min(1).max(512)
|
|
260362
260364
|
}).strict().optional()
|
|
260363
260365
|
}).strict().superRefine((value, ctx) => {
|
|
@@ -261698,6 +261700,13 @@ function explicitToolResultEvidenceKinds(result) {
|
|
|
261698
261700
|
const text = toolResultText(result);
|
|
261699
261701
|
return /(?:^|\s)BLUN_EVIDENCE_KIND=reachability(?:\s|$)/u.test(text) ? ["reachability"] : [];
|
|
261700
261702
|
}
|
|
261703
|
+
function explicitToolResultEvidenceScopes(result) {
|
|
261704
|
+
const text = toolResultText(result);
|
|
261705
|
+
return [...text.matchAll(/(?:^|\s)BLUN_EVIDENCE_SCOPE=([A-Za-z0-9._:/\\-]{1,256})(?=\s|$)/gu)]
|
|
261706
|
+
.map((match) => match[1])
|
|
261707
|
+
.filter((scope, index, scopes) => scopes.indexOf(scope) === index)
|
|
261708
|
+
.slice(0, 5);
|
|
261709
|
+
}
|
|
261701
261710
|
function abandonedToolResultOutput(ended) {
|
|
261702
261711
|
return `Tool call did not complete: ${ended.reason === "cancelled" ? "the turn was cancelled" : ended.reason === "failed" ? `the turn failed${ended.error !== void 0 ? ` (${ended.error.message})` : ""}` : "the turn ended"} before its result was recorded. Do not assume the tool completed successfully.`;
|
|
261703
261712
|
}
|
|
@@ -262801,7 +262810,8 @@ var init_turn = __esmMin((() => {
|
|
|
262801
262810
|
outcome,
|
|
262802
262811
|
durationMs: Date.now() - started.startedAt,
|
|
262803
262812
|
toolArgs: started.args,
|
|
262804
|
-
resultEvidenceKinds: explicitToolResultEvidenceKinds(event.result)
|
|
262813
|
+
resultEvidenceKinds: explicitToolResultEvidenceKinds(event.result),
|
|
262814
|
+
resultEvidenceScopes: explicitToolResultEvidenceScopes(event.result)
|
|
262805
262815
|
});
|
|
262806
262816
|
this.agent.telemetry.track("tool_call", properties);
|
|
262807
262817
|
this.agent.feedRootMissionContract("result", {
|
|
@@ -262908,6 +262918,7 @@ var init_update_goal$1 = __esmMin((() => {
|
|
|
262908
262918
|
update_goal_default = "Update the current autonomous goal. Set `status` only for a lifecycle change. After a coherent work slice, save `actionCheckpoint` with a monotone revision, the last verified result, exact next action, expected evidence, exact `nextTrigger`, and an explicit evidence basis. Persist the exact `nextTrigger` that releases `nextAction`: use `immediate` outside the `wait` phase; while waiting, name the external event, time, dependency, or user decision instead of pretending work can continue. A `time` trigger must include the exact ISO timestamp in `dueAt`; no other trigger kind may include `dueAt`. Use `runtime_tool` only when a successful tool in this turn measured the result; use `user_statement` for a direct user assertion, `external_report` for a report not independently measured here, and `carried_forward` only when the last verified text is unchanged. Classify knowledge as `verified`, `credible_unverified`, `hypothesis`, `uncertain_memory`, `stale`, or `unknown`; never present a weaker state as verified, and preserve the state on carry-forward. Start at revision 1 and increment the currently projected revision by exactly one; stale writers fail closed. This is durable progress state, not permission, and should change only when the facts change. A checkpoint-only call keeps the goal active.\n\n- `active` — resume a paused or blocked goal when the user explicitly asks you to work on that goal.\n- `complete` — the objective is fully satisfied, all files are written, all tests pass, and any stated validation has passed. When the goal has a completion criterion, first save a `verify` checkpoint with `runtime_tool`, `verified`, and a successful runtime evidence receipt.\n- `blocked` — a genuine external condition or required user decision prevents progress.\n- `paused` — set the goal aside for now.\n\nDo not mark complete after a plan or partial result. If useful work remains, checkpoint it and continue. Do not ask for permission merely to execute an already authorized checkpoint; ask only at a real rights boundary or missing user decision.\n";
|
|
262909
262919
|
update_goal_default += "\nBefore completing a goal with a criterion, bind the verified claim to the exact successful current-turn verification call in `verificationProof`, including its `toolCallId`. A write, edit, copy, deploy, or other action is not proof that the changed behavior works, even when it shares a mixed-use tool such as `Bash` with tests. Use `subject: result` for a result, report, measurement, or download. Use `subject: verifier` only when the new or changed test, gate, harness, or detector itself is the completion subject; then bind `sharpnessProof` to a separate successful current-turn counterexample or mutation call. Do not require a red probe for a normal report or measurement.\n";
|
|
262910
262920
|
update_goal_default += "\nSet the proof `kind` to the exact capability of that call: `inspection` reads or searches, `integrity` compares bytes or hashes, `syntax` parses or type-checks, and `test` runs assertions. None of these alone proves a stronger kind. Use `reachability` only for a successful runtime probe that actually invokes the changed path and emits the exact marker `BLUN_EVIDENCE_KIND=reachability` after its assertions; loading a module without reaching the changed path is not reachability.\n";
|
|
262921
|
+
update_goal_default += "\nBind each proof `scope` to the exact target measured by that successful call, never to a free-text claim or intended file. Read and search tools derive scope from their target arguments. For shell or command tools, include the same safe token `BLUN_EVIDENCE_SCOPE=<scope>` in the launched non-mutating verification command and emit it only after that exact target succeeds; the runtime requires both sides.\n";
|
|
262911
262922
|
update_goal_default += "\nFor a non-trivial or unfamiliar problem, preserve `problemFrame` with the success criterion, missing knowledge, bounded candidate actions, selected action and reason, support choice, risk, and reversibility. The selected action must match one candidate. Bind each selected action to the projected durable facts or assumptions it relies on by copying their explicit refs into `decisionBasis`. A stale or unknown decision basis requires replanning before execution. Problem framing is descriptive state and never grants permission.\n";
|
|
262912
262923
|
}));
|
|
262913
262924
|
//#endregion
|