wogiflow 2.31.1 → 2.31.2
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/package.json
CHANGED
|
@@ -886,6 +886,33 @@ const CONFIG_DEFAULTS = {
|
|
|
886
886
|
}
|
|
887
887
|
},
|
|
888
888
|
|
|
889
|
+
// --- Deferral Gate (wf-f9912af6 + wf-b8839d99) ---
|
|
890
|
+
// wf-740f47e4 (DOCS-DRIFT): explicit defaults so config-schema.md isn't lying.
|
|
891
|
+
// The gate worked via inline fallbacks before, but config consumers couldn't
|
|
892
|
+
// discover the keys through the defaults loader.
|
|
893
|
+
deferralGate: {
|
|
894
|
+
enabled: true,
|
|
895
|
+
authTtlSeconds: 600,
|
|
896
|
+
classifyUserPrompts: true,
|
|
897
|
+
minClassifierConfidence: 75
|
|
898
|
+
},
|
|
899
|
+
|
|
900
|
+
// --- Self-Adversary Gate (wf-e399bd8d) ---
|
|
901
|
+
selfAdversaryGate: {
|
|
902
|
+
enabled: true,
|
|
903
|
+
targetConfidence: 95,
|
|
904
|
+
maxIterations: 8,
|
|
905
|
+
generatorModel: 'anthropic:claude-sonnet-4-6',
|
|
906
|
+
adversaryModel: 'anthropic:claude-3-5-haiku-latest'
|
|
907
|
+
},
|
|
908
|
+
|
|
909
|
+
// --- Research-Required Gate (wf-5cd71b1f) ---
|
|
910
|
+
researchRequiredGate: {
|
|
911
|
+
enabled: true,
|
|
912
|
+
requiredEvidence: 2,
|
|
913
|
+
maxAttempts: 3
|
|
914
|
+
},
|
|
915
|
+
|
|
889
916
|
// --- Long Input Gate ---
|
|
890
917
|
longInputGate: {
|
|
891
918
|
enabled: true,
|
|
@@ -359,17 +359,22 @@ async function runSelfAdversaryLoop(opts = {}) {
|
|
|
359
359
|
verdict
|
|
360
360
|
});
|
|
361
361
|
|
|
362
|
-
// Termination checks
|
|
362
|
+
// Termination checks. wf-740f47e4 (L-1-RESIDUAL): adversary VERDICT is
|
|
363
|
+
// authoritative — confidence threshold alone cannot override 'revise'.
|
|
364
|
+
// Previously a second unconditional `if (adjustedConfidence >= target)`
|
|
365
|
+
// bypassed the verdict, accepting decisions the adversary explicitly
|
|
366
|
+
// wanted refined. The S-3 confidence-cap (+10 ceiling) limited damage
|
|
367
|
+
// but the verdict contract was still violated.
|
|
363
368
|
if (verdict === 'needs-user') {
|
|
364
369
|
return buildEscalate(candidate, iterationMemory, targetConfidence, 'adversary-says-needs-user');
|
|
365
370
|
}
|
|
366
371
|
if (verdict === 'accept' && adjustedConfidence >= targetConfidence) {
|
|
367
372
|
return buildSuccess({ ...candidate, confidence: adjustedConfidence }, iterationMemory, targetConfidence);
|
|
368
373
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
//
|
|
374
|
+
// verdict === 'revise' or any other value → continue iterating, even if
|
|
375
|
+
// adjustedConfidence is high. The adversary explicitly said "not yet";
|
|
376
|
+
// honor it. Only the loop-exhausted path (below) can ship a 'revise'
|
|
377
|
+
// decision — and even then it surfaces via buildEscalate, not Success.
|
|
373
378
|
}
|
|
374
379
|
|
|
375
380
|
// Max iterations exhausted without reaching threshold
|
|
@@ -331,7 +331,9 @@ function stripQuotedContent(cmd) {
|
|
|
331
331
|
// heredoc; longer than that, the gate fails open (no strip) which is safer than
|
|
332
332
|
// ReDoS. Single unified terminator regex covers both EOL-anchored and word-
|
|
333
333
|
// boundary cases; tolerates optional trailing whitespace/punctuation.
|
|
334
|
-
|
|
334
|
+
// wf-740f47e4 (CRLF): accept both \n and \r\n terminators so Windows-style
|
|
335
|
+
// line endings in fixtures or test inputs don't bypass the strip.
|
|
336
|
+
stripped = stripped.replace(/<<-?\s*['"]?(\w+)['"]?[\s\S]{0,8000}?\r?\n\1(?:\s*[;)]?\s*$|\b)/gm, ' <<HEREDOC>> ');
|
|
335
337
|
// Single-quoted strings
|
|
336
338
|
stripped = stripped.replace(/'[^']*'/g, "''");
|
|
337
339
|
// Backtick command substitution
|
|
@@ -46,6 +46,22 @@ const REMEDIATION_LABELS = Object.freeze({
|
|
|
46
46
|
'workspace-overdue': 'workspace-overdue (a worker dispatch is past its deadline)'
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Internal: rank gate IDs by REMEDIATION_PRIORITY. Unknown gates sort to
|
|
51
|
+
* the bottom. Returns the IDs in priority order. wf-740f47e4 (DUAL API):
|
|
52
|
+
* extracted from pickTopRemediation + pickStopHookGate so the priority
|
|
53
|
+
* source-of-truth is single.
|
|
54
|
+
*/
|
|
55
|
+
function _rankByPriority(gateIds) {
|
|
56
|
+
return [...gateIds].sort((a, b) => {
|
|
57
|
+
const ia = REMEDIATION_PRIORITY.indexOf(a);
|
|
58
|
+
const ib = REMEDIATION_PRIORITY.indexOf(b);
|
|
59
|
+
const na = ia === -1 ? Number.POSITIVE_INFINITY : ia;
|
|
60
|
+
const nb = ib === -1 ? Number.POSITIVE_INFINITY : ib;
|
|
61
|
+
return na - nb;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
49
65
|
/**
|
|
50
66
|
* Pick the top-priority active remediation from a set of (gateId, message) pairs.
|
|
51
67
|
*
|
|
@@ -58,16 +74,13 @@ function pickTopRemediation(active) {
|
|
|
58
74
|
if (!Array.isArray(active) || active.length === 0) {
|
|
59
75
|
return { top: null, queued: [] };
|
|
60
76
|
}
|
|
61
|
-
// Filter to valid entries and sort by priority index.
|
|
62
77
|
const valid = active.filter(g => g && typeof g.id === 'string' && typeof g.message === 'string' && g.message.trim().length > 0);
|
|
63
78
|
if (valid.length === 0) return { top: null, queued: [] };
|
|
64
79
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const top = { id: indexed[0].id, message: indexed[0].message };
|
|
70
|
-
const queued = indexed.slice(1).map(g => g.id);
|
|
80
|
+
const byId = new Map(valid.map(g => [g.id, g.message]));
|
|
81
|
+
const ranked = _rankByPriority(valid.map(g => g.id));
|
|
82
|
+
const top = { id: ranked[0], message: byId.get(ranked[0]) };
|
|
83
|
+
const queued = ranked.slice(1);
|
|
71
84
|
return { top, queued };
|
|
72
85
|
}
|
|
73
86
|
|
|
@@ -111,12 +124,12 @@ function selectAndRender(gateMap) {
|
|
|
111
124
|
*/
|
|
112
125
|
function pickStopHookGate(activeFlags) {
|
|
113
126
|
if (!activeFlags || typeof activeFlags !== 'object') return { topGateId: null, queued: [] };
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
};
|
|
127
|
+
// wf-740f47e4 (DUAL API): use the shared _rankByPriority helper so this
|
|
128
|
+
// and pickTopRemediation can never disagree on priority order.
|
|
129
|
+
const activeIds = Object.keys(activeFlags).filter(id => activeFlags[id] === true);
|
|
130
|
+
if (activeIds.length === 0) return { topGateId: null, queued: [] };
|
|
131
|
+
const ranked = _rankByPriority(activeIds);
|
|
132
|
+
return { topGateId: ranked[0], queued: ranked.slice(1) };
|
|
120
133
|
}
|
|
121
134
|
|
|
122
135
|
module.exports = {
|
|
@@ -42,10 +42,13 @@ async function orchestrateStop({ parsedInput }) {
|
|
|
42
42
|
let orchestratorTopGate = null;
|
|
43
43
|
try {
|
|
44
44
|
const { pickStopHookGate } = require('./gate-orchestrator');
|
|
45
|
-
|
|
45
|
+
// wf-740f47e4 (NULL-CHECK): guard against malformed return shape.
|
|
46
|
+
const result = pickStopHookGate({
|
|
46
47
|
'long-input-pending': activeGates['long-input-pending'] === true
|
|
47
48
|
});
|
|
48
|
-
orchestratorTopGate = topGateId
|
|
49
|
+
orchestratorTopGate = (result && typeof result === 'object' && typeof result.topGateId === 'string')
|
|
50
|
+
? result.topGateId
|
|
51
|
+
: null;
|
|
49
52
|
} catch (_err) { /* fail-open */ }
|
|
50
53
|
const longInputActive = orchestratorTopGate === 'long-input-pending';
|
|
51
54
|
|