@toddzheng024/dscode-bundle 0.7.18 → 0.7.20
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
|
@@ -94,6 +94,9 @@ export function apply(ctx, config) {
|
|
|
94
94
|
announce(req.agent, `Automatic review rejected ${req.toolName}: ${decision.reason}. Do not retry the same outcome via another command or tool. Continue only with a materially safer alternative or ask the user.${state.blocked ? ' Stop this turn: three consecutive denials.' : ''}`);
|
|
95
95
|
return 'rejected';
|
|
96
96
|
}
|
|
97
|
+
// Only an explicit allow runs: `defer` and any future verdict value fall back
|
|
98
|
+
// to the human instead of being read as approval.
|
|
99
|
+
if (decision.decision !== 'allow') return fallback(decision.reason ?? 'Unrecognized review verdict.', details);
|
|
97
100
|
state.denials = 0;
|
|
98
101
|
return 'allowed-once';
|
|
99
102
|
};
|
|
@@ -132,13 +135,18 @@ export function apply(ctx, config) {
|
|
|
132
135
|
verdict = undefined;
|
|
133
136
|
}
|
|
134
137
|
if (verdict !== undefined) {
|
|
135
|
-
|
|
138
|
+
const jevDetails = {
|
|
136
139
|
actionHash, provider: 'openrouter', model: verdict.model, source: 'jev',
|
|
137
140
|
choice: verdict.choice, confidence: verdict.confidence, denyProbability: verdict.denyProbability,
|
|
138
141
|
authorized: verdict.authorized, destructive: verdict.destructive, credentialRisk: verdict.credentialRisk,
|
|
139
142
|
durationMs: verdict.durationMs ?? (Date.now() - started),
|
|
140
143
|
usage: verdict.usage ?? null, usageComplete: verdict.usage != null,
|
|
141
|
-
}
|
|
144
|
+
};
|
|
145
|
+
// Jev hands its risk guards over when the instruction authorizes the work;
|
|
146
|
+
// the reviewer model below sees the pending arguments and decides, and its
|
|
147
|
+
// own `human` verdict still reaches the user.
|
|
148
|
+
if (verdict.decision !== 'defer') return applyVerdict({ decision: verdict.decision, reason: verdict.reason }, jevDetails);
|
|
149
|
+
record(req, { decision: 'deferred', reason: verdict.reason, ...jevDetails });
|
|
142
150
|
}
|
|
143
151
|
// A caller that cancelled must not fall through to a reviewer request.
|
|
144
152
|
if (req.signal?.aborted) {
|
package/plugins/jev/approval.mjs
CHANGED
|
@@ -38,12 +38,18 @@ export function approvalQuestions() {
|
|
|
38
38
|
criteria: {
|
|
39
39
|
allow: 'Read-only, or a change the retained user instruction already asked for.',
|
|
40
40
|
ask: 'Plausibly within the task but not clearly authorized, or the blast radius is unclear.',
|
|
41
|
-
deny: 'Outside the user instruction, or it would disclose data, destroy unrelated work, or publish something.',
|
|
41
|
+
deny: 'Outside the user instruction, or it would disclose data, destroy unrelated work, or publish something the instruction did not ask for.',
|
|
42
42
|
},
|
|
43
43
|
},
|
|
44
44
|
authorized: {
|
|
45
45
|
type: 'noul',
|
|
46
|
-
|
|
46
|
+
// Scored on its own, never as a function of how risky the action is: the
|
|
47
|
+
// deployment uses this number to decide whether a risk guard may defer to
|
|
48
|
+
// the model reviewer, and collapsing authorization into apparent safety
|
|
49
|
+
// made user-requested work (a release that must leave the sandbox) read as
|
|
50
|
+
// unauthorized. An instruction almost never names the exact command, so the
|
|
51
|
+
// question is about the task it asks for, not about a literal match.
|
|
52
|
+
instructions: 'Judge the authorization alone, separately from how risky the action is: an action the instruction asks for scores high even when it is dangerous, and a risky action nobody asked for scores low. The instruction rarely names a command, so read it as the task it asks for and decide whether this call is a required or ordinary step of that task, including its target and effect. Score 0.9 or more when the instruction directly asks for this step; 0.6 up to but not including 0.9 when the step is necessary to carry out a stated task, or the instruction names the target but not the means; 0.2 up to but not including 0.6 when the call is plausibly part of the task but optional or unclear; below 0.2 when the instruction does not cover it or it serves a different goal.',
|
|
47
53
|
},
|
|
48
54
|
destructive: {
|
|
49
55
|
type: 'score',
|
|
@@ -67,8 +73,16 @@ const clip = (value, limit) => {
|
|
|
67
73
|
// call, and the retained direct user instruction. It is posted to OpenRouter, so
|
|
68
74
|
// it is bounded and never carries credentials.
|
|
69
75
|
export function approvalState({ action, context } = {}) {
|
|
76
|
+
// `contextFor` hands these over as `{ seq, text }`; a caller may also pass raw
|
|
77
|
+
// message objects. Reading only `content` left `userInstructions` empty, so Jev
|
|
78
|
+
// judged every escalation without ever seeing what the user had asked for.
|
|
70
79
|
const instructions = (context?.userMessages ?? [])
|
|
71
|
-
.map(message =>
|
|
80
|
+
.map(message => {
|
|
81
|
+
if (typeof message?.text === 'string') return message.text.trim();
|
|
82
|
+
const content = message?.content;
|
|
83
|
+
if (typeof content === 'string') return content.trim();
|
|
84
|
+
return Array.isArray(content) ? content.map(block => block?.text ?? '').join(' ').trim() : '';
|
|
85
|
+
})
|
|
72
86
|
.filter(Boolean)
|
|
73
87
|
.join('\n---\n');
|
|
74
88
|
return {
|
|
@@ -100,10 +114,18 @@ export function approvalVerdict(answers, thresholds = DEFAULT_THRESHOLDS) {
|
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
// Everything below guards the allow direction: high risk or a non-allowing
|
|
103
|
-
// answer
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
117
|
+
// answer must not run on Jev's word alone. None of these guards is a denial, so
|
|
118
|
+
// when the instruction itself authorizes the work they defer to the reviewer
|
|
119
|
+
// model, which sees the exact pending arguments and the retained instruction:
|
|
120
|
+
// Jev's scores are coarse, and this deployment already allows ordinary network
|
|
121
|
+
// access and a CLI's own stored credentials. A caller that does not know
|
|
122
|
+
// `defer` must treat it as "review me", never as an allow.
|
|
123
|
+
const guard = reason => authorized >= thresholds.authorizedVeto
|
|
124
|
+
? { decision: 'defer', reason, ...detail }
|
|
125
|
+
: { decision: 'human', reason, ...detail };
|
|
126
|
+
if (credentialRisk >= thresholds.credentialRisk) return guard('Automatic review found possible credential handling.');
|
|
127
|
+
if (destructive >= thresholds.destructiveCeiling) return guard('Automatic review judged this action hard to undo.');
|
|
128
|
+
if (verdict.choice !== 'allow') return guard('Automatic review asked for a human decision.');
|
|
129
|
+
if (confidence < thresholds.autoAllow) return guard(`Automatic review was not confident enough (${confidence.toFixed(2)}).`);
|
|
108
130
|
return { decision: 'allow', reason: 'Automatic review approved the action.', ...detail };
|
|
109
131
|
}
|