blun-king-cli 9.1.450 → 9.1.451
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.
|
@@ -13,6 +13,7 @@ const TRIGGER_KINDS = new Set([
|
|
|
13
13
|
'immediate', 'external_event', 'time', 'dependency', 'user_decision',
|
|
14
14
|
]);
|
|
15
15
|
const VERIFICATION_SUBJECTS = new Set(['result', 'verifier']);
|
|
16
|
+
const VERIFICATION_KINDS = new Set(['inspection', 'integrity', 'syntax', 'test', 'reachability']);
|
|
16
17
|
const MODEL_KEYS = new Set([
|
|
17
18
|
'revision', 'phase', 'evidenceBasis', 'epistemicState', 'lastVerified', 'nextAction', 'expectedEvidence', 'verificationProof', 'nextTrigger', 'problemFrame', 'updatedAt',
|
|
18
19
|
]);
|
|
@@ -24,6 +25,7 @@ const PROBLEM_FRAME_KEYS = new Set([
|
|
|
24
25
|
const NEXT_TRIGGER_KEYS = new Set(['kind', 'condition', 'dueAt']);
|
|
25
26
|
const EVIDENCE_INPUT_KEYS = new Set([
|
|
26
27
|
'turnId', 'toolCallId', 'toolName', 'decision', 'outcome', 'durationMs', 'toolArgs',
|
|
28
|
+
'resultEvidenceKinds',
|
|
27
29
|
]);
|
|
28
30
|
const REQUIRED_EVIDENCE_INPUT_KEYS = new Set([
|
|
29
31
|
'turnId', 'toolCallId', 'toolName', 'decision', 'outcome', 'durationMs',
|
|
@@ -36,14 +38,19 @@ const ACTION_ONLY_TOOL_NAMES = new Set([
|
|
|
36
38
|
'ExitPlanMode', 'GenerateImage', 'GenerateSpeech', 'GenerateVideo', 'LipSyncMedia',
|
|
37
39
|
'MistakeRecord', 'SetGoalBudget', 'TaskStop', 'TaskUpdate', 'UpdateGoal', 'Write',
|
|
38
40
|
]);
|
|
39
|
-
const
|
|
41
|
+
const INSPECTION_TOOL_NAMES = new Set([
|
|
40
42
|
'codebasesearch', 'cronlist', 'fetchurl', 'getgoal', 'getmedia', 'glob', 'grep',
|
|
41
|
-
'read', 'readmediafile', 'taskoutput', '
|
|
43
|
+
'read', 'readmediafile', 'taskoutput', 'understandimage', 'understandvideo',
|
|
42
44
|
'websearch',
|
|
43
45
|
]);
|
|
46
|
+
const TEST_TOOL_NAMES = new Set(['test']);
|
|
44
47
|
const COMMAND_TOOL_NAMES = new Set(['bash', 'command', 'exec_command', 'shell']);
|
|
45
48
|
const MUTATING_COMMAND = /(?:^|(?:&&|\|\||;|\s))(?:(?:cp|mv|rm|mkdir|touch|tee|install|scp|sftp|ssh)\b|(?:sed\s+-i\b)|(?:git\s+(?:add|commit|push|checkout|switch|reset|clean|merge|rebase)\b)|(?:Set-Content|Add-Content|Copy-Item|Move-Item|Remove-Item|New-Item|Start-Process)\b)/iu;
|
|
46
|
-
const
|
|
49
|
+
const INSPECTION_COMMAND = /(?:^|(?:&&|\|\||;|\s))(?:(?:git\s+(?:status|rev-parse|show))|(?:wc|rg|grep|cat|ls|stat)\b|(?:Get-Content|Get-Item|Test-Path|Measure-Object)\b)/iu;
|
|
50
|
+
const INTEGRITY_COMMAND = /(?:^|(?:&&|\|\||;|\s))(?:(?:git\s+(?:diff(?:\s+--check)?|fsck))|(?:sha(?:1|256|512)sum|shasum|cmp|diff)\b|(?:certutil\s+-hashfile)|(?:Get-FileHash|Compare-Object)\b)/iu;
|
|
51
|
+
const SYNTAX_COMMAND = /(?:^|(?:&&|\|\||;|\s))(?:(?:node\s+--check\b)|(?:(?:npx\s+)?tsc\b)|(?:(?:npm|pnpm|yarn)\s+(?:(?:run\s+)?typecheck)\b))/iu;
|
|
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
|
+
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;
|
|
47
54
|
const MAX_SUCCESSFUL_TOOL_DIGESTS = 32;
|
|
48
55
|
|
|
49
56
|
function bounded(value, field, max = 512) {
|
|
@@ -181,6 +188,17 @@ function successfulToolCallDigest(turnId, toolCallId, toolName) {
|
|
|
181
188
|
.slice(0, 16);
|
|
182
189
|
}
|
|
183
190
|
|
|
191
|
+
function successfulVerificationCallDigest(turnId, toolCallId, toolName, kind) {
|
|
192
|
+
const turn = normalizedTurnId(turnId);
|
|
193
|
+
const callId = bounded(toolCallId, 'verificationProof toolCallId', 256);
|
|
194
|
+
const name = bounded(toolName, 'verificationProof toolName', 128);
|
|
195
|
+
const normalizedKind = normalizedVerificationKind(kind);
|
|
196
|
+
return crypto.createHash('sha256')
|
|
197
|
+
.update(`turn:${turn}\0call:${callId}\0tool:${name}\0kind:${normalizedKind}`)
|
|
198
|
+
.digest('hex')
|
|
199
|
+
.slice(0, 16);
|
|
200
|
+
}
|
|
201
|
+
|
|
184
202
|
function isActionOnlyTool(toolName) {
|
|
185
203
|
return ACTION_ONLY_TOOL_NAMES.has(String(toolName ?? '').trim());
|
|
186
204
|
}
|
|
@@ -191,14 +209,45 @@ function verificationCommand(toolArgs) {
|
|
|
191
209
|
return typeof command === 'string' ? command.trim().replace(/\s+/gu, ' ') : '';
|
|
192
210
|
}
|
|
193
211
|
|
|
194
|
-
function
|
|
212
|
+
function verificationKindsForToolCall(toolName, toolArgs) {
|
|
213
|
+
const normalizedName = String(toolName ?? '').trim().toLowerCase();
|
|
214
|
+
if (INSPECTION_TOOL_NAMES.has(normalizedName)) return Object.freeze(['inspection']);
|
|
215
|
+
if (TEST_TOOL_NAMES.has(normalizedName)) return Object.freeze(['test']);
|
|
216
|
+
if (!COMMAND_TOOL_NAMES.has(normalizedName)) return Object.freeze([]);
|
|
217
|
+
const command = verificationCommand(toolArgs);
|
|
218
|
+
if (command.length < 1 || MUTATING_COMMAND.test(command)) return Object.freeze([]);
|
|
219
|
+
const kinds = [];
|
|
220
|
+
if (INSPECTION_COMMAND.test(command)) kinds.push('inspection');
|
|
221
|
+
if (INTEGRITY_COMMAND.test(command)) kinds.push('integrity');
|
|
222
|
+
if (SYNTAX_COMMAND.test(command)) kinds.push('syntax');
|
|
223
|
+
if (TEST_COMMAND.test(command)) kinds.push('test');
|
|
224
|
+
return Object.freeze(kinds);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function canCarryExplicitResultEvidence(toolName, toolArgs) {
|
|
195
228
|
const normalizedName = String(toolName ?? '').trim().toLowerCase();
|
|
196
|
-
if (VERIFICATION_TOOL_NAMES.has(normalizedName)) return true;
|
|
197
229
|
if (!COMMAND_TOOL_NAMES.has(normalizedName)) return false;
|
|
198
230
|
const command = verificationCommand(toolArgs);
|
|
199
231
|
return command.length > 0
|
|
200
232
|
&& !MUTATING_COMMAND.test(command)
|
|
201
|
-
&&
|
|
233
|
+
&& RUNTIME_EVIDENCE_COMMAND.test(command);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function normalizedVerificationKind(value, field = 'verificationProof kind') {
|
|
237
|
+
const kind = String(value ?? '').trim();
|
|
238
|
+
if (!VERIFICATION_KINDS.has(kind)) throw new TypeError(`${field} is invalid`);
|
|
239
|
+
return kind;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function normalizedResultEvidenceKinds(value) {
|
|
243
|
+
if (value === undefined) return Object.freeze([]);
|
|
244
|
+
const kinds = Array.isArray(value) ? value.map((item) => String(item ?? '').trim()) : [];
|
|
245
|
+
if (!Array.isArray(value) || value.length > VERIFICATION_KINDS.size
|
|
246
|
+
|| kinds.some((item) => !VERIFICATION_KINDS.has(item))
|
|
247
|
+
|| new Set(kinds).size !== kinds.length) {
|
|
248
|
+
throw new TypeError('result evidence kinds are invalid');
|
|
249
|
+
}
|
|
250
|
+
return Object.freeze(kinds);
|
|
202
251
|
}
|
|
203
252
|
|
|
204
253
|
function normalizeSuccessfulToolDigests(value) {
|
|
@@ -211,12 +260,15 @@ function normalizeSuccessfulToolDigests(value) {
|
|
|
211
260
|
return Object.freeze([...value]);
|
|
212
261
|
}
|
|
213
262
|
|
|
214
|
-
function normalizeExactVerificationCall(input, receipt, label) {
|
|
263
|
+
function normalizeExactVerificationCall(input, receipt, label, options = {}) {
|
|
264
|
+
const requireKind = options.requireKind === true;
|
|
265
|
+
const expectedKeys = requireKind ? 4 : 3;
|
|
215
266
|
if (!input || typeof input !== 'object' || Array.isArray(input)
|
|
216
|
-
|| Object.keys(input).length !==
|
|
267
|
+
|| Object.keys(input).length !== expectedKeys
|
|
217
268
|
|| !Object.hasOwn(input, 'toolCallId')
|
|
218
269
|
|| !Object.hasOwn(input, 'toolName')
|
|
219
|
-
|| !Object.hasOwn(input, 'claim')
|
|
270
|
+
|| !Object.hasOwn(input, 'claim')
|
|
271
|
+
|| requireKind !== Object.hasOwn(input, 'kind')) {
|
|
220
272
|
throw new TypeError(`${label} fields are invalid`);
|
|
221
273
|
}
|
|
222
274
|
const toolCallId = bounded(input.toolCallId, `${label} toolCallId`, 256);
|
|
@@ -230,6 +282,14 @@ function normalizeExactVerificationCall(input, receipt, label) {
|
|
|
230
282
|
if (!receipt.successfulToolCallDigests.includes(callDigest)) {
|
|
231
283
|
throw new TypeError(`${label} must match a successful current-turn verification call`);
|
|
232
284
|
}
|
|
285
|
+
if (requireKind) {
|
|
286
|
+
const kind = normalizedVerificationKind(input.kind, `${label} kind`);
|
|
287
|
+
const typedDigest = successfulVerificationCallDigest(receipt.turnId, toolCallId, toolName, kind);
|
|
288
|
+
if (!receipt.successfulVerificationCallDigests.includes(typedDigest)) {
|
|
289
|
+
throw new TypeError(`${label} kind must match the successful current-turn verification call`);
|
|
290
|
+
}
|
|
291
|
+
return Object.freeze({ toolCallId, toolName, kind, claim });
|
|
292
|
+
}
|
|
233
293
|
return Object.freeze({ toolCallId, toolName, claim });
|
|
234
294
|
}
|
|
235
295
|
|
|
@@ -247,18 +307,34 @@ function normalizeVerificationProof(input, evidenceReceipt, options = {}) {
|
|
|
247
307
|
&& Object.hasOwn(input, 'toolName')
|
|
248
308
|
&& Object.hasOwn(input, 'claim');
|
|
249
309
|
const subject = String(input?.subject ?? '').trim();
|
|
250
|
-
const
|
|
310
|
+
const legacySubjectResult = options.allowLegacy === true
|
|
311
|
+
&& subject === 'result'
|
|
251
312
|
&& keys.length === 4
|
|
252
313
|
&& Object.hasOwn(input, 'toolCallId')
|
|
253
314
|
&& Object.hasOwn(input, 'toolName')
|
|
254
315
|
&& Object.hasOwn(input, 'claim');
|
|
255
|
-
const
|
|
316
|
+
const legacySubjectVerifier = options.allowLegacy === true
|
|
317
|
+
&& subject === 'verifier'
|
|
256
318
|
&& (keys.length === 4 || keys.length === 5)
|
|
257
319
|
&& Object.hasOwn(input, 'toolCallId')
|
|
258
320
|
&& Object.hasOwn(input, 'toolName')
|
|
259
321
|
&& Object.hasOwn(input, 'claim')
|
|
260
322
|
&& keys.every((key) => ['subject', 'toolCallId', 'toolName', 'claim', 'sharpnessProof'].includes(key));
|
|
261
|
-
|
|
323
|
+
const currentResult = subject === 'result'
|
|
324
|
+
&& keys.length === 5
|
|
325
|
+
&& Object.hasOwn(input, 'toolCallId')
|
|
326
|
+
&& Object.hasOwn(input, 'toolName')
|
|
327
|
+
&& Object.hasOwn(input, 'kind')
|
|
328
|
+
&& Object.hasOwn(input, 'claim');
|
|
329
|
+
const currentVerifier = subject === 'verifier'
|
|
330
|
+
&& (keys.length === 5 || keys.length === 6)
|
|
331
|
+
&& Object.hasOwn(input, 'toolCallId')
|
|
332
|
+
&& Object.hasOwn(input, 'toolName')
|
|
333
|
+
&& Object.hasOwn(input, 'kind')
|
|
334
|
+
&& Object.hasOwn(input, 'claim')
|
|
335
|
+
&& keys.every((key) => ['subject', 'toolCallId', 'toolName', 'kind', 'claim', 'sharpnessProof'].includes(key));
|
|
336
|
+
if (!legacyName && !legacyExact && !legacySubjectResult && !legacySubjectVerifier
|
|
337
|
+
&& !currentResult && !currentVerifier) {
|
|
262
338
|
throw new TypeError('verificationProof fields are invalid');
|
|
263
339
|
}
|
|
264
340
|
const receipt = normalizeActionEvidenceReceipt(evidenceReceipt);
|
|
@@ -273,18 +349,22 @@ function normalizeVerificationProof(input, evidenceReceipt, options = {}) {
|
|
|
273
349
|
}
|
|
274
350
|
return Object.freeze({ toolName, claim });
|
|
275
351
|
}
|
|
352
|
+
const legacySubject = legacySubjectResult || legacySubjectVerifier;
|
|
276
353
|
const primary = normalizeExactVerificationCall(legacyExact ? input : {
|
|
277
354
|
toolCallId: input.toolCallId,
|
|
278
355
|
toolName: input.toolName,
|
|
356
|
+
...(legacySubject ? {} : { kind: input.kind }),
|
|
279
357
|
claim: input.claim,
|
|
280
|
-
}, receipt, 'verificationProof');
|
|
358
|
+
}, receipt, 'verificationProof', { requireKind: !legacyExact && !legacySubject });
|
|
281
359
|
if (legacyExact) return primary;
|
|
282
360
|
if (!VERIFICATION_SUBJECTS.has(subject)) throw new TypeError('verificationProof subject is invalid');
|
|
283
361
|
if (subject === 'result') return Object.freeze({ subject, ...primary });
|
|
284
362
|
if (input.sharpnessProof === undefined) {
|
|
285
363
|
throw new TypeError('verifier proof requires a sharpnessProof');
|
|
286
364
|
}
|
|
287
|
-
const sharpnessProof = normalizeExactVerificationCall(input.sharpnessProof, receipt, 'sharpnessProof'
|
|
365
|
+
const sharpnessProof = normalizeExactVerificationCall(input.sharpnessProof, receipt, 'sharpnessProof', {
|
|
366
|
+
requireKind: !legacySubject,
|
|
367
|
+
});
|
|
288
368
|
if (sharpnessProof.toolCallId === primary.toolCallId
|
|
289
369
|
&& sharpnessProof.toolName === primary.toolName) {
|
|
290
370
|
throw new TypeError('sharpnessProof must name a distinct verification call');
|
|
@@ -301,6 +381,7 @@ function emptyActionEvidenceReceipt(turnId) {
|
|
|
301
381
|
failedTools: 0,
|
|
302
382
|
successfulToolDigests: Object.freeze([]),
|
|
303
383
|
successfulToolCallDigests: Object.freeze([]),
|
|
384
|
+
successfulVerificationCallDigests: Object.freeze([]),
|
|
304
385
|
digest: crypto.createHash('sha256').update(`turn:${normalized}:empty`).digest('hex').slice(0, 16),
|
|
305
386
|
});
|
|
306
387
|
}
|
|
@@ -308,7 +389,10 @@ function emptyActionEvidenceReceipt(turnId) {
|
|
|
308
389
|
function normalizeActionEvidenceReceipt(input) {
|
|
309
390
|
if (!input || typeof input !== 'object' || Array.isArray(input)) throw new TypeError('evidence receipt must be an object');
|
|
310
391
|
const requiredKeys = new Set(['turnId', 'completedTools', 'successfulTools', 'failedTools', 'digest']);
|
|
311
|
-
const allowedKeys = new Set([
|
|
392
|
+
const allowedKeys = new Set([
|
|
393
|
+
...requiredKeys, 'successfulToolDigests', 'successfulToolCallDigests',
|
|
394
|
+
'successfulVerificationCallDigests',
|
|
395
|
+
]);
|
|
312
396
|
if (!Object.keys(input).every((key) => allowedKeys.has(key))
|
|
313
397
|
|| ![...requiredKeys].every((key) => Object.hasOwn(input, key))) {
|
|
314
398
|
throw new TypeError('evidence receipt fields are invalid');
|
|
@@ -320,6 +404,9 @@ function normalizeActionEvidenceReceipt(input) {
|
|
|
320
404
|
failedTools: Number(input.failedTools),
|
|
321
405
|
successfulToolDigests: normalizeSuccessfulToolDigests(input.successfulToolDigests),
|
|
322
406
|
successfulToolCallDigests: normalizeSuccessfulToolDigests(input.successfulToolCallDigests),
|
|
407
|
+
successfulVerificationCallDigests: normalizeSuccessfulToolDigests(
|
|
408
|
+
input.successfulVerificationCallDigests,
|
|
409
|
+
),
|
|
323
410
|
digest: String(input.digest ?? ''),
|
|
324
411
|
};
|
|
325
412
|
if (![receipt.completedTools, receipt.successfulTools, receipt.failedTools]
|
|
@@ -352,20 +439,37 @@ function advanceActionEvidenceReceipt(current, input) {
|
|
|
352
439
|
const successful = decision === 'passed' && outcome === 'success';
|
|
353
440
|
const successfulToolDigests = [...prior.successfulToolDigests];
|
|
354
441
|
const successfulToolCallDigests = [...prior.successfulToolCallDigests];
|
|
442
|
+
const successfulVerificationCallDigests = [...prior.successfulVerificationCallDigests];
|
|
355
443
|
const toolDigest = successfulToolDigest(toolName);
|
|
356
444
|
if (successful && !successfulToolDigests.includes(toolDigest)) {
|
|
357
445
|
successfulToolDigests.push(toolDigest);
|
|
358
446
|
if (successfulToolDigests.length > MAX_SUCCESSFUL_TOOL_DIGESTS) successfulToolDigests.shift();
|
|
359
447
|
}
|
|
360
|
-
const
|
|
448
|
+
const providedResultKinds = normalizedResultEvidenceKinds(input.resultEvidenceKinds);
|
|
449
|
+
const explicitResultKinds = successful && canCarryExplicitResultEvidence(toolName, input.toolArgs)
|
|
450
|
+
? providedResultKinds
|
|
451
|
+
: [];
|
|
452
|
+
const verificationKinds = successful
|
|
453
|
+
? [...new Set([...verificationKindsForToolCall(toolName, input.toolArgs), ...explicitResultKinds])]
|
|
454
|
+
: [];
|
|
455
|
+
const verificationCall = verificationKinds.length > 0;
|
|
361
456
|
if (verificationCall) {
|
|
362
457
|
const callDigest = successfulToolCallDigest(turnId, toolCallId, toolName);
|
|
363
458
|
if (!successfulToolCallDigests.includes(callDigest)) successfulToolCallDigests.push(callDigest);
|
|
364
459
|
if (successfulToolCallDigests.length > MAX_SUCCESSFUL_TOOL_DIGESTS) successfulToolCallDigests.shift();
|
|
460
|
+
for (const kind of verificationKinds) {
|
|
461
|
+
const typedDigest = successfulVerificationCallDigest(turnId, toolCallId, toolName, kind);
|
|
462
|
+
if (!successfulVerificationCallDigests.includes(typedDigest)) {
|
|
463
|
+
successfulVerificationCallDigests.push(typedDigest);
|
|
464
|
+
}
|
|
465
|
+
if (successfulVerificationCallDigests.length > MAX_SUCCESSFUL_TOOL_DIGESTS) {
|
|
466
|
+
successfulVerificationCallDigests.shift();
|
|
467
|
+
}
|
|
468
|
+
}
|
|
365
469
|
}
|
|
366
470
|
const digest = crypto.createHash('sha256').update([
|
|
367
471
|
prior.digest, String(turnId), toolCallId, toolName, decision, outcome, String(durationMs),
|
|
368
|
-
|
|
472
|
+
verificationKinds.join(','),
|
|
369
473
|
].join('\0')).digest('hex').slice(0, 16);
|
|
370
474
|
return Object.freeze({
|
|
371
475
|
turnId,
|
|
@@ -374,6 +478,7 @@ function advanceActionEvidenceReceipt(current, input) {
|
|
|
374
478
|
failedTools: prior.failedTools + (successful ? 0 : 1),
|
|
375
479
|
successfulToolDigests: Object.freeze(successfulToolDigests),
|
|
376
480
|
successfulToolCallDigests: Object.freeze(successfulToolCallDigests),
|
|
481
|
+
successfulVerificationCallDigests: Object.freeze(successfulVerificationCallDigests),
|
|
377
482
|
digest,
|
|
378
483
|
});
|
|
379
484
|
}
|
|
@@ -490,10 +595,14 @@ function projectActionCheckpoint(checkpoint) {
|
|
|
490
595
|
const subject = value.verificationProof.subject === undefined
|
|
491
596
|
? ''
|
|
492
597
|
: ` [${value.verificationProof.subject}]`;
|
|
493
|
-
|
|
598
|
+
const kind = value.verificationProof.kind === undefined
|
|
599
|
+
? ''
|
|
600
|
+
: ` [${value.verificationProof.kind}]`;
|
|
601
|
+
lines.push(`Verification proof${subject}${kind}: ${call} - ${value.verificationProof.claim}`);
|
|
494
602
|
if (value.verificationProof.sharpnessProof !== undefined) {
|
|
495
603
|
const sharpness = value.verificationProof.sharpnessProof;
|
|
496
|
-
|
|
604
|
+
const sharpnessKind = sharpness.kind === undefined ? '' : ` [${sharpness.kind}]`;
|
|
605
|
+
lines.push(`Sharpness proof${sharpnessKind}: ${sharpness.toolName} call ${sharpness.toolCallId} - ${sharpness.claim}`);
|
|
497
606
|
}
|
|
498
607
|
}
|
|
499
608
|
if (value.nextTrigger !== undefined) {
|
|
@@ -534,5 +643,7 @@ module.exports = {
|
|
|
534
643
|
normalizeVerificationProof,
|
|
535
644
|
projectActionCheckpoint,
|
|
536
645
|
successfulToolCallDigest,
|
|
646
|
+
successfulVerificationCallDigest,
|
|
537
647
|
successfulToolDigest,
|
|
648
|
+
verificationKindsForToolCall,
|
|
538
649
|
};
|
|
@@ -30,6 +30,10 @@ function verificationProofGaps(checkpoint) {
|
|
|
30
30
|
.test(String(error?.message ?? ''))) {
|
|
31
31
|
return ['The verifier sharpness proof does not match a successful current-turn verification call.'];
|
|
32
32
|
}
|
|
33
|
+
if (/(?:verificationProof|sharpnessProof) kind must match the successful current-turn verification call/u
|
|
34
|
+
.test(String(error?.message ?? ''))) {
|
|
35
|
+
return ['The completion proof kind exceeds what its exact verification call measured.'];
|
|
36
|
+
}
|
|
33
37
|
if (/action-only tool/u.test(String(error?.message ?? ''))) {
|
|
34
38
|
return ['The completion proof names an action-only tool, not a verification tool.'];
|
|
35
39
|
}
|
package/blun.mjs
CHANGED
|
@@ -260352,10 +260352,12 @@ function createActionCheckpointInputSchema(problemFrameSchema, requireProblemFra
|
|
|
260352
260352
|
subject: _enum(["result", "verifier"]),
|
|
260353
260353
|
toolCallId: string().min(1).max(256),
|
|
260354
260354
|
toolName: string().min(1).max(128),
|
|
260355
|
+
kind: _enum(["inspection", "integrity", "syntax", "test", "reachability"]),
|
|
260355
260356
|
claim: string().min(1).max(512),
|
|
260356
260357
|
sharpnessProof: object({
|
|
260357
260358
|
toolCallId: string().min(1).max(256),
|
|
260358
260359
|
toolName: string().min(1).max(128),
|
|
260360
|
+
kind: _enum(["inspection", "integrity", "syntax", "test", "reachability"]),
|
|
260359
260361
|
claim: string().min(1).max(512)
|
|
260360
260362
|
}).strict().optional()
|
|
260361
260363
|
}).strict().superRefine((value, ctx) => {
|
|
@@ -261692,6 +261694,10 @@ function telemetryToolErrorType(result) {
|
|
|
261692
261694
|
function toolResultText(result) {
|
|
261693
261695
|
return toolOutputText(result.output);
|
|
261694
261696
|
}
|
|
261697
|
+
function explicitToolResultEvidenceKinds(result) {
|
|
261698
|
+
const text = toolResultText(result);
|
|
261699
|
+
return /(?:^|\s)BLUN_EVIDENCE_KIND=reachability(?:\s|$)/u.test(text) ? ["reachability"] : [];
|
|
261700
|
+
}
|
|
261695
261701
|
function abandonedToolResultOutput(ended) {
|
|
261696
261702
|
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.`;
|
|
261697
261703
|
}
|
|
@@ -262794,7 +262800,8 @@ var init_turn = __esmMin((() => {
|
|
|
262794
262800
|
toolName: started.name,
|
|
262795
262801
|
outcome,
|
|
262796
262802
|
durationMs: Date.now() - started.startedAt,
|
|
262797
|
-
toolArgs: started.args
|
|
262803
|
+
toolArgs: started.args,
|
|
262804
|
+
resultEvidenceKinds: explicitToolResultEvidenceKinds(event.result)
|
|
262798
262805
|
});
|
|
262799
262806
|
this.agent.telemetry.track("tool_call", properties);
|
|
262800
262807
|
this.agent.feedRootMissionContract("result", {
|
|
@@ -262900,6 +262907,7 @@ var update_goal_default;
|
|
|
262900
262907
|
var init_update_goal$1 = __esmMin((() => {
|
|
262901
262908
|
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";
|
|
262902
262909
|
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
|
+
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";
|
|
262903
262911
|
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";
|
|
262904
262912
|
}));
|
|
262905
262913
|
//#endregion
|