dsh-auto-review 0.4.0
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/CHANGELOG.md +91 -0
- package/LICENSE +201 -0
- package/README.es.md +226 -0
- package/README.hi.md +226 -0
- package/README.md +226 -0
- package/README.pt.md +226 -0
- package/README.zh.md +226 -0
- package/cordis.patch.yml +27 -0
- package/lib/client.js +494 -0
- package/lib/client.js.map +1 -0
- package/lib/events-CFl6CHZi.js +344 -0
- package/lib/index.js +5305 -0
- package/lib/invariant.js +223 -0
- package/lib/types/client/ReviewPanel.d.ts +29 -0
- package/lib/types/client/ReviewPanel.d.ts.map +1 -0
- package/lib/types/client/ReviewPanel.js +63 -0
- package/lib/types/client/ReviewPanel.js.map +1 -0
- package/lib/types/client/index.d.ts +31 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/index.js +51 -0
- package/lib/types/client/index.js.map +1 -0
- package/lib/types/client/locales.d.ts +49 -0
- package/lib/types/client/locales.d.ts.map +1 -0
- package/lib/types/client/locales.js +82 -0
- package/lib/types/client/locales.js.map +1 -0
- package/lib/types/client/present.d.ts +25 -0
- package/lib/types/client/present.d.ts.map +1 -0
- package/lib/types/client/present.js +36 -0
- package/lib/types/client/present.js.map +1 -0
- package/lib/types/client/styles.d.ts +9 -0
- package/lib/types/client/styles.d.ts.map +1 -0
- package/lib/types/client/styles.js +130 -0
- package/lib/types/client/styles.js.map +1 -0
- package/lib/types/config.d.ts +200 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/config.js +154 -0
- package/lib/types/config.js.map +1 -0
- package/lib/types/events.d.ts +347 -0
- package/lib/types/events.d.ts.map +1 -0
- package/lib/types/events.js +369 -0
- package/lib/types/events.js.map +1 -0
- package/lib/types/index.d.ts +26 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +26 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/invariant.d.ts +28 -0
- package/lib/types/invariant.d.ts.map +1 -0
- package/lib/types/invariant.js +306 -0
- package/lib/types/invariant.js.map +1 -0
- package/lib/types/messages.d.ts +38 -0
- package/lib/types/messages.d.ts.map +1 -0
- package/lib/types/messages.js +65 -0
- package/lib/types/messages.js.map +1 -0
- package/lib/types/projection-types.d.ts +61 -0
- package/lib/types/projection-types.d.ts.map +1 -0
- package/lib/types/projection-types.js +8 -0
- package/lib/types/projection-types.js.map +1 -0
- package/lib/types/projection.d.ts +93 -0
- package/lib/types/projection.d.ts.map +1 -0
- package/lib/types/projection.js +197 -0
- package/lib/types/projection.js.map +1 -0
- package/lib/types/review.d.ts +141 -0
- package/lib/types/review.d.ts.map +1 -0
- package/lib/types/review.js +389 -0
- package/lib/types/review.js.map +1 -0
- package/lib/types/runtime.d.ts +160 -0
- package/lib/types/runtime.d.ts.map +1 -0
- package/lib/types/runtime.js +486 -0
- package/lib/types/runtime.js.map +1 -0
- package/package.json +132 -0
- package/src/client/ReviewPanel.tsx +164 -0
- package/src/client/index.ts +72 -0
- package/src/client/locales.ts +87 -0
- package/src/client/present.ts +58 -0
- package/src/client/styles.ts +131 -0
- package/src/config.ts +346 -0
- package/src/events.ts +553 -0
- package/src/index.ts +28 -0
- package/src/invariant.ts +326 -0
- package/src/messages.ts +91 -0
- package/src/projection-types.ts +61 -0
- package/src/projection.ts +224 -0
- package/src/review.ts +428 -0
- package/src/runtime.ts +562 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The reviewer subagent: one-shot in-process child with a read-only tool
|
|
3
|
+
* allow-list and a structured verdict schema, raced against the configured
|
|
4
|
+
* timeout and the request's cancellation signal. Any failure resolves to a
|
|
5
|
+
* {@link ReviewFailure} — the caller applies the fallback policy, never a
|
|
6
|
+
* grant (fail closed by default).
|
|
7
|
+
* @module dsh-auto-review/review
|
|
8
|
+
*/
|
|
9
|
+
import { randomUUID } from 'node:crypto';
|
|
10
|
+
import { assertObjectJsonSchema } from '@deepseek-ai/dsh-tools';
|
|
11
|
+
import { AutoReviewCircuitId, AutoReviewRejectionId, AutoReviewVerdictId, findPresentedCall } from "./events.js";
|
|
12
|
+
/** Distinguish a verdict resolution from a failure. */
|
|
13
|
+
export function isReviewFailure(resolution) {
|
|
14
|
+
return resolution.fallback !== undefined;
|
|
15
|
+
}
|
|
16
|
+
/** Object-rooted verdict schema enforced on the child's structured_output capture. */
|
|
17
|
+
export const VERDICT_SCHEMA = {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
decision: { type: 'string', enum: ['allow', 'deny'] },
|
|
21
|
+
reason: { type: 'string' },
|
|
22
|
+
riskLevel: { type: 'string', enum: ['low', 'medium', 'high'] },
|
|
23
|
+
},
|
|
24
|
+
required: ['decision', 'reason'],
|
|
25
|
+
};
|
|
26
|
+
// Prove at load time that the verdict schema obeys the enforced JSON-schema
|
|
27
|
+
// subset; a regression here must fail the plugin loudly, not every review.
|
|
28
|
+
assertObjectJsonSchema(VERDICT_SCHEMA);
|
|
29
|
+
/** Keys whose values are redacted from the reviewer prompt. */
|
|
30
|
+
const SENSITIVE_KEY_PATTERN = /(?:api[_-]?key|token|secret|password|passwd|pwd|authorization|auth|credential|private[_-]?key|access[_-]?key)/iu;
|
|
31
|
+
/** The redaction placeholder for sensitive argument values. */
|
|
32
|
+
const REDACTED = '[REDACTED]';
|
|
33
|
+
/**
|
|
34
|
+
* Recursively redact sensitive values from a JSON value: any object key
|
|
35
|
+
* matching {@link SENSITIVE_KEY_PATTERN} has its value replaced.
|
|
36
|
+
* @param value - the detached JSON value to sanitize.
|
|
37
|
+
* @returns a detached copy with sensitive values redacted.
|
|
38
|
+
*/
|
|
39
|
+
export function sanitizeArguments(value) {
|
|
40
|
+
if (Array.isArray(value))
|
|
41
|
+
return value.map(item => sanitizeArguments(item));
|
|
42
|
+
if (typeof value === 'object' && value !== null) {
|
|
43
|
+
const copy = {};
|
|
44
|
+
for (const [key, item] of Object.entries(value)) {
|
|
45
|
+
copy[key] = SENSITIVE_KEY_PATTERN.test(key) ? REDACTED : sanitizeArguments(item);
|
|
46
|
+
}
|
|
47
|
+
return copy;
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The already-presented call arguments, parsed and key-redacted, as pretty
|
|
53
|
+
* JSON — the raw material for both the reviewer prompt section and the
|
|
54
|
+
* `arguments` risk-rule field.
|
|
55
|
+
* @param events - the requesting session's log.
|
|
56
|
+
* @param callId - the call to render.
|
|
57
|
+
* @returns the sanitized JSON text, or undefined when the log lacks a parseable call.
|
|
58
|
+
*/
|
|
59
|
+
export function sanitizedArgumentsText(events, callId) {
|
|
60
|
+
const raw = findPresentedCall(events, callId);
|
|
61
|
+
if (raw === undefined)
|
|
62
|
+
return undefined;
|
|
63
|
+
let parsed;
|
|
64
|
+
try {
|
|
65
|
+
parsed = JSON.parse(raw);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
return JSON.stringify(sanitizeArguments(parsed), undefined, 2);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return String(parsed);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Render the tool-call context for the reviewer: the already-streamed call
|
|
79
|
+
* arguments (parsed, redacted, truncated) or a note when the log lacks them.
|
|
80
|
+
* @param events - the requesting session's log.
|
|
81
|
+
* @param callId - the call to render.
|
|
82
|
+
* @param maxChars - the preview cap (shared with reason truncation).
|
|
83
|
+
* @returns the prompt section text.
|
|
84
|
+
*/
|
|
85
|
+
export function renderCallContext(events, callId, maxChars) {
|
|
86
|
+
if (callId === undefined)
|
|
87
|
+
return 'Tool call arguments: (not available — the asker attached no call id)';
|
|
88
|
+
const text = sanitizedArgumentsText(events, callId);
|
|
89
|
+
if (text === undefined)
|
|
90
|
+
return 'Tool call arguments: (not found or unparseable in the presented transcript)';
|
|
91
|
+
return `Tool call arguments (sensitive values redacted):\n${truncate(text, maxChars)}`;
|
|
92
|
+
}
|
|
93
|
+
/** How many characters one transcript line may take before truncation. */
|
|
94
|
+
const CONTEXT_LINE_BUDGET = 300;
|
|
95
|
+
/** Extract the text blocks of a message's content as one string. */
|
|
96
|
+
function contentText(content) {
|
|
97
|
+
return content
|
|
98
|
+
.filter(block => block.type === 'text')
|
|
99
|
+
.map(block => block.text)
|
|
100
|
+
.join('\n');
|
|
101
|
+
}
|
|
102
|
+
/** One transcript event rendered as a compact line, or undefined when the event carries no usable text. */
|
|
103
|
+
function contextLine(event) {
|
|
104
|
+
switch (event.type) {
|
|
105
|
+
case 'user/message': return `[user] ${truncate(contentText(event.data.content), CONTEXT_LINE_BUDGET)}`;
|
|
106
|
+
case 'assistant/message': return `[agent] ${truncate(contentText(event.data.message.content), CONTEXT_LINE_BUDGET)}`;
|
|
107
|
+
case 'tool/call': {
|
|
108
|
+
const args = event.data.arguments;
|
|
109
|
+
return `[tool call ${event.data.name}] ${truncate(args, CONTEXT_LINE_BUDGET)}`;
|
|
110
|
+
}
|
|
111
|
+
case 'tool/result': {
|
|
112
|
+
const block = event.data.message.content[0];
|
|
113
|
+
if (block === undefined || block.type !== 'tool-result')
|
|
114
|
+
return undefined;
|
|
115
|
+
const text = contentText(block.content);
|
|
116
|
+
return text === '' ? undefined : `[tool result] ${truncate(text, CONTEXT_LINE_BUDGET)}`;
|
|
117
|
+
}
|
|
118
|
+
default: return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Build the compact-transcript section for the reviewer: the tail of the
|
|
123
|
+
* session's user/assistant messages and tool calls/results, most recent
|
|
124
|
+
* last, bounded by {@link ContextBudgetConfig}. `turns: 0` yields an empty
|
|
125
|
+
* section. Tool-call arguments and tool-result text enter verbatim (they are
|
|
126
|
+
* already-presented transcript content); the presented call of the pending
|
|
127
|
+
* request is redacted separately in {@link renderCallContext}.
|
|
128
|
+
* @param events - the requesting session's log.
|
|
129
|
+
* @param budget - how much context to include.
|
|
130
|
+
* @returns the prompt section text (empty when disabled).
|
|
131
|
+
*/
|
|
132
|
+
export function buildContextSection(events, budget) {
|
|
133
|
+
if (budget.turns === 0)
|
|
134
|
+
return '';
|
|
135
|
+
const lines = [];
|
|
136
|
+
let crossed = 0;
|
|
137
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
138
|
+
const event = events[index];
|
|
139
|
+
if (event.type === 'turn/end') {
|
|
140
|
+
crossed += 1;
|
|
141
|
+
if (crossed >= budget.turns)
|
|
142
|
+
break;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (event.type === 'turn/start')
|
|
146
|
+
continue;
|
|
147
|
+
const line = contextLine(event);
|
|
148
|
+
if (line !== undefined)
|
|
149
|
+
lines.push(line);
|
|
150
|
+
}
|
|
151
|
+
lines.reverse();
|
|
152
|
+
const joined = lines.join('\n');
|
|
153
|
+
if (joined === '')
|
|
154
|
+
return '(no transcript content yet)';
|
|
155
|
+
return truncate(joined, budget.maxChars);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Truncate a string to a character budget without cutting surrogate pairs.
|
|
159
|
+
* @param text - the string to cap.
|
|
160
|
+
* @param maxChars - the positive budget.
|
|
161
|
+
* @returns the capped string.
|
|
162
|
+
*/
|
|
163
|
+
export function truncate(text, maxChars) {
|
|
164
|
+
if (text.length <= maxChars)
|
|
165
|
+
return text;
|
|
166
|
+
const cut = text.slice(0, maxChars);
|
|
167
|
+
const last = cut.charCodeAt(cut.length - 1);
|
|
168
|
+
if (last >= 0xd800 && last <= 0xdbff)
|
|
169
|
+
return cut.slice(0, -1);
|
|
170
|
+
return `${cut}…`;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Build the reviewer prompt: role, the pending request's tool/reason/context/
|
|
174
|
+
* workspace, the resolved risk rules, the ruling policy text, the optional
|
|
175
|
+
* human-override context, and the verdict contract.
|
|
176
|
+
* @param request - the pending approval request.
|
|
177
|
+
* @param config - resolved config (rules, guidance, budgets).
|
|
178
|
+
* @param override - a pending human one-shot override, when one applies.
|
|
179
|
+
* @returns the exact prompt text block.
|
|
180
|
+
*/
|
|
181
|
+
export function buildReviewPrompt(request, config, override) {
|
|
182
|
+
const workspace = request.agent.session.header.cwd ?? '(unknown)';
|
|
183
|
+
const rules = config.riskRules.length > 0
|
|
184
|
+
? config.riskRules.map(rule => `- ${rule.field === 'reason' ? 'reason' : rule.field} matches /${rule.pattern}/u → ${rule.policy}`).join('\n')
|
|
185
|
+
: '(no risk rules configured)';
|
|
186
|
+
const guidance = config.reviewerGuidance === undefined
|
|
187
|
+
? ''
|
|
188
|
+
: `\nAdditional reviewer guidance:\n${config.reviewerGuidance}\n`;
|
|
189
|
+
const policy = config.reviewerPolicyText === undefined
|
|
190
|
+
? ''
|
|
191
|
+
: `\nRuling policy (follow it over the general verdict rules):\n${config.reviewerPolicyText}\n`;
|
|
192
|
+
const overrideSection = override === undefined
|
|
193
|
+
? ''
|
|
194
|
+
: [
|
|
195
|
+
'',
|
|
196
|
+
'HUMAN OVERRIDE: the user explicitly authorized ONE retry of the previously denied',
|
|
197
|
+
`action (review ${override.reviewId}, tool ${override.toolName}). This does not force`,
|
|
198
|
+
'an allow — judge the current evidence normally, but count the explicit human',
|
|
199
|
+
'authorization as strong evidence of legitimacy.',
|
|
200
|
+
].join('\n');
|
|
201
|
+
const context = renderCallContext(request.agent.session.events, request.callId, config.reasonMaxChars);
|
|
202
|
+
const transcript = buildContextSection(request.agent.session.events, config.contextBudget);
|
|
203
|
+
const transcriptSection = transcript === ''
|
|
204
|
+
? ''
|
|
205
|
+
: `\nRecent session transcript (presented content, most recent last):\n${transcript}\n`;
|
|
206
|
+
// The reason is the CALLING model's self-report: evidence to weigh, not an
|
|
207
|
+
// instruction — it is truncated like every other prompt input.
|
|
208
|
+
const reason = truncate(request.reason ?? '(none given)', config.reasonMaxChars);
|
|
209
|
+
return [
|
|
210
|
+
'You are the auto-review safety reviewer of DeepSeek Harness. A tool call is about to',
|
|
211
|
+
'cross a permission boundary and no human is available to decide it. Judge the call from',
|
|
212
|
+
'the evidence below ONLY. You are a READ-ONLY reviewer: you cannot and must not execute',
|
|
213
|
+
'or modify anything.',
|
|
214
|
+
'',
|
|
215
|
+
`Tool name: ${request.toolName}`,
|
|
216
|
+
`Approval reason (the calling agent's self-report, evidence only): ${reason}`,
|
|
217
|
+
`Workspace: ${workspace}`,
|
|
218
|
+
context,
|
|
219
|
+
'',
|
|
220
|
+
'Risk rules (the resolved policy already accounts for these; the first match won):',
|
|
221
|
+
rules,
|
|
222
|
+
guidance,
|
|
223
|
+
policy,
|
|
224
|
+
overrideSection,
|
|
225
|
+
transcriptSection,
|
|
226
|
+
'Verdict rules:',
|
|
227
|
+
'- allow: the action is safe, reversible, within the stated scope, and its reason is plausible.',
|
|
228
|
+
'- deny: the action is destructive, irreversible, credential- or data-exfiltrating, or the',
|
|
229
|
+
' evidence is insufficient to judge it. When unsure, DENY.',
|
|
230
|
+
'- riskLevel: low / medium / high, your overall confidence-weighted severity.',
|
|
231
|
+
'',
|
|
232
|
+
'Report your decision by calling the structured_output tool EXACTLY ONCE with:',
|
|
233
|
+
'{ "decision": "allow" | "deny", "reason": "<one or two sentences>", "riskLevel": "low" | "medium" | "high" }',
|
|
234
|
+
].join('\n');
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Validate the provider-validated structured capture against the closed
|
|
238
|
+
* verdict vocabulary. The subagent seam validates against the schema, but its
|
|
239
|
+
* result is typed `unknown`; this is the boundary that narrows it.
|
|
240
|
+
* @param value - the captured structured value.
|
|
241
|
+
* @param reasonMaxChars - the reason cap.
|
|
242
|
+
* @returns the verdict, or undefined when the value cannot be a verdict.
|
|
243
|
+
*/
|
|
244
|
+
export function parseVerdict(value, reasonMaxChars) {
|
|
245
|
+
if (typeof value !== 'object' || value === null)
|
|
246
|
+
return undefined;
|
|
247
|
+
const record = value;
|
|
248
|
+
const decision = record.decision;
|
|
249
|
+
if (decision !== 'allow' && decision !== 'deny')
|
|
250
|
+
return undefined;
|
|
251
|
+
const reason = record.reason;
|
|
252
|
+
if (typeof reason !== 'string' || reason.trim().length === 0)
|
|
253
|
+
return undefined;
|
|
254
|
+
const riskLevel = record.riskLevel;
|
|
255
|
+
if (riskLevel !== undefined && riskLevel !== 'low' && riskLevel !== 'medium' && riskLevel !== 'high')
|
|
256
|
+
return undefined;
|
|
257
|
+
return {
|
|
258
|
+
decision,
|
|
259
|
+
reason: truncate(reason.trim(), reasonMaxChars),
|
|
260
|
+
...riskLevel === undefined ? {} : { riskLevel },
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Run one review attempt: start a one-shot reviewer child on the configured
|
|
265
|
+
* provider, await its structured verdict, and race both the configured
|
|
266
|
+
* timeout and the request signal. Every failure path resolves to a
|
|
267
|
+
* {@link ReviewFailure} — never to a grant.
|
|
268
|
+
* @param ctx - the plugin context (`ctx.subagents` and the request's parent agent).
|
|
269
|
+
* @param config - resolved config (provider, timeout, tools, model, budgets).
|
|
270
|
+
* @param request - the pending approval request (parent, signal, and evidence).
|
|
271
|
+
* @param reviewerSessions - the runtime's live reviewer session ids, so the
|
|
272
|
+
* answerer can refuse the child's own approval asks while the review runs.
|
|
273
|
+
* @param override - a pending human one-shot override, when one applies.
|
|
274
|
+
* @returns the verdict or the failure.
|
|
275
|
+
*/
|
|
276
|
+
export async function runReview(ctx, config, request, reviewerSessions, override) {
|
|
277
|
+
const provider = config.reviewerProvider;
|
|
278
|
+
const providerInfo = ctx.subagents.getProvider(provider);
|
|
279
|
+
if (providerInfo === undefined) {
|
|
280
|
+
return { fallback: 'unavailable', error: `subagent provider "${provider}" is not registered` };
|
|
281
|
+
}
|
|
282
|
+
const capabilities = providerInfo.capabilities;
|
|
283
|
+
// Absent capabilities (mock providers) skip the precheck; the service
|
|
284
|
+
// rejects unsupported requests at start time either way.
|
|
285
|
+
if (capabilities?.outputSchema === false) {
|
|
286
|
+
return { fallback: 'unavailable', error: `subagent provider "${provider}" does not support outputSchema, which the structured verdict requires` };
|
|
287
|
+
}
|
|
288
|
+
if (capabilities?.toolFilter === false) {
|
|
289
|
+
return { fallback: 'unavailable', error: `subagent provider "${provider}" does not support toolFilter, which the read-only reviewer face requires` };
|
|
290
|
+
}
|
|
291
|
+
const prompt = [{ type: 'text', text: buildReviewPrompt(request, config, override) }];
|
|
292
|
+
const controller = new AbortController();
|
|
293
|
+
let timedOut = false;
|
|
294
|
+
const timer = setTimeout(() => {
|
|
295
|
+
timedOut = true;
|
|
296
|
+
controller.abort();
|
|
297
|
+
}, config.reviewerTimeoutMs);
|
|
298
|
+
const onAbort = () => {
|
|
299
|
+
controller.abort();
|
|
300
|
+
};
|
|
301
|
+
request.signal?.addEventListener('abort', onAbort, { once: true });
|
|
302
|
+
let reviewerSessionId;
|
|
303
|
+
let model;
|
|
304
|
+
let run;
|
|
305
|
+
const failure = (fallback, error) => ({
|
|
306
|
+
fallback,
|
|
307
|
+
error,
|
|
308
|
+
...reviewerSessionId !== undefined ? { reviewerSessionId } : {},
|
|
309
|
+
...model !== undefined ? { model } : {},
|
|
310
|
+
});
|
|
311
|
+
try {
|
|
312
|
+
run = await ctx.subagents.start(provider, {
|
|
313
|
+
label: `auto-review: ${request.toolName}`,
|
|
314
|
+
prompt,
|
|
315
|
+
parent: request.agent,
|
|
316
|
+
signal: controller.signal,
|
|
317
|
+
toolFilter: { allow: config.reviewerTools },
|
|
318
|
+
outputSchema: VERDICT_SCHEMA,
|
|
319
|
+
// The cap equals the reviewer's OWN computed depth (parent depth + 1):
|
|
320
|
+
// the reviewer may run, but any child it tries to spawn would exceed it.
|
|
321
|
+
maxDepth: (request.agent.session.header.delegationDepth ?? 0) + 1,
|
|
322
|
+
...config.reviewerModel !== undefined ? { agentOptions: { model: config.reviewerModel } } : {},
|
|
323
|
+
});
|
|
324
|
+
reviewerSessionId = run.id;
|
|
325
|
+
reviewerSessions.add(run.id);
|
|
326
|
+
model = config.reviewerModel;
|
|
327
|
+
const result = await run.result;
|
|
328
|
+
if (timedOut) {
|
|
329
|
+
return failure('timeout', `reviewer exceeded ${config.reviewerTimeoutMs} ms`);
|
|
330
|
+
}
|
|
331
|
+
if (request.signal?.aborted === true) {
|
|
332
|
+
return failure('cancelled', 'approval request was cancelled while the reviewer ran');
|
|
333
|
+
}
|
|
334
|
+
if (result.stopReason !== 'completed') {
|
|
335
|
+
return failure('unavailable', `reviewer ended with stopReason "${result.stopReason}"`);
|
|
336
|
+
}
|
|
337
|
+
const verdict = parseVerdict(result.structured, config.reasonMaxChars);
|
|
338
|
+
if (verdict === undefined) {
|
|
339
|
+
return failure('schema', 'reviewer returned no valid structured verdict');
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
...verdict,
|
|
343
|
+
...reviewerSessionId !== undefined ? { reviewerSessionId } : {},
|
|
344
|
+
...model !== undefined ? { model } : {},
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
// A start/run rejection can be the timeout's or the request's abort
|
|
349
|
+
// surfacing (e.g. the fork driver's pre-publication abort); classify from
|
|
350
|
+
// the two races BEFORE the generic unavailable bucket, or the verdict's
|
|
351
|
+
// `fallback`/`outcome` would contradict the service's `approval/decided`.
|
|
352
|
+
if (timedOut)
|
|
353
|
+
return failure('timeout', `reviewer exceeded ${config.reviewerTimeoutMs} ms`);
|
|
354
|
+
if (request.signal?.aborted === true)
|
|
355
|
+
return failure('cancelled', 'approval request was cancelled before the reviewer delivered');
|
|
356
|
+
return failure('unavailable', `reviewer subagent failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
357
|
+
}
|
|
358
|
+
finally {
|
|
359
|
+
if (run !== undefined)
|
|
360
|
+
await run.dispose();
|
|
361
|
+
if (reviewerSessionId !== undefined)
|
|
362
|
+
reviewerSessions.delete(reviewerSessionId);
|
|
363
|
+
clearTimeout(timer);
|
|
364
|
+
request.signal?.removeEventListener('abort', onAbort);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Mint one verdict id. Wrapped for testability (audit uniqueness is a UUID).
|
|
369
|
+
* @returns a fresh branded id.
|
|
370
|
+
*/
|
|
371
|
+
export function newVerdictId() {
|
|
372
|
+
return AutoReviewVerdictId(randomUUID());
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Mint one circuit-trip id. Wrapped for testability (audit uniqueness is a UUID).
|
|
376
|
+
* @returns a fresh branded id.
|
|
377
|
+
*/
|
|
378
|
+
export function newCircuitId() {
|
|
379
|
+
return AutoReviewCircuitId(randomUUID());
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Mint one hard-disable rejection id. Wrapped for testability (audit
|
|
383
|
+
* uniqueness is a UUID).
|
|
384
|
+
* @returns a fresh branded id.
|
|
385
|
+
*/
|
|
386
|
+
export function newRejectionId() {
|
|
387
|
+
return AutoReviewRejectionId(randomUUID());
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime of `dsh-auto-review`: the `approval/request` answerer (claim when
|
|
3
|
+
* the session and tool policy say `ai`, otherwise strictly `next()`), the
|
|
4
|
+
* reviewer verdict handling with fail-closed fallback, the risk-policy
|
|
5
|
+
* escalation, the rejection circuit breaker, the deny-reason injection into
|
|
6
|
+
* the denied tool result, and the `/auto-review` session command. Every
|
|
7
|
+
* registration is an effect (ctx.on / commands.register).
|
|
8
|
+
* @module dsh-auto-review/runtime
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
11
|
+
import type { CommandInvocation, CommandResult } from '@deepseek-ai/dsh-commands';
|
|
12
|
+
import type { ApprovalOutcome, ApprovalRequest } from '@deepseek-ai/dsh-user-approval';
|
|
13
|
+
import type { PostToolDecision, ToolExecution, ToolExecutionResult } from '@deepseek-ai/dsh-tools';
|
|
14
|
+
import type { Config, ResolvedConfig } from './config.ts';
|
|
15
|
+
export declare const name = "auto-review";
|
|
16
|
+
export declare const inject: string[];
|
|
17
|
+
/**
|
|
18
|
+
* Answerer state and behavior. One instance per plugin mount; disposals are
|
|
19
|
+
* owned by the ctx.on / commands.register effects in {@link apply}.
|
|
20
|
+
*/
|
|
21
|
+
export declare class AutoReviewRuntime {
|
|
22
|
+
private readonly ctx;
|
|
23
|
+
readonly config: ResolvedConfig;
|
|
24
|
+
/** Live reviewer child sessions — their approval asks never re-enter AI review. */
|
|
25
|
+
private readonly reviewerSessions;
|
|
26
|
+
/** Feedback texts keyed by call id, consumed (and deleted) by the post-execute listener. */
|
|
27
|
+
private readonly feedback;
|
|
28
|
+
constructor(ctx: Context, config: ResolvedConfig);
|
|
29
|
+
/**
|
|
30
|
+
* The `approval/request` answerer. Claims a request ONLY when auto-review
|
|
31
|
+
* is enabled for the session AND the policy for this tool/reason is `ai`
|
|
32
|
+
* AND both per-turn budgets remain AND the rejection circuit breaker is
|
|
33
|
+
* not tripped; everything else delegates via `next()` (or deterministically
|
|
34
|
+
* rejects for `never`). The reviewer's own asks are always delegated
|
|
35
|
+
* (anti-recursion).
|
|
36
|
+
* @param request - the pending decision.
|
|
37
|
+
* @param next - the downstream answerer chain.
|
|
38
|
+
* @returns the closed approval outcome.
|
|
39
|
+
*/
|
|
40
|
+
answer(request: ApprovalRequest, next: () => Promise<ApprovalOutcome>): Promise<ApprovalOutcome>;
|
|
41
|
+
/**
|
|
42
|
+
* Settle a `never`-policy request deterministically: record the log-only
|
|
43
|
+
* `autoReview/rejection` audit event, and feed a model-visible
|
|
44
|
+
* `[auto-review-never]` marker text (plus the deny guidance) into the
|
|
45
|
+
* denied call's tool result — without it the model only sees the generic
|
|
46
|
+
* rejection and keeps retrying a hard-disabled action. No reviewer runs
|
|
47
|
+
* and no budget is consumed.
|
|
48
|
+
* @param request - the hard-disabled decision.
|
|
49
|
+
* @param source - the matched risk rule or policy table entry.
|
|
50
|
+
* @returns the closed rejection.
|
|
51
|
+
*/
|
|
52
|
+
private neverReject;
|
|
53
|
+
/**
|
|
54
|
+
* Run the reviewer for one claimed request, register the child for
|
|
55
|
+
* anti-recursion, apply the risk policy, record the verdict, trip the
|
|
56
|
+
* circuit breaker on denials, and settle the answerer chain.
|
|
57
|
+
* @param request - the pending decision.
|
|
58
|
+
* @param approvalId - the correlated `approval/asked` id.
|
|
59
|
+
* @param next - the downstream chain (used by risk-policy delegation).
|
|
60
|
+
* @param override - a pending human one-shot override, when one applies.
|
|
61
|
+
* @returns the closed approval outcome.
|
|
62
|
+
*/
|
|
63
|
+
private review;
|
|
64
|
+
/**
|
|
65
|
+
* Append the fallback verdict event and apply the configured fallback
|
|
66
|
+
* policy. A user cancellation settles `cancelled` regardless of policy;
|
|
67
|
+
* otherwise `rejected` (fail closed), `allow-once`, or `delegate`
|
|
68
|
+
* (continue the chain) per config.
|
|
69
|
+
*/
|
|
70
|
+
private finish;
|
|
71
|
+
/**
|
|
72
|
+
* Map one reviewer failure to the approval outcome the answerer settles
|
|
73
|
+
* with: `cancelled` when the user aborted the request; otherwise the
|
|
74
|
+
* configured fallback policy.
|
|
75
|
+
* @param failure - the review failure.
|
|
76
|
+
* @returns the outcome, or undefined when the chain must continue.
|
|
77
|
+
*/
|
|
78
|
+
private fallbackOutcome;
|
|
79
|
+
/**
|
|
80
|
+
* Settle one request while the rejection circuit breaker is tripped:
|
|
81
|
+
* `delegate` continues the chain; `reject` (and `abort-turn`, whose abort
|
|
82
|
+
* already happened at trip time) rejects with an auditable marker.
|
|
83
|
+
* @param request - the pending decision.
|
|
84
|
+
* @param circuit - the turn's recorded circuit trip.
|
|
85
|
+
* @param next - the downstream chain.
|
|
86
|
+
* @returns the closed approval outcome.
|
|
87
|
+
*/
|
|
88
|
+
private circuitSettle;
|
|
89
|
+
/**
|
|
90
|
+
* Trip the rejection circuit breaker after a denial, at most once per
|
|
91
|
+
* turn. `abort-turn` also injects a model-visible warning and cancels the
|
|
92
|
+
* agent (deferred a macrotask so the service's `approval/decided` append
|
|
93
|
+
* commits first — the pair must stay turn-enclosed).
|
|
94
|
+
* @param request - the request whose denial may trip the breaker.
|
|
95
|
+
*/
|
|
96
|
+
private checkCircuit;
|
|
97
|
+
/**
|
|
98
|
+
* Store one model-visible feedback text for a denied/failed call's tool
|
|
99
|
+
* result, keyed by call id. Consumed once by the post-execute listener;
|
|
100
|
+
* entries expire after a bounded TTL so a result path that never reaches
|
|
101
|
+
* post-execute cannot grow the map. Same call id twice is last-wins (a
|
|
102
|
+
* retried approval replaces its own pending feedback).
|
|
103
|
+
*/
|
|
104
|
+
private recordFeedback;
|
|
105
|
+
/**
|
|
106
|
+
* Record a deny reason (plus the anti-circumvention guidance) for the
|
|
107
|
+
* denied call's tool result.
|
|
108
|
+
* @param callId - the denied call.
|
|
109
|
+
* @param toolName - the denied tool.
|
|
110
|
+
* @param reviewId - the verdict event's id (embedded in the injected text).
|
|
111
|
+
* @param reason - the reviewer's reason.
|
|
112
|
+
*/
|
|
113
|
+
private recordDenyReason;
|
|
114
|
+
/**
|
|
115
|
+
* Record a fallback-rejection text for the failed call's tool result.
|
|
116
|
+
* @param callId - the failed call.
|
|
117
|
+
* @param reviewId - the fallback verdict event's id (embedded in the text).
|
|
118
|
+
* @param fallback - the failure category.
|
|
119
|
+
* @param error - the failure detail.
|
|
120
|
+
*/
|
|
121
|
+
private recordFallbackFeedback;
|
|
122
|
+
/**
|
|
123
|
+
* The `tools/post-execute` listener: replace the generic rejection text of
|
|
124
|
+
* a call THIS answerer denied with the recorded feedback (the model-visible
|
|
125
|
+
* content, reconstructable via the embedded marker). Any other call
|
|
126
|
+
* delegates untouched.
|
|
127
|
+
*/
|
|
128
|
+
injectDenyReason(exec: ToolExecution, result: Readonly<ToolExecutionResult>, next: () => Promise<PostToolDecision>): Promise<PostToolDecision>;
|
|
129
|
+
/**
|
|
130
|
+
* Execute the `/auto-review` command: `on` / `off` write the durable
|
|
131
|
+
* `autoReview/state` override (surviving restore) and inject a switch
|
|
132
|
+
* notice; `status` reports the effective state, both per-turn budgets,
|
|
133
|
+
* and the session's cumulative statistics; `approve [n]` records a
|
|
134
|
+
* one-shot human override for a recent denial.
|
|
135
|
+
* @param invocation - the received command invocation.
|
|
136
|
+
* @returns the command result shown to the user.
|
|
137
|
+
*/
|
|
138
|
+
command(invocation: CommandInvocation): CommandResult;
|
|
139
|
+
/**
|
|
140
|
+
* Execute `/auto-review approve [n]`: record a single-use human override
|
|
141
|
+
* for the n-th most recent denial (1 = most recent). The override is
|
|
142
|
+
* consumed by the NEXT same-tool review within `overrideTtlMs`, which
|
|
143
|
+
* carries the authorization as reviewer context — the reviewer still
|
|
144
|
+
* decides.
|
|
145
|
+
* @param invocation - the received command invocation.
|
|
146
|
+
* @returns the command result shown to the user.
|
|
147
|
+
*/
|
|
148
|
+
private approveCommand;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Mount the plugin: resolve config, register the answerer and the
|
|
152
|
+
* post-execute listener as effects, register the slash command, and register
|
|
153
|
+
* the `autoReview` session projection (when the host provides the
|
|
154
|
+
* session-projection capability — the web profile does; bare test mounts and
|
|
155
|
+
* minimal compositions may not, and the answerer must not depend on it).
|
|
156
|
+
* @param ctx - the host context.
|
|
157
|
+
* @param config - raw plugin config.
|
|
158
|
+
*/
|
|
159
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
160
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAEjF,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAqB,MAAM,gCAAgC,CAAA;AAGzG,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAElG,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAoB,MAAM,aAAa,CAAA;AA6B3E,eAAO,MAAM,IAAI,gBAAgB,CAAA;AACjC,eAAO,MAAM,MAAM,UAAiD,CAAA;AA+CpE;;;GAGG;AACH,qBAAa,iBAAiB;IAQ1B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,QAAQ,CAAC,MAAM,EAAE,cAAc;IARjC,mFAAmF;IACnF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAuB;IAExD,4FAA4F;IAC5F,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;gBAGzC,GAAG,EAAE,OAAO,EACpB,MAAM,EAAE,cAAc;IAGjC;;;;;;;;;;OAUG;IACH,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC;IAoChG;;;;;;;;;;OAUG;IACH,OAAO,CAAC,WAAW;IAgBnB;;;;;;;;;OASG;YACW,MAAM;IAuDpB;;;;;OAKG;IACH,OAAO,CAAC,MAAM;IAmCd;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAUvB;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAWrB;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IA+BpB;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAStB;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;IASxB;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAS9B;;;;;OAKG;IACH,gBAAgB,CACd,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,QAAQ,CAAC,mBAAmB,CAAC,EACrC,IAAI,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,GACpC,OAAO,CAAC,gBAAgB,CAAC;IAa5B;;;;;;;;OAQG;IACH,OAAO,CAAC,UAAU,EAAE,iBAAiB,GAAG,aAAa;IAoDrD;;;;;;;;OAQG;IACH,OAAO,CAAC,cAAc;CA0BvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAcxD"}
|