blun-king-cli 9.1.445 → 9.1.447
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.
|
@@ -18,13 +18,14 @@ const MODEL_KEYS = new Set([
|
|
|
18
18
|
const RUNTIME_KEYS = new Set([...MODEL_KEYS, 'evidenceReceipt']);
|
|
19
19
|
const PROBLEM_FRAME_KEYS = new Set([
|
|
20
20
|
'successCriterion', 'missingKnowledge', 'candidateActions', 'selectedAction',
|
|
21
|
-
'selectionReason', 'supportChoice', 'risk', 'reversibility',
|
|
21
|
+
'selectionReason', 'supportChoice', 'risk', 'reversibility', 'decisionBasis',
|
|
22
22
|
]);
|
|
23
23
|
const NEXT_TRIGGER_KEYS = new Set(['kind', 'condition', 'dueAt']);
|
|
24
24
|
const EVIDENCE_INPUT_KEYS = new Set([
|
|
25
25
|
'turnId', 'toolCallId', 'toolName', 'decision', 'outcome', 'durationMs',
|
|
26
26
|
]);
|
|
27
27
|
const EVIDENCE_DIGEST_RE = /^[a-f0-9]{16}$/u;
|
|
28
|
+
const DECISION_BASIS_RE = /^[a-f0-9]{16}$/u;
|
|
28
29
|
const ISO_TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}(?::?\d{2})?)$/u;
|
|
29
30
|
|
|
30
31
|
function bounded(value, field, max = 512) {
|
|
@@ -60,6 +61,15 @@ function boundedList(value, field) {
|
|
|
60
61
|
return Object.freeze(value.map((item, index) => bounded(item, `${field}[${index}]`, 256)));
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
function normalizedDecisionBasis(value) {
|
|
65
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > 5
|
|
66
|
+
|| value.some((item) => typeof item !== 'string' || !DECISION_BASIS_RE.test(item))
|
|
67
|
+
|| new Set(value).size !== value.length) {
|
|
68
|
+
throw new TypeError('decisionBasis must contain between 1 and 5 unique evidence refs');
|
|
69
|
+
}
|
|
70
|
+
return Object.freeze([...value]);
|
|
71
|
+
}
|
|
72
|
+
|
|
63
73
|
function normalizeProblemFrame(input) {
|
|
64
74
|
if (!input || typeof input !== 'object' || Array.isArray(input)) {
|
|
65
75
|
throw new TypeError('problemFrame must be an object');
|
|
@@ -73,7 +83,7 @@ function normalizeProblemFrame(input) {
|
|
|
73
83
|
if (!candidateActions.includes(selectedAction)) {
|
|
74
84
|
throw new TypeError('selectedAction must match a candidateAction');
|
|
75
85
|
}
|
|
76
|
-
|
|
86
|
+
const frame = {
|
|
77
87
|
successCriterion: bounded(input.successCriterion, 'successCriterion'),
|
|
78
88
|
missingKnowledge,
|
|
79
89
|
candidateActions,
|
|
@@ -82,7 +92,9 @@ function normalizeProblemFrame(input) {
|
|
|
82
92
|
supportChoice: bounded(input.supportChoice, 'supportChoice', 256),
|
|
83
93
|
risk: bounded(input.risk, 'risk'),
|
|
84
94
|
reversibility: bounded(input.reversibility, 'reversibility'),
|
|
85
|
-
}
|
|
95
|
+
};
|
|
96
|
+
if (input.decisionBasis !== undefined) frame.decisionBasis = normalizedDecisionBasis(input.decisionBasis);
|
|
97
|
+
return Object.freeze(frame);
|
|
86
98
|
}
|
|
87
99
|
|
|
88
100
|
function normalizeNextTrigger(input, phase) {
|
|
@@ -312,6 +324,7 @@ function projectActionCheckpoint(checkpoint) {
|
|
|
312
324
|
lines.push(`Support choice: ${frame.supportChoice}`);
|
|
313
325
|
lines.push(`Risk: ${frame.risk}`);
|
|
314
326
|
lines.push(`Reversibility: ${frame.reversibility}`);
|
|
327
|
+
if (frame.decisionBasis !== undefined) lines.push(`Decision basis: ${frame.decisionBasis.join(' | ')}`);
|
|
315
328
|
}
|
|
316
329
|
if (value.evidenceReceipt !== undefined) {
|
|
317
330
|
const receipt = value.evidenceReceipt;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const crypto = require('node:crypto');
|
|
3
4
|
const { resolveCognitiveEvidenceGroup } = require('./cognitive-effective-view.cjs');
|
|
4
5
|
const {
|
|
5
6
|
buildCognitiveSalienceIndex,
|
|
@@ -55,15 +56,19 @@ function normalizeScopes(value) {
|
|
|
55
56
|
return scopes.every(Boolean) ? [...new Set(scopes)] : null;
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
function cognitiveEvidenceRef(item) {
|
|
60
|
+
const scope = clean(item?.scope, 128);
|
|
61
|
+
const domain = String(item?.domain ?? '');
|
|
62
|
+
const key = clean(item?.key, 128);
|
|
63
|
+
const observationId = clean(item?.observationId ?? item?.observation_id, 128);
|
|
64
|
+
if (!scope || scope === 'runtime' || !FOCUS_DOMAINS.has(domain) || !key || !observationId) return '';
|
|
65
|
+
return crypto.createHash('sha256')
|
|
66
|
+
.update([scope, domain, key, observationId].join('\0'))
|
|
67
|
+
.digest('hex').slice(0, 16);
|
|
68
|
+
}
|
|
66
69
|
|
|
70
|
+
function normalizedFocusGroups(state) {
|
|
71
|
+
if (!Array.isArray(state?.observations)) return null;
|
|
67
72
|
const groups = new Map();
|
|
68
73
|
state.observations.forEach((item, index) => {
|
|
69
74
|
const domain = String(item?.domain ?? '');
|
|
@@ -80,7 +85,7 @@ function buildCognitiveFocusSelection(state, {
|
|
|
80
85
|
? 'legacy_unknown' : String(item.epistemic_state);
|
|
81
86
|
const occurredAt = Date.parse(String(item?.occurred_at ?? ''));
|
|
82
87
|
if (!FOCUS_DOMAINS.has(domain) || !key || !value || !scope || scope === 'runtime'
|
|
83
|
-
|| !Number.isFinite(confidence) || confidence < 0.5 || confidence > 1
|
|
88
|
+
|| !observationId || !Number.isFinite(confidence) || confidence < 0.5 || confidence > 1
|
|
84
89
|
|| !EPISTEMIC_MARKERS.has(epistemicState)
|
|
85
90
|
|| !Number.isFinite(occurredAt)) return;
|
|
86
91
|
const groupKey = `${scope}\0${domain}\0${key}`;
|
|
@@ -91,11 +96,66 @@ function buildCognitiveFocusSelection(state, {
|
|
|
91
96
|
});
|
|
92
97
|
groups.set(groupKey, existing);
|
|
93
98
|
});
|
|
99
|
+
for (const entries of groups.values()) {
|
|
100
|
+
entries.sort((left, right) => left.occurredAt - right.occurredAt || left.index - right.index);
|
|
101
|
+
}
|
|
102
|
+
return groups;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function currentEvidenceRefs(entries, effective) {
|
|
106
|
+
if (!effective || effective.conflict) return [];
|
|
107
|
+
const withdrawals = entries.filter((item) => Boolean(item.withdraws));
|
|
108
|
+
const deletionCutoff = withdrawals.length > 0
|
|
109
|
+
? Math.max(...withdrawals.map((item) => item.occurredAt)) : Number.NEGATIVE_INFINITY;
|
|
110
|
+
const evidence = entries.filter((item) => !item.withdraws && item.occurredAt > deletionCutoff);
|
|
111
|
+
const superseded = new Set(evidence.map((item) => item.supersedes).filter(Boolean));
|
|
112
|
+
return evidence
|
|
113
|
+
.filter((item) => !superseded.has(item.observationId) && item.value === effective.value)
|
|
114
|
+
.map(cognitiveEvidenceRef)
|
|
115
|
+
.filter(Boolean);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function evaluateCognitiveDecisionBasis(state, refs) {
|
|
119
|
+
if (refs === undefined || refs === null) return null;
|
|
120
|
+
if (!Array.isArray(refs) || refs.length < 1 || refs.length > 5
|
|
121
|
+
|| refs.some((ref) => !/^[a-f0-9]{16}$/u.test(String(ref)))
|
|
122
|
+
|| new Set(refs).size !== refs.length) {
|
|
123
|
+
return { status: 'unknown', currentRefs: [], staleRefs: [], unknownRefs: [] };
|
|
124
|
+
}
|
|
125
|
+
const groups = normalizedFocusGroups(state);
|
|
126
|
+
if (groups === null) return { status: 'unknown', currentRefs: [], staleRefs: [], unknownRefs: [...refs] };
|
|
127
|
+
const historical = new Set();
|
|
128
|
+
const current = new Set();
|
|
129
|
+
for (const entries of groups.values()) {
|
|
130
|
+
entries.map(cognitiveEvidenceRef).filter(Boolean).forEach((ref) => historical.add(ref));
|
|
131
|
+
const effective = resolveCognitiveEvidenceGroup(entries);
|
|
132
|
+
currentEvidenceRefs(entries, effective).forEach((ref) => current.add(ref));
|
|
133
|
+
}
|
|
134
|
+
const currentRefs = refs.filter((ref) => current.has(ref));
|
|
135
|
+
const staleRefs = refs.filter((ref) => !current.has(ref) && historical.has(ref));
|
|
136
|
+
const unknownRefs = refs.filter((ref) => !current.has(ref) && !historical.has(ref));
|
|
137
|
+
return {
|
|
138
|
+
status: staleRefs.length > 0 ? 'stale' : unknownRefs.length > 0 ? 'unknown' : 'current',
|
|
139
|
+
currentRefs,
|
|
140
|
+
staleRefs,
|
|
141
|
+
unknownRefs,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function buildCognitiveFocusSelection(state, {
|
|
146
|
+
focusScopes, maxItems = 6, maxChars = 900, currentSessionId,
|
|
147
|
+
} = {}) {
|
|
148
|
+
const scopes = normalizeScopes(focusScopes);
|
|
149
|
+
if (scopes === null || !Number.isSafeInteger(maxItems) || maxItems < 1 || maxItems > 8
|
|
150
|
+
|| !Number.isSafeInteger(maxChars) || maxChars < 320 || maxChars > 1600) return null;
|
|
151
|
+
if (scopes.length === 0) return null;
|
|
152
|
+
|
|
153
|
+
const groups = normalizedFocusGroups(state);
|
|
154
|
+
if (groups === null) return null;
|
|
94
155
|
|
|
95
156
|
const salience = buildCognitiveSalienceIndex(state, { currentSessionId });
|
|
96
157
|
const ranked = [];
|
|
97
158
|
for (const entries of groups.values()) {
|
|
98
|
-
entries.sort((left, right) => left.occurredAt - right.occurredAt || left.index - right.index);
|
|
99
159
|
const latest = entries.at(-1);
|
|
100
160
|
if (!scopes.includes(latest.scope)) continue;
|
|
101
161
|
const effective = resolveCognitiveEvidenceGroup(entries);
|
|
@@ -117,7 +177,7 @@ function buildCognitiveFocusSelection(state, {
|
|
|
117
177
|
if (item.conflict) return `- Conflict: ${item.key} has incompatible evidence; verify before relying on it.`;
|
|
118
178
|
const marker = item.corrected ? ' [corrected]'
|
|
119
179
|
: item.contested ? ' [contested; stronger evidence]' : item.revised ? ' [revised]' : '';
|
|
120
|
-
return `- ${LABELS.get(item.domain)}: ${item.value}${EPISTEMIC_MARKERS.get(item.epistemicState)}${marker}`;
|
|
180
|
+
return `- ${LABELS.get(item.domain)}: ${item.value}${EPISTEMIC_MARKERS.get(item.epistemicState)}${marker} [ref:${cognitiveEvidenceRef(item)}]`;
|
|
121
181
|
});
|
|
122
182
|
while ([`Current durable focus (${lines.length} items):`, ...lines, SAFETY_LINE].join('\n').length > maxChars
|
|
123
183
|
&& lines.length > 0) lines.pop();
|
|
@@ -125,7 +185,12 @@ function buildCognitiveFocusSelection(state, {
|
|
|
125
185
|
const kept = selected.slice(0, lines.length);
|
|
126
186
|
return {
|
|
127
187
|
text: [`Current durable focus (${lines.length} items):`, ...lines, SAFETY_LINE].join('\n'),
|
|
128
|
-
selected: kept.map((item) => ({
|
|
188
|
+
selected: kept.map((item) => ({
|
|
189
|
+
scope: item.scope,
|
|
190
|
+
domain: item.domain,
|
|
191
|
+
key: item.key,
|
|
192
|
+
...(item.conflict ? {} : { evidenceRef: cognitiveEvidenceRef(item) }),
|
|
193
|
+
})),
|
|
129
194
|
};
|
|
130
195
|
}
|
|
131
196
|
|
|
@@ -133,4 +198,9 @@ function buildCognitiveFocusProjection(state, options) {
|
|
|
133
198
|
return buildCognitiveFocusSelection(state, options)?.text ?? null;
|
|
134
199
|
}
|
|
135
200
|
|
|
136
|
-
module.exports = {
|
|
201
|
+
module.exports = {
|
|
202
|
+
buildCognitiveFocusProjection,
|
|
203
|
+
buildCognitiveFocusSelection,
|
|
204
|
+
cognitiveEvidenceRef,
|
|
205
|
+
evaluateCognitiveDecisionBasis,
|
|
206
|
+
};
|
|
@@ -6,7 +6,10 @@ const path = require('node:path');
|
|
|
6
6
|
const { openCognitiveMemoryAdapter } = require('./cognitive-memory-adapter.cjs');
|
|
7
7
|
const { loadConfiguredCognitiveMemoryAdapter } = require('./cognitive-memory-provider.cjs');
|
|
8
8
|
const { buildCognitiveContextProjection } = require('./cognitive-context-projection.cjs');
|
|
9
|
-
const {
|
|
9
|
+
const {
|
|
10
|
+
buildCognitiveFocusSelection,
|
|
11
|
+
evaluateCognitiveDecisionBasis,
|
|
12
|
+
} = require('./cognitive-focus-projection.cjs');
|
|
10
13
|
const { cognitiveEntityKey, focusAccessObservation } = require('./cognitive-salience-policy.cjs');
|
|
11
14
|
const { authorizeAttentionCandidate } = require('./cognitive-attention-runtime.cjs');
|
|
12
15
|
|
|
@@ -490,6 +493,11 @@ function createCognitiveTurnLifecycle({
|
|
|
490
493
|
return [focus?.text, continuity].filter(Boolean).join('\n\n') || null;
|
|
491
494
|
}
|
|
492
495
|
|
|
496
|
+
function evaluateDecisionBasis(refs) {
|
|
497
|
+
const state = store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess);
|
|
498
|
+
return evaluateCognitiveDecisionBasis(state, refs);
|
|
499
|
+
}
|
|
500
|
+
|
|
493
501
|
function authorizeAttention(input) {
|
|
494
502
|
const candidate = input?.candidate;
|
|
495
503
|
const authorization = input?.authorization;
|
|
@@ -552,6 +560,7 @@ function createCognitiveTurnLifecycle({
|
|
|
552
560
|
withdrawFocusObservation,
|
|
553
561
|
authorizeAttention,
|
|
554
562
|
memoryStatus,
|
|
563
|
+
evaluateDecisionBasis,
|
|
555
564
|
projectForTurn,
|
|
556
565
|
endTurn,
|
|
557
566
|
read: () => store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess),
|
|
@@ -23,7 +23,7 @@ function bounded(value, max = 512) {
|
|
|
23
23
|
return text.length <= max ? text : `${text.slice(0, max - 3).trimEnd()}...`;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function buildCognitiveWorkFocus(goal) {
|
|
26
|
+
function buildCognitiveWorkFocus(goal, { decisionFreshness } = {}) {
|
|
27
27
|
if (!goal || typeof goal !== 'object' || Array.isArray(goal)) return null;
|
|
28
28
|
const goalId = String(goal.goalId ?? '').trim();
|
|
29
29
|
const objective = bounded(goal.objective);
|
|
@@ -75,6 +75,11 @@ function buildCognitiveWorkFocus(goal) {
|
|
|
75
75
|
const frameSupportChoice = bounded(problemFrame?.supportChoice, 256);
|
|
76
76
|
const frameRisk = bounded(problemFrame?.risk);
|
|
77
77
|
const frameReversibility = bounded(problemFrame?.reversibility);
|
|
78
|
+
const frameDecisionBasis = Array.isArray(problemFrame?.decisionBasis)
|
|
79
|
+
&& problemFrame.decisionBasis.length >= 1 && problemFrame.decisionBasis.length <= 5
|
|
80
|
+
&& problemFrame.decisionBasis.every((item) => /^[a-f0-9]{16}$/u.test(String(item)))
|
|
81
|
+
&& new Set(problemFrame.decisionBasis).size === problemFrame.decisionBasis.length
|
|
82
|
+
? [...problemFrame.decisionBasis] : [];
|
|
78
83
|
const hasProblemFrame = problemFrame !== null && frameSuccessCriterion
|
|
79
84
|
&& frameMissingKnowledge.length > 0 && frameCandidates.length > 0
|
|
80
85
|
&& frameSelectedAction && frameSelectionReason && frameSupportChoice
|
|
@@ -83,8 +88,17 @@ function buildCognitiveWorkFocus(goal) {
|
|
|
83
88
|
&& nextAction && checkpointEvidence;
|
|
84
89
|
const epistemicState = hasCheckpoint && EPISTEMIC_STATES.has(checkpointEpistemicState)
|
|
85
90
|
? checkpointEpistemicState : hasCheckpoint ? 'legacy_unknown' : 'verified';
|
|
86
|
-
const
|
|
91
|
+
const decisionFreshnessStatus = frameDecisionBasis.length > 0
|
|
92
|
+
&& ['current', 'stale', 'unknown'].includes(decisionFreshness?.status)
|
|
93
|
+
? decisionFreshness.status : frameDecisionBasis.length > 0 ? 'unknown' : '';
|
|
94
|
+
const staleDecision = decisionFreshnessStatus === 'stale' || decisionFreshnessStatus === 'unknown';
|
|
95
|
+
const replanKnowledgeGap = 'Re-evaluate the selected action against current durable evidence.';
|
|
96
|
+
const replanTrigger = 'Re-evaluate the selected action against the current durable evidence.';
|
|
97
|
+
const replanEvidence = 'A replacement action is bound to current durable evidence refs.';
|
|
98
|
+
const knowledgeGapValue = staleDecision ? `${replanKnowledgeGap} ${frameMissingKnowledge.join(' | ')}`
|
|
99
|
+
: hasProblemFrame ? frameMissingKnowledge.join(' | ') : 'none';
|
|
87
100
|
const decisionThread = hasProblemFrame ? [
|
|
101
|
+
...(staleDecision ? [`Decision basis ${decisionFreshnessStatus}; replan before executing the selected action.`] : []),
|
|
88
102
|
`Goal is ${status}`,
|
|
89
103
|
`Phase ${checkpointPhase}`,
|
|
90
104
|
`Last verified: ${bounded(lastVerified, 80)}`,
|
|
@@ -112,6 +126,8 @@ function buildCognitiveWorkFocus(goal) {
|
|
|
112
126
|
hasProblemFrame ? frameSupportChoice : '',
|
|
113
127
|
hasProblemFrame ? frameRisk : '',
|
|
114
128
|
hasProblemFrame ? frameReversibility : '',
|
|
129
|
+
hasProblemFrame ? frameDecisionBasis.join('\0') : '',
|
|
130
|
+
decisionFreshnessStatus,
|
|
115
131
|
].join('\0'))
|
|
116
132
|
.digest('hex').slice(0, 40);
|
|
117
133
|
const keyRoot = `goal:${goalId}`;
|
|
@@ -128,24 +144,34 @@ function buildCognitiveWorkFocus(goal) {
|
|
|
128
144
|
`Next action: ${nextAction}`,
|
|
129
145
|
].join(' ')
|
|
130
146
|
: `Goal is ${status}.`),
|
|
131
|
-
confidence: 1,
|
|
147
|
+
confidence: 1,
|
|
148
|
+
epistemicState: staleDecision ? decisionFreshnessStatus : epistemicState,
|
|
149
|
+
scope: focusScope,
|
|
132
150
|
},
|
|
133
151
|
{
|
|
134
152
|
domain: 'knowledge_gap', key: `${keyRoot}:knowledge-gaps`,
|
|
135
153
|
value: knowledgeGapValue,
|
|
136
154
|
confidence: 1,
|
|
137
|
-
epistemicState: hasProblemFrame ? 'unknown' : 'verified',
|
|
155
|
+
epistemicState: hasProblemFrame || staleDecision ? 'unknown' : 'verified',
|
|
138
156
|
scope: focusScope,
|
|
139
157
|
},
|
|
140
158
|
{
|
|
141
159
|
domain: 'next_trigger', key: `${keyRoot}:next`,
|
|
142
|
-
value: status === 'active' && hasCheckpoint
|
|
143
|
-
|
|
160
|
+
value: status === 'active' && hasCheckpoint
|
|
161
|
+
? staleDecision ? replanTrigger : triggerValue
|
|
162
|
+
: NEXT_TRIGGER.get(status),
|
|
163
|
+
confidence: 1,
|
|
164
|
+
epistemicState: staleDecision ? decisionFreshnessStatus : epistemicState,
|
|
165
|
+
scope: focusScope,
|
|
144
166
|
},
|
|
145
167
|
{
|
|
146
168
|
domain: 'expected_evidence', key: `${keyRoot}:evidence`,
|
|
147
|
-
value: status === 'active' && hasCheckpoint
|
|
148
|
-
|
|
169
|
+
value: status === 'active' && hasCheckpoint
|
|
170
|
+
? staleDecision ? replanEvidence : checkpointEvidence
|
|
171
|
+
: completionCriterion,
|
|
172
|
+
confidence: 1,
|
|
173
|
+
epistemicState: staleDecision ? decisionFreshnessStatus : epistemicState,
|
|
174
|
+
scope: focusScope,
|
|
149
175
|
},
|
|
150
176
|
],
|
|
151
177
|
};
|
|
@@ -5,6 +5,11 @@ const DEFAULT_WINDOW_WORDS = 20;
|
|
|
5
5
|
const DEFAULT_REQUIRED_OCCURRENCES = 4;
|
|
6
6
|
const DEFAULT_MAX_CHARS = 24_000;
|
|
7
7
|
const DEFAULT_CHECK_EVERY_WORDS = 24;
|
|
8
|
+
const DEFAULT_SHORT_BURST_MAX_WORDS = 8;
|
|
9
|
+
const DEFAULT_SHORT_BURST_MIN_OCCURRENCES = 8;
|
|
10
|
+
const DEFAULT_SHORT_BURST_MIN_TOTAL_WORDS = 24;
|
|
11
|
+
const DEFAULT_SHORT_BURST_MIN_WORDS = 2;
|
|
12
|
+
const DEFAULT_SHORT_BURST_SCAN_WORDS = 192;
|
|
8
13
|
|
|
9
14
|
function normalizeWords(text) {
|
|
10
15
|
return String(text)
|
|
@@ -40,16 +45,80 @@ function repeatedWindow(words, options) {
|
|
|
40
45
|
return null;
|
|
41
46
|
}
|
|
42
47
|
|
|
48
|
+
function equalWindow(words, left, right, width) {
|
|
49
|
+
for (let offset = 0; offset < width; offset += 1) {
|
|
50
|
+
if (words[left + offset] !== words[right + offset]) return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function canCloseConsecutiveWindow(words, minWords, maxWords) {
|
|
56
|
+
const lastIndex = words.length - 1;
|
|
57
|
+
for (let windowWords = minWords; windowWords <= maxWords; windowWords += 1) {
|
|
58
|
+
const previousIndex = lastIndex - windowWords;
|
|
59
|
+
if (previousIndex >= 0 && words[lastIndex] === words[previousIndex]) return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function repeatedConsecutiveWindow(words, options) {
|
|
65
|
+
const {
|
|
66
|
+
maxWords,
|
|
67
|
+
minOccurrences,
|
|
68
|
+
minTotalWords,
|
|
69
|
+
minWords,
|
|
70
|
+
scanWords,
|
|
71
|
+
firstEnd = 1,
|
|
72
|
+
} = options;
|
|
73
|
+
const sourceStart = Math.max(0, words.length - scanWords);
|
|
74
|
+
const localFirstEnd = Math.max(sourceStart + 1, firstEnd);
|
|
75
|
+
|
|
76
|
+
for (let end = localFirstEnd; end <= words.length; end += 1) {
|
|
77
|
+
for (let windowWords = minWords; windowWords <= maxWords; windowWords += 1) {
|
|
78
|
+
const requiredOccurrences = Math.max(
|
|
79
|
+
minOccurrences,
|
|
80
|
+
Math.ceil(minTotalWords / windowWords),
|
|
81
|
+
);
|
|
82
|
+
const requiredSpan = windowWords * requiredOccurrences;
|
|
83
|
+
const start = end - requiredSpan;
|
|
84
|
+
if (start < sourceStart) continue;
|
|
85
|
+
let count = 1;
|
|
86
|
+
let cursor = start + windowWords;
|
|
87
|
+
while (cursor + windowWords <= end
|
|
88
|
+
&& equalWindow(words, start, cursor, windowWords)) {
|
|
89
|
+
count += 1;
|
|
90
|
+
cursor += windowWords;
|
|
91
|
+
}
|
|
92
|
+
if (count < requiredOccurrences) continue;
|
|
93
|
+
return {
|
|
94
|
+
kind: 'short_burst',
|
|
95
|
+
count,
|
|
96
|
+
firstWords: words.slice(start, start + windowWords).join(' '),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
43
103
|
function createLiveResponseRepetitionGuard(options = {}) {
|
|
44
104
|
const config = {
|
|
45
105
|
checkEveryWords: options.checkEveryWords ?? DEFAULT_CHECK_EVERY_WORDS,
|
|
46
106
|
maxChars: options.maxChars ?? DEFAULT_MAX_CHARS,
|
|
47
107
|
minWords: options.minWords ?? DEFAULT_MIN_WORDS,
|
|
48
108
|
requiredOccurrences: options.requiredOccurrences ?? DEFAULT_REQUIRED_OCCURRENCES,
|
|
109
|
+
shortBurstMaxWords: options.shortBurstMaxWords ?? DEFAULT_SHORT_BURST_MAX_WORDS,
|
|
110
|
+
shortBurstMinOccurrences: options.shortBurstMinOccurrences
|
|
111
|
+
?? DEFAULT_SHORT_BURST_MIN_OCCURRENCES,
|
|
112
|
+
shortBurstMinTotalWords: options.shortBurstMinTotalWords
|
|
113
|
+
?? DEFAULT_SHORT_BURST_MIN_TOTAL_WORDS,
|
|
114
|
+
shortBurstMinWords: options.shortBurstMinWords ?? DEFAULT_SHORT_BURST_MIN_WORDS,
|
|
115
|
+
shortBurstScanWords: options.shortBurstScanWords ?? DEFAULT_SHORT_BURST_SCAN_WORDS,
|
|
49
116
|
windowWords: options.windowWords ?? DEFAULT_WINDOW_WORDS,
|
|
50
117
|
};
|
|
51
118
|
let text = '';
|
|
52
119
|
let lastCheckedWords = 0;
|
|
120
|
+
let lastShortBurstLastWord = '';
|
|
121
|
+
let lastShortBurstWordCount = 0;
|
|
53
122
|
let detection = null;
|
|
54
123
|
|
|
55
124
|
return {
|
|
@@ -57,12 +126,46 @@ function createLiveResponseRepetitionGuard(options = {}) {
|
|
|
57
126
|
if (detection !== null || typeof delta !== 'string' || delta.length === 0) return detection;
|
|
58
127
|
text = `${text}${delta}`.slice(-config.maxChars);
|
|
59
128
|
const words = normalizeWords(text);
|
|
129
|
+
const previousShortBurstWordCount = lastShortBurstWordCount;
|
|
130
|
+
const lastWord = words.at(-1) ?? '';
|
|
131
|
+
const wordCountChanged = words.length !== previousShortBurstWordCount;
|
|
132
|
+
const lastWordChanged = lastWord !== lastShortBurstLastWord;
|
|
133
|
+
const firstChangedEnd = words.length > lastShortBurstWordCount
|
|
134
|
+
? Math.max(1, lastShortBurstWordCount)
|
|
135
|
+
: words.length;
|
|
136
|
+
const shouldCheckShortBurst = wordCountChanged || (lastWordChanged
|
|
137
|
+
&& canCloseConsecutiveWindow(
|
|
138
|
+
words,
|
|
139
|
+
config.shortBurstMinWords,
|
|
140
|
+
config.shortBurstMaxWords,
|
|
141
|
+
));
|
|
142
|
+
lastShortBurstLastWord = lastWord;
|
|
143
|
+
lastShortBurstWordCount = words.length;
|
|
144
|
+
if (words.length >= config.shortBurstMinTotalWords && shouldCheckShortBurst) {
|
|
145
|
+
const shortBurst = repeatedConsecutiveWindow(words, {
|
|
146
|
+
firstEnd: firstChangedEnd,
|
|
147
|
+
maxWords: config.shortBurstMaxWords,
|
|
148
|
+
minOccurrences: config.shortBurstMinOccurrences,
|
|
149
|
+
minTotalWords: config.shortBurstMinTotalWords,
|
|
150
|
+
minWords: config.shortBurstMinWords,
|
|
151
|
+
scanWords: config.shortBurstScanWords,
|
|
152
|
+
});
|
|
153
|
+
if (shortBurst !== null) {
|
|
154
|
+
detection = {
|
|
155
|
+
...shortBurst,
|
|
156
|
+
charCount: text.length,
|
|
157
|
+
wordCount: words.length,
|
|
158
|
+
};
|
|
159
|
+
return detection;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
60
162
|
if (words.length < config.minWords) return null;
|
|
61
163
|
if (words.length - lastCheckedWords < config.checkEveryWords) return null;
|
|
62
164
|
lastCheckedWords = words.length;
|
|
63
165
|
const repeated = repeatedWindow(words, config);
|
|
64
166
|
if (repeated === null) return null;
|
|
65
167
|
detection = {
|
|
168
|
+
kind: 'long_window',
|
|
66
169
|
...repeated,
|
|
67
170
|
charCount: text.length,
|
|
68
171
|
wordCount: words.length,
|
|
@@ -80,8 +183,14 @@ module.exports = {
|
|
|
80
183
|
DEFAULT_MAX_CHARS,
|
|
81
184
|
DEFAULT_MIN_WORDS,
|
|
82
185
|
DEFAULT_REQUIRED_OCCURRENCES,
|
|
186
|
+
DEFAULT_SHORT_BURST_MAX_WORDS,
|
|
187
|
+
DEFAULT_SHORT_BURST_MIN_OCCURRENCES,
|
|
188
|
+
DEFAULT_SHORT_BURST_MIN_TOTAL_WORDS,
|
|
189
|
+
DEFAULT_SHORT_BURST_MIN_WORDS,
|
|
190
|
+
DEFAULT_SHORT_BURST_SCAN_WORDS,
|
|
83
191
|
DEFAULT_WINDOW_WORDS,
|
|
84
192
|
createLiveResponseRepetitionGuard,
|
|
85
193
|
normalizeWords,
|
|
194
|
+
repeatedConsecutiveWindow,
|
|
86
195
|
repeatedWindow,
|
|
87
196
|
};
|
package/blun.mjs
CHANGED
|
@@ -245806,7 +245806,8 @@ var init_events$1 = __esmMin((() => {
|
|
|
245806
245806
|
selectionReason: string(),
|
|
245807
245807
|
supportChoice: string(),
|
|
245808
245808
|
risk: string(),
|
|
245809
|
-
reversibility: string()
|
|
245809
|
+
reversibility: string(),
|
|
245810
|
+
decisionBasis: array(string()).optional()
|
|
245810
245811
|
}).strict().optional(),
|
|
245811
245812
|
updatedAt: string(),
|
|
245812
245813
|
evidenceReceipt: object({
|
|
@@ -260306,6 +260307,7 @@ bytesWritten: number$1().int().nonnegative() });
|
|
|
260306
260307
|
var create_goal_default;
|
|
260307
260308
|
var init_create_goal$1 = __esmMin((() => {
|
|
260308
260309
|
create_goal_default = "Create a durable, structured goal that the runtime will pursue across multiple turns.\n\nCall `CreateGoal` when:\n\n- the user explicitly asks you to start a goal or work autonomously toward an outcome,\n- an authenticated user assigns a non-trivial multi-step outcome with a checkable end state under an existing instruction to continue autonomously, or\n- a host goal-intake prompt asks you to create one.\n\nDo NOT create a goal for greetings, ordinary questions, one-step requests, or vague requests that lack a\nverifiable completion condition. A goal needs a checkable end state.\n\nWhen the request is vague, ask the user for the missing completion criterion before creating\nthe goal. If the user clearly insists after you warn them that the wording is vague or risky,\nrespect that and create the goal.\n\nInclude a `completionCriterion` when the user provides one, or when it can be stated without\ninventing new requirements. Keep `objective` concise; reference long task descriptions by file\npath rather than pasting them. Start every created goal with revision 1 and a complete `problemFrame`\ninside `actionCheckpoint`, so the success criterion, missing knowledge, candidate actions, chosen\naction, support choice, risk, reversibility, next action, expected evidence, and exact next trigger survive interruption.\nThis frame is descriptive state only and never grants permission.\n\nCreating a goal fails if one already exists, so use `replace: true` only when the user explicitly\nwants to abandon the current goal and start a new one.\n";
|
|
260310
|
+
create_goal_default += "\nBind 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.\n";
|
|
260309
260311
|
}));
|
|
260310
260312
|
//#endregion
|
|
260311
260313
|
//#region ../../packages/agent-core/src/tools/builtin/goal/serialize.ts
|
|
@@ -260333,7 +260335,8 @@ function createProblemFrameInputSchema() {
|
|
|
260333
260335
|
selectionReason: string().min(1).max(512),
|
|
260334
260336
|
supportChoice: string().min(1).max(256),
|
|
260335
260337
|
risk: string().min(1).max(512),
|
|
260336
|
-
reversibility: string().min(1).max(512)
|
|
260338
|
+
reversibility: string().min(1).max(512),
|
|
260339
|
+
decisionBasis: array(string().regex(/^[a-f0-9]{16}$/u)).min(1).max(5).optional()
|
|
260337
260340
|
}).strict();
|
|
260338
260341
|
}
|
|
260339
260342
|
function createActionCheckpointInputSchema(problemFrameSchema, requireProblemFrame = false) {
|
|
@@ -261835,7 +261838,9 @@ var init_turn = __esmMin((() => {
|
|
|
261835
261838
|
try {
|
|
261836
261839
|
const focusScopes = cognitiveFocusScopesForTurn(input);
|
|
261837
261840
|
const lifecycle = this.getCognitiveLifecycle();
|
|
261838
|
-
const
|
|
261841
|
+
const goal = this.agent.goal.getGoal().goal;
|
|
261842
|
+
const decisionFreshness = lifecycle?.evaluateDecisionBasis(goal?.actionCheckpoint?.problemFrame?.decisionBasis) ?? null;
|
|
261843
|
+
const workFocus = buildCognitiveWorkFocus(goal, { decisionFreshness });
|
|
261839
261844
|
if (workFocus !== null) {
|
|
261840
261845
|
lifecycle?.recordFocusSnapshot({
|
|
261841
261846
|
snapshotId: workFocus.snapshotId,
|
|
@@ -262863,7 +262868,7 @@ var init_outcome_prompts = __esmMin((() => {}));
|
|
|
262863
262868
|
var update_goal_default;
|
|
262864
262869
|
var init_update_goal$1 = __esmMin((() => {
|
|
262865
262870
|
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";
|
|
262866
|
-
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. Problem framing is descriptive state and never grants permission.\n";
|
|
262871
|
+
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";
|
|
262867
262872
|
}));
|
|
262868
262873
|
//#endregion
|
|
262869
262874
|
//#region ../../packages/agent-core/src/tools/builtin/goal/update-goal.ts
|